From 51957dd3aec5d09c83ffca921966229d4a382b3f Mon Sep 17 00:00:00 2001 From: Derek Severin Date: Wed, 2 Mar 2022 15:37:53 +0700 Subject: [PATCH 01/13] Deformer node ids validation plugin for Maya --- .../validate_node_ids_deformer_transfer.py | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 openpype/hosts/maya/plugins/publish/validate_node_ids_deformer_transfer.py diff --git a/openpype/hosts/maya/plugins/publish/validate_node_ids_deformer_transfer.py b/openpype/hosts/maya/plugins/publish/validate_node_ids_deformer_transfer.py new file mode 100644 index 0000000000..67b4aff136 --- /dev/null +++ b/openpype/hosts/maya/plugins/publish/validate_node_ids_deformer_transfer.py @@ -0,0 +1,105 @@ +from maya import cmds + +import pyblish.api +import openpype.api +import openpype.hosts.maya.api.action +from openpype.hosts.maya.api import lib + + +class ValidateNodeIdsDeformerTransfer(pyblish.api.InstancePlugin): + """Validate if deformed shapes have related IDs to the original + shapes. + + When a deformer is applied in the scene on a mesh, + Maya creates a new "deformer" shape node for the mesh. + This new node does not get the original ID and later references + to the original node ID don't match. + + This validator checks whether the IDs are valid on all the shape + nodes in the instance. + """ + + order = openpype.api.ValidateContentsOrder + families = ['rig'] + hosts = ['maya'] + label = 'Deformed shape ids transferred' + actions = [ + openpype.hosts.maya.api.action.SelectInvalidAction, + openpype.api.RepairAction + ] + + def process(self, instance): + """Process all the nodes in the instance""" + + # Ensure nodes with sibling share the same ID + invalid = self.get_invalid(instance) + if invalid: + raise RuntimeError( + "Shapes found that are considered 'Deformed'" + " with invalid object ids: {0}".format(invalid) + ) + + @classmethod + def get_invalid(cls, instance): + """Get all nodes which do not match the criteria""" + + shapes = cmds.ls(instance[:], + dag=True, + leaf=True, + shapes=True, + long=True, + noIntermediate=True) + + invalid = [] + for shape in shapes: + sibling_id = cls._get_id_from_sibling(shape) + if not sibling_id: + continue + + current_id = lib.get_id(shape) + if current_id != sibling_id: + invalid.append(shape) + + return invalid + + @classmethod + def _get_id_from_sibling(cls, node): + """In some cases, the history of the deformed shapes cannot be used + to get the original shape, as the relation with the orignal shape + has been lost. + The original shape can be found as a sibling of the deformed shape + (sharing same transform parent), which has the "intermediate object" + attribute set. + The ID of that shape node can then be transferred to the deformed + shape node. + """ + + # Get long name + node = cmds.ls(node, long=True)[0] + + parent = cmds.listRelatives(node, parent=True, fullPath=True) + + # Get siblings of same type + node_type = cmds.nodeType(node) + similar_nodes = cmds.listRelatives(parent, type=node_type, fullPath=1) + # Exclude itself + similar_nodes = [x for x in similar_nodes if x != node] + + for similar_node in similar_nodes: + # Make sure it is an "intermediate object" + if cmds.getAttr(similar_node + ".io"): + _id = lib.get_id(similar_node) + if _id: + return _id + + @classmethod + def repair(cls, instance): + + for node in cls.get_invalid(instance): + # Get the original id from sibling + sibling_id = cls._get_id_from_sibling(node) + if not sibling_id: + cls.log.error("Could not find ID from sibling for '%s'", node) + continue + + lib.set_id(node, sibling_id, overwrite=True) From d714e52921ca6a36d2568e1a9e98fc7da8085662 Mon Sep 17 00:00:00 2001 From: Derek Severin Date: Wed, 2 Mar 2022 18:47:07 +0700 Subject: [PATCH 02/13] Refactor to existing lib function + plugin --- openpype/hosts/maya/api/lib.py | 30 ++++- ...date_animation_out_set_related_node_ids.py | 4 +- .../validate_node_ids_deformed_shapes.py | 4 +- .../validate_node_ids_deformer_transfer.py | 105 ------------------ .../publish/validate_rig_out_set_node_ids.py | 16 +-- 5 files changed, 38 insertions(+), 121 deletions(-) delete mode 100644 openpype/hosts/maya/plugins/publish/validate_node_ids_deformer_transfer.py diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 41528f20ba..2f7a09d4c4 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -1751,18 +1751,24 @@ def remove_other_uv_sets(mesh): cmds.removeMultiInstance(attr, b=True) -def get_id_from_history(node): +def get_id_from_sibling(node, history_only=True): """Return first node id in the history chain that matches this node. The nodes in history must be of the exact same node type and must be parented under the same parent. + If no matching node is found in history, the siblings of the node + are checked. Additionally to having the same parent, the sibling must + be marked as 'intermediate object'. + Args: - node (str): node to retrieve the + node (str): node to retrieve the history from + history_only (bool): also looks in node's siblings if True + and if nothing found in history Returns: - str or None: The id from the node in history or None when no id found - on any valid nodes in the history. + str or None: The id from the sibling node or None when no id found + on any valid nodes in the history or siblings. """ @@ -1791,6 +1797,22 @@ def get_id_from_history(node): if _id: return _id + if not history_only: + # Get siblings of same type + similar_nodes = cmds.listRelatives(parent, + type=node_type, + fullPath=True) + # Exclude itself + similar_nodes = [x for x in similar_nodes if x != node] + + for similar_node in similar_nodes: + # Check if "intermediate object" + if cmds.getAttr(similar_node + ".io"): + _id = get_id(similar_node) + if _id: + return _id + + # Project settings def set_scene_fps(fps, update=True): diff --git a/openpype/hosts/maya/plugins/publish/validate_animation_out_set_related_node_ids.py b/openpype/hosts/maya/plugins/publish/validate_animation_out_set_related_node_ids.py index 00f0d38775..7c1c695237 100644 --- a/openpype/hosts/maya/plugins/publish/validate_animation_out_set_related_node_ids.py +++ b/openpype/hosts/maya/plugins/publish/validate_animation_out_set_related_node_ids.py @@ -65,7 +65,7 @@ class ValidateOutRelatedNodeIds(pyblish.api.InstancePlugin): invalid.append(node) continue - history_id = lib.get_id_from_history(node) + history_id = lib.get_id_from_sibling(node) if history_id is not None and node_id != history_id: invalid.append(node) @@ -76,7 +76,7 @@ class ValidateOutRelatedNodeIds(pyblish.api.InstancePlugin): for node in cls.get_invalid(instance): # Get the original id from history - history_id = lib.get_id_from_history(node) + history_id = lib.get_id_from_sibling(node) if not history_id: cls.log.error("Could not find ID in history for '%s'", node) continue diff --git a/openpype/hosts/maya/plugins/publish/validate_node_ids_deformed_shapes.py b/openpype/hosts/maya/plugins/publish/validate_node_ids_deformed_shapes.py index a4d4d2bcc2..0324be9fc9 100644 --- a/openpype/hosts/maya/plugins/publish/validate_node_ids_deformed_shapes.py +++ b/openpype/hosts/maya/plugins/publish/validate_node_ids_deformed_shapes.py @@ -48,7 +48,7 @@ class ValidateNodeIdsDeformedShape(pyblish.api.InstancePlugin): invalid = [] for shape in shapes: - history_id = lib.get_id_from_history(shape) + history_id = lib.get_id_from_sibling(shape) if history_id: current_id = lib.get_id(shape) if current_id != history_id: @@ -61,7 +61,7 @@ class ValidateNodeIdsDeformedShape(pyblish.api.InstancePlugin): for node in cls.get_invalid(instance): # Get the original id from history - history_id = lib.get_id_from_history(node) + history_id = lib.get_id_from_sibling(node) if not history_id: cls.log.error("Could not find ID in history for '%s'", node) continue diff --git a/openpype/hosts/maya/plugins/publish/validate_node_ids_deformer_transfer.py b/openpype/hosts/maya/plugins/publish/validate_node_ids_deformer_transfer.py deleted file mode 100644 index 67b4aff136..0000000000 --- a/openpype/hosts/maya/plugins/publish/validate_node_ids_deformer_transfer.py +++ /dev/null @@ -1,105 +0,0 @@ -from maya import cmds - -import pyblish.api -import openpype.api -import openpype.hosts.maya.api.action -from openpype.hosts.maya.api import lib - - -class ValidateNodeIdsDeformerTransfer(pyblish.api.InstancePlugin): - """Validate if deformed shapes have related IDs to the original - shapes. - - When a deformer is applied in the scene on a mesh, - Maya creates a new "deformer" shape node for the mesh. - This new node does not get the original ID and later references - to the original node ID don't match. - - This validator checks whether the IDs are valid on all the shape - nodes in the instance. - """ - - order = openpype.api.ValidateContentsOrder - families = ['rig'] - hosts = ['maya'] - label = 'Deformed shape ids transferred' - actions = [ - openpype.hosts.maya.api.action.SelectInvalidAction, - openpype.api.RepairAction - ] - - def process(self, instance): - """Process all the nodes in the instance""" - - # Ensure nodes with sibling share the same ID - invalid = self.get_invalid(instance) - if invalid: - raise RuntimeError( - "Shapes found that are considered 'Deformed'" - " with invalid object ids: {0}".format(invalid) - ) - - @classmethod - def get_invalid(cls, instance): - """Get all nodes which do not match the criteria""" - - shapes = cmds.ls(instance[:], - dag=True, - leaf=True, - shapes=True, - long=True, - noIntermediate=True) - - invalid = [] - for shape in shapes: - sibling_id = cls._get_id_from_sibling(shape) - if not sibling_id: - continue - - current_id = lib.get_id(shape) - if current_id != sibling_id: - invalid.append(shape) - - return invalid - - @classmethod - def _get_id_from_sibling(cls, node): - """In some cases, the history of the deformed shapes cannot be used - to get the original shape, as the relation with the orignal shape - has been lost. - The original shape can be found as a sibling of the deformed shape - (sharing same transform parent), which has the "intermediate object" - attribute set. - The ID of that shape node can then be transferred to the deformed - shape node. - """ - - # Get long name - node = cmds.ls(node, long=True)[0] - - parent = cmds.listRelatives(node, parent=True, fullPath=True) - - # Get siblings of same type - node_type = cmds.nodeType(node) - similar_nodes = cmds.listRelatives(parent, type=node_type, fullPath=1) - # Exclude itself - similar_nodes = [x for x in similar_nodes if x != node] - - for similar_node in similar_nodes: - # Make sure it is an "intermediate object" - if cmds.getAttr(similar_node + ".io"): - _id = lib.get_id(similar_node) - if _id: - return _id - - @classmethod - def repair(cls, instance): - - for node in cls.get_invalid(instance): - # Get the original id from sibling - sibling_id = cls._get_id_from_sibling(node) - if not sibling_id: - cls.log.error("Could not find ID from sibling for '%s'", node) - continue - - lib.set_id(node, sibling_id, overwrite=True) diff --git a/openpype/hosts/maya/plugins/publish/validate_rig_out_set_node_ids.py b/openpype/hosts/maya/plugins/publish/validate_rig_out_set_node_ids.py index e2090080f6..c1029366e8 100644 --- a/openpype/hosts/maya/plugins/publish/validate_rig_out_set_node_ids.py +++ b/openpype/hosts/maya/plugins/publish/validate_rig_out_set_node_ids.py @@ -51,10 +51,10 @@ class ValidateRigOutSetNodeIds(pyblish.api.InstancePlugin): noIntermediate=True) for shape in shapes: - history_id = lib.get_id_from_history(shape) - if history_id: + sibling_id = lib.get_id_from_sibling(shape, history_only=False) + if sibling_id: current_id = lib.get_id(shape) - if current_id != history_id: + if current_id != sibling_id: invalid.append(shape) return invalid @@ -63,10 +63,10 @@ class ValidateRigOutSetNodeIds(pyblish.api.InstancePlugin): def repair(cls, instance): for node in cls.get_invalid(instance): - # Get the original id from history - history_id = lib.get_id_from_history(node) - if not history_id: - cls.log.error("Could not find ID in history for '%s'", node) + # Get the original id from sibling + sibling_id = lib.get_id_from_sibling(node, history_only=False) + if not sibling_id: + cls.log.error("Could not find ID in siblings for '%s'", node) continue - lib.set_id(node, history_id, overwrite=True) + lib.set_id(node, sibling_id, overwrite=True) From c95752be966e5f99f0ac25490a035a47c1264f1a Mon Sep 17 00:00:00 2001 From: Derek Severin Date: Thu, 3 Mar 2022 14:57:35 +0700 Subject: [PATCH 03/13] 'history only' as plugin setting --- .../publish/validate_rig_out_set_node_ids.py | 9 +++++++-- .../schemas/schema_maya_publish.json | 20 +++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/validate_rig_out_set_node_ids.py b/openpype/hosts/maya/plugins/publish/validate_rig_out_set_node_ids.py index c1029366e8..c272c5c485 100644 --- a/openpype/hosts/maya/plugins/publish/validate_rig_out_set_node_ids.py +++ b/openpype/hosts/maya/plugins/publish/validate_rig_out_set_node_ids.py @@ -24,6 +24,7 @@ class ValidateRigOutSetNodeIds(pyblish.api.InstancePlugin): openpype.hosts.maya.api.action.SelectInvalidAction, openpype.api.RepairAction ] + allow_history_only = False def process(self, instance): """Process all meshes""" @@ -51,7 +52,9 @@ class ValidateRigOutSetNodeIds(pyblish.api.InstancePlugin): noIntermediate=True) for shape in shapes: - sibling_id = lib.get_id_from_sibling(shape, history_only=False) + sibling_id = \ + lib.get_id_from_sibling(shape, + history_only=cls.allow_history_only) if sibling_id: current_id = lib.get_id(shape) if current_id != sibling_id: @@ -64,7 +67,9 @@ class ValidateRigOutSetNodeIds(pyblish.api.InstancePlugin): for node in cls.get_invalid(instance): # Get the original id from sibling - sibling_id = lib.get_id_from_sibling(node, history_only=False) + sibling_id = \ + lib.get_id_from_sibling(node, + history_only=cls.allow_history_only) if not sibling_id: cls.log.error("Could not find ID in siblings for '%s'", node) continue diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json index 7c9a5a6b46..0c82997cce 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json @@ -396,6 +396,26 @@ "label": "Validate Rig Controllers" } ] + }, + { + "type": "dict", + "collapsible": true, + "checkbox_key": "enabled", + "key": "ValidateRigOutSetNodeIds", + "label": "Validate Rig Out Set Node Ids", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "allow_history_only", + "label": "Allow history only" + } + ] } ] }, From acd86c30914f1a2e52dcd3e2f3c9a63d9b3be7d7 Mon Sep 17 00:00:00 2001 From: Derek Severin Date: Thu, 3 Mar 2022 16:25:38 +0700 Subject: [PATCH 04/13] Full attribute name for readability --- openpype/hosts/maya/api/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 2f7a09d4c4..c9e10c7041 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -1807,7 +1807,7 @@ def get_id_from_sibling(node, history_only=True): for similar_node in similar_nodes: # Check if "intermediate object" - if cmds.getAttr(similar_node + ".io"): + if cmds.getAttr(similar_node + ".intermediateObject"): _id = get_id(similar_node) if _id: return _id From cd498441a6aa86d02cc2deb8be6c33102797e1ff Mon Sep 17 00:00:00 2001 From: Derek Severin Date: Thu, 3 Mar 2022 16:55:40 +0700 Subject: [PATCH 05/13] Code style fix --- .../publish/validate_rig_out_set_node_ids.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/validate_rig_out_set_node_ids.py b/openpype/hosts/maya/plugins/publish/validate_rig_out_set_node_ids.py index c272c5c485..ed1d36261a 100644 --- a/openpype/hosts/maya/plugins/publish/validate_rig_out_set_node_ids.py +++ b/openpype/hosts/maya/plugins/publish/validate_rig_out_set_node_ids.py @@ -52,9 +52,10 @@ class ValidateRigOutSetNodeIds(pyblish.api.InstancePlugin): noIntermediate=True) for shape in shapes: - sibling_id = \ - lib.get_id_from_sibling(shape, - history_only=cls.allow_history_only) + sibling_id = lib.get_id_from_sibling( + shape, + history_only=cls.allow_history_only + ) if sibling_id: current_id = lib.get_id(shape) if current_id != sibling_id: @@ -67,9 +68,10 @@ class ValidateRigOutSetNodeIds(pyblish.api.InstancePlugin): for node in cls.get_invalid(instance): # Get the original id from sibling - sibling_id = \ - lib.get_id_from_sibling(node, - history_only=cls.allow_history_only) + sibling_id = lib.get_id_from_sibling( + node, + history_only=cls.allow_history_only + ) if not sibling_id: cls.log.error("Could not find ID in siblings for '%s'", node) continue From 4ba40f2a175ec78ac8371dbf62ea2a3eeb61998b Mon Sep 17 00:00:00 2001 From: Derek Severin Date: Thu, 3 Mar 2022 17:48:40 +0700 Subject: [PATCH 06/13] Exact type for siblings --- openpype/hosts/maya/api/lib.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index c9e10c7041..bbd7786b36 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -1802,6 +1802,8 @@ def get_id_from_sibling(node, history_only=True): similar_nodes = cmds.listRelatives(parent, type=node_type, fullPath=True) + similar_nodes = cmds.ls(similar_nodes, exactType=node_type, long=True) + # Exclude itself similar_nodes = [x for x in similar_nodes if x != node] From 024a7220fe36f8a3df60347df10873aa01a1cd6b Mon Sep 17 00:00:00 2001 From: Derek Severin Date: Thu, 3 Mar 2022 17:52:18 +0700 Subject: [PATCH 07/13] Plugin setting default value --- openpype/settings/defaults/project_settings/maya.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index a756071106..b6fa3719ef 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -351,6 +351,10 @@ "optional": true, "active": true }, + "ValidateRigOutSetNodeIds": { + "enabled": true, + "allow_history_only": false + }, "ValidateCameraAttributes": { "enabled": false, "optional": true, From 3b0cee19ba2b3f9351e87c49f690950d86587b90 Mon Sep 17 00:00:00 2001 From: Derek Severin Date: Thu, 3 Mar 2022 19:20:52 +0700 Subject: [PATCH 08/13] Adapted/corrected comment --- openpype/hosts/maya/api/lib.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index bbd7786b36..62de5a96eb 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -1757,14 +1757,16 @@ def get_id_from_sibling(node, history_only=True): The nodes in history must be of the exact same node type and must be parented under the same parent. - If no matching node is found in history, the siblings of the node - are checked. Additionally to having the same parent, the sibling must - be marked as 'intermediate object'. + Optionally, if no matching node is found from the history, all the + siblings of the node that are of the same type are checked. + Additionally to having the same parent, the sibling must be marked as + 'intermediate object'. Args: node (str): node to retrieve the history from - history_only (bool): also looks in node's siblings if True - and if nothing found in history + history_only (bool): if True and if nothing found in history, + look for an 'intermediate object' in all the node's siblings + of same type Returns: str or None: The id from the sibling node or None when no id found From db7e9cc4aa6b4fd09496139d2fff878e3606312f Mon Sep 17 00:00:00 2001 From: 2-REC Date: Wed, 16 Mar 2022 12:13:47 +0700 Subject: [PATCH 09/13] Warning log if more than 1 shape id --- openpype/hosts/maya/api/lib.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 62de5a96eb..f49c0f689e 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -1809,12 +1809,22 @@ def get_id_from_sibling(node, history_only=True): # Exclude itself similar_nodes = [x for x in similar_nodes if x != node] + first_id = None for similar_node in similar_nodes: # Check if "intermediate object" if cmds.getAttr(similar_node + ".intermediateObject"): _id = get_id(similar_node) if _id: - return _id + # Check if already found an id + if first_id: + log.warning(("Found more than 1 matching intermediate" + " shape for '{}'. Using id of first" + " found: '{}'".format(node, found_node))) + break + first_id = _id + found_node = similar_node + + return first_id From 802f8a482d6278f2184b0f38ad52fc56efb737cb Mon Sep 17 00:00:00 2001 From: 2-REC Date: Wed, 16 Mar 2022 12:16:33 +0700 Subject: [PATCH 10/13] Variable declaration --- openpype/hosts/maya/api/lib.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index f49c0f689e..e2c07624e6 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -1810,6 +1810,7 @@ def get_id_from_sibling(node, history_only=True): similar_nodes = [x for x in similar_nodes if x != node] first_id = None + found_node = None for similar_node in similar_nodes: # Check if "intermediate object" if cmds.getAttr(similar_node + ".intermediateObject"): From a11fe7a5503c993b53c72c16eb306d3447ead29a Mon Sep 17 00:00:00 2001 From: 2-REC Date: Wed, 16 Mar 2022 16:38:17 +0700 Subject: [PATCH 11/13] Fix to allow more than 1 shape with same ids --- openpype/hosts/maya/api/lib.py | 40 ++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index b46eff5a4b..f0f6bb706f 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -1989,23 +1989,35 @@ def get_id_from_sibling(node, history_only=True): # Exclude itself similar_nodes = [x for x in similar_nodes if x != node] - first_id = None - found_node = None + + # Get all unique ids from siblings in order since + # we consistently take the first one found + sibling_ids = OrderedDict() for similar_node in similar_nodes: # Check if "intermediate object" - if cmds.getAttr(similar_node + ".intermediateObject"): - _id = get_id(similar_node) - if _id: - # Check if already found an id - if first_id: - log.warning(("Found more than 1 matching intermediate" - " shape for '{}'. Using id of first" - " found: '{}'".format(node, found_node))) - break - first_id = _id - found_node = similar_node + if not cmds.getAttr(similar_node + ".intermediateObject"): + continue - return first_id + _id = get_id(similar_node) + if not _id: + continue + + if _id in sibling_ids: + sibling_ids[_id].append(similar_node) + else: + sibling_ids[_id] = [similar_node] + + if sibling_ids: + first_id, found_nodes = next(iter(sibling_ids.items())) + + # Log a warning if we've found multiple unique ids + if len(sibling_ids) > 1: + log.warning(("Found more than 1 intermediate shape with" + " unique id for '{}'. Using id of first" + " found: '{}'".format(node, found_nodes[0]))) + break + + return first_id From 9e4a3cf9504ebbb09c30d3c1d2bcd772eed1cf4d Mon Sep 17 00:00:00 2001 From: 2-REC Date: Wed, 16 Mar 2022 16:41:27 +0700 Subject: [PATCH 12/13] Distraction fix... --- openpype/hosts/maya/api/lib.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index f0f6bb706f..f7507d87c5 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -1989,7 +1989,6 @@ def get_id_from_sibling(node, history_only=True): # Exclude itself similar_nodes = [x for x in similar_nodes if x != node] - # Get all unique ids from siblings in order since # we consistently take the first one found sibling_ids = OrderedDict() @@ -2015,7 +2014,6 @@ def get_id_from_sibling(node, history_only=True): log.warning(("Found more than 1 intermediate shape with" " unique id for '{}'. Using id of first" " found: '{}'".format(node, found_nodes[0]))) - break return first_id From 8af535adba3303ae759638f9933cb68ec46517bb Mon Sep 17 00:00:00 2001 From: 2-REC Date: Wed, 16 Mar 2022 18:09:50 +0700 Subject: [PATCH 13/13] More adapted error message --- .../publish/validate_animation_out_set_related_node_ids.py | 4 ++-- .../maya/plugins/publish/validate_rig_out_set_node_ids.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/validate_animation_out_set_related_node_ids.py b/openpype/hosts/maya/plugins/publish/validate_animation_out_set_related_node_ids.py index 7c1c695237..05d63f1d56 100644 --- a/openpype/hosts/maya/plugins/publish/validate_animation_out_set_related_node_ids.py +++ b/openpype/hosts/maya/plugins/publish/validate_animation_out_set_related_node_ids.py @@ -32,8 +32,8 @@ class ValidateOutRelatedNodeIds(pyblish.api.InstancePlugin): # if a deformer has been created on the shape invalid = self.get_invalid(instance) if invalid: - raise RuntimeError("Nodes found with non-related " - "asset IDs: {0}".format(invalid)) + raise RuntimeError("Nodes found with mismatching " + "IDs: {0}".format(invalid)) @classmethod def get_invalid(cls, instance): diff --git a/openpype/hosts/maya/plugins/publish/validate_rig_out_set_node_ids.py b/openpype/hosts/maya/plugins/publish/validate_rig_out_set_node_ids.py index ed1d36261a..cc3723a6e1 100644 --- a/openpype/hosts/maya/plugins/publish/validate_rig_out_set_node_ids.py +++ b/openpype/hosts/maya/plugins/publish/validate_rig_out_set_node_ids.py @@ -33,8 +33,8 @@ class ValidateRigOutSetNodeIds(pyblish.api.InstancePlugin): # if a deformer has been created on the shape invalid = self.get_invalid(instance) if invalid: - raise RuntimeError("Nodes found with non-related " - "asset IDs: {0}".format(invalid)) + raise RuntimeError("Nodes found with mismatching " + "IDs: {0}".format(invalid)) @classmethod def get_invalid(cls, instance):