def remove_unused_looks(): """Removes all loaded looks for which none of the shaders are used. This will cleanup all loaded "LookLoader" containers that are unused in the current scene. """ host = api.registered_host() unused = list() for container in host.ls(): if container['loader'] == "LookLoader": members = cmds.sets(container['objectName'], query=True) look_sets = cmds.ls(members, type="objectSet") for look_set in look_sets: # If the set is used than we consider this look *in use* if cmds.sets(look_set, query=True): break else: unused.append(container) for container in unused: log.info("Removing unused look container: %s", container['objectName']) api.remove(container) log.info("Finished removing unused looks. (see log for details)")
def remove(self, container): """Remove all sub containers""" from avalon import api from colorbleed import setdress_api import maya.cmds as cmds # Remove all members member_containers = setdress_api.get_contained_containers(container) for member_container in member_containers: self.log.info("Removing container %s", member_container['objectName']) api.remove(member_container) # Remove alembic hierarchy reference # TODO: Check whether removing all contained references is safe enough members = cmds.sets(container['objectName'], query=True) or [] references = cmds.ls(members, type="reference") for reference in references: self.log.info("Removing %s", reference) fname = cmds.referenceQuery(reference, filename=True) cmds.file(fname, removeReference=True) # Delete container and its contents if cmds.objExists(container['objectName']): members = cmds.sets(container['objectName'], query=True) or [] cmds.delete([container['objectName']] + members)
def _remove(self, layout_container): layout_container_metadata = layout_container.get( blender.pipeline.AVALON_PROPERTY) if layout_container.children: for child in layout_container.children: child_container = child.get(blender.pipeline.AVALON_PROPERTY) child_container['objectName'] = child.name api.remove(child_container) for c in bpy.data.collections: metadata = c.get('avalon') if metadata: print("metadata.get('id')") print(metadata.get('id')) if metadata and metadata.get('id') == 'pyblish.avalon.instance': print("metadata.get('dependencies')") print(metadata.get('dependencies')) print("layout_container_metadata.get('representation')") print(layout_container_metadata.get('representation')) if metadata.get( 'dependencies') == layout_container_metadata.get( 'representation'): for child in c.children: bpy.data.collections.remove(child) bpy.data.collections.remove(c) break
def update_scene(set_container, containers, current_data, new_data, new_file): """Updates the hierarchy, assets and their matrix Updates the following withing the scene: * Setdress hierarchy alembic * Matrix * Parenting * Representations It removes any assets which are not present in the new build data Args: set_container (dict): the setdress container of the scene containers (list): the list of containers under the setdress container current_data (dict): the current build data of the setdress new_data (dict): the new build data of the setdres Returns: processed_containers (list): all new and updated containers """ from colorbleed.maya.lib import DEFAULT_MATRIX, get_container_transforms set_namespace = set_container['namespace'] # Update the setdress hierarchy alembic set_root = get_container_transforms(set_container, root=True) set_hierarchy_root = cmds.listRelatives(set_root, fullPath=True)[0] set_hierarchy_reference = cmds.referenceQuery(set_hierarchy_root, referenceNode=True) new_alembic = new_file.replace(".json", ".abc") assert os.path.exists(new_alembic), "%s does not exist." % new_alembic with unlocked(cmds.listRelatives(set_root, ad=True, fullPath=True)): cmds.file(new_alembic, loadReference=set_hierarchy_reference, type="Alembic") identity = DEFAULT_MATRIX[:] processed_namespaces = set() processed_containers = list() new_lookup = _instances_by_namespace(new_data) old_lookup = _instances_by_namespace(current_data) for container in containers: container_ns = container['namespace'] # Consider it processed here, even it it fails we want to store that # the namespace was already available. processed_namespaces.add(container_ns) processed_containers.append(container['objectName']) if container_ns in new_lookup: root = get_container_transforms(container, root=True) if not root: log.error("Can't find root for %s", container['objectName']) continue old_instance = old_lookup.get(container_ns, {}) new_instance = new_lookup[container_ns] # Update the matrix # check matrix against old_data matrix to find local overrides current_matrix = cmds.xform(root, query=True, matrix=True, objectSpace=True) original_matrix = old_instance.get("matrix", identity) has_matrix_override = not matrix_equals(current_matrix, original_matrix) if has_matrix_override: log.warning("Matrix override preserved on %s", container_ns) else: new_matrix = new_instance.get("matrix", identity) cmds.xform(root, matrix=new_matrix, objectSpace=True) # Update the parenting if old_instance.get("parent", None) != new_instance["parent"]: parent = to_namespace(new_instance['parent'], set_namespace) if not cmds.objExists(parent): log.error("Can't find parent %s", parent) continue # Set the new parent cmds.lockNode(root, lock=False) root = cmds.parent(root, parent, relative=True) cmds.lockNode(root, lock=True) # Update the representation representation_current = container['representation'] representation_old = old_instance['representation'] representation_new = new_instance['representation'] has_representation_override = (representation_current != representation_old) if representation_new != representation_current: if has_representation_override: log.warning( "Your scene had local representation " "overrides within the set. New " "representations not loaded for %s.", container_ns) continue # We check it against the current 'loader' in the scene instead # of the original data of the package that was loaded because # an Artist might have made scene local overrides if new_instance['loader'] != container['loader']: log.warning( "Loader is switched - local edits will be " "lost. Removing: %s", container_ns) # Remove this from the "has been processed" list so it's # considered as new element and added afterwards. processed_containers.pop() processed_namespaces.remove(container_ns) api.remove(container) continue # Check whether the conversion can be done by the Loader. # They *must* use the same asset, subset and Loader for # `api.update` to make sense. old = io.find_one({"_id": io.ObjectId(representation_current)}) new = io.find_one({"_id": io.ObjectId(representation_new)}) is_valid = compare_representations(old=old, new=new) if not is_valid: log.error("Skipping: %s. See log for details.", container_ns) continue new_version = new["context"]["version"] api.update(container, version=new_version) else: # Remove this container because it's not in the new data log.warning("Removing content: %s", container_ns) api.remove(container) # Add new assets all_loaders = api.discover(api.Loader) for representation_id, instances in new_data.items(): # Find the compatible loaders loaders = api.loaders_from_representation(all_loaders, representation_id) for instance in instances: # Already processed in update functionality if instance['namespace'] in processed_namespaces: continue container = _add(instance=instance, representation_id=representation_id, loaders=loaders, namespace=set_container['namespace'], root=set_root) # Add to the setdress container cmds.sets(container, addElement=set_container['objectName']) processed_containers.append(container) return processed_containers