Minor fixes

This commit is contained in:
Colin Basnett
2025-07-23 10:26:56 -07:00
parent e7ce934383
commit 921efe97aa
3 changed files with 17 additions and 14 deletions

View File

@@ -1,9 +1,9 @@
from collections import Counter
from typing import List, Iterable, Dict, Tuple, Optional
from typing import List, Iterable, Dict, Tuple, cast as typing_cast
import bpy
from bpy.props import StringProperty
from bpy.types import Context, Action, Object, AnimData, TimelineMarker, Operator
from bpy.types import Context, Action, Object, AnimData, TimelineMarker, Operator, Armature
from bpy_extras.io_utils import ExportHelper
from .properties import (
@@ -12,6 +12,7 @@ from .properties import (
filter_sequences,
get_sequences_from_name_and_frame_range,
)
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
@@ -19,7 +20,7 @@ from ...shared.semver import SemanticVersion
from ...shared.ui import draw_bone_filter_mode
def get_sequences_propnames_from_source(sequence_source: str) -> Optional[Tuple[str, str]]:
def get_sequences_propnames_from_source(sequence_source: str) -> Tuple[str, str]:
match sequence_source:
case 'ACTIONS':
return 'action_list', 'action_list_index'
@@ -48,7 +49,7 @@ def is_action_for_object(obj: Object, action: Action):
It would simply check if it had any f-curves that corresponded to any bones in the armature.
"""
import re
armature_data = obj.data
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)
@@ -57,6 +58,7 @@ def is_action_for_object(obj: Object, action: Action):
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)
@@ -178,7 +180,7 @@ def get_animation_data_object(context: Context) -> Object:
active_object = context.view_layer.objects.active
if active_object.type != 'ARMATURE':
if active_object is None or active_object.type != 'ARMATURE':
raise RuntimeError('Active object must be an Armature')
if pg.sequence_source != 'ACTIONS' and pg.should_override_animation_data:
@@ -335,8 +337,6 @@ class PSA_OT_export(Operator, ExportHelper):
row.operator(PSA_OT_export_actions_select_all.bl_idname, text='All', icon='CHECKBOX_HLT')
row.operator(PSA_OT_export_actions_deselect_all.bl_idname, text='None', icon='CHECKBOX_DEHLT')
from .ui import PSA_UL_export_sequences
propname, active_propname = get_sequences_propnames_from_source(pg.sequence_source)
sequences_panel.template_list(PSA_UL_export_sequences.bl_idname, '', pg, propname, pg, active_propname,
rows=max(3, min(len(getattr(pg, propname)), 10)))

View File

@@ -1,9 +1,9 @@
import bmesh
import bpy
import numpy as np
from bpy.types import Armature, Collection, Context, Depsgraph, Object
from bpy.types import Armature, Collection, Context, Depsgraph, Object, ArmatureModifier
from mathutils import Matrix
from typing import Dict, Iterable, List, Optional, Set, Tuple, cast as typing_cast
from typing import Dict, Iterable, List, Optional, Set, cast as typing_cast
from .data import Psk
from .properties import triangle_type_and_bit_flags_to_poly_flags
from ..shared.data import Vector3
@@ -55,6 +55,8 @@ def get_mesh_objects_for_collection(collection: Collection) -> Iterable[DfsObjec
def get_mesh_objects_for_context(context: Context) -> Iterable[DfsObject]:
if context.view_layer is None:
return
for dfs_object in dfs_view_layer_objects(context.view_layer):
if dfs_object.obj.type == 'MESH' and dfs_object.is_selected:
yield dfs_object
@@ -64,9 +66,10 @@ def get_armature_for_mesh_object(mesh_object: Object) -> Optional[Object]:
if mesh_object.type != 'MESH':
return None
# Get the first armature modifier with a non-empty armature object.
for modifier in mesh_object.modifiers:
if modifier.type == 'ARMATURE' and modifier.object is not None:
return modifier.object
for modifier in filter(lambda x: x.type == 'ARMATURE', mesh_object.modifiers):
armature_modifier = typing_cast(ArmatureModifier, modifier)
if armature_modifier.object is not None:
return armature_modifier.object
return None
@@ -161,7 +164,7 @@ def build_psk(context: Context, input_objects: PskInputObjects, options: PskBuil
# The material name list may contain materials that are not on the mesh objects.
# Therefore, we can take the material_name_list as gospel and simply use it as a lookup table.
# If a look-up fails, replace it with an empty material.
materials = [bpy.data.materials.get(x.material_name, None) for x in options.material_name_list]
materials = [bpy.data.materials.get(x, None) for x in options.material_name_list]
case _:
assert False, f'Invalid material order mode: {options.material_order_mode}'

View File

@@ -254,7 +254,7 @@ def get_psk_build_options_from_property_group(scene: Scene, pg: PskExportMixin)
options.bone_collection_indices = [PsxBoneCollection(x.armature_object_name, x.armature_data_name, x.index) for x in pg.bone_collection_list if x.is_selected]
options.root_bone_name = pg.root_bone_name
options.material_order_mode = pg.material_order_mode
options.material_name_list = pg.material_name_list
options.material_name_list = [x.material_name for x in pg.material_name_list]
match pg.transform_source:
case 'SCENE':