mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
Merge branch 'develop' into bugfix/maya_camera_publish_image_plane
This commit is contained in:
commit
71c63b6e81
5 changed files with 152 additions and 52 deletions
|
|
@ -167,7 +167,7 @@ class JsonLayoutLoader(plugin.AssetLoader):
|
|||
asset_group.empty_display_type = 'SINGLE_ARROW'
|
||||
avalon_container.objects.link(asset_group)
|
||||
|
||||
self._process(libpath, asset, asset_group, None)
|
||||
self._process(libpath, asset_name, asset_group, None)
|
||||
|
||||
bpy.context.scene.collection.objects.link(asset_group)
|
||||
|
||||
|
|
|
|||
|
|
@ -92,10 +92,6 @@ class PrecollectInstances(pyblish.api.ContextPlugin):
|
|||
|
||||
folder_path, folder_name = self._get_folder_data(tag_data)
|
||||
|
||||
product_name = tag_data.get("productName")
|
||||
if product_name is None:
|
||||
product_name = tag_data["subset"]
|
||||
|
||||
families = [str(f) for f in tag_data["families"]]
|
||||
|
||||
# TODO: remove backward compatibility
|
||||
|
|
@ -293,7 +289,7 @@ class PrecollectInstances(pyblish.api.ContextPlugin):
|
|||
label += " {}".format(product_name)
|
||||
|
||||
data.update({
|
||||
"name": "{}_{}".format(folder_path, subset),
|
||||
"name": "{}_{}".format(folder_path, product_name),
|
||||
"label": label,
|
||||
"productName": product_name,
|
||||
"productType": product_type,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,21 @@
|
|||
from collections import deque
|
||||
|
||||
import pyblish.api
|
||||
|
||||
from ayon_core.pipeline import registered_host
|
||||
|
||||
|
||||
def collect_input_containers(nodes):
|
||||
def get_container_members(container):
|
||||
node = container["node"]
|
||||
# Usually the loaded containers don't have any complex references
|
||||
# and the contained children should be all we need. So we disregard
|
||||
# checking for .references() on the nodes.
|
||||
members = set(node.allSubChildren())
|
||||
members.add(node) # include the node itself
|
||||
return members
|
||||
|
||||
|
||||
def collect_input_containers(containers, nodes):
|
||||
"""Collect containers that contain any of the node in `nodes`.
|
||||
|
||||
This will return any loaded Avalon container that contains at least one of
|
||||
|
|
@ -11,30 +23,13 @@ def collect_input_containers(nodes):
|
|||
there are member nodes of that container.
|
||||
|
||||
Returns:
|
||||
list: Input avalon containers
|
||||
list: Loaded containers that contain the `nodes`
|
||||
|
||||
"""
|
||||
|
||||
# Lookup by node ids
|
||||
lookup = frozenset(nodes)
|
||||
|
||||
containers = []
|
||||
host = registered_host()
|
||||
for container in host.ls():
|
||||
|
||||
node = container["node"]
|
||||
|
||||
# Usually the loaded containers don't have any complex references
|
||||
# and the contained children should be all we need. So we disregard
|
||||
# checking for .references() on the nodes.
|
||||
members = set(node.allSubChildren())
|
||||
members.add(node) # include the node itself
|
||||
|
||||
# If there's an intersection
|
||||
if not lookup.isdisjoint(members):
|
||||
containers.append(container)
|
||||
|
||||
return containers
|
||||
# Assume the containers have collected their cached '_members' data
|
||||
# in the collector.
|
||||
return [container for container in containers
|
||||
if any(node in container["_members"] for node in nodes)]
|
||||
|
||||
|
||||
def iter_upstream(node):
|
||||
|
|
@ -54,7 +49,7 @@ def iter_upstream(node):
|
|||
)
|
||||
|
||||
# Initialize process queue with the node's ancestors itself
|
||||
queue = list(upstream)
|
||||
queue = deque(upstream)
|
||||
collected = set(upstream)
|
||||
|
||||
# Traverse upstream references for all nodes and yield them as we
|
||||
|
|
@ -72,6 +67,10 @@ def iter_upstream(node):
|
|||
|
||||
# Include the references' ancestors that have not been collected yet.
|
||||
for reference in references:
|
||||
if reference in collected:
|
||||
# Might have been collected in previous iteration
|
||||
continue
|
||||
|
||||
ancestors = reference.inputAncestors(
|
||||
include_ref_inputs=True, follow_subnets=True
|
||||
)
|
||||
|
|
@ -108,13 +107,32 @@ class CollectUpstreamInputs(pyblish.api.InstancePlugin):
|
|||
)
|
||||
return
|
||||
|
||||
# Collect all upstream parents
|
||||
nodes = list(iter_upstream(output))
|
||||
nodes.append(output)
|
||||
# For large scenes the querying of "host.ls()" can be relatively slow
|
||||
# e.g. up to a second. Many instances calling it easily slows this
|
||||
# down. As such, we cache it so we trigger it only once.
|
||||
# todo: Instead of hidden cache make "CollectContainers" plug-in
|
||||
cache_key = "__cache_containers"
|
||||
scene_containers = instance.context.data.get(cache_key, None)
|
||||
if scene_containers is None:
|
||||
# Query the scenes' containers if there's no cache yet
|
||||
host = registered_host()
|
||||
scene_containers = list(host.ls())
|
||||
for container in scene_containers:
|
||||
# Embed the members into the container dictionary
|
||||
container_members = set(get_container_members(container))
|
||||
container["_members"] = container_members
|
||||
instance.context.data[cache_key] = scene_containers
|
||||
|
||||
# Collect containers for the given set of nodes
|
||||
containers = collect_input_containers(nodes)
|
||||
inputs = []
|
||||
if scene_containers:
|
||||
# Collect all upstream parents
|
||||
nodes = list(iter_upstream(output))
|
||||
nodes.append(output)
|
||||
|
||||
# Collect containers for the given set of nodes
|
||||
containers = collect_input_containers(scene_containers, nodes)
|
||||
|
||||
inputs = [c["representation"] for c in containers]
|
||||
|
||||
inputs = [c["representation"] for c in containers]
|
||||
instance.data["inputRepresentations"] = inputs
|
||||
self.log.debug("Collected inputs: %s" % inputs)
|
||||
|
|
|
|||
|
|
@ -1917,6 +1917,29 @@ def apply_attributes(attributes, nodes_by_id):
|
|||
set_attribute(attr, value, node)
|
||||
|
||||
|
||||
def is_valid_reference_node(reference_node):
|
||||
"""Return whether Maya considers the reference node a valid reference.
|
||||
|
||||
Maya might report an error when using `maya.cmds.referenceQuery`:
|
||||
Reference node 'reference_node' is not associated with a reference file.
|
||||
|
||||
Note that this does *not* check whether the reference node points to an
|
||||
existing file. Instead it only returns whether maya considers it valid
|
||||
and thus is not an unassociated reference node
|
||||
|
||||
Arguments:
|
||||
reference_node (str): Reference node name
|
||||
|
||||
Returns:
|
||||
bool: Whether reference node is a valid reference
|
||||
|
||||
"""
|
||||
sel = OpenMaya.MSelectionList()
|
||||
sel.add(reference_node)
|
||||
depend_node = sel.getDependNode(0)
|
||||
return OpenMaya.MFnReference(depend_node).isValidReference()
|
||||
|
||||
|
||||
def get_container_members(container):
|
||||
"""Returns the members of a container.
|
||||
This includes the nodes from any loaded references in the container.
|
||||
|
|
@ -1942,7 +1965,16 @@ def get_container_members(container):
|
|||
if ref.rsplit(":", 1)[-1].startswith("_UNKNOWN_REF_NODE_"):
|
||||
continue
|
||||
|
||||
reference_members = cmds.referenceQuery(ref, nodes=True, dagPath=True)
|
||||
try:
|
||||
reference_members = cmds.referenceQuery(ref,
|
||||
nodes=True,
|
||||
dagPath=True)
|
||||
except RuntimeError:
|
||||
# Ignore reference nodes that are not associated with a
|
||||
# referenced file on which `referenceQuery` command fails
|
||||
if not is_valid_reference_node(ref):
|
||||
continue
|
||||
raise
|
||||
reference_members = cmds.ls(reference_members,
|
||||
long=True,
|
||||
objectsOnly=True)
|
||||
|
|
@ -4238,6 +4270,9 @@ def get_reference_node(members, log=None):
|
|||
if ref.rsplit(":", 1)[-1].startswith("_UNKNOWN_REF_NODE_"):
|
||||
continue
|
||||
|
||||
if not is_valid_reference_node(ref):
|
||||
continue
|
||||
|
||||
references.add(ref)
|
||||
|
||||
assert references, "No reference node found in container"
|
||||
|
|
@ -4268,15 +4303,19 @@ def get_reference_node_parents(ref):
|
|||
list: The upstream parent reference nodes.
|
||||
|
||||
"""
|
||||
parent = cmds.referenceQuery(ref,
|
||||
referenceNode=True,
|
||||
parent=True)
|
||||
def _get_parent(reference_node):
|
||||
"""Return parent reference node, but ignore invalid reference nodes"""
|
||||
if not is_valid_reference_node(reference_node):
|
||||
return
|
||||
return cmds.referenceQuery(reference_node,
|
||||
referenceNode=True,
|
||||
parent=True)
|
||||
|
||||
parent = _get_parent(ref)
|
||||
parents = []
|
||||
while parent:
|
||||
parents.append(parent)
|
||||
parent = cmds.referenceQuery(parent,
|
||||
referenceNode=True,
|
||||
parent=True)
|
||||
parent = _get_parent(parent)
|
||||
return parents
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -284,7 +284,13 @@ class ProductsModel(QtGui.QStandardItemModel):
|
|||
model_item.setData(label, QtCore.Qt.DisplayRole)
|
||||
return model_item
|
||||
|
||||
def _set_version_data_to_product_item(self, model_item, version_item):
|
||||
def _set_version_data_to_product_item(
|
||||
self,
|
||||
model_item,
|
||||
version_item,
|
||||
repre_count_by_version_id=None,
|
||||
sync_availability_by_version_id=None,
|
||||
):
|
||||
"""
|
||||
|
||||
Args:
|
||||
|
|
@ -292,6 +298,10 @@ class ProductsModel(QtGui.QStandardItemModel):
|
|||
from version item.
|
||||
version_item (VersionItem): Item from entities model with
|
||||
information about version.
|
||||
repre_count_by_version_id (Optional[str, int]): Mapping of
|
||||
representation count by version id.
|
||||
sync_availability_by_version_id (Optional[str, Tuple[int, int]]):
|
||||
Mapping of sync availability by version id.
|
||||
"""
|
||||
|
||||
model_item.setData(version_item.version_id, VERSION_ID_ROLE)
|
||||
|
|
@ -312,12 +322,20 @@ class ProductsModel(QtGui.QStandardItemModel):
|
|||
# TODO call site sync methods for all versions at once
|
||||
project_name = self._last_project_name
|
||||
version_id = version_item.version_id
|
||||
repre_count = self._controller.get_versions_representation_count(
|
||||
project_name, [version_id]
|
||||
)[version_id]
|
||||
active, remote = self._controller.get_version_sync_availability(
|
||||
project_name, [version_id]
|
||||
)[version_id]
|
||||
if repre_count_by_version_id is None:
|
||||
repre_count_by_version_id = (
|
||||
self._controller.get_versions_representation_count(
|
||||
project_name, [version_id]
|
||||
)
|
||||
)
|
||||
if sync_availability_by_version_id is None:
|
||||
sync_availability_by_version_id = (
|
||||
self._controller.get_version_sync_availability(
|
||||
project_name, [version_id]
|
||||
)
|
||||
)
|
||||
repre_count = repre_count_by_version_id[version_id]
|
||||
active, remote = sync_availability_by_version_id[version_id]
|
||||
|
||||
model_item.setData(repre_count, REPRESENTATIONS_COUNT_ROLE)
|
||||
model_item.setData(active, SYNC_ACTIVE_SITE_AVAILABILITY)
|
||||
|
|
@ -327,7 +345,9 @@ class ProductsModel(QtGui.QStandardItemModel):
|
|||
self,
|
||||
product_item,
|
||||
active_site_icon,
|
||||
remote_site_icon
|
||||
remote_site_icon,
|
||||
repre_count_by_version_id,
|
||||
sync_availability_by_version_id,
|
||||
):
|
||||
model_item = self._items_by_id.get(product_item.product_id)
|
||||
versions = list(product_item.version_items.values())
|
||||
|
|
@ -357,7 +377,12 @@ class ProductsModel(QtGui.QStandardItemModel):
|
|||
model_item.setData(active_site_icon, ACTIVE_SITE_ICON_ROLE)
|
||||
model_item.setData(remote_site_icon, REMOTE_SITE_ICON_ROLE)
|
||||
|
||||
self._set_version_data_to_product_item(model_item, last_version)
|
||||
self._set_version_data_to_product_item(
|
||||
model_item,
|
||||
last_version,
|
||||
repre_count_by_version_id,
|
||||
sync_availability_by_version_id,
|
||||
)
|
||||
return model_item
|
||||
|
||||
def get_last_project_name(self):
|
||||
|
|
@ -387,6 +412,24 @@ class ProductsModel(QtGui.QStandardItemModel):
|
|||
product_item.product_id: product_item
|
||||
for product_item in product_items
|
||||
}
|
||||
last_version_id_by_product_id = {}
|
||||
for product_item in product_items:
|
||||
versions = list(product_item.version_items.values())
|
||||
versions.sort()
|
||||
last_version = versions[-1]
|
||||
last_version_id_by_product_id[product_item.product_id] = (
|
||||
last_version.version_id
|
||||
)
|
||||
|
||||
version_ids = set(last_version_id_by_product_id.values())
|
||||
repre_count_by_version_id = self._controller.get_versions_representation_count(
|
||||
project_name, version_ids
|
||||
)
|
||||
sync_availability_by_version_id = (
|
||||
self._controller.get_version_sync_availability(
|
||||
project_name, version_ids
|
||||
)
|
||||
)
|
||||
|
||||
# Prepare product groups
|
||||
product_name_matches_by_group = collections.defaultdict(dict)
|
||||
|
|
@ -443,6 +486,8 @@ class ProductsModel(QtGui.QStandardItemModel):
|
|||
product_item,
|
||||
active_site_icon,
|
||||
remote_site_icon,
|
||||
repre_count_by_version_id,
|
||||
sync_availability_by_version_id,
|
||||
)
|
||||
new_items.append(item)
|
||||
|
||||
|
|
@ -463,6 +508,8 @@ class ProductsModel(QtGui.QStandardItemModel):
|
|||
product_item,
|
||||
active_site_icon,
|
||||
remote_site_icon,
|
||||
repre_count_by_version_id,
|
||||
sync_availability_by_version_id,
|
||||
)
|
||||
new_merged_items.append(item)
|
||||
merged_product_types.add(product_item.product_type)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue