diff --git a/colorbleed/maya/__init__.py b/colorbleed/maya/__init__.py index 94f315faee..2a28f61684 100644 --- a/colorbleed/maya/__init__.py +++ b/colorbleed/maya/__init__.py @@ -97,11 +97,7 @@ def on_save(_): avalon.logger.info("Running callback on save..") - types = ["objectSet", "file", "mesh", "nurbsCurve", "nurbsSurface"] - type_nodes = set(cmds.ls(type=types, long=True)) - nodes = lib.filter_out_nodes(type_nodes, - defaults=True, - referenced_nodes=True) + nodes = lib.get_id_required_nodes(referenced_nodes=False) # Lead with asset ID from the database asset = os.environ["AVALON_ASSET"] @@ -111,5 +107,4 @@ def on_save(_): # generate the ids for node in nodes: - print node _set_uuid(str(asset_id["_id"]), node) diff --git a/colorbleed/maya/lib.py b/colorbleed/maya/lib.py index 343847a4fb..8b7d04ef87 100644 --- a/colorbleed/maya/lib.py +++ b/colorbleed/maya/lib.py @@ -595,55 +595,45 @@ def maya_temp_folder(): return tmp_dir -def remap_resource_nodes(resources, folder=None): - - log.info("Updating resource nodes ...") - for resource in resources: - source = resource["source"] - if folder: - fname = os.path.basename(source) - fpath = os.path.join(folder, fname) - else: - fpath = source - - node_attr = resource["attribute"] - cmds.setAttr(node_attr, fpath, type="string") - - log.info("Saving file ...") - cmds.file(save=True, type="mayaAscii") - - -def filter_out_nodes(nodes, defaults=False, referenced_nodes=False): +def get_id_required_nodes(referenced_nodes=False): """Filter out any node which are locked (reference) or readOnly Args: - nodes (set): nodes to filter - locked (bool): set True to filter out lockedNodes - readonly (bool): set True to filter out readOnly + referenced_nodes (bool): set True to filter out reference nodes Returns: - nodes (list): list of filtered nodes + nodes (set): list of filtered nodes """ - # establish set of nodes to ignore + # `readOnly` flag is obsolete as of Maya 2016 therefor we explicitly remove # default nodes and reference nodes + camera_shapes = ["frontShape", "sideShape", "topShape", "perspShape"] ignore = set() - if referenced_nodes: - ignore |= set(cmds.ls(long=True, referencedNodes=referenced_nodes)) + if not referenced_nodes: + ignore |= set(cmds.ls(long=True, referencedNodes=True)) - if defaults: - ignore |= set(cmds.ls(long=True, defaultNodes=defaults)) + # list all defaultNodes to filter out from the rest + ignore |= set(cmds.ls(long=True, defaultNodes=True)) + ignore |= set(cmds.ls(camera_shapes, long=True)) + + # establish set of nodes to ignore + types = ["objectSet", "file", "mesh", "nurbsCurve", "nurbsSurface"] + + # We *always* ignore intermediate shapes, so we filter them out + # directly + nodes = cmds.ls(type=types, long=True, noIntermediate=True) # The items which need to pass the id to their parent # Add the collected transform to the nodes - dag = cmds.ls(list(nodes), - type="dagNode", - long=True) # query only dag nodes + dag = cmds.ls(nodes, type="dagNode", long=True) # query only dag nodes + transforms = cmds.listRelatives(dag, parent=True, fullPath=True) or [] + nodes = set(nodes) nodes |= set(transforms) + nodes -= ignore # Remove the ignored nodes return nodes @@ -663,14 +653,10 @@ def get_id(node): if node is None: return - try: - attr = "{}.cbId".format(node) - attribute_value = cmds.getAttr(attr) - except Exception as e: - log.debug(e) + if not cmds.attributeQuery("cbId", node=node, exists=True): return - return attribute_value + return cmds.getAttr("{}.cbId".format(node)) def get_representation_file(representation, template=TEMPLATE): @@ -910,7 +896,7 @@ def apply_shaders(relationships, shadernodes, nodes): """ attributes = relationships.get("attributes", []) - shader_sets = relationships.get("sets", []) + shader_data = relationships.get("relationships", {}) shading_engines = cmds.ls(shadernodes, type="objectSet", long=True) assert len(shading_engines) > 0, ("Error in retrieving objectSets " @@ -927,10 +913,10 @@ def apply_shaders(relationships, shadernodes, nodes): # endregion # region assign - for shader_set in shader_sets: + for data in shader_data.values(): # collect all unique IDs of the set members - shader_uuid = shader_set["uuid"] - member_uuids = [member["uuid"] for member in shader_set["members"]] + shader_uuid = data["uuid"] + member_uuids = [member["uuid"] for member in data["members"]] filtered_nodes = list() for uuid in member_uuids: diff --git a/colorbleed/plugin.py b/colorbleed/plugin.py index 70b2c76c6f..84e64f6392 100644 --- a/colorbleed/plugin.py +++ b/colorbleed/plugin.py @@ -1,7 +1,5 @@ import tempfile import pyblish.api -import avalon.maya - ValidatePipelineOrder = pyblish.api.ValidatorOrder + 0.05 ValidateContentsOrder = pyblish.api.ValidatorOrder + 0.1 diff --git a/colorbleed/plugins/maya/publish/collect_look.py b/colorbleed/plugins/maya/publish/collect_look.py index d8f7ec08f9..d9f1b8067f 100644 --- a/colorbleed/plugins/maya/publish/collect_look.py +++ b/colorbleed/plugins/maya/publish/collect_look.py @@ -67,7 +67,7 @@ class CollectLook(pyblish.api.InstancePlugin): hosts = ["maya"] # Ignore specifically named sets (check with endswith) - IGNORE = ["out_SET", "controls_SET", "_INST"] + IGNORE = ["out_SET", "controls_SET", "_INST", "_CON"] def process(self, instance): """Collect the Look in the instance with the correct layer settings""" @@ -120,19 +120,20 @@ class CollectLook(pyblish.api.InstancePlugin): # Store data on the instance instance.data["lookData"] = {"attributes": attributes, - "relationships": sets.values(), - "sets": looksets} + "relationships": sets} - # Collect file nodes used by shading engines - history = cmds.listHistory(looksets) - files = cmds.ls(history, type="file", long=True) + # Collect file nodes used by shading engines (if we have any) + files = list() + if looksets: + history = cmds.listHistory(looksets) + files = cmds.ls(history, type="file", long=True) # Collect textures resources = [self.collect_resource(n) for n in files] instance.data["resources"] = resources # Log a warning when no relevant sets were retrieved for the look. - if not instance.data["lookData"]["sets"]: + if not instance.data["lookData"]["relationships"]: self.log.warning("No sets found for the nodes in the instance: " "%s" % instance[:]) @@ -168,8 +169,7 @@ class CollectLook(pyblish.api.InstancePlugin): if objset in sets: continue - sets[objset] = {"name": objset, - "uuid": lib.get_id(objset), + sets[objset] = {"uuid": lib.get_id(objset), "members": list()} return sets diff --git a/colorbleed/plugins/maya/publish/extract_look.py b/colorbleed/plugins/maya/publish/extract_look.py index 46d45400a4..eb7e7228d0 100644 --- a/colorbleed/plugins/maya/publish/extract_look.py +++ b/colorbleed/plugins/maya/publish/extract_look.py @@ -41,7 +41,7 @@ class ExtractLook(colorbleed.api.Extractor): # exported file by accident self.log.info("Extract sets (Maya ASCII) ...") lookdata = instance.data["lookData"] - sets = lookdata["sets"] + sets = lookdata["relationships"].keys() resources = instance.data["resources"] remap = {} @@ -72,7 +72,7 @@ class ExtractLook(colorbleed.api.Extractor): # Write the JSON data self.log.info("Extract json..") data = {"attributes": lookdata["attributes"], - "sets": lookdata["relationships"]} + "relationships": lookdata["relationships"]} with open(json_path, "w") as f: json.dump(data, f) diff --git a/colorbleed/plugins/maya/publish/validate_look_contents.py b/colorbleed/plugins/maya/publish/validate_look_contents.py index 1dc6a7c849..1bdd3d0aef 100644 --- a/colorbleed/plugins/maya/publish/validate_look_contents.py +++ b/colorbleed/plugins/maya/publish/validate_look_contents.py @@ -1,5 +1,8 @@ +import maya.cmds as cmds + import pyblish.api import colorbleed.api +import colorbleed.maya.lib as lib class ValidateLookContents(pyblish.api.InstancePlugin): @@ -13,32 +16,32 @@ class ValidateLookContents(pyblish.api.InstancePlugin): order = colorbleed.api.ValidateContentsOrder families = ['colorbleed.lookdev'] hosts = ['maya'] - label = 'Look Contents' + label = 'Look Data Contents' actions = [colorbleed.api.SelectInvalidAction] - invalid = [] - errors = [] - def process(self, instance): """Process all the nodes in the instance""" if not instance[:]: raise RuntimeError("Instance is empty") - self.get_invalid(instance) - - if self.errors: - error_string = "\n".join(self.errors) - raise RuntimeError("Invalid look content. " - "Errors : {}".format(error_string)) + invalid = self.get_invalid(instance) + if invalid: + raise RuntimeError("'{}' has invalid look " + "content".format(instance.name)) @classmethod def get_invalid(cls, instance): + """Get all invalid nodes""" - invalid_attr = list(cls.validate_lookdata_attributes(instance)) - invalid_rels = list(cls.validate_relationships(instance)) + cls.log.info("Validating look content for " + "'{}'".format(instance.name)) - invalid = invalid_attr + invalid_rels + instance_items = cls.validate_instance_items(instance) + attributes = list(cls.validate_lookdata_attributes(instance)) + relationships = list(cls.validate_relationship_ids(instance)) + + invalid = instance_items + attributes + relationships return invalid @@ -53,30 +56,50 @@ class ValidateLookContents(pyblish.api.InstancePlugin): invalid = set() - attributes = ["sets", "relationships", "attributes"] + attributes = ["relationships", "attributes"] lookdata = instance.data["lookData"] for attr in attributes: if attr not in lookdata: - cls.errors.append("Look Data has no attribute " - "'{}'".format(attr)) + cls.log.error("Look Data has no attribute " + "'{}'".format(attr)) invalid.add(instance.name) + # Validate at least one single relationship is collected + if not lookdata["relationships"]: + cls.log.error("Look '{}' has no " + "`relationship`".format(instance.name)) + invalid.add(instance.name) + return invalid @classmethod - def validate_relationships(cls, instance): + def validate_relationship_ids(cls, instance): """Validate and update lookData relationships""" invalid = set() relationships = instance.data["lookData"]["relationships"] - for relationship in relationships: - look_name = relationship["name"] - for key, value in relationship.items(): - if value is None: - cls.errors.append("{} has invalid attribite " - "'{}'".format(look_name, key)) - - invalid.add(look_name) + for objectset, members in relationships.items(): + uuid = members["uuid"] + if not uuid: + look_name = objectset + cls.log.error("{} has invalid ID ".format(look_name)) + invalid.add(look_name) return invalid + + @classmethod + def validate_instance_items(cls, instance): + + required_nodes = lib.get_id_required_nodes(referenced_nodes=False) + + invalid = [node for node in instance if node in required_nodes + and not lib.get_id(node)] + if invalid: + nr_of_invalid = len(invalid) + cls.log.error("Found {} nodes without ID: {}".format(nr_of_invalid, + invalid)) + return invalid + + + diff --git a/colorbleed/plugins/maya/publish/validate_look_default_shaders_connections.py b/colorbleed/plugins/maya/publish/validate_look_default_shaders_connections.py index f24011d3c9..dce90dc0df 100644 --- a/colorbleed/plugins/maya/publish/validate_look_default_shaders_connections.py +++ b/colorbleed/plugins/maya/publish/validate_look_default_shaders_connections.py @@ -1,3 +1,5 @@ +from maya import cmds + import pyblish.api import colorbleed.api @@ -20,11 +22,10 @@ class ValidateLookDefaultShadersConnections(pyblish.api.InstancePlugin): label = 'Look Default Shader Connections' # The default connections to check - DEFAULTS = [ - ("initialShadingGroup.surfaceShader", "lambert1"), - ("initialParticleSE.surfaceShader", "lambert1"), - ("initialParticleSE.volumeShader", "particleCloud1") - ] + DEFAULTS = [("initialShadingGroup.surfaceShader", "lambert1"), + ("initialParticleSE.surfaceShader", "lambert1"), + ("initialParticleSE.volumeShader", "particleCloud1") + ] def process(self, instance): @@ -33,19 +34,15 @@ class ValidateLookDefaultShadersConnections(pyblish.api.InstancePlugin): # the family is not present in an instance. key = "__validate_look_default_shaders_connections_checked" context = instance.context - is_run = context.data.get(key, - False) + is_run = context.data.get(key, False) if is_run: return else: context.data[key] = True # Process as usual - from maya import cmds - invalid = list() for plug, input_node in self.DEFAULTS: - inputs = cmds.listConnections(plug, source=True, destination=False) or None diff --git a/colorbleed/plugins/maya/publish/validate_look_members_node_ids.py b/colorbleed/plugins/maya/publish/validate_look_members_node_ids.py index 7c256f8399..9ecc8cd5fa 100644 --- a/colorbleed/plugins/maya/publish/validate_look_members_node_ids.py +++ b/colorbleed/plugins/maya/publish/validate_look_members_node_ids.py @@ -3,7 +3,7 @@ import colorbleed.api import colorbleed.maya.lib as lib -class ValidateLookMembersHaveId(pyblish.api.InstancePlugin): +class ValidateLookMembers(pyblish.api.InstancePlugin): """Validate look members have colorbleed id attributes Looks up the contents of the look to see if all its members have @@ -18,35 +18,27 @@ class ValidateLookMembersHaveId(pyblish.api.InstancePlugin): order = colorbleed.api.ValidatePipelineOrder families = ['colorbleed.lookdev'] hosts = ['maya'] - label = 'Look Members Have ID Attribute' + label = 'Look Members' actions = [colorbleed.api.SelectInvalidAction, colorbleed.api.GenerateUUIDsOnInvalidAction] def process(self, instance): """Process all meshes""" - invalid = self.get_invalid(instance) - if invalid: - raise RuntimeError("Members found without " - "asset IDs: {0}".format(invalid)) + invalid_ids = self.get_invalid(instance) + if invalid_ids: + raise RuntimeError("Found invalid nodes.\nNo ID : " + "{}".format(invalid_ids)) @classmethod def get_invalid(cls, instance): - # Get all members from the sets - members = [] - relations = instance.data["lookData"]["relationships"] - for relation in relations: - members = [member['name'] for member in relation['members']] - members.extend(members) + members = set() + relationships = instance.data["lookData"]["relationships"] + for relation in relationships.values(): + members.update([member['name'] for member in relation['members']]) - # Get all sets - members = list(set(members)) - - # Ensure all nodes have a cbId - invalid = list() - for node in members: - if not lib.get_id(node): - invalid.append(node) + invalid = [m for m in members if not lib.get_id(m)] return invalid + diff --git a/colorbleed/plugins/maya/publish/validate_look_members_unique.py b/colorbleed/plugins/maya/publish/validate_look_members_unique.py index 6d85ce5339..1dfac3f3f1 100644 --- a/colorbleed/plugins/maya/publish/validate_look_members_unique.py +++ b/colorbleed/plugins/maya/publish/validate_look_members_unique.py @@ -4,15 +4,7 @@ from maya import cmds import pyblish.api import colorbleed.api - - -def get_unique_id(node): - attr = 'cbId' - unique_id = None - has_attribute = cmds.attributeQuery(attr, node=node, exists=True) - if has_attribute: - unique_id = cmds.getAttr("{}.{}".format(node, attr)) - return unique_id +import colorbleed.maya.lib as lib class ValidateNonDuplicateRelationshipMembers(pyblish.api.InstancePlugin): @@ -43,26 +35,22 @@ class ValidateNonDuplicateRelationshipMembers(pyblish.api.InstancePlugin): # Get all members from the sets members = [] relationships = instance.data["lookData"]["relationships"] - for sg in relationships: - sg_members = [member['name'] for member in sg['members']] - members.extend(sg_members) + for relationship in relationships.values(): + members.extend([i['name'] for i in relationship['members']]) # Ensure we don't have components but the objects - members = cmds.ls(members, objectsOnly=True, long=True) - members = list(set(members)) + members = set(cmds.ls(members, objectsOnly=True, long=True)) + members = list(members) # Group members per id id_nodes = defaultdict(set) for node in members: - node_id = get_unique_id(node) + node_id = lib.get_id(node) if not node_id: continue id_nodes[node_id].add(node) - invalid = list() - for nodes in id_nodes.itervalues(): - if len(nodes) > 1: - invalid.extend(nodes) + invalid = [n for n in id_nodes.itervalues() if len(n) > 1] return invalid diff --git a/colorbleed/plugins/maya/publish/validate_look_no_default_shaders.py b/colorbleed/plugins/maya/publish/validate_look_no_default_shaders.py index 4f33e15b1c..5042d01796 100644 --- a/colorbleed/plugins/maya/publish/validate_look_no_default_shaders.py +++ b/colorbleed/plugins/maya/publish/validate_look_no_default_shaders.py @@ -37,16 +37,15 @@ class ValidateLookNoDefaultShaders(pyblish.api.InstancePlugin): "initialParticleSE", "particleCloud1"] - setmembers = instance.data["setMembers"] - members = cmds.listRelatives(setmembers, + members = cmds.listRelatives(instance, allDescendents=True, - type="shape") - + shapes=True, + noIntermediate=True) or [] for member in members: # get connection # listConnections returns a list or None - shading_engine = cmds.listConnections(member, type="shadingEngine") + shading_engine = cmds.listConnections(member, type="objectSet") if not shading_engine: cls.log.error("Detected shape without shading engine : " "'{}'".format(member)) @@ -58,6 +57,7 @@ class ValidateLookNoDefaultShaders(pyblish.api.InstancePlugin): if shading_engine in disallowed: cls.log.error("Member connected to a disallows objectSet: " "'{}'".format(member)) + invalid.append(member) else: continue @@ -66,7 +66,6 @@ class ValidateLookNoDefaultShaders(pyblish.api.InstancePlugin): def process(self, instance): """Process all the nodes in the instance""" - # sets = self.get_invalid_sets(instance) - sets = self.get_invalid(instance) - if sets: - raise RuntimeError("Invalid shaders found: {0}".format(sets)) + invalid = self.get_invalid(instance) + if invalid: + raise RuntimeError("Invalid shaders found: {0}".format(invalid)) diff --git a/colorbleed/plugins/maya/publish/validate_look_node_unique_ids.py b/colorbleed/plugins/maya/publish/validate_look_node_unique_ids.py index 251ecbf24f..fbfc007a9a 100644 --- a/colorbleed/plugins/maya/publish/validate_look_node_unique_ids.py +++ b/colorbleed/plugins/maya/publish/validate_look_node_unique_ids.py @@ -1,9 +1,9 @@ +import pprint from collections import defaultdict -import maya.cmds as cmds - import pyblish.api import colorbleed.api +import colorbleed.maya.lib as lib class ValidateLookNodeUniqueIds(pyblish.api.InstancePlugin): @@ -18,26 +18,44 @@ class ValidateLookNodeUniqueIds(pyblish.api.InstancePlugin): actions = [colorbleed.api.SelectInvalidAction, colorbleed.api.RepairAction] - @staticmethod - def get_invalid(instance): + @classmethod + def get_invalid(cls, instance): - nodes = instance.data["lookData"]["sets"] + invalid = [] + uuids_dict = defaultdict(list) - # Ensure all nodes have a cbId - id_sets = defaultdict(list) - invalid = list() - for node in nodes: - unique_id = None - if cmds.attributeQuery("cbId", node=node, exists=True): - unique_id = cmds.getAttr("{}.cbId".format(node)) - if not unique_id: - continue + relationships = instance.data["lookData"]["relationships"] + pprint.pprint(relationships) + for objectset, relationship in relationships.items(): + cls.log.info("Validating lookData for '%s'" % objectset) + # check if node has UUID and this matches with found node + for member in relationship["members"]: + node = member["name"] + member_uuid = member["uuid"] + uuid_query = lib.get_id(node) - id_sets[unique_id].append(node) + if not member_uuid: + cls.log.error("No UUID found for '{}'".format(node)) + invalid.append(node) + continue - for unique_id, nodes in id_sets.iteritems(): - if len(nodes) > 1: - invalid.extend(nodes) + if uuid_query != member_uuid: + cls.log.error("UUID in lookData does not match with " + "queried UUID of '{}'".format(node)) + invalid.append(node) + continue + + # check if the uuid has already passed through the check + # if so it means its a duplicate. + uuids_dict[objectset].append(uuid_query) + + for objectset, member_uuids in uuids_dict.items(): + stored = len(member_uuids) + unique = len(set(member_uuids)) + if unique != stored: + rel_members = relationships[objectset]["members"] + invalid.extend([i["name"] for i in rel_members if + i["uuid"] not in unique]) return invalid @@ -46,5 +64,7 @@ class ValidateLookNodeUniqueIds(pyblish.api.InstancePlugin): invalid = self.get_invalid(instance) if invalid: - raise RuntimeError("Nodes found without " - "asset IDs: {0}".format(invalid)) + for item in invalid: + self.log.error("Invalid node : %s" % item) + raise RuntimeError("Nodes found without unique " + "IDs, see records") diff --git a/colorbleed/plugins/maya/publish/validate_look_single_shader.py b/colorbleed/plugins/maya/publish/validate_look_single_shader.py new file mode 100644 index 0000000000..1d780bc302 --- /dev/null +++ b/colorbleed/plugins/maya/publish/validate_look_single_shader.py @@ -0,0 +1,61 @@ +from maya import cmds + +import pyblish.api +import colorbleed.api + + +class ValidateSingleShader(pyblish.api.InstancePlugin): + """Validate default shaders in the scene have their default connections. + + For example the lambert1 could potentially be disconnected from the + initialShadingGroup. As such it's not lambert1 that will be identified + as the default shader which can have unpredictable results. + + To fix the default connections need to be made again. See the logs for + more details on which connections are missing. + + """ + + order = colorbleed.api.ValidateContentsOrder + families = ['colorbleed.lookdev'] + hosts = ['maya'] + label = 'Look Single Shader Per Shape' + + # The default connections to check + def process(self, instance): + + invalid = self.get_invalid(instance) + if invalid: + raise RuntimeError("Found shapes which have multiple " + "shadingEngines connected." + "\n{}".format(invalid)) + + @classmethod + def get_invalid(cls, instance): + invalid = [] + shape_types = ["numrbsCurve", "nurbsSurface", "mesh"] + + # Get all shapes from the instance + shapes = set() + for node in instance[:]: + + nodetype = cmds.nodeType(node) + if nodetype in shape_types: + shapes.add(node) + + elif nodetype == "transform": + shape = cmds.listRelatives(node, children=True, + type="shape", fullPath=True) + if not shape: + continue + shapes.add(shape[0]) + + # Check the number of connected shadingEngines per shape + for shape in shapes: + shading_engines = cmds.listConnections(shape, + destination=True, + type="shadingEngine") or [] + if len(shading_engines) > 1: + invalid.append(shape) + + return invalid diff --git a/colorbleed/plugins/maya/publish/validate_no_animation.py b/colorbleed/plugins/maya/publish/validate_no_animation.py index 6c57183d31..8b0da47d89 100644 --- a/colorbleed/plugins/maya/publish/validate_no_animation.py +++ b/colorbleed/plugins/maya/publish/validate_no_animation.py @@ -20,11 +20,16 @@ class ValidateNoAnimation(pyblish.api.Validator): optional = True actions = [colorbleed.api.SelectInvalidAction] + def process(self, instance): + + invalid = self.get_invalid(instance) + if invalid: + raise RuntimeError("Keyframes found: {0}".format(invalid)) + @staticmethod def get_invalid(instance): nodes = instance[:] - if not nodes: return [] @@ -33,10 +38,3 @@ class ValidateNoAnimation(pyblish.api.Validator): return list(set(cmds.listConnections(curves))) return [] - - def process(self, instance): - - invalid = self.get_invalid(instance) - - if invalid: - raise RuntimeError("Keyframes found: {0}".format(invalid)) diff --git a/colorbleed/plugins/maya/publish/validate_node_ids.py b/colorbleed/plugins/maya/publish/validate_node_ids.py index 37e0bda5c9..733af05d4f 100644 --- a/colorbleed/plugins/maya/publish/validate_node_ids.py +++ b/colorbleed/plugins/maya/publish/validate_node_ids.py @@ -1,5 +1,3 @@ -import maya.cmds as cmds - import pyblish.api import colorbleed.api @@ -12,7 +10,7 @@ class ValidateNodeIDs(pyblish.api.InstancePlugin): """ order = colorbleed.api.ValidatePipelineOrder - label = 'Node Ids (ID)' + label = 'Instance Nodes Have ID' hosts = ['maya'] families = ["colorbleed.model", "colorbleed.lookdev", @@ -33,19 +31,11 @@ class ValidateNodeIDs(pyblish.api.InstancePlugin): @classmethod def get_invalid(cls, instance): """Return the member nodes that are invalid""" - invalid = list() - # TODO: Implement check on only nodes like on_save callback. - instance_shape = cmds.ls(instance, type="shape") - - # We do want to check the referenced nodes as we it might be + # We do want to check the referenced nodes as it might be # part of the end product - nodes = lib.filter_out_nodes(set(instance_shape), defaults=True) - for node in nodes: - if not lib.get_id(node): - invalid.append(node) + id_nodes = lib.get_id_required_nodes(referenced_nodes=True) + invalid = [n for n in instance[:] if n in id_nodes + and not lib.get_id(n)] return invalid - - - diff --git a/colorbleed/plugins/maya/publish/validate_node_ids_related.py b/colorbleed/plugins/maya/publish/validate_node_ids_related.py new file mode 100644 index 0000000000..84c28c6427 --- /dev/null +++ b/colorbleed/plugins/maya/publish/validate_node_ids_related.py @@ -0,0 +1,59 @@ +import pyblish.api +import colorbleed.api + +import avalon.io as io + +from colorbleed.maya import lib + + +class ValidateNodeIDsRelated(pyblish.api.InstancePlugin): + """Validate nodes have a related Colorbleed Id to the instance asset + + """ + + order = colorbleed.api.ValidatePipelineOrder + label = 'Node Ids Related (ID)' + hosts = ['maya'] + families = ["colorbleed.model", + "colorbleed.lookdev", + "colorbleed.rig"] + + actions = [colorbleed.api.SelectInvalidAction, + colorbleed.api.GenerateUUIDsOnInvalidAction] + + def process(self, instance): + """Process all nodes in instance (including hierarchy)""" + # Ensure all nodes have a cbId + invalid = self.get_invalid(instance) + if invalid: + raise RuntimeError("Nodes IDs found that are not related to asset " + "'{}' : {}".format(instance.data['asset'], + invalid)) + + @classmethod + def get_invalid(cls, instance): + """Return the member nodes that are invalid""" + invalid = list() + + asset = instance.data['asset'] + asset_data = io.find_one({"name": asset, + "type": "asset"}, + projection={"_id": True}) + asset_id = str(asset_data['_id']) + + # We do want to check the referenced nodes as we it might be + # part of the end product + for node in instance: + + _id = lib.get_id(node) + if not _id: + continue + + node_asset_id = _id.split(":", 1)[0] + if node_asset_id != asset_id: + invalid.append(node) + + return invalid + + + diff --git a/colorbleed/plugins/maya/publish/validate_rig_contents.py b/colorbleed/plugins/maya/publish/validate_rig_contents.py index 3ef1220e56..d07fafe362 100644 --- a/colorbleed/plugins/maya/publish/validate_rig_contents.py +++ b/colorbleed/plugins/maya/publish/validate_rig_contents.py @@ -100,7 +100,6 @@ class ValidateRigContents(pyblish.api.InstancePlugin): """ errors = [] for node in nodes: - print node if node not in hierarchy: errors.append(node) return errors