mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-25 05:14:40 +01:00
Refactor metadata code to allow more structure for future Substance Painter plugins
This commit is contained in:
parent
c101f6a2cb
commit
ccb4371641
3 changed files with 91 additions and 48 deletions
|
|
@ -36,6 +36,10 @@ LOAD_PATH = os.path.join(PLUGINS_DIR, "load")
|
|||
CREATE_PATH = os.path.join(PLUGINS_DIR, "create")
|
||||
INVENTORY_PATH = os.path.join(PLUGINS_DIR, "inventory")
|
||||
|
||||
|
||||
OPENPYPE_METADATA_KEY = "OpenPype"
|
||||
OPENPYPE_METADATA_CONTAINERS_KEY = "containers" # child key
|
||||
|
||||
self = sys.modules[__name__]
|
||||
self.menu = None
|
||||
self.callbacks = []
|
||||
|
|
@ -127,8 +131,8 @@ class SubstanceHost(HostBase, IWorkfileHost, ILoadHost, IPublishHost):
|
|||
if not substance_painter.project.is_open():
|
||||
return
|
||||
|
||||
metadata = substance_painter.project.Metadata("OpenPype")
|
||||
containers = metadata.get("containers")
|
||||
metadata = substance_painter.project.Metadata(OPENPYPE_METADATA_KEY)
|
||||
containers = metadata.get(OPENPYPE_METADATA_CONTAINERS_KEY)
|
||||
if containers:
|
||||
for key, container in containers.items():
|
||||
container["objectName"] = key
|
||||
|
|
@ -275,3 +279,49 @@ def imprint_container(container,
|
|||
]
|
||||
for key, value in data:
|
||||
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."""
|
||||
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
|
||||
|
||||
Args:
|
||||
object_name (str): The unique object name identifier for the container
|
||||
container_data (dict): The data for the container.
|
||||
Note 'objectName' data is derived from `object_name` and key in
|
||||
`container_data` will be ignored.
|
||||
update (bool): Whether to only update the dict data.
|
||||
|
||||
"""
|
||||
# The objectName is derived from the key in the metadata so won't be stored
|
||||
# in the metadata in the container's data.
|
||||
container_data.pop("objectName", None)
|
||||
|
||||
metadata = substance_painter.project.Metadata(OPENPYPE_METADATA_KEY)
|
||||
containers = metadata.get(OPENPYPE_METADATA_CONTAINERS_KEY) or {}
|
||||
if update:
|
||||
existing_data = containers.setdefault(object_name, {})
|
||||
existing_data.update(container_data) # mutable dict, in-place update
|
||||
else:
|
||||
containers[object_name] = container_data
|
||||
metadata.set("containers", containers)
|
||||
|
||||
|
||||
def remove_container_metadata(object_name):
|
||||
"""Helper method to remove the data for a specific container"""
|
||||
metadata = substance_painter.project.Metadata(OPENPYPE_METADATA_KEY)
|
||||
containers = metadata.get(OPENPYPE_METADATA_CONTAINERS_KEY)
|
||||
if containers:
|
||||
containers.pop(object_name, None)
|
||||
metadata.set("containers", containers)
|
||||
|
|
|
|||
|
|
@ -5,20 +5,10 @@ from openpype.pipeline import CreatedInstance, AutoCreator
|
|||
from openpype.pipeline import legacy_io
|
||||
from openpype.client import get_asset_by_name
|
||||
|
||||
import substance_painter.project
|
||||
|
||||
|
||||
def set_workfile_data(data, update=False):
|
||||
if update:
|
||||
data = get_workfile_data().update(data)
|
||||
metadata = substance_painter.project.Metadata("OpenPype")
|
||||
metadata.set("workfile", data)
|
||||
|
||||
|
||||
def get_workfile_data():
|
||||
metadata = substance_painter.project.Metadata("OpenPype")
|
||||
return metadata.get("workfile") or {}
|
||||
|
||||
from openpype.hosts.substancepainter.api.pipeline import (
|
||||
set_project_metadata,
|
||||
get_project_metadata
|
||||
)
|
||||
|
||||
class CreateWorkfile(AutoCreator):
|
||||
"""Workfile auto-creator."""
|
||||
|
|
@ -71,17 +61,20 @@ class CreateWorkfile(AutoCreator):
|
|||
current_instance["task"] = task_name
|
||||
current_instance["subset"] = subset_name
|
||||
|
||||
set_workfile_data(current_instance.data_to_store())
|
||||
set_project_metadata("workfile", current_instance.data_to_store())
|
||||
|
||||
def collect_instances(self):
|
||||
workfile = get_workfile_data()
|
||||
workfile = get_project_metadata("workfile")
|
||||
if not workfile:
|
||||
return
|
||||
self.create_instance_in_context_from_existing(workfile)
|
||||
|
||||
def update_instances(self, update_list):
|
||||
for instance, _changes in update_list:
|
||||
set_workfile_data(instance.data_to_store(), update=True)
|
||||
# Update project's workfile metadata
|
||||
data = get_project_metadata("workfile") or {}
|
||||
data.update(instance.data_to_store())
|
||||
set_project_metadata("workfile", data)
|
||||
|
||||
# Helper methods (this might get moved into Creator class)
|
||||
def create_instance_in_context(self, subset_name, data):
|
||||
|
|
|
|||
|
|
@ -2,27 +2,16 @@ from openpype.pipeline import (
|
|||
load,
|
||||
get_representation_path,
|
||||
)
|
||||
from openpype.hosts.substancepainter.api.pipeline import imprint_container
|
||||
from openpype.hosts.substancepainter.api.pipeline import (
|
||||
imprint_container,
|
||||
set_container_metadata,
|
||||
remove_container_metadata
|
||||
)
|
||||
|
||||
import substance_painter.project
|
||||
import qargparse
|
||||
|
||||
|
||||
def set_container(key, container):
|
||||
metadata = substance_painter.project.Metadata("OpenPype")
|
||||
containers = metadata.get("containers") or {}
|
||||
containers[key] = container
|
||||
metadata.set("containers", containers)
|
||||
|
||||
|
||||
def remove_container(key):
|
||||
metadata = substance_painter.project.Metadata("OpenPype")
|
||||
containers = metadata.get("containers")
|
||||
if containers:
|
||||
containers.pop(key, None)
|
||||
metadata.set("containers", containers)
|
||||
|
||||
|
||||
class SubstanceLoadProjectMesh(load.LoaderPlugin):
|
||||
"""Load mesh for project"""
|
||||
|
||||
|
|
@ -48,10 +37,12 @@ class SubstanceLoadProjectMesh(load.LoaderPlugin):
|
|||
)
|
||||
]
|
||||
|
||||
container_key = "ProjectMesh"
|
||||
|
||||
def load(self, context, name, namespace, data):
|
||||
|
||||
# Get user inputs
|
||||
import_cameras = data.get("import_cameras", True)
|
||||
preserve_strokes = data.get("preserve_strokes", True)
|
||||
|
||||
if not substance_painter.project.is_open():
|
||||
# Allow to 'initialize' a new project
|
||||
# TODO: preferably these settings would come from the actual
|
||||
|
|
@ -59,7 +50,7 @@ class SubstanceLoadProjectMesh(load.LoaderPlugin):
|
|||
# visually similar to still allow artist decisions)
|
||||
settings = substance_painter.project.Settings(
|
||||
default_texture_resolution=4096,
|
||||
import_cameras=data.get("import_cameras", True),
|
||||
import_cameras=import_cameras,
|
||||
)
|
||||
|
||||
substance_painter.project.create(
|
||||
|
|
@ -70,8 +61,8 @@ class SubstanceLoadProjectMesh(load.LoaderPlugin):
|
|||
else:
|
||||
# Reload the mesh
|
||||
settings = substance_painter.project.MeshReloadingSettings(
|
||||
import_cameras=data.get("import_cameras", True),
|
||||
preserve_strokes=data.get("preserve_strokes", True)
|
||||
import_cameras=import_cameras,
|
||||
preserve_strokes=preserve_strokes
|
||||
)
|
||||
|
||||
def on_mesh_reload(status: substance_painter.project.ReloadMeshStatus): # noqa
|
||||
|
|
@ -87,13 +78,21 @@ class SubstanceLoadProjectMesh(load.LoaderPlugin):
|
|||
|
||||
# Store container
|
||||
container = {}
|
||||
project_mesh_object_name = "_ProjectMesh_"
|
||||
imprint_container(container,
|
||||
name=self.container_key,
|
||||
namespace=self.container_key,
|
||||
name=project_mesh_object_name,
|
||||
namespace=project_mesh_object_name,
|
||||
context=context,
|
||||
loader=self)
|
||||
container["options"] = data
|
||||
set_container(self.container_key, container)
|
||||
|
||||
# We want store some options for updating to keep consistent behavior
|
||||
# from the user's original choice. We don't store 'preserve_strokes'
|
||||
# as we always preserve strokes on updates.
|
||||
container["options"] = {
|
||||
"import_cameras": import_cameras,
|
||||
}
|
||||
|
||||
set_container_metadata(project_mesh_object_name, container)
|
||||
|
||||
def switch(self, container, representation):
|
||||
self.update(container, representation)
|
||||
|
|
@ -107,7 +106,7 @@ class SubstanceLoadProjectMesh(load.LoaderPlugin):
|
|||
container_options = container.get("options", {})
|
||||
settings = substance_painter.project.MeshReloadingSettings(
|
||||
import_cameras=container_options.get("import_cameras", True),
|
||||
preserve_strokes=container_options.get("preserve_strokes", True)
|
||||
preserve_strokes=True
|
||||
)
|
||||
|
||||
def on_mesh_reload(status: substance_painter.project.ReloadMeshStatus):
|
||||
|
|
@ -119,8 +118,9 @@ class SubstanceLoadProjectMesh(load.LoaderPlugin):
|
|||
substance_painter.project.reload_mesh(path, settings, on_mesh_reload)
|
||||
|
||||
# Update container representation
|
||||
container["representation"] = str(representation["_id"])
|
||||
set_container(self.container_key, container)
|
||||
object_name = container["objectName"]
|
||||
update_data = {"representation": str(representation["_id"])}
|
||||
set_container_metadata(object_name, update_data, update=True)
|
||||
|
||||
def remove(self, container):
|
||||
|
||||
|
|
@ -128,4 +128,4 @@ class SubstanceLoadProjectMesh(load.LoaderPlugin):
|
|||
# or close the project?
|
||||
# TODO: This is likely best 'hidden' away to the user because
|
||||
# this will leave the project's mesh unmanaged.
|
||||
remove_container(self.container_key)
|
||||
remove_container_metadata(container["objectName"])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue