From aa600f88d45dcff4452d3f34de53168958cf5172 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Fri, 26 Apr 2024 23:20:45 +0300 Subject: [PATCH 01/54] Support HDA Publishing from non object level --- .../hosts/houdini/plugins/create/create_hda.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py index d399aa5e15..d747abc738 100644 --- a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py +++ b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py @@ -37,16 +37,24 @@ class CreateHDA(plugin.HoudiniCreator): self, folder_path, node_name, parent, node_type="geometry" ): - parent_node = hou.node("/obj") if self.selected_nodes: # if we have `use selection` enabled, and we have some # selected nodes ... + parent_node = self.selected_nodes[0].parent() subnet = parent_node.collapseIntoSubnet( self.selected_nodes, subnet_name="{}_subnet".format(node_name)) subnet.moveToGoodPosition() to_hda = subnet else: + # Use Obj as the default path + parent_node = hou.node("/obj") + # Find and return the NetworkEditor pane tab with the minimum index + pane = hou.ui.paneTabOfType(hou.paneTabType.NetworkEditor) + if isinstance(pane, hou.NetworkEditor): + # Use the NetworkEditor pane path as the parent path. + parent_node = pane.pwd() + to_hda = parent_node.createNode( "subnet", node_name="{}_subnet".format(node_name)) if not to_hda.type().definition(): From 1953a74ae1635c3e0b2159fcec7ca0ec2d6cfef3 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Fri, 26 Apr 2024 23:21:50 +0300 Subject: [PATCH 02/54] Allow users to specify maximum inputs of the HDA --- .../hosts/houdini/plugins/create/create_hda.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py index d747abc738..4538266bce 100644 --- a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py +++ b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py @@ -4,6 +4,7 @@ import ayon_api from ayon_core.pipeline import CreatorError from ayon_core.hosts.houdini.api import plugin +from ayon_core.lib import NumberDef import hou @@ -16,6 +17,8 @@ class CreateHDA(plugin.HoudiniCreator): icon = "gears" maintain_selection = False + max_num_inputs = 0 + def _check_existing(self, folder_path, product_name): # type: (str, str) -> bool """Check if existing product name versions already exists.""" @@ -66,7 +69,8 @@ class CreateHDA(plugin.HoudiniCreator): hda_node = to_hda.createDigitalAsset( name=node_name, - hda_file_name="$HIP/{}.hda".format(node_name) + hda_file_name="$HIP/{}.hda".format(node_name), + max_num_inputs=self.max_num_inputs ) hda_node.layoutChildren() elif self._check_existing(folder_path, node_name): @@ -83,6 +87,8 @@ class CreateHDA(plugin.HoudiniCreator): def create(self, product_name, instance_data, pre_create_data): instance_data.pop("active", None) + self.max_num_inputs = pre_create_data["max_num_inputs"] + instance = super(CreateHDA, self).create( product_name, instance_data, @@ -94,3 +100,12 @@ class CreateHDA(plugin.HoudiniCreator): return [ hou.objNodeTypeCategory() ] + + def get_pre_create_attr_defs(self): + attrs = super(CreateHDA, self).get_pre_create_attr_defs() + return attrs + [ + NumberDef("max_num_inputs", + label="Maximum Inputs", + default=self.max_num_inputs, + decimals=0) + ] From 079b332e48ad42f2a69d142e35521cf0d97d6610 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Fri, 26 Apr 2024 23:23:20 +0300 Subject: [PATCH 03/54] fix a bug with setName --- client/ayon_core/hosts/houdini/plugins/create/create_hda.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py index 4538266bce..1a4457d2d4 100644 --- a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py +++ b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py @@ -80,7 +80,11 @@ class CreateHDA(plugin.HoudiniCreator): else: hda_node = to_hda - hda_node.setName(node_name) + # If user tries to create the same HDA instance more than + # once, then all of them will have the same product name and + # point to the same hda_file_name. But, their node names will + # be incremented. + hda_node.setName(node_name, unique_name=True) self.customize_node_look(hda_node) return hda_node From b8dcd4cc315e311a90d7ccaf0c41964e53f2cdd4 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Fri, 26 Apr 2024 23:50:34 +0300 Subject: [PATCH 04/54] ignore_external_references when creating a digital asset --- client/ayon_core/hosts/houdini/plugins/create/create_hda.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py index 1a4457d2d4..119afd3edc 100644 --- a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py +++ b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py @@ -70,7 +70,8 @@ class CreateHDA(plugin.HoudiniCreator): hda_node = to_hda.createDigitalAsset( name=node_name, hda_file_name="$HIP/{}.hda".format(node_name), - max_num_inputs=self.max_num_inputs + max_num_inputs=self.max_num_inputs, + ignore_external_references=True ) hda_node.layoutChildren() elif self._check_existing(folder_path, node_name): From a41b564f2f5bfc5d18551a9fde7c49da8ccb55dd Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Mon, 29 Apr 2024 11:20:02 +0300 Subject: [PATCH 05/54] don't create a subnetwork if user seleted a subnetwork --- .../hosts/houdini/plugins/create/create_hda.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py index 119afd3edc..6a4ebc324d 100644 --- a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py +++ b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py @@ -43,12 +43,16 @@ class CreateHDA(plugin.HoudiniCreator): if self.selected_nodes: # if we have `use selection` enabled, and we have some # selected nodes ... - parent_node = self.selected_nodes[0].parent() - subnet = parent_node.collapseIntoSubnet( - self.selected_nodes, - subnet_name="{}_subnet".format(node_name)) - subnet.moveToGoodPosition() - to_hda = subnet + if self.selected_nodes[0].type().name() == "subnet": + to_hda = self.selected_nodes[0] + to_hda.setName("{}_subnet".format(node_name), unique_name=True) + else: + parent_node = self.selected_nodes[0].parent() + subnet = parent_node.collapseIntoSubnet( + self.selected_nodes, + subnet_name="{}_subnet".format(node_name)) + subnet.moveToGoodPosition() + to_hda = subnet else: # Use Obj as the default path parent_node = hou.node("/obj") From 8399a6832de451e97e5692408aed867a9f796d97 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Mon, 29 Apr 2024 11:24:35 +0300 Subject: [PATCH 06/54] Allow users to specify minimum inputs of the HDA --- .../ayon_core/hosts/houdini/plugins/create/create_hda.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py index 6a4ebc324d..f79b49fb2b 100644 --- a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py +++ b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py @@ -17,6 +17,7 @@ class CreateHDA(plugin.HoudiniCreator): icon = "gears" maintain_selection = False + min_num_inputs = 0 max_num_inputs = 0 def _check_existing(self, folder_path, product_name): @@ -74,6 +75,7 @@ class CreateHDA(plugin.HoudiniCreator): hda_node = to_hda.createDigitalAsset( name=node_name, hda_file_name="$HIP/{}.hda".format(node_name), + min_num_inputs=self.min_num_inputs, max_num_inputs=self.max_num_inputs, ignore_external_references=True ) @@ -96,6 +98,7 @@ class CreateHDA(plugin.HoudiniCreator): def create(self, product_name, instance_data, pre_create_data): instance_data.pop("active", None) + self.min_num_inputs = pre_create_data["min_num_inputs"] self.max_num_inputs = pre_create_data["max_num_inputs"] instance = super(CreateHDA, self).create( @@ -113,6 +116,10 @@ class CreateHDA(plugin.HoudiniCreator): def get_pre_create_attr_defs(self): attrs = super(CreateHDA, self).get_pre_create_attr_defs() return attrs + [ + NumberDef("min_num_inputs", + label="Minimum Inputs", + default=self.min_num_inputs, + decimals=0), NumberDef("max_num_inputs", label="Maximum Inputs", default=self.max_num_inputs, From 23583ab02243ee55cfe6b1424c71e05df90a0e91 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Tue, 30 Apr 2024 08:47:50 +0300 Subject: [PATCH 07/54] CreateHDA: update get_network_categories --- client/ayon_core/hosts/houdini/plugins/create/create_hda.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py index f79b49fb2b..772ff4e255 100644 --- a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py +++ b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py @@ -110,7 +110,11 @@ class CreateHDA(plugin.HoudiniCreator): def get_network_categories(self): return [ - hou.objNodeTypeCategory() + category for name, category in hou.nodeTypeCategories().items() + if name in { + "Chop", "Cop2", "Dop", "Driver", "Lop", + "Object", "Shop", "Sop", "Top", "Vop" + } ] def get_pre_create_attr_defs(self): From 05886e882a81fd02c01925ce423bc35dce2d883c Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Fri, 3 May 2024 11:51:20 +0200 Subject: [PATCH 08/54] Pass `pre_create_data` to `create_instance_node` --- client/ayon_core/hosts/houdini/api/plugin.py | 7 +++++- .../houdini/plugins/create/create_hda.py | 25 ++++++++++++------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/client/ayon_core/hosts/houdini/api/plugin.py b/client/ayon_core/hosts/houdini/api/plugin.py index a9c8c313b9..75527e0b3f 100644 --- a/client/ayon_core/hosts/houdini/api/plugin.py +++ b/client/ayon_core/hosts/houdini/api/plugin.py @@ -141,7 +141,11 @@ class HoudiniCreatorBase(object): @staticmethod def create_instance_node( - folder_path, node_name, parent, node_type="geometry" + folder_path, + node_name, + parent, + node_type="geometry", + pre_create_data=None ): """Create node representing instance. @@ -150,6 +154,7 @@ class HoudiniCreatorBase(object): node_name (str): Name of the new node. parent (str): Name of the parent node. node_type (str, optional): Type of the node. + pre_create_data (Optional[Dict]): Pre create data. Returns: hou.Node: Newly created instance node. diff --git a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py index 772ff4e255..bc4ad093bf 100644 --- a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py +++ b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py @@ -38,8 +38,20 @@ class CreateHDA(plugin.HoudiniCreator): return product_name.lower() in existing_product_names_low def create_instance_node( - self, folder_path, node_name, parent, node_type="geometry" + self, + folder_path, + node_name, + parent, + node_type="geometry", + pre_create_data=None ): + if pre_create_data is None: + pre_create_data = {} + + min_num_inputs = pre_create_data.get("min_num_inputs", + self.min_num_inputs) + max_num_inputs = pre_create_data.get("min_num_inputs", + self.max_num_inputs) if self.selected_nodes: # if we have `use selection` enabled, and we have some @@ -75,8 +87,8 @@ class CreateHDA(plugin.HoudiniCreator): hda_node = to_hda.createDigitalAsset( name=node_name, hda_file_name="$HIP/{}.hda".format(node_name), - min_num_inputs=self.min_num_inputs, - max_num_inputs=self.max_num_inputs, + min_num_inputs=min_num_inputs, + max_num_inputs=max_num_inputs, ignore_external_references=True ) hda_node.layoutChildren() @@ -98,16 +110,11 @@ class CreateHDA(plugin.HoudiniCreator): def create(self, product_name, instance_data, pre_create_data): instance_data.pop("active", None) - self.min_num_inputs = pre_create_data["min_num_inputs"] - self.max_num_inputs = pre_create_data["max_num_inputs"] - - instance = super(CreateHDA, self).create( + return super(CreateHDA, self).create( product_name, instance_data, pre_create_data) - return instance - def get_network_categories(self): return [ category for name, category in hou.nodeTypeCategories().items() From 2a654bcfe82f6e5df8a156823a7a85cc97957102 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Fri, 3 May 2024 19:38:18 +0300 Subject: [PATCH 09/54] pass pre_create_data argument to self.create_instance_node --- client/ayon_core/hosts/houdini/api/plugin.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/houdini/api/plugin.py b/client/ayon_core/hosts/houdini/api/plugin.py index 75527e0b3f..6c878867c0 100644 --- a/client/ayon_core/hosts/houdini/api/plugin.py +++ b/client/ayon_core/hosts/houdini/api/plugin.py @@ -189,7 +189,12 @@ class HoudiniCreator(NewCreator, HoudiniCreatorBase): folder_path = instance_data["folderPath"] instance_node = self.create_instance_node( - folder_path, product_name, "/out", node_type) + folder_path, + product_name, + "/out", + node_type, + pre_create_data + ) self.customize_node_look(instance_node) From 689c87b6d9ddf5605825767eef8f0446d1931c75 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Fri, 3 May 2024 19:38:58 +0300 Subject: [PATCH 10/54] fix pre_create_data key --- client/ayon_core/hosts/houdini/plugins/create/create_hda.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py index bc4ad093bf..9566a6c5f3 100644 --- a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py +++ b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py @@ -50,7 +50,7 @@ class CreateHDA(plugin.HoudiniCreator): min_num_inputs = pre_create_data.get("min_num_inputs", self.min_num_inputs) - max_num_inputs = pre_create_data.get("min_num_inputs", + max_num_inputs = pre_create_data.get("max_num_inputs", self.max_num_inputs) if self.selected_nodes: From 79139ce0dd4b31c32c98d26403a2f78c6e345f14 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Fri, 3 May 2024 20:09:02 +0300 Subject: [PATCH 11/54] use explicit network categories --- .../hosts/houdini/plugins/create/create_hda.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py index 9566a6c5f3..0eb2b5dd52 100644 --- a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py +++ b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py @@ -116,12 +116,20 @@ class CreateHDA(plugin.HoudiniCreator): pre_create_data) def get_network_categories(self): + # Houdini allows creating sub-network nodes inside + # these categories. + # Therefore this plugin can work in these categories. return [ - category for name, category in hou.nodeTypeCategories().items() - if name in { - "Chop", "Cop2", "Dop", "Driver", "Lop", - "Object", "Shop", "Sop", "Top", "Vop" - } + hou.chopNodeTypeCategory(), + hou.cop2NodeTypeCategory(), + hou.dopNodeTypeCategory(), + hou.ropNodeTypeCategory(), + hou.lopNodeTypeCategory(), + hou.objNodeTypeCategory(), + hou.shopNodeTypeCategory(), + hou.sopNodeTypeCategory(), + hou.topNodeTypeCategory(), + hou.vopNodeTypeCategory() ] def get_pre_create_attr_defs(self): From 618bab2c281936a9a2ec9982f98f96513d7b2e8c Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Tue, 7 May 2024 01:30:49 +0300 Subject: [PATCH 12/54] add more options for HDA creator --- .../houdini/plugins/create/create_hda.py | 47 ++++++++++++++++--- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py index 0eb2b5dd52..ff56a63132 100644 --- a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py +++ b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py @@ -1,11 +1,12 @@ # -*- coding: utf-8 -*- """Creator plugin for creating publishable Houdini Digital Assets.""" import ayon_api - +import getpass from ayon_core.pipeline import CreatorError from ayon_core.hosts.houdini.api import plugin -from ayon_core.lib import NumberDef +from ayon_core.lib import NumberDef, BoolDef import hou +from ayon_core.resources import get_ayon_icon_filepath class CreateHDA(plugin.HoudiniCreator): @@ -19,6 +20,7 @@ class CreateHDA(plugin.HoudiniCreator): min_num_inputs = 0 max_num_inputs = 0 + max_num_outputs = 1 def _check_existing(self, folder_path, product_name): # type: (str, str) -> bool @@ -52,7 +54,8 @@ class CreateHDA(plugin.HoudiniCreator): self.min_num_inputs) max_num_inputs = pre_create_data.get("max_num_inputs", self.max_num_inputs) - + max_num_outputs = pre_create_data.get("max_num_outputs", + self.max_num_outputs) if self.selected_nodes: # if we have `use selection` enabled, and we have some # selected nodes ... @@ -87,8 +90,6 @@ class CreateHDA(plugin.HoudiniCreator): hda_node = to_hda.createDigitalAsset( name=node_name, hda_file_name="$HIP/{}.hda".format(node_name), - min_num_inputs=min_num_inputs, - max_num_inputs=max_num_inputs, ignore_external_references=True ) hda_node.layoutChildren() @@ -105,6 +106,24 @@ class CreateHDA(plugin.HoudiniCreator): # be incremented. hda_node.setName(node_name, unique_name=True) self.customize_node_look(hda_node) + + # Set Custom settings. + hda_def = hda_node.type().definition() + hda_def.setMinNumInputs(min_num_inputs) + hda_def.setMaxNumInputs(max_num_inputs) + hda_def.setMaxNumOutputs(max_num_outputs) + + if pre_create_data.get("use_ayon_icon"): + hda_def.setIcon(get_ayon_icon_filepath()) + + if pre_create_data.get("set_user"): + hda_def.setUserInfo(getpass.getuser()) + + if pre_create_data.get("use_project"): + tool_name = hou.shelves.defaultToolName( + hda_def.nodeTypeCategory().name(), hda_def.nodeTypeName()) + hou.shelves.tool(tool_name).setToolLocations((self.project_name,)) + return hda_node def create(self, product_name, instance_data, pre_create_data): @@ -142,5 +161,21 @@ class CreateHDA(plugin.HoudiniCreator): NumberDef("max_num_inputs", label="Maximum Inputs", default=self.max_num_inputs, - decimals=0) + decimals=0), + NumberDef("max_num_outputs", + label="Maximum Outputs", + default=self.max_num_outputs, + decimals=0), + BoolDef("use_ayon_icon", + tooltip="Use Ayon icon for the digital asset.", + default=True, + label="Use AYON Icon"), + BoolDef("set_user", + tooltip="Set current user as the author of the HDA", + default=True, + label="Set Current User"), + BoolDef("use_project", + tooltip="Use project name as tab submenu path", + default=True, + label="Use Project as menu entry"), ] From 2ab0e240f8ca0e119bbb317452e8d78247e7f296 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Tue, 7 May 2024 16:09:27 +0300 Subject: [PATCH 13/54] remove shop from network categories --- client/ayon_core/hosts/houdini/plugins/create/create_hda.py | 1 - 1 file changed, 1 deletion(-) diff --git a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py index ff56a63132..d4dcd245ec 100644 --- a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py +++ b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py @@ -145,7 +145,6 @@ class CreateHDA(plugin.HoudiniCreator): hou.ropNodeTypeCategory(), hou.lopNodeTypeCategory(), hou.objNodeTypeCategory(), - hou.shopNodeTypeCategory(), hou.sopNodeTypeCategory(), hou.topNodeTypeCategory(), hou.vopNodeTypeCategory() From 7d37953011078a0d07b3a0c086507891329ec1d3 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Tue, 7 May 2024 16:15:44 +0300 Subject: [PATCH 14/54] remove setting number of inputs and outputs --- .../houdini/plugins/create/create_hda.py | 27 +------------------ 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py index d4dcd245ec..0e0436d981 100644 --- a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py +++ b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py @@ -4,7 +4,7 @@ import ayon_api import getpass from ayon_core.pipeline import CreatorError from ayon_core.hosts.houdini.api import plugin -from ayon_core.lib import NumberDef, BoolDef +from ayon_core.lib import BoolDef import hou from ayon_core.resources import get_ayon_icon_filepath @@ -18,10 +18,6 @@ class CreateHDA(plugin.HoudiniCreator): icon = "gears" maintain_selection = False - min_num_inputs = 0 - max_num_inputs = 0 - max_num_outputs = 1 - def _check_existing(self, folder_path, product_name): # type: (str, str) -> bool """Check if existing product name versions already exists.""" @@ -50,12 +46,6 @@ class CreateHDA(plugin.HoudiniCreator): if pre_create_data is None: pre_create_data = {} - min_num_inputs = pre_create_data.get("min_num_inputs", - self.min_num_inputs) - max_num_inputs = pre_create_data.get("max_num_inputs", - self.max_num_inputs) - max_num_outputs = pre_create_data.get("max_num_outputs", - self.max_num_outputs) if self.selected_nodes: # if we have `use selection` enabled, and we have some # selected nodes ... @@ -109,9 +99,6 @@ class CreateHDA(plugin.HoudiniCreator): # Set Custom settings. hda_def = hda_node.type().definition() - hda_def.setMinNumInputs(min_num_inputs) - hda_def.setMaxNumInputs(max_num_inputs) - hda_def.setMaxNumOutputs(max_num_outputs) if pre_create_data.get("use_ayon_icon"): hda_def.setIcon(get_ayon_icon_filepath()) @@ -153,18 +140,6 @@ class CreateHDA(plugin.HoudiniCreator): def get_pre_create_attr_defs(self): attrs = super(CreateHDA, self).get_pre_create_attr_defs() return attrs + [ - NumberDef("min_num_inputs", - label="Minimum Inputs", - default=self.min_num_inputs, - decimals=0), - NumberDef("max_num_inputs", - label="Maximum Inputs", - default=self.max_num_inputs, - decimals=0), - NumberDef("max_num_outputs", - label="Maximum Outputs", - default=self.max_num_outputs, - decimals=0), BoolDef("use_ayon_icon", tooltip="Use Ayon icon for the digital asset.", default=True, From 99179cc6453e968741313dd946671ff5aa56939f Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Tue, 7 May 2024 16:21:07 +0300 Subject: [PATCH 15/54] update default values of attr defs --- client/ayon_core/hosts/houdini/plugins/create/create_hda.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py index 0e0436d981..a810f06283 100644 --- a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py +++ b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py @@ -142,11 +142,11 @@ class CreateHDA(plugin.HoudiniCreator): return attrs + [ BoolDef("use_ayon_icon", tooltip="Use Ayon icon for the digital asset.", - default=True, + default=False, label="Use AYON Icon"), BoolDef("set_user", tooltip="Set current user as the author of the HDA", - default=True, + default=False, label="Set Current User"), BoolDef("use_project", tooltip="Use project name as tab submenu path", From 8f1dd6acf6f16f2f1f608fced6be7e416de747ee Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Wed, 8 May 2024 22:50:06 +0300 Subject: [PATCH 16/54] support loading HDAs from non object level --- .../hosts/houdini/plugins/load/load_hda.py | 131 +++++++++++++++--- 1 file changed, 115 insertions(+), 16 deletions(-) diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_hda.py b/client/ayon_core/hosts/houdini/plugins/load/load_hda.py index 10fc03be03..b2d2337266 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_hda.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_hda.py @@ -3,10 +3,28 @@ import os from ayon_core.pipeline import ( load, get_representation_path, + AVALON_CONTAINER_ID ) -from ayon_core.hosts.houdini.api import pipeline +from ayon_core.hosts.houdini.api import lib, pipeline +import hou +def get_avalon_container(): + path = pipeline.AVALON_CONTAINERS + avalon_container = hou.node(path) + if not avalon_container: + # Let's create avalon container secretly + # but make sure the pipeline still is built the + # way we anticipate it was built, asserting it. + assert path == "/obj/AVALON_CONTAINERS" + + parent = hou.node("/obj") + avalon_container = parent.createNode( + "subnet", node_name="AVALON_CONTAINERS" + ) + + return avalon_container + class HdaLoader(load.LoaderPlugin): """Load Houdini Digital Asset file.""" @@ -18,38 +36,44 @@ class HdaLoader(load.LoaderPlugin): color = "orange" def load(self, context, name=None, namespace=None, data=None): - import hou # Format file name, Houdini only wants forward slashes file_path = self.filepath_from_context(context) file_path = os.path.normpath(file_path) file_path = file_path.replace("\\", "/") - # Get the root node - obj = hou.node("/obj") - # Create a unique name counter = 1 namespace = namespace or context["folder"]["name"] formatted = "{}_{}".format(namespace, name) if namespace else name node_name = "{0}_{1:03d}".format(formatted, counter) + hda_defs = hou.hda.definitionsInFile(file_path) + if not hda_defs: + raise RuntimeError ("No HDA definitions found!") + + hda_def = hda_defs[0] + parent_node = self._create_dedicated_parent_node(hda_def) + hou.hda.installFile(file_path) - hda_node = obj.createNode(name, node_name) + hda_node = parent_node.createNode(name, node_name) + hda_node.moveToGoodPosition() - self[:] = [hda_node] + # Imprint it manually + data = { + "schema": "openpype:container-2.0", + "id": AVALON_CONTAINER_ID, + "name": node_name, + "namespace": namespace, + "loader": str(self.__class__.__name__), + "representation": context["representation"]["id"], + } - return pipeline.containerise( - node_name, - namespace, - [hda_node], - context, - self.__class__.__name__, - suffix="", - ) + lib.imprint(hda_node, data) + + return hda_node def update(self, container, context): - import hou repre_entity = context["representation"] hda_node = container["node"] @@ -66,4 +90,79 @@ class HdaLoader(load.LoaderPlugin): def remove(self, container): node = container["node"] + parent = node.parent() node.destroy() + + if parent.type().category() == hou.objNodeTypeCategory(): + return + + # Remove parent if empty. + if not parent.children(): + parent.destroy() + + def _create_dedicated_parent_node(self, hda_def): + + # Get the root node + parent_node = get_avalon_container() + node = None + node_type = None + if hda_def.nodeTypeCategory() == hou.objNodeTypeCategory(): + return parent_node + elif hda_def.nodeTypeCategory() == hou.chopNodeTypeCategory(): + node_type, node_name = "chopnet", "MOTION" + elif hda_def.nodeTypeCategory() == hou.cop2NodeTypeCategory(): + node_type, node_name = "cop2net", "IMAGES" + elif hda_def.nodeTypeCategory() == hou.dopNodeTypeCategory(): + node_type, node_name = "dopnet", "DOPS" + elif hda_def.nodeTypeCategory() == hou.ropNodeTypeCategory(): + node_type, node_name = "ropnet", "ROPS" + elif hda_def.nodeTypeCategory() == hou.lopNodeTypeCategory(): + node_type, node_name = "lopnet", "LOPS" + elif hda_def.nodeTypeCategory() == hou.sopNodeTypeCategory(): + node_type, node_name = "geo", "SOPS" + elif hda_def.nodeTypeCategory() == hou.topNodeTypeCategory(): + node_type, node_name = "topnet", "TOPS" + # TODO: Create a dedicated parent node based on Vop Node vex context. + elif hda_def.nodeTypeCategory() == hou.vopNodeTypeCategory(): + parent_node, node_type, node_name = self._get_dedicated_parent_for_vop(parent_node, hda_def) + + node = parent_node.node(node_name) + if not node: + node = parent_node.createNode(node_type, node_name) + + node.moveToGoodPosition() + return node + + def _get_dedicated_parent_for_vop(self, parent_node, hda_def): + """create_dedicated_parent_for_vop + + VOPs are a little special because they can exist + in different contexts. + e.g. + - Material Network + - SOPs > VOP nodes + - Chop > VOP nodes + - Cop2 > VOP nodes + + Get the vex context of the HDA and return + dedicated node_type and node_name. + + It creates intermediate nodes if needed. + """ + vex_context = hou.vexContextForNodeTypeCategory(hda_def.nodeTypeCategory()) + + if vex_context: + new_parent = parent_node.node("VOPS") + if not new_parent: + new_parent = parent_node.createNode("vopnet", "VOPS") + new_parent.moveToGoodPosition() + + if vex_context.name() == "Cop2": + return new_parent, "cop2filter", "COP_VOP" + elif vex_context.name() == "Chop": + return new_parent, "chop", "CHOP_VOP" + elif vex_context.name() == "Sop": + return new_parent, "sop", "SOP_VOP" + + # Fall to material net if no vex context found + return parent_node, "matnet", "MATS" From 01906888d959df4d3445b78f6e3bd29276bc5704 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Thu, 9 May 2024 16:28:14 +0300 Subject: [PATCH 17/54] update ToolLocation --- client/ayon_core/hosts/houdini/plugins/create/create_hda.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py index a810f06283..e6aeba270c 100644 --- a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py +++ b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py @@ -109,7 +109,8 @@ class CreateHDA(plugin.HoudiniCreator): if pre_create_data.get("use_project"): tool_name = hou.shelves.defaultToolName( hda_def.nodeTypeCategory().name(), hda_def.nodeTypeName()) - hou.shelves.tool(tool_name).setToolLocations((self.project_name,)) + hou.shelves.tool(tool_name).setToolLocations( + ("AYON/{}".format(self.project_name),)) return hda_node From f8d07c0045d8437838f2e4d56b0e0e6ad1bc1c74 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Thu, 9 May 2024 16:32:15 +0300 Subject: [PATCH 18/54] update Tooltip --- client/ayon_core/hosts/houdini/plugins/create/create_hda.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py index e6aeba270c..3ca82ccb60 100644 --- a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py +++ b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py @@ -150,7 +150,9 @@ class CreateHDA(plugin.HoudiniCreator): default=False, label="Set Current User"), BoolDef("use_project", - tooltip="Use project name as tab submenu path", + tooltip="Use project name as tab submenu path.\n" + "The location in TAB Menu will be\n" + "'AYON/project_name/your_HDA_name'", default=True, label="Use Project as menu entry"), ] From 4f532560f3c958fb6431e2a7cad22340ece7700b Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Thu, 9 May 2024 18:09:23 +0300 Subject: [PATCH 19/54] add use_project to creator_attributes --- .../ayon_core/hosts/houdini/plugins/create/create_hda.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py index 3ca82ccb60..462ae5eb7c 100644 --- a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py +++ b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py @@ -117,6 +117,13 @@ class CreateHDA(plugin.HoudiniCreator): def create(self, product_name, instance_data, pre_create_data): instance_data.pop("active", None) + # Transfer settings from pre create to instance + creator_attributes = instance_data.setdefault( + "creator_attributes", dict()) + for key in {"use_project"}: + if key in pre_create_data: + creator_attributes[key] = pre_create_data[key] + return super(CreateHDA, self).create( product_name, instance_data, From 9b4d36eee848b9dc8704b03f263a6c70c4d1e7a2 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Thu, 9 May 2024 18:09:50 +0300 Subject: [PATCH 20/54] set HDA TAB menu loaction interactively --- client/ayon_core/hosts/houdini/plugins/load/load_hda.py | 7 +++++++ .../hosts/houdini/plugins/publish/extract_hda.py | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_hda.py b/client/ayon_core/hosts/houdini/plugins/load/load_hda.py index b2d2337266..2faa403858 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_hda.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_hda.py @@ -59,6 +59,13 @@ class HdaLoader(load.LoaderPlugin): hda_node = parent_node.createNode(name, node_name) hda_node.moveToGoodPosition() + # Set TAB Menu location interactively + # This shouldn't be needed if the Tool Location is saved in the HDA. + tool_name = hou.shelves.defaultToolName( + hda_def.nodeTypeCategory().name(), hda_def.nodeTypeName()) + hou.shelves.tool(tool_name).setToolLocations( + ("AYON/{}".format(context["project"]["name"]),)) + # Imprint it manually data = { "schema": "openpype:container-2.0", diff --git a/client/ayon_core/hosts/houdini/plugins/publish/extract_hda.py b/client/ayon_core/hosts/houdini/plugins/publish/extract_hda.py index 5fe83e0dcf..5ac102332a 100644 --- a/client/ayon_core/hosts/houdini/plugins/publish/extract_hda.py +++ b/client/ayon_core/hosts/houdini/plugins/publish/extract_hda.py @@ -26,6 +26,14 @@ class ExtractHDA(publish.Extractor): hda_def.setOptions(hda_options) hda_def.save(hda_def.libraryFilePath(), hda_node, hda_options) + if instance.data["creator_attributes"].get("use_project"): + # Set TAB Menu location interactively + # This shouldn't be needed if the Tool Location is saved in the HDA. + tool_name = hou.shelves.defaultToolName( + hda_def.nodeTypeCategory().name(), hda_def.nodeTypeName()) + hou.shelves.tool(tool_name).setToolLocations( + ("AYON/{}".format(self.project_name),)) + if "representations" not in instance.data: instance.data["representations"] = [] From a5e664619457c2a41f4c97abd16ad4d7f1e4d57e Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Thu, 9 May 2024 18:13:55 +0300 Subject: [PATCH 21/54] use matnet as the parent node to load VOP HDAs --- .../hosts/houdini/plugins/load/load_hda.py | 36 +------------------ 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_hda.py b/client/ayon_core/hosts/houdini/plugins/load/load_hda.py index 2faa403858..9368c8d2fb 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_hda.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_hda.py @@ -131,7 +131,7 @@ class HdaLoader(load.LoaderPlugin): node_type, node_name = "topnet", "TOPS" # TODO: Create a dedicated parent node based on Vop Node vex context. elif hda_def.nodeTypeCategory() == hou.vopNodeTypeCategory(): - parent_node, node_type, node_name = self._get_dedicated_parent_for_vop(parent_node, hda_def) + node_type, node_name = "matnet", "MATSandVOPS" node = parent_node.node(node_name) if not node: @@ -139,37 +139,3 @@ class HdaLoader(load.LoaderPlugin): node.moveToGoodPosition() return node - - def _get_dedicated_parent_for_vop(self, parent_node, hda_def): - """create_dedicated_parent_for_vop - - VOPs are a little special because they can exist - in different contexts. - e.g. - - Material Network - - SOPs > VOP nodes - - Chop > VOP nodes - - Cop2 > VOP nodes - - Get the vex context of the HDA and return - dedicated node_type and node_name. - - It creates intermediate nodes if needed. - """ - vex_context = hou.vexContextForNodeTypeCategory(hda_def.nodeTypeCategory()) - - if vex_context: - new_parent = parent_node.node("VOPS") - if not new_parent: - new_parent = parent_node.createNode("vopnet", "VOPS") - new_parent.moveToGoodPosition() - - if vex_context.name() == "Cop2": - return new_parent, "cop2filter", "COP_VOP" - elif vex_context.name() == "Chop": - return new_parent, "chop", "CHOP_VOP" - elif vex_context.name() == "Sop": - return new_parent, "sop", "SOP_VOP" - - # Fall to material net if no vex context found - return parent_node, "matnet", "MATS" From 943a36130f56f54aba49ba3e48b887344fea3ba4 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Thu, 9 May 2024 22:04:54 +0300 Subject: [PATCH 22/54] Update 'creator>product_name_profiles': add Houdini HDA template to default values --- client/ayon_core/version.py | 2 +- package.py | 3 +-- server/settings/tools.py | 11 +++++++++++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/client/ayon_core/version.py b/client/ayon_core/version.py index a60de0493a..a0def120c4 100644 --- a/client/ayon_core/version.py +++ b/client/ayon_core/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring AYON core addon version.""" -__version__ = "0.3.1-dev.1" +__version__ = "0.3.1-dev.2" diff --git a/package.py b/package.py index 79450d029f..2a84c68f35 100644 --- a/package.py +++ b/package.py @@ -1,6 +1,6 @@ name = "core" title = "Core" -version = "0.3.1-dev.1" +version = "0.3.1-dev.2" client_dir = "ayon_core" @@ -8,4 +8,3 @@ plugin_for = ["ayon_server"] requires = [ "~ayon_server-1.0.3+<2.0.0", ] - diff --git a/server/settings/tools.py b/server/settings/tools.py index fb8430a71c..ce3ceaea6e 100644 --- a/server/settings/tools.py +++ b/server/settings/tools.py @@ -403,6 +403,17 @@ DEFAULT_TOOLS_VALUES = { "task_types": [], "tasks": [], "template": "SK_{folder[name]}{variant}" + }, + { + "product_types": [ + "hda" + ], + "hosts": [ + "houdini" + ], + "task_types": [], + "tasks": [], + "template": "{folder[label]}_{variant}" } ] }, From 95f33b2da2d175e29198855322d1f876bed25d28 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Thu, 9 May 2024 22:06:22 +0300 Subject: [PATCH 23/54] add folder name and label to dynamic data --- .../houdini/plugins/create/create_hda.py | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py index 462ae5eb7c..957da8f230 100644 --- a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py +++ b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py @@ -51,12 +51,12 @@ class CreateHDA(plugin.HoudiniCreator): # selected nodes ... if self.selected_nodes[0].type().name() == "subnet": to_hda = self.selected_nodes[0] - to_hda.setName("{}_subnet".format(node_name), unique_name=True) + to_hda.setName("{}_HDA".format(node_name), unique_name=True) else: parent_node = self.selected_nodes[0].parent() subnet = parent_node.collapseIntoSubnet( self.selected_nodes, - subnet_name="{}_subnet".format(node_name)) + subnet_name="{}_HDA".format(node_name)) subnet.moveToGoodPosition() to_hda = subnet else: @@ -69,7 +69,7 @@ class CreateHDA(plugin.HoudiniCreator): parent_node = pane.pwd() to_hda = parent_node.createNode( - "subnet", node_name="{}_subnet".format(node_name)) + "subnet", node_name="{}_HDA".format(node_name)) if not to_hda.type().definition(): # if node type has not its definition, it is not user # created hda. We test if hda can be created from the node. @@ -163,3 +163,30 @@ class CreateHDA(plugin.HoudiniCreator): default=True, label="Use Project as menu entry"), ] + + def get_dynamic_data( + self, + project_name, + folder_entity, + task_entity, + variant, + host_name, + instance + ): + """ + Pass product name from product name templates as dynamic data. + """ + dynamic_data = super(CreateHDA, self).get_dynamic_data( + project_name, + folder_entity, + task_entity, + variant, + host_name, + instance + ) + + dynamic_data["folder"] = { + "label": folder_entity["label"], + "name": folder_entity["name"] + } + return dynamic_data From 389288a50649526c1c438cea5b720e32a0c7f1d7 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Thu, 9 May 2024 22:06:40 +0300 Subject: [PATCH 24/54] add hda to families --- .../hosts/houdini/plugins/publish/validate_subset_name.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/houdini/plugins/publish/validate_subset_name.py b/client/ayon_core/hosts/houdini/plugins/publish/validate_subset_name.py index 0481929824..1bcd2dada2 100644 --- a/client/ayon_core/hosts/houdini/plugins/publish/validate_subset_name.py +++ b/client/ayon_core/hosts/houdini/plugins/publish/validate_subset_name.py @@ -25,7 +25,7 @@ class ValidateSubsetName(pyblish.api.InstancePlugin, """ - families = ["staticMesh"] + families = ["staticMesh", "hda"] hosts = ["houdini"] label = "Validate Product Name" order = ValidateContentsOrder + 0.1 From fa8b4e808b8f45a1f1672f015bf8d46ea61bd4a6 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Fri, 10 May 2024 12:04:33 +0300 Subject: [PATCH 25/54] fux bug, get project name from context --- client/ayon_core/hosts/houdini/plugins/publish/extract_hda.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/houdini/plugins/publish/extract_hda.py b/client/ayon_core/hosts/houdini/plugins/publish/extract_hda.py index 5ac102332a..1a3bcacc38 100644 --- a/client/ayon_core/hosts/houdini/plugins/publish/extract_hda.py +++ b/client/ayon_core/hosts/houdini/plugins/publish/extract_hda.py @@ -32,7 +32,7 @@ class ExtractHDA(publish.Extractor): tool_name = hou.shelves.defaultToolName( hda_def.nodeTypeCategory().name(), hda_def.nodeTypeName()) hou.shelves.tool(tool_name).setToolLocations( - ("AYON/{}".format(self.project_name),)) + ("AYON/{}".format(instance.context.data["projectName"]),)) if "representations" not in instance.data: instance.data["representations"] = [] From bc2c9479d557464be6d8b001f73bc6d66e9a35cf Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Fri, 10 May 2024 12:05:17 +0300 Subject: [PATCH 26/54] add missing dynamic data keys --- .../hosts/houdini/plugins/publish/validate_subset_name.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/houdini/plugins/publish/validate_subset_name.py b/client/ayon_core/hosts/houdini/plugins/publish/validate_subset_name.py index 1bcd2dada2..6c79687d88 100644 --- a/client/ayon_core/hosts/houdini/plugins/publish/validate_subset_name.py +++ b/client/ayon_core/hosts/houdini/plugins/publish/validate_subset_name.py @@ -67,7 +67,13 @@ class ValidateSubsetName(pyblish.api.InstancePlugin, instance.context.data["hostName"], instance.data["productType"], variant=instance.data["variant"], - dynamic_data={"asset": folder_entity["name"]} + dynamic_data={ + "asset": folder_entity["name"], + "folder": { + "label": folder_entity["label"], + "name": folder_entity["name"] + } + } ) if instance.data.get("productName") != product_name: From e95fcbe995ce018564cf235cf8e3da795bd384d6 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 10 May 2024 23:39:51 +0800 Subject: [PATCH 27/54] add joint into accepted_controllers --- .../hosts/maya/plugins/publish/validate_animated_reference.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_animated_reference.py b/client/ayon_core/hosts/maya/plugins/publish/validate_animated_reference.py index 2ba2bff6fc..c9dcc662af 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_animated_reference.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_animated_reference.py @@ -16,7 +16,7 @@ class ValidateAnimatedReferenceRig(pyblish.api.InstancePlugin, hosts = ["maya"] families = ["animation.fbx"] label = "Animated Reference Rig" - accepted_controllers = ["transform", "locator"] + accepted_controllers = ["transform", "locator", "joint"] actions = [ayon_core.hosts.maya.api.action.SelectInvalidAction] optional = False From c02d5522f3d6617c27fd4fe9da2e0c5de999f503 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 10 May 2024 23:58:34 +0800 Subject: [PATCH 28/54] make sure the animation doesnt get resample --- .../hosts/maya/plugins/publish/extract_fbx_animation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/client/ayon_core/hosts/maya/plugins/publish/extract_fbx_animation.py b/client/ayon_core/hosts/maya/plugins/publish/extract_fbx_animation.py index ee66ed2fb7..36dc1b1544 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/extract_fbx_animation.py +++ b/client/ayon_core/hosts/maya/plugins/publish/extract_fbx_animation.py @@ -36,6 +36,7 @@ class ExtractFBXAnimation(publish.Extractor): out_members = instance.data.get("animated_skeleton", []) # Export instance.data["constraints"] = True + instance.data["bakeResampleAnimation"] = False instance.data["skeletonDefinitions"] = True instance.data["referencedAssetsContent"] = True fbx_exporter.set_options_from_instance(instance) From 1b70c0a6a4bd08815ab680549b7dd99f199c85ec Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 10 May 2024 23:59:19 +0800 Subject: [PATCH 29/54] revert commits --- .../hosts/maya/plugins/publish/extract_fbx_animation.py | 1 - .../hosts/maya/plugins/publish/validate_animated_reference.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/extract_fbx_animation.py b/client/ayon_core/hosts/maya/plugins/publish/extract_fbx_animation.py index 36dc1b1544..ee66ed2fb7 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/extract_fbx_animation.py +++ b/client/ayon_core/hosts/maya/plugins/publish/extract_fbx_animation.py @@ -36,7 +36,6 @@ class ExtractFBXAnimation(publish.Extractor): out_members = instance.data.get("animated_skeleton", []) # Export instance.data["constraints"] = True - instance.data["bakeResampleAnimation"] = False instance.data["skeletonDefinitions"] = True instance.data["referencedAssetsContent"] = True fbx_exporter.set_options_from_instance(instance) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_animated_reference.py b/client/ayon_core/hosts/maya/plugins/publish/validate_animated_reference.py index c9dcc662af..2ba2bff6fc 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_animated_reference.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_animated_reference.py @@ -16,7 +16,7 @@ class ValidateAnimatedReferenceRig(pyblish.api.InstancePlugin, hosts = ["maya"] families = ["animation.fbx"] label = "Animated Reference Rig" - accepted_controllers = ["transform", "locator", "joint"] + accepted_controllers = ["transform", "locator"] actions = [ayon_core.hosts.maya.api.action.SelectInvalidAction] optional = False From 888c4ff35434588fc28cc468753a1ac9ce05001f Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Thu, 23 May 2024 12:18:36 +0300 Subject: [PATCH 30/54] revert changes to ayon-core version --- client/ayon_core/version.py | 2 +- package.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/version.py b/client/ayon_core/version.py index 28731bcb47..275e1b1dd6 100644 --- a/client/ayon_core/version.py +++ b/client/ayon_core/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring AYON core addon version.""" -__version__ = "0.3.2-dev.2" +__version__ = "0.3.2-dev.1" diff --git a/package.py b/package.py index f5d1ee3d03..b7b8d2dae6 100644 --- a/package.py +++ b/package.py @@ -1,6 +1,6 @@ name = "core" title = "Core" -version = "0.3.2-dev.2" +version = "0.3.2-dev.1" client_dir = "ayon_core" From d54ddf2210d5f023837abf5ddcf26df760600158 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Thu, 23 May 2024 12:25:39 +0300 Subject: [PATCH 31/54] replace getpass.getuser() with get_ayon_username() --- .../ayon_core/hosts/houdini/plugins/create/create_hda.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py index 957da8f230..7f270b5cc2 100644 --- a/client/ayon_core/hosts/houdini/plugins/create/create_hda.py +++ b/client/ayon_core/hosts/houdini/plugins/create/create_hda.py @@ -1,10 +1,12 @@ # -*- coding: utf-8 -*- """Creator plugin for creating publishable Houdini Digital Assets.""" import ayon_api -import getpass from ayon_core.pipeline import CreatorError from ayon_core.hosts.houdini.api import plugin -from ayon_core.lib import BoolDef +from ayon_core.lib import ( + get_ayon_username, + BoolDef +) import hou from ayon_core.resources import get_ayon_icon_filepath @@ -104,7 +106,7 @@ class CreateHDA(plugin.HoudiniCreator): hda_def.setIcon(get_ayon_icon_filepath()) if pre_create_data.get("set_user"): - hda_def.setUserInfo(getpass.getuser()) + hda_def.setUserInfo(get_ayon_username()) if pre_create_data.get("use_project"): tool_name = hou.shelves.defaultToolName( From 0cccc9a7e8d52abcf7a03750a90d323c945d0d54 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Mon, 3 Jun 2024 21:02:43 +0300 Subject: [PATCH 32/54] add missing dynamic data keys in repair action --- .../ayon_houdini/plugins/publish/validate_subset_name.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/server_addon/houdini/client/ayon_houdini/plugins/publish/validate_subset_name.py b/server_addon/houdini/client/ayon_houdini/plugins/publish/validate_subset_name.py index 999dcc3981..4f15f193fc 100644 --- a/server_addon/houdini/client/ayon_houdini/plugins/publish/validate_subset_name.py +++ b/server_addon/houdini/client/ayon_houdini/plugins/publish/validate_subset_name.py @@ -103,7 +103,13 @@ class ValidateSubsetName(plugin.HoudiniInstancePlugin, instance.context.data["hostName"], instance.data["productType"], variant=instance.data["variant"], - dynamic_data={"asset": folder_entity["name"]} + dynamic_data={ + "asset": folder_entity["name"], + "folder": { + "label": folder_entity["label"], + "name": folder_entity["name"] + } + } ) instance.data["productName"] = product_name From 17ec19f5069860be184733254db79f4a86308de5 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Wed, 12 Jun 2024 22:24:37 +0300 Subject: [PATCH 33/54] set tab shelf location properly and revert unnecessary logic --- .../client/ayon_houdini/plugins/create/create_hda.py | 7 +++---- .../houdini/client/ayon_houdini/plugins/load/load_hda.py | 7 ------- .../client/ayon_houdini/plugins/publish/extract_hda.py | 8 -------- 3 files changed, 3 insertions(+), 19 deletions(-) diff --git a/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py b/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py index c727fe0b09..e0929e16f7 100644 --- a/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py +++ b/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- """Creator plugin for creating publishable Houdini Digital Assets.""" import hou +from assettools import setToolSubmenu + import ayon_api from ayon_core.pipeline import CreatorError from ayon_core.lib import ( @@ -109,10 +111,7 @@ class CreateHDA(plugin.HoudiniCreator): hda_def.setUserInfo(get_ayon_username()) if pre_create_data.get("use_project"): - tool_name = hou.shelves.defaultToolName( - hda_def.nodeTypeCategory().name(), hda_def.nodeTypeName()) - hou.shelves.tool(tool_name).setToolLocations( - ("AYON/{}".format(self.project_name),)) + setToolSubmenu(hda_def, "AYON/{}".format(self.project_name)) return hda_node diff --git a/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py b/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py index 3ee487f496..85477965cd 100644 --- a/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py +++ b/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py @@ -62,13 +62,6 @@ class HdaLoader(plugin.HoudiniLoader): hda_node = parent_node.createNode(name, node_name) hda_node.moveToGoodPosition() - # Set TAB Menu location interactively - # This shouldn't be needed if the Tool Location is saved in the HDA. - tool_name = hou.shelves.defaultToolName( - hda_def.nodeTypeCategory().name(), hda_def.nodeTypeName()) - hou.shelves.tool(tool_name).setToolLocations( - ("AYON/{}".format(context["project"]["name"]),)) - # Imprint it manually data = { "schema": "openpype:container-2.0", diff --git a/server_addon/houdini/client/ayon_houdini/plugins/publish/extract_hda.py b/server_addon/houdini/client/ayon_houdini/plugins/publish/extract_hda.py index 0ff7948a88..e4449d11f8 100644 --- a/server_addon/houdini/client/ayon_houdini/plugins/publish/extract_hda.py +++ b/server_addon/houdini/client/ayon_houdini/plugins/publish/extract_hda.py @@ -25,14 +25,6 @@ class ExtractHDA(plugin.HoudiniExtractorPlugin): hda_def.setOptions(hda_options) hda_def.save(hda_def.libraryFilePath(), hda_node, hda_options) - if instance.data["creator_attributes"].get("use_project"): - # Set TAB Menu location interactively - # This shouldn't be needed if the Tool Location is saved in the HDA. - tool_name = hou.shelves.defaultToolName( - hda_def.nodeTypeCategory().name(), hda_def.nodeTypeName()) - hou.shelves.tool(tool_name).setToolLocations( - ("AYON/{}".format(instance.context.data["projectName"]),)) - if "representations" not in instance.data: instance.data["representations"] = [] From 45f72649464dc6071e6c92789de2176c411133cf Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Wed, 12 Jun 2024 22:47:36 +0300 Subject: [PATCH 34/54] revert changes in subnetwork naming, use postfix _subnet --- .../client/ayon_houdini/plugins/create/create_hda.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py b/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py index e0929e16f7..18b26bb533 100644 --- a/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py +++ b/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py @@ -55,12 +55,12 @@ class CreateHDA(plugin.HoudiniCreator): # selected nodes ... if self.selected_nodes[0].type().name() == "subnet": to_hda = self.selected_nodes[0] - to_hda.setName("{}_HDA".format(node_name), unique_name=True) + to_hda.setName("{}_subnet".format(node_name), unique_name=True) else: parent_node = self.selected_nodes[0].parent() subnet = parent_node.collapseIntoSubnet( self.selected_nodes, - subnet_name="{}_HDA".format(node_name)) + subnet_name="{}_subnet".format(node_name)) subnet.moveToGoodPosition() to_hda = subnet else: @@ -73,7 +73,7 @@ class CreateHDA(plugin.HoudiniCreator): parent_node = pane.pwd() to_hda = parent_node.createNode( - "subnet", node_name="{}_HDA".format(node_name)) + "subnet", node_name="{}_subnet".format(node_name)) if not to_hda.type().definition(): # if node type has not its definition, it is not user # created hda. We test if hda can be created from the node. From 65e8b0383ac4233d7d625ac7c6bfcae231e899f3 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Thu, 13 Jun 2024 22:29:52 +0300 Subject: [PATCH 35/54] update default hda product name profile --- server/settings/tools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/settings/tools.py b/server/settings/tools.py index f73287eafd..3ed12d3d0a 100644 --- a/server/settings/tools.py +++ b/server/settings/tools.py @@ -458,7 +458,7 @@ DEFAULT_TOOLS_VALUES = { ], "task_types": [], "tasks": [], - "template": "{folder[label]}_{variant}" + "template": "{folder[name]}_{variant}" } ], "filter_creator_profiles": [] From 503e8bce3d30ea03d622bea1196e6ff3ff963cb3 Mon Sep 17 00:00:00 2001 From: Mustafa Taher Date: Thu, 13 Jun 2024 22:36:29 +0300 Subject: [PATCH 36/54] skip str casting Co-authored-by: Kayla Man <64118225+moonyuet@users.noreply.github.com> --- .../houdini/client/ayon_houdini/plugins/load/load_hda.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py b/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py index 85477965cd..46fcb74b2c 100644 --- a/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py +++ b/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py @@ -68,7 +68,7 @@ class HdaLoader(plugin.HoudiniLoader): "id": AVALON_CONTAINER_ID, "name": node_name, "namespace": namespace, - "loader": str(self.__class__.__name__), + "loader": self.__class__.__name__, "representation": context["representation"]["id"], } From 121fa8a98b1f204b0d20d004e4178c414c69d772 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Fri, 14 Jun 2024 16:50:19 +0300 Subject: [PATCH 37/54] revert 'use ayon icon as HDA icon' --- .../client/ayon_houdini/plugins/create/create_hda.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py b/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py index 18b26bb533..1b9ffb1b5e 100644 --- a/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py +++ b/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py @@ -9,7 +9,7 @@ from ayon_core.lib import ( get_ayon_username, BoolDef ) -from ayon_core.resources import get_ayon_icon_filepath + from ayon_houdini.api import plugin @@ -104,9 +104,6 @@ class CreateHDA(plugin.HoudiniCreator): # Set Custom settings. hda_def = hda_node.type().definition() - if pre_create_data.get("use_ayon_icon"): - hda_def.setIcon(get_ayon_icon_filepath()) - if pre_create_data.get("set_user"): hda_def.setUserInfo(get_ayon_username()) @@ -149,10 +146,6 @@ class CreateHDA(plugin.HoudiniCreator): def get_pre_create_attr_defs(self): attrs = super(CreateHDA, self).get_pre_create_attr_defs() return attrs + [ - BoolDef("use_ayon_icon", - tooltip="Use Ayon icon for the digital asset.", - default=False, - label="Use AYON Icon"), BoolDef("set_user", tooltip="Set current user as the author of the HDA", default=False, From eea56697995c664107eeeb9358c096021ef06e52 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Fri, 14 Jun 2024 17:31:10 +0300 Subject: [PATCH 38/54] don't transfere creator attribute --- .../client/ayon_houdini/plugins/create/create_hda.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py b/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py index 72107bef72..e03f290ae8 100644 --- a/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py +++ b/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py @@ -128,13 +128,6 @@ class CreateHDA(plugin.HoudiniCreator): def create(self, product_name, instance_data, pre_create_data): instance_data.pop("active", None) - # Transfer settings from pre create to instance - creator_attributes = instance_data.setdefault( - "creator_attributes", dict()) - for key in {"use_project"}: - if key in pre_create_data: - creator_attributes[key] = pre_create_data[key] - return super(CreateHDA, self).create( product_name, instance_data, From 71be4e99a7e04356ea3c3912ab9706dbf99b3333 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Fri, 14 Jun 2024 17:40:06 +0300 Subject: [PATCH 39/54] use the last HDA Def --- .../houdini/client/ayon_houdini/plugins/load/load_hda.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py b/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py index 289b8beb69..eb9a74a7ad 100644 --- a/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py +++ b/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py @@ -55,10 +55,10 @@ class HdaLoader(plugin.HoudiniLoader): if not hda_defs: raise LoadError(f"No HDA definitions found in file: {file_path}") - parent_node = self._create_dedicated_parent_node(hda_defs[0]) + parent_node = self._create_dedicated_parent_node(hda_defs[-1]) # Get the type name from the HDA definition. - type_name = hda_defs[0].nodeTypeName() + type_name = hda_defs[-1].nodeTypeName() hda_node = parent_node.createNode(type_name, node_name) hda_node.moveToGoodPosition() From 819664cf0561956a729accc531f81dc8b20bbf67 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 19 Jun 2024 22:26:02 +0800 Subject: [PATCH 40/54] add option to stripe shader assignment --- .../maya/client/ayon_maya/plugins/create/create_setdress.py | 3 +++ .../client/ayon_maya/plugins/publish/extract_maya_scene_raw.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/server_addon/maya/client/ayon_maya/plugins/create/create_setdress.py b/server_addon/maya/client/ayon_maya/plugins/create/create_setdress.py index 12532e0724..98d6de867f 100644 --- a/server_addon/maya/client/ayon_maya/plugins/create/create_setdress.py +++ b/server_addon/maya/client/ayon_maya/plugins/create/create_setdress.py @@ -15,5 +15,8 @@ class CreateSetDress(plugin.MayaCreator): return [ BoolDef("exactSetMembersOnly", label="Exact Set Members Only", + default=True), + BoolDef("shader", + label="Include shader", default=True) ] diff --git a/server_addon/maya/client/ayon_maya/plugins/publish/extract_maya_scene_raw.py b/server_addon/maya/client/ayon_maya/plugins/publish/extract_maya_scene_raw.py index 6e66353c7a..f0d0c70ae4 100644 --- a/server_addon/maya/client/ayon_maya/plugins/publish/extract_maya_scene_raw.py +++ b/server_addon/maya/client/ayon_maya/plugins/publish/extract_maya_scene_raw.py @@ -96,7 +96,7 @@ class ExtractMayaSceneRaw(plugin.MayaExtractorPlugin, AYONPyblishPluginMixin): "preserve_references" ], constructionHistory=True, - shader=True, + shader=True if instance.data.get("shader", False) else False, constraints=True, expressions=True) From 4265c92ceaaa0c0d3d60dd9123a5e792467f1439 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 19 Jun 2024 22:27:15 +0800 Subject: [PATCH 41/54] make sure shader is always true if it is not in the instance.data --- .../client/ayon_maya/plugins/publish/extract_maya_scene_raw.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server_addon/maya/client/ayon_maya/plugins/publish/extract_maya_scene_raw.py b/server_addon/maya/client/ayon_maya/plugins/publish/extract_maya_scene_raw.py index f0d0c70ae4..fde48afb8f 100644 --- a/server_addon/maya/client/ayon_maya/plugins/publish/extract_maya_scene_raw.py +++ b/server_addon/maya/client/ayon_maya/plugins/publish/extract_maya_scene_raw.py @@ -96,7 +96,7 @@ class ExtractMayaSceneRaw(plugin.MayaExtractorPlugin, AYONPyblishPluginMixin): "preserve_references" ], constructionHistory=True, - shader=True if instance.data.get("shader", False) else False, + shader=True if instance.data.get("shader", True) else False, constraints=True, expressions=True) From 320f97c9c68ff5acd220c5da8f632258f935c2dd Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Wed, 19 Jun 2024 20:32:07 +0300 Subject: [PATCH 42/54] be more explicit about which node to skip --- .../houdini/client/ayon_houdini/plugins/load/load_hda.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py b/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py index eb9a74a7ad..2f8d6aae49 100644 --- a/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py +++ b/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py @@ -96,7 +96,7 @@ class HdaLoader(plugin.HoudiniLoader): parent = node.parent() node.destroy() - if parent.type().category() == hou.objNodeTypeCategory(): + if parent.path() == pipeline.AVALON_CONTAINERS: return # Remove parent if empty. From 928115f25a64f98a83b7593fadfd7142e2d3e35b Mon Sep 17 00:00:00 2001 From: Mustafa Taher Date: Wed, 19 Jun 2024 20:53:05 +0300 Subject: [PATCH 43/54] remove redundant attribute Co-authored-by: Roy Nieterau --- .../client/ayon_houdini/plugins/publish/validate_subset_name.py | 1 - 1 file changed, 1 deletion(-) diff --git a/server_addon/houdini/client/ayon_houdini/plugins/publish/validate_subset_name.py b/server_addon/houdini/client/ayon_houdini/plugins/publish/validate_subset_name.py index 4f15f193fc..a63a4f16c7 100644 --- a/server_addon/houdini/client/ayon_houdini/plugins/publish/validate_subset_name.py +++ b/server_addon/houdini/client/ayon_houdini/plugins/publish/validate_subset_name.py @@ -26,7 +26,6 @@ class ValidateSubsetName(plugin.HoudiniInstancePlugin, """ families = ["staticMesh", "hda"] - hosts = ["houdini"] label = "Validate Product Name" order = ValidateContentsOrder + 0.1 actions = [FixProductNameAction, SelectInvalidAction] From 336d38b21835f02bd04b5a2a4e317d07e5bb94b1 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Wed, 19 Jun 2024 20:56:36 +0300 Subject: [PATCH 44/54] move get_avalon_container to ayon_houdini.api.pipeline --- .../client/ayon_houdini/api/pipeline.py | 25 ++++++++++++++----- .../ayon_houdini/plugins/load/load_hda.py | 18 +------------ 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/server_addon/houdini/client/ayon_houdini/api/pipeline.py b/server_addon/houdini/client/ayon_houdini/api/pipeline.py index 6af4993d25..0ca7de23bd 100644 --- a/server_addon/houdini/client/ayon_houdini/api/pipeline.py +++ b/server_addon/houdini/client/ayon_houdini/api/pipeline.py @@ -221,12 +221,8 @@ def containerise(name, """ - # Ensure AVALON_CONTAINERS subnet exists - subnet = hou.node(AVALON_CONTAINERS) - if subnet is None: - obj_network = hou.node("/obj") - subnet = obj_network.createNode("subnet", - node_name="AVALON_CONTAINERS") + # Get AVALON_CONTAINERS subnet + subnet = get_avalon_container() # Create proper container name container_name = "{}_{}".format(name, suffix or "CON") @@ -401,6 +397,23 @@ def on_new(): _enforce_start_frame() +def get_avalon_container(): + path = AVALON_CONTAINERS + avalon_container = hou.node(path) + if not avalon_container: + # Let's create avalon container secretly + # but make sure the pipeline still is built the + # way we anticipate it was built, asserting it. + assert path == "/obj/AVALON_CONTAINERS" + + parent = hou.node("/obj") + avalon_container = parent.createNode( + "subnet", node_name="AVALON_CONTAINERS" + ) + + return avalon_container + + def _set_context_settings(): """Apply the project settings from the project definition diff --git a/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py b/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py index 2f8d6aae49..d7268da39e 100644 --- a/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py +++ b/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py @@ -12,22 +12,6 @@ from ayon_houdini.api import ( plugin ) -def get_avalon_container(): - path = pipeline.AVALON_CONTAINERS - avalon_container = hou.node(path) - if not avalon_container: - # Let's create avalon container secretly - # but make sure the pipeline still is built the - # way we anticipate it was built, asserting it. - assert path == "/obj/AVALON_CONTAINERS" - - parent = hou.node("/obj") - avalon_container = parent.createNode( - "subnet", node_name="AVALON_CONTAINERS" - ) - - return avalon_container - class HdaLoader(plugin.HoudiniLoader): """Load Houdini Digital Asset file.""" @@ -106,7 +90,7 @@ class HdaLoader(plugin.HoudiniLoader): def _create_dedicated_parent_node(self, hda_def): # Get the root node - parent_node = get_avalon_container() + parent_node = pipeline.get_avalon_container() node = None node_type = None if hda_def.nodeTypeCategory() == hou.objNodeTypeCategory(): From 0ddfaa5b91a2a6d35dec5f6df70bb6094db582a7 Mon Sep 17 00:00:00 2001 From: Mustafa Taher Date: Thu, 20 Jun 2024 16:04:40 +0300 Subject: [PATCH 45/54] refactor `get_avalon_container` to `get_or_create_avalon_container` Co-authored-by: Roy Nieterau --- .../client/ayon_houdini/api/pipeline.py | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/server_addon/houdini/client/ayon_houdini/api/pipeline.py b/server_addon/houdini/client/ayon_houdini/api/pipeline.py index 0ca7de23bd..ba7804cb02 100644 --- a/server_addon/houdini/client/ayon_houdini/api/pipeline.py +++ b/server_addon/houdini/client/ayon_houdini/api/pipeline.py @@ -397,21 +397,16 @@ def on_new(): _enforce_start_frame() -def get_avalon_container(): - path = AVALON_CONTAINERS - avalon_container = hou.node(path) - if not avalon_container: - # Let's create avalon container secretly - # but make sure the pipeline still is built the - # way we anticipate it was built, asserting it. - assert path == "/obj/AVALON_CONTAINERS" +def get_or_create_avalon_container() -> "hou.OpNode": + avalon_container = hou.node(AVALON_CONTAINERS) + if avalon_container: + return avalon_container - parent = hou.node("/obj") - avalon_container = parent.createNode( - "subnet", node_name="AVALON_CONTAINERS" - ) - - return avalon_container + parent_path, name = AVALON_CONTAINERS.rsplit("/", 1) + parent = hou.node(parent_path) + return parent.createNode( + "subnet", node_name=name + ) def _set_context_settings(): From 9757f276a092a119453b21266ad7c34c3c8b66b9 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Thu, 20 Jun 2024 16:12:00 +0300 Subject: [PATCH 46/54] replace `get_avalon_container` calls with `get_or_create_avalon_container` --- server_addon/houdini/client/ayon_houdini/api/pipeline.py | 2 +- .../houdini/client/ayon_houdini/plugins/load/load_hda.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server_addon/houdini/client/ayon_houdini/api/pipeline.py b/server_addon/houdini/client/ayon_houdini/api/pipeline.py index ba7804cb02..be8901d1f9 100644 --- a/server_addon/houdini/client/ayon_houdini/api/pipeline.py +++ b/server_addon/houdini/client/ayon_houdini/api/pipeline.py @@ -222,7 +222,7 @@ def containerise(name, """ # Get AVALON_CONTAINERS subnet - subnet = get_avalon_container() + subnet = get_or_create_avalon_container() # Create proper container name container_name = "{}_{}".format(name, suffix or "CON") diff --git a/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py b/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py index d7268da39e..fcf0e834f8 100644 --- a/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py +++ b/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py @@ -90,7 +90,7 @@ class HdaLoader(plugin.HoudiniLoader): def _create_dedicated_parent_node(self, hda_def): # Get the root node - parent_node = pipeline.get_avalon_container() + parent_node = pipeline.get_or_create_avalon_container() node = None node_type = None if hda_def.nodeTypeCategory() == hou.objNodeTypeCategory(): From 6c5fe9476162b174d294fe42069bcee1afaac372 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Thu, 20 Jun 2024 16:41:28 +0300 Subject: [PATCH 47/54] update dynamic data in CreateHDA --- .../ayon_houdini/plugins/create/create_hda.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py b/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py index e03f290ae8..179a6c2b00 100644 --- a/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py +++ b/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py @@ -185,8 +185,14 @@ class CreateHDA(plugin.HoudiniCreator): instance ) - dynamic_data["folder"] = { - "label": folder_entity["label"], - "name": folder_entity["name"] - } + dynamic_data.update( + { + "asset": folder_entity["name"], + "folder": { + "label": folder_entity["label"], + "name": folder_entity["name"] + } + } + ) + return dynamic_data From 8336a0ff1843c14beffe3ff405aa31591f8be8cd Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 21 Jun 2024 21:42:41 +0800 Subject: [PATCH 48/54] add the setdress setting into ayon setting --- .../ayon_maya/plugins/create/create_setdress.py | 6 ++++-- server_addon/maya/client/ayon_maya/version.py | 2 +- server_addon/maya/package.py | 2 +- server_addon/maya/server/settings/creators.py | 14 ++++++++++++-- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/server_addon/maya/client/ayon_maya/plugins/create/create_setdress.py b/server_addon/maya/client/ayon_maya/plugins/create/create_setdress.py index 98d6de867f..6e1c4e1c4f 100644 --- a/server_addon/maya/client/ayon_maya/plugins/create/create_setdress.py +++ b/server_addon/maya/client/ayon_maya/plugins/create/create_setdress.py @@ -9,14 +9,16 @@ class CreateSetDress(plugin.MayaCreator): label = "Set Dress" product_type = "setdress" icon = "cubes" + exactSetMembersOnly = True + shader = True default_variants = ["Main", "Anim"] def get_instance_attr_defs(self): return [ BoolDef("exactSetMembersOnly", label="Exact Set Members Only", - default=True), + default=self.exactSetMembersOnly), BoolDef("shader", label="Include shader", - default=True) + default=self.shader) ] diff --git a/server_addon/maya/client/ayon_maya/version.py b/server_addon/maya/client/ayon_maya/version.py index 37f9026945..df66e3f399 100644 --- a/server_addon/maya/client/ayon_maya/version.py +++ b/server_addon/maya/client/ayon_maya/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring AYON addon 'maya' version.""" -__version__ = "0.2.4" +__version__ = "0.2.5" diff --git a/server_addon/maya/package.py b/server_addon/maya/package.py index 17614ed9c1..3dd863a1b3 100644 --- a/server_addon/maya/package.py +++ b/server_addon/maya/package.py @@ -1,6 +1,6 @@ name = "maya" title = "Maya" -version = "0.2.4" +version = "0.2.5" client_dir = "ayon_maya" ayon_required_addons = { diff --git a/server_addon/maya/server/settings/creators.py b/server_addon/maya/server/settings/creators.py index 5f3b850a1f..ede33b6eec 100644 --- a/server_addon/maya/server/settings/creators.py +++ b/server_addon/maya/server/settings/creators.py @@ -124,6 +124,14 @@ class CreateVrayProxyModel(BaseSettingsModel): default_factory=list, title="Default Products") +class CreateSetDressModel(BaseSettingsModel): + enabled: bool = SettingsField(True) + exactSetMembersOnly: bool = SettingsField(title="Exact Set Members Only") + shader: bool = SettingsField(title="Include shader") + default_variants: list[str] = SettingsField( + default_factory=list, title="Default Products") + + class CreateMultishotLayout(BasicCreatorModel): shotParent: str = SettingsField(title="Shot Parent Folder") groupLoadedAssets: bool = SettingsField(title="Group Loaded Assets") @@ -217,8 +225,8 @@ class CreatorsModel(BaseSettingsModel): default_factory=BasicCreatorModel, title="Create Rig" ) - CreateSetDress: BasicCreatorModel = SettingsField( - default_factory=BasicCreatorModel, + CreateSetDress: CreateSetDressModel = SettingsField( + default_factory=CreateSetDressModel, title="Create Set Dress" ) CreateVrayProxy: CreateVrayProxyModel = SettingsField( @@ -396,6 +404,8 @@ DEFAULT_CREATORS_SETTINGS = { }, "CreateSetDress": { "enabled": True, + "exactSetMembersOnly": True, + "shader": True, "default_variants": [ "Main", "Anim" From f6c7d508d9fe62976f3027bad9311f374b2e1874 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 21 Jun 2024 21:49:11 +0800 Subject: [PATCH 49/54] add the setdress setting into ayon setting --- .../client/ayon_maya/plugins/publish/extract_maya_scene_raw.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server_addon/maya/client/ayon_maya/plugins/publish/extract_maya_scene_raw.py b/server_addon/maya/client/ayon_maya/plugins/publish/extract_maya_scene_raw.py index fde48afb8f..2052abe648 100644 --- a/server_addon/maya/client/ayon_maya/plugins/publish/extract_maya_scene_raw.py +++ b/server_addon/maya/client/ayon_maya/plugins/publish/extract_maya_scene_raw.py @@ -96,7 +96,7 @@ class ExtractMayaSceneRaw(plugin.MayaExtractorPlugin, AYONPyblishPluginMixin): "preserve_references" ], constructionHistory=True, - shader=True if instance.data.get("shader", True) else False, + shader=instance.data.get("shader", True), constraints=True, expressions=True) From 89eb86a140a8195b45bce495244d7cfd21ebc5f6 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 21 Jun 2024 22:34:41 +0800 Subject: [PATCH 50/54] add support to assign default shaders to the published setdress --- .../plugins/publish/extract_maya_scene_raw.py | 37 +++++++++++++------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/server_addon/maya/client/ayon_maya/plugins/publish/extract_maya_scene_raw.py b/server_addon/maya/client/ayon_maya/plugins/publish/extract_maya_scene_raw.py index 2052abe648..7253dc38c2 100644 --- a/server_addon/maya/client/ayon_maya/plugins/publish/extract_maya_scene_raw.py +++ b/server_addon/maya/client/ayon_maya/plugins/publish/extract_maya_scene_raw.py @@ -5,7 +5,7 @@ import os from ayon_core.lib import BoolDef from ayon_core.pipeline import AVALON_CONTAINER_ID, AYON_CONTAINER_ID from ayon_core.pipeline.publish import AYONPyblishPluginMixin -from ayon_maya.api.lib import maintained_selection +from ayon_maya.api.lib import maintained_selection, shader from ayon_maya.api import plugin from maya import cmds @@ -88,17 +88,30 @@ class ExtractMayaSceneRaw(plugin.MayaExtractorPlugin, AYONPyblishPluginMixin): ) with maintained_selection(): cmds.select(selection, noExpand=True) - cmds.file(path, - force=True, - typ="mayaAscii" if self.scene_type == "ma" else "mayaBinary", # noqa: E501 - exportSelected=True, - preserveReferences=attribute_values[ - "preserve_references" - ], - constructionHistory=True, - shader=instance.data.get("shader", True), - constraints=True, - expressions=True) + if instance.data.get("shader", True): + with shader(selection, shadingEngine="initialShadingGroup"): + cmds.file(path, + force=True, + typ="mayaAscii" if self.scene_type == "ma" else "mayaBinary", # noqa: E501 + exportSelected=True, + preserveReferences=attribute_values[ + "preserve_references" + ], + constructionHistory=True, + shader=instance.data.get("shader", True), + expressions=True) + else: + cmds.file(path, + force=True, + typ="mayaAscii" if self.scene_type == "ma" else "mayaBinary", # noqa: E501 + exportSelected=True, + preserveReferences=attribute_values[ + "preserve_references" + ], + constructionHistory=True, + shader=True, + constraints=True, + expressions=True) if "representations" not in instance.data: instance.data["representations"] = [] From 9b02eed4c6c4620f3b1c08944c0e41f4b8e0fe89 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 21 Jun 2024 23:08:30 +0800 Subject: [PATCH 51/54] add exit stack contextlib for default shader assignment for meshes in the published scene --- .../plugins/publish/extract_maya_scene_raw.py | 29 +++++++------------ 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/server_addon/maya/client/ayon_maya/plugins/publish/extract_maya_scene_raw.py b/server_addon/maya/client/ayon_maya/plugins/publish/extract_maya_scene_raw.py index 7253dc38c2..047b7f6e6c 100644 --- a/server_addon/maya/client/ayon_maya/plugins/publish/extract_maya_scene_raw.py +++ b/server_addon/maya/client/ayon_maya/plugins/publish/extract_maya_scene_raw.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """Extract data as Maya scene (raw).""" import os - +import contextlib from ayon_core.lib import BoolDef from ayon_core.pipeline import AVALON_CONTAINER_ID, AYON_CONTAINER_ID from ayon_core.pipeline.publish import AYONPyblishPluginMixin @@ -88,28 +88,19 @@ class ExtractMayaSceneRaw(plugin.MayaExtractorPlugin, AYONPyblishPluginMixin): ) with maintained_selection(): cmds.select(selection, noExpand=True) - if instance.data.get("shader", True): - with shader(selection, shadingEngine="initialShadingGroup"): - cmds.file(path, - force=True, - typ="mayaAscii" if self.scene_type == "ma" else "mayaBinary", # noqa: E501 - exportSelected=True, - preserveReferences=attribute_values[ - "preserve_references" - ], - constructionHistory=True, - shader=instance.data.get("shader", True), - expressions=True) - else: + with contextlib.ExitStack() as stack: + if not instance.data.get("shader", True): + # Fix bug where export without shader may import the geometry 'green' + # due to the lack of any shader on import. + stack.enter_context(shader(selection, shadingEngine="initialShadingGroup")) + cmds.file(path, force=True, - typ="mayaAscii" if self.scene_type == "ma" else "mayaBinary", # noqa: E501 + typ="mayaAscii" if self.scene_type == "ma" else "mayaBinary", exportSelected=True, - preserveReferences=attribute_values[ - "preserve_references" - ], + preserveReferences=attribute_values["preserve_references"], constructionHistory=True, - shader=True, + shader=instance.data.get("shader", True), constraints=True, expressions=True) From 201d36589935b92c137a2a4810e2a406ad0d9be5 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 24 Jun 2024 12:31:29 +0200 Subject: [PATCH 52/54] Cosmetics (fix docstring triple quotes) --- .../client/ayon_aftereffects/api/workfile_template_builder.py | 2 +- .../client/ayon_blender/plugins/publish/extract_thumbnail.py | 2 +- .../client/ayon_hiero/vendor/google/protobuf/text_format.py | 2 +- .../nuke/client/ayon_nuke/vendor/google/protobuf/text_format.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/server_addon/aftereffects/client/ayon_aftereffects/api/workfile_template_builder.py b/server_addon/aftereffects/client/ayon_aftereffects/api/workfile_template_builder.py index 77fd1059b5..a4d90be548 100644 --- a/server_addon/aftereffects/client/ayon_aftereffects/api/workfile_template_builder.py +++ b/server_addon/aftereffects/client/ayon_aftereffects/api/workfile_template_builder.py @@ -92,7 +92,7 @@ class AEPlaceholderPlugin(PlaceholderPlugin): return None, None def _collect_scene_placeholders(self): - """" Cache placeholder data to shared data. + """ Cache placeholder data to shared data. Returns: (list) of dicts """ diff --git a/server_addon/blender/client/ayon_blender/plugins/publish/extract_thumbnail.py b/server_addon/blender/client/ayon_blender/plugins/publish/extract_thumbnail.py index 40097aaa89..e3bce8bf73 100644 --- a/server_addon/blender/client/ayon_blender/plugins/publish/extract_thumbnail.py +++ b/server_addon/blender/client/ayon_blender/plugins/publish/extract_thumbnail.py @@ -83,7 +83,7 @@ class ExtractThumbnail(plugin.BlenderExtractor): instance.data["representations"].append(representation) def _fix_output_path(self, filepath): - """"Workaround to return correct filepath. + """Workaround to return correct filepath. To workaround this we just glob.glob() for any file extensions and assume the latest modified file is the correct file and return it. diff --git a/server_addon/hiero/client/ayon_hiero/vendor/google/protobuf/text_format.py b/server_addon/hiero/client/ayon_hiero/vendor/google/protobuf/text_format.py index 412385c26f..39739e21fb 100644 --- a/server_addon/hiero/client/ayon_hiero/vendor/google/protobuf/text_format.py +++ b/server_addon/hiero/client/ayon_hiero/vendor/google/protobuf/text_format.py @@ -548,7 +548,7 @@ class _Printer(object): self.out.write(' ' if self.as_one_line else '\n') def _PrintShortRepeatedPrimitivesValue(self, field, value): - """"Prints short repeated primitives value.""" + """Prints short repeated primitives value.""" # Note: this is called only when value has at least one element. self._PrintFieldName(field) self.out.write(' [') diff --git a/server_addon/nuke/client/ayon_nuke/vendor/google/protobuf/text_format.py b/server_addon/nuke/client/ayon_nuke/vendor/google/protobuf/text_format.py index 412385c26f..39739e21fb 100644 --- a/server_addon/nuke/client/ayon_nuke/vendor/google/protobuf/text_format.py +++ b/server_addon/nuke/client/ayon_nuke/vendor/google/protobuf/text_format.py @@ -548,7 +548,7 @@ class _Printer(object): self.out.write(' ' if self.as_one_line else '\n') def _PrintShortRepeatedPrimitivesValue(self, field, value): - """"Prints short repeated primitives value.""" + """Prints short repeated primitives value.""" # Note: this is called only when value has at least one element. self._PrintFieldName(field) self.out.write(' [') From 28dede482fedddebf272696c85b21db8fca909f3 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 24 Jun 2024 14:37:48 +0200 Subject: [PATCH 53/54] Update server_addon/aftereffects/client/ayon_aftereffects/api/workfile_template_builder.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- .../client/ayon_aftereffects/api/workfile_template_builder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server_addon/aftereffects/client/ayon_aftereffects/api/workfile_template_builder.py b/server_addon/aftereffects/client/ayon_aftereffects/api/workfile_template_builder.py index a4d90be548..7fbd469851 100644 --- a/server_addon/aftereffects/client/ayon_aftereffects/api/workfile_template_builder.py +++ b/server_addon/aftereffects/client/ayon_aftereffects/api/workfile_template_builder.py @@ -92,7 +92,7 @@ class AEPlaceholderPlugin(PlaceholderPlugin): return None, None def _collect_scene_placeholders(self): - """ Cache placeholder data to shared data. + """Cache placeholder data to shared data. Returns: (list) of dicts """ From e342f9fe0d6594e930f28ed83617ee61c33a7602 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 24 Jun 2024 14:49:23 +0200 Subject: [PATCH 54/54] Revert changes to vendorized files Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- .../client/ayon_hiero/vendor/google/protobuf/text_format.py | 2 +- .../nuke/client/ayon_nuke/vendor/google/protobuf/text_format.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server_addon/hiero/client/ayon_hiero/vendor/google/protobuf/text_format.py b/server_addon/hiero/client/ayon_hiero/vendor/google/protobuf/text_format.py index 39739e21fb..412385c26f 100644 --- a/server_addon/hiero/client/ayon_hiero/vendor/google/protobuf/text_format.py +++ b/server_addon/hiero/client/ayon_hiero/vendor/google/protobuf/text_format.py @@ -548,7 +548,7 @@ class _Printer(object): self.out.write(' ' if self.as_one_line else '\n') def _PrintShortRepeatedPrimitivesValue(self, field, value): - """Prints short repeated primitives value.""" + """"Prints short repeated primitives value.""" # Note: this is called only when value has at least one element. self._PrintFieldName(field) self.out.write(' [') diff --git a/server_addon/nuke/client/ayon_nuke/vendor/google/protobuf/text_format.py b/server_addon/nuke/client/ayon_nuke/vendor/google/protobuf/text_format.py index 39739e21fb..412385c26f 100644 --- a/server_addon/nuke/client/ayon_nuke/vendor/google/protobuf/text_format.py +++ b/server_addon/nuke/client/ayon_nuke/vendor/google/protobuf/text_format.py @@ -548,7 +548,7 @@ class _Printer(object): self.out.write(' ' if self.as_one_line else '\n') def _PrintShortRepeatedPrimitivesValue(self, field, value): - """Prints short repeated primitives value.""" + """"Prints short repeated primitives value.""" # Note: this is called only when value has at least one element. self._PrintFieldName(field) self.out.write(' [')