mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-26 05:42:15 +01:00
improved check to validate if IDs are related to original use shape
This commit is contained in:
parent
3430b6660b
commit
dee1d504bf
1 changed files with 86 additions and 43 deletions
|
|
@ -3,11 +3,10 @@ import maya.cmds as cmds
|
|||
import pyblish.api
|
||||
import colorbleed.api
|
||||
import colorbleed.maya.lib as lib
|
||||
import avalon.io as io
|
||||
|
||||
|
||||
class ValidateAnimationOutSetRelatedNodeIds(pyblish.api.InstancePlugin):
|
||||
"""Validate rig out_SET nodes have related ids to current context
|
||||
"""Validate if nodes have related IDs to the source (original shapes)
|
||||
|
||||
An ID is 'related' if its built in the current Item.
|
||||
|
||||
|
|
@ -18,10 +17,10 @@ class ValidateAnimationOutSetRelatedNodeIds(pyblish.api.InstancePlugin):
|
|||
"""
|
||||
|
||||
order = colorbleed.api.ValidateContentsOrder
|
||||
families = ['colorbleed.animation']
|
||||
families = ['colorbleed.animation', "colorbleed.pointcache"]
|
||||
hosts = ['maya']
|
||||
label = 'Animation Out Set Related Node Ids'
|
||||
actions = [colorbleed.api.SelectInvalidAction]
|
||||
actions = [colorbleed.api.SelectInvalidAction, colorbleed.api.RepairAction]
|
||||
optional = True
|
||||
|
||||
ignore_types = ("constraint",)
|
||||
|
|
@ -29,61 +28,105 @@ class ValidateAnimationOutSetRelatedNodeIds(pyblish.api.InstancePlugin):
|
|||
def process(self, instance):
|
||||
"""Process all meshes"""
|
||||
|
||||
# Ensure all nodes have a cbId
|
||||
# Ensure all nodes have a cbId and a related ID to the original shapes
|
||||
# if a deformer has been created on the shape
|
||||
invalid = self.get_invalid(instance)
|
||||
if invalid:
|
||||
raise RuntimeError("Nodes found with non-related "
|
||||
"asset IDs: {0}".format(invalid))
|
||||
|
||||
@classmethod
|
||||
def get_pointcache_nodes(cls, instance):
|
||||
|
||||
# Get out_SET
|
||||
sets = cmds.ls(instance, type='objectSet')
|
||||
pointcache_sets = [x for x in sets if x == 'out_SET']
|
||||
|
||||
nodes = list()
|
||||
for s in pointcache_sets:
|
||||
# Ensure long names
|
||||
members = cmds.ls(cmds.sets(s, query=True), long=True)
|
||||
descendants = cmds.listRelatives(members,
|
||||
allDescendents=True,
|
||||
fullPath=True) or []
|
||||
descendants = cmds.ls(descendants,
|
||||
noIntermediate=True,
|
||||
long=True)
|
||||
hierarchy = members + descendants
|
||||
nodes.extend(hierarchy)
|
||||
|
||||
# ignore certain node types (e.g. constraints)
|
||||
ignore = cmds.ls(nodes, type=cls.ignore_types, long=True)
|
||||
if ignore:
|
||||
ignore = set(ignore)
|
||||
nodes = [node for node in nodes if node not in ignore]
|
||||
|
||||
return nodes
|
||||
|
||||
@classmethod
|
||||
def get_invalid(cls, instance):
|
||||
invalid_items = []
|
||||
"""Get all nodes which do not match the criteria"""
|
||||
invalid = []
|
||||
|
||||
# get asset id
|
||||
nodes = cls.get_pointcache_nodes(instance)
|
||||
nodes = instance.data["pointcache_data"]
|
||||
for node in nodes:
|
||||
node_type = cmds.nodeType(node)
|
||||
node_id = lib.get_id(node)
|
||||
|
||||
if node_type == "mesh" and not node_id:
|
||||
invalid.append(node)
|
||||
continue
|
||||
|
||||
if not node_id:
|
||||
invalid_items.append(node)
|
||||
continue
|
||||
|
||||
# TODO: Should we check whether the ids are related to the rig's asset?
|
||||
root_id = cls.get_history_root_id(node=node)
|
||||
if root_id is not None:
|
||||
asset_id = cls.to_item(node_id)
|
||||
if root_id != asset_id:
|
||||
invalid.append(node)
|
||||
|
||||
# Log invalid item ids
|
||||
if invalid_items:
|
||||
for item_id in sorted(invalid_items):
|
||||
cls.log.warning("Found invalid item id: {0}".format(item_id))
|
||||
return invalid
|
||||
|
||||
return invalid_items
|
||||
@classmethod
|
||||
def get_history_root_id(cls, node):
|
||||
"""
|
||||
|
||||
Get the original node ID when a node has been deformed
|
||||
Args:
|
||||
node (str): node to retrieve the
|
||||
|
||||
Returns:
|
||||
str: the asset ID as found in the database
|
||||
"""
|
||||
|
||||
asset_id = None
|
||||
node = cmds.ls(node, long=True)[0]
|
||||
|
||||
# We only check when the node is *not* referenced
|
||||
if cmds.referenceQuery(node, isNodeReferenced=True):
|
||||
return
|
||||
|
||||
# Find all similar nodes in history
|
||||
history = cmds.listHistory(node)
|
||||
node_type = cmds.nodeType(node)
|
||||
similar_nodes = cmds.ls(history, exactType=node_type, long=True)
|
||||
|
||||
# Exclude itself
|
||||
similar_nodes = [x for x in similar_nodes if x != node]
|
||||
|
||||
# The node *must be* under the same parent
|
||||
parent = cls.get_parent(node)
|
||||
similar_nodes = [i for i in similar_nodes if
|
||||
cls.get_parent(i) == parent]
|
||||
|
||||
# Check all of the remaining similar nodes and take the first one
|
||||
# with an id and assume it's the original.
|
||||
for similar_node in similar_nodes:
|
||||
|
||||
_id = lib.get_id(similar_node)
|
||||
if not _id:
|
||||
continue
|
||||
|
||||
asset_id = cls.to_item(_id)
|
||||
break
|
||||
|
||||
return asset_id
|
||||
|
||||
@classmethod
|
||||
def repair(cls, instance):
|
||||
|
||||
for node in cls.get_invalid(instance):
|
||||
# Get node ID and the asset ID part
|
||||
node_id = lib.get_id(node)
|
||||
asset_id = cls.to_item(node_id)
|
||||
|
||||
# Get root asset ID
|
||||
root_id = cls.get_history_root_id(node=node)
|
||||
|
||||
# Replace errored ID with good ID
|
||||
new_id = node_id.replace(asset_id, root_id)
|
||||
|
||||
cmds.setAttr("%s.cbId" % node, new_id, type="string")
|
||||
|
||||
@staticmethod
|
||||
def to_item(_id):
|
||||
"""Split the item id part from a node id"""
|
||||
return _id.rsplit(":", 1)[0]
|
||||
return _id.split(":", 1)[0]
|
||||
|
||||
@staticmethod
|
||||
def get_parent(node):
|
||||
return cmds.listRelatives(node, parent=True, fullPath=True)
|
||||
Loading…
Add table
Add a link
Reference in a new issue