beautify_anm_data v2.0 (#2508)

This commit is contained in:
YunataSavior 2025-06-28 04:55:20 -07:00 committed by GitHub
parent 6eb1f72383
commit c5eeeda337
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 210 additions and 134 deletions

View File

@ -80,7 +80,7 @@ public:
/* 8053E6C8 */ void checkChangeJoint(int);
/* 8053E6D8 */ void checkRemoveJoint(int);
static void* mCutNameList[15];
static char* mCutNameList[15];
static u8 mCutList[180];
private:
@ -89,50 +89,16 @@ private:
STATIC_ASSERT(sizeof(daNpc_Besu_c) == 0x1138);
struct daNpc_Besu_HIOParam {
/* 0x00 */ daNpcT_HIOParam common;
/* 0x8C */ f32 field_0x8c;
};
class daNpc_Besu_Param_c {
public:
/* 8053E6E8 */ ~daNpc_Besu_Param_c();
struct Data {
/* 0x00 */ f32 field_0x00;
/* 0x04 */ f32 field_0x04;
/* 0x08 */ f32 field_0x08;
/* 0x0C */ f32 field_0x0c;
/* 0x10 */ f32 field_0x10;
/* 0x14 */ f32 field_0x14;
/* 0x18 */ f32 field_0x18;
/* 0x1C */ f32 field_0x1c;
/* 0x20 */ u32 field_0x20;
/* 0x24 */ u32 field_0x24;
/* 0x28 */ f32 field_0x28;
/* 0x2C */ f32 field_0x2c;
/* 0x30 */ f32 field_0x30;
/* 0x34 */ f32 field_0x34;
/* 0x38 */ f32 field_0x38;
/* 0x3C */ f32 field_0x3c;
/* 0x40 */ f32 field_0x40;
/* 0x44 */ f32 field_0x44;
/* 0x48 */ u32 field_0x48;
/* 0x4C */ u32 field_0x4c;
/* 0x50 */ f32 field_0x50;
/* 0x54 */ u32 field_0x54;
/* 0x58 */ u32 field_0x58;
/* 0x5C */ u32 field_0x5c;
/* 0x60 */ u32 field_0x60;
/* 0x64 */ u32 field_0x64;
/* 0x68 */ u32 field_0x68;
/* 0x6C */ f32 field_0x6c;
/* 0x70 */ f32 field_0x70;
/* 0x74 */ u32 field_0x74;
/* 0x78 */ f32 field_0x78;
/* 0x7C */ f32 field_0x7c;
/* 0x80 */ f32 field_0x80;
/* 0x84 */ f32 field_0x84;
/* 0x88 */ f32 field_0x88;
/* 0x8C */ f32 field_0x8c;
};
static const Data m;
static const daNpc_Besu_HIOParam m;
};
#endif /* D_A_NPC_BESU_H */

View File

@ -376,52 +376,36 @@ SECTION_DATA static u8 l_bmdData[48] = {
};
/* 8053EBAC-8053EC14 -00001 0068+00 0/1 0/0 0/0 .data l_evtList */
#pragma push
#pragma force_active on
SECTION_DATA static void* l_evtList[26] = {
(void*)&d_a_npc_besu__stringBase0,
(void*)NULL,
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0x1),
(void*)NULL,
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0xD),
(void*)0x0000000B,
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0x27),
(void*)0x0000000B,
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0x41),
(void*)0x00000004,
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0x5E),
(void*)0x00000004,
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0x7B),
(void*)0x00000004,
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0x98),
(void*)0x00000009,
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0xAE),
(void*)NULL,
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0xB9),
(void*)0x00000006,
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0xC2),
(void*)0x00000005,
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0xDD),
(void*)0x0000000A,
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0xE3),
(void*)0x00000005,
static daNpcT_evtData_c l_evtList[13] = {
{"", 0},
{"NO_RESPONSE", 0},
{"CONVERSATION_ABOUT_SARU01", 11},
{"CONVERSATION_ABOUT_SARU02", 11},
{"CONVERSATION_ABOUT_PACHINKO1", 4},
{"CONVERSATION_ABOUT_PACHINKO2", 4},
{"CONVERSATION_ABOUT_PACHINKO3", 4},
{"CACARICO_CONVERSATION", 9},
{"DEMO13_STB", 0},
{"SURPRISE", 6},
{"CONVERSATION_ABOUT_DEATHMT", 5},
{"NURSE", 10},
{"CONVERSATION_ABOUT_ZORA", 5},
};
#pragma pop
/* 8053EC14-8053EC44 -00001 0030+00 3/4 0/0 0/0 .data l_resNameList */
SECTION_DATA static void* l_resNameList[12] = {
(void*)&d_a_npc_besu__stringBase0,
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0xFB),
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0x100),
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0x108),
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0x10E),
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0x114),
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0x11A),
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0x120),
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0x128),
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0x12D),
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0x133),
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0x138),
static char* l_resNameList[12] = {
"",
"Besu",
"Besu_TW",
"Besu0",
"Besu1",
"Besu2",
"Besu3",
"Besu_p1",
"Len1",
"Taro1",
"Lud2",
"Sera",
};
/* 8053EC44-8053EC48 0000E8 0004+00 1/0 0/0 0/0 .data l_loadResPtrn0 */
@ -598,22 +582,22 @@ static daNpcT_MotionSeqMngr_c::sequenceStepData_c l_motionSequenceData[120] = {
};
/* 8053F744-8053F780 -00001 003C+00 1/1 0/0 0/0 .data mCutNameList__12daNpc_Besu_c */
SECTION_DATA void* daNpc_Besu_c::mCutNameList[15] = {
(void*)&d_a_npc_besu__stringBase0,
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0x13D),
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0x155),
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0x171),
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0x18C),
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0x198),
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0x1A4),
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0x98),
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0xB9),
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0x1B0),
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0xC2),
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0x1C6),
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0xDD),
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0x1DF),
(void*)(((char*)&d_a_npc_besu__stringBase0) + 0x1E9),
char* daNpc_Besu_c::mCutNameList[15] = {
"",
"CONVERSATION_ABOUT_SARU",
"CONVERSATION_ABOUT_PACHINKO",
"CONVERSATION_ABOUT_WOODSWD",
"SWDTUTORIAL",
"FIND_MONKEY",
"GET_WOODSWD",
"CACARICO_CONVERSATION",
"SURPRISE",
"CONVERSATION_IN_HOTEL",
"CONVERSATION_ABOUT_DEATHMT",
"CONVERSATION_ABOUT_GORON",
"NURSE",
"CLOTH_TRY",
"THANK_YOU",
};
/* 8053F780-8053F78C -00001 000C+00 0/1 0/0 0/0 .data @3908 */
@ -1235,7 +1219,7 @@ daNpc_Besu_c::~daNpc_Besu_c() {
/* ############################################################################################## */
/* 8053E754-8053E7E4 000000 0090+00 13/13 0/0 0/0 .rodata m__18daNpc_Besu_Param_c */
daNpc_Besu_Param_c::Data const daNpc_Besu_Param_c::m = {
const daNpc_Besu_HIOParam daNpc_Besu_Param_c::m = {
160.0f,
-3.0f,
1.0f,
@ -1244,8 +1228,8 @@ daNpc_Besu_Param_c::Data const daNpc_Besu_Param_c::m = {
140.0f,
35.0f,
30.0f,
0x00000000,
0x00000000,
0.0f,
0.0f,
10.0f,
-10.0f,
30.0f,
@ -1254,18 +1238,24 @@ daNpc_Besu_Param_c::Data const daNpc_Besu_Param_c::m = {
-45.0f,
0.6f,
12.0f,
0x00030006,
0x00050006,
3,
6,
5,
6,
110.0f,
0x00000000,
0x00000000,
0x00000000,
0x003C0008,
0x00000000,
0x00000000,
0.0f,
0.0f,
0.0f,
60,
8,
0,
0,
0,
0,
0,
4.0f,
-15.0f,
0x00000000,
0.0f,
-15.0f,
15.0f,
30.0f,

View File

@ -1,4 +1,6 @@
#
# Version v2.0
#
# Author: YunataSavior
# Brief: Converts byte-array anm data into their proper forms.
#
@ -19,17 +21,26 @@ MOTION_TYPE = "daNpcT_motionAnmData_c l_motionAnmData"
MOTION_PATTERN = r'SECTION_DATA static u8 l_motionAnmData\[\d+\] = {'
SEQ_FACE_MOTION_TYPE = "daNpcT_MotionSeqMngr_c::sequenceStepData_c l_faceMotionSequenceData"
SEQ_FACE_MOTION_PATTERN = "SECTION_DATA static u8 l_faceMotionSequenceData\[\d+\] = {"
SEQ_FACE_MOTION_PATTERN = r'SECTION_DATA static u8 l_faceMotionSequenceData\[\d+\] = {'
SEQ_MOTION_TYPE = "daNpcT_MotionSeqMngr_c::sequenceStepData_c l_motionSequenceData"
SEQ_MOTION_PATTERN = "SECTION_DATA static u8 l_motionSequenceData\[\d+\] = {"
SEQ_MOTION_PATTERN = r'SECTION_DATA static u8 l_motionSequenceData\[\d+\] = {'
HEAP_SIZE_TYPE = "int const heapSize"
HEAP_SIZE_PATTERN = "SECTION_RODATA static u8 const heapSize\[\d+\] = {"
HEAP_SIZE_PATTERN = r'SECTION_RODATA static u8 const heapSize\[\d+\] = {'
PARAM_TYPE = "::m"
PARAM_PATTERN = r'SECTION_RODATA u8 const (\w+_Param_c)::m\[\d+\] = {'
EVT_LIST_PATTERN = r'SECTION_DATA static void\* l_evtList\[\d+\] = {'
RES_NAME_PATTERN = r'SECTION_DATA static void\* l_resNameList\[\d+\] = {'
CUT_NAME_PATTERN = r'SECTION_DATA void\* ([a-zA-Z_][a-zA-Z0-9_]*)::mCutNameList\[(\d+)\] = \{'
VOID_PTR_INT_PATTERN = r'\(void\*\)(NULL|0x[0-9A-Fa-f]+)'
STRING_BASE_PATTERN = r'^SECTION_DEAD static char const\* const stringBase_([0-9A-Fa-f]+)\s*=\s*(".*?");'
STR_NO_OFFSET_PATTERN = r'\(void\*\)&([a-zA-Z0-9_]+)__stringBase0'
STR_WITH_OFFSET_PATTERN = r'\(void\*\)\(\(\(char\*\)&([a-zA-Z0-9_]+)__stringBase0\) \+ 0x([0-9A-Fa-f]+)\)'
def unsigned_val(hexstr):
value = int(hexstr, 16)
@ -70,7 +81,7 @@ def float_to_hex(f):
return f"{d:08X}"
def handle_npc_param(byte_collection, param_name, type):
def handle_npc_param(byte_collection, param_name, type, no_auto_float):
my_len = len(byte_collection)
if my_len % 4 != 0:
print(f"Error: len() = '{my_len}' isn't divisble by 4")
@ -79,9 +90,13 @@ def handle_npc_param(byte_collection, param_name, type):
# Special handling.
instr_arr = []
common_name = ""
is_raw = False
if type is None:
print("ERROR: --type <type> must be specified")
sys.exit(1)
elif type == "raw":
print("// Make sure the type isn't actually daNpcT nor daNpcF.")
is_raw = True
elif type == "daNpcT":
common_name = "daNpcT_HIOParam"
instr_arr = [
@ -142,6 +157,7 @@ def handle_npc_param(byte_collection, param_name, type):
hexstr = ""
res_array = []
common_size = 0
prms_is_float: list[bool] = []
while ptr < my_len:
curbyte = byte_collection[ptr]
ptr += 1
@ -164,6 +180,11 @@ def handle_npc_param(byte_collection, param_name, type):
val = twos_complement(hexstr, exp_bytes*8)
res_array.append(val)
elif my_type == 'h':
if is_raw or common_size != 0:
if no_auto_float:
prms_is_float.append(False)
else:
prms_is_float.append(prm_is_float(hexstr))
res_array.append("0x" + hexstr)
elif my_type == 'f':
fvalue = hex_to_float(hexstr)
@ -176,23 +197,25 @@ def handle_npc_param(byte_collection, param_name, type):
sys.exit(1)
hexstr = ""
if common_size == 0:
if not is_raw and common_size == 0:
cur_instr += 1
if cur_instr == len(instr_arr):
if not is_raw and cur_instr == len(instr_arr):
if common_size == 0:
common_size = ptr
assert common_size != 0, "Param array is too short for specified type"
assert is_raw or common_size != 0, "Param array is too short for specified type"
hio_name = re.sub(r'_Param_c$', '_HIOParam', param_name)
res_str = "// Must be put OUTSIDE {}:\n".format(param_name)
res_str += "struct {} {{\n".format(hio_name)
idx = common_size
res_str += " /* 0x00 */ {} common;\n".format(common_name)
if not is_raw:
res_str += " /* 0x00 */ {} common;\n".format(common_name)
while idx < my_len:
upper = f'{idx:02X}'
lower = f'{idx:02x}'
res_str += " /* 0x{} */ u32 field_0x{};\n".format(upper, lower)
mych = 'f' if (prms_is_float[int((idx-common_size) / 4)] is True) else 'u'
res_str += " /* 0x{} */ {}32 field_0x{};\n".format(upper, mych, lower)
idx += 4
res_str += "};\n\n"
@ -201,6 +224,7 @@ def handle_npc_param(byte_collection, param_name, type):
res_str += "const {} {}::m".format(hio_name, param_name)
res_str += " = {\n"
cur_pos = 0
for value in res_array:
res_str += " "
@ -209,8 +233,20 @@ def handle_npc_param(byte_collection, param_name, type):
elif isinstance(value, float):
res_str += str(value) + "f"
else:
res_str += value
adj_pos = cur_pos - len(instr_arr)
if adj_pos >= 0 and prms_is_float[adj_pos] is True:
fvalue = hex_to_float(value[2:])
fvalue = round(fvalue, 6)
res_str += f"{fvalue}f"
chk_val = "0x" + float_to_hex(fvalue)
# Sanity check in case rounding is too aggressive:
assert chk_val == value, f"chk_val {chk_val} != value {value}"
# if prmfloat_dbg is True:
# res_str += f" // {value}"
else:
res_str += value
res_str += ",\n"
cur_pos += 1
res_str += "};\n"
print(res_str)
@ -340,7 +376,29 @@ def build_anm_struct(byte_collection, anm_type):
print(res_str)
def run_beautify_anm_data(in_file, type=None):
def handle_charptr_array(int_collection, charptr_collection, charptr_type, class_name):
res_str = ""
if charptr_type == "l_evtList":
assert len(charptr_collection) == len(int_collection)
res_str += f"static daNpcT_evtData_c l_evtList[{len(charptr_collection)}] = {{\n"
elif charptr_type == "l_resNameList":
res_str += f"static char* l_resNameList[{len(charptr_collection)}] = {{\n"
elif charptr_type == "mCutNameList":
res_str += f"char* {class_name}::mCutNameList[{len(charptr_collection)}] = {{\n"
else:
raise Exception(f"Unknown charptr_type \"{charptr_type}\"")
for idx in range(len(charptr_collection)):
if charptr_type == "l_evtList":
res_str += f" {{{charptr_collection[idx]}, {int_collection[idx]}}},\n"
else:
res_str += f" {charptr_collection[idx]},\n"
res_str += "};\n"
print(res_str)
def run_beautify_anm_data(in_file, type=None, no_auto_float=False):
# Check if the file exists
if not os.path.isfile(in_file):
print(f"Error: File '{in_file}' not found.")
@ -351,16 +409,38 @@ def run_beautify_anm_data(in_file, type=None):
lines = fConts.splitlines()
in_byte_array = False
in_charptr_array = False
byte_collection = []
charptr_collection = []
int_collection = []
anm_type = ""
charptr_type = ""
param_name = ""
class_name = ""
str_lit_start = 0
strlit_map = {}
for line in lines:
words = line.split()
if len(words) == 0:
continue
if in_byte_array is False:
sb_match = re.search(STRING_BASE_PATTERN, line)
if sb_match:
addr = sb_match.group(1)
string_lit = sb_match.group(2)
addr_int = unsigned_val(addr)
offset = 0
if str_lit_start == 0:
str_lit_start = addr_int
else:
offset = addr_int - str_lit_start
# print(f"Address: 0x{addr}, Offset: {offset} String: {string_lit}")
strlit_map[offset] = string_lit
continue
if in_byte_array is False and in_charptr_array is False:
if re.search(FACE_MOTION_PATTERN, line):
in_byte_array = True
anm_type = FACE_MOTION_TYPE
@ -376,6 +456,17 @@ def run_beautify_anm_data(in_file, type=None):
elif re.search(HEAP_SIZE_PATTERN, line):
in_byte_array = True
anm_type = HEAP_SIZE_TYPE
elif re.search(EVT_LIST_PATTERN, line):
in_charptr_array = True
charptr_type = "l_evtList"
elif re.search(RES_NAME_PATTERN, line):
in_charptr_array = True
charptr_type = "l_resNameList"
elif match := re.search(CUT_NAME_PATTERN, line):
in_charptr_array = True
class_name = match.group(1)
# print(f"Class: {class_name}, Array Size: {match.group(2)}")
charptr_type = "mCutNameList"
else:
match = re.search(PARAM_PATTERN, line)
if match:
@ -384,18 +475,47 @@ def run_beautify_anm_data(in_file, type=None):
param_name = match.group(1)
else:
if words[0] == '};':
if anm_type == PARAM_TYPE:
handle_npc_param(byte_collection, param_name, type)
if in_byte_array:
if anm_type == PARAM_TYPE:
handle_npc_param(byte_collection, param_name, type, no_auto_float)
else:
build_anm_struct(byte_collection, anm_type)
in_byte_array = False
byte_collection.clear()
else:
build_anm_struct(byte_collection, anm_type)
in_byte_array = False
byte_collection.clear()
handle_charptr_array(int_collection, charptr_collection, charptr_type, class_name)
int_collection.clear()
charptr_collection.clear()
in_charptr_array = False
else:
bytes = re.split(r'[,\s]+', line)
for byte in bytes:
if (len(byte) == 0):
continue
byte_collection.append(byte)
if in_byte_array:
bytes = re.split(r'[,\s]+', line)
for byte in bytes:
if (len(byte) == 0):
continue
byte_collection.append(byte)
else:
if re.search(STR_NO_OFFSET_PATTERN, line):
# symbol = match_no_offset.group(1)
offset = 0
# print(f"Symbol: {symbol}, Offset: {offset}")
charptr_collection.append(strlit_map[offset])
elif match_offset := re.search(STR_WITH_OFFSET_PATTERN, line):
# symbol = match_offset.group(1)
offset = int(match_offset.group(2), 16)
# print(f"Symbol: {symbol}, Offset: {offset}")
charptr_collection.append(strlit_map[offset])
elif vip_match := re.search(VOID_PTR_INT_PATTERN, line):
assert charptr_type == "l_evtList"
value_str = vip_match.group(1)
if value_str == 'NULL':
value = 0
else:
value = int(value_str, 16)
# print(f"Parsed Value: {value}")
int_collection.append(value)
else:
raise Exception(f"ptr parsing: unknown line type: \"{line}\"")
# End of for loop.
fDesc.close()