Added cross-version compatibility for is_action_for_armature function

This commit is contained in:
Colin Basnett
2025-01-13 12:02:13 -08:00
parent 35ac0bf86c
commit f8234b3892
2 changed files with 77 additions and 11 deletions

View File

@@ -1,4 +1,3 @@
import re
from collections import Counter from collections import Counter
from typing import List, Iterable, Dict, Tuple, cast, Optional from typing import List, Iterable, Dict, Tuple, cast, Optional
@@ -12,7 +11,7 @@ from .properties import PSA_PG_export, PSA_PG_export_action_list_item, filter_se
get_sequences_from_name_and_frame_range get_sequences_from_name_and_frame_range
from ..builder import build_psa, PsaBuildSequence, PsaBuildOptions from ..builder import build_psa, PsaBuildSequence, PsaBuildOptions
from ..writer import write_psa from ..writer import write_psa
from ...shared.helpers import populate_bone_collection_list, get_nla_strips_in_frame_range from ...shared.helpers import populate_bone_collection_list, get_nla_strips_in_frame_range, SemanticVersion
from ...shared.ui import draw_bone_filter_mode from ...shared.ui import draw_bone_filter_mode
@@ -33,6 +32,11 @@ def get_sequences_propnames_from_source(sequence_source: str) -> Optional[Tuple[
def is_action_for_armature(armature: Armature, action: Action): def is_action_for_armature(armature: Armature, action: Action):
if len(action.fcurves) == 0: if len(action.fcurves) == 0:
return False return False
version = SemanticVersion(bpy.app.version)
if version < SemanticVersion((4, 4, 0)):
import re
bone_names = set([x.name for x in armature.bones]) bone_names = set([x.name for x in armature.bones])
for fcurve in action.fcurves: for fcurve in action.fcurves:
match = re.match(r'pose\.bones\[\"([^\"]+)\"](\[\"([^\"]+)\"])?', fcurve.data_path) match = re.match(r'pose\.bones\[\"([^\"]+)\"](\[\"([^\"]+)\"])?', fcurve.data_path)
@@ -41,6 +45,14 @@ def is_action_for_armature(armature: Armature, action: Action):
bone_name = match.group(1) bone_name = match.group(1)
if bone_name in bone_names: if bone_name in bone_names:
return True return True
else:
# Look up the armature by ID and check if its data block pointer matches the armature.
for slot in filter(lambda x: x.id_root == 'OBJECT', action.slots):
# Lop off the 'OB' prefix from the identifier for the lookup.
object = bpy.data.objects.get(slot.identifier[2:], None)
if object and object.data == armature:
return True
return False return False

View File

@@ -1,4 +1,4 @@
from typing import List, Iterable, cast from typing import List, Iterable, cast, Tuple
import bpy import bpy
from bpy.props import CollectionProperty from bpy.props import CollectionProperty
@@ -154,3 +154,57 @@ def get_export_bone_names(armature_object: Object, bone_filter_mode: str, bone_c
def is_bdk_addon_loaded() -> bool: def is_bdk_addon_loaded() -> bool:
return 'bdk' in dir(bpy.ops) return 'bdk' in dir(bpy.ops)
class SemanticVersion(object):
def __init__(self, version: Tuple[int, int, int]):
self.major, self.minor, self.patch = version
def __iter__(self):
yield self.major
yield self.minor
yield self.patch
@staticmethod
def compare(lhs: 'SemanticVersion', rhs: 'SemanticVersion') -> int:
"""
Compares two semantic versions.
Returns:
-1 if lhs < rhs
0 if lhs == rhs
1 if lhs > rhs
"""
for l, r in zip(lhs, rhs):
if l < r:
return -1
if l > r:
return 1
return 0
def __str__(self):
return f'{self.major}.{self.minor}.{self.patch}'
def __repr__(self):
return str(self)
def __eq__(self, other):
return self.compare(self, other) == 0
def __ne__(self, other):
return not self == other
def __lt__(self, other):
return self.compare(self, other) == -1
def __le__(self, other):
return self.compare(self, other) <= 0
def __gt__(self, other):
return self.compare(self, other) == 1
def __ge__(self, other):
return self.compare(self, other) >= 0
def __hash__(self):
return hash((self.major, self.minor, self.patch))