Store instances in single project metadata key by id + fix adding/removing instances

This commit is contained in:
Roy Nieterau 2023-03-23 18:09:13 +01:00
parent d4a0c6634c
commit 22d628d054
3 changed files with 93 additions and 40 deletions

View file

@ -39,6 +39,7 @@ INVENTORY_PATH = os.path.join(PLUGINS_DIR, "inventory")
OPENPYPE_METADATA_KEY = "OpenPype"
OPENPYPE_METADATA_CONTAINERS_KEY = "containers" # child key
OPENPYPE_METADATA_CONTEXT_KEY = "context" # child key
OPENPYPE_METADATA_INSTANCES_KEY = "instances" # child key
class SubstanceHost(HostBase, IWorkfileHost, ILoadHost, IPublishHost):
@ -312,21 +313,6 @@ def imprint_container(container,
container[key] = value
def set_project_metadata(key, data):
"""Set a key in project's OpenPype metadata."""
metadata = substance_painter.project.Metadata(OPENPYPE_METADATA_KEY)
metadata.set(key, data)
def get_project_metadata(key):
"""Get a key from project's OpenPype metadata."""
if not substance_painter.project.is_open():
return
metadata = substance_painter.project.Metadata(OPENPYPE_METADATA_KEY)
return metadata.get(key)
def set_container_metadata(object_name, container_data, update=False):
"""Helper method to directly set the data for a specific container
@ -359,3 +345,54 @@ def remove_container_metadata(object_name):
if containers:
containers.pop(object_name, None)
metadata.set("containers", containers)
def set_instance(instance_id, instance_data, update=False):
"""Helper method to directly set the data for a specific container
Args:
instance_id (str): Unique identifier for the instance
instance_data (dict): The instance data to store in the metaadata.
"""
set_instances({instance_id: instance_data}, update=update)
def set_instances(instance_data_by_id, update=False):
"""Store data for multiple instances at the same time.
This is more optimal than querying and setting them in the metadata one
by one.
"""
metadata = substance_painter.project.Metadata(OPENPYPE_METADATA_KEY)
instances = metadata.get(OPENPYPE_METADATA_INSTANCES_KEY) or {}
for instance_id, instance_data in instance_data_by_id.items():
if update:
existing_data = instances.get(instance_id, {})
existing_data.update(instance_data)
else:
instances[instance_id] = instance_data
metadata.set("instances", instances)
def remove_instance(instance_id):
"""Helper method to remove the data for a specific container"""
metadata = substance_painter.project.Metadata(OPENPYPE_METADATA_KEY)
instances = metadata.get(OPENPYPE_METADATA_INSTANCES_KEY) or {}
instances.pop(instance_id, None)
metadata.set("instances", instances)
def get_instances_by_id():
"""Return all instances stored in the project instances metadata"""
if not substance_painter.project.is_open():
return {}
metadata = substance_painter.project.Metadata(OPENPYPE_METADATA_KEY)
return metadata.get(OPENPYPE_METADATA_INSTANCES_KEY) or {}
def get_instances():
"""Return all instances stored in the project instances as a list"""
return list(get_instances_by_id().values())

View file

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
"""Creator plugin for creating textures."""
from openpype.pipeline import CreatedInstance, Creator
from openpype.pipeline import CreatedInstance, Creator, CreatorError
from openpype.lib import (
EnumDef,
UILabelDef,
@ -9,8 +9,10 @@ from openpype.lib import (
)
from openpype.hosts.substancepainter.api.pipeline import (
set_project_metadata,
get_project_metadata
get_instances,
set_instance,
set_instances,
remove_instance
)
from openpype.hosts.substancepainter.api.lib import get_export_presets
@ -29,27 +31,34 @@ class CreateTextures(Creator):
def create(self, subset_name, instance_data, pre_create_data):
if not substance_painter.project.is_open():
return
raise CreatorError("Can't create a Texture Set instance without "
"an open project.")
instance = self.create_instance_in_context(subset_name, instance_data)
set_project_metadata("textureSet", instance.data_to_store())
instance = self.create_instance_in_context(subset_name,
instance_data)
set_instance(
instance_id=instance["instance_id"],
instance_data=instance.data_to_store()
)
def collect_instances(self):
workfile = get_project_metadata("textureSet")
if workfile:
self.create_instance_in_context_from_existing(workfile)
for instance in get_instances():
if (instance.get("creator_identifier") == self.identifier or
instance.get("family") == self.family):
self.create_instance_in_context_from_existing(instance)
def update_instances(self, update_list):
instance_data_by_id = {}
for instance, _changes in update_list:
# Update project's metadata
data = get_project_metadata("textureSet") or {}
data.update(instance.data_to_store())
set_project_metadata("textureSet", data)
# Persist the data
instance_id = instance.get("instance_id")
instance_data = instance.data_to_store()
instance_data_by_id[instance_id] = instance_data
set_instances(instance_data_by_id, update=True)
def remove_instances(self, instances):
for instance in instances:
# TODO: Implement removal
# api.remove_instance(instance)
remove_instance(instance["instance_id"])
self._remove_instance_from_context(instance)
# Helper methods (this might get moved into Creator class)

View file

@ -5,8 +5,9 @@ from openpype.pipeline import CreatedInstance, AutoCreator
from openpype.client import get_asset_by_name
from openpype.hosts.substancepainter.api.pipeline import (
set_project_metadata,
get_project_metadata
set_instances,
set_instance,
get_instances
)
import substance_painter.project
@ -66,19 +67,25 @@ class CreateWorkfile(AutoCreator):
current_instance["task"] = task_name
current_instance["subset"] = subset_name
set_project_metadata("workfile", current_instance.data_to_store())
set_instance(
instance_id=current_instance.get("instance_id"),
instance_data=current_instance.data_to_store()
)
def collect_instances(self):
workfile = get_project_metadata("workfile")
if workfile:
self.create_instance_in_context_from_existing(workfile)
for instance in get_instances():
if (instance.get("creator_identifier") == self.identifier or
instance.get("family") == self.family):
self.create_instance_in_context_from_existing(instance)
def update_instances(self, update_list):
instance_data_by_id = {}
for instance, _changes in update_list:
# Update project's workfile metadata
data = get_project_metadata("workfile") or {}
data.update(instance.data_to_store())
set_project_metadata("workfile", data)
# Persist the data
instance_id = instance.get("instance_id")
instance_data = instance.data_to_store()
instance_data_by_id[instance_id] = instance_data
set_instances(instance_data_by_id, update=True)
# Helper methods (this might get moved into Creator class)
def create_instance_in_context(self, subset_name, data):