From 0adcf3334ad5a119341132c777540a22a5f51f30 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 13 Sep 2021 13:35:24 +0200 Subject: [PATCH 1/4] Added new InventoryAction to import (localize) reference in Maya PYPE-1399 --- openpype/hosts/maya/api/__init__.py | 1 + .../plugins/inventory/import_reference.py | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 openpype/hosts/maya/plugins/inventory/import_reference.py diff --git a/openpype/hosts/maya/api/__init__.py b/openpype/hosts/maya/api/__init__.py index 9219da407f..1c8534d9a5 100644 --- a/openpype/hosts/maya/api/__init__.py +++ b/openpype/hosts/maya/api/__init__.py @@ -35,6 +35,7 @@ def install(): pyblish.register_plugin_path(PUBLISH_PATH) avalon.register_plugin_path(avalon.Loader, LOAD_PATH) avalon.register_plugin_path(avalon.Creator, CREATE_PATH) + avalon.register_plugin_path(avalon.InventoryAction, INVENTORY_PATH) log.info(PUBLISH_PATH) menu.install() diff --git a/openpype/hosts/maya/plugins/inventory/import_reference.py b/openpype/hosts/maya/plugins/inventory/import_reference.py new file mode 100644 index 0000000000..d389c8733e --- /dev/null +++ b/openpype/hosts/maya/plugins/inventory/import_reference.py @@ -0,0 +1,27 @@ +from maya import cmds + +from avalon import api + + +class ImportReference(api.InventoryAction): + """Imports selected reference inside the file.""" + + label = "Import Reference" + icon = "mouse-pointer" + color = "#d8d8d8" + + def process(self, containers): + references = cmds.ls(type="reference") + + for container in containers: + if container["loader"] != "ReferenceLoader": + print("Not a reference, skipping") + continue + + reference_name = container["namespace"] + "RN" + if reference_name in references: + print("Importing {}".format(reference_name)) + + ref_file = cmds.referenceQuery(reference_name, f=True) + + cmds.file(ref_file, importReference=True) From dfa3f76d2c71975ebcd26335f6d6077968ae0be1 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 13 Sep 2021 13:46:37 +0200 Subject: [PATCH 2/4] Added return to force refresh of SceneInventory window --- openpype/hosts/maya/plugins/inventory/import_reference.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/hosts/maya/plugins/inventory/import_reference.py b/openpype/hosts/maya/plugins/inventory/import_reference.py index d389c8733e..ac97096ee7 100644 --- a/openpype/hosts/maya/plugins/inventory/import_reference.py +++ b/openpype/hosts/maya/plugins/inventory/import_reference.py @@ -25,3 +25,5 @@ class ImportReference(api.InventoryAction): ref_file = cmds.referenceQuery(reference_name, f=True) cmds.file(ref_file, importReference=True) + + return "refresh" From 32d65315a0c9fb3f900fd1c3bae10510074fee8f Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 14 Sep 2021 15:54:48 +0200 Subject: [PATCH 3/4] Changed how reference nodes are resolved Added get_reference_node as public api method --- openpype/hosts/maya/api/plugin.py | 93 ++++++++++--------- .../plugins/inventory/import_reference.py | 20 ++-- 2 files changed, 60 insertions(+), 53 deletions(-) diff --git a/openpype/hosts/maya/api/plugin.py b/openpype/hosts/maya/api/plugin.py index 121f7a08a7..448cb814d9 100644 --- a/openpype/hosts/maya/api/plugin.py +++ b/openpype/hosts/maya/api/plugin.py @@ -4,6 +4,53 @@ import avalon.maya from openpype.api import PypeCreatorMixin +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. + + """ + + from maya import cmds + + # 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: + from openpype.lib import PypeLogger + + log = PypeLogger().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 @@ -109,7 +156,7 @@ class ReferenceLoader(api.Loader): loader=self.__class__.__name__ )) else: - ref_node = self._get_reference_node(nodes) + ref_node = get_reference_node(nodes, self.log) loaded_containers.append(containerise( name=name, namespace=namespace, @@ -126,46 +173,6 @@ class ReferenceLoader(api.Loader): """To be implemented by subclass""" raise NotImplementedError("Must be implemented by subclass") - def _get_reference_node(self, members): - """Get the reference node from the container members - Args: - members: list of node names - - Returns: - str: Reference node name. - - """ - - from maya import cmds - - # 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: - self.log.warning("More than one reference node found in " - "container, using highest reference node: " - "%s (in: %s)", highest, list(references)) - - return highest def update(self, container, representation): @@ -178,7 +185,7 @@ class ReferenceLoader(api.Loader): # Get reference node from container members members = cmds.sets(node, query=True, nodesOnly=True) - reference_node = self._get_reference_node(members) + reference_node = get_reference_node(members, self.log) file_type = { "ma": "mayaAscii", @@ -274,7 +281,7 @@ class ReferenceLoader(api.Loader): # Assume asset has been referenced members = cmds.sets(node, query=True) - reference_node = self._get_reference_node(members) + reference_node = get_reference_node(members, self.log) assert reference_node, ("Imported container not supported; " "container must be referenced.") diff --git a/openpype/hosts/maya/plugins/inventory/import_reference.py b/openpype/hosts/maya/plugins/inventory/import_reference.py index ac97096ee7..2fa132a867 100644 --- a/openpype/hosts/maya/plugins/inventory/import_reference.py +++ b/openpype/hosts/maya/plugins/inventory/import_reference.py @@ -2,28 +2,28 @@ from maya import cmds from avalon import api +from openpype.hosts.maya.api.plugin import get_reference_node + class ImportReference(api.InventoryAction): - """Imports selected reference inside the file.""" + """Imports selected reference to inside of the file.""" label = "Import Reference" - icon = "mouse-pointer" + icon = "download" color = "#d8d8d8" def process(self, containers): references = cmds.ls(type="reference") - for container in containers: if container["loader"] != "ReferenceLoader": print("Not a reference, skipping") continue - reference_name = container["namespace"] + "RN" - if reference_name in references: - print("Importing {}".format(reference_name)) + node = container["objectName"] + members = cmds.sets(node, query=True, nodesOnly=True) + ref_node = get_reference_node(members) - ref_file = cmds.referenceQuery(reference_name, f=True) + ref_file = cmds.referenceQuery(ref_node, f=True) + cmds.file(ref_file, importReference=True) - cmds.file(ref_file, importReference=True) - - return "refresh" + return True # return anything to trigger model refresh From e402c9c51f83ac4abcda56c5b006e086e50acd4b Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 17 Sep 2021 16:18:36 +0200 Subject: [PATCH 4/4] Added possibility to configure of synchronization of workfile version with selected families --- .../plugins/publish/precollect_instances.py | 13 ++++----- .../defaults/project_settings/nuke.json | 8 +++++- .../schemas/schema_nuke_publish.json | 27 ++++++++++++++++--- 3 files changed, 38 insertions(+), 10 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/precollect_instances.py b/openpype/hosts/nuke/plugins/publish/precollect_instances.py index c2c25d0627..d9aec14dc2 100644 --- a/openpype/hosts/nuke/plugins/publish/precollect_instances.py +++ b/openpype/hosts/nuke/plugins/publish/precollect_instances.py @@ -13,7 +13,7 @@ class PreCollectNukeInstances(pyblish.api.ContextPlugin): hosts = ["nuke", "nukeassist"] # presets - sync_workfile_version = False + sync_workfile_version_on_families = [] def process(self, context): asset_data = io.find_one({ @@ -120,11 +120,12 @@ class PreCollectNukeInstances(pyblish.api.ContextPlugin): # sync workfile version _families_test = [family] + families self.log.debug("__ _families_test: `{}`".format(_families_test)) - if not next((f for f in _families_test - if "prerender" in f), - None) and self.sync_workfile_version: - # get version to instance for integration - instance.data['version'] = instance.context.data['version'] + for family_test in _families_test: + if family_test in self.sync_workfile_version_on_families: + self.log.debug("Syncing version with workfile for '{}'" + .format(family_test)) + # get version to instance for integration + instance.data['version'] = instance.context.data['version'] instance.data.update({ "subset": subset, diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index 136f1d6b42..6ee7c2cd39 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -30,7 +30,13 @@ }, "publish": { "PreCollectNukeInstances": { - "sync_workfile_version": true + "sync_workfile_version_on_families": [ + "nukenodes", + "camera", + "gizmo", + "source", + "render" + ] }, "ValidateContainers": { "enabled": true, diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json index 782179cfd1..2772c5f3a6 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json @@ -16,9 +16,30 @@ "is_group": true, "children": [ { - "type": "boolean", - "key": "sync_workfile_version", - "label": "Sync Version from workfile" + "type": "enum", + "key": "sync_workfile_version_on_families", + "label": "Sync workfile version for families", + "multiselection": true, + "enum_items": [ + { + "nukenodes": "nukenodes" + }, + { + "camera": "camera" + }, + { + "gizmo": "gizmo" + }, + { + "source": "source" + }, + { + "prerender": "prerender" + }, + { + "render": "render" + } + ] } ] },