From 06e55d533a28a9905e3563eda382292d64a34587 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Wed, 13 Nov 2019 11:59:22 +0100 Subject: [PATCH] added plugins from 3de --- .../global/publish/collect_scene_version.py | 2 +- .../maya/publish/validate_assembly_name.py | 50 ++++++++++ .../maya/publish/validate_model_name.py | 98 +++++++++++++++++++ .../maya/publish/validate_shader_name.py | 78 +++++++++++++++ 4 files changed, 227 insertions(+), 1 deletion(-) create mode 100644 pype/plugins/maya/publish/validate_assembly_name.py create mode 100644 pype/plugins/maya/publish/validate_model_name.py create mode 100644 pype/plugins/maya/publish/validate_shader_name.py diff --git a/pype/plugins/global/publish/collect_scene_version.py b/pype/plugins/global/publish/collect_scene_version.py index 0d76015909..2844a695e2 100644 --- a/pype/plugins/global/publish/collect_scene_version.py +++ b/pype/plugins/global/publish/collect_scene_version.py @@ -24,4 +24,4 @@ class CollectSceneVersion(pyblish.api.ContextPlugin): rootVersion = pype.get_version_from_path(filename) context.data['version'] = rootVersion - self.log.info('Scene Version: %s' % context.data('version')) + self.log.info('Scene Version: %s' % context.data.get('version')) diff --git a/pype/plugins/maya/publish/validate_assembly_name.py b/pype/plugins/maya/publish/validate_assembly_name.py new file mode 100644 index 0000000000..2a3a92e950 --- /dev/null +++ b/pype/plugins/maya/publish/validate_assembly_name.py @@ -0,0 +1,50 @@ +import pyblish.api +import maya.cmds as cmds +import pype.maya.action + + +class ValidateAssemblyName(pyblish.api.InstancePlugin): + """ Ensure Assembly name ends with `GRP` + + Check if assembly name ends with `_GRP` string. + """ + + label = "Validate Assembly Name" + order = pyblish.api.ValidatorOrder + families = ["assembly"] + actions = [pype.maya.action.SelectInvalidAction] + active = False + + @classmethod + def get_invalid(cls, instance): + cls.log.info("Checking name of {}".format(instance.name)) + + content_instance = instance.data.get("setMembers", None) + if not content_instance: + cls.log.error("Instance has no nodes!") + return True + + # All children will be included in the extracted export so we also + # validate *all* descendents of the set members and we skip any + # intermediate shapes + descendants = cmds.listRelatives(content_instance, + allDescendents=True, + fullPath=True) or [] + descendants = cmds.ls(descendants, noIntermediate=True, long=True) + content_instance = list(set(content_instance + descendants)) + assemblies = cmds.ls(content_instance, assemblies=True, long=True) + + invalid = [] + for cr in assemblies: + if not cr.endswith('_GRP'): + cls.log.error("{} doesn't end with _GRP".format(cr)) + invalid.append(cr) + + return invalid + + def process(self, instance): + + invalid = self.get_invalid(instance) + if invalid: + raise RuntimeError("Found {} invalid named assembly " + "items".format(len(invalid))) diff --git a/pype/plugins/maya/publish/validate_model_name.py b/pype/plugins/maya/publish/validate_model_name.py new file mode 100644 index 0000000000..89c629c5a4 --- /dev/null +++ b/pype/plugins/maya/publish/validate_model_name.py @@ -0,0 +1,98 @@ +from maya import cmds +import pyblish.api +import pype.api +import pype.maya.action +import re + + +class ValidateModelName(pyblish.api.InstancePlugin): + """Validate name of model + + starts with (somename)_###_(materialID)_GEO + materialID must be present in list + padding number doesn't have limit + + """ + optional = True + order = pype.api.ValidateContentsOrder + hosts = ["maya"] + families = ["model"] + label = "Model Name" + actions = [pype.maya.action.SelectInvalidAction] + # path to shader names definitions + # TODO: move it to preset file + material_file = None + active = False + regex = '(.*)_(\\d)*_(.*)_(GEO)' + + @classmethod + def get_invalid(cls, instance): + + # find out if supplied transform is group or not + def is_group(groupName): + try: + children = cmds.listRelatives(groupName, children=True) + for child in children: + if not cmds.ls(child, transforms=True): + return False + return True + except: + return False + + invalid = [] + content_instance = instance.data.get("setMembers", None) + if not content_instance: + cls.log.error("Instance has no nodes!") + return True + pass + descendants = cmds.listRelatives(content_instance, + allDescendents=True, + fullPath=True) or [] + + descendants = cmds.ls(descendants, noIntermediate=True, long=True) + trns = cmds.ls(descendants, long=False, type=('transform')) + + # filter out groups + filter = [node for node in trns if not is_group(node)] + + # load shader list file as utf-8 + if cls.material_file: + shader_file = open(cls.material_file, "r") + shaders = shader_file.readlines() + shader_file.close() + + # strip line endings from list + shaders = map(lambda s: s.rstrip(), shaders) + + # compile regex for testing names + r = re.compile(cls.regex) + + for obj in filter: + m = r.match(obj) + if m is None: + cls.log.error("invalid name on: {}".format(obj)) + invalid.append(obj) + else: + # if we have shader files and shader named group is in + # regex, test this group against names in shader file + if 'shader' in r.groupindex and shaders: + try: + if not m.group('shader') in shaders: + cls.log.error( + "invalid materialID on: {0} ({1})".format( + obj, m.group('shader'))) + invalid.append(obj) + except IndexError: + # shader named group doesn't match + cls.log.error( + "shader group doesn't match: {}".format(obj)) + invalid.append(obj) + + return invalid + + def process(self, instance): + + invalid = self.get_invalid(instance) + + if invalid: + raise RuntimeError("Model naming is invalid. See log.") diff --git a/pype/plugins/maya/publish/validate_shader_name.py b/pype/plugins/maya/publish/validate_shader_name.py new file mode 100644 index 0000000000..c6f72a2940 --- /dev/null +++ b/pype/plugins/maya/publish/validate_shader_name.py @@ -0,0 +1,78 @@ +from maya import cmds + +import pyblish.api +import pype.api +import pype.maya.action +import re + + +class ValidateShaderName(pyblish.api.InstancePlugin): + """Validate shader name assigned. + + It should be _<*>_SHD + + """ + optional = True + active = False + order = pype.api.ValidateContentsOrder + families = ["look"] + hosts = ['maya'] + label = 'Validate Shaders Name' + actions = [pype.maya.action.SelectInvalidAction] + regex = r'(?P.*)_(.*)_SHD' + + # The default connections to check + def process(self, instance): + + invalid = self.get_invalid(instance) + if invalid: + raise RuntimeError("Found shapes with invalid shader names " + "assigned: " + "\n{}".format(invalid)) + + @classmethod + def get_invalid(cls, instance): + + invalid = [] + + # Get all shapes from the instance + content_instance = instance.data.get("setMembers", None) + if not content_instance: + cls.log.error("Instance has no nodes!") + return True + pass + descendants = cmds.listRelatives(content_instance, + allDescendents=True, + fullPath=True) or [] + + descendants = cmds.ls(descendants, noIntermediate=True, long=True) + shapes = cmds.ls(descendants, type=["nurbsSurface", "mesh"], long=True) + asset_name = instance.data.get("asset", None) + + # Check the number of connected shadingEngines per shape + r = re.compile(cls.regex) + for shape in shapes: + shading_engines = cmds.listConnections(shape, + destination=True, + type="shadingEngine") or [] + shaders = cmds.ls( + cmds.listConnections(shading_engines), materials=1 + ) + + for shader in shaders: + m = r.match(cls.regex, shader) + if m is None: + invalid.append(shape) + cls.log.error( + "object {0} has invalid shader name {1}".format(shape, + shader) + ) + else: + if 'asset' in r.groupindex: + if m.group('asset') != asset_name: + invalid.append(shape) + cls.log.error(("object {0} has invalid " + "shader name {1}").format(shape, + shader)) + + return invalid