From 8c4b303c586669f36f7ffaae8b8e4cdc8dee89d0 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Tue, 18 Apr 2023 12:45:28 +0100 Subject: [PATCH 01/17] Use get_reference_node and parent in hierarchy. --- openpype/hosts/maya/api/lib.py | 65 +++++++++++++++++++ .../maya/api/workfile_template_builder.py | 17 ++++- 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 61ea3d59df..1af1cb569e 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -3913,3 +3913,68 @@ def get_capture_preset(task_name, task_type, subset, project_settings, log): capture_preset = plugin_settings["capture_preset"] return capture_preset or {} + + +def get_reference_node(members, log=None): + """Get the reference node from the container members + Args: + members: list of node names + + Returns: + str: Reference node name. + + """ + + # Collect the references without .placeHolderList[] attributes as + # unique entries (objects only) and skipping the sharedReferenceNode. + references = set() + for ref in cmds.ls(members, exactType="reference", objectsOnly=True): + + # Ignore any `:sharedReferenceNode` + if ref.rsplit(":", 1)[-1].startswith("sharedReferenceNode"): + continue + + # Ignore _UNKNOWN_REF_NODE_ (PLN-160) + if ref.rsplit(":", 1)[-1].startswith("_UNKNOWN_REF_NODE_"): + continue + + references.add(ref) + + assert references, "No reference node found in container" + + # Get highest reference node (least parents) + highest = min(references, + key=lambda x: len(get_reference_node_parents(x))) + + # Warn the user when we're taking the highest reference node + if len(references) > 1: + if not log: + log = logging.getLogger(__name__) + + log.warning("More than one reference node found in " + "container, using highest reference node: " + "%s (in: %s)", highest, list(references)) + + return highest + + +def get_reference_node_parents(ref): + """Return all parent reference nodes of reference node + + Args: + ref (str): reference node. + + Returns: + list: The upstream parent reference nodes. + + """ + parent = cmds.referenceQuery(ref, + referenceNode=True, + parent=True) + parents = [] + while parent: + parents.append(parent) + parent = cmds.referenceQuery(parent, + referenceNode=True, + parent=True) + return parents diff --git a/openpype/hosts/maya/api/workfile_template_builder.py b/openpype/hosts/maya/api/workfile_template_builder.py index d65e4c74d2..f8169adb52 100644 --- a/openpype/hosts/maya/api/workfile_template_builder.py +++ b/openpype/hosts/maya/api/workfile_template_builder.py @@ -14,7 +14,7 @@ from openpype.tools.workfile_template_build import ( WorkfileBuildPlaceholderDialog, ) -from .lib import read, imprint +from .lib import read, imprint, get_reference_node PLACEHOLDER_SET = "PLACEHOLDERS_SET" @@ -258,8 +258,16 @@ class MayaPlaceholderLoadPlugin(PlaceholderPlugin, PlaceholderLoadMixin): return roots = cmds.sets(container, q=True) + ref_node = get_reference_node(roots) nodes_to_parent = [] for root in roots: + if ref_node: + ref_root = cmds.referenceQuery(root, n=True)[0] + ref_root = ( + cmds.listRelatives(ref_root, parent=True) or [ref_root] + ) + nodes_to_parent.extend(ref_root) + continue if root.endswith("_RN"): refRoot = cmds.referenceQuery(root, n=True)[0] refRoot = cmds.listRelatives(refRoot, parent=True) or [refRoot] @@ -277,10 +285,17 @@ class MayaPlaceholderLoadPlugin(PlaceholderPlugin, PlaceholderLoadMixin): matrix=True, worldSpace=True ) + scene_parent = cmds.listRelatives( + placeholder.scene_identifier, parent=True + ) for node in set(nodes_to_parent): cmds.reorder(node, front=True) cmds.reorder(node, relative=placeholder.data["index"]) cmds.xform(node, matrix=placeholder_form, ws=True) + if scene_parent: + cmds.parent(node, scene_parent) + else: + cmds.parent(node, world=True) holding_sets = cmds.listSets(object=placeholder.scene_identifier) if not holding_sets: From b3237d4cd549da30c5df3e13a44176d46ec9a30d Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Tue, 18 Apr 2023 15:10:36 +0100 Subject: [PATCH 02/17] Update openpype/hosts/maya/api/workfile_template_builder.py --- openpype/hosts/maya/api/workfile_template_builder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/api/workfile_template_builder.py b/openpype/hosts/maya/api/workfile_template_builder.py index f8169adb52..bbcc2f802a 100644 --- a/openpype/hosts/maya/api/workfile_template_builder.py +++ b/openpype/hosts/maya/api/workfile_template_builder.py @@ -262,7 +262,7 @@ class MayaPlaceholderLoadPlugin(PlaceholderPlugin, PlaceholderLoadMixin): nodes_to_parent = [] for root in roots: if ref_node: - ref_root = cmds.referenceQuery(root, n=True)[0] + ref_root = cmds.referenceQuery(root, nodes=True)[0] ref_root = ( cmds.listRelatives(ref_root, parent=True) or [ref_root] ) From 78a1d4f9664354201c49cf1b85ee61e8abf718a5 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Thu, 20 Apr 2023 08:44:57 +0100 Subject: [PATCH 03/17] Update openpype/hosts/maya/api/workfile_template_builder.py --- openpype/hosts/maya/api/workfile_template_builder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/api/workfile_template_builder.py b/openpype/hosts/maya/api/workfile_template_builder.py index bbcc2f802a..9dc91ed772 100644 --- a/openpype/hosts/maya/api/workfile_template_builder.py +++ b/openpype/hosts/maya/api/workfile_template_builder.py @@ -286,7 +286,7 @@ class MayaPlaceholderLoadPlugin(PlaceholderPlugin, PlaceholderLoadMixin): worldSpace=True ) scene_parent = cmds.listRelatives( - placeholder.scene_identifier, parent=True + placeholder.scene_identifier, parent=True, fullPath=True ) for node in set(nodes_to_parent): cmds.reorder(node, front=True) From b253e4366dbc52bad090b453d1697bc4dcf531d0 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Thu, 20 Apr 2023 09:07:47 +0100 Subject: [PATCH 04/17] Remove methods from plugin.py --- openpype/hosts/maya/api/plugin.py | 67 ++----------------------------- 1 file changed, 3 insertions(+), 64 deletions(-) diff --git a/openpype/hosts/maya/api/plugin.py b/openpype/hosts/maya/api/plugin.py index 714278ba6c..f065c081f4 100644 --- a/openpype/hosts/maya/api/plugin.py +++ b/openpype/hosts/maya/api/plugin.py @@ -18,70 +18,9 @@ from openpype.settings import get_project_settings from .pipeline import containerise from . import lib - -def get_reference_node(members, log=None): - """Get the reference node from the container members - Args: - members: list of node names - - Returns: - str: Reference node name. - - """ - - # Collect the references without .placeHolderList[] attributes as - # unique entries (objects only) and skipping the sharedReferenceNode. - references = set() - for ref in cmds.ls(members, exactType="reference", objectsOnly=True): - - # Ignore any `:sharedReferenceNode` - if ref.rsplit(":", 1)[-1].startswith("sharedReferenceNode"): - continue - - # Ignore _UNKNOWN_REF_NODE_ (PLN-160) - if ref.rsplit(":", 1)[-1].startswith("_UNKNOWN_REF_NODE_"): - continue - - references.add(ref) - - assert references, "No reference node found in container" - - # Get highest reference node (least parents) - highest = min(references, - key=lambda x: len(get_reference_node_parents(x))) - - # Warn the user when we're taking the highest reference node - if len(references) > 1: - if not log: - log = Logger.get_logger(__name__) - - log.warning("More than one reference node found in " - "container, using highest reference node: " - "%s (in: %s)", highest, list(references)) - - return highest - - -def get_reference_node_parents(ref): - """Return all parent reference nodes of reference node - - Args: - ref (str): reference node. - - Returns: - list: The upstream parent reference nodes. - - """ - parent = cmds.referenceQuery(ref, - referenceNode=True, - parent=True) - parents = [] - while parent: - parents.append(parent) - parent = cmds.referenceQuery(parent, - referenceNode=True, - parent=True) - return parents +# Backwards compatibility: these functions has been moved to lib. +get_reference_node = lib.get_reference_node +get_reference_node_parents = lib.get_reference_node_parents def get_custom_namespace(custom_namespace): From f6c32300c20689e6fe33c368f2108c4fc7334fe8 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 21 Apr 2023 10:32:26 +0100 Subject: [PATCH 05/17] Log warning when using plugin methods. --- openpype/hosts/maya/api/plugin.py | 32 ++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/maya/api/plugin.py b/openpype/hosts/maya/api/plugin.py index f065c081f4..87015a0ae9 100644 --- a/openpype/hosts/maya/api/plugin.py +++ b/openpype/hosts/maya/api/plugin.py @@ -18,9 +18,31 @@ from openpype.settings import get_project_settings from .pipeline import containerise from . import lib + +log = Logger.get_logger() + + # Backwards compatibility: these functions has been moved to lib. -get_reference_node = lib.get_reference_node -get_reference_node_parents = lib.get_reference_node_parents +def get_reference_node(*args, **kwargs): + """ + Deprecated: + This funcation was moved ... and will be removed in 3.16.x. + """ + msg = "Function 'get_reference_node' has been moved." + log.warning(msg) + cmds.warning(msg) + return lib.get_reference_node(*args, **kwargs) + + +def get_reference_node_parents(*args, **kwargs): + """ + Deprecated: + This funcation was moved ... and will be removed in 3.16.x. + """ + msg = "Function 'get_reference_node_parents' has been moved." + log.warning(msg) + cmds.warning(msg) + return lib.get_reference_node_parents(*args, **kwargs) def get_custom_namespace(custom_namespace): @@ -182,7 +204,7 @@ class ReferenceLoader(Loader): if not nodes: return - ref_node = get_reference_node(nodes, self.log) + ref_node = lib.get_reference_node(nodes, self.log) container = containerise( name=name, namespace=namespace, @@ -211,7 +233,7 @@ class ReferenceLoader(Loader): # Get reference node from container members members = get_container_members(node) - reference_node = get_reference_node(members, self.log) + reference_node = lib.get_reference_node(members, self.log) namespace = cmds.referenceQuery(reference_node, namespace=True) file_type = { @@ -359,7 +381,7 @@ class ReferenceLoader(Loader): # Assume asset has been referenced members = cmds.sets(node, query=True) - reference_node = get_reference_node(members, self.log) + reference_node = lib.get_reference_node(members, self.log) assert reference_node, ("Imported container not supported; " "container must be referenced.") From f4117a7a5cd84df6ce53e4afd2a91fbb601fc705 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 26 Apr 2023 10:35:40 +0100 Subject: [PATCH 06/17] Clean up of placeholder. --- .../hosts/maya/api/workfile_template_builder.py | 4 ++++ .../pipeline/workfile/workfile_template_builder.py | 13 +++++++++++++ 2 files changed, 17 insertions(+) diff --git a/openpype/hosts/maya/api/workfile_template_builder.py b/openpype/hosts/maya/api/workfile_template_builder.py index 9dc91ed772..eb90dfdc37 100644 --- a/openpype/hosts/maya/api/workfile_template_builder.py +++ b/openpype/hosts/maya/api/workfile_template_builder.py @@ -242,6 +242,10 @@ class MayaPlaceholderLoadPlugin(PlaceholderPlugin, PlaceholderLoadMixin): cmds.hide(node) cmds.setAttr(node + ".hiddenInOutliner", True) + def delete_placeholder(self, placeholder): + """Remove placeholder if building was successful""" + cmds.delete(placeholder._scene_identifier) + def load_succeed(self, placeholder, container): self._parent_in_hierarchy(placeholder, container) diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index a3d7340367..3d28d862a3 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -1555,6 +1555,15 @@ class PlaceholderLoadMixin(object): self.load_succeed(placeholder, container) self.cleanup_placeholder(placeholder, failed) + if failed: + self.log.debug( + "Placeholder cleanup skipped due to failed placeholder " + "population." + ) + return + if not placeholder.data["keep_placeholder"]: + self.delete_placeholder(placeholder) + def load_failed(self, placeholder, representation): if hasattr(placeholder, "load_failed"): placeholder.load_failed(representation) @@ -1577,6 +1586,10 @@ class PlaceholderLoadMixin(object): pass + def delete_placeholder(self, placeholder, failed): + """Called when all item population is done.""" + self.log.debug("Clean up of placeholder is not implemented.") + class PlaceholderCreateMixin(object): """Mixin prepared for creating placeholder plugins. From fa73bbb568b78f2abae63ac8979dac99a163a9bc Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 26 Apr 2023 11:26:35 +0100 Subject: [PATCH 07/17] Account for "create_first_version" setting. --- openpype/pipeline/workfile/workfile_template_builder.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index 3d28d862a3..ef8930daf7 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -477,7 +477,9 @@ class AbstractTemplateBuilder(object): create_first_version = template_preset["create_first_version"] # check if first version is created - created_version_workfile = self.create_first_workfile_version() + created_version_workfile = False + if create_first_version: + created_version_workfile = self.create_first_workfile_version() # if first version is created, import template # and populate placeholders From 9747398ce8cb4803139bdae489dbc3eb01de1634 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 28 Apr 2023 15:25:37 +0100 Subject: [PATCH 08/17] Rename "cleanup_placeholder" to "post_representation_load" --- openpype/hosts/maya/api/workfile_template_builder.py | 2 +- openpype/hosts/nuke/api/workfile_template_builder.py | 4 ++-- openpype/pipeline/workfile/workfile_template_builder.py | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/openpype/hosts/maya/api/workfile_template_builder.py b/openpype/hosts/maya/api/workfile_template_builder.py index eb90dfdc37..11b8c8bd4b 100644 --- a/openpype/hosts/maya/api/workfile_template_builder.py +++ b/openpype/hosts/maya/api/workfile_template_builder.py @@ -233,7 +233,7 @@ class MayaPlaceholderLoadPlugin(PlaceholderPlugin, PlaceholderLoadMixin): def get_placeholder_options(self, options=None): return self.get_load_plugin_options(options) - def cleanup_placeholder(self, placeholder, failed): + def post_representation_load(self, placeholder, failed): """Hide placeholder, add them to placeholder set """ node = placeholder._scene_identifier diff --git a/openpype/hosts/nuke/api/workfile_template_builder.py b/openpype/hosts/nuke/api/workfile_template_builder.py index 72d4ffb476..235a8d1c59 100644 --- a/openpype/hosts/nuke/api/workfile_template_builder.py +++ b/openpype/hosts/nuke/api/workfile_template_builder.py @@ -189,7 +189,7 @@ class NukePlaceholderLoadPlugin(NukePlaceholderPlugin, PlaceholderLoadMixin): def get_placeholder_options(self, options=None): return self.get_load_plugin_options(options) - def cleanup_placeholder(self, placeholder, failed): + def post_representation_load(self, placeholder, failed): # deselect all selected nodes placeholder_node = nuke.toNode(placeholder.scene_identifier) @@ -603,7 +603,7 @@ class NukePlaceholderCreatePlugin( def get_placeholder_options(self, options=None): return self.get_create_plugin_options(options) - def cleanup_placeholder(self, placeholder, failed): + def post_representation_load(self, placeholder, failed): # deselect all selected nodes placeholder_node = nuke.toNode(placeholder.scene_identifier) diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index ef8930daf7..e8738bd259 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -1555,7 +1555,7 @@ class PlaceholderLoadMixin(object): else: failed = False self.load_succeed(placeholder, container) - self.cleanup_placeholder(placeholder, failed) + self.post_representation_load(placeholder, failed) if failed: self.log.debug( @@ -1574,7 +1574,7 @@ class PlaceholderLoadMixin(object): if hasattr(placeholder, "load_succeed"): placeholder.load_succeed(container) - def cleanup_placeholder(self, placeholder, failed): + def post_representation_load(self, placeholder, failed): """Cleanup placeholder after load of single representation. Can be called multiple times during placeholder item populating and is @@ -1751,7 +1751,7 @@ class PlaceholderCreateMixin(object): failed = False self.create_succeed(placeholder, creator_instance) - self.cleanup_placeholder(placeholder, failed) + self.post_representation_load(placeholder, failed) def create_failed(self, placeholder, creator_data): if hasattr(placeholder, "create_failed"): @@ -1761,7 +1761,7 @@ class PlaceholderCreateMixin(object): if hasattr(placeholder, "create_succeed"): placeholder.create_succeed(creator_instance) - def cleanup_placeholder(self, placeholder, failed): + def post_representation_load(self, placeholder, failed): """Cleanup placeholder after load of single representation. Can be called multiple times during placeholder item populating and is From 8cf509fbd105b3e54362db39a35975ad6ace3683 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Thu, 11 May 2023 10:17:51 +0100 Subject: [PATCH 09/17] Fix for multiple placeholder matches. --- openpype/hosts/maya/api/workfile_template_builder.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/maya/api/workfile_template_builder.py b/openpype/hosts/maya/api/workfile_template_builder.py index 11b8c8bd4b..1380d65ba9 100644 --- a/openpype/hosts/maya/api/workfile_template_builder.py +++ b/openpype/hosts/maya/api/workfile_template_builder.py @@ -268,11 +268,13 @@ class MayaPlaceholderLoadPlugin(PlaceholderPlugin, PlaceholderLoadMixin): if ref_node: ref_root = cmds.referenceQuery(root, nodes=True)[0] ref_root = ( - cmds.listRelatives(ref_root, parent=True) or [ref_root] + cmds.listRelatives(ref_root, parent=True, path=True) or + [ref_root] ) nodes_to_parent.extend(ref_root) continue if root.endswith("_RN"): + # Backwards compatibility for hardcoded reference names. refRoot = cmds.referenceQuery(root, n=True)[0] refRoot = cmds.listRelatives(refRoot, parent=True) or [refRoot] nodes_to_parent.extend(refRoot) From d2842b0cd7586f1a842a9f957575d49b7e1a2def Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Thu, 11 May 2023 17:55:25 +0100 Subject: [PATCH 10/17] post_representation_load > post_placeholder_process --- openpype/hosts/maya/api/workfile_template_builder.py | 2 +- openpype/hosts/nuke/api/workfile_template_builder.py | 4 ++-- openpype/pipeline/workfile/workfile_template_builder.py | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/openpype/hosts/maya/api/workfile_template_builder.py b/openpype/hosts/maya/api/workfile_template_builder.py index 1380d65ba9..d392ceebec 100644 --- a/openpype/hosts/maya/api/workfile_template_builder.py +++ b/openpype/hosts/maya/api/workfile_template_builder.py @@ -233,7 +233,7 @@ class MayaPlaceholderLoadPlugin(PlaceholderPlugin, PlaceholderLoadMixin): def get_placeholder_options(self, options=None): return self.get_load_plugin_options(options) - def post_representation_load(self, placeholder, failed): + def post_placeholder_process(self, placeholder, failed): """Hide placeholder, add them to placeholder set """ node = placeholder._scene_identifier diff --git a/openpype/hosts/nuke/api/workfile_template_builder.py b/openpype/hosts/nuke/api/workfile_template_builder.py index 235a8d1c59..8cb1e7839a 100644 --- a/openpype/hosts/nuke/api/workfile_template_builder.py +++ b/openpype/hosts/nuke/api/workfile_template_builder.py @@ -189,7 +189,7 @@ class NukePlaceholderLoadPlugin(NukePlaceholderPlugin, PlaceholderLoadMixin): def get_placeholder_options(self, options=None): return self.get_load_plugin_options(options) - def post_representation_load(self, placeholder, failed): + def post_placeholder_process(self, placeholder, failed): # deselect all selected nodes placeholder_node = nuke.toNode(placeholder.scene_identifier) @@ -603,7 +603,7 @@ class NukePlaceholderCreatePlugin( def get_placeholder_options(self, options=None): return self.get_create_plugin_options(options) - def post_representation_load(self, placeholder, failed): + def post_placeholder_process(self, placeholder, failed): # deselect all selected nodes placeholder_node = nuke.toNode(placeholder.scene_identifier) diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index e8738bd259..f4dca685d1 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -1555,7 +1555,7 @@ class PlaceholderLoadMixin(object): else: failed = False self.load_succeed(placeholder, container) - self.post_representation_load(placeholder, failed) + self.post_placeholder_process(placeholder, failed) if failed: self.log.debug( @@ -1574,7 +1574,7 @@ class PlaceholderLoadMixin(object): if hasattr(placeholder, "load_succeed"): placeholder.load_succeed(container) - def post_representation_load(self, placeholder, failed): + def post_placeholder_process(self, placeholder, failed): """Cleanup placeholder after load of single representation. Can be called multiple times during placeholder item populating and is @@ -1751,7 +1751,7 @@ class PlaceholderCreateMixin(object): failed = False self.create_succeed(placeholder, creator_instance) - self.post_representation_load(placeholder, failed) + self.post_placeholder_process(placeholder, failed) def create_failed(self, placeholder, creator_data): if hasattr(placeholder, "create_failed"): @@ -1761,7 +1761,7 @@ class PlaceholderCreateMixin(object): if hasattr(placeholder, "create_succeed"): placeholder.create_succeed(creator_instance) - def post_representation_load(self, placeholder, failed): + def post_placeholder_process(self, placeholder, failed): """Cleanup placeholder after load of single representation. Can be called multiple times during placeholder item populating and is From 67f012e441a18e669c93c7b15ce17a6d9dbcc05d Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 12 Jun 2023 16:03:26 +0200 Subject: [PATCH 11/17] Fix typo + cosmetics --- openpype/hosts/maya/api/plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/api/plugin.py b/openpype/hosts/maya/api/plugin.py index 691c7da6cf..967d39674c 100644 --- a/openpype/hosts/maya/api/plugin.py +++ b/openpype/hosts/maya/api/plugin.py @@ -26,7 +26,7 @@ log = Logger.get_logger() def get_reference_node(*args, **kwargs): """ Deprecated: - This funcation was moved ... and will be removed in 3.16.x. + This function was moved and will be removed in 3.16.x. """ msg = "Function 'get_reference_node' has been moved." log.warning(msg) @@ -37,7 +37,7 @@ def get_reference_node(*args, **kwargs): def get_reference_node_parents(*args, **kwargs): """ Deprecated: - This funcation was moved ... and will be removed in 3.16.x. + This function was moved and will be removed in 3.16.x. """ msg = "Function 'get_reference_node_parents' has been moved." log.warning(msg) From dcf3b2749326d173a9a6b635f51f213b83baa6ab Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Fri, 23 Jun 2023 14:49:46 +0100 Subject: [PATCH 12/17] Update openpype/pipeline/workfile/workfile_template_builder.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/pipeline/workfile/workfile_template_builder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index 83d602fa79..489297efe4 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -1574,7 +1574,7 @@ class PlaceholderLoadMixin(object): "population." ) return - if not placeholder.data["keep_placeholder"]: + if not placeholder.data.get("keep_placeholder", True): self.delete_placeholder(placeholder) def load_failed(self, placeholder, representation): From 4a8e5c48179464e59a533b87777c81738d0f255c Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 23 Jun 2023 14:56:44 +0100 Subject: [PATCH 13/17] Illicit feedback --- openpype/hosts/maya/api/workfile_template_builder.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/api/workfile_template_builder.py b/openpype/hosts/maya/api/workfile_template_builder.py index 4471fc2b3b..38ac8f9f8a 100644 --- a/openpype/hosts/maya/api/workfile_template_builder.py +++ b/openpype/hosts/maya/api/workfile_template_builder.py @@ -253,7 +253,7 @@ class MayaPlaceholderLoadPlugin(PlaceholderPlugin, PlaceholderLoadMixin): def post_placeholder_process(self, placeholder, failed): """Hide placeholder, add them to placeholder set """ - node = placeholder._scene_identifier + node = placeholder.scene_identifier cmds.sets(node, addElement=PLACEHOLDER_SET) cmds.hide(node) @@ -261,7 +261,7 @@ class MayaPlaceholderLoadPlugin(PlaceholderPlugin, PlaceholderLoadMixin): def delete_placeholder(self, placeholder): """Remove placeholder if building was successful""" - cmds.delete(placeholder._scene_identifier) + cmds.delete(placeholder.scene_identifier) def load_succeed(self, placeholder, container): self._parent_in_hierarchy(placeholder, container) From eb7aceb7e538dfff0dad121c0128369943a13871 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 26 Jun 2023 14:29:19 +0000 Subject: [PATCH 14/17] chore(): update bug report / version --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 2f185a3f87..57a49406f0 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -35,6 +35,7 @@ body: label: Version description: What version are you running? Look to OpenPype Tray options: + - 3.15.11 - 3.15.11-nightly.5 - 3.15.11-nightly.4 - 3.15.11-nightly.3 @@ -134,7 +135,6 @@ body: - 3.14.4-nightly.2 - 3.14.4-nightly.1 - 3.14.3 - - 3.14.3-nightly.7 validations: required: true - type: dropdown From 83242487fd9ad2d1ead7a13baca6da1951c2350a Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 27 Jun 2023 10:58:55 +0200 Subject: [PATCH 15/17] AfterEffects: support for workfile template builder (#5163) * OP-5661 - added new menu item to AE extension * OP-5661 - added support for addPlaceholder into extension * OP-5661 - fix broken abstract loader In some cases discover couldn't recognize that base plugin is abstract. Handled properly * OP-5661 - WIP of implementing workfile template builder * OP-5661 - added route to add placeholder * OP-5661 - added route to build workfile * OP-5661 - refactored arguments * OP-5661 - implemented build workfile operation moved from wrong position * OP-5661 - removed wrong base plugin * OP-5661 - implemented update placeholder logic * OP-5661 - fix update placeholder metadata * OP-5661 - added Creator placeholder plugin * OP-5661 - pre_create_data could be passed into Creator This allow to modify `pre_create_data` before automatically creating an instance. (Useful for overridding defaults.) * OP-5661 - implemented populate of Create placeholder * OP-5661 - implemented import of template * OP-5661 - fix to populate correct create placeholder Implemented function to select item(s) by their id. (CreateRender expects selected composition.) * OP-5661 - fix workfile builder schema to multiplatform path Path should be separated by platform. * OP-5661 - implemented adding loaded items instead of placeholders * OP-5661 - add Create Placeholder plugin to dropdown * OP-5661 - add templated workfile to Settings * OP-5661 - fix to choose template file from multiplatform * OP-5661 - added documentation --- openpype/hosts/aftereffects/api/extension.zxp | Bin 101866 -> 102930 bytes .../api/extension/CSXS/manifest.xml | 2 +- .../aftereffects/api/extension/index.html | 39 +++ .../aftereffects/api/extension/js/main.js | 46 ++- .../api/extension/jsx/hostscript.jsx | 113 +++++++- .../hosts/aftereffects/api/launch_logic.py | 30 ++ openpype/hosts/aftereffects/api/pipeline.py | 10 + openpype/hosts/aftereffects/api/plugin.py | 4 + .../api/workfile_template_builder.py | 271 ++++++++++++++++++ openpype/hosts/aftereffects/api/ws_stub.py | 78 ++++- .../plugins/load/load_background.py | 11 +- .../aftereffects/plugins/load/load_file.py | 9 +- .../workfile/workfile_template_builder.py | 12 +- .../project_settings/aftereffects.json | 3 + .../schema_project_aftereffects.json | 4 + .../schema_templated_workfile_build.json | 2 +- website/docs/admin_hosts_aftereffects.md | 15 + website/docs/artist_hosts_aftereffects.md | 41 ++- .../aftereffects_create_placeholder.png | Bin 0 -> 20572 bytes .../assets/aftereffects_load_placeholder.png | Bin 0 -> 52653 bytes .../aftereffects_populated_template.png | Bin 0 -> 33441 bytes .../assets/aftereffects_prepared_template.png | Bin 0 -> 31476 bytes 22 files changed, 664 insertions(+), 26 deletions(-) create mode 100644 openpype/hosts/aftereffects/api/workfile_template_builder.py create mode 100644 website/docs/assets/aftereffects_create_placeholder.png create mode 100644 website/docs/assets/aftereffects_load_placeholder.png create mode 100644 website/docs/assets/aftereffects_populated_template.png create mode 100644 website/docs/assets/aftereffects_prepared_template.png diff --git a/openpype/hosts/aftereffects/api/extension.zxp b/openpype/hosts/aftereffects/api/extension.zxp index 50fda416f806515e8a6e90e745153e341f73c7b2..358e9740d3c2479b88dff08af47eba3d74be63ce 100644 GIT binary patch delta 15296 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 - diff --git a/openpype/hosts/aftereffects/api/extension/index.html b/openpype/hosts/aftereffects/api/extension/index.html index 291965559f..480b814a57 100644 --- a/openpype/hosts/aftereffects/api/extension/index.html +++ b/openpype/hosts/aftereffects/api/extension/index.html @@ -104,6 +104,39 @@ }); + + + + + +