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 collections import Counter
from typing import List, Iterable, Dict, Tuple, Optional from typing import List, Iterable, Dict, Tuple, cast as typing_cast
import bpy import bpy
from bpy.props import StringProperty 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 bpy_extras.io_utils import ExportHelper
from .properties import ( from .properties import (
@@ -12,6 +12,7 @@ from .properties import (
filter_sequences, filter_sequences,
get_sequences_from_name_and_frame_range, get_sequences_from_name_and_frame_range,
) )
from .ui import PSA_UL_export_sequences
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, PsxBoneCollection 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 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: match sequence_source:
case 'ACTIONS': case 'ACTIONS':
return 'action_list', 'action_list_index' 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. It would simply check if it had any f-curves that corresponded to any bones in the armature.
""" """
import re import re
armature_data = obj.data armature_data = typing_cast(Armature, obj.data)
bone_names = set([x.name for x in armature_data.bones]) bone_names = set([x.name for x in armature_data.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)
@@ -57,6 +58,7 @@ def is_action_for_object(obj: Object, 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
return False
if version < SemanticVersion((4, 4, 0)): if version < SemanticVersion((4, 4, 0)):
return is_action_for_object_legacy(action, obj) 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 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') raise RuntimeError('Active object must be an Armature')
if pg.sequence_source != 'ACTIONS' and pg.should_override_animation_data: 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_select_all.bl_idname, text='All', icon='CHECKBOX_HLT')
row.operator(PSA_OT_export_actions_deselect_all.bl_idname, text='None', icon='CHECKBOX_DEHLT') 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) 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, sequences_panel.template_list(PSA_UL_export_sequences.bl_idname, '', pg, propname, pg, active_propname,
rows=max(3, min(len(getattr(pg, propname)), 10))) rows=max(3, min(len(getattr(pg, propname)), 10)))

View File

@@ -1,9 +1,9 @@
import bmesh import bmesh
import bpy import bpy
import numpy as np 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 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 .data import Psk
from .properties import triangle_type_and_bit_flags_to_poly_flags from .properties import triangle_type_and_bit_flags_to_poly_flags
from ..shared.data import Vector3 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]: 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): for dfs_object in dfs_view_layer_objects(context.view_layer):
if dfs_object.obj.type == 'MESH' and dfs_object.is_selected: if dfs_object.obj.type == 'MESH' and dfs_object.is_selected:
yield dfs_object yield dfs_object
@@ -64,9 +66,10 @@ def get_armature_for_mesh_object(mesh_object: Object) -> Optional[Object]:
if mesh_object.type != 'MESH': if mesh_object.type != 'MESH':
return None return None
# Get the first armature modifier with a non-empty armature object. # Get the first armature modifier with a non-empty armature object.
for modifier in mesh_object.modifiers: for modifier in filter(lambda x: x.type == 'ARMATURE', mesh_object.modifiers):
if modifier.type == 'ARMATURE' and modifier.object is not None: armature_modifier = typing_cast(ArmatureModifier, modifier)
return modifier.object if armature_modifier.object is not None:
return armature_modifier.object
return None 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. # 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. # 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. # 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 _: case _:
assert False, f'Invalid material order mode: {options.material_order_mode}' 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.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.root_bone_name = pg.root_bone_name
options.material_order_mode = pg.material_order_mode 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: match pg.transform_source:
case 'SCENE': case 'SCENE':