Blender Kitsu: Add option to Exclude Collections from Output Collection #120
@ -109,7 +109,11 @@ class KITSU_OT_anim_check_action_names(bpy.types.Operator):
|
|||||||
)
|
)
|
||||||
wrong: List[Tuple[bpy.types.Action, str]] = []
|
wrong: List[Tuple[bpy.types.Action, str]] = []
|
||||||
created: List[bpy.types.Action] = []
|
created: List[bpy.types.Action] = []
|
||||||
cleanup_empty_actions: bpy.props.BoolProperty(name="Delete Empty Action Data-Blocks", default=False, description="Remove any empty action data-blocks, actions that have 0 Fcurves/Keyframes")
|
cleanup_empty_actions: bpy.props.BoolProperty(
|
||||||
|
name="Delete Empty Action Data-Blocks",
|
||||||
|
default=False,
|
||||||
|
description="Remove any empty action data-blocks, actions that have 0 Fcurves/Keyframes",
|
||||||
|
)
|
||||||
|
|
||||||
# List of tuples that contains the action on index 0 with the wrong name
|
# List of tuples that contains the action on index 0 with the wrong name
|
||||||
# and the name it should have on index 1.
|
# and the name it should have on index 1.
|
||||||
@ -135,17 +139,17 @@ class KITSU_OT_anim_check_action_names(bpy.types.Operator):
|
|||||||
succeeded = []
|
succeeded = []
|
||||||
removed = []
|
removed = []
|
||||||
|
|
||||||
|
|
||||||
if self.cleanup_empty_actions:
|
if self.cleanup_empty_actions:
|
||||||
for action in bpy.data.actions:
|
for action in bpy.data.actions:
|
||||||
if len(action.fcurves) == 0 and action.use_fake_user and action.users == 1:
|
if (
|
||||||
|
len(action.fcurves) == 0
|
||||||
|
and action.use_fake_user
|
||||||
|
and action.users == 1
|
||||||
|
):
|
||||||
removed.append(action.name)
|
removed.append(action.name)
|
||||||
action.use_fake_user = False
|
action.use_fake_user = False
|
||||||
bpy.data.actions.remove(action)
|
bpy.data.actions.remove(action)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for obj in [obj for obj in bpy.data.objects if obj.type == "ARMATURE"]:
|
for obj in [obj for obj in bpy.data.objects if obj.type == "ARMATURE"]:
|
||||||
# Cerate Action if None Exists
|
# Cerate Action if None Exists
|
||||||
if obj.animation_data is None or obj.animation_data.action is None:
|
if obj.animation_data is None or obj.animation_data.action is None:
|
||||||
@ -186,8 +190,6 @@ class KITSU_OT_anim_check_action_names(bpy.types.Operator):
|
|||||||
if len(self.created) != 0:
|
if len(self.created) != 0:
|
||||||
report_str += f" | Created Actions: {len(self.created)}"
|
report_str += f" | Created Actions: {len(self.created)}"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
self.report(
|
self.report(
|
||||||
{report_state},
|
{report_state},
|
||||||
report_str,
|
report_str,
|
||||||
@ -397,6 +399,15 @@ class KITSU_OT_unlink_collection_with_string(bpy.types.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
class KITSU_PG_anim_exclude_coll(bpy.types.PropertyGroup):
|
||||||
|
exclude: bpy.props.BoolProperty(
|
||||||
|
name="Exclude",
|
||||||
|
description="",
|
||||||
|
default=False,
|
||||||
|
override={"LIBRARY_OVERRIDABLE"},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class KITSU_OT_anim_update_output_coll(bpy.types.Operator):
|
class KITSU_OT_anim_update_output_coll(bpy.types.Operator):
|
||||||
bl_idname = "kitsu.anim_update_output_coll"
|
bl_idname = "kitsu.anim_update_output_coll"
|
||||||
bl_label = "Update Output Collection"
|
bl_label = "Update Output Collection"
|
||||||
@ -404,6 +415,8 @@ class KITSU_OT_anim_update_output_coll(bpy.types.Operator):
|
|||||||
bl_description = (
|
bl_description = (
|
||||||
"Scans scene for any collections that are not yet in the output collection"
|
"Scans scene for any collections that are not yet in the output collection"
|
||||||
)
|
)
|
||||||
|
output_coll = None
|
||||||
|
asset_colls = None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context: bpy.types.Context) -> bool:
|
def poll(cls, context: bpy.types.Context) -> bool:
|
||||||
@ -416,40 +429,48 @@ class KITSU_OT_anim_update_output_coll(bpy.types.Operator):
|
|||||||
|
|
||||||
return bool(active_shot and output_coll)
|
return bool(active_shot and output_coll)
|
||||||
|
|
||||||
def execute(self, context: bpy.types.Context) -> Set[str]:
|
def invoke(self, context, event):
|
||||||
active_shot = cache.shot_active_get()
|
active_shot = cache.shot_active_get()
|
||||||
output_coll_name = opsdata.get_output_coll_name(active_shot)
|
output_coll_name = opsdata.get_output_coll_name(active_shot)
|
||||||
output_coll = bpy.data.collections[output_coll_name]
|
self.output_coll = bpy.data.collections[output_coll_name]
|
||||||
|
return context.window_manager.invoke_props_dialog(self, width=500)
|
||||||
# Clear Out Output Collection before Starting
|
|
||||||
for collection in output_coll.children:
|
|
||||||
output_coll.children.unlink(collection)
|
|
||||||
bpy.context.view_layer.update()
|
|
||||||
|
|
||||||
asset_colls = opsdata.find_asset_collections_in_scene(context.scene)
|
|
||||||
missing: List[bpy.types.Collection] = []
|
|
||||||
output_coll_childs = list(opsdata.traverse_collection_tree(output_coll))
|
|
||||||
|
|
||||||
# Check if all found asset colls are in output coll.
|
|
||||||
for coll in asset_colls:
|
|
||||||
if coll in output_coll_childs:
|
|
||||||
continue
|
|
||||||
missing.append(coll)
|
|
||||||
|
|
||||||
|
def get_collections(self, context):
|
||||||
|
self.asset_colls = opsdata.find_asset_collections_in_scene(context.scene)
|
||||||
# Only take parent colls.
|
# Only take parent colls.
|
||||||
childs = []
|
childs = []
|
||||||
for i in range(len(missing)):
|
for i in range(len(self.asset_colls)):
|
||||||
coll = missing[i]
|
coll = self.asset_colls[i]
|
||||||
coll_childs = list(opsdata.traverse_collection_tree(coll))
|
coll_childs = list(opsdata.traverse_collection_tree(coll))
|
||||||
for j in range(i + 1, len(missing)):
|
for j in range(i + 1, len(self.asset_colls)):
|
||||||
coll_comp = missing[j]
|
coll_comp = self.asset_colls[j]
|
||||||
if coll_comp in coll_childs:
|
if coll_comp in coll_childs:
|
||||||
childs.append(coll_comp)
|
childs.append(coll_comp)
|
||||||
|
|
||||||
parents = [coll for coll in missing if coll not in childs]
|
return [coll for coll in self.asset_colls if coll not in childs]
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
parents = self.get_collections(context)
|
||||||
|
# Must display collections that already exist in output collection so user can exclude them
|
||||||
|
for col in self.output_coll.children:
|
||||||
|
parents.append(col)
|
||||||
|
layout = self.layout
|
||||||
|
box = layout.box()
|
||||||
|
box.label(text="Select Collection to Exclude", icon="OUTLINER_COLLECTION")
|
||||||
|
column = box.column(align=True)
|
||||||
|
for col in parents:
|
||||||
|
column.prop(col.anim_output, "exclude", text=col.name)
|
||||||
|
|
||||||
|
def execute(self, context: bpy.types.Context) -> Set[str]:
|
||||||
|
# Clear Out Output Collection before Starting
|
||||||
|
for collection in self.output_coll.children:
|
||||||
|
self.output_coll.children.unlink(collection)
|
||||||
|
bpy.context.view_layer.update()
|
||||||
|
parents = self.get_collections(context)
|
||||||
|
parents = [col for col in parents if not col.anim_output.exclude]
|
||||||
for coll in parents:
|
for coll in parents:
|
||||||
output_coll.children.link(coll)
|
self.output_coll.children.link(coll)
|
||||||
logger.info("%s linked in %s", coll.name, output_coll.name)
|
logger.info("%s linked in %s", coll.name, self.output_coll.name)
|
||||||
|
|
||||||
# Ensure Camera Rig is Linked
|
# Ensure Camera Rig is Linked
|
||||||
for coll in [col for col in bpy.data.collections]:
|
for coll in [col for col in bpy.data.collections]:
|
||||||
@ -457,11 +478,11 @@ class KITSU_OT_anim_update_output_coll(bpy.types.Operator):
|
|||||||
if (
|
if (
|
||||||
coll.override_library.hierarchy_root.name == "CA-camera_rig"
|
coll.override_library.hierarchy_root.name == "CA-camera_rig"
|
||||||
): # TODO Fix this hack to be generic
|
): # TODO Fix this hack to be generic
|
||||||
output_coll.children.link(coll)
|
self.output_coll.children.link(coll)
|
||||||
|
|
||||||
self.report(
|
self.report(
|
||||||
{"INFO"},
|
{"INFO"},
|
||||||
f"Found Asset Collections: {len(asset_colls)} | Added to output collection: {len(parents)}",
|
f"Found Asset Collections: {len(self.asset_colls)} | Added to output collection: {len(parents)}",
|
||||||
)
|
)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
@ -474,14 +495,19 @@ classes = [
|
|||||||
KITSU_OT_anim_update_output_coll,
|
KITSU_OT_anim_update_output_coll,
|
||||||
KITSU_OT_anim_enforce_naming_convention,
|
KITSU_OT_anim_enforce_naming_convention,
|
||||||
KITSU_OT_unlink_collection_with_string,
|
KITSU_OT_unlink_collection_with_string,
|
||||||
|
KITSU_PG_anim_exclude_coll,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
for cls in classes:
|
for cls in classes:
|
||||||
bpy.utils.register_class(cls)
|
bpy.utils.register_class(cls)
|
||||||
|
bpy.types.Collection.anim_output = bpy.props.PointerProperty(
|
||||||
|
type=KITSU_PG_anim_exclude_coll
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
for cls in reversed(classes):
|
for cls in reversed(classes):
|
||||||
bpy.utils.unregister_class(cls)
|
bpy.utils.unregister_class(cls)
|
||||||
|
del bpy.types.Collection.anim_output
|
||||||
|
Loading…
Reference in New Issue
Block a user