239 lines
8.0 KiB
Python
239 lines
8.0 KiB
Python
# SPDX-FileCopyrightText: 2021 Blender Studio Tools Authors
|
|
#
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
import bpy
|
|
from bpy_extras.id_map_utils import get_id_reference_map, get_all_referenced_ids
|
|
from .util import get_storage_of_id
|
|
from .. import constants, config
|
|
from .util import data_type_from_transfer_data_key
|
|
|
|
|
|
def merge_get_target_suffix(suffix: str) -> str:
|
|
"""Get the corresponding suffix for a given suffix
|
|
|
|
Args:
|
|
suffix (str): Suffix for External or Local Datablock
|
|
|
|
Returns:
|
|
str: Returns External Suffix if given Local suffix for vice-versa
|
|
"""
|
|
if suffix.endswith(constants.EXTERNAL_SUFFIX):
|
|
return constants.LOCAL_SUFFIX
|
|
if suffix.endswith(constants.LOCAL_SUFFIX):
|
|
return constants.EXTERNAL_SUFFIX
|
|
|
|
|
|
def merge_get_target_name(name: str) -> str:
|
|
"""Get the corresponding target name for a given datablock's suffix.
|
|
Suffixes are set by the add_suffix_to_hierarchy() function prior to
|
|
calling this function.
|
|
|
|
Args:
|
|
name (str): Name of a given datablock including its suffix
|
|
|
|
Returns:
|
|
str: Returns datablock name with the opposite suffix
|
|
"""
|
|
old = name.split(constants.MERGE_DELIMITER)[-1]
|
|
new = merge_get_target_suffix(old)
|
|
assert new, "Failed to flip the LOC/EXT suffix of this name, this should never happen : " + name
|
|
li = name.rsplit(old, 1)
|
|
return new.join(li)
|
|
|
|
|
|
def merge_get_basename(name: str) -> str:
|
|
"""Returns the name of an asset without its suffix"""
|
|
if name.endswith(constants.LOCAL_SUFFIX) or name.endswith(
|
|
constants.EXTERNAL_SUFFIX
|
|
):
|
|
return constants.MERGE_DELIMITER.join(
|
|
name.split(constants.MERGE_DELIMITER)[:-1]
|
|
)
|
|
return name
|
|
|
|
|
|
def merge_remove_suffix_from_hierarchy(collection: bpy.types.Collection) -> None:
|
|
"""Removes the suffix after a set delimiter from all datablocks
|
|
referenced by a collection, itself included
|
|
|
|
Args:
|
|
collection (bpy.types.Collection): Collection that as been suffixed
|
|
"""
|
|
ref_map = get_id_reference_map()
|
|
datablocks = get_all_referenced_ids(collection, ref_map)
|
|
datablocks.add(collection)
|
|
for action in bpy.data.actions:
|
|
datablocks.add(action)
|
|
for db in datablocks:
|
|
if db == None:
|
|
# Not sure why this would happen.
|
|
raise Exception(
|
|
f"None value in datablock list"
|
|
)
|
|
if db.library:
|
|
# Don't rename linked datablocks.
|
|
continue
|
|
try:
|
|
db.name = merge_get_basename(db.name)
|
|
except:
|
|
pass
|
|
|
|
|
|
def merge_add_suffix_to_hierarchy(
|
|
collection: bpy.types.Collection, suffix_base: str
|
|
) -> None:
|
|
"""Add a suffix to the names of all datablocks referenced by a collection,
|
|
itself included.
|
|
|
|
Args:
|
|
collection (bpy.types.Collection): Collection that needs to be suffixed
|
|
suffix_base (str): Suffix to append to collection and items linked to collection
|
|
"""
|
|
|
|
suffix = f"{constants.MERGE_DELIMITER}{suffix_base}"
|
|
|
|
ref_map = get_id_reference_map()
|
|
datablocks = get_all_referenced_ids(collection, ref_map)
|
|
datablocks.add(collection)
|
|
for db in datablocks:
|
|
if db == None:
|
|
# Not sure why this would happen.
|
|
continue
|
|
if len(db.name) > 59:
|
|
raise Exception(
|
|
f"Datablock name too long, must be max 59 characters: {db.name}"
|
|
)
|
|
if db.library:
|
|
# Don't rename linked datablocks.
|
|
continue
|
|
collision_db = get_storage_of_id(db).get(db.name + suffix)
|
|
if collision_db:
|
|
collision_db.name += f'{constants.MERGE_DELIMITER}OLD'
|
|
try:
|
|
new_name = db.name + suffix
|
|
db.name = new_name
|
|
assert (
|
|
db.name == new_name
|
|
), "This should never happen here, unless some add-on suffix is >3 characters. Avoid!"
|
|
except:
|
|
pass
|
|
|
|
|
|
def asset_prefix_name_get(name: str) -> str:
|
|
"""Returns a string with the asset prefix if it is not already set.
|
|
Users can specify a prefix to live on all objects during the
|
|
asset creation process. This prefix is stored in the scene.
|
|
|
|
Args:
|
|
name (str): Name to add prefix to
|
|
|
|
Returns:
|
|
str: Returns name with prefix
|
|
"""
|
|
asset_pipe = bpy.context.scene.asset_pipeline
|
|
if name.startswith(asset_pipe.prefix + constants.NAME_DELIMITER):
|
|
return name
|
|
prefix = (
|
|
asset_pipe.prefix + constants.NAME_DELIMITER if asset_pipe.prefix != "" else ""
|
|
)
|
|
return prefix + name
|
|
|
|
|
|
def task_layer_prefix_name_get(name: str, task_layer_owner: str) -> str:
|
|
"""Returns a string with the task layer prefix if one is not already set.
|
|
Prefix for assets is defined task_layer.json file within TASK_LAYER_TYPES
|
|
Will return early if any prefix is found, cannot replace existing prefixes.
|
|
|
|
Args:
|
|
name (str): Name to add prefix to
|
|
task_layer_owner (str):
|
|
|
|
Returns:
|
|
str: Returns name with prefix
|
|
"""
|
|
prefix = config.TASK_LAYER_TYPES[task_layer_owner]
|
|
return prefix + constants.NAME_DELIMITER + task_layer_prefix_basename_get(name)
|
|
|
|
|
|
def task_layer_prefix_basename_get(name: str) -> str:
|
|
"""Get the base of a name if it contains a task layer prefix.
|
|
This prefix is set on some Transferable Data items, this functions
|
|
removes the prefixes and returns the basename
|
|
|
|
Args:
|
|
name (str): Original name including prefix
|
|
|
|
Returns:
|
|
str: Returns name without task layer prefix
|
|
"""
|
|
for task_layer_key in config.TASK_LAYER_TYPES:
|
|
prefix = config.TASK_LAYER_TYPES[task_layer_key] + constants.NAME_DELIMITER
|
|
if name.startswith(prefix):
|
|
return name[len(prefix):]
|
|
return name
|
|
|
|
|
|
def task_layer_prefix_legacy_basename(name) -> str:
|
|
# TODO Remove this is legacy code (coordinate with team)
|
|
if "." in name:
|
|
legacy_name = name.replace(".", "")
|
|
for task_layer_key in config.TASK_LAYER_TYPES:
|
|
if legacy_name.startswith(config.TASK_LAYER_TYPES[task_layer_key]):
|
|
return legacy_name.replace(config.TASK_LAYER_TYPES[task_layer_key], "")
|
|
|
|
|
|
def task_layer_prefix_transfer_data_update(
|
|
transfer_data_item: bpy.types.CollectionProperty,
|
|
) -> bool:
|
|
"""Task Layer Prefix can become out of date with the actual owner of the task layer.
|
|
This will update the existing prefixes on transfer_data_item so it can match the
|
|
owner of that transfer_data_item. Will update both the transfer_data_item.name and the
|
|
name of the actual data the transfer_data_item is referring to.
|
|
|
|
Args:
|
|
transfer_data_item (bpy.types.CollectionProperty): Transferable Data Item that is named with prefix
|
|
|
|
Returns:
|
|
bool: Returns True if a change to the name was completed
|
|
"""
|
|
prefix_types = [constants.MODIFIER_KEY, constants.CONSTRAINT_KEY]
|
|
if transfer_data_item.type not in prefix_types:
|
|
return
|
|
obj = transfer_data_item.id_data
|
|
td_data = data_type_from_transfer_data_key(obj, transfer_data_item.type)
|
|
|
|
# TODO Remove this
|
|
# Legacy Prefix Name was used during add-on testing stage but not production
|
|
legacy_name = task_layer_prefix_legacy_basename(transfer_data_item.name)
|
|
|
|
if legacy_name:
|
|
base_name = legacy_name
|
|
else:
|
|
base_name = task_layer_prefix_basename_get(transfer_data_item.name)
|
|
|
|
prefix = config.TASK_LAYER_TYPES[transfer_data_item.owner]
|
|
new_name = prefix + constants.NAME_DELIMITER + base_name
|
|
if new_name == transfer_data_item.name or not td_data.get(transfer_data_item.name):
|
|
return
|
|
|
|
# Ensure no period in name
|
|
# TODO Remove this is legacy code (coordinate with team)
|
|
new_name = new_name.replace(".", "")
|
|
|
|
td_data[transfer_data_item.name].name = new_name
|
|
transfer_data_item.name = new_name
|
|
return True
|
|
|
|
|
|
def get_id_type_name(id_type: bpy.types) -> str:
|
|
"""Return the cosmetic name of a given ID type
|
|
|
|
Args:
|
|
id_type (bpy.types): An ID type e.g. bpy.types.Object
|
|
|
|
Returns:
|
|
str: Name of an ID type e.g. bpy.types.Object will return 'Object'
|
|
"""
|
|
return str(id_type).split("'bpy_types.")[1].replace("'>", "")
|