mirror of
https://github.com/DarklightGames/io_scene_psk_psa.git
synced 2024-12-18 09:15:57 +01:00
All string literals now use single-quotes instead of double-quotes where possible
This commit is contained in:
parent
b2f5985681
commit
564f7ec221
@ -1,15 +1,15 @@
|
|||||||
from bpy.app.handlers import persistent
|
from bpy.app.handlers import persistent
|
||||||
|
|
||||||
bl_info = {
|
bl_info = {
|
||||||
"name": "PSK/PSA Importer/Exporter",
|
'name': 'PSK/PSA Importer/Exporter',
|
||||||
"author": "Colin Basnett, Yurii Ti",
|
'author': 'Colin Basnett, Yurii Ti',
|
||||||
"version": (6, 1, 2),
|
'version': (6, 1, 2),
|
||||||
"blender": (4, 0, 0),
|
'blender': (4, 0, 0),
|
||||||
"description": "PSK/PSA Import/Export (.psk/.psa)",
|
'description': 'PSK/PSA Import/Export (.psk/.psa)',
|
||||||
"warning": "",
|
'warning': '',
|
||||||
"doc_url": "https://github.com/DarklightGames/io_scene_psk_psa",
|
'doc_url': 'https://github.com/DarklightGames/io_scene_psk_psa',
|
||||||
"tracker_url": "https://github.com/DarklightGames/io_scene_psk_psa/issues",
|
'tracker_url': 'https://github.com/DarklightGames/io_scene_psk_psa/issues',
|
||||||
"category": "Import-Export"
|
'category': 'Import-Export'
|
||||||
}
|
}
|
||||||
|
|
||||||
if 'bpy' in locals():
|
if 'bpy' in locals():
|
||||||
|
@ -30,12 +30,12 @@ def get_nla_strips_in_frame_range(animation_data: AnimData, frame_min: float, fr
|
|||||||
|
|
||||||
|
|
||||||
def populate_bone_collection_list(armature_object: Object, bone_collection_list: bpy.props.CollectionProperty) -> None:
|
def populate_bone_collection_list(armature_object: Object, bone_collection_list: bpy.props.CollectionProperty) -> None:
|
||||||
"""
|
'''
|
||||||
Updates the bone collections collection.
|
Updates the bone collections collection.
|
||||||
|
|
||||||
Bone collection selections are preserved between updates unless none of the groups were previously selected;
|
Bone collection selections are preserved between updates unless none of the groups were previously selected;
|
||||||
otherwise, all collections are selected by default.
|
otherwise, all collections are selected by default.
|
||||||
"""
|
'''
|
||||||
has_selected_collections = any([g.is_selected for g in bone_collection_list])
|
has_selected_collections = any([g.is_selected for g in bone_collection_list])
|
||||||
unassigned_collection_is_selected, selected_assigned_collection_names = True, []
|
unassigned_collection_is_selected, selected_assigned_collection_names = True, []
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ def check_bone_names(bone_names: Iterable[str]):
|
|||||||
|
|
||||||
|
|
||||||
def get_export_bone_names(armature_object: Object, bone_filter_mode: str, bone_collection_indices: List[int]) -> List[str]:
|
def get_export_bone_names(armature_object: Object, bone_filter_mode: str, bone_collection_indices: List[int]) -> List[str]:
|
||||||
"""
|
'''
|
||||||
Returns a sorted list of bone indices that should be exported for the given bone filter mode and bone collections.
|
Returns a sorted list of bone indices that should be exported for the given bone filter mode and bone collections.
|
||||||
|
|
||||||
Note that the ancestors of bones within the bone collections will also be present in the returned list.
|
Note that the ancestors of bones within the bone collections will also be present in the returned list.
|
||||||
@ -93,7 +93,7 @@ def get_export_bone_names(armature_object: Object, bone_filter_mode: str, bone_c
|
|||||||
:param bone_filter_mode: One of ['ALL', 'BONE_COLLECTIONS']
|
:param bone_filter_mode: One of ['ALL', 'BONE_COLLECTIONS']
|
||||||
:param bone_collection_indices: List of bone collection indices to be exported.
|
:param bone_collection_indices: List of bone collection indices to be exported.
|
||||||
:return: A sorted list of bone indices that should be exported.
|
:return: A sorted list of bone indices that should be exported.
|
||||||
"""
|
'''
|
||||||
if armature_object is None or armature_object.type != 'ARMATURE':
|
if armature_object is None or armature_object.type != 'ARMATURE':
|
||||||
raise ValueError('An armature object must be supplied')
|
raise ValueError('An armature object must be supplied')
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ class PsaConfig:
|
|||||||
|
|
||||||
|
|
||||||
def _load_config_file(file_path: str) -> ConfigParser:
|
def _load_config_file(file_path: str) -> ConfigParser:
|
||||||
"""
|
'''
|
||||||
UEViewer exports a dialect of INI files that is not compatible with Python's ConfigParser.
|
UEViewer exports a dialect of INI files that is not compatible with Python's ConfigParser.
|
||||||
Specifically, it allows values in this format:
|
Specifically, it allows values in this format:
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ def _load_config_file(file_path: str) -> ConfigParser:
|
|||||||
|
|
||||||
This is not allowed in Python's ConfigParser, which requires a '=' character after each key name.
|
This is not allowed in Python's ConfigParser, which requires a '=' character after each key name.
|
||||||
To work around this, we'll modify the file to add the '=' character after each key name if it is missing.
|
To work around this, we'll modify the file to add the '=' character after each key name if it is missing.
|
||||||
"""
|
'''
|
||||||
with open(file_path, 'r') as f:
|
with open(file_path, 'r') as f:
|
||||||
lines = f.read().split('\n')
|
lines = f.read().split('\n')
|
||||||
|
|
||||||
|
@ -4,10 +4,10 @@ from typing import List
|
|||||||
|
|
||||||
from ..data import *
|
from ..data import *
|
||||||
|
|
||||||
"""
|
'''
|
||||||
Note that keys are not stored within the Psa object.
|
Note that keys are not stored within the Psa object.
|
||||||
Use the PsaReader::get_sequence_keys to get the keys for a sequence.
|
Use the PsaReader::get_sequence_keys to get the keys for a sequence.
|
||||||
"""
|
'''
|
||||||
|
|
||||||
|
|
||||||
class Psa:
|
class Psa:
|
||||||
|
@ -30,15 +30,15 @@ class PSA_UL_export_sequences(UIList):
|
|||||||
pg = getattr(context.scene, 'psa_export')
|
pg = getattr(context.scene, 'psa_export')
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
subrow = row.row(align=True)
|
subrow = row.row(align=True)
|
||||||
subrow.prop(pg, 'sequence_filter_name', text="")
|
subrow.prop(pg, 'sequence_filter_name', text='')
|
||||||
subrow.prop(pg, 'sequence_use_filter_invert', text="", icon='ARROW_LEFTRIGHT')
|
subrow.prop(pg, 'sequence_use_filter_invert', text='', icon='ARROW_LEFTRIGHT')
|
||||||
# subrow.prop(pg, 'sequence_use_filter_sort_reverse', text='', icon='SORT_ASC')
|
# subrow.prop(pg, 'sequence_use_filter_sort_reverse', text='', icon='SORT_ASC')
|
||||||
|
|
||||||
if pg.sequence_source == 'ACTIONS':
|
if pg.sequence_source == 'ACTIONS':
|
||||||
subrow = row.row(align=True)
|
subrow = row.row(align=True)
|
||||||
subrow.prop(pg, 'sequence_filter_asset', icon_only=True, icon='ASSET_MANAGER')
|
subrow.prop(pg, 'sequence_filter_asset', icon_only=True, icon='ASSET_MANAGER')
|
||||||
subrow.prop(pg, 'sequence_filter_pose_marker', icon_only=True, icon='PMARKER')
|
subrow.prop(pg, 'sequence_filter_pose_marker', icon_only=True, icon='PMARKER')
|
||||||
subrow.prop(pg, 'sequence_filter_reversed', text="", icon='FRAME_PREV')
|
subrow.prop(pg, 'sequence_filter_reversed', text='', icon='FRAME_PREV')
|
||||||
|
|
||||||
def filter_items(self, context, data, prop):
|
def filter_items(self, context, data, prop):
|
||||||
pg = getattr(context.scene, 'psa_export')
|
pg = getattr(context.scene, 'psa_export')
|
||||||
|
@ -95,15 +95,15 @@ class PSA_OT_import_select_file(Operator):
|
|||||||
bl_options = {'INTERNAL'}
|
bl_options = {'INTERNAL'}
|
||||||
bl_description = 'Select a PSA file from which to import animations'
|
bl_description = 'Select a PSA file from which to import animations'
|
||||||
filepath: StringProperty(subtype='FILE_PATH')
|
filepath: StringProperty(subtype='FILE_PATH')
|
||||||
filter_glob: StringProperty(default="*.psa", options={'HIDDEN'})
|
filter_glob: StringProperty(default='*.psa', options={'HIDDEN'})
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
getattr(context.scene, 'psa_import').psa_file_path = self.filepath
|
getattr(context.scene, 'psa_import').psa_file_path = self.filepath
|
||||||
return {"FINISHED"}
|
return {'FINISHED'}
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
context.window_manager.fileselect_add(self)
|
context.window_manager.fileselect_add(self)
|
||||||
return {"RUNNING_MODAL"}
|
return {'RUNNING_MODAL'}
|
||||||
|
|
||||||
|
|
||||||
def load_psa_file(context, filepath: str):
|
def load_psa_file(context, filepath: str):
|
||||||
|
@ -17,10 +17,10 @@ class PSA_UL_sequences(UIList):
|
|||||||
pg = getattr(context.scene, 'psa_import')
|
pg = getattr(context.scene, 'psa_import')
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
sub_row = row.row(align=True)
|
sub_row = row.row(align=True)
|
||||||
sub_row.prop(pg, 'sequence_filter_name', text="")
|
sub_row.prop(pg, 'sequence_filter_name', text='')
|
||||||
sub_row.prop(pg, 'sequence_use_filter_invert', text="", icon='ARROW_LEFTRIGHT')
|
sub_row.prop(pg, 'sequence_use_filter_invert', text='', icon='ARROW_LEFTRIGHT')
|
||||||
sub_row.prop(pg, 'sequence_use_filter_regex', text="", icon='SORTBYEXT')
|
sub_row.prop(pg, 'sequence_use_filter_regex', text='', icon='SORTBYEXT')
|
||||||
sub_row.prop(pg, 'sequence_filter_is_selected', text="", icon='CHECKBOX_HLT')
|
sub_row.prop(pg, 'sequence_filter_is_selected', text='', icon='CHECKBOX_HLT')
|
||||||
|
|
||||||
def filter_items(self, context, data, property_):
|
def filter_items(self, context, data, property_):
|
||||||
pg = getattr(context.scene, 'psa_import')
|
pg = getattr(context.scene, 'psa_import')
|
||||||
|
@ -64,12 +64,12 @@ class PsaImportResult:
|
|||||||
|
|
||||||
|
|
||||||
def _get_armature_bone_index_for_psa_bone(psa_bone_name: str, armature_bone_names: List[str], bone_mapping_mode: str = 'EXACT') -> Optional[int]:
|
def _get_armature_bone_index_for_psa_bone(psa_bone_name: str, armature_bone_names: List[str], bone_mapping_mode: str = 'EXACT') -> Optional[int]:
|
||||||
"""
|
'''
|
||||||
@param psa_bone_name: The name of the PSA bone.
|
@param psa_bone_name: The name of the PSA bone.
|
||||||
@param armature_bone_names: The names of the bones in the armature.
|
@param armature_bone_names: The names of the bones in the armature.
|
||||||
@param bone_mapping_mode: One of 'EXACT' or 'CASE_INSENSITIVE'.
|
@param bone_mapping_mode: One of 'EXACT' or 'CASE_INSENSITIVE'.
|
||||||
@return: The index of the armature bone that corresponds to the given PSA bone, or None if no such bone exists.
|
@return: The index of the armature bone that corresponds to the given PSA bone, or None if no such bone exists.
|
||||||
"""
|
'''
|
||||||
for armature_bone_index, armature_bone_name in enumerate(armature_bone_names):
|
for armature_bone_index, armature_bone_name in enumerate(armature_bone_names):
|
||||||
if bone_mapping_mode == 'CASE_INSENSITIVE':
|
if bone_mapping_mode == 'CASE_INSENSITIVE':
|
||||||
if armature_bone_name.lower() == psa_bone_name.lower():
|
if armature_bone_name.lower() == psa_bone_name.lower():
|
||||||
|
@ -11,24 +11,23 @@ def _try_fix_cue4parse_issue_103(sequences) -> bool:
|
|||||||
# The issue was that the frame_start_index was not being set correctly, and was always being set to the same value
|
# The issue was that the frame_start_index was not being set correctly, and was always being set to the same value
|
||||||
# as the frame_count.
|
# as the frame_count.
|
||||||
# This fix will eventually be deprecated as it is only necessary for files exported prior to the fix.
|
# This fix will eventually be deprecated as it is only necessary for files exported prior to the fix.
|
||||||
if len(sequences) > 0:
|
if len(sequences) == 0 and sequences[0].frame_start_index == sequences[0].frame_count:
|
||||||
if sequences[0].frame_start_index == sequences[0].frame_count:
|
# Manually set the frame_start_index for each sequence. This assumes that the sequences are in order with
|
||||||
# Manually set the frame_start_index for each sequence. This assumes that the sequences are in order with
|
# no shared frames between sequences (all exporters that I know of do this, so it's a safe assumption).
|
||||||
# no shared frames between sequences (all exporters that I know of do this, so it's a safe assumption).
|
frame_start_index = 0
|
||||||
frame_start_index = 0
|
for i, sequence in enumerate(sequences):
|
||||||
for i, sequence in enumerate(sequences):
|
sequence.frame_start_index = frame_start_index
|
||||||
sequence.frame_start_index = frame_start_index
|
frame_start_index += sequence.frame_count
|
||||||
frame_start_index += sequence.frame_count
|
return True
|
||||||
return True
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class PsaReader(object):
|
class PsaReader(object):
|
||||||
"""
|
'''
|
||||||
This class reads the sequences and bone information immediately upon instantiation and holds onto a file handle.
|
This class reads the sequences and bone information immediately upon instantiation and holds onto a file handle.
|
||||||
The keyframe data is not read into memory upon instantiation due to its potentially very large size.
|
The keyframe data is not read into memory upon instantiation due to its potentially very large size.
|
||||||
To read the key data for a particular sequence, call :read_sequence_keys.
|
To read the key data for a particular sequence, call :read_sequence_keys.
|
||||||
"""
|
'''
|
||||||
|
|
||||||
def __init__(self, path):
|
def __init__(self, path):
|
||||||
self.keys_data_offset: int = 0
|
self.keys_data_offset: int = 0
|
||||||
@ -44,11 +43,11 @@ class PsaReader(object):
|
|||||||
return self.psa.sequences
|
return self.psa.sequences
|
||||||
|
|
||||||
def read_sequence_data_matrix(self, sequence_name: str) -> np.ndarray:
|
def read_sequence_data_matrix(self, sequence_name: str) -> np.ndarray:
|
||||||
"""
|
'''
|
||||||
Reads and returns the data matrix for the given sequence.
|
Reads and returns the data matrix for the given sequence.
|
||||||
@param sequence_name: The name of the sequence.
|
@param sequence_name: The name of the sequence.
|
||||||
@return: An FxBx7 matrix where F is the number of frames, B is the number of bones.
|
@return: An FxBx7 matrix where F is the number of frames, B is the number of bones.
|
||||||
"""
|
'''
|
||||||
sequence = self.psa.sequences[sequence_name]
|
sequence = self.psa.sequences[sequence_name]
|
||||||
keys = self.read_sequence_keys(sequence_name)
|
keys = self.read_sequence_keys(sequence_name)
|
||||||
bone_count = len(self.bones)
|
bone_count = len(self.bones)
|
||||||
@ -61,12 +60,12 @@ class PsaReader(object):
|
|||||||
return matrix
|
return matrix
|
||||||
|
|
||||||
def read_sequence_keys(self, sequence_name: str) -> List[Psa.Key]:
|
def read_sequence_keys(self, sequence_name: str) -> List[Psa.Key]:
|
||||||
"""
|
'''
|
||||||
Reads and returns the key data for a sequence.
|
Reads and returns the key data for a sequence.
|
||||||
|
|
||||||
@param sequence_name: The name of the sequence.
|
@param sequence_name: The name of the sequence.
|
||||||
@return: A list of Psa.Keys.
|
@return: A list of Psa.Keys.
|
||||||
"""
|
'''
|
||||||
# Set the file reader to the beginning of the keys data
|
# Set the file reader to the beginning of the keys data
|
||||||
sequence = self.psa.sequences[sequence_name]
|
sequence = self.psa.sequences[sequence_name]
|
||||||
data_size = sizeof(Psa.Key)
|
data_size = sizeof(Psa.Key)
|
||||||
|
@ -51,7 +51,7 @@ class PSK_OT_material_list_move_up(Operator):
|
|||||||
pg = getattr(context.scene, 'psk_export')
|
pg = getattr(context.scene, 'psk_export')
|
||||||
pg.material_list.move(pg.material_list_index, pg.material_list_index - 1)
|
pg.material_list.move(pg.material_list_index, pg.material_list_index - 1)
|
||||||
pg.material_list_index -= 1
|
pg.material_list_index -= 1
|
||||||
return {"FINISHED"}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
class PSK_OT_material_list_move_down(Operator):
|
class PSK_OT_material_list_move_down(Operator):
|
||||||
@ -69,7 +69,7 @@ class PSK_OT_material_list_move_down(Operator):
|
|||||||
pg = getattr(context.scene, 'psk_export')
|
pg = getattr(context.scene, 'psk_export')
|
||||||
pg.material_list.move(pg.material_list_index, pg.material_list_index + 1)
|
pg.material_list.move(pg.material_list_index, pg.material_list_index + 1)
|
||||||
pg.material_list_index += 1
|
pg.material_list_index += 1
|
||||||
return {"FINISHED"}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
class PSK_OT_export(Operator, ExportHelper):
|
class PSK_OT_export(Operator, ExportHelper):
|
||||||
|
@ -26,9 +26,9 @@ class PskImportOptions:
|
|||||||
|
|
||||||
|
|
||||||
class ImportBone:
|
class ImportBone:
|
||||||
"""
|
'''
|
||||||
Intermediate bone type for the purpose of construction.
|
Intermediate bone type for the purpose of construction.
|
||||||
"""
|
'''
|
||||||
def __init__(self, index: int, psk_bone: Psk.Bone):
|
def __init__(self, index: int, psk_bone: Psk.Bone):
|
||||||
self.index: int = index
|
self.index: int = index
|
||||||
self.psk_bone: Psk.Bone = psk_bone
|
self.psk_bone: Psk.Bone = psk_bone
|
||||||
|
@ -23,7 +23,7 @@ def _read_material_references(path: str) -> List[str]:
|
|||||||
return []
|
return []
|
||||||
# Do a crude regex match to find the Material list entries.
|
# Do a crude regex match to find the Material list entries.
|
||||||
contents = property_file_path.read_text()
|
contents = property_file_path.read_text()
|
||||||
pattern = r"Material\s*=\s*([^\s^,]+)"
|
pattern = r'Material\s*=\s*([^\s^,]+)'
|
||||||
return re.findall(pattern, contents)
|
return re.findall(pattern, contents)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user