ported Validate Context data to Max

This commit is contained in:
Kayla Man 2024-02-14 13:39:02 +08:00
commit 64d48641b0
4 changed files with 165 additions and 2 deletions

View file

@ -0,0 +1,42 @@
from pymxs import runtime as rt
import pyblish.api
from ayon_core.pipeline.publish import get_errored_instances_from_context
class SelectInvalidAction(pyblish.api.Action):
"""Select invalid objects in Blender when a publish plug-in failed."""
label = "Select Invalid"
on = "failed"
icon = "search"
def process(self, context, plugin):
errored_instances = get_errored_instances_from_context(context,
plugin=plugin)
# Get the invalid nodes for the plug-ins
self.log.info("Finding invalid nodes...")
invalid = list()
for instance in errored_instances:
invalid_nodes = plugin.get_invalid(instance)
if invalid_nodes:
if isinstance(invalid_nodes, (list, tuple)):
invalid.extend(invalid_nodes)
else:
self.log.warning(
"Failed plug-in doesn't have any selectable objects."
)
if not invalid:
self.log.info("No invalid nodes found.")
return
invalid_names = [obj.name for obj in invalid if isinstance(obj, str)]
if not invalid_names:
invalid_names = [obj.name for obj, _ in invalid]
invalid = [obj for obj, _ in invalid]
self.log.info(
"Selecting invalid objects: %s", ", ".join(invalid_names)
)
rt.Select(invalid)

View file

@ -0,0 +1,107 @@
# -*- coding: utf-8 -*-
"""Validate if instance asset is the same as context asset."""
from __future__ import absolute_import
import pyblish.api
from ayon_core.pipeline.publish import (
RepairAction,
ValidateContentsOrder,
PublishValidationError,
OptionalPyblishPluginMixin
)
from ayon_core.hosts.max.api.action import SelectInvalidAction
from pymxs import runtime as rt
class ValidateInstanceInContext(pyblish.api.InstancePlugin,
OptionalPyblishPluginMixin):
"""Validator to check if instance asset match context asset.
When working in per-shot style you always publish data in context of
current asset (shot). This validator checks if this is so. It is optional
so it can be disabled when needed.
Action on this validator will select invalid instances.
"""
order = ValidateContentsOrder
label = "Instance in same Context"
optional = True
hosts = ["max"]
actions = [SelectInvalidAction, RepairAction]
def process(self, instance):
if not self.is_active(instance.data):
return
instance_node = rt.getNodeByName(instance.data.get(
"instance_node", ""))
if not instance_node:
return
asset = rt.getUserProp(instance_node, "folderPath")
context_asset = self.get_context_asset(instance)
task = rt.getUserProp(instance_node, "task")
context_task = self.get_context_task(instance)
if asset != context_asset:
raise PublishValidationError(
message=(
"Instance '{}' publishes to different asset than current "
"context: {}. Current context: {}".format(
instance.name, asset, context_asset
)
),
description=(
"## Publishing to a different asset\n"
"There are publish instances present which are publishing "
"into a different asset than your current context.\n\n"
"Usually this is not what you want but there can be cases "
"where you might want to publish into another asset or "
"shot. If that's the case you can disable the validation "
"on the instance to ignore it."
)
)
if task != context_task:
raise PublishValidationError(
message=(
"Instance '{}' publishes to different task than current "
"context: {}. Current context: {}".format(
instance.name, task, context_task
)
),
description=(
"## Publishing to a different asset\n"
"There are publish instances present which are publishing "
"into a different asset than your current context.\n\n"
"Usually this is not what you want but there can be cases "
"where you might want to publish into another asset or "
"shot. If that's the case you can disable the validation "
"on the instance to ignore it."
)
)
@classmethod
def get_invalid(cls, instance):
node = rt.getNodeByName(instance.data["instance_node"])
asset = rt.getUserProp(node, "folderPath")
context_asset = cls.get_context_asset(instance)
if asset != context_asset:
return instance.data["instance_node"]
@classmethod
def repair(cls, instance):
context_asset = cls.get_context_asset(instance)
context_task = cls.get_context_task(instance)
instance_node = rt.getNodeByName(instance.data.get(
"instance_node", ""))
if not instance_node:
return
rt.SetUserProp(instance_node, "folderPath", context_asset)
rt.SetUserProp(instance_node, "task", context_task)
@staticmethod
def get_context_asset(instance):
return instance.context.data["asset"]
@staticmethod
def get_context_task(instance):
return instance.context.data["task"]

View file

@ -47,6 +47,11 @@
}
},
"publish": {
"ValidateInstanceInContext": {
"enabled": true,
"optional": true,
"active": true
},
"ValidateFrameRange": {
"enabled": true,
"optional": true,

View file

@ -54,10 +54,14 @@ class BasicValidateModel(BaseSettingsModel):
class PublishersModel(BaseSettingsModel):
ValidateInstanceInContext: BasicValidateModel = SettingsField(
default_factory=BasicValidateModel,
title="Validate Instance In Context",
section="Validators"
)
ValidateFrameRange: BasicValidateModel = SettingsField(
default_factory=BasicValidateModel,
title="Validate Frame Range",
section="Validators"
title="Validate Frame Range"
)
ValidateAttributes: ValidateAttributesModel = SettingsField(
default_factory=ValidateAttributesModel,
@ -92,6 +96,11 @@ class PublishersModel(BaseSettingsModel):
DEFAULT_PUBLISH_SETTINGS = {
"ValidateInstanceInContext": {
"enabled": True,
"optional": True,
"active": True
},
"ValidateFrameRange": {
"enabled": True,
"optional": True,