From 881340b60a1dd2eba9d76331082679b9e26e6df9 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 2 Nov 2023 12:27:22 +0800 Subject: [PATCH] supports families check before the validation of loaded plugins --- .../plugins/publish/validate_loaded_plugin.py | 59 +++++++++++++------ .../plugins/publish/collect_scene_version.py | 1 + openpype/settings/ayon_settings.py | 13 ++++ .../defaults/project_settings/max.json | 2 +- .../schemas/schema_max_publish.json | 12 ++-- .../max/server/settings/publishers.py | 12 +++- 6 files changed, 74 insertions(+), 25 deletions(-) diff --git a/openpype/hosts/max/plugins/publish/validate_loaded_plugin.py b/openpype/hosts/max/plugins/publish/validate_loaded_plugin.py index 69f72ccf1d..e8284aeedd 100644 --- a/openpype/hosts/max/plugins/publish/validate_loaded_plugin.py +++ b/openpype/hosts/max/plugins/publish/validate_loaded_plugin.py @@ -1,10 +1,11 @@ # -*- coding: utf-8 -*- """Validator for Loaded Plugin.""" -from pyblish.api import ContextPlugin, ValidatorOrder +import os +from pyblish.api import InstancePlugin, ValidatorOrder from pymxs import runtime as rt from openpype.pipeline.publish import ( - RepairContextAction, + RepairAction, OptionalPyblishPluginMixin, PublishValidationError ) @@ -12,7 +13,7 @@ from openpype.hosts.max.api.lib import get_plugins class ValidateLoadedPlugin(OptionalPyblishPluginMixin, - ContextPlugin): + InstancePlugin): """Validates if the specific plugin is loaded in 3ds max. Studio Admin(s) can add the plugins they want to check in validation via studio defined project settings""" @@ -21,17 +22,17 @@ class ValidateLoadedPlugin(OptionalPyblishPluginMixin, hosts = ["max"] label = "Validate Loaded Plugins" optional = True - actions = [RepairContextAction] + actions = [RepairAction] - def get_invalid(self, context): + def get_invalid(self, instance): """Plugin entry point.""" - if not self.is_active(context.data): + if not self.is_active(instance.data): self.log.debug("Skipping Validate Loaded Plugin...") return required_plugins = ( - context.data["project_settings"]["max"]["publish"] - ["ValidateLoadedPlugin"]["plugins_for_check"] + instance.context.data["project_settings"]["max"]["publish"] + ["ValidateLoadedPlugin"]["family_plugins_mapping"] ) if not required_plugins: @@ -45,9 +46,21 @@ class ValidateLoadedPlugin(OptionalPyblishPluginMixin, get_plugins()) } - for plugin in required_plugins: - plugin_name = plugin.lower() + for families, plugin in required_plugins.items(): + families_list = families.split(",") + excluded_families = [family for family in families_list + if instance.data["family"]!=family + and family!="_"] + if excluded_families: + self.log.debug("The {} instance is not part of {}.".format( + instance.data["family"], excluded_families + )) + return + if not plugin: + return + + plugin_name = plugin.format(**os.environ).lower() plugin_index = available_plugins.get(plugin_name) if plugin_index is None: @@ -61,8 +74,8 @@ class ValidateLoadedPlugin(OptionalPyblishPluginMixin, return invalid - def process(self, context): - invalid_plugins = self.get_invalid(context) + def process(self, instance): + invalid_plugins = self.get_invalid(instance) if invalid_plugins: bullet_point_invalid_statement = "\n".join( "- {}".format(invalid) for invalid in invalid_plugins @@ -76,18 +89,30 @@ class ValidateLoadedPlugin(OptionalPyblishPluginMixin, report, title="Required Plugins unloaded") @classmethod - def repair(cls, context): + def repair(cls, instance): # get all DLL loaded plugins in Max and their plugin index available_plugins = { plugin_name.lower(): index for index, plugin_name in enumerate( get_plugins()) } required_plugins = ( - context.data["project_settings"]["max"]["publish"] - ["ValidateLoadedPlugin"]["plugins_for_check"] + instance.context.data["project_settings"]["max"]["publish"] + ["ValidateLoadedPlugin"]["family_plugins_mapping"] ) - for plugin in required_plugins: - plugin_name = plugin.lower() + for families, plugin in required_plugins.items(): + families_list = families.split(",") + excluded_families = [family for family in families_list + if instance.data["family"]!=family + and family!="_"] + if excluded_families: + cls.log.debug("The {} instance is not part of {}.".format( + instance.data["family"], excluded_families + )) + continue + if not plugin: + continue + + plugin_name = plugin.format(**os.environ).lower() plugin_index = available_plugins.get(plugin_name) if plugin_index is None: diff --git a/openpype/plugins/publish/collect_scene_version.py b/openpype/plugins/publish/collect_scene_version.py index 7920c1e82b..f870ae9ad7 100644 --- a/openpype/plugins/publish/collect_scene_version.py +++ b/openpype/plugins/publish/collect_scene_version.py @@ -24,6 +24,7 @@ class CollectSceneVersion(pyblish.api.ContextPlugin): "hiero", "houdini", "maya", + "max", "nuke", "photoshop", "resolve", diff --git a/openpype/settings/ayon_settings.py b/openpype/settings/ayon_settings.py index 8d4683490b..0cc2abdda4 100644 --- a/openpype/settings/ayon_settings.py +++ b/openpype/settings/ayon_settings.py @@ -640,6 +640,19 @@ def _convert_3dsmax_project_settings(ayon_settings, output): } ayon_max["PointCloud"]["attribute"] = new_point_cloud_attribute + ayon_publish = ayon_max["publish"] + if "ValidateLoadedPlugin" in ayon_publish: + family_plugin_mapping = ( + ayon_publish["ValidateLoadedPlugin"]["family_plugins_mapping"] + ) + new_family_plugin_mapping = { + item["families"]: item["plugins"] + for item in family_plugin_mapping + } + ayon_max["ValidateLoadedPlugin"]["family_plugins_mapping"] = ( + new_family_plugin_mapping + ) + output["max"] = ayon_max diff --git a/openpype/settings/defaults/project_settings/max.json b/openpype/settings/defaults/project_settings/max.json index 45246fdf2b..78eba08750 100644 --- a/openpype/settings/defaults/project_settings/max.json +++ b/openpype/settings/defaults/project_settings/max.json @@ -40,7 +40,7 @@ "ValidateLoadedPlugin": { "enabled": false, "optional": true, - "plugins_for_check": [] + "family_plugins_mapping": {} } } } 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 index 4490c5353d..74c06f8156 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_max_publish.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_max_publish.json @@ -47,10 +47,14 @@ "label": "Optional" }, { - "type": "list", - "key": "plugins_for_check", - "label": "Plugins Needed For Check", - "object_type": "text" + "type": "dict-modifiable", + "collapsible": true, + "key": "family_plugins_mapping", + "label": "Family Plugins Mapping", + "use_label_wrap": true, + "object_type": { + "type": "text" + } } ] } diff --git a/server_addon/max/server/settings/publishers.py b/server_addon/max/server/settings/publishers.py index 8a28224a07..3cf3ecf2a5 100644 --- a/server_addon/max/server/settings/publishers.py +++ b/server_addon/max/server/settings/publishers.py @@ -3,11 +3,17 @@ from pydantic import Field from ayon_server.settings import BaseSettingsModel +class FamilyPluginsMappingModel(BaseSettingsModel): + _layout = "compact" + families: str = Field(title="Families") + plugins: str = Field(title="Plugins") + + class ValidateLoadedPluginModel(BaseSettingsModel): enabled: bool = Field(title="ValidateLoadedPlugin") optional: bool = Field(title="Optional") - plugins_for_check: list[str] = Field( - default_factory=list, title="Plugins Needed For Check" + family_plugins_mapping: list[FamilyPluginsMappingModel] = Field( + default_factory=list, title="Family Plugins Mapping" ) @@ -37,6 +43,6 @@ DEFAULT_PUBLISH_SETTINGS = { "ValidateLoadedPlugin": { "enabled": False, "optional": True, - "plugins_for_check": [] + "family_plugins_mapping": {} } }