Merge branch 'develop' into bugfix/unreal-executable-name-on-linux

This commit is contained in:
Ondřej Samohel 2024-05-20 12:53:34 +02:00 committed by GitHub
commit ed005ac62b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 152 additions and 87 deletions

View file

@ -58,3 +58,55 @@ class SelectInvalidAction(pyblish.api.Action):
self.log.info(
"Selecting invalid tools: %s" % ", ".join(sorted(names))
)
class SelectToolAction(pyblish.api.Action):
"""Select invalid output tool in Fusion when plug-in failed.
"""
label = "Select saver"
on = "failed" # This action is only available on a failed plug-in
icon = "search" # Icon from Awesome Icon
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..")
tools = []
for instance in errored_instances:
tool = instance.data.get("tool")
if tool is not None:
tools.append(tool)
else:
self.log.warning(
"Plug-in returned to be invalid, "
f"but has no saver for instance {instance.name}."
)
if not tools:
# Assume relevant comp is current comp and clear selection
self.log.info("No invalid tools found.")
comp = get_current_comp()
flow = comp.CurrentFrame.FlowView
flow.Select() # No args equals clearing selection
return
# Assume a single comp
first_tool = tools[0]
comp = first_tool.Comp()
flow = comp.CurrentFrame.FlowView
flow.Select() # No args equals clearing selection
names = set()
for tool in tools:
flow.Select(tool, True)
comp.SetActiveTool(tool)
names.add(tool.Name)
self.log.info(
"Selecting invalid tools: %s" % ", ".join(sorted(names))
)

View file

@ -52,7 +52,7 @@ class CollectFusionRender(
if product_type not in ["render", "image"]:
continue
task_name = context.data["task"]
task_name = inst.data["task"]
tool = inst.data["transientData"]["tool"]
instance_families = inst.data.get("families", [])

View file

@ -0,0 +1,80 @@
# -*- coding: utf-8 -*-
"""Validate if instance context is the same as publish context."""
import pyblish.api
from ayon_core.hosts.fusion.api.action import SelectToolAction
from ayon_core.pipeline.publish import (
RepairAction,
ValidateContentsOrder,
PublishValidationError,
OptionalPyblishPluginMixin
)
class ValidateInstanceInContextFusion(pyblish.api.InstancePlugin,
OptionalPyblishPluginMixin):
"""Validator to check if instance context matches context of publish.
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.
"""
# Similar to maya and houdini-equivalent `ValidateInstanceInContext`
order = ValidateContentsOrder
label = "Instance in same Context"
optional = True
hosts = ["fusion"]
actions = [SelectToolAction, RepairAction]
def process(self, instance):
if not self.is_active(instance.data):
return
instance_context = self.get_context(instance.data)
context = self.get_context(instance.context.data)
if instance_context != context:
context_label = "{} > {}".format(*context)
instance_label = "{} > {}".format(*instance_context)
raise PublishValidationError(
message=(
"Instance '{}' publishes to different asset than current "
"context: {}. Current context: {}".format(
instance.name, instance_label, context_label
)
),
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 repair(cls, instance):
create_context = instance.context.data["create_context"]
instance_id = instance.data.get("instance_id")
created_instance = create_context.get_instance_by_id(
instance_id
)
if created_instance is None:
raise RuntimeError(
f"No CreatedInstances found with id '{instance_id} "
f"in {create_context.instances_by_id}"
)
context_asset, context_task = cls.get_context(instance.context.data)
created_instance["folderPath"] = context_asset
created_instance["task"] = context_task
create_context.save_changes()
@staticmethod
def get_context(data):
"""Return asset, task from publishing context data"""
return data["folderPath"], data["task"]

View file

@ -1,71 +0,0 @@
import pyblish.api
import ayon_core.hosts.maya.api.action
from ayon_core.pipeline.publish import (
PublishValidationError,
ValidateContentsOrder,
OptionalPyblishPluginMixin
)
from maya import cmds
class ValidateAnimatedReferenceRig(pyblish.api.InstancePlugin,
OptionalPyblishPluginMixin):
"""Validate all nodes in skeletonAnim_SET are referenced"""
order = ValidateContentsOrder
hosts = ["maya"]
families = ["animation.fbx"]
label = "Animated Reference Rig"
accepted_controllers = ["transform", "locator"]
actions = [ayon_core.hosts.maya.api.action.SelectInvalidAction]
optional = False
def process(self, instance):
if not self.is_active(instance.data):
return
animated_sets = instance.data.get("animated_skeleton", [])
if not animated_sets:
self.log.debug(
"No nodes found in skeletonAnim_SET. "
"Skipping validation of animated reference rig..."
)
return
for animated_reference in animated_sets:
is_referenced = cmds.referenceQuery(
animated_reference, isNodeReferenced=True)
if not bool(is_referenced):
raise PublishValidationError(
"All the content in skeletonAnim_SET"
" should be referenced nodes"
)
invalid_controls = self.validate_controls(animated_sets)
if invalid_controls:
raise PublishValidationError(
"All the content in skeletonAnim_SET"
" should be transforms"
)
@classmethod
def validate_controls(self, set_members):
"""Check if the controller set contains only accepted node types.
Checks if all its set members are within the hierarchy of the root
Checks if the node types of the set members valid
Args:
set_members: list of nodes of the skeleton_anim_set
hierarchy: list of nodes which reside under the root node
Returns:
errors (list)
"""
# Validate control types
invalid = []
set_members = cmds.ls(set_members, long=True)
for node in set_members:
if cmds.nodeType(node) not in self.accepted_controllers:
invalid.append(node)
return invalid

View file

@ -835,7 +835,7 @@ class ExporterReviewMov(ExporterReview):
self.log.info("Nodes exported...")
return path
def generate_mov(self, farm=False, **kwargs):
def generate_mov(self, farm=False, delete=True, **kwargs):
# colorspace data
colorspace = None
# get colorspace settings
@ -990,8 +990,13 @@ class ExporterReviewMov(ExporterReview):
self.render(write_node.name())
# ---------- generate representation data
tags = ["review", "need_thumbnail"]
if delete:
tags.append("delete")
self.get_representation_data(
tags=["review", "need_thumbnail", "delete"] + add_tags,
tags=tags + add_tags,
custom_tags=add_custom_tags,
range=True,
colorspace=colorspace

View file

@ -136,11 +136,16 @@ class ExtractReviewIntermediates(publish.Extractor):
self, instance, o_name, o_data["extension"],
multiple_presets)
o_data["add_custom_tags"].append("intermediate")
delete = not o_data.get("publish", False)
if instance.data.get("farm"):
if "review" in instance.data["families"]:
instance.data["families"].remove("review")
data = exporter.generate_mov(farm=True, **o_data)
data = exporter.generate_mov(
farm=True, delete=delete, **o_data
)
self.log.debug(
"_ data: {}".format(data))
@ -154,7 +159,7 @@ class ExtractReviewIntermediates(publish.Extractor):
"bakeWriteNodeName": data.get("bakeWriteNodeName")
})
else:
data = exporter.generate_mov(**o_data)
data = exporter.generate_mov(delete=delete, **o_data)
# add representation generated by exporter
generated_repres.extend(data["representations"])

View file

@ -1,3 +1,3 @@
name = "maya"
title = "Maya"
version = "0.1.18"
version = "0.1.19"

View file

@ -917,10 +917,6 @@ class PublishersModel(BaseSettingsModel):
default_factory=BasicValidateModel,
title="Validate Rig Controllers",
)
ValidateAnimatedReferenceRig: BasicValidateModel = SettingsField(
default_factory=BasicValidateModel,
title="Validate Animated Reference Rig",
)
ValidateAnimationContent: BasicValidateModel = SettingsField(
default_factory=BasicValidateModel,
title="Validate Animation Content",
@ -1447,11 +1443,6 @@ DEFAULT_PUBLISH_SETTINGS = {
"optional": True,
"active": True
},
"ValidateAnimatedReferenceRig": {
"enabled": True,
"optional": False,
"active": True
},
"ValidateAnimationContent": {
"enabled": True,
"optional": False,

View file

@ -1,3 +1,3 @@
name = "nuke"
title = "Nuke"
version = "0.1.11"
version = "0.1.12"

View file

@ -125,6 +125,7 @@ class ReformatNodesConfigModel(BaseSettingsModel):
class IntermediateOutputModel(BaseSettingsModel):
name: str = SettingsField(title="Output name")
publish: bool = SettingsField(title="Publish")
filter: BakingStreamFilterModel = SettingsField(
title="Filter", default_factory=BakingStreamFilterModel)
read_raw: bool = SettingsField(
@ -346,6 +347,7 @@ DEFAULT_PUBLISH_PLUGIN_SETTINGS = {
"outputs": [
{
"name": "baking",
"publish": False,
"filter": {
"task_types": [],
"product_types": [],
@ -401,6 +403,7 @@ DEFAULT_PUBLISH_PLUGIN_SETTINGS = {
"outputs": [
{
"name": "baking",
"publish": False,
"filter": {
"task_types": [],
"product_types": [],