248 lines
9.0 KiB
Python
248 lines
9.0 KiB
Python
# SPDX-FileCopyrightText: 2025 Blender Studio Tools Authors
|
|
#
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
import bpy
|
|
from typing import List
|
|
from . import constants
|
|
from . import config
|
|
from pathlib import Path
|
|
from .prefs import get_addon_prefs
|
|
from .asset_catalog import get_asset_catalog_items, get_asset_name, get_asset_id
|
|
|
|
""" NOTE Items in these properties groups should be generated by a function that finds the
|
|
avaliable task layers from the task_layer.json file that needs to be created.
|
|
"""
|
|
|
|
|
|
def get_safely_string_prop(self, name: str) -> str:
|
|
"""Return Value of String Property, and return "" if value isn't set"""
|
|
try:
|
|
return self[name]
|
|
except KeyError:
|
|
return ""
|
|
|
|
|
|
def get_task_layer_presets(self, context):
|
|
prefs = get_addon_prefs()
|
|
user_tls = Path(prefs.custom_task_layers_dir)
|
|
|
|
presets_dir = config.get_task_layer_presets_path()
|
|
items = []
|
|
|
|
for file in presets_dir.glob('*.json'):
|
|
items.append((file.__str__(), file.name.replace(".json", ""), file.name))
|
|
if user_tls.exists() and user_tls.is_dir():
|
|
for file in user_tls.glob('*.json'):
|
|
items.append((file.__str__(), file.name.replace(".json", ""), file.name))
|
|
return items
|
|
|
|
|
|
class AssetTransferData(bpy.types.PropertyGroup):
|
|
"""Properties to track transferable data on an object"""
|
|
|
|
owner: bpy.props.StringProperty(name="Owner", default="NONE")
|
|
type: bpy.props.EnumProperty(
|
|
name="Transferable Data Type",
|
|
items=constants.TRANSFER_DATA_TYPES_ENUM_ITEMS,
|
|
)
|
|
surrender: bpy.props.BoolProperty(name="Surrender Ownership", default=False)
|
|
|
|
@property
|
|
def obj_name(self):
|
|
return self.id_data.name
|
|
|
|
|
|
class AssetTransferDataTemp(bpy.types.PropertyGroup):
|
|
"""Class used when finding new ownership data so it can be drawn
|
|
with the same method as the existing ownership data from ASSET_TRANSFER_DATA"""
|
|
|
|
owner: bpy.props.StringProperty(name="Owner", default="NONE")
|
|
type: bpy.props.EnumProperty(
|
|
name="Transferable Data Type",
|
|
items=constants.TRANSFER_DATA_TYPES_ENUM_ITEMS,
|
|
)
|
|
surrender: bpy.props.BoolProperty(name="Surrender Ownership", default=False)
|
|
obj_name: bpy.props.StringProperty(name="Object Name", default="")
|
|
|
|
|
|
class TaskLayerSettings(bpy.types.PropertyGroup):
|
|
is_local: bpy.props.BoolProperty(name="Task Layer is Local", default=False)
|
|
|
|
|
|
class AssetPipeline(bpy.types.PropertyGroup):
|
|
"""Properties to manage the status of asset pipeline files"""
|
|
|
|
is_asset_pipeline_file: bpy.props.BoolProperty(
|
|
name="Asset Pipeline File",
|
|
description="Asset Pipeline Files are used in the asset pipeline, if file is not asset pipeline file user will be prompted to create a new asset",
|
|
default=False,
|
|
)
|
|
is_depreciated: bpy.props.BoolProperty(
|
|
name="Depreciated",
|
|
description="Depreciated files do not recieve any updates when syncing from a task layer",
|
|
default=False,
|
|
)
|
|
|
|
def get_is_published(self):
|
|
return bool(Path(bpy.data.filepath).parent.name in constants.PUBLISH_KEYS)
|
|
|
|
is_published: bpy.props.BoolProperty(
|
|
name="Is Published",
|
|
description="File is Published",
|
|
get=lambda self: Path(bpy.data.filepath).parent.name in constants.PUBLISH_KEYS,
|
|
)
|
|
|
|
@property
|
|
def asset_collection(self):
|
|
return bpy.data.collections.get(self.asset_collection_name) or bpy.data.collections.get(
|
|
self.asset_collection_name + "." + constants.LOCAL_SUFFIX
|
|
)
|
|
|
|
@asset_collection.setter
|
|
def asset_collection(self, coll):
|
|
self.asset_collection_name = coll.name
|
|
|
|
asset_collection_name: bpy.props.StringProperty(
|
|
name="Asset",
|
|
default="",
|
|
description="Top Level Collection of the Asset, all other collections of the asset will be children of this collection",
|
|
)
|
|
|
|
# Commented out - Let's use a weak ref for now because this causes the collection to evaluate even when hidden, causing performance nightmares
|
|
# asset_collection: bpy.props.PointerProperty(
|
|
# type=bpy.types.Collection,
|
|
# name="Asset",
|
|
# description="Top Level Collection of the Asset, all other collections of the
|
|
# asset will be children of this collection",
|
|
# )
|
|
|
|
temp_transfer_data: bpy.props.CollectionProperty(type=AssetTransferDataTemp)
|
|
|
|
def add_temp_transfer_data(self, name, owner, type, obj_name, surrender) -> 'AssetTransferDataTemp':
|
|
new_transfer_data = self.temp_transfer_data
|
|
transfer_data_item = new_transfer_data.add()
|
|
transfer_data_item.name = name
|
|
transfer_data_item.owner = owner
|
|
transfer_data_item.type = type
|
|
transfer_data_item.obj_name = obj_name
|
|
transfer_data_item.surrender = surrender
|
|
return transfer_data_item
|
|
|
|
## NEW FILE
|
|
|
|
new_file_mode: bpy.props.EnumProperty(
|
|
name="New File Mode",
|
|
items=(
|
|
('KEEP', "Current File", "Setup the Existing File/Directory as an Asset"),
|
|
('BLANK', "Blank File", "Create a New Blank Asset in a New Directory"),
|
|
),
|
|
)
|
|
|
|
dir: bpy.props.StringProperty(
|
|
name="Directory",
|
|
description="Target Path for new asset files",
|
|
subtype="DIR_PATH",
|
|
)
|
|
name: bpy.props.StringProperty(name="Name", description="Name for new Asset")
|
|
|
|
prefix: bpy.props.StringProperty(name="Prefix", description="Prefix for new Asset", default="")
|
|
|
|
task_layer_config_type: bpy.props.EnumProperty(
|
|
name="Task Layer Preset",
|
|
items=get_task_layer_presets,
|
|
) # type: ignore
|
|
|
|
temp_file: bpy.props.StringProperty(name="Pre-Sync Backup")
|
|
source_file: bpy.props.StringProperty(name="File that started Sync")
|
|
sync_error: bpy.props.BoolProperty(name="Sync Error", default=False)
|
|
|
|
all_task_layers: bpy.props.CollectionProperty(type=TaskLayerSettings)
|
|
local_task_layers: bpy.props.CollectionProperty(type=TaskLayerSettings)
|
|
|
|
def set_local_task_layers(self, task_layer_keys: List[str]):
|
|
# Update Local Task Layers for New File
|
|
self.local_task_layers.clear()
|
|
for task_layer in self.all_task_layers:
|
|
if task_layer.name in task_layer_keys:
|
|
new_local_task_layer = self.local_task_layers.add()
|
|
new_local_task_layer.name = task_layer.name
|
|
|
|
def get_local_task_layers(self) -> list[str]:
|
|
return [task_layer.name for task_layer in self.local_task_layers]
|
|
|
|
def set_asset_catalog_name(self, input):
|
|
task_layer_dict = config.get_task_layer_dict()
|
|
task_layer_dict["ASSET_CATALOG_ID"] = get_asset_id(input)
|
|
config.update_task_layer_json_data(task_layer_dict)
|
|
self['asset_catalog_name'] = input
|
|
|
|
def get_asset_catalog_name(self):
|
|
if config.ASSET_CATALOG_ID != "":
|
|
asset_name = get_asset_name(config.ASSET_CATALOG_ID)
|
|
if asset_name is None:
|
|
return ""
|
|
return asset_name
|
|
return get_safely_string_prop(self, 'asset_catalog_name')
|
|
|
|
def get_asset_catalogs_search(self, context, edit_text: str):
|
|
return get_asset_catalog_items()
|
|
|
|
asset_catalog_name: bpy.props.StringProperty(
|
|
name="Catalog",
|
|
get=get_asset_catalog_name,
|
|
set=set_asset_catalog_name,
|
|
search=get_asset_catalogs_search,
|
|
search_options={'SORT'},
|
|
description="Select Asset Library Catalog for the current Asset, this value will be updated each time you Push to an 'Active' Publish",
|
|
) # type: ignore
|
|
|
|
|
|
@bpy.app.handlers.persistent
|
|
def set_asset_collection_name_post_file_load(_):
|
|
# Version the PointerProperty to the StringProperty, and the left-over pointer.
|
|
for scene in bpy.data.scenes:
|
|
if 'asset_collection' not in scene.asset_pipeline:
|
|
continue
|
|
coll = scene.asset_pipeline['asset_collection']
|
|
if coll:
|
|
scene.asset_pipeline.asset_collection_name = coll.name
|
|
del scene.asset_pipeline['asset_collection']
|
|
|
|
|
|
@bpy.app.handlers.persistent
|
|
def refresh_asset_catalog(_):
|
|
get_asset_catalog_items()
|
|
config.verify_task_layer_json_data()
|
|
|
|
|
|
classes = (
|
|
AssetTransferData,
|
|
AssetTransferDataTemp,
|
|
TaskLayerSettings,
|
|
AssetPipeline,
|
|
)
|
|
|
|
|
|
def register():
|
|
for i in classes:
|
|
bpy.utils.register_class(i)
|
|
bpy.types.Object.transfer_data_ownership = bpy.props.CollectionProperty(type=AssetTransferData)
|
|
bpy.types.Scene.asset_pipeline = bpy.props.PointerProperty(type=AssetPipeline)
|
|
bpy.types.ID.asset_id_owner = bpy.props.StringProperty(name="Owner", default="NONE")
|
|
bpy.types.ID.asset_id_surrender = bpy.props.BoolProperty(
|
|
name="Surrender Ownership", default=False
|
|
)
|
|
bpy.app.handlers.load_post.append(set_asset_collection_name_post_file_load)
|
|
bpy.app.handlers.load_post.append(refresh_asset_catalog)
|
|
|
|
|
|
def unregister():
|
|
for i in classes:
|
|
bpy.utils.unregister_class(i)
|
|
del bpy.types.Object.transfer_data_ownership
|
|
del bpy.types.Scene.asset_pipeline
|
|
del bpy.types.ID.asset_id_owner
|
|
bpy.app.handlers.load_post.remove(set_asset_collection_name_post_file_load)
|
|
bpy.app.handlers.load_post.remove(refresh_asset_catalog)
|