From a644949a29b017f2d38c6697fd73c67e0d11f1c5 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 29 Mar 2023 15:21:03 +0800 Subject: [PATCH 01/71] make sure the render dialog is close for the update of resolution and other render settings --- openpype/hosts/max/api/lib.py | 8 +++++++- openpype/hosts/max/plugins/create/create_render.py | 7 +++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/max/api/lib.py b/openpype/hosts/max/api/lib.py index ac7d75db08..519eeffd7f 100644 --- a/openpype/hosts/max/api/lib.py +++ b/openpype/hosts/max/api/lib.py @@ -173,10 +173,16 @@ def set_scene_resolution(width: int, height: int): None """ + # make sure the render dialog is closed + # for the update of resolution + # Changing the Render Setup dialog settingsshould be done + # with the actual Render Setup dialog in a closed state. + if rt.renderSceneDialog.isOpen(): + rt.renderSceneDialog.close() + rt.renderWidth = width rt.renderHeight = height - def reset_scene_resolution(): """Apply the scene resolution from the project definition diff --git a/openpype/hosts/max/plugins/create/create_render.py b/openpype/hosts/max/plugins/create/create_render.py index 269fff2e32..a8720f464d 100644 --- a/openpype/hosts/max/plugins/create/create_render.py +++ b/openpype/hosts/max/plugins/create/create_render.py @@ -27,6 +27,13 @@ class CreateRender(plugin.MaxCreator): # for additional work on the node: # instance_node = rt.getNodeByName(instance.get("instance_node")) + # make sure the render dialog is closed + # for the update of resolution + # Changing the Render Setup dialog settings should be done + # with the actual Render Setup dialog in a closed state. + if rt.renderSceneDialog.isOpen(): + rt.renderSceneDialog.close() + # set viewport camera for rendering(mandatory for deadline) RenderSettings().set_render_camera(sel_obj) # set output paths for rendering(mandatory for deadline) From 0079322a6de30b70108dd5103bb04403a0730e56 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 31 Mar 2023 16:25:51 +0800 Subject: [PATCH 02/71] close the render setup dialog before the render settings --- openpype/hosts/max/api/lib_rendersettings.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openpype/hosts/max/api/lib_rendersettings.py b/openpype/hosts/max/api/lib_rendersettings.py index 4940265a23..e7f4ee1e6b 100644 --- a/openpype/hosts/max/api/lib_rendersettings.py +++ b/openpype/hosts/max/api/lib_rendersettings.py @@ -105,6 +105,9 @@ class RenderSettings(object): rt.rendSaveFile = True + if rt.renderSceneDialog.isOpen(): + rt.renderSceneDialog.close() + def arnold_setup(self): # get Arnold RenderView run in the background # for setting up renderable camera From ee8b5e770013b42553b3c3e32aec44d37479728f Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 31 Mar 2023 16:28:41 +0800 Subject: [PATCH 03/71] cleanup --- openpype/hosts/max/plugins/create/create_render.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openpype/hosts/max/plugins/create/create_render.py b/openpype/hosts/max/plugins/create/create_render.py index a8720f464d..68ae5eac72 100644 --- a/openpype/hosts/max/plugins/create/create_render.py +++ b/openpype/hosts/max/plugins/create/create_render.py @@ -31,8 +31,6 @@ class CreateRender(plugin.MaxCreator): # for the update of resolution # Changing the Render Setup dialog settings should be done # with the actual Render Setup dialog in a closed state. - if rt.renderSceneDialog.isOpen(): - rt.renderSceneDialog.close() # set viewport camera for rendering(mandatory for deadline) RenderSettings().set_render_camera(sel_obj) From 6872e32c1eca3b739aed578b6aa059efbf2348bc Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 11 Apr 2023 21:45:16 +0200 Subject: [PATCH 04/71] Generate shelves only in UI mode + defer generation to avoid slow Houdini launch on Windows --- openpype/hosts/houdini/api/pipeline.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/houdini/api/pipeline.py b/openpype/hosts/houdini/api/pipeline.py index 45e2f8f87f..62a8fba55e 100644 --- a/openpype/hosts/houdini/api/pipeline.py +++ b/openpype/hosts/houdini/api/pipeline.py @@ -81,7 +81,13 @@ class HoudiniHost(HostBase, IWorkfileHost, ILoadHost, IPublishHost): # TODO: make sure this doesn't trigger when # opening with last workfile. _set_context_settings() - shelves.generate_shelves() + + if not IS_HEADLESS: + import hdefereval # noqa, hdefereval is only available in ui mode + # Defer generation of shelves due to issue on Windows where shelf + # initialization during start up delays Houdini UI by minutes + # making it extremely slow to launch. + hdefereval.executeDeferred(shelves.generate_shelves) def has_unsaved_changes(self): return hou.hipFile.hasUnsavedChanges() From db72ed2e634389e4f57ee555585efb1b934c3e32 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 18 Apr 2023 15:46:47 +0800 Subject: [PATCH 05/71] the resolution and the frame range set correctly before saving the scene --- openpype/hosts/max/api/pipeline.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openpype/hosts/max/api/pipeline.py b/openpype/hosts/max/api/pipeline.py index dacc402318..957c674518 100644 --- a/openpype/hosts/max/api/pipeline.py +++ b/openpype/hosts/max/api/pipeline.py @@ -52,8 +52,11 @@ class MaxHost(HostBase, IWorkfileHost, ILoadHost, INewPublisher): def context_setting(): return lib.set_context_setting() + rt.callbacks.addScript(rt.Name('systemPostNew'), context_setting) + rt.callbacks.addScript(rt.Name('filePreSave'), + context_setting) def has_unsaved_changes(self): # TODO: how to get it from 3dsmax? From 973caf2d6de18b1f63384aef8089a0908878b4ba Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 18 Apr 2023 15:56:13 +0800 Subject: [PATCH 06/71] not adding the before save callback --- openpype/hosts/max/api/pipeline.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openpype/hosts/max/api/pipeline.py b/openpype/hosts/max/api/pipeline.py index 957c674518..50fe30b299 100644 --- a/openpype/hosts/max/api/pipeline.py +++ b/openpype/hosts/max/api/pipeline.py @@ -55,8 +55,6 @@ class MaxHost(HostBase, IWorkfileHost, ILoadHost, INewPublisher): rt.callbacks.addScript(rt.Name('systemPostNew'), context_setting) - rt.callbacks.addScript(rt.Name('filePreSave'), - context_setting) def has_unsaved_changes(self): # TODO: how to get it from 3dsmax? From 5f78ba9bb8a4c5747618b6f669d9c0ddd287a363 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 18 Apr 2023 16:06:20 +0800 Subject: [PATCH 07/71] adding callback to reset the resolution when opening the file --- openpype/hosts/max/api/pipeline.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openpype/hosts/max/api/pipeline.py b/openpype/hosts/max/api/pipeline.py index 50fe30b299..ac841d395f 100644 --- a/openpype/hosts/max/api/pipeline.py +++ b/openpype/hosts/max/api/pipeline.py @@ -56,6 +56,9 @@ class MaxHost(HostBase, IWorkfileHost, ILoadHost, INewPublisher): rt.callbacks.addScript(rt.Name('systemPostNew'), context_setting) + rt.callbacks.addScript(rt.Name('filePostOpen'), + context_setting) + def has_unsaved_changes(self): # TODO: how to get it from 3dsmax? return True From 5e012d6be254dfa68721d5f08a981cafecbc8842 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 21 Apr 2023 17:29:47 +0800 Subject: [PATCH 08/71] add validator for resolution setting --- openpype/hosts/max/api/pipeline.py | 3 - .../publish/validate_resolution_setting.py | 59 +++++++++++++++++++ 2 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 openpype/hosts/max/plugins/publish/validate_resolution_setting.py diff --git a/openpype/hosts/max/api/pipeline.py b/openpype/hosts/max/api/pipeline.py index ac841d395f..50fe30b299 100644 --- a/openpype/hosts/max/api/pipeline.py +++ b/openpype/hosts/max/api/pipeline.py @@ -56,9 +56,6 @@ class MaxHost(HostBase, IWorkfileHost, ILoadHost, INewPublisher): rt.callbacks.addScript(rt.Name('systemPostNew'), context_setting) - rt.callbacks.addScript(rt.Name('filePostOpen'), - context_setting) - def has_unsaved_changes(self): # TODO: how to get it from 3dsmax? return True diff --git a/openpype/hosts/max/plugins/publish/validate_resolution_setting.py b/openpype/hosts/max/plugins/publish/validate_resolution_setting.py new file mode 100644 index 0000000000..43a3a3a278 --- /dev/null +++ b/openpype/hosts/max/plugins/publish/validate_resolution_setting.py @@ -0,0 +1,59 @@ +import pyblish.api +from openpype.pipeline import ( + PublishValidationError, + OptionalPyblishPluginMixin +) +from pymxs import runtime as rt +from openpype.hosts.max.api.lib import reset_scene_resolution + +from openpype.pipeline.context_tools import ( + get_current_project_asset, + get_current_project +) + + +class ValidateResolutionSetting(pyblish.api.InstancePlugin, + OptionalPyblishPluginMixin): + """Validate the resolution setting aligned with DB""" + + order = pyblish.api.ValidatorOrder- 0.01 + families = ["maxrender"] + hosts = ["max"] + label = "Validate Resolution Setting" + optional = True + + def process(self, instance): + if not self.is_active(instance.data): + return + width, height = self.get_db_resolution(instance) + current_width = rt.renderwidth + current_height = rt.renderHeight + if current_width != width and current_height != height: + raise PublishValidationError("Resolution Setting" + " not aligned with DB") + if current_width != width: + raise PublishValidationError("Width in Resolution Setting " + "not aligned with DB") + + if current_height != height: + raise PublishValidationError("Height in Resolution Setting " + "not aligned with DB") + + + def get_db_resolution(self, instance): + data = ["data.resolutionWidth", "data.resolutionHeight"] + project_resolution = get_current_project(fields=data) + project_resolution_data = project_resolution["data"] + asset_resolution = get_current_project_asset(fields=data) + asset_resolution_data = asset_resolution["data"] + # Set project resolution + project_width = int(project_resolution_data.get("resolutionWidth", 1920)) + project_height = int(project_resolution_data.get("resolutionHeight", 1080)) + width = int(asset_resolution_data.get("resolutionWidth", project_width)) + height = int(asset_resolution_data.get("resolutionHeight", project_height)) + + return width, height + + @classmethod + def repair(cls, instance): + reset_scene_resolution() From dac51f41ec5d97384698faf0f19e4ba398d96be6 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 21 Apr 2023 17:32:11 +0800 Subject: [PATCH 09/71] hound fix --- .../publish/validate_resolution_setting.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/max/plugins/publish/validate_resolution_setting.py b/openpype/hosts/max/plugins/publish/validate_resolution_setting.py index 43a3a3a278..ce1f8a975d 100644 --- a/openpype/hosts/max/plugins/publish/validate_resolution_setting.py +++ b/openpype/hosts/max/plugins/publish/validate_resolution_setting.py @@ -16,7 +16,7 @@ class ValidateResolutionSetting(pyblish.api.InstancePlugin, OptionalPyblishPluginMixin): """Validate the resolution setting aligned with DB""" - order = pyblish.api.ValidatorOrder- 0.01 + order = pyblish.api.ValidatorOrder - 0.01 families = ["maxrender"] hosts = ["max"] label = "Validate Resolution Setting" @@ -39,7 +39,6 @@ class ValidateResolutionSetting(pyblish.api.InstancePlugin, raise PublishValidationError("Height in Resolution Setting " "not aligned with DB") - def get_db_resolution(self, instance): data = ["data.resolutionWidth", "data.resolutionHeight"] project_resolution = get_current_project(fields=data) @@ -47,10 +46,17 @@ class ValidateResolutionSetting(pyblish.api.InstancePlugin, asset_resolution = get_current_project_asset(fields=data) asset_resolution_data = asset_resolution["data"] # Set project resolution - project_width = int(project_resolution_data.get("resolutionWidth", 1920)) - project_height = int(project_resolution_data.get("resolutionHeight", 1080)) - width = int(asset_resolution_data.get("resolutionWidth", project_width)) - height = int(asset_resolution_data.get("resolutionHeight", project_height)) + project_width = int( + project_resolution_data.get("resolutionWidth", 1920) + ) + project_height = int( + project_resolution_data.get("resolutionHeight", 1080)) + width = int( + asset_resolution_data.get("resolutionWidth", project_width) + ) + height = int( + asset_resolution_data.get("resolutionHeight", project_height) + ) return width, height From 90f12d15e050e0136eaec50a53d2049385e3fcf6 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 21 Apr 2023 17:33:08 +0800 Subject: [PATCH 10/71] hound fix --- .../max/plugins/publish/validate_resolution_setting.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/max/plugins/publish/validate_resolution_setting.py b/openpype/hosts/max/plugins/publish/validate_resolution_setting.py index ce1f8a975d..9424b24380 100644 --- a/openpype/hosts/max/plugins/publish/validate_resolution_setting.py +++ b/openpype/hosts/max/plugins/publish/validate_resolution_setting.py @@ -47,16 +47,13 @@ class ValidateResolutionSetting(pyblish.api.InstancePlugin, asset_resolution_data = asset_resolution["data"] # Set project resolution project_width = int( - project_resolution_data.get("resolutionWidth", 1920) - ) + project_resolution_data.get("resolutionWidth", 1920)) project_height = int( project_resolution_data.get("resolutionHeight", 1080)) width = int( - asset_resolution_data.get("resolutionWidth", project_width) - ) + asset_resolution_data.get("resolutionWidth", project_width)) height = int( - asset_resolution_data.get("resolutionHeight", project_height) - ) + asset_resolution_data.get("resolutionHeight", project_height)) return width, height From a1eff27bbfcb5e54e05061b644245c4eae9deaeb Mon Sep 17 00:00:00 2001 From: Jacob Danell Date: Fri, 28 Apr 2023 09:17:09 +0200 Subject: [PATCH 11/71] Added OptionalPyblishPluginMixin and is_active check --- .../plugins/publish/increment_current_file.py | 19 ++++++++++++++----- .../publish/validate_background_depth.py | 15 ++++++++++----- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/openpype/hosts/fusion/plugins/publish/increment_current_file.py b/openpype/hosts/fusion/plugins/publish/increment_current_file.py index 42891446f7..4facd61893 100644 --- a/openpype/hosts/fusion/plugins/publish/increment_current_file.py +++ b/openpype/hosts/fusion/plugins/publish/increment_current_file.py @@ -1,7 +1,10 @@ import pyblish.api +from openpype.pipeline import OptionalPyblishPluginMixin -class FusionIncrementCurrentFile(pyblish.api.ContextPlugin): +class FusionIncrementCurrentFile( + pyblish.api.ContextPlugin, OptionalPyblishPluginMixin +): """Increment the current file. Saves the current file with an increased version number. @@ -15,15 +18,21 @@ class FusionIncrementCurrentFile(pyblish.api.ContextPlugin): optional = True def process(self, context): + if not self.is_active(context.data): + return from openpype.lib import version_up from openpype.pipeline.publish import get_errored_plugins_from_context errored_plugins = get_errored_plugins_from_context(context) - if any(plugin.__name__ == "FusionSubmitDeadline" - for plugin in errored_plugins): - raise RuntimeError("Skipping incrementing current file because " - "submission to render farm failed.") + if any( + plugin.__name__ == "FusionSubmitDeadline" + for plugin in errored_plugins + ): + raise RuntimeError( + "Skipping incrementing current file because " + "submission to render farm failed." + ) comp = context.data.get("currentComp") assert comp, "Must have comp" diff --git a/openpype/hosts/fusion/plugins/publish/validate_background_depth.py b/openpype/hosts/fusion/plugins/publish/validate_background_depth.py index db2c4f0dd9..384f6c2979 100644 --- a/openpype/hosts/fusion/plugins/publish/validate_background_depth.py +++ b/openpype/hosts/fusion/plugins/publish/validate_background_depth.py @@ -1,12 +1,14 @@ import pyblish.api -from openpype.pipeline.publish import RepairAction +from openpype.pipeline import publish, OptionalPyblishPluginMixin from openpype.pipeline import PublishValidationError from openpype.hosts.fusion.api.action import SelectInvalidAction -class ValidateBackgroundDepth(pyblish.api.InstancePlugin): +class ValidateBackgroundDepth( + pyblish.api.InstancePlugin, OptionalPyblishPluginMixin +): """Validate if all Background tool are set to float32 bit""" order = pyblish.api.ValidatorOrder @@ -15,11 +17,10 @@ class ValidateBackgroundDepth(pyblish.api.InstancePlugin): families = ["render"] optional = True - actions = [SelectInvalidAction, RepairAction] + actions = [SelectInvalidAction, publish.RepairAction] @classmethod def get_invalid(cls, instance): - context = instance.context comp = context.data.get("currentComp") assert comp, "Must have Comp object" @@ -31,12 +32,16 @@ class ValidateBackgroundDepth(pyblish.api.InstancePlugin): return [i for i in backgrounds if i.GetInput("Depth") != 4.0] def process(self, instance): + if not self.is_active(instance.data): + return + invalid = self.get_invalid(instance) if invalid: raise PublishValidationError( "Found {} Backgrounds tools which" " are not set to float32".format(len(invalid)), - title=self.label) + title=self.label, + ) @classmethod def repair(cls, instance): From 1cf5a9e6a726d68f995da56933edba7ebea00dea Mon Sep 17 00:00:00 2001 From: Jacob Danell Date: Fri, 28 Apr 2023 09:24:17 +0200 Subject: [PATCH 12/71] Cleaned up imports --- .../hosts/fusion/plugins/publish/increment_current_file.py | 1 + .../fusion/plugins/publish/validate_background_depth.py | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/fusion/plugins/publish/increment_current_file.py b/openpype/hosts/fusion/plugins/publish/increment_current_file.py index 4facd61893..938a0ed698 100644 --- a/openpype/hosts/fusion/plugins/publish/increment_current_file.py +++ b/openpype/hosts/fusion/plugins/publish/increment_current_file.py @@ -1,4 +1,5 @@ import pyblish.api + from openpype.pipeline import OptionalPyblishPluginMixin diff --git a/openpype/hosts/fusion/plugins/publish/validate_background_depth.py b/openpype/hosts/fusion/plugins/publish/validate_background_depth.py index 384f6c2979..6908889eb4 100644 --- a/openpype/hosts/fusion/plugins/publish/validate_background_depth.py +++ b/openpype/hosts/fusion/plugins/publish/validate_background_depth.py @@ -1,7 +1,10 @@ import pyblish.api -from openpype.pipeline import publish, OptionalPyblishPluginMixin -from openpype.pipeline import PublishValidationError +from openpype.pipeline import ( + publish, + OptionalPyblishPluginMixin, + PublishValidationError, +) from openpype.hosts.fusion.api.action import SelectInvalidAction From d5b719b8c87ca2cee643b460436852e64bc5c912 Mon Sep 17 00:00:00 2001 From: Jacob Danell Date: Fri, 28 Apr 2023 11:00:51 +0200 Subject: [PATCH 13/71] Made name more clear when showing up under `Context` in publisher --- openpype/hosts/fusion/plugins/publish/increment_current_file.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/fusion/plugins/publish/increment_current_file.py b/openpype/hosts/fusion/plugins/publish/increment_current_file.py index 938a0ed698..ed0fd0fbc8 100644 --- a/openpype/hosts/fusion/plugins/publish/increment_current_file.py +++ b/openpype/hosts/fusion/plugins/publish/increment_current_file.py @@ -12,7 +12,7 @@ class FusionIncrementCurrentFile( """ - label = "Increment current file" + label = "Increment workfile version" order = pyblish.api.IntegratorOrder + 9.0 hosts = ["fusion"] families = ["workfile"] From 4f5a85aee0d48738cfae3fda8acdf453d3e2556f Mon Sep 17 00:00:00 2001 From: Jacob Danell Date: Fri, 28 Apr 2023 11:01:26 +0200 Subject: [PATCH 14/71] Removed familiy so it can version up even if workfile isn't published --- openpype/hosts/fusion/plugins/publish/increment_current_file.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/fusion/plugins/publish/increment_current_file.py b/openpype/hosts/fusion/plugins/publish/increment_current_file.py index ed0fd0fbc8..de6f697073 100644 --- a/openpype/hosts/fusion/plugins/publish/increment_current_file.py +++ b/openpype/hosts/fusion/plugins/publish/increment_current_file.py @@ -15,7 +15,6 @@ class FusionIncrementCurrentFile( label = "Increment workfile version" order = pyblish.api.IntegratorOrder + 9.0 hosts = ["fusion"] - families = ["workfile"] optional = True def process(self, context): From eb78b8359b31ded4a4f3339b7d983599df667aff Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 28 Apr 2023 17:47:09 +0800 Subject: [PATCH 15/71] add validators and change to take the frame range from the render setting --- openpype/hosts/max/api/lib.py | 8 ++- openpype/hosts/max/api/lib_renderproducts.py | 5 +- .../max/plugins/publish/collect_render.py | 4 +- .../plugins/publish/validate_frame_range.py | 61 +++++++++++++++++++ .../publish/validate_frame_range_type.py | 32 ++++++++++ 5 files changed, 103 insertions(+), 7 deletions(-) create mode 100644 openpype/hosts/max/plugins/publish/validate_frame_range.py create mode 100644 openpype/hosts/max/plugins/publish/validate_frame_range_type.py diff --git a/openpype/hosts/max/api/lib.py b/openpype/hosts/max/api/lib.py index ad9a450cad..7d629922fc 100644 --- a/openpype/hosts/max/api/lib.py +++ b/openpype/hosts/max/api/lib.py @@ -150,10 +150,10 @@ def set_framerange(start_frame, end_frame): Todo: Current type is hard-coded, there should be a custom setting for this. """ - rt.rendTimeType = 4 + rt.rendTimeType = 3 if start_frame is not None and end_frame is not None: - frame_range = "{0}-{1}".format(start_frame, end_frame) - rt.rendPickupFrames = frame_range + rt.rendStart = int(start_frame) + rt.rendEnd = int(end_frame) def get_multipass_setting(project_setting=None): @@ -243,6 +243,7 @@ def reset_frame_range(fps: bool = True): frame_end = frame_range["frameEnd"] + int(frame_range["handleEnd"]) frange_cmd = f"animationRange = interval {frame_start} {frame_end}" rt.execute(frange_cmd) + set_framerange(frame_start, frame_end) def set_context_setting(): @@ -259,6 +260,7 @@ def set_context_setting(): None """ reset_scene_resolution() + reset_frame_range() def get_max_version(): diff --git a/openpype/hosts/max/api/lib_renderproducts.py b/openpype/hosts/max/api/lib_renderproducts.py index 350eb97661..8224d589ad 100644 --- a/openpype/hosts/max/api/lib_renderproducts.py +++ b/openpype/hosts/max/api/lib_renderproducts.py @@ -36,8 +36,9 @@ class RenderProducts(object): container) context = get_current_project_asset() - startFrame = context["data"].get("frameStart") - endFrame = context["data"].get("frameEnd") + 1 + # TODO: change the frame range follows the current render setting + startFrame = int(rt.rendStart) + endFrame = int(rt.rendEnd) + 1 img_fmt = self._project_settings["max"]["RenderSettings"]["image_format"] # noqa full_render_list = self.beauty_render_product(output_file, diff --git a/openpype/hosts/max/plugins/publish/collect_render.py b/openpype/hosts/max/plugins/publish/collect_render.py index b040467522..9d93a40021 100644 --- a/openpype/hosts/max/plugins/publish/collect_render.py +++ b/openpype/hosts/max/plugins/publish/collect_render.py @@ -59,8 +59,8 @@ class CollectRender(pyblish.api.InstancePlugin): "source": filepath, "expectedFiles": render_layer_files, "plugin": "3dsmax", - "frameStart": context.data['frameStart'], - "frameEnd": context.data['frameEnd'], + "frameStart": int(rt.rendStart), + "frameEnd": int(rt.rendEnd), "version": version_int, "farm": True } diff --git a/openpype/hosts/max/plugins/publish/validate_frame_range.py b/openpype/hosts/max/plugins/publish/validate_frame_range.py new file mode 100644 index 0000000000..2e1d7c9177 --- /dev/null +++ b/openpype/hosts/max/plugins/publish/validate_frame_range.py @@ -0,0 +1,61 @@ +import pyblish.api + +from pymxs import runtime as rt +from openpype.pipeline import ( + OptionalPyblishPluginMixin +) +from openpype.pipeline.publish import ( + RepairAction, + ValidateContentsOrder, + PublishValidationError +) + + +class ValidateFrameRange(pyblish.api.InstancePlugin, + OptionalPyblishPluginMixin): + """Validates the frame ranges. + + This is an optional validator checking if the frame range on instance + matches the frame range specified for the asset. + + It also validates render frame ranges of render layers. + + Repair action will change everything to match the asset frame range. + + This can be turned off by the artist to allow custom ranges. + """ + + label = "Validate Frame Range" + order = ValidateContentsOrder + families = ["maxrender"] + hosts = ["max"] + optional = True + actions = [RepairAction] + + def process(self, instance): + if not self.is_active(instance.data): + self.log.info("Skipping validation...") + return + context = instance.context + + frame_start = int(context.data.get("frameStart")) + frame_end = int(context.data.get("frameEnd")) + + inst_frame_start = int(instance.data.get("frameStart")) + inst_frame_end = int(instance.data.get("frameEnd")) + + + if frame_start != inst_frame_start: + raise PublishValidationError( + "startFrame on instance does not match" + " with startFrame from the context data") + + if frame_end != inst_frame_end: + raise PublishValidationError( + "endFrame on instance does not match" + " with endFrame from the context data") + + @classmethod + def repair(cls, instance): + rt.rendStart = instance.context.data.get("frameStart") + rt.rendEnd = instance.context.data.get("frameEnd") diff --git a/openpype/hosts/max/plugins/publish/validate_frame_range_type.py b/openpype/hosts/max/plugins/publish/validate_frame_range_type.py new file mode 100644 index 0000000000..2403595b3b --- /dev/null +++ b/openpype/hosts/max/plugins/publish/validate_frame_range_type.py @@ -0,0 +1,32 @@ +import pyblish.api + +from pymxs import runtime as rt +from openpype.pipeline.publish import ( + RepairAction, + ValidateContentsOrder, + PublishValidationError +) + + +class ValidateFrameRangeType(pyblish.api.InstancePlugin): + """ + Validates whether the User + specified Frame Range(Type 3) is used in render setting + + """ + + label = "Validate Render Frame Range Type" + order = ValidateContentsOrder + families = ["maxrender"] + hosts = ["max"] + actions = [RepairAction] + + def process(self, instance): + if rt.rendTimeType != 3: + raise PublishValidationError("Incorrect type of frame range" + " used in render setting..") + + @classmethod + def repair(cls, instance): + rt.renderTimeType = 3 + return instance From c54447372308ac7fda9d91aa16a0ced50480ad17 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 28 Apr 2023 17:59:36 +0800 Subject: [PATCH 16/71] set frame range validator to switch off by default --- openpype/hosts/max/plugins/publish/validate_frame_range.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/max/plugins/publish/validate_frame_range.py b/openpype/hosts/max/plugins/publish/validate_frame_range.py index 2e1d7c9177..8d5d99197e 100644 --- a/openpype/hosts/max/plugins/publish/validate_frame_range.py +++ b/openpype/hosts/max/plugins/publish/validate_frame_range.py @@ -29,7 +29,7 @@ class ValidateFrameRange(pyblish.api.InstancePlugin, order = ValidateContentsOrder families = ["maxrender"] hosts = ["max"] - optional = True + optional = False actions = [RepairAction] def process(self, instance): From d4422d7ec57fc894bac76b4bf974945d1db3413d Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 28 Apr 2023 18:00:12 +0800 Subject: [PATCH 17/71] cosmetic fix --- openpype/hosts/max/plugins/publish/validate_frame_range.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/max/plugins/publish/validate_frame_range.py b/openpype/hosts/max/plugins/publish/validate_frame_range.py index 8d5d99197e..1fafacb8b0 100644 --- a/openpype/hosts/max/plugins/publish/validate_frame_range.py +++ b/openpype/hosts/max/plugins/publish/validate_frame_range.py @@ -44,7 +44,6 @@ class ValidateFrameRange(pyblish.api.InstancePlugin, inst_frame_start = int(instance.data.get("frameStart")) inst_frame_end = int(instance.data.get("frameEnd")) - if frame_start != inst_frame_start: raise PublishValidationError( "startFrame on instance does not match" From 13264ea11c7985f8c5c117f4dcc84ecc925c009b Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 28 Apr 2023 18:41:05 +0800 Subject: [PATCH 18/71] roy's comment --- openpype/hosts/max/api/lib_rendersettings.py | 4 ++-- openpype/hosts/max/plugins/publish/validate_frame_range.py | 6 ++++-- .../hosts/max/plugins/publish/validate_frame_range_type.py | 3 ++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/max/api/lib_rendersettings.py b/openpype/hosts/max/api/lib_rendersettings.py index 4940265a23..82a25dfa29 100644 --- a/openpype/hosts/max/api/lib_rendersettings.py +++ b/openpype/hosts/max/api/lib_rendersettings.py @@ -6,7 +6,7 @@ from openpype.pipeline import legacy_io from openpype.pipeline.context_tools import get_current_project_asset from openpype.hosts.max.api.lib import ( - set_framerange, + set_render_frame_range, get_current_renderer, get_default_render_folder ) @@ -68,7 +68,7 @@ class RenderSettings(object): # Set Frame Range frame_start = context["data"].get("frame_start") frame_end = context["data"].get("frame_end") - set_framerange(frame_start, frame_end) + set_render_frame_range(frame_start, frame_end) # get the production render renderer_class = get_current_renderer() renderer = str(renderer_class).split(":")[0] diff --git a/openpype/hosts/max/plugins/publish/validate_frame_range.py b/openpype/hosts/max/plugins/publish/validate_frame_range.py index 1fafacb8b0..fc2782ded6 100644 --- a/openpype/hosts/max/plugins/publish/validate_frame_range.py +++ b/openpype/hosts/max/plugins/publish/validate_frame_range.py @@ -47,12 +47,14 @@ class ValidateFrameRange(pyblish.api.InstancePlugin, if frame_start != inst_frame_start: raise PublishValidationError( "startFrame on instance does not match" - " with startFrame from the context data") + " with startFrame from the context data" + " You can use repair action to fix it") if frame_end != inst_frame_end: raise PublishValidationError( "endFrame on instance does not match" - " with endFrame from the context data") + " with endFrame from the context data" + " You can use repair action to fix it") @classmethod def repair(cls, instance): diff --git a/openpype/hosts/max/plugins/publish/validate_frame_range_type.py b/openpype/hosts/max/plugins/publish/validate_frame_range_type.py index 2403595b3b..7bc23e5a70 100644 --- a/openpype/hosts/max/plugins/publish/validate_frame_range_type.py +++ b/openpype/hosts/max/plugins/publish/validate_frame_range_type.py @@ -24,7 +24,8 @@ class ValidateFrameRangeType(pyblish.api.InstancePlugin): def process(self, instance): if rt.rendTimeType != 3: raise PublishValidationError("Incorrect type of frame range" - " used in render setting..") + " used in render setting.." + "Repair action can help to fix it.") @classmethod def repair(cls, instance): From f3b1002f2641bcc122e24debee6b042cb05dee1e Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 28 Apr 2023 19:02:17 +0800 Subject: [PATCH 19/71] style fix --- openpype/hosts/max/api/lib.py | 4 ++-- openpype/hosts/max/plugins/publish/validate_frame_range.py | 4 ++-- .../hosts/max/plugins/publish/validate_frame_range_type.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/max/api/lib.py b/openpype/hosts/max/api/lib.py index 7d629922fc..1673fc5ab8 100644 --- a/openpype/hosts/max/api/lib.py +++ b/openpype/hosts/max/api/lib.py @@ -138,7 +138,7 @@ def get_default_render_folder(project_setting=None): ["default_render_image_folder"]) -def set_framerange(start_frame, end_frame): +def set_render_frame_range(start_frame, end_frame): """ Note: Frame range can be specified in different types. Possible values are: @@ -243,7 +243,7 @@ def reset_frame_range(fps: bool = True): frame_end = frame_range["frameEnd"] + int(frame_range["handleEnd"]) frange_cmd = f"animationRange = interval {frame_start} {frame_end}" rt.execute(frange_cmd) - set_framerange(frame_start, frame_end) + set_render_frame_range(frame_start, frame_end) def set_context_setting(): diff --git a/openpype/hosts/max/plugins/publish/validate_frame_range.py b/openpype/hosts/max/plugins/publish/validate_frame_range.py index fc2782ded6..dc12eece39 100644 --- a/openpype/hosts/max/plugins/publish/validate_frame_range.py +++ b/openpype/hosts/max/plugins/publish/validate_frame_range.py @@ -47,13 +47,13 @@ class ValidateFrameRange(pyblish.api.InstancePlugin, if frame_start != inst_frame_start: raise PublishValidationError( "startFrame on instance does not match" - " with startFrame from the context data" + " with startFrame from the context data." " You can use repair action to fix it") if frame_end != inst_frame_end: raise PublishValidationError( "endFrame on instance does not match" - " with endFrame from the context data" + " with endFrame from the context data." " You can use repair action to fix it") @classmethod diff --git a/openpype/hosts/max/plugins/publish/validate_frame_range_type.py b/openpype/hosts/max/plugins/publish/validate_frame_range_type.py index 7bc23e5a70..944780f6fa 100644 --- a/openpype/hosts/max/plugins/publish/validate_frame_range_type.py +++ b/openpype/hosts/max/plugins/publish/validate_frame_range_type.py @@ -24,7 +24,7 @@ class ValidateFrameRangeType(pyblish.api.InstancePlugin): def process(self, instance): if rt.rendTimeType != 3: raise PublishValidationError("Incorrect type of frame range" - " used in render setting.." + " used in render setting." "Repair action can help to fix it.") @classmethod From 88e7b3386b70756ff0b3a81bfd6a33bcd062830a Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 2 May 2023 11:22:10 +0800 Subject: [PATCH 20/71] cosmetic fix --- openpype/hosts/max/plugins/publish/validate_frame_range_type.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/max/plugins/publish/validate_frame_range_type.py b/openpype/hosts/max/plugins/publish/validate_frame_range_type.py index 944780f6fa..d77b1503e0 100644 --- a/openpype/hosts/max/plugins/publish/validate_frame_range_type.py +++ b/openpype/hosts/max/plugins/publish/validate_frame_range_type.py @@ -25,7 +25,7 @@ class ValidateFrameRangeType(pyblish.api.InstancePlugin): if rt.rendTimeType != 3: raise PublishValidationError("Incorrect type of frame range" " used in render setting." - "Repair action can help to fix it.") + " Repair action can help to fix it.") @classmethod def repair(cls, instance): From 0d2a0f87230a78fedbf3e68e54868c3a5269ff06 Mon Sep 17 00:00:00 2001 From: Sharkitty Date: Tue, 2 May 2023 14:36:18 +0200 Subject: [PATCH 21/71] Feature: Remove and load inv action --- openpype/plugins/inventory/remove_and_load.py | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 openpype/plugins/inventory/remove_and_load.py diff --git a/openpype/plugins/inventory/remove_and_load.py b/openpype/plugins/inventory/remove_and_load.py new file mode 100644 index 0000000000..27ae1d4139 --- /dev/null +++ b/openpype/plugins/inventory/remove_and_load.py @@ -0,0 +1,44 @@ +from openpype.pipeline import InventoryAction +from openpype.pipeline.legacy_io import Session +from openpype.pipeline.load.plugins import discover_loader_plugins +from openpype.pipeline.load.utils import ( + get_loader_identifier, + remove_container, + load_container, +) +from openpype.client import get_representation_by_id + + +class RemoveAndLoad(InventoryAction): + """Delete inventory item and reload it.""" + + label = "Remove and load" + icon = "refresh" + + def process(self, containers): + for container in containers: + project_name = Session.get("AVALON_PROJECT") + + # Get loader + loader_name = container["loader"] + for plugin in discover_loader_plugins(project_name=project_name): + if get_loader_identifier(plugin) == loader_name: + loader = plugin + break + + assert ( + loader, + "Failed to get loader, can't remove and load container", + ) + + # Get representation + representation = get_representation_by_id( + project_name, container["representation"] + ) + assert representation, "Represenatation not found" + + # Remove container + remove_container(container) + + # Load container + load_container(loader, representation) From cffe72f0010f0128efd257bf2d6ec749f56958a8 Mon Sep 17 00:00:00 2001 From: Sharkitty Date: Tue, 2 May 2023 16:46:01 +0200 Subject: [PATCH 22/71] register inventory actions --- openpype/pipeline/context_tools.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openpype/pipeline/context_tools.py b/openpype/pipeline/context_tools.py index dede2b8fce..ada78b989d 100644 --- a/openpype/pipeline/context_tools.py +++ b/openpype/pipeline/context_tools.py @@ -35,6 +35,7 @@ from . import ( register_inventory_action_path, register_creator_plugin_path, deregister_loader_plugin_path, + deregister_inventory_action_path, ) @@ -54,6 +55,7 @@ PLUGINS_DIR = os.path.join(PACKAGE_DIR, "plugins") # Global plugin paths PUBLISH_PATH = os.path.join(PLUGINS_DIR, "publish") LOAD_PATH = os.path.join(PLUGINS_DIR, "load") +INVENTORY_PATH = os.path.join(PLUGINS_DIR, "inventory") def _get_modules_manager(): @@ -158,6 +160,7 @@ def install_openpype_plugins(project_name=None, host_name=None): pyblish.api.register_plugin_path(PUBLISH_PATH) pyblish.api.register_discovery_filter(filter_pyblish_plugins) register_loader_plugin_path(LOAD_PATH) + register_inventory_action_path(INVENTORY_PATH) if host_name is None: host_name = os.environ.get("AVALON_APP") @@ -223,6 +226,7 @@ def uninstall_host(): pyblish.api.deregister_plugin_path(PUBLISH_PATH) pyblish.api.deregister_discovery_filter(filter_pyblish_plugins) deregister_loader_plugin_path(LOAD_PATH) + deregister_inventory_action_path(INVENTORY_PATH) log.info("Global plug-ins unregistred") deregister_host() From dc34bcc776c14aba094d7d2bde0f58cbf53002d5 Mon Sep 17 00:00:00 2001 From: Sharkitty Date: Tue, 2 May 2023 17:08:39 +0200 Subject: [PATCH 23/71] pre rebase From 865ba2c97539396ac4a871733d1088c2e25661bb Mon Sep 17 00:00:00 2001 From: Sharkitty Date: Tue, 2 May 2023 17:12:36 +0200 Subject: [PATCH 24/71] edited assertion --- openpype/plugins/inventory/remove_and_load.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/openpype/plugins/inventory/remove_and_load.py b/openpype/plugins/inventory/remove_and_load.py index 27ae1d4139..981722c065 100644 --- a/openpype/plugins/inventory/remove_and_load.py +++ b/openpype/plugins/inventory/remove_and_load.py @@ -27,9 +27,8 @@ class RemoveAndLoad(InventoryAction): break assert ( - loader, - "Failed to get loader, can't remove and load container", - ) + loader + ), "Failed to get loader, can't remove and load container" # Get representation representation = get_representation_by_id( From 7c2a1542145ba75808d7927507bfda45f5166810 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 3 May 2023 15:32:22 +0800 Subject: [PATCH 25/71] add settings to switch on/off the frame range validator --- .../plugins/publish/validate_frame_range.py | 2 +- .../publish/validate_frame_range_type.py | 33 ------------------- .../defaults/project_settings/max.json | 7 ++++ .../projects_schema/schema_project_max.json | 4 +++ .../schemas/schema_max_publish.json | 33 +++++++++++++++++++ 5 files changed, 45 insertions(+), 34 deletions(-) delete mode 100644 openpype/hosts/max/plugins/publish/validate_frame_range_type.py create mode 100644 openpype/settings/entities/schemas/projects_schema/schemas/schema_max_publish.json diff --git a/openpype/hosts/max/plugins/publish/validate_frame_range.py b/openpype/hosts/max/plugins/publish/validate_frame_range.py index dc12eece39..e07c6390c1 100644 --- a/openpype/hosts/max/plugins/publish/validate_frame_range.py +++ b/openpype/hosts/max/plugins/publish/validate_frame_range.py @@ -29,7 +29,7 @@ class ValidateFrameRange(pyblish.api.InstancePlugin, order = ValidateContentsOrder families = ["maxrender"] hosts = ["max"] - optional = False + optional = True actions = [RepairAction] def process(self, instance): diff --git a/openpype/hosts/max/plugins/publish/validate_frame_range_type.py b/openpype/hosts/max/plugins/publish/validate_frame_range_type.py deleted file mode 100644 index d77b1503e0..0000000000 --- a/openpype/hosts/max/plugins/publish/validate_frame_range_type.py +++ /dev/null @@ -1,33 +0,0 @@ -import pyblish.api - -from pymxs import runtime as rt -from openpype.pipeline.publish import ( - RepairAction, - ValidateContentsOrder, - PublishValidationError -) - - -class ValidateFrameRangeType(pyblish.api.InstancePlugin): - """ - Validates whether the User - specified Frame Range(Type 3) is used in render setting - - """ - - label = "Validate Render Frame Range Type" - order = ValidateContentsOrder - families = ["maxrender"] - hosts = ["max"] - actions = [RepairAction] - - def process(self, instance): - if rt.rendTimeType != 3: - raise PublishValidationError("Incorrect type of frame range" - " used in render setting." - " Repair action can help to fix it.") - - @classmethod - def repair(cls, instance): - rt.renderTimeType = 3 - return instance diff --git a/openpype/settings/defaults/project_settings/max.json b/openpype/settings/defaults/project_settings/max.json index d59cdf8c4a..a757e08ef5 100644 --- a/openpype/settings/defaults/project_settings/max.json +++ b/openpype/settings/defaults/project_settings/max.json @@ -19,5 +19,12 @@ "custFloats": "custFloats", "custVecs": "custVecs" } + }, + "publish": { + "ValidateFrameRange": { + "enabled": true, + "optional": true, + "active": true + } } } diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_max.json b/openpype/settings/entities/schemas/projects_schema/schema_project_max.json index 4fba9aff0a..42506559d0 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_max.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_max.json @@ -73,6 +73,10 @@ } } ] + }, + { + "type": "schema", + "name": "schema_max_publish" } ] } diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_max_publish.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_max_publish.json new file mode 100644 index 0000000000..ea08c735a6 --- /dev/null +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_max_publish.json @@ -0,0 +1,33 @@ +{ + "type": "dict", + "collapsible": true, + "key": "publish", + "label": "Publish plugins", + "children": [ + { + "type": "dict", + "collapsible": true, + "checkbox_key": "enabled", + "key": "ValidateFrameRange", + "label": "Validate Frame Range", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "boolean", + "key": "active", + "label": "Active" + } + ] + } + ] + } From 273eb747915722c29e2c88d123cac43977b3b575 Mon Sep 17 00:00:00 2001 From: Sharkitty <81646000+Sharkitty@users.noreply.github.com> Date: Wed, 3 May 2023 08:13:37 +0000 Subject: [PATCH 26/71] Update openpype/plugins/inventory/remove_and_load.py Fix typo Co-authored-by: Roy Nieterau --- openpype/plugins/inventory/remove_and_load.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/plugins/inventory/remove_and_load.py b/openpype/plugins/inventory/remove_and_load.py index 981722c065..9befaf8729 100644 --- a/openpype/plugins/inventory/remove_and_load.py +++ b/openpype/plugins/inventory/remove_and_load.py @@ -34,7 +34,7 @@ class RemoveAndLoad(InventoryAction): representation = get_representation_by_id( project_name, container["representation"] ) - assert representation, "Represenatation not found" + assert representation, "Representation not found" # Remove container remove_container(container) From e2da9a0552356688f2fe2e091ca5de0ae6a5b84c Mon Sep 17 00:00:00 2001 From: Sharkitty Date: Wed, 3 May 2023 10:20:50 +0200 Subject: [PATCH 27/71] Using for else to raise loader not found error --- openpype/plugins/inventory/remove_and_load.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/plugins/inventory/remove_and_load.py b/openpype/plugins/inventory/remove_and_load.py index 9befaf8729..998be119d5 100644 --- a/openpype/plugins/inventory/remove_and_load.py +++ b/openpype/plugins/inventory/remove_and_load.py @@ -25,10 +25,10 @@ class RemoveAndLoad(InventoryAction): if get_loader_identifier(plugin) == loader_name: loader = plugin break - - assert ( - loader - ), "Failed to get loader, can't remove and load container" + else: + raise RuntimeError( + "Failed to get loader, can't remove and load container" + ) # Get representation representation = get_representation_by_id( From 9d3e15378b0109f332c99a21c2468012ff7d60c4 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 3 May 2023 22:31:43 +0800 Subject: [PATCH 28/71] repharse the actual msg for the artists --- .../max/plugins/publish/validate_resolution_setting.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/max/plugins/publish/validate_resolution_setting.py b/openpype/hosts/max/plugins/publish/validate_resolution_setting.py index 9424b24380..94cd093569 100644 --- a/openpype/hosts/max/plugins/publish/validate_resolution_setting.py +++ b/openpype/hosts/max/plugins/publish/validate_resolution_setting.py @@ -29,15 +29,15 @@ class ValidateResolutionSetting(pyblish.api.InstancePlugin, current_width = rt.renderwidth current_height = rt.renderHeight if current_width != width and current_height != height: - raise PublishValidationError("Resolution Setting" - " not aligned with DB") + raise PublishValidationError("Resolution Setting " + "not matching resolution set on asset or shot.") if current_width != width: raise PublishValidationError("Width in Resolution Setting " - "not aligned with DB") + "not matching resolution set on asset or shot.") if current_height != height: raise PublishValidationError("Height in Resolution Setting " - "not aligned with DB") + "not matching resolution set on asset or shot.") def get_db_resolution(self, instance): data = ["data.resolutionWidth", "data.resolutionHeight"] From d8e62093acaf92ca21df28240c420a8d7895f808 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 3 May 2023 22:33:13 +0800 Subject: [PATCH 29/71] hound fix --- .../max/plugins/publish/validate_resolution_setting.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/max/plugins/publish/validate_resolution_setting.py b/openpype/hosts/max/plugins/publish/validate_resolution_setting.py index 94cd093569..5fcb843b20 100644 --- a/openpype/hosts/max/plugins/publish/validate_resolution_setting.py +++ b/openpype/hosts/max/plugins/publish/validate_resolution_setting.py @@ -30,14 +30,17 @@ class ValidateResolutionSetting(pyblish.api.InstancePlugin, current_height = rt.renderHeight if current_width != width and current_height != height: raise PublishValidationError("Resolution Setting " - "not matching resolution set on asset or shot.") + "not matching resolution " + "set on asset or shot.") if current_width != width: raise PublishValidationError("Width in Resolution Setting " - "not matching resolution set on asset or shot.") + "not matching resolution set " + "on asset or shot.") if current_height != height: raise PublishValidationError("Height in Resolution Setting " - "not matching resolution set on asset or shot.") + "not matching resolution set " + "on asset or shot.") def get_db_resolution(self, instance): data = ["data.resolutionWidth", "data.resolutionHeight"] From 64eea1dc4a58444afaa8a58e32e2b50d834144c7 Mon Sep 17 00:00:00 2001 From: Jacob Danell Date: Wed, 3 May 2023 21:33:01 +0200 Subject: [PATCH 30/71] Updated raise error --- .../hosts/fusion/plugins/publish/increment_current_file.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/fusion/plugins/publish/increment_current_file.py b/openpype/hosts/fusion/plugins/publish/increment_current_file.py index de6f697073..08a65bf52d 100644 --- a/openpype/hosts/fusion/plugins/publish/increment_current_file.py +++ b/openpype/hosts/fusion/plugins/publish/increment_current_file.py @@ -1,6 +1,7 @@ import pyblish.api from openpype.pipeline import OptionalPyblishPluginMixin +from openpype.pipeline import KnownPublishError class FusionIncrementCurrentFile( @@ -29,7 +30,7 @@ class FusionIncrementCurrentFile( plugin.__name__ == "FusionSubmitDeadline" for plugin in errored_plugins ): - raise RuntimeError( + raise KnownPublishError( "Skipping incrementing current file because " "submission to render farm failed." ) From feaa01eff56d9fbae19adf97edb5ef3f620ac1f5 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 5 May 2023 11:49:47 +0200 Subject: [PATCH 31/71] :fire: remove obsolete validator --- .../publish/validate_sequence_frames.py | 66 ------------------- 1 file changed, 66 deletions(-) delete mode 100644 openpype/plugins/publish/validate_sequence_frames.py diff --git a/openpype/plugins/publish/validate_sequence_frames.py b/openpype/plugins/publish/validate_sequence_frames.py deleted file mode 100644 index 239008ee21..0000000000 --- a/openpype/plugins/publish/validate_sequence_frames.py +++ /dev/null @@ -1,66 +0,0 @@ -import os -import re - -import clique -import pyblish.api - - -class ValidateSequenceFrames(pyblish.api.InstancePlugin): - """Ensure the sequence of frames is complete - - The files found in the folder are checked against the startFrame and - endFrame of the instance. If the first or last file is not - corresponding with the first or last frame it is flagged as invalid. - - Used regular expression pattern handles numbers in the file names - (eg "Main_beauty.v001.1001.exr", "Main_beauty_v001.1001.exr", - "Main_beauty.1001.1001.exr") but not numbers behind frames (eg. - "Main_beauty.1001.v001.exr") - """ - - order = pyblish.api.ValidatorOrder - label = "Validate Sequence Frames" - families = ["imagesequence", "render"] - hosts = ["shell", "unreal"] - - def process(self, instance): - representations = instance.data.get("representations") - if not representations: - return - for repr in representations: - repr_files = repr["files"] - if isinstance(repr_files, str): - continue - - ext = repr.get("ext") - if not ext: - _, ext = os.path.splitext(repr_files[0]) - elif not ext.startswith("."): - ext = ".{}".format(ext) - pattern = r"\D?(?P(?P0*)\d+){}$".format( - re.escape(ext)) - patterns = [pattern] - - collections, remainder = clique.assemble( - repr_files, minimum_items=1, patterns=patterns) - - assert not remainder, "Must not have remainder" - assert len(collections) == 1, "Must detect single collection" - collection = collections[0] - frames = list(collection.indexes) - - if instance.data.get("slate"): - # Slate is not part of the frame range - frames = frames[1:] - - current_range = (frames[0], frames[-1]) - - required_range = (instance.data["frameStart"], - instance.data["frameEnd"]) - - if current_range != required_range: - raise ValueError(f"Invalid frame range: {current_range} - " - f"expected: {required_range}") - - missing = collection.holes().indexes - assert not missing, "Missing frames: %s" % (missing,) From c0499c46b852c3ffe9983d17f739cabeee596963 Mon Sep 17 00:00:00 2001 From: Sharkitty Date: Fri, 5 May 2023 14:02:40 +0200 Subject: [PATCH 32/71] Changes based on suggestions --- openpype/plugins/inventory/remove_and_load.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openpype/plugins/inventory/remove_and_load.py b/openpype/plugins/inventory/remove_and_load.py index 998be119d5..be24220c56 100644 --- a/openpype/plugins/inventory/remove_and_load.py +++ b/openpype/plugins/inventory/remove_and_load.py @@ -1,5 +1,5 @@ from openpype.pipeline import InventoryAction -from openpype.pipeline.legacy_io import Session +from openpype.pipeline import get_current_project_name from openpype.pipeline.load.plugins import discover_loader_plugins from openpype.pipeline.load.utils import ( get_loader_identifier, @@ -16,12 +16,13 @@ class RemoveAndLoad(InventoryAction): icon = "refresh" def process(self, containers): + project_name = get_current_project_name() for container in containers: - project_name = Session.get("AVALON_PROJECT") # Get loader loader_name = container["loader"] - for plugin in discover_loader_plugins(project_name=project_name): + loaders = discover_loader_plugins(project_name=project_name) + for plugin in loader: if get_loader_identifier(plugin) == loader_name: loader = plugin break From 43b71e4f1e2f8387cb9fba4b20e401a15b140e51 Mon Sep 17 00:00:00 2001 From: Sharkitty Date: Fri, 5 May 2023 14:24:46 +0200 Subject: [PATCH 33/71] Fixed wrong variable --- openpype/plugins/inventory/remove_and_load.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/plugins/inventory/remove_and_load.py b/openpype/plugins/inventory/remove_and_load.py index be24220c56..d465154187 100644 --- a/openpype/plugins/inventory/remove_and_load.py +++ b/openpype/plugins/inventory/remove_and_load.py @@ -22,7 +22,7 @@ class RemoveAndLoad(InventoryAction): # Get loader loader_name = container["loader"] loaders = discover_loader_plugins(project_name=project_name) - for plugin in loader: + for plugin in loaders: if get_loader_identifier(plugin) == loader_name: loader = plugin break From e08ff46bfa4edb8b526501b88ff2dcdc36538885 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 5 May 2023 17:22:14 +0200 Subject: [PATCH 34/71] adding settings for creators --- .../defaults/project_settings/fusion.json | 13 ++++++ .../schema_project_fusion.json | 44 +++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/openpype/settings/defaults/project_settings/fusion.json b/openpype/settings/defaults/project_settings/fusion.json index f974eebaca..d76ed82942 100644 --- a/openpype/settings/defaults/project_settings/fusion.json +++ b/openpype/settings/defaults/project_settings/fusion.json @@ -21,5 +21,18 @@ "copy_path": "~/.openpype/hosts/fusion/profiles", "copy_status": false, "force_sync": false + }, + "create": { + "CreateSaver": { + "temp_rendering_path_template": "{workdir}/renders/fusion/{subset}/{subset}..{ext}", + "default_variants": [ + "Main", + "Mask" + ], + "instance_attributes": [ + "reviewable", + "farm_rendering" + ] + } } } diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_fusion.json b/openpype/settings/entities/schemas/projects_schema/schema_project_fusion.json index 464cf2c06d..7971c62300 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_fusion.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_fusion.json @@ -68,6 +68,50 @@ "label": "Resync profile on each launch" } ] + }, + { + "type": "dict", + "collapsible": true, + "key": "create", + "label": "Creator plugins", + "children": [ + { + "type": "dict", + "collapsible": true, + "key": "CreateSaver", + "label": "Create Saver", + "is_group": true, + "children": [ + { + "type": "text", + "key": "temp_rendering_path_template", + "label": "Temporary rendering path template" + }, + { + "type": "list", + "key": "default_variants", + "label": "Default variants", + "object_type": { + "type": "text" + } + }, + { + "key": "instance_attributes", + "label": "Instance attributes", + "type": "enum", + "multiselection": true, + "enum_items": [ + { + "reviewable": "Reviewable" + }, + { + "farm_rendering": "Farm rendering" + } + ] + } + ] + } + ] } ] } From d637fed33de88d4048c40b56ecf3f5cb86aab654 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 5 May 2023 17:23:27 +0200 Subject: [PATCH 35/71] implementing settings also adding temp rendering path attribute with with support for tempates --- .../fusion/plugins/create/create_saver.py | 78 +++++++++++++++---- 1 file changed, 65 insertions(+), 13 deletions(-) diff --git a/openpype/hosts/fusion/plugins/create/create_saver.py b/openpype/hosts/fusion/plugins/create/create_saver.py index cedc4029fa..fb6767d2cd 100644 --- a/openpype/hosts/fusion/plugins/create/create_saver.py +++ b/openpype/hosts/fusion/plugins/create/create_saver.py @@ -1,4 +1,6 @@ +from copy import deepcopy import os +from pprint import pformat from openpype.hosts.fusion.api import ( get_current_comp, @@ -11,7 +13,7 @@ from openpype.lib import ( ) from openpype.pipeline import ( legacy_io, - Creator, + Creator as NewCreator, CreatedInstance, ) from openpype.client import ( @@ -19,7 +21,7 @@ from openpype.client import ( ) -class CreateSaver(Creator): +class CreateSaver(NewCreator): identifier = "io.openpype.creators.fusion.saver" label = "Render (saver)" name = "render" @@ -28,7 +30,15 @@ class CreateSaver(Creator): description = "Fusion Saver to generate image sequence" icon = "fa5.eye" - instance_attributes = ["reviewable"] + instance_attributes = [ + "reviewable" + ] + default_variants = [ + "Main", + "Mask" + ] + temp_rendering_path_template = ( + "{workdir}/renders/fusion/{subset}/{subset}..{ext}") def create(self, subset_name, instance_data, pre_create_data): # TODO: Add pre_create attributes to choose file format? @@ -125,17 +135,34 @@ class CreateSaver(Creator): original_subset = tool.GetData("openpype.subset") subset = data["subset"] if original_subset != subset: - # Subset change detected - # Update output filepath - workdir = os.path.normpath(legacy_io.Session["AVALON_WORKDIR"]) - filename = f"{subset}..exr" - filepath = os.path.join(workdir, "render", subset, filename) - tool["Clip"] = filepath + self._configure_saver_tool(data, tool, subset) - # Rename tool - if tool.Name != subset: - print(f"Renaming {tool.Name} -> {subset}") - tool.SetAttrs({"TOOLS_Name": subset}) + def _configure_saver_tool(self, data, tool, subset): + formatting_data = deepcopy(data) + self.log.warning(pformat(formatting_data)) + + # Subset change detected + workdir = os.path.normpath(legacy_io.Session["AVALON_WORKDIR"]) + formatting_data.update({ + "workdir": workdir, + "ext": "exr" + }) + + # build file path to render + filepath = self.temp_rendering_path_template.format( + **formatting_data) + + # create directory + if not os.path.isdir(os.path.dirname(filepath)): + self.log.warning("Path does not exist! I am creating it.") + os.makedirs(os.path.dirname(filepath)) + + tool["Clip"] = filepath + + # Rename tool + if tool.Name != subset: + print(f"Renaming {tool.Name} -> {subset}") + tool.SetAttrs({"TOOLS_Name": subset}) def _collect_unmanaged_saver(self, tool): # TODO: this should not be done this way - this should actually @@ -238,3 +265,28 @@ class CreateSaver(Creator): default=("reviewable" in self.instance_attributes), label="Review", ) + + def apply_settings( + self, + project_settings, + system_settings + ): + """Method called on initialization of plugin to apply settings.""" + + # plugin settings + plugin_settings = self._get_creator_settings(project_settings) + + # individual attributes + self.instance_attributes = plugin_settings.get( + "instance_attributes") or self.instance_attributes + self.default_variants = plugin_settings.get( + "default_variants") or self.default_variants + self.temp_rendering_path_template = ( + plugin_settings.get("temp_rendering_path_template") + or self.temp_rendering_path_template + ) + + def _get_creator_settings(self, project_settings, settings_key=None): + if not settings_key: + settings_key = self.__class__.__name__ + return project_settings["fusion"]["create"][settings_key] From c73772919a32f349ecb16229140338b58e466445 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 5 May 2023 17:42:38 +0200 Subject: [PATCH 36/71] fixing path slashes --- openpype/hosts/fusion/plugins/create/create_saver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/fusion/plugins/create/create_saver.py b/openpype/hosts/fusion/plugins/create/create_saver.py index fb6767d2cd..8bf364cf20 100644 --- a/openpype/hosts/fusion/plugins/create/create_saver.py +++ b/openpype/hosts/fusion/plugins/create/create_saver.py @@ -144,7 +144,7 @@ class CreateSaver(NewCreator): # Subset change detected workdir = os.path.normpath(legacy_io.Session["AVALON_WORKDIR"]) formatting_data.update({ - "workdir": workdir, + "workdir": workdir.replace("\\", "/"), "ext": "exr" }) From 291432d49bcd92120904ad868a27e9981d010865 Mon Sep 17 00:00:00 2001 From: Sharkitty <81646000+Sharkitty@users.noreply.github.com> Date: Mon, 8 May 2023 16:01:57 +0000 Subject: [PATCH 37/71] Update openpype/plugins/inventory/remove_and_load.py Changed representation assertion into a warning with more info Co-authored-by: Roy Nieterau --- openpype/plugins/inventory/remove_and_load.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openpype/plugins/inventory/remove_and_load.py b/openpype/plugins/inventory/remove_and_load.py index d465154187..015f80cd4e 100644 --- a/openpype/plugins/inventory/remove_and_load.py +++ b/openpype/plugins/inventory/remove_and_load.py @@ -35,7 +35,10 @@ class RemoveAndLoad(InventoryAction): representation = get_representation_by_id( project_name, container["representation"] ) - assert representation, "Representation not found" + if not representation: + self.log.warning( + "Skipping remove and load because representation id is not" + " found in database: '{}'".format(container["representation"]) # Remove container remove_container(container) From 9a2a25a957cf25ed7fc5f1bcf10c3d15dc6b505c Mon Sep 17 00:00:00 2001 From: Sharkitty Date: Mon, 8 May 2023 18:05:18 +0200 Subject: [PATCH 38/71] Added continue statement + linting --- openpype/plugins/inventory/remove_and_load.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/openpype/plugins/inventory/remove_and_load.py b/openpype/plugins/inventory/remove_and_load.py index 015f80cd4e..062a44354b 100644 --- a/openpype/plugins/inventory/remove_and_load.py +++ b/openpype/plugins/inventory/remove_and_load.py @@ -18,7 +18,6 @@ class RemoveAndLoad(InventoryAction): def process(self, containers): project_name = get_current_project_name() for container in containers: - # Get loader loader_name = container["loader"] loaders = discover_loader_plugins(project_name=project_name) @@ -38,7 +37,11 @@ class RemoveAndLoad(InventoryAction): if not representation: self.log.warning( "Skipping remove and load because representation id is not" - " found in database: '{}'".format(container["representation"]) + " found in database: '{}'".format( + container["representation"] + ) + ) + continue # Remove container remove_container(container) From 55bebf86426cf467f6f4268882ec00c7b44234e2 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 10 May 2023 12:33:38 +0200 Subject: [PATCH 39/71] pr comments --- openpype/hosts/fusion/plugins/create/create_saver.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/fusion/plugins/create/create_saver.py b/openpype/hosts/fusion/plugins/create/create_saver.py index 8bf364cf20..7378dec2b4 100644 --- a/openpype/hosts/fusion/plugins/create/create_saver.py +++ b/openpype/hosts/fusion/plugins/create/create_saver.py @@ -1,6 +1,5 @@ from copy import deepcopy import os -from pprint import pformat from openpype.hosts.fusion.api import ( get_current_comp, @@ -139,7 +138,6 @@ class CreateSaver(NewCreator): def _configure_saver_tool(self, data, tool, subset): formatting_data = deepcopy(data) - self.log.warning(pformat(formatting_data)) # Subset change detected workdir = os.path.normpath(legacy_io.Session["AVALON_WORKDIR"]) @@ -274,7 +272,9 @@ class CreateSaver(NewCreator): """Method called on initialization of plugin to apply settings.""" # plugin settings - plugin_settings = self._get_creator_settings(project_settings) + plugin_settings = ( + project_settings["fusion"]["create"][self.__class__.__name__] + ) # individual attributes self.instance_attributes = plugin_settings.get( @@ -285,8 +285,3 @@ class CreateSaver(NewCreator): plugin_settings.get("temp_rendering_path_template") or self.temp_rendering_path_template ) - - def _get_creator_settings(self, project_settings, settings_key=None): - if not settings_key: - settings_key = self.__class__.__name__ - return project_settings["fusion"]["create"][settings_key] From 98d27fa5a403143e5910d343ccc62af8b5e8cbb1 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 10 May 2023 12:54:30 +0200 Subject: [PATCH 40/71] fusion: frame padding from anatomy templates --- .../hosts/fusion/plugins/create/create_saver.py | 16 +++++++++++++--- .../defaults/project_settings/fusion.json | 2 +- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/fusion/plugins/create/create_saver.py b/openpype/hosts/fusion/plugins/create/create_saver.py index 7378dec2b4..fb05d13597 100644 --- a/openpype/hosts/fusion/plugins/create/create_saver.py +++ b/openpype/hosts/fusion/plugins/create/create_saver.py @@ -5,6 +5,7 @@ from openpype.hosts.fusion.api import ( get_current_comp, comp_lock_and_undo_chunk, ) +from openpype.hosts.fusion.api.lib import get_frame_path from openpype.lib import ( BoolDef, @@ -14,6 +15,7 @@ from openpype.pipeline import ( legacy_io, Creator as NewCreator, CreatedInstance, + Anatomy ) from openpype.client import ( get_asset_by_name, @@ -37,7 +39,7 @@ class CreateSaver(NewCreator): "Mask" ] temp_rendering_path_template = ( - "{workdir}/renders/fusion/{subset}/{subset}..{ext}") + "{workdir}/renders/fusion/{subset}/{subset}.{frame}.{ext}") def create(self, subset_name, instance_data, pre_create_data): # TODO: Add pre_create attributes to choose file format? @@ -139,10 +141,17 @@ class CreateSaver(NewCreator): def _configure_saver_tool(self, data, tool, subset): formatting_data = deepcopy(data) + # get frame padding from anatomy templates + anatomy = Anatomy() + frame_padding = int( + anatomy.templates["render"].get("frame_padding", 4) + ) + # Subset change detected workdir = os.path.normpath(legacy_io.Session["AVALON_WORKDIR"]) formatting_data.update({ "workdir": workdir.replace("\\", "/"), + "frame": "0" * frame_padding, "ext": "exr" }) @@ -180,8 +189,9 @@ class CreateSaver(NewCreator): path = tool["Clip"][comp.TIME_UNDEFINED] fname = os.path.basename(path) - fname, _ext = os.path.splitext(fname) - variant = fname.rstrip(".") + head, _, _ = get_frame_path(fname) + + variant = head.rstrip(".") subset = self.get_subset_name( variant=variant, task_name=task, diff --git a/openpype/settings/defaults/project_settings/fusion.json b/openpype/settings/defaults/project_settings/fusion.json index d76ed82942..066fc3816a 100644 --- a/openpype/settings/defaults/project_settings/fusion.json +++ b/openpype/settings/defaults/project_settings/fusion.json @@ -24,7 +24,7 @@ }, "create": { "CreateSaver": { - "temp_rendering_path_template": "{workdir}/renders/fusion/{subset}/{subset}..{ext}", + "temp_rendering_path_template": "{workdir}/renders/fusion/{subset}/{subset}.{frame}.{ext}", "default_variants": [ "Main", "Mask" From a08f9176b0bc26d9a5f32968f8643966f59ad502 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 10 May 2023 12:55:30 +0200 Subject: [PATCH 41/71] fusion: removing path making during creation --- openpype/hosts/fusion/plugins/create/create_saver.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/openpype/hosts/fusion/plugins/create/create_saver.py b/openpype/hosts/fusion/plugins/create/create_saver.py index fb05d13597..64a99d07c1 100644 --- a/openpype/hosts/fusion/plugins/create/create_saver.py +++ b/openpype/hosts/fusion/plugins/create/create_saver.py @@ -159,11 +159,6 @@ class CreateSaver(NewCreator): filepath = self.temp_rendering_path_template.format( **formatting_data) - # create directory - if not os.path.isdir(os.path.dirname(filepath)): - self.log.warning("Path does not exist! I am creating it.") - os.makedirs(os.path.dirname(filepath)) - tool["Clip"] = filepath # Rename tool From 95237c43c775f3d15b8475ffacac53fcc4d94002 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 10 May 2023 13:00:53 +0200 Subject: [PATCH 42/71] adding todo for later renaming --- openpype/hosts/fusion/plugins/create/create_saver.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/hosts/fusion/plugins/create/create_saver.py b/openpype/hosts/fusion/plugins/create/create_saver.py index 64a99d07c1..bb4615db17 100644 --- a/openpype/hosts/fusion/plugins/create/create_saver.py +++ b/openpype/hosts/fusion/plugins/create/create_saver.py @@ -38,6 +38,8 @@ class CreateSaver(NewCreator): "Main", "Mask" ] + + # TODO: This should be renamed together with Nuke so it is aligned temp_rendering_path_template = ( "{workdir}/renders/fusion/{subset}/{subset}.{frame}.{ext}") From 1a48ddefe4a665997dc9e4bac066200721949d3c Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 10 May 2023 15:37:19 +0200 Subject: [PATCH 43/71] normalizing path --- openpype/hosts/fusion/plugins/create/create_saver.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/fusion/plugins/create/create_saver.py b/openpype/hosts/fusion/plugins/create/create_saver.py index bb4615db17..f924c30b0a 100644 --- a/openpype/hosts/fusion/plugins/create/create_saver.py +++ b/openpype/hosts/fusion/plugins/create/create_saver.py @@ -152,7 +152,7 @@ class CreateSaver(NewCreator): # Subset change detected workdir = os.path.normpath(legacy_io.Session["AVALON_WORKDIR"]) formatting_data.update({ - "workdir": workdir.replace("\\", "/"), + "workdir": workdir, "frame": "0" * frame_padding, "ext": "exr" }) @@ -161,7 +161,7 @@ class CreateSaver(NewCreator): filepath = self.temp_rendering_path_template.format( **formatting_data) - tool["Clip"] = filepath + tool["Clip"] = os.path.normpath(filepath) # Rename tool if tool.Name != subset: From 27ac1b4590c2211548d94dfc5a26b902c3938c72 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 10 May 2023 16:16:50 +0200 Subject: [PATCH 44/71] Removing unmanaged compatibility This fixes issue https://github.com/ynput/OpenPype/pull/4943#pullrequestreview-1420557288 --- .../fusion/plugins/create/create_saver.py | 48 ++++++------------- 1 file changed, 14 insertions(+), 34 deletions(-) diff --git a/openpype/hosts/fusion/plugins/create/create_saver.py b/openpype/hosts/fusion/plugins/create/create_saver.py index f924c30b0a..27394ae15b 100644 --- a/openpype/hosts/fusion/plugins/create/create_saver.py +++ b/openpype/hosts/fusion/plugins/create/create_saver.py @@ -91,7 +91,7 @@ class CreateSaver(NewCreator): for tool in tools: data = self.get_managed_tool_data(tool) if not data: - data = self._collect_unmanaged_saver(tool) + data = self._collect_saver(tool) # Add instance created_instance = CreatedInstance.from_existing(data, self) @@ -168,43 +168,23 @@ class CreateSaver(NewCreator): print(f"Renaming {tool.Name} -> {subset}") tool.SetAttrs({"TOOLS_Name": subset}) - def _collect_unmanaged_saver(self, tool): - # TODO: this should not be done this way - this should actually - # get the data as stored on the tool explicitly (however) - # that would disallow any 'regular saver' to be collected - # unless the instance data is stored on it to begin with - - print("Collecting unmanaged saver..") - comp = tool.Comp() - - # Allow regular non-managed savers to also be picked up - project = legacy_io.Session["AVALON_PROJECT"] - asset = legacy_io.Session["AVALON_ASSET"] - task = legacy_io.Session["AVALON_TASK"] - - asset_doc = get_asset_by_name(project_name=project, asset_name=asset) - - path = tool["Clip"][comp.TIME_UNDEFINED] - fname = os.path.basename(path) - head, _, _ = get_frame_path(fname) - - variant = head.rstrip(".") - subset = self.get_subset_name( - variant=variant, - task_name=task, - asset_doc=asset_doc, - project_name=project, - ) - + def _collect_saver(self, tool): + print("Collecting saver..") attrs = tool.GetAttrs() + + ctx_data = {} + keys = ["asset", "subset", "task", "variant"] + for key in keys: + ctx_data[key] = tool.GetData(f"openpype.{key}") + passthrough = attrs["TOOLB_PassThrough"] return { # Required data - "project": project, - "asset": asset, - "subset": subset, - "task": task, - "variant": variant, + "project": self.project_name, + "asset": ctx_data["asset"], + "subset": ctx_data["subset"], + "task": ctx_data["task"], + "variant": ctx_data["variant"], "active": not passthrough, "family": self.family, # Unique identifier for instance and this creator From dfea365474995dfbdffd85d296f3b8e61b3e4ffd Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 10 May 2023 16:38:17 +0200 Subject: [PATCH 45/71] moving instnance id so it is imprinted once created addressing issue form here https://github.com/ynput/OpenPype/pull/4943#issuecomment-1542241467 --- openpype/hosts/fusion/plugins/create/create_saver.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/fusion/plugins/create/create_saver.py b/openpype/hosts/fusion/plugins/create/create_saver.py index 27394ae15b..224ec0d48e 100644 --- a/openpype/hosts/fusion/plugins/create/create_saver.py +++ b/openpype/hosts/fusion/plugins/create/create_saver.py @@ -44,6 +44,11 @@ class CreateSaver(NewCreator): "{workdir}/renders/fusion/{subset}/{subset}.{frame}.{ext}") def create(self, subset_name, instance_data, pre_create_data): + instance_data.update({ + "id": "pyblish.avalon.instance", + "subset": subset_name + }) + # TODO: Add pre_create attributes to choose file format? file_format = "OpenEXRFormat" @@ -52,7 +57,6 @@ class CreateSaver(NewCreator): args = (-32768, -32768) # Magical position numbers saver = comp.AddTool("Saver", *args) - instance_data["subset"] = subset_name self._update_tool_with_data(saver, data=instance_data) saver["OutputFormat"] = file_format @@ -173,7 +177,7 @@ class CreateSaver(NewCreator): attrs = tool.GetAttrs() ctx_data = {} - keys = ["asset", "subset", "task", "variant"] + keys = ["id", "asset", "subset", "task", "variant"] for key in keys: ctx_data[key] = tool.GetData(f"openpype.{key}") @@ -188,7 +192,7 @@ class CreateSaver(NewCreator): "active": not passthrough, "family": self.family, # Unique identifier for instance and this creator - "id": "pyblish.avalon.instance", + "id": ctx_data["id"], "creator_identifier": self.identifier, } From f5215f323b3c3b8b76ef278de6771bfdf6b0dcca Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 10 May 2023 16:39:29 +0200 Subject: [PATCH 46/71] hound --- openpype/hosts/fusion/plugins/create/create_saver.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/openpype/hosts/fusion/plugins/create/create_saver.py b/openpype/hosts/fusion/plugins/create/create_saver.py index 224ec0d48e..ecdad30b4c 100644 --- a/openpype/hosts/fusion/plugins/create/create_saver.py +++ b/openpype/hosts/fusion/plugins/create/create_saver.py @@ -5,7 +5,6 @@ from openpype.hosts.fusion.api import ( get_current_comp, comp_lock_and_undo_chunk, ) -from openpype.hosts.fusion.api.lib import get_frame_path from openpype.lib import ( BoolDef, @@ -17,9 +16,6 @@ from openpype.pipeline import ( CreatedInstance, Anatomy ) -from openpype.client import ( - get_asset_by_name, -) class CreateSaver(NewCreator): @@ -173,14 +169,11 @@ class CreateSaver(NewCreator): tool.SetAttrs({"TOOLS_Name": subset}) def _collect_saver(self, tool): - print("Collecting saver..") + self.log.info("Collecting saver..") attrs = tool.GetAttrs() - ctx_data = {} keys = ["id", "asset", "subset", "task", "variant"] - for key in keys: - ctx_data[key] = tool.GetData(f"openpype.{key}") - + ctx_data = {key: tool.GetData(f"openpype.{key}") for key in keys} passthrough = attrs["TOOLB_PassThrough"] return { # Required data From 4095c7bd008923f288c8b16f5ce94e0c0aacca99 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 10 May 2023 22:51:52 +0800 Subject: [PATCH 47/71] use rt.rendpickupframe and ondrej's comment --- openpype/hosts/max/api/lib.py | 6 ++--- .../max/plugins/publish/collect_render.py | 8 +++--- .../plugins/publish/validate_frame_range.py | 26 +++++++++++-------- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/openpype/hosts/max/api/lib.py b/openpype/hosts/max/api/lib.py index 1673fc5ab8..b21ce0f789 100644 --- a/openpype/hosts/max/api/lib.py +++ b/openpype/hosts/max/api/lib.py @@ -150,10 +150,10 @@ def set_render_frame_range(start_frame, end_frame): Todo: Current type is hard-coded, there should be a custom setting for this. """ - rt.rendTimeType = 3 + rt.rendTimeType = 4 if start_frame is not None and end_frame is not None: - rt.rendStart = int(start_frame) - rt.rendEnd = int(end_frame) + frame_range = "{0}-{1}".format(start_frame, end_frame) + rt.rendPickupFrames = frame_range def get_multipass_setting(project_setting=None): diff --git a/openpype/hosts/max/plugins/publish/collect_render.py b/openpype/hosts/max/plugins/publish/collect_render.py index 9d93a40021..2742c36fc8 100644 --- a/openpype/hosts/max/plugins/publish/collect_render.py +++ b/openpype/hosts/max/plugins/publish/collect_render.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- """Collect Render""" import os +import re import pyblish.api from pymxs import runtime as rt @@ -46,7 +47,8 @@ class CollectRender(pyblish.api.InstancePlugin): self.log.debug(f"Setting {version_int} to context.") context.data["version"] = version_int - + pattern = r"^(?P-?[0-9]+)(?:(?:-)(?P-?[0-9]+))?$" + match = re.match(pattern, rt.rendPickupFrames) # setup the plugin as 3dsmax for the internal renderer data = { "subset": instance.name, @@ -59,8 +61,8 @@ class CollectRender(pyblish.api.InstancePlugin): "source": filepath, "expectedFiles": render_layer_files, "plugin": "3dsmax", - "frameStart": int(rt.rendStart), - "frameEnd": int(rt.rendEnd), + "frameStart": int(match.group("start")), + "frameEnd": int(match.group("end")), "version": version_int, "farm": True } diff --git a/openpype/hosts/max/plugins/publish/validate_frame_range.py b/openpype/hosts/max/plugins/publish/validate_frame_range.py index e07c6390c1..4cc9cb530c 100644 --- a/openpype/hosts/max/plugins/publish/validate_frame_range.py +++ b/openpype/hosts/max/plugins/publish/validate_frame_range.py @@ -44,19 +44,23 @@ class ValidateFrameRange(pyblish.api.InstancePlugin, inst_frame_start = int(instance.data.get("frameStart")) inst_frame_end = int(instance.data.get("frameEnd")) + errors = [] if frame_start != inst_frame_start: - raise PublishValidationError( - "startFrame on instance does not match" - " with startFrame from the context data." - " You can use repair action to fix it") - + errors.append( + f"Start frame ({inst_frame_start}) on instance does not match " + f"with the start frame ({frame_start}) set on the asset data. ") if frame_end != inst_frame_end: - raise PublishValidationError( - "endFrame on instance does not match" - " with endFrame from the context data." - " You can use repair action to fix it") + errors.append( + f"End frame ({inst_frame_end}) on instance does not match " + f"with the end frame ({frame_start}) from the asset data. ") + + if errors: + errors.append("You can use repair action to fix it.") + raise PublishValidationError("\n".join(errors)) @classmethod def repair(cls, instance): - rt.rendStart = instance.context.data.get("frameStart") - rt.rendEnd = instance.context.data.get("frameEnd") + start = instance.context.data.get("frameStart") + end = instance.context.data.get("frameEnd") + frame_range = "{0}-{1}".format(start, end) + rt.rendPickupFrames = frame_range From da7d8ac091d45d6d73a2d34177f2f7ab3992f9b0 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 10 May 2023 22:53:02 +0800 Subject: [PATCH 48/71] hound fix --- openpype/hosts/max/plugins/publish/validate_frame_range.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/max/plugins/publish/validate_frame_range.py b/openpype/hosts/max/plugins/publish/validate_frame_range.py index 4cc9cb530c..761e7bf085 100644 --- a/openpype/hosts/max/plugins/publish/validate_frame_range.py +++ b/openpype/hosts/max/plugins/publish/validate_frame_range.py @@ -47,8 +47,8 @@ class ValidateFrameRange(pyblish.api.InstancePlugin, errors = [] if frame_start != inst_frame_start: errors.append( - f"Start frame ({inst_frame_start}) on instance does not match " - f"with the start frame ({frame_start}) set on the asset data. ") + f"Start frame ({inst_frame_start}) on instance does not match " # noqa + f"with the start frame ({frame_start}) set on the asset data. ") # noqa if frame_end != inst_frame_end: errors.append( f"End frame ({inst_frame_end}) on instance does not match " From e69e1f76c8f86ab2cfc9ca7a9272b99d2ea98546 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 10 May 2023 23:16:39 +0800 Subject: [PATCH 49/71] use ranges --- openpype/hosts/max/api/lib.py | 6 +++--- openpype/hosts/max/plugins/publish/collect_render.py | 6 ++---- openpype/hosts/max/plugins/publish/validate_frame_range.py | 6 ++---- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/openpype/hosts/max/api/lib.py b/openpype/hosts/max/api/lib.py index b21ce0f789..1673fc5ab8 100644 --- a/openpype/hosts/max/api/lib.py +++ b/openpype/hosts/max/api/lib.py @@ -150,10 +150,10 @@ def set_render_frame_range(start_frame, end_frame): Todo: Current type is hard-coded, there should be a custom setting for this. """ - rt.rendTimeType = 4 + rt.rendTimeType = 3 if start_frame is not None and end_frame is not None: - frame_range = "{0}-{1}".format(start_frame, end_frame) - rt.rendPickupFrames = frame_range + rt.rendStart = int(start_frame) + rt.rendEnd = int(end_frame) def get_multipass_setting(project_setting=None): diff --git a/openpype/hosts/max/plugins/publish/collect_render.py b/openpype/hosts/max/plugins/publish/collect_render.py index 2742c36fc8..31f1eba409 100644 --- a/openpype/hosts/max/plugins/publish/collect_render.py +++ b/openpype/hosts/max/plugins/publish/collect_render.py @@ -47,8 +47,6 @@ class CollectRender(pyblish.api.InstancePlugin): self.log.debug(f"Setting {version_int} to context.") context.data["version"] = version_int - pattern = r"^(?P-?[0-9]+)(?:(?:-)(?P-?[0-9]+))?$" - match = re.match(pattern, rt.rendPickupFrames) # setup the plugin as 3dsmax for the internal renderer data = { "subset": instance.name, @@ -61,8 +59,8 @@ class CollectRender(pyblish.api.InstancePlugin): "source": filepath, "expectedFiles": render_layer_files, "plugin": "3dsmax", - "frameStart": int(match.group("start")), - "frameEnd": int(match.group("end")), + "frameStart": int(rt.rendStart), + "frameEnd": int(rt.rendEnd), "version": version_int, "farm": True } diff --git a/openpype/hosts/max/plugins/publish/validate_frame_range.py b/openpype/hosts/max/plugins/publish/validate_frame_range.py index 761e7bf085..21e847405e 100644 --- a/openpype/hosts/max/plugins/publish/validate_frame_range.py +++ b/openpype/hosts/max/plugins/publish/validate_frame_range.py @@ -60,7 +60,5 @@ class ValidateFrameRange(pyblish.api.InstancePlugin, @classmethod def repair(cls, instance): - start = instance.context.data.get("frameStart") - end = instance.context.data.get("frameEnd") - frame_range = "{0}-{1}".format(start, end) - rt.rendPickupFrames = frame_range + rt.rendStart = instance.context.data.get("frameStart") + rt.rendEnd = instance.context.data.get("frameEnd") From 210ed4d41fdc8c28cb18e9a2d61b10b8848cbf26 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 10 May 2023 23:17:58 +0800 Subject: [PATCH 50/71] hound fix --- openpype/hosts/max/plugins/publish/collect_render.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/max/plugins/publish/collect_render.py b/openpype/hosts/max/plugins/publish/collect_render.py index 31f1eba409..00e00a8eb5 100644 --- a/openpype/hosts/max/plugins/publish/collect_render.py +++ b/openpype/hosts/max/plugins/publish/collect_render.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- """Collect Render""" import os -import re import pyblish.api from pymxs import runtime as rt From 9f1bdda8b35509907351cc12ac271299bb186c0b Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 11 May 2023 12:18:36 +0200 Subject: [PATCH 51/71] fusion: removing obsolete code --- .../fusion/plugins/create/create_saver.py | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/openpype/hosts/fusion/plugins/create/create_saver.py b/openpype/hosts/fusion/plugins/create/create_saver.py index ecdad30b4c..2af811ef5b 100644 --- a/openpype/hosts/fusion/plugins/create/create_saver.py +++ b/openpype/hosts/fusion/plugins/create/create_saver.py @@ -90,8 +90,6 @@ class CreateSaver(NewCreator): tools = comp.GetToolList(False, "Saver").values() for tool in tools: data = self.get_managed_tool_data(tool) - if not data: - data = self._collect_saver(tool) # Add instance created_instance = CreatedInstance.from_existing(data, self) @@ -168,27 +166,6 @@ class CreateSaver(NewCreator): print(f"Renaming {tool.Name} -> {subset}") tool.SetAttrs({"TOOLS_Name": subset}) - def _collect_saver(self, tool): - self.log.info("Collecting saver..") - attrs = tool.GetAttrs() - - keys = ["id", "asset", "subset", "task", "variant"] - ctx_data = {key: tool.GetData(f"openpype.{key}") for key in keys} - passthrough = attrs["TOOLB_PassThrough"] - return { - # Required data - "project": self.project_name, - "asset": ctx_data["asset"], - "subset": ctx_data["subset"], - "task": ctx_data["task"], - "variant": ctx_data["variant"], - "active": not passthrough, - "family": self.family, - # Unique identifier for instance and this creator - "id": ctx_data["id"], - "creator_identifier": self.identifier, - } - def get_managed_tool_data(self, tool): """Return data of the tool if it matches creator identifier""" data = tool.GetData("openpype") From bf2e02699a0b60af16b1a6057b4f82d9faa33373 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 11 May 2023 12:20:56 +0200 Subject: [PATCH 52/71] returning important condition --- openpype/hosts/fusion/plugins/create/create_saver.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/hosts/fusion/plugins/create/create_saver.py b/openpype/hosts/fusion/plugins/create/create_saver.py index 2af811ef5b..13836aa1a0 100644 --- a/openpype/hosts/fusion/plugins/create/create_saver.py +++ b/openpype/hosts/fusion/plugins/create/create_saver.py @@ -90,6 +90,8 @@ class CreateSaver(NewCreator): tools = comp.GetToolList(False, "Saver").values() for tool in tools: data = self.get_managed_tool_data(tool) + if not data: + continue # Add instance created_instance = CreatedInstance.from_existing(data, self) From 03d777503cc8da73cd46ad213d9b249c3b3f7aa3 Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Thu, 11 May 2023 16:14:16 +0100 Subject: [PATCH 53/71] Remove render extractor --- .../unreal/plugins/publish/extract_render.py | 48 ------------------- 1 file changed, 48 deletions(-) delete mode 100644 openpype/hosts/unreal/plugins/publish/extract_render.py diff --git a/openpype/hosts/unreal/plugins/publish/extract_render.py b/openpype/hosts/unreal/plugins/publish/extract_render.py deleted file mode 100644 index 8ff38fbee0..0000000000 --- a/openpype/hosts/unreal/plugins/publish/extract_render.py +++ /dev/null @@ -1,48 +0,0 @@ -from pathlib import Path - -import unreal - -from openpype.pipeline import publish - - -class ExtractRender(publish.Extractor): - """Extract render.""" - - label = "Extract Render" - hosts = ["unreal"] - families = ["render"] - optional = True - - def process(self, instance): - # Define extract output file path - stagingdir = self.staging_dir(instance) - - # Perform extraction - self.log.info("Performing extraction..") - - # Get the render output directory - project_dir = unreal.Paths.project_dir() - render_dir = (f"{project_dir}/Saved/MovieRenders/" - f"{instance.data['subset']}") - - assert unreal.Paths.directory_exists(render_dir), \ - "Render directory does not exist" - - render_path = Path(render_dir) - - frames = [] - - for x in render_path.iterdir(): - if x.is_file() and x.suffix == '.png': - frames.append(str(x)) - - if "representations" not in instance.data: - instance.data["representations"] = [] - - render_representation = { - 'name': 'png', - 'ext': 'png', - 'files': frames, - "stagingDir": stagingdir, - } - instance.data["representations"].append(render_representation) From 9086511970927f662807e67db02e43628f1adce9 Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Thu, 11 May 2023 16:14:41 +0100 Subject: [PATCH 54/71] Fix start and end frames to be int --- .../hosts/unreal/plugins/publish/collect_render_instances.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/unreal/plugins/publish/collect_render_instances.py b/openpype/hosts/unreal/plugins/publish/collect_render_instances.py index 6697a6b90d..a352b2c3f3 100644 --- a/openpype/hosts/unreal/plugins/publish/collect_render_instances.py +++ b/openpype/hosts/unreal/plugins/publish/collect_render_instances.py @@ -73,8 +73,8 @@ class CollectRenderInstances(pyblish.api.InstancePlugin): new_data["level"] = data.get("level") new_data["output"] = s.get('output') new_data["fps"] = seq.get_display_rate().numerator - new_data["frameStart"] = s.get('frame_range')[0] - new_data["frameEnd"] = s.get('frame_range')[1] + new_data["frameStart"] = int(s.get('frame_range')[0]) + new_data["frameEnd"] = int(s.get('frame_range')[1]) new_data["sequence"] = seq.get_path_name() new_data["master_sequence"] = data["master_sequence"] new_data["master_level"] = data["master_level"] From e56f4286c123149f3595920fcb1d550e0c1a8c38 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 12 May 2023 13:39:51 +0200 Subject: [PATCH 55/71] remove python syntax available since 3.8 from unreal addon --- openpype/hosts/unreal/addon.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/unreal/addon.py b/openpype/hosts/unreal/addon.py index db40d629bc..9ded333d7d 100644 --- a/openpype/hosts/unreal/addon.py +++ b/openpype/hosts/unreal/addon.py @@ -23,9 +23,10 @@ class UnrealAddon(OpenPypeModule, IHostAddon): UNREAL_ROOT_DIR, "integration", f"UE_{ue_version}", "Ayon" ) if not Path(unreal_plugin_path).exists(): - if compatible_versions := get_compatible_integration( + compatible_versions = get_compatible_integration( ue_version, Path(UNREAL_ROOT_DIR) / "integration" - ): + ) + if compatible_versions: unreal_plugin_path = compatible_versions[-1] / "Ayon" unreal_plugin_path = unreal_plugin_path.as_posix() From 6968c7c8ba0bed66e131c81ec4b0f53eaa99c3da Mon Sep 17 00:00:00 2001 From: Thomas Fricard <51854004+friquette@users.noreply.github.com> Date: Fri, 12 May 2023 14:57:17 +0200 Subject: [PATCH 56/71] add shortcut to action if in configuration (#4927) Co-authored-by: Thomas Fricard --- .../python/common/scriptsmenu/scriptsmenu.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/openpype/vendor/python/common/scriptsmenu/scriptsmenu.py b/openpype/vendor/python/common/scriptsmenu/scriptsmenu.py index 6f6d0b5715..8ab621f757 100644 --- a/openpype/vendor/python/common/scriptsmenu/scriptsmenu.py +++ b/openpype/vendor/python/common/scriptsmenu/scriptsmenu.py @@ -19,9 +19,9 @@ class ScriptsMenu(QtWidgets.QMenu): Args: title (str): the name of the root menu which will be created - + parent (QtWidgets.QObject) : the QObject to parent the menu to - + Returns: None @@ -94,7 +94,7 @@ class ScriptsMenu(QtWidgets.QMenu): parent(QtWidgets.QWidget): the object to parent the menu to title(str): the title of the menu - + Returns: QtWidget.QMenu instance """ @@ -111,7 +111,7 @@ class ScriptsMenu(QtWidgets.QMenu): return menu def add_script(self, parent, title, command, sourcetype, icon=None, - tags=None, label=None, tooltip=None): + tags=None, label=None, tooltip=None, shortcut=None): """Create an action item which runs a script when clicked Args: @@ -134,6 +134,8 @@ class ScriptsMenu(QtWidgets.QMenu): tooltip (str): A tip for the user about the usage fo the tool + shortcut (str): A shortcut to run the command + Returns: QtWidget.QAction instance @@ -166,6 +168,9 @@ class ScriptsMenu(QtWidgets.QMenu): raise RuntimeError("Script action can't be " "processed: {}".format(e)) + if shortcut: + script_action.setShortcut(shortcut) + if icon: iconfile = os.path.expandvars(icon) script_action.iconfile = iconfile @@ -253,7 +258,7 @@ class ScriptsMenu(QtWidgets.QMenu): def _update_search(self, search): """Hide all the samples which do not match the user's import - + Returns: None From d3428da3937bb0dbad2e1f86705e95d2bbe6b695 Mon Sep 17 00:00:00 2001 From: kaa Date: Fri, 12 May 2023 15:19:23 +0200 Subject: [PATCH 57/71] fix get_linked_assets project name arg (#4940) --- openpype/pipeline/workfile/build_workfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/pipeline/workfile/build_workfile.py b/openpype/pipeline/workfile/build_workfile.py index 26b17fa151..8329487839 100644 --- a/openpype/pipeline/workfile/build_workfile.py +++ b/openpype/pipeline/workfile/build_workfile.py @@ -186,7 +186,7 @@ class BuildWorkfile: if link_context_profiles: # Find and append linked assets if preset has set linked mapping - link_assets = get_linked_assets(current_asset_entity) + link_assets = get_linked_assets(project_name, current_asset_entity) if link_assets: assets.extend(link_assets) From d8b569b160167d491ab29367d00d0f504f40c0ab Mon Sep 17 00:00:00 2001 From: Sharkitty <81646000+Sharkitty@users.noreply.github.com> Date: Fri, 12 May 2023 14:14:44 +0000 Subject: [PATCH 58/71] Update openpype/plugins/inventory/remove_and_load.py Discover plugins only once Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/plugins/inventory/remove_and_load.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/plugins/inventory/remove_and_load.py b/openpype/plugins/inventory/remove_and_load.py index 062a44354b..d90cc9462c 100644 --- a/openpype/plugins/inventory/remove_and_load.py +++ b/openpype/plugins/inventory/remove_and_load.py @@ -17,10 +17,10 @@ class RemoveAndLoad(InventoryAction): def process(self, containers): project_name = get_current_project_name() + loaders = discover_loader_plugins(project_name=project_name) for container in containers: # Get loader loader_name = container["loader"] - loaders = discover_loader_plugins(project_name=project_name) for plugin in loaders: if get_loader_identifier(plugin) == loader_name: loader = plugin From ce1e45f7082a108258b2fa1bbd3e5a37e25f52e3 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Fri, 12 May 2023 16:35:10 +0200 Subject: [PATCH 59/71] fix key assignment on instance data (#4966) --- .../ftrack/plugins/publish/integrate_hierarchy_ftrack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/modules/ftrack/plugins/publish/integrate_hierarchy_ftrack.py b/openpype/modules/ftrack/plugins/publish/integrate_hierarchy_ftrack.py index 9f35424d42..6daaea5f18 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_hierarchy_ftrack.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_hierarchy_ftrack.py @@ -378,7 +378,7 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): existing_tasks.append(task_name_low) for instance in instances_by_task_name[task_name_low]: - instance["ftrackTask"] = child + instance.data["ftrackTask"] = child for task_name in tasks: task_type = tasks[task_name]["type"] From ab357eb03e316691057633b5762cdb094b35ef8d Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Fri, 12 May 2023 16:44:44 +0200 Subject: [PATCH 60/71] Addons directory (#4893) * Add addons directory * add addons dir to modules dirs automatically --------- Co-authored-by: iLLiCiTiT --- .gitignore | 6 ++++++ openpype/addons/README.md | 3 +++ openpype/modules/base.py | 6 +++++- 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 openpype/addons/README.md diff --git a/.gitignore b/.gitignore index 18e7cd7bf2..50f52f65a3 100644 --- a/.gitignore +++ b/.gitignore @@ -112,3 +112,9 @@ tools/run_eventserver.* tools/dev_* .github_changelog_generator + + +# Addons +######## +/openpype/addons/* +!/openpype/addons/README.md diff --git a/openpype/addons/README.md b/openpype/addons/README.md new file mode 100644 index 0000000000..92b8b8c07c --- /dev/null +++ b/openpype/addons/README.md @@ -0,0 +1,3 @@ +This directory is for storing external addons that needs to be included in the pipeline when distributed. + +The directory is ignored by Git, but included in the zip and installation files. diff --git a/openpype/modules/base.py b/openpype/modules/base.py index ed1eeb04cd..732525b6eb 100644 --- a/openpype/modules/base.py +++ b/openpype/modules/base.py @@ -311,6 +311,7 @@ def _load_modules(): # Look for OpenPype modules in paths defined with `get_module_dirs` # - dynamically imported OpenPype modules and addons module_dirs = get_module_dirs() + # Add current directory at first place # - has small differences in import logic current_dir = os.path.abspath(os.path.dirname(__file__)) @@ -318,8 +319,11 @@ def _load_modules(): module_dirs.insert(0, hosts_dir) module_dirs.insert(0, current_dir) + addons_dir = os.path.join(os.path.dirname(current_dir), "addons") + module_dirs.append(addons_dir) + processed_paths = set() - for dirpath in module_dirs: + for dirpath in frozenset(module_dirs): # Skip already processed paths if dirpath in processed_paths: continue From 5ff9ab368b392e48dbc1c522a461d5b52c300b79 Mon Sep 17 00:00:00 2001 From: Sharkitty Date: Fri, 12 May 2023 17:07:52 +0200 Subject: [PATCH 61/71] pre cache loader by name, loader name in error --- openpype/plugins/inventory/remove_and_load.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/openpype/plugins/inventory/remove_and_load.py b/openpype/plugins/inventory/remove_and_load.py index d90cc9462c..ae66b95f6e 100644 --- a/openpype/plugins/inventory/remove_and_load.py +++ b/openpype/plugins/inventory/remove_and_load.py @@ -17,17 +17,18 @@ class RemoveAndLoad(InventoryAction): def process(self, containers): project_name = get_current_project_name() - loaders = discover_loader_plugins(project_name=project_name) + loaders_by_name = { + get_loader_identifier(plugin): plugin + for plugin in discover_loader_plugins(project_name=project_name) + } for container in containers: # Get loader loader_name = container["loader"] - for plugin in loaders: - if get_loader_identifier(plugin) == loader_name: - loader = plugin - break - else: + loader = loaders_by_name.get(loader_name, None) + if not loader: raise RuntimeError( - "Failed to get loader, can't remove and load container" + "Failed to get loader '{}', can't remove " + "and load container".format(loader_name) ) # Get representation From 78f8bbfd8066604d490aa89b56e0061a0d8d191b Mon Sep 17 00:00:00 2001 From: Ember Light <49758407+EmberLightVFX@users.noreply.github.com> Date: Fri, 12 May 2023 17:29:38 +0200 Subject: [PATCH 62/71] Kitsu - Add "image", "online" and "plate" to review families (#4923) * Add kitsu review to the default png review's tags * Add "image", "online" and "plate" as possible review families --- .../modules/kitsu/plugins/publish/integrate_kitsu_note.py | 7 ++++--- .../kitsu/plugins/publish/integrate_kitsu_review.py | 3 +-- openpype/settings/defaults/project_settings/global.json | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py index f8e56377bb..6e5dd056f3 100644 --- a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py +++ b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py @@ -9,7 +9,7 @@ class IntegrateKitsuNote(pyblish.api.ContextPlugin): order = pyblish.api.IntegratorOrder label = "Kitsu Note and Status" - families = ["render", "kitsu"] + families = ["render", "image", "online", "plate", "kitsu"] # status settings set_status_note = False @@ -52,8 +52,9 @@ class IntegrateKitsuNote(pyblish.api.ContextPlugin): for instance in context: # Check if instance is a review by checking its family # Allow a match to primary family or any of families - families = set([instance.data["family"]] + - instance.data.get("families", [])) + families = set( + [instance.data["family"]] + instance.data.get("families", []) + ) if "review" not in families: continue diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py index e05ff05f50..bbed4a3024 100644 --- a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py +++ b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py @@ -8,11 +8,10 @@ class IntegrateKitsuReview(pyblish.api.InstancePlugin): order = pyblish.api.IntegratorOrder + 0.01 label = "Kitsu Review" - families = ["render", "kitsu"] + families = ["render", "image", "online", "plate", "kitsu"] optional = True def process(self, instance): - # Check comment has been created comment_id = instance.data.get("kitsu_comment", {}).get("id") if not comment_id: diff --git a/openpype/settings/defaults/project_settings/global.json b/openpype/settings/defaults/project_settings/global.json index 50b62737d8..75f335f1de 100644 --- a/openpype/settings/defaults/project_settings/global.json +++ b/openpype/settings/defaults/project_settings/global.json @@ -82,7 +82,8 @@ "png": { "ext": "png", "tags": [ - "ftrackreview" + "ftrackreview", + "kitsureview" ], "burnins": [], "ffmpeg_args": { From eaefd594b6f2f89a0e8a1accbb5912b1a744035a Mon Sep 17 00:00:00 2001 From: Ynbot Date: Sat, 13 May 2023 03:25:18 +0000 Subject: [PATCH 63/71] [Automated] Bump version --- openpype/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/version.py b/openpype/version.py index 7df154fe1e..319a58d384 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.15.7-nightly.2" +__version__ = "3.15.7-nightly.3" From 927f92df87d3bae5d035c3ae4f857ac171e84dfa Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 13 May 2023 03:26:01 +0000 Subject: [PATCH 64/71] chore(): update bug report / version --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 0d75b669d2..7d224aa73f 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -35,6 +35,7 @@ body: label: Version description: What version are you running? Look to OpenPype Tray options: + - 3.15.7-nightly.3 - 3.15.7-nightly.2 - 3.15.7-nightly.1 - 3.15.6 @@ -134,7 +135,6 @@ body: - 3.14.1-nightly.4 - 3.14.1-nightly.3 - 3.14.1-nightly.2 - - 3.14.1-nightly.1 validations: required: true - type: dropdown From 11b895624afb2d1dde099eefe09c46b7d3f65b24 Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Mon, 15 May 2023 10:44:58 +0100 Subject: [PATCH 65/71] Fix transform when loading layout to match existing assets --- .../plugins/load/load_layout_existing.py | 81 +++++++------------ 1 file changed, 28 insertions(+), 53 deletions(-) diff --git a/openpype/hosts/unreal/plugins/load/load_layout_existing.py b/openpype/hosts/unreal/plugins/load/load_layout_existing.py index 96ee8cfc25..f4a2d1e7cc 100644 --- a/openpype/hosts/unreal/plugins/load/load_layout_existing.py +++ b/openpype/hosts/unreal/plugins/load/load_layout_existing.py @@ -89,50 +89,26 @@ class ExistingLayoutLoader(plugin.Loader): raise NotImplementedError( f"Unreal version {ue_major} not supported") - def _get_transform(self, ext, import_data, lasset): - conversion = unreal.Matrix.IDENTITY.transform() - fbx_tuning = unreal.Matrix.IDENTITY.transform() + def _transform_from_basis(self, transform, basis): + """Transform a transform from a basis to a new basis.""" + # Get the basis matrix + basis_matrix = unreal.Matrix( + basis[0], + basis[1], + basis[2], + basis[3] + ) + transform_matrix = unreal.Matrix( + transform[0], + transform[1], + transform[2], + transform[3] + ) - basis = unreal.Matrix( - lasset.get('basis')[0], - lasset.get('basis')[1], - lasset.get('basis')[2], - lasset.get('basis')[3] - ).transform() - transform = unreal.Matrix( - lasset.get('transform_matrix')[0], - lasset.get('transform_matrix')[1], - lasset.get('transform_matrix')[2], - lasset.get('transform_matrix')[3] - ).transform() + new_transform = ( + basis_matrix.get_inverse() * transform_matrix * basis_matrix) - # Check for the conversion settings. We cannot access - # the alembic conversion settings, so we assume that - # the maya ones have been applied. - if ext == '.fbx': - loc = import_data.import_translation - rot = import_data.import_rotation.to_vector() - scale = import_data.import_uniform_scale - conversion = unreal.Transform( - location=[loc.x, loc.y, loc.z], - rotation=[rot.x, rot.y, rot.z], - scale=[-scale, scale, scale] - ) - fbx_tuning = unreal.Transform( - rotation=[180.0, 0.0, 90.0], - scale=[1.0, 1.0, 1.0] - ) - elif ext == '.abc': - # This is the standard conversion settings for - # alembic files from Maya. - conversion = unreal.Transform( - location=[0.0, 0.0, 0.0], - rotation=[0.0, 0.0, 0.0], - scale=[1.0, -1.0, 1.0] - ) - - new_transform = (basis.inverse() * transform * basis) - return fbx_tuning * conversion.inverse() * new_transform + return new_transform.transform() def _spawn_actor(self, obj, lasset): actor = EditorLevelLibrary.spawn_actor_from_object( @@ -140,16 +116,13 @@ class ExistingLayoutLoader(plugin.Loader): ) actor.set_actor_label(lasset.get('instance_name')) - smc = actor.get_editor_property('static_mesh_component') - mesh = smc.get_editor_property('static_mesh') - import_data = mesh.get_editor_property('asset_import_data') - filename = import_data.get_first_filename() - path = Path(filename) - transform = self._get_transform( - path.suffix, import_data, lasset) + transform = lasset.get('transform_matrix') + basis = lasset.get('basis') - actor.set_actor_transform(transform, False, True) + t = self._transform_from_basis(transform, basis) + + actor.set_actor_transform(t, False, True) @staticmethod def _get_fbx_loader(loaders, family): @@ -320,9 +293,11 @@ class ExistingLayoutLoader(plugin.Loader): containers.append(container) # Set the transform for the actor. - transform = self._get_transform( - path.suffix, import_data, lasset) - actor.set_actor_transform(transform, False, True) + transform = lasset.get('transform_matrix') + basis = lasset.get('basis') + + t = self._transform_from_basis(transform, basis) + actor.set_actor_transform(t, False, True) actors_matched.append(actor) found = True From 5625c1f45b542286877bc7a8894c7562053f7a30 Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Mon, 15 May 2023 12:09:25 +0100 Subject: [PATCH 66/71] Use proper variable names --- .../hosts/unreal/plugins/load/load_layout_existing.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/unreal/plugins/load/load_layout_existing.py b/openpype/hosts/unreal/plugins/load/load_layout_existing.py index f4a2d1e7cc..929a9a1399 100644 --- a/openpype/hosts/unreal/plugins/load/load_layout_existing.py +++ b/openpype/hosts/unreal/plugins/load/load_layout_existing.py @@ -120,9 +120,9 @@ class ExistingLayoutLoader(plugin.Loader): transform = lasset.get('transform_matrix') basis = lasset.get('basis') - t = self._transform_from_basis(transform, basis) + computed_transform = self._transform_from_basis(transform, basis) - actor.set_actor_transform(t, False, True) + actor.set_actor_transform(computed_transform, False, True) @staticmethod def _get_fbx_loader(loaders, family): @@ -296,8 +296,9 @@ class ExistingLayoutLoader(plugin.Loader): transform = lasset.get('transform_matrix') basis = lasset.get('basis') - t = self._transform_from_basis(transform, basis) - actor.set_actor_transform(t, False, True) + computed_transform = self._transform_from_basis( + transform, basis) + actor.set_actor_transform(computed_transform, False, True) actors_matched.append(actor) found = True From 0845ba29dd4edd1872118a65fe72653b6e429531 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Mon, 15 May 2023 14:08:35 +0200 Subject: [PATCH 67/71] General: Project Anatomy on creators (#4962) * added project anatomy to create context * added project anatomy to create plugin --- openpype/pipeline/create/context.py | 19 ++++++++++++++++++- openpype/pipeline/create/creator_plugins.py | 16 +++++++++++++++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/openpype/pipeline/create/context.py b/openpype/pipeline/create/context.py index 382bbea05e..2fc0669732 100644 --- a/openpype/pipeline/create/context.py +++ b/openpype/pipeline/create/context.py @@ -23,7 +23,7 @@ from openpype.lib.attribute_definitions import ( get_default_values, ) from openpype.host import IPublishHost, IWorkfileHost -from openpype.pipeline import legacy_io +from openpype.pipeline import legacy_io, Anatomy from openpype.pipeline.plugin_discover import DiscoverResult from .creator_plugins import ( @@ -1383,6 +1383,8 @@ class CreateContext: self._current_task_name = None self._current_workfile_path = None + self._current_project_anatomy = None + self._host_is_valid = host_is_valid # Currently unused variable self.headless = headless @@ -1546,6 +1548,18 @@ class CreateContext: return self._current_workfile_path + def get_current_project_anatomy(self): + """Project anatomy for current project. + + Returns: + Anatomy: Anatomy object ready to be used. + """ + + if self._current_project_anatomy is None: + self._current_project_anatomy = Anatomy( + self._current_project_name) + return self._current_project_anatomy + @property def context_has_changed(self): """Host context has changed. @@ -1568,6 +1582,7 @@ class CreateContext: ) project_name = property(get_current_project_name) + project_anatomy = property(get_current_project_anatomy) @property def log(self): @@ -1680,6 +1695,8 @@ class CreateContext: self._current_task_name = task_name self._current_workfile_path = workfile_path + self._current_project_anatomy = None + def reset_plugins(self, discover_publish_plugins=True): """Reload plugins. diff --git a/openpype/pipeline/create/creator_plugins.py b/openpype/pipeline/create/creator_plugins.py index bd3fbaf78f..9e47e9cc12 100644 --- a/openpype/pipeline/create/creator_plugins.py +++ b/openpype/pipeline/create/creator_plugins.py @@ -231,10 +231,24 @@ class BaseCreator: @property def project_name(self): - """Family that plugin represents.""" + """Current project name. + + Returns: + str: Name of a project. + """ return self.create_context.project_name + @property + def project_anatomy(self): + """Current project anatomy. + + Returns: + Anatomy: Project anatomy object. + """ + + return self.create_context.project_anatomy + @property def host(self): return self.create_context.host From 40d4fea857202fcb4194376511f208d8db0f3655 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Mon, 15 May 2023 14:10:49 +0200 Subject: [PATCH 68/71] Maya: Validate shader name - OP-5903 (#4971) * Fix regex matching. * Add active setting * Update openpype/hosts/maya/plugins/publish/validate_shader_name.py --- .../plugins/publish/validate_shader_name.py | 20 +++++++++---------- .../defaults/project_settings/maya.json | 1 + .../schemas/schema_maya_publish.json | 5 +++++ 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/validate_shader_name.py b/openpype/hosts/maya/plugins/publish/validate_shader_name.py index b3e51f011d..034db471da 100644 --- a/openpype/hosts/maya/plugins/publish/validate_shader_name.py +++ b/openpype/hosts/maya/plugins/publish/validate_shader_name.py @@ -50,7 +50,8 @@ class ValidateShaderName(pyblish.api.InstancePlugin): asset_name = instance.data.get("asset", None) # Check the number of connected shadingEngines per shape - r = re.compile(cls.regex) + regex_compile = re.compile(cls.regex) + error_message = "object {0} has invalid shader name {1}" for shape in shapes: shading_engines = cmds.listConnections(shape, destination=True, @@ -60,19 +61,18 @@ class ValidateShaderName(pyblish.api.InstancePlugin): ) for shader in shaders: - m = r.match(cls.regex, shader) + m = regex_compile.match(shader) if m is None: invalid.append(shape) - cls.log.error( - "object {0} has invalid shader name {1}".format(shape, - shader) - ) + cls.log.error(error_message.format(shape, shader)) else: - if 'asset' in r.groupindex: + if 'asset' in regex_compile.groupindex: if m.group('asset') != asset_name: invalid.append(shape) - cls.log.error(("object {0} has invalid " - "shader name {1}").format(shape, - shader)) + message = error_message + message += " with missing asset name \"{2}\"" + cls.log.error( + message.format(shape, shader, asset_name) + ) return invalid diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index 72b330ce7a..a2a43eefb5 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -734,6 +734,7 @@ "ValidateShaderName": { "enabled": false, "optional": true, + "active": true, "regex": "(?P.*)_(.*)_SHD" }, "ValidateShadingEngine": { diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json index 346948c658..07c8d8715b 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json @@ -126,6 +126,11 @@ "key": "optional", "label": "Optional" }, + { + "type": "boolean", + "key": "active", + "label": "Active" + }, { "type": "label", "label": "Shader name regex can use named capture group asset to validate against current asset name.

Example:
^.*(?P=<asset>.+)_SHD

" From 628ecbe5e2e6fb2c11df0185726e60a168eba013 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Mon, 15 May 2023 17:58:12 +0200 Subject: [PATCH 69/71] :truck: move test file --- .../unreal}/plugins/publish/test_validate_sequence_frames.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/unit/openpype/{ => hosts/unreal}/plugins/publish/test_validate_sequence_frames.py (100%) diff --git a/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py b/tests/unit/openpype/hosts/unreal/plugins/publish/test_validate_sequence_frames.py similarity index 100% rename from tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py rename to tests/unit/openpype/hosts/unreal/plugins/publish/test_validate_sequence_frames.py From 380a9cba51448a90e3e7b1c67fd50a818837f20c Mon Sep 17 00:00:00 2001 From: Ynbot Date: Tue, 16 May 2023 08:44:24 +0000 Subject: [PATCH 70/71] [Automated] Release --- CHANGELOG.md | 297 ++++++++++++++++++++++++++++++++++++++++++++ openpype/version.py | 2 +- pyproject.toml | 2 +- 3 files changed, 299 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07c1e7d5fd..bba6b64bfe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,303 @@ # Changelog +## [3.15.7](https://github.com/ynput/OpenPype/tree/3.15.7) + + +[Full Changelog](https://github.com/ynput/OpenPype/compare/3.15.6...3.15.7) + +### **🆕 New features** + + +
+Addons directory #4893 + +This adds a directory for Addons, for easier distribution of studio specific code. + + +___ + +
+ + +
+Kitsu - Add "image", "online" and "plate" to review families #4923 + +This PR adds "image", "online" and "plate" to the review families so they also can be uploaded to Kitsu.It also adds the `Add review to Kitsu` tag to the default png review. Without it the user would manually need to add it for single image uploads to Kitsu and might confuse users (it confused me first for a while as movies did work). + + +___ + +
+ + +
+Feature/remove and load inv action #4930 + +Added the ability to remove and load a container, as a way to reset it.This can be useful in cases where a container breaks in a way that can be fixed by removing it, then reloading it.Also added the ability to add `InventoryAction` plugins by placing them in `openpype/plugins/inventory`. + + +___ + +
+ +### **🚀 Enhancements** + + +
+Load Rig References - Change Rig to Animation in Animation instance #4877 + +We are using the template builder to build an animation scene. All the rig placeholders are imported correctly, but the automatically created animation instances retain the rig family in their names and subsets. In our example, we need animationMain instead of rigMain, because this name will be used in the following steps like lighting.Here is the result we need. I checked, and it's not a template builder problem, because even if I load a rig as a reference, the result is the same. For me, since we are in the animation instance, it makes more sense to have animation instead of rig in the name. The naming is just fine if we use create from the Openpype menu. + + +___ + +
+ + +
+Maya template builder - preserve all references when importing a template #4797 + +When building a template with Maya template builder, we import the template and also the references inside the template file. This causes some problems: +- We cannot use the references to version assets imported by the template. +- When we import the file, the internal reference files are also imported. As a side effect, Maya complains about a reference that no longer exists.`// Error: file: /xxx/maya/2023.3/linux/scripts/AETemplates/AEtransformRelated.mel line 58: Reference node 'turntable_mayaSceneMain_01_RN' is not associated with a reference file.` + + +___ + +
+ + +
+Unreal: Renaming the integration plugin to Ayon. #4646 + +Renamed the .h, and .cpp files to Ayon. Also renamed the classes to with the Ayon keyword. + + +___ + +
+ + +
+3dsMax: render dialogue needs to be closed #4729 + +Make sure the render setup dialog is in a closed state for the update of resolution and other render settings + + +___ + +
+ + +
+Maya Template Builder - Remove default cameras from renderable cameras #4815 + +When we build an asset workfile with build workfile from template inside Maya, we load our turntable camera. But then we end up with 2 renderables camera : **persp** the one imported from the template.We need to remove the **persp** camera (or any other default camera) from renderable cameras when building the work file. + + +___ + +
+ + +
+Validators for Frame Range in Max #4914 + +Switch Render Frame Range Type to 3 for specific ranges (initial setup for the range type is 4)Reset Frame Range will also set the frame range for render settingsRender Collector won't take the frame range from context data but take the range directly from render settingAdd validators for render frame range type and frame range respectively with repair action + + +___ + +
+ + +
+Fusion: Saver creator settings #4943 + +Adding Saver creator settings and enhanced rendering path with template. + + +___ + +
+ + +
+General: Project Anatomy on creators #4962 + +Anatomy object of current project is available on `CreateContext` and create plugins. + + +___ + +
+ +### **🐛 Bug fixes** + + +
+Maya: Validate shader name - OP-5903 #4971 + +Running the plugin would error with: +``` +// TypeError: 'str' object cannot be interpreted as an integer +```Fixed and added setting `active`. + + +___ + +
+ + +
+Houdini: Fix slow Houdini launch due to shelves generation #4829 + +Shelf generation during Houdini startup would add an insane amount of delay for the Houdini UI to launch correctly. By deferring the shelf generation this takes away the 5+ minutes of delay for the Houdini UI to launch. + + +___ + +
+ + +
+Fusion - Fixed "optional validation" #4912 + +Added OptionalPyblishPluginMixin and is_active checks for all publish tools that should be optional + + +___ + +
+ + +
+Bug: add missing `pyblish.util` import #4937 + +remote publishing was missing import of `remote_publish`. This is adding it back. + + +___ + +
+ + +
+Unreal: Fix missing 'object_path' property #4938 + +Epic removed the `object_path` property from `AssetData`. This PR fixes usages of that property.Fixes #4936 + + +___ + +
+ + +
+Remove obsolete global validator #4939 + +Removing `Validate Sequence Frames` validator from global plugins as it wasn't handling correctly many things and was by mistake enabled, breaking functionality on Deadline. + + +___ + +
+ + +
+General: fix build_workfile get_linked_assets missing project_name arg #4940 + +Linked assets collection don't work within `build_workfile` because `get_linked_assets` function call has a missing `project_name`argument. +- Added the `project_name` arg to the `get_linked_assets` function call. + + +___ + +
+ + +
+General: fix Scene Inventory switch version error dialog missing parent arg on init #4941 + +QuickFix for the switch version error dialog to set inventory widget as parent. + + +___ + +
+ + +
+Unreal: Fix camera frame range #4956 + +Fix the frame range of the level sequence for the Camera in Unreal. + + +___ + +
+ + +
+Unreal: Fix missing parameter when updating Alembic StaticMesh #4957 + +Fix an error when updating an Alembic StaticMesh in Unreal, due to a missing parameter in a function call. + + +___ + +
+ + +
+Unreal: Fix render extraction #4963 + +Fix a problem with the extraction of renders in Unreal. + + +___ + +
+ + +
+Unreal: Remove Python 3.8 syntax from addon #4965 + +Removed Python 3.8 syntax from addon. + + +___ + +
+ + +
+Ftrack: Fix editorial task creation #4966 + +Fix key assignment on instance data during editorial publishing in ftrack hierarchy integration. + + +___ + +
+ +### **Merged pull requests** + + +
+Add "shortcut" to Scripts Menu Definition #4927 + +Add the possibility to associate a shorcut for an entry in the script menu definition with the key "shortcut" + + +___ + +
+ + + + ## [3.15.6](https://github.com/ynput/OpenPype/tree/3.15.6) diff --git a/openpype/version.py b/openpype/version.py index 319a58d384..3a0d05be0e 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.15.7-nightly.3" +__version__ = "3.15.7" diff --git a/pyproject.toml b/pyproject.toml index 003f6cf2d3..190ecb9329 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "OpenPype" -version = "3.15.6" # OpenPype +version = "3.15.7" # OpenPype description = "Open VFX and Animation pipeline with support." authors = ["OpenPype Team "] license = "MIT License" From 28e0838d00e9b3edc8880c3bc59a753cb6727929 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 16 May 2023 08:45:43 +0000 Subject: [PATCH 71/71] chore(): update bug report / version --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 7d224aa73f..08d20c2058 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -35,6 +35,7 @@ body: label: Version description: What version are you running? Look to OpenPype Tray options: + - 3.15.7 - 3.15.7-nightly.3 - 3.15.7-nightly.2 - 3.15.7-nightly.1 @@ -134,7 +135,6 @@ body: - 3.14.1 - 3.14.1-nightly.4 - 3.14.1-nightly.3 - - 3.14.1-nightly.2 validations: required: true - type: dropdown