From 30e84371e0be60bfd31d912ae342b70f7f5383b4 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 20 Mar 2024 17:16:32 +0100 Subject: [PATCH 01/14] Blender: Export Alembic with subdiv schema (creases) --- .../blender/plugins/publish/extract_abc.py | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/blender/plugins/publish/extract_abc.py b/client/ayon_core/hosts/blender/plugins/publish/extract_abc.py index 094f88fd8c..6251c1c0c5 100644 --- a/client/ayon_core/hosts/blender/plugins/publish/extract_abc.py +++ b/client/ayon_core/hosts/blender/plugins/publish/extract_abc.py @@ -2,6 +2,7 @@ import os import bpy +from ayon_core.lib import BoolDef from ayon_core.pipeline import publish from ayon_core.hosts.blender.api import plugin @@ -17,6 +18,8 @@ class ExtractABC(publish.Extractor, publish.OptionalPyblishPluginMixin): if not self.is_active(instance.data): return + attr_values = self.get_attr_values_from_data(instance.data) + # Define extract output file path stagingdir = self.staging_dir(instance) folder_name = instance.data["folderEntity"]["name"] @@ -46,7 +49,8 @@ class ExtractABC(publish.Extractor, publish.OptionalPyblishPluginMixin): bpy.ops.wm.alembic_export( filepath=filepath, selected=True, - flatten=False + flatten=False, + subdiv_schema=attr_values.get("subdiv_schema", False) ) plugin.deselect_all() @@ -65,6 +69,21 @@ class ExtractABC(publish.Extractor, publish.OptionalPyblishPluginMixin): self.log.debug("Extracted instance '%s' to: %s", instance.name, representation) + @classmethod + def get_attribute_defs(cls): + return [ + BoolDef( + "subdiv_schema", + label="Alembic Mesh Subdiv Schema", + tooltip="Export Meshes using Alembic's subdivision schema.\n" + "Enabling this includes creases with the export but " + "excludes the mesh's normals.\n" + "Enabling this usually result in smaller file size " + "due to lack of normals.", + default=True + ) + ] + class ExtractModelABC(ExtractABC): """Extract model as ABC.""" From b2af91ba37adcb8cff5fd669d8f2e65b5eb91aa5 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 20 Mar 2024 17:17:42 +0100 Subject: [PATCH 02/14] Default to False for backwards compatibility --- client/ayon_core/hosts/blender/plugins/publish/extract_abc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/blender/plugins/publish/extract_abc.py b/client/ayon_core/hosts/blender/plugins/publish/extract_abc.py index 6251c1c0c5..6590be515c 100644 --- a/client/ayon_core/hosts/blender/plugins/publish/extract_abc.py +++ b/client/ayon_core/hosts/blender/plugins/publish/extract_abc.py @@ -80,7 +80,7 @@ class ExtractABC(publish.Extractor, publish.OptionalPyblishPluginMixin): "excludes the mesh's normals.\n" "Enabling this usually result in smaller file size " "due to lack of normals.", - default=True + default=False ) ] From 028375620fe7a7c44955e4ec6c025f4cf9ed13a0 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Mon, 15 Apr 2024 16:02:56 +0200 Subject: [PATCH 03/14] filter representations by id earlier --- .../workfile/workfile_template_builder.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/client/ayon_core/pipeline/workfile/workfile_template_builder.py b/client/ayon_core/pipeline/workfile/workfile_template_builder.py index 5e63ba444a..20783dd1ca 100644 --- a/client/ayon_core/pipeline/workfile/workfile_template_builder.py +++ b/client/ayon_core/pipeline/workfile/workfile_template_builder.py @@ -1587,14 +1587,14 @@ class PlaceholderLoadMixin(object): placeholder_representations = self._get_representations(placeholder) - filtered_representations = [] - for representation in self._reduce_last_version_repre_entities( - placeholder_representations - ): - repre_id = representation["id"] - if repre_id not in ignore_repre_ids: - filtered_representations.append(representation) - + filtered_representations = [ + repre_entity + for repre_entity in self._get_representations(placeholder) + if repre_entity["id"] not in ignore_repre_ids + ] + filtered_representations = self._reduce_last_version_repre_entities( + filtered_representations + ) if not filtered_representations: self.log.info(( "There's no representation for this placeholder: {}" From f3ab54493d3f2c276680fe4aca6c931800093d03 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Mon, 15 Apr 2024 16:03:31 +0200 Subject: [PATCH 04/14] get and use repre contexts earlier --- .../workfile/workfile_template_builder.py | 52 +++++++------------ 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/client/ayon_core/pipeline/workfile/workfile_template_builder.py b/client/ayon_core/pipeline/workfile/workfile_template_builder.py index 20783dd1ca..ae54b732f3 100644 --- a/client/ayon_core/pipeline/workfile/workfile_template_builder.py +++ b/client/ayon_core/pipeline/workfile/workfile_template_builder.py @@ -1529,35 +1529,24 @@ class PlaceholderLoadMixin(object): pass - def _reduce_last_version_repre_entities(self, representations): + def _reduce_last_version_repre_entities(self, repre_contexts): """Reduce representations to last verison.""" mapping = {} - # TODO use representation context with entities - # - using 'folder', 'subset' and 'version' from context on - # representation is danger - for repre_entity in representations: - repre_context = repre_entity["context"] + for repre_context in repre_contexts: + folder_id = repre_context["folder"]["id"] + product_id = repre_context["product"]["id"] + version = repre_context["version"]["version"] - folder_name = repre_context["asset"] - product_name = repre_context["subset"] - version = repre_context.get("version", -1) + parents_path = "/".join([folder_id, product_id]) + version_mapping = mapping.setdefault(parents_path, {}) - if folder_name not in mapping: - mapping[folder_name] = {} - - product_mapping = mapping[folder_name] - if product_name not in product_mapping: - product_mapping[product_name] = collections.defaultdict(list) - - version_mapping = product_mapping[product_name] - version_mapping[version].append(repre_entity) + version_mapping[version].append(repre_context) output = [] - for product_mapping in mapping.values(): - for version_mapping in product_mapping.values(): - last_version = tuple(sorted(version_mapping.keys()))[-1] - output.extend(version_mapping[last_version]) + for version_mapping in mapping.values(): + last_version = tuple(sorted(version_mapping.keys()))[-1] + output.extend(version_mapping[last_version]) return output def populate_load_placeholder(self, placeholder, ignore_repre_ids=None): @@ -1585,32 +1574,31 @@ class PlaceholderLoadMixin(object): loader_name = placeholder.data["loader"] loader_args = self.parse_loader_args(placeholder.data["loader_args"]) - placeholder_representations = self._get_representations(placeholder) - - filtered_representations = [ + placeholder_representations = [ repre_entity for repre_entity in self._get_representations(placeholder) if repre_entity["id"] not in ignore_repre_ids ] - filtered_representations = self._reduce_last_version_repre_entities( - filtered_representations + + repre_load_contexts = get_representation_contexts( + self.project_name, placeholder_representations ) - if not filtered_representations: + filtered_repre_contexts = self._reduce_last_version_repre_entities( + repre_load_contexts + ) + if not filtered_repre_contexts: self.log.info(( "There's no representation for this placeholder: {}" ).format(placeholder.scene_identifier)) return - repre_load_contexts = get_representation_contexts( - self.project_name, filtered_representations - ) loaders_by_name = self.builder.get_loaders_by_name() self._before_placeholder_load( placeholder ) failed = False - for repre_load_context in repre_load_contexts.values(): + for repre_load_context in filtered_repre_contexts: folder_path = repre_load_context["folder"]["path"] product_name = repre_load_context["product"]["name"] representation = repre_load_context["representation"] From b1e73835bbe9868b0dbf30ed5ce8fcb17c4646c6 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Mon, 15 Apr 2024 16:25:26 +0200 Subject: [PATCH 05/14] skip folder id in mapping --- .../pipeline/workfile/workfile_template_builder.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/client/ayon_core/pipeline/workfile/workfile_template_builder.py b/client/ayon_core/pipeline/workfile/workfile_template_builder.py index ae54b732f3..3e4d47f195 100644 --- a/client/ayon_core/pipeline/workfile/workfile_template_builder.py +++ b/client/ayon_core/pipeline/workfile/workfile_template_builder.py @@ -1532,19 +1532,17 @@ class PlaceholderLoadMixin(object): def _reduce_last_version_repre_entities(self, repre_contexts): """Reduce representations to last verison.""" - mapping = {} + version_mapping_by_product_id = {} for repre_context in repre_contexts: - folder_id = repre_context["folder"]["id"] product_id = repre_context["product"]["id"] version = repre_context["version"]["version"] - - parents_path = "/".join([folder_id, product_id]) - version_mapping = mapping.setdefault(parents_path, {}) - + version_mapping = version_mapping_by_product_id.setdefault( + product_id, {} + ) version_mapping[version].append(repre_context) output = [] - for version_mapping in mapping.values(): + for version_mapping in version_mapping_by_product_id.values(): last_version = tuple(sorted(version_mapping.keys()))[-1] output.extend(version_mapping[last_version]) return output From 78c73259ef4d724b72a7c442c3dcda7c3752a6d4 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Mon, 15 Apr 2024 16:30:10 +0200 Subject: [PATCH 06/14] fix typo Co-authored-by: Roy Nieterau --- client/ayon_core/pipeline/workfile/workfile_template_builder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/pipeline/workfile/workfile_template_builder.py b/client/ayon_core/pipeline/workfile/workfile_template_builder.py index 3e4d47f195..c3b1267466 100644 --- a/client/ayon_core/pipeline/workfile/workfile_template_builder.py +++ b/client/ayon_core/pipeline/workfile/workfile_template_builder.py @@ -1530,7 +1530,7 @@ class PlaceholderLoadMixin(object): pass def _reduce_last_version_repre_entities(self, repre_contexts): - """Reduce representations to last verison.""" + """Reduce representations to last version.""" version_mapping_by_product_id = {} for repre_context in repre_contexts: From 6873f02e6b08fec57cec6cd65a3ac840759e3ed2 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 18 Apr 2024 00:06:51 +0200 Subject: [PATCH 07/14] Fix typos --- .../workfile/workfile_template_builder.py | 22 +++++++++---------- .../tools/workfile_template_build/lib.py | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/client/ayon_core/pipeline/workfile/workfile_template_builder.py b/client/ayon_core/pipeline/workfile/workfile_template_builder.py index 5e63ba444a..012251cd91 100644 --- a/client/ayon_core/pipeline/workfile/workfile_template_builder.py +++ b/client/ayon_core/pipeline/workfile/workfile_template_builder.py @@ -329,7 +329,7 @@ class AbstractTemplateBuilder(object): is good practice to check if the same value is not already stored under different key or if the key is not already used for something else. - Key should be self explanatory to content. + Key should be self-explanatory to content. - wrong: 'folder' - good: 'folder_name' @@ -375,7 +375,7 @@ class AbstractTemplateBuilder(object): is good practice to check if the same value is not already stored under different key or if the key is not already used for something else. - Key should be self explanatory to content. + Key should be self-explanatory to content. - wrong: 'folder' - good: 'folder_path' @@ -395,7 +395,7 @@ class AbstractTemplateBuilder(object): is good practice to check if the same value is not already stored under different key or if the key is not already used for something else. - Key should be self explanatory to content. + Key should be self-explanatory to content. - wrong: 'folder' - good: 'folder_path' @@ -466,7 +466,7 @@ class AbstractTemplateBuilder(object): return list(sorted( placeholders, - key=lambda i: i.order + key=lambda placeholder: placeholder.order )) def build_template( @@ -685,7 +685,7 @@ class AbstractTemplateBuilder(object): for placeholder in placeholders } all_processed = len(placeholders) == 0 - # Counter is checked at the ned of a loop so the loop happens at least + # Counter is checked at the end of a loop so the loop happens at least # once. iter_counter = 0 while not all_processed: @@ -1045,7 +1045,7 @@ class PlaceholderPlugin(object): Using shared data from builder but stored under plugin identifier. - Key should be self explanatory to content. + Key should be self-explanatory to content. - wrong: 'folder' - good: 'folder_path' @@ -1085,7 +1085,7 @@ class PlaceholderPlugin(object): Using shared data from builder but stored under plugin identifier. - Key should be self explanatory to content. + Key should be self-explanatory to content. - wrong: 'folder' - good: 'folder_path' @@ -1107,10 +1107,10 @@ class PlaceholderItem(object): """Item representing single item in scene that is a placeholder to process. Items are always created and updated by their plugins. Each plugin can use - modified class of 'PlacehoderItem' but only to add more options instead of + modified class of 'PlaceholderItem' but only to add more options instead of new other. - Scene identifier is used to avoid processing of the palceholder item + Scene identifier is used to avoid processing of the placeholder item multiple times so must be unique across whole workfile builder. Args: @@ -1162,7 +1162,7 @@ class PlaceholderItem(object): """Placeholder data which can modify how placeholder is processed. Possible general keys - - order: Can define the order in which is palceholder processed. + - order: Can define the order in which is placeholder processed. Lower == earlier. Other keys are defined by placeholder and should validate them on item @@ -1264,7 +1264,7 @@ class PlaceholderLoadMixin(object): """Unified attribute definitions for load placeholder. Common function for placeholder plugins used for loading of - repsentations. Use it in 'get_placeholder_options'. + representations. Use it in 'get_placeholder_options'. Args: plugin (PlaceholderPlugin): Plugin used for loading of diff --git a/client/ayon_core/tools/workfile_template_build/lib.py b/client/ayon_core/tools/workfile_template_build/lib.py index de3a0d0084..ffd6fefc38 100644 --- a/client/ayon_core/tools/workfile_template_build/lib.py +++ b/client/ayon_core/tools/workfile_template_build/lib.py @@ -8,12 +8,12 @@ from ayon_core.tools.utils.dialogs import show_message_dialog def open_template_ui(builder, main_window): """Open template from `builder` - Asks user about overwriting current scene and feedsback exceptions. + Asks user about overwriting current scene and feedback exceptions. """ result = QtWidgets.QMessageBox.question( main_window, "Opening template", - "Caution! You will loose unsaved changes.\nDo you want to continue?", + "Caution! You will lose unsaved changes.\nDo you want to continue?", QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No ) if result == QtWidgets.QMessageBox.Yes: From a59c54d1aa8807659cac331af9a0ee9a2019a6c8 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 18 Apr 2024 00:09:29 +0200 Subject: [PATCH 08/14] Remove non-existing arguments from docstring --- .../ayon_core/pipeline/workfile/workfile_template_builder.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/client/ayon_core/pipeline/workfile/workfile_template_builder.py b/client/ayon_core/pipeline/workfile/workfile_template_builder.py index 012251cd91..1c094e1d52 100644 --- a/client/ayon_core/pipeline/workfile/workfile_template_builder.py +++ b/client/ayon_core/pipeline/workfile/workfile_template_builder.py @@ -1267,8 +1267,6 @@ class PlaceholderLoadMixin(object): representations. Use it in 'get_placeholder_options'. Args: - plugin (PlaceholderPlugin): Plugin used for loading of - representations. options (Dict[str, Any]): Already available options which are used as defaults for attributes. @@ -1695,8 +1693,6 @@ class PlaceholderCreateMixin(object): publishable instances. Use it with 'get_placeholder_options'. Args: - plugin (PlaceholderPlugin): Plugin used for creating of - publish instances. options (Dict[str, Any]): Already available options which are used as defaults for attributes. From 2b6889a6ea55dd8a5916f5584b3e39ced8c4d913 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 18 Apr 2024 00:12:42 +0200 Subject: [PATCH 09/14] Also delete placeholder if Keep Placeholder is not enabled and no representations were loaded --- client/ayon_core/pipeline/workfile/workfile_template_builder.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/ayon_core/pipeline/workfile/workfile_template_builder.py b/client/ayon_core/pipeline/workfile/workfile_template_builder.py index 5e63ba444a..56a7a5f33a 100644 --- a/client/ayon_core/pipeline/workfile/workfile_template_builder.py +++ b/client/ayon_core/pipeline/workfile/workfile_template_builder.py @@ -1599,6 +1599,8 @@ class PlaceholderLoadMixin(object): self.log.info(( "There's no representation for this placeholder: {}" ).format(placeholder.scene_identifier)) + if not placeholder.data.get("keep_placeholder", True): + self.delete_placeholder(placeholder) return repre_load_contexts = get_representation_contexts( From bf0d3477d9b7ac5f7b24392404efe5dd0222721c Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 18 Apr 2024 10:24:14 +0200 Subject: [PATCH 10/14] fix expading of values Co-authored-by: Roy Nieterau --- client/ayon_core/pipeline/workfile/workfile_template_builder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/pipeline/workfile/workfile_template_builder.py b/client/ayon_core/pipeline/workfile/workfile_template_builder.py index c3b1267466..ed7a2b8475 100644 --- a/client/ayon_core/pipeline/workfile/workfile_template_builder.py +++ b/client/ayon_core/pipeline/workfile/workfile_template_builder.py @@ -1582,7 +1582,7 @@ class PlaceholderLoadMixin(object): self.project_name, placeholder_representations ) filtered_repre_contexts = self._reduce_last_version_repre_entities( - repre_load_contexts + repre_load_contexts.values() ) if not filtered_repre_contexts: self.log.info(( From 646c0df474e100b307d33c1c896cd46b6c610580 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 18 Apr 2024 10:25:22 +0200 Subject: [PATCH 11/14] fix version entity manipulation --- .../ayon_core/pipeline/workfile/workfile_template_builder.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/pipeline/workfile/workfile_template_builder.py b/client/ayon_core/pipeline/workfile/workfile_template_builder.py index ed7a2b8475..7b8d29ee37 100644 --- a/client/ayon_core/pipeline/workfile/workfile_template_builder.py +++ b/client/ayon_core/pipeline/workfile/workfile_template_builder.py @@ -1539,11 +1539,11 @@ class PlaceholderLoadMixin(object): version_mapping = version_mapping_by_product_id.setdefault( product_id, {} ) - version_mapping[version].append(repre_context) + version_mapping.setdefault(version, []).append(repre_context) output = [] for version_mapping in version_mapping_by_product_id.values(): - last_version = tuple(sorted(version_mapping.keys()))[-1] + last_version = max(version_mapping.keys()) output.extend(version_mapping[last_version]) return output From 3d496be7c65a28fc1567cc4e62e6caadc6d45a4e Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 18 Apr 2024 10:26:20 +0200 Subject: [PATCH 12/14] fix product type key access --- .../ayon_core/pipeline/workfile/workfile_template_builder.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/pipeline/workfile/workfile_template_builder.py b/client/ayon_core/pipeline/workfile/workfile_template_builder.py index 7b8d29ee37..013a8fb37f 100644 --- a/client/ayon_core/pipeline/workfile/workfile_template_builder.py +++ b/client/ayon_core/pipeline/workfile/workfile_template_builder.py @@ -1468,7 +1468,9 @@ class PlaceholderLoadMixin(object): product_name_regex = None if product_name_regex_value: product_name_regex = re.compile(product_name_regex_value) - product_type = placeholder.data["family"] + product_type = placeholder.data.get("product_type") + if product_type is None: + product_type = placeholder.data.get("family") builder_type = placeholder.data["builder_type"] folder_ids = [] From d5a3296d4c09086d5805c3d62e617f48c1fd2b1a Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 18 Apr 2024 10:48:12 +0200 Subject: [PATCH 13/14] Crash if product type is not available. --- client/ayon_core/pipeline/workfile/workfile_template_builder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/pipeline/workfile/workfile_template_builder.py b/client/ayon_core/pipeline/workfile/workfile_template_builder.py index 013a8fb37f..525a7396e7 100644 --- a/client/ayon_core/pipeline/workfile/workfile_template_builder.py +++ b/client/ayon_core/pipeline/workfile/workfile_template_builder.py @@ -1470,7 +1470,7 @@ class PlaceholderLoadMixin(object): product_name_regex = re.compile(product_name_regex_value) product_type = placeholder.data.get("product_type") if product_type is None: - product_type = placeholder.data.get("family") + product_type = placeholder.data["family"] builder_type = placeholder.data["builder_type"] folder_ids = [] From 276b293577ad9c8396584d4dab63f55b8d21f05d Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 18 Apr 2024 17:09:02 +0200 Subject: [PATCH 14/14] Fix `apply_settings` signature --- .../hosts/maya/plugins/publish/collect_file_dependencies.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/collect_file_dependencies.py b/client/ayon_core/hosts/maya/plugins/publish/collect_file_dependencies.py index 93b46c511b..60853bd1ee 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/collect_file_dependencies.py +++ b/client/ayon_core/hosts/maya/plugins/publish/collect_file_dependencies.py @@ -12,7 +12,7 @@ class CollectFileDependencies(pyblish.api.ContextPlugin): families = ["renderlayer"] @classmethod - def apply_settings(cls, project_settings, system_settings): + def apply_settings(cls, project_settings): # Disable plug-in if not used for deadline submission anyway settings = project_settings["deadline"]["publish"]["MayaSubmitDeadline"] # noqa cls.enabled = settings.get("asset_dependencies", True)