Skip to content

validate_rig_output_ids

ValidateRigOutputIds

Bases: MayaInstancePlugin

Validate rig output ids.

Ids must share the same id as similarly named nodes in the scene. This is to ensure the id from the model is preserved through animation.

Source code in client/ayon_maya/plugins/publish/validate_rig_output_ids.py
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
class ValidateRigOutputIds(plugin.MayaInstancePlugin):
    """Validate rig output ids.

    Ids must share the same id as similarly named nodes in the scene. This is
    to ensure the id from the model is preserved through animation.

    """
    order = ValidateContentsOrder + 0.05
    label = "Rig Output Ids"
    families = ["rig"]
    actions = [RepairAction,
               ayon_maya.api.action.SelectInvalidAction]

    @classmethod
    def apply_settings(cls, project_settings):
        # Disable plug-in if cbId workflow is disabled
        if not project_settings["maya"].get("use_cbid_workflow", True):
            cls.enabled = False
            return

    def process(self, instance):
        invalid = self.get_invalid(instance, compute=True)
        if invalid:
            raise PublishValidationError("Found nodes with mismatched IDs.")

    @classmethod
    def get_invalid(cls, instance, compute=False):
        invalid_matches = cls.get_invalid_matches(instance, compute=compute)
        return list(invalid_matches.keys())

    @classmethod
    def get_invalid_matches(cls, instance, compute=False):
        invalid = {}

        if compute:
            out_set = cls.get_node(instance)
            if not out_set:
                instance.data["mismatched_output_ids"] = invalid
                return invalid

            instance_nodes = cmds.sets(out_set, query=True, nodesOnly=True)
            instance_nodes = cmds.ls(instance_nodes, long=True)
            for node in instance_nodes:
                shapes = cmds.listRelatives(node, shapes=True, fullPath=True)
                if shapes:
                    instance_nodes.extend(shapes)

            scene_nodes = cmds.ls(type="transform", long=True)
            scene_nodes += cmds.ls(type="mesh", long=True)
            scene_nodes = set(scene_nodes) - set(instance_nodes)

            scene_nodes_by_basename = defaultdict(list)
            for node in scene_nodes:
                basename = get_basename(node)
                scene_nodes_by_basename[basename].append(node)

            for instance_node in instance_nodes:
                basename = get_basename(instance_node)
                if basename not in scene_nodes_by_basename:
                    continue

                matches = scene_nodes_by_basename[basename]

                ids = set(get_id(node) for node in matches)
                ids.add(get_id(instance_node))

                if len(ids) > 1:
                    cls.log.error(
                        "\"{}\" id mismatch to: {}".format(
                            instance_node, matches
                        )
                    )
                    invalid[instance_node] = matches

            instance.data["mismatched_output_ids"] = invalid
        else:
            invalid = instance.data["mismatched_output_ids"]

        return invalid

    @classmethod
    def repair(cls, instance):
        invalid_matches = cls.get_invalid_matches(instance)

        multiple_ids_match = []
        for instance_node, matches in invalid_matches.items():
            ids = set(get_id(node) for node in matches)

            # If there are multiple scene ids matched, and error needs to be
            # raised for manual correction.
            if len(ids) > 1:
                multiple_ids_match.append({"node": instance_node,
                                           "matches": matches})
                continue

            id_to_set = next(iter(ids))
            set_id(instance_node, id_to_set, overwrite=True)

        if multiple_ids_match:
            raise PublishValidationError(
                "Multiple matched ids found. Please repair manually: "
                "{}".format(multiple_ids_match)
            )

    @classmethod
    def get_node(cls, instance):
        """Get target object nodes from out_SET

        Args:
            instance (str): instance

        Returns:
            list: list of object nodes from out_SET
        """
        return instance.data["rig_sets"].get("out_SET")

get_node(instance) classmethod

Get target object nodes from out_SET

Parameters:

Name Type Description Default
instance str

instance

required

Returns:

Name Type Description
list

list of object nodes from out_SET

Source code in client/ayon_maya/plugins/publish/validate_rig_output_ids.py
123
124
125
126
127
128
129
130
131
132
133
@classmethod
def get_node(cls, instance):
    """Get target object nodes from out_SET

    Args:
        instance (str): instance

    Returns:
        list: list of object nodes from out_SET
    """
    return instance.data["rig_sets"].get("out_SET")

ValidateSkeletonRigOutputIds

Bases: ValidateRigOutputIds

Validate rig output ids from the skeleton sets.

Ids must share the same id as similarly named nodes in the scene. This is to ensure the id from the model is preserved through animation.

Source code in client/ayon_maya/plugins/publish/validate_rig_output_ids.py
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
class ValidateSkeletonRigOutputIds(ValidateRigOutputIds):
    """Validate rig output ids from the skeleton sets.

    Ids must share the same id as similarly named nodes in the scene. This is
    to ensure the id from the model is preserved through animation.

    """
    order = ValidateContentsOrder + 0.05
    label = "Skeleton Rig Output Ids"
    hosts = ["maya"]
    families = ["rig.fbx"]

    @classmethod
    def get_node(cls, instance):
        """Get target object nodes from skeletonMesh_SET

        Args:
            instance (str): instance

        Returns:
            list: list of object nodes from skeletonMesh_SET
        """
        return instance.data["rig_sets"].get("skeletonMesh_SET")

get_node(instance) classmethod

Get target object nodes from skeletonMesh_SET

Parameters:

Name Type Description Default
instance str

instance

required

Returns:

Name Type Description
list

list of object nodes from skeletonMesh_SET

Source code in client/ayon_maya/plugins/publish/validate_rig_output_ids.py
148
149
150
151
152
153
154
155
156
157
158
@classmethod
def get_node(cls, instance):
    """Get target object nodes from skeletonMesh_SET

    Args:
        instance (str): instance

    Returns:
        list: list of object nodes from skeletonMesh_SET
    """
    return instance.data["rig_sets"].get("skeletonMesh_SET")

get_basename(node)

Return node short name without namespace

Source code in client/ayon_maya/plugins/publish/validate_rig_output_ids.py
14
15
16
def get_basename(node):
    """Return node short name without namespace"""
    return node.rsplit("|", 1)[-1].rsplit(":", 1)[-1]