From f4b20e4e0f4c4d6db467fb39550c3b471f8c00a5 Mon Sep 17 00:00:00 2001 From: Colin Basnett Date: Sun, 3 Aug 2025 01:40:38 -0700 Subject: [PATCH] Reverted to old "is action for armature" functionality The current Blender 4.4 functionality is still very wishy washy (not able to inspect channel bags), and the solution that was created was broken. In addition, newly created actions will be given an appropriately named slot instead of it being a "Legacy Slot". --- io_scene_psk_psa/psa/export/operators.py | 38 ++++++++---------------- io_scene_psk_psa/psa/importer.py | 1 + 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/io_scene_psk_psa/psa/export/operators.py b/io_scene_psk_psa/psa/export/operators.py index 926a2d9..d969cbb 100644 --- a/io_scene_psk_psa/psa/export/operators.py +++ b/io_scene_psk_psa/psa/export/operators.py @@ -2,6 +2,7 @@ from collections import Counter from typing import List, Iterable, Dict, Tuple, cast as typing_cast import bpy +import re from bpy.props import StringProperty from bpy.types import Context, Action, Object, AnimData, TimelineMarker, Operator, Armature from bpy_extras.io_utils import ExportHelper @@ -16,7 +17,6 @@ from .ui import PSA_UL_export_sequences from ..builder import build_psa, PsaBuildSequence, PsaBuildOptions from ..writer import write_psa from ...shared.helpers import populate_bone_collection_list, get_nla_strips_in_frame_range, PsxBoneCollection -from ...shared.semver import SemanticVersion from ...shared.ui import draw_bone_filter_mode @@ -41,30 +41,18 @@ def is_action_for_object(obj: Object, action: Action): if obj is None or obj.animation_data is None or obj.type != 'ARMATURE': return False - version = SemanticVersion(bpy.app.version) - - def is_action_for_object_legacy(action: Action, obj: Object): - """ - This is the legacy behavior before slotted actions were introduced in Blender 4.4. - It would simply check if it had any f-curves that corresponded to any bones in the armature. - """ - import re - armature_data = typing_cast(Armature, obj.data) - bone_names = set([x.name for x in armature_data.bones]) - for fcurve in action.fcurves: - match = re.match(r'pose\.bones\[\"([^\"]+)\"](\[\"([^\"]+)\"])?', fcurve.data_path) - if not match: - continue - bone_name = match.group(1) - if bone_name in bone_names: - return True - return False - - if version < SemanticVersion((4, 4, 0)): - return is_action_for_object_legacy(action, obj) - - # If the object is a part of the slot's user list, then it is a valid action for the object. - return any(obj in slot.users() for slot in action.slots) + armature_data = typing_cast(Armature, obj.data) + bone_names = set([x.name for x in armature_data.bones]) + + for fcurve in action.fcurves: + match = re.match(r'pose\.bones\[\"([^\"]+)\"](\[\"([^\"]+)\"])?', fcurve.data_path) + if not match: + continue + bone_name = match.group(1) + if bone_name in bone_names: + return True + + return False def update_actions_and_timeline_markers(context: Context, armature_objects: Iterable[Object]): diff --git a/io_scene_psk_psa/psa/importer.py b/io_scene_psk_psa/psa/importer.py index 06fb419..f56bd36 100644 --- a/io_scene_psk_psa/psa/importer.py +++ b/io_scene_psk_psa/psa/importer.py @@ -252,6 +252,7 @@ def import_psa(context: Context, psa_reader: PsaReader, armature_object: Object, action = bpy.data.actions[action_name] else: action = bpy.data.actions.new(name=action_name) + action.slots.new('OBJECT', armature_object.name) # Calculate the target FPS. match options.fps_source: