Bases: OptionalPyblishPluginMixin
, 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
Source code in client/ayon_max/plugins/publish/validate_loaded_plugin.py
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143 | class ValidateLoadedPlugin(OptionalPyblishPluginMixin,
pyblish.api.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
"""
order = pyblish.api.ValidatorOrder
hosts = ["max"]
label = "Validate Loaded Plugins"
optional = True
actions = [RepairAction]
settings_category = "max"
family_plugins_mapping = []
@classmethod
def get_invalid(cls, instance):
"""Plugin entry point."""
family_plugins_mapping = cls.family_plugins_mapping
if not family_plugins_mapping:
return
# Backward compatibility - settings did have 'product_types'
if "product_types" in family_plugins_mapping:
family_plugins_mapping["families"] = family_plugins_mapping.pop(
"product_types"
)
invalid = []
# Find all plug-in requirements for current instance
instance_families = {instance.data["productType"]}
instance_families.update(instance.data.get("families", []))
cls.log.debug("Checking plug-in validation "
f"for instance families: {instance_families}")
all_required_plugins = set()
for mapping in family_plugins_mapping:
# Check for matching families
if not mapping:
return
match_families = {
fam.strip() for fam in mapping["families"]
}
has_match = "*" in match_families or match_families.intersection(
instance_families)
if not has_match:
continue
cls.log.debug(
f"Found plug-in family requirements: {match_families}")
required_plugins = [
# match lowercase and format with os.environ to allow
# plugin names defined by max version, e.g. {3DSMAX_VERSION}
plugin.format(**os.environ).lower()
for plugin in mapping["plugins"]
# ignore empty fields in settings
if plugin.strip()
]
all_required_plugins.update(required_plugins)
if not all_required_plugins:
# Instance has no plug-in requirements
return
# 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())
}
# validate the required plug-ins
for plugin in sorted(all_required_plugins):
plugin_index = available_plugins.get(plugin)
if plugin_index is None:
debug_msg = (
f"Plugin {plugin} does not exist"
" in 3dsMax Plugin List."
)
invalid.append((plugin, debug_msg))
continue
if not rt.pluginManager.isPluginDllLoaded(plugin_index):
debug_msg = f"Plugin {plugin} not loaded."
invalid.append((plugin, debug_msg))
return invalid
def process(self, instance):
if not self.is_active(instance.data):
self.log.debug("Skipping Validate Loaded Plugin...")
return
invalid = self.get_invalid(instance)
if invalid:
bullet_point_invalid_statement = "\n".join(
"- {}".format(message) for _, message in invalid
)
report = (
"Required plugins are not loaded.\n\n"
f"{bullet_point_invalid_statement}\n\n"
"You can use repair action to load the plugin."
)
raise PublishValidationError(
report, title="Missing Required Plugins")
@classmethod
def repair(cls, instance):
# get all DLL loaded plugins in Max and their plugin index
invalid = cls.get_invalid(instance)
if not invalid:
return
# 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())
}
for invalid_plugin, _ in invalid:
plugin_index = available_plugins.get(invalid_plugin)
if plugin_index is None:
cls.log.warning(
f"Can't enable missing plugin: {invalid_plugin}")
continue
if not rt.pluginManager.isPluginDllLoaded(plugin_index):
rt.pluginManager.loadPluginDll(plugin_index)
|
get_invalid(instance)
classmethod
Plugin entry point.
Source code in client/ayon_max/plugins/publish/validate_loaded_plugin.py
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102 | @classmethod
def get_invalid(cls, instance):
"""Plugin entry point."""
family_plugins_mapping = cls.family_plugins_mapping
if not family_plugins_mapping:
return
# Backward compatibility - settings did have 'product_types'
if "product_types" in family_plugins_mapping:
family_plugins_mapping["families"] = family_plugins_mapping.pop(
"product_types"
)
invalid = []
# Find all plug-in requirements for current instance
instance_families = {instance.data["productType"]}
instance_families.update(instance.data.get("families", []))
cls.log.debug("Checking plug-in validation "
f"for instance families: {instance_families}")
all_required_plugins = set()
for mapping in family_plugins_mapping:
# Check for matching families
if not mapping:
return
match_families = {
fam.strip() for fam in mapping["families"]
}
has_match = "*" in match_families or match_families.intersection(
instance_families)
if not has_match:
continue
cls.log.debug(
f"Found plug-in family requirements: {match_families}")
required_plugins = [
# match lowercase and format with os.environ to allow
# plugin names defined by max version, e.g. {3DSMAX_VERSION}
plugin.format(**os.environ).lower()
for plugin in mapping["plugins"]
# ignore empty fields in settings
if plugin.strip()
]
all_required_plugins.update(required_plugins)
if not all_required_plugins:
# Instance has no plug-in requirements
return
# 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())
}
# validate the required plug-ins
for plugin in sorted(all_required_plugins):
plugin_index = available_plugins.get(plugin)
if plugin_index is None:
debug_msg = (
f"Plugin {plugin} does not exist"
" in 3dsMax Plugin List."
)
invalid.append((plugin, debug_msg))
continue
if not rt.pluginManager.isPluginDllLoaded(plugin_index):
debug_msg = f"Plugin {plugin} not loaded."
invalid.append((plugin, debug_msg))
return invalid
|