import struct import click import sys import os import re import subprocess # Enum mappings cCcD_ObjAtType = { 0x00000002: "AT_TYPE_NORMAL_SWORD", 0x00000004: "AT_TYPE_HORSE", 0x00000008: "AT_TYPE_THROW_OBJ", 0x00000010: "AT_TYPE_SHIELD_ATTACK", 0x00000020: "AT_TYPE_BOMB", 0x00000040: "AT_TYPE_40", 0x00000080: "AT_TYPE_SLINGSHOT", 0x00000200: "AT_TYPE_LANTERN_SWING", 0x00000400: "AT_TYPE_CSTATUE_SWING", 0x00000800: "AT_TYPE_800", 0x00001000: "AT_TYPE_1000", 0x00002000: "AT_TYPE_ARROW", 0x00004000: "AT_TYPE_HOOKSHOT", 0x00010000: "AT_TYPE_BOOMERANG", 0x00040000: "AT_TYPE_40000", 0x00080000: "AT_TYPE_SPINNER", 0x00100000: "AT_TYPE_CSTATUE_BOSS_SWING", 0x00200000: "AT_TYPE_HEAVY_BOOTS", 0x00400000: "AT_TYPE_IRON_BALL", 0x00800000: "AT_TYPE_COPY_ROD", 0x01000000: "AT_TYPE_1000000", 0x04000000: "AT_TYPE_MASTER_SWORD", 0x08000000: "AT_TYPE_MIDNA_LOCK", 0x10000000: "AT_TYPE_10000000", 0x40000000: "AT_TYPE_WOLF_CUT_TURN", 0x80000000: "AT_TYPE_WOLF_ATTACK", 0xD8000000: "AT_TYPE_UNK" } dCcD_hitSe = { 0x0: "dCcD_SE_NONE", 0x1: "dCcD_SE_SWORD", 0x2: "dCcD_SE_SHIELD_ATTACK", 0x3: "dCcD_SE_WOLF_KICK", 0x4: "dCcD_SE_WOLF_BITE", 0x5: "dCcD_SE_WOOD", 0x6: "dCcD_SE_HAMMER", 0x7: "dCcD_SE_ARROW_STICK", 0x8: "dCcD_SE_HOOKSHOT_STICK", 0x9: "dCcD_SE_METAL", 0xA: "dCcD_SE_STONE", 0xB: "dCcD_SE_HARD_BODY", 0xC: "dCcD_SE_SOFT_BODY", 0xD: "dCcD_SE_13", 0xE: "dCcD_SE_SWORD_STAB", 0xF: "dCcD_SE_15", 0x10: "dCcD_SE_SWORD_RUN", 0x11: "dCcD_SE_17", 0x12: "dCcD_SE_THROW_OBJ", 0x13: "dCcD_SE_SPINNER", 0x14: "dCcD_SE_COPYROD", 0x15: "dCcD_SE_STATUE_HAMMER", 0x16: "dCcD_SE_PACHINKO", 0x17: "dCcD_SE_23" } def unpack_cylinder_data(data): # Verify data length is correct if len(data) != 68: print("Invalid data length for cylinder: %d" % len(data)) print("Cylinder data (dCcD_SrcCyl) should be 68 bytes long.") return None # dCcD_SrcGObjInf mFlags, = struct.unpack('>I', bytes(data[:4])) mObjAt_mType, mObjAt_mAtp, mObjAt_mBase = struct.unpack('>lBxxxl', bytes(data[4:16])) mObjTg_mType, mObjTg_mBase = struct.unpack('>Il', bytes(data[16:24])) mObjCo_mBase, = struct.unpack('>l', bytes(data[24:28])) mGObjAt_mSe, mGObjAt_mHitMark, mGObjAt_mSpl, mGObjAt_mMtrl, mGObjAt_mGFlag = struct.unpack('>4BI', bytes(data[28:36])) mGObjTg_mSe, mGObjTg_mHitMark, mGObjTg_mSpl, mGObjTg_mMtrl, mGObjTg_mGFlag = struct.unpack('>4BI', bytes(data[36:44])) mGObjCo_mGFlag, = struct.unpack('>I', bytes(data[44:48])) # Swap in enums for known values mObjAt_mType = cCcD_ObjAtType.get(mObjAt_mType, hex(mObjAt_mType)) mGObjAt_mSe = dCcD_hitSe.get(mGObjAt_mSe, hex(mGObjAt_mSe)) mGObjTg_mSe = dCcD_hitSe.get(mGObjTg_mSe, hex(mGObjTg_mSe)) # cM3dGCylS mCenter_x, mCenter_y, mCenter_z, mRadius, mHeight = struct.unpack('>3f2f', bytes(data[48:68])) return { "mFlags": mFlags, "mObjAt": (mObjAt_mType, mObjAt_mAtp, mObjAt_mBase), "mObjTg": (mObjTg_mType, mObjTg_mBase), "mObjCo": mObjCo_mBase, "mGObjAt": (mGObjAt_mSe, mGObjAt_mHitMark, mGObjAt_mSpl, mGObjAt_mMtrl, mGObjAt_mGFlag), "mGObjTg": (mGObjTg_mSe, mGObjTg_mHitMark, mGObjTg_mSpl, mGObjTg_mMtrl, mGObjTg_mGFlag), "mGObjCo": mGObjCo_mGFlag, "mCenter": (mCenter_x, mCenter_y, mCenter_z), "mRadius": mRadius, "mHeight": mHeight } def unpack_sphere_data(data): # Verify data length is correct if len(data) != 64: print("Invalid data length for sphere: %d" % len(data)) print("Sphere data (dCcD_SrcSph) should be 64 bytes long.") return None # dCcD_SrcGObjInf mFlags, = struct.unpack('>I', bytes(data[:4])) mObjAt_mType, mObjAt_mAtp, mObjAt_mBase = struct.unpack('>lBxxxl', bytes(data[4:16])) mObjTg_mType, mObjTg_mBase = struct.unpack('>Il', bytes(data[16:24])) mObjCo_mBase, = struct.unpack('>l', bytes(data[24:28])) mGObjAt_mSe, mGObjAt_mHitMark, mGObjAt_mSpl, mGObjAt_mMtrl, mGObjAt_mGFlag = struct.unpack('>4BI', bytes(data[28:36])) mGObjTg_mSe, mGObjTg_mHitMark, mGObjTg_mSpl, mGObjTg_mMtrl, mGObjTg_mGFlag = struct.unpack('>4BI', bytes(data[36:44])) mGObjCo_mGFlag, = struct.unpack('>I', bytes(data[44:48])) # Swap in enums for known values mObjAt_mType = cCcD_ObjAtType.get(mObjAt_mType, hex(mObjAt_mType)) mGObjAt_mSe = dCcD_hitSe.get(mGObjAt_mSe, hex(mGObjAt_mSe)) mGObjTg_mSe = dCcD_hitSe.get(mGObjTg_mSe, hex(mGObjTg_mSe)) # cM3dGSphS mCenter_x, mCenter_y, mCenter_z, mRadius = struct.unpack('>3f1f', bytes(data[48:64])) return { "mFlags": mFlags, "mObjAt": (mObjAt_mType, mObjAt_mAtp, mObjAt_mBase), "mObjTg": (mObjTg_mType, mObjTg_mBase), "mObjCo": mObjCo_mBase, "mGObjAt": (mGObjAt_mSe, mGObjAt_mHitMark, mGObjAt_mSpl, mGObjAt_mMtrl, mGObjAt_mGFlag), "mGObjTg": (mGObjTg_mSe, mGObjTg_mHitMark, mGObjTg_mSpl, mGObjTg_mMtrl, mGObjTg_mGFlag), "mGObjCo": mGObjCo_mGFlag, "mCenter": (mCenter_x, mCenter_y, mCenter_z), "mRadius": mRadius } def unpack_triangle_data(data): # Verify data length is correct if len(data) != 84: print("Invalid data length for triangle: %d" % len(data)) print("Triangle data (dCcD_SrcTri) should be 84 bytes long.") return None # dCcD_SrcGObjInf mFlags, = struct.unpack('>I', bytes(data[:4])) mObjAt_mType, mObjAt_mAtp, mObjAt_mBase = struct.unpack('>lBxxxl', bytes(data[4:16])) mObjTg_mType, mObjTg_mBase = struct.unpack('>Il', bytes(data[16:24])) mObjCo_mBase, = struct.unpack('>l', bytes(data[24:28])) mGObjAt_mSe, mGObjAt_mHitMark, mGObjAt_mSpl, mGObjAt_mMtrl, mGObjAt_mGFlag = struct.unpack('>4BI', bytes(data[28:36])) mGObjTg_mSe, mGObjTg_mHitMark, mGObjTg_mSpl, mGObjTg_mMtrl, mGObjTg_mGFlag = struct.unpack('>4BI', bytes(data[36:44])) mGObjCo_mGFlag, = struct.unpack('>I', bytes(data[44:48])) # Swap in enums for known values mObjAt_mType = cCcD_ObjAtType.get(mObjAt_mType, hex(mObjAt_mType)) mGObjAt_mSe = dCcD_hitSe.get(mGObjAt_mSe, hex(mGObjAt_mSe)) mGObjTg_mSe = dCcD_hitSe.get(mGObjTg_mSe, hex(mGObjTg_mSe)) # cM3dGTriS a_x, a_y, a_z, b_x, b_y, b_z, c_x, c_y, c_z = struct.unpack('>3f3f3f', bytes(data[48:84])) return { "mFlags": mFlags, "mObjAt": (mObjAt_mType, mObjAt_mAtp, mObjAt_mBase), "mObjTg": (mObjTg_mType, mObjTg_mBase), "mObjCo": mObjCo_mBase, "mGObjAt": (mGObjAt_mSe, mGObjAt_mHitMark, mGObjAt_mSpl, mGObjAt_mMtrl, mGObjAt_mGFlag), "mGObjTg": (mGObjTg_mSe, mGObjTg_mHitMark, mGObjTg_mSpl, mGObjTg_mMtrl, mGObjTg_mGFlag), "mGObjCo": mGObjCo_mGFlag, "a": (a_x, a_y, a_z), "b": (b_x, b_y, b_z), "c": (c_x, c_y, c_z), } def unpack_capsule_data(data): # Verify data length is correct if len(data) != 76: print("Invalid data length for capsule: %d" % len(data)) print("Capsule data (dCcD_SrcCps) should be 76 bytes long.") return None # dCcD_SrcGObjInf mFlags, = struct.unpack('>I', bytes(data[:4])) mObjAt_mType, mObjAt_mAtp, mObjAt_mBase = struct.unpack('>lBxxxl', bytes(data[4:16])) mObjTg_mType, mObjTg_mBase = struct.unpack('>Il', bytes(data[16:24])) mObjCo_mBase, = struct.unpack('>l', bytes(data[24:28])) mGObjAt_mSe, mGObjAt_mHitMark, mGObjAt_mSpl, mGObjAt_mMtrl, mGObjAt_mGFlag = struct.unpack('>4BI', bytes(data[28:36])) mGObjTg_mSe, mGObjTg_mHitMark, mGObjTg_mSpl, mGObjTg_mMtrl, mGObjTg_mGFlag = struct.unpack('>4BI', bytes(data[36:44])) mGObjCo_mGFlag, = struct.unpack('>I', bytes(data[44:48])) # Swap in enums for known values mObjAt_mType = cCcD_ObjAtType.get(mObjAt_mType, hex(mObjAt_mType)) mGObjAt_mSe = dCcD_hitSe.get(mGObjAt_mSe, hex(mGObjAt_mSe)) mGObjTg_mSe = dCcD_hitSe.get(mGObjTg_mSe, hex(mGObjTg_mSe)) # cM3dGTriS mStart_x, mStart_y, mStart_z, mEnd_x, mEnd_y, mEnd_z, mRadius = struct.unpack('>3f3f1f', bytes(data[48:76])) return { "mFlags": mFlags, "mObjAt": (mObjAt_mType, mObjAt_mAtp, mObjAt_mBase), "mObjTg": (mObjTg_mType, mObjTg_mBase), "mObjCo": mObjCo_mBase, "mGObjAt": (mGObjAt_mSe, mGObjAt_mHitMark, mGObjAt_mSpl, mGObjAt_mMtrl, mGObjAt_mGFlag), "mGObjTg": (mGObjTg_mSe, mGObjTg_mHitMark, mGObjTg_mSpl, mGObjTg_mMtrl, mGObjTg_mGFlag), "mGObjCo": mGObjCo_mGFlag, "mStart": (mStart_x, mStart_y, mStart_z), "mEnd": (mEnd_x, mEnd_y, mEnd_z), "mRadius": mRadius, } # Fetch the byte data from the file def fetch_shape_data(filename, variable_name): with open(filename, 'r') as f: lines = f.readlines() # Find the start and end of the data start_index = None end_index = None section_rodata_present = False section_data_present = False for i, line in enumerate(lines): if variable_name in line: start_index = i if 'SECTION_RODATA' in line: section_rodata_present = True elif 'SECTION_DATA' in line: section_data_present = True if start_index is not None and '};' in line: end_index = i break if start_index is None or end_index is None: print(f"{variable_name} data not found in the file.") return None elif not section_rodata_present and not section_data_present: print(f"{variable_name} already setup!") return None # Extract the byte data byte_data = [] for line in lines[start_index + 1:end_index]: byte_values = line.strip().split(',') for value in byte_values: if value: byte_data.append(int(value, 16)) return ({ "data": byte_data, "section_rodata_present": section_rodata_present, "start_index": start_index, "end_index": end_index }) # Write the unpacked data back to the file def write_cylinder_shape_data(filename, data, variable_name, section_rodata_present, start_index, end_index): with open(filename, 'r') as f: lines = f.readlines() # Formatting the output const_keyword = "const " if section_rodata_present else "" formatted_output = [] formatted_output.append(f"{const_keyword}static dCcD_SrcCyl {variable_name} = {{\n") formatted_output.append(" {\n") # cCcD_SrcObj members formatted_output.append(f" {{{hex(data['mFlags'])}, {{{{{data['mObjAt'][0]}, {hex(data['mObjAt'][1])}, {hex(data['mObjAt'][2])}}}, {{{hex(data['mObjTg'][0])}, {hex(data['mObjTg'][1])}}}, {hex(data['mObjCo'])}}}}}, // mObj\n") # dCcD_SrcGObjAt members formatted_output.append(f" {{{data['mGObjAt'][0]}, {hex(data['mGObjAt'][1])}, {hex(data['mGObjAt'][2])}, {hex(data['mGObjAt'][3])}, {hex(data['mGObjAt'][4])}}}, // mGObjAt\n") # dCcD_SrcGObjTg members formatted_output.append(f" {{{data['mGObjTg'][0]}, {hex(data['mGObjTg'][1])}, {hex(data['mGObjTg'][2])}, {hex(data['mGObjTg'][3])}, {hex(data['mGObjTg'][4])}}}, // mGObjTg\n") # dCcD_SrcGObjCo members formatted_output.append(f" {{{hex(data['mGObjCo'])}}}, // mGObjCo\n") formatted_output.append(" }, // mObjInf\n") # cM3dGCylS members formatted_output.append(" {\n") formatted_output.append(f" {{{data['mCenter'][0]}f, {data['mCenter'][1]}f, {data['mCenter'][2]}f}}, // mCenter\n") formatted_output.append(f" {data['mRadius']}f, // mRadius\n") formatted_output.append(f" {data['mHeight']}f // mHeight\n") formatted_output.append(" } // mCyl\n") formatted_output.append("};\n") # Remove the compiler strip gate macro if it was present if 'COMPILER_STRIP_GATE' in lines[end_index+1]: del lines[end_index+1] # Replace the original section with the new formatted output lines[start_index:end_index+1] = formatted_output # Write the modified lines back to the file with open(filename, 'w') as f: f.writelines(lines) # Write the unpacked data back to the file def write_sphere_shape_data(filename, data, variable_name, section_rodata_present, start_index, end_index): with open(filename, 'r') as f: lines = f.readlines() # Formatting the output const_keyword = "const " if section_rodata_present else "" formatted_output = [] formatted_output.append(f"{const_keyword}static dCcD_SrcSph {variable_name} = {{\n") formatted_output.append(" {\n") # cCcD_SrcObj members formatted_output.append(f" {{{hex(data['mFlags'])}, {{{{{data['mObjAt'][0]}, {hex(data['mObjAt'][1])}, {hex(data['mObjAt'][2])}}}, {{{hex(data['mObjTg'][0])}, {hex(data['mObjTg'][1])}}}, {hex(data['mObjCo'])}}}}}, // mObj\n") # dCcD_SrcGObjAt members formatted_output.append(f" {{{data['mGObjAt'][0]}, {hex(data['mGObjAt'][1])}, {hex(data['mGObjAt'][2])}, {hex(data['mGObjAt'][3])}, {hex(data['mGObjAt'][4])}}}, // mGObjAt\n") # dCcD_SrcGObjTg members formatted_output.append(f" {{{data['mGObjTg'][0]}, {hex(data['mGObjTg'][1])}, {hex(data['mGObjTg'][2])}, {hex(data['mGObjTg'][3])}, {hex(data['mGObjTg'][4])}}}, // mGObjTg\n") # dCcD_SrcGObjCo members formatted_output.append(f" {{{hex(data['mGObjCo'])}}}, // mGObjCo\n") formatted_output.append(" }, // mObjInf\n") # cM3dGCylS members formatted_output.append(" {\n") formatted_output.append(f" {{{{{data['mCenter'][0]}f, {data['mCenter'][1]}f, {data['mCenter'][2]}f}}, {data['mRadius']}f}} // mSph\n") formatted_output.append(" } // mSphAttr\n") formatted_output.append("};\n") # Remove the compiler strip gate macro if it was present if 'COMPILER_STRIP_GATE' in lines[end_index+1]: del lines[end_index+1] # Replace the original section with the new formatted output lines[start_index:end_index+1] = formatted_output # Write the modified lines back to the file with open(filename, 'w') as f: f.writelines(lines) # Write the unpacked data back to the file def write_triangle_shape_data(filename, data, variable_name, section_rodata_present, start_index, end_index): with open(filename, 'r') as f: lines = f.readlines() # Formatting the output const_keyword = "const " if section_rodata_present else "" formatted_output = [] formatted_output.append(f"{const_keyword}static dCcD_SrcTri {variable_name} = {{\n") formatted_output.append(" {\n") # cCcD_SrcObj members formatted_output.append(f" {{{hex(data['mFlags'])}, {{{{{data['mObjAt'][0]}, {hex(data['mObjAt'][1])}, {hex(data['mObjAt'][2])}}}, {{{hex(data['mObjTg'][0])}, {hex(data['mObjTg'][1])}}}, {hex(data['mObjCo'])}}}}}, // mObj\n") # dCcD_SrcGObjAt members formatted_output.append(f" {{{data['mGObjAt'][0]}, {hex(data['mGObjAt'][1])}, {hex(data['mGObjAt'][2])}, {hex(data['mGObjAt'][3])}, {hex(data['mGObjAt'][4])}}}, // mGObjAt\n") # dCcD_SrcGObjTg members formatted_output.append(f" {{{data['mGObjTg'][0]}, {hex(data['mGObjTg'][1])}, {hex(data['mGObjTg'][2])}, {hex(data['mGObjTg'][3])}, {hex(data['mGObjTg'][4])}}}, // mGObjTg\n") # dCcD_SrcGObjCo members formatted_output.append(f" {{{hex(data['mGObjCo'])}}}, // mGObjCo\n") formatted_output.append(" }, // mObjInf\n") # cM3dGCylS members formatted_output.append(" {\n") formatted_output.append(f" {{{{{data['a'][0]}f, {data['a'][1]}f, {data['a'][2]}f}}, {{{data['b'][0]}f, {data['b'][1]}f, {data['b'][2]}f}}, {{{data['c'][0]}f, {data['c'][1]}f, {data['c'][2]}f}}}} // mTri\n") formatted_output.append(" } // mTriAttr\n") formatted_output.append("};\n") # Remove the compiler strip gate macro if it was present if 'COMPILER_STRIP_GATE' in lines[end_index+1]: del lines[end_index+1] # Replace the original section with the new formatted output lines[start_index:end_index+1] = formatted_output # Write the modified lines back to the file with open(filename, 'w') as f: f.writelines(lines) # Write the unpacked data back to the file def write_capsule_shape_data(filename, data, variable_name, section_rodata_present, start_index, end_index): with open(filename, 'r') as f: lines = f.readlines() # Formatting the output const_keyword = "const " if section_rodata_present else "" formatted_output = [] formatted_output.append(f"{const_keyword}static dCcD_SrcCps {variable_name} = {{\n") formatted_output.append(" {\n") # cCcD_SrcObj members formatted_output.append(f" {{{hex(data['mFlags'])}, {{{{{data['mObjAt'][0]}, {hex(data['mObjAt'][1])}, {hex(data['mObjAt'][2])}}}, {{{hex(data['mObjTg'][0])}, {hex(data['mObjTg'][1])}}}, {hex(data['mObjCo'])}}}}}, // mObj\n") # dCcD_SrcGObjAt members formatted_output.append(f" {{{data['mGObjAt'][0]}, {hex(data['mGObjAt'][1])}, {hex(data['mGObjAt'][2])}, {hex(data['mGObjAt'][3])}, {hex(data['mGObjAt'][4])}}}, // mGObjAt\n") # dCcD_SrcGObjTg members formatted_output.append(f" {{{data['mGObjTg'][0]}, {hex(data['mGObjTg'][1])}, {hex(data['mGObjTg'][2])}, {hex(data['mGObjTg'][3])}, {hex(data['mGObjTg'][4])}}}, // mGObjTg\n") # dCcD_SrcGObjCo members formatted_output.append(f" {{{hex(data['mGObjCo'])}}}, // mGObjCo\n") formatted_output.append(" }, // mObjInf\n") # cM3dGCylS members formatted_output.append(" {\n") formatted_output.append(f" {{{{{data['mStart'][0]}f, {data['mStart'][1]}f, {data['mStart'][2]}f}}, {{{data['mEnd'][0]}f, {data['mEnd'][1]}f, {data['mEnd'][2]}f}}, {data['mRadius']}f}}, // mCps\n") formatted_output.append(" } // mCpsAttr\n") formatted_output.append("};\n") # Remove the compiler strip gate macro if it was present if 'COMPILER_STRIP_GATE' in lines[end_index+1]: del lines[end_index+1] # Replace the original section with the new formatted output lines[start_index:end_index+1] = formatted_output # Write the modified lines back to the file with open(filename, 'w') as f: f.writelines(lines) def post_process(filename): """ Checks if we need to include d_cc_d header file, remove structs, remove functions and/or rename ctor/dtors. """ with open(filename, 'r') as f: lines = f.readlines() remove_structs = { "struct Vec", "struct cXyz", "struct dCcD_Stts", "struct dCcD_GStts", "struct dCcD_GObjInf", "struct dCcD_SrcSph" "struct dCcD_Cyl", "struct dCcD_Cyl", "struct dCcD_Sph", "struct dCcD_Cps", "struct dCcD_Tri", "struct dCcD_SrcSph", "struct dCcD_SrcCyl", "struct dCcD_SrcCps", "struct dCcD_SrcTri", "struct dCcD_GAtTgCoCommonBase", "struct cCcD_Obj", "struct cCcD_Stts", "struct cCcD_GStts", "struct cM3dGSph", "struct cM3dGPla", "struct cM3dGCyl", "struct cM3dGCps", "struct cM3dGAab", "struct cM3dGLin", "struct cM3dGTri", "struct Z2SeMgr", "struct JAISoundID", "struct Z2AudioMgr", "struct JGeometry" } remove_functions = { "void PSVECAdd();", "void PSVECSubtract();", "void PSVECSquareMag();", "void PSVECScale();", "void PSVECSquareDistance();", "void PSVECDotProduct();", "void PSVECCrossProduct();", "void C_VECReflect();", "void abs();", "void sin();", "void acos();", "void tan();", "u32 __float_nan;", "f32 G_CM3D_F_ABS_MIN", "u32 __float_max" } extern_c_replacements = { "asm cXyz::~cXyz()", "asm cM3dGPla::~cM3dGPla()", "cXyz::cXyz()", "asm cM3dGPla::~cM3dGPla()", "asm cM3dGCyl::~cM3dGCyl()", "asm cM3dGSph::~cM3dGSph()", "asm cM3dGAab::~cM3dGAab()", "asm dCcD_Sph::~dCcD_Sph()", "asm dCcD_Sph::dCcD_Sph()", "asm dCcD_GStts::~dCcD_GStts()", "asm cCcD_GStts::~cCcD_GStts()", "asm cXyz::cXyz(cXyz const& param_0)", "asm cXyz::cXyz(f32 param_0, f32 param_1, f32 param_2)", "asm void cXyz::set(f32 param_0, f32 param_1, f32 param_2)", "asm void cXyz::set(Vec const& param_0)", "asm void cXyz::operator=(cXyz const& param_0)", "asm void cXyz::operator+=(Vec const& param_0)", "JAISoundID::JAISoundID(u32 param_0)", # special case, needs manual replacement "asm dCcD_Cyl::~dCcD_Cyl()", "asm cM3dGLin::~cM3dGLin()", "asm dCcD_Cyl::dCcD_Cyl()", "asm dCcD_Stts::~dCcD_Stts()", "asm dCcD_Stts::dCcD_Stts()", "asm dCcD_Tri::~dCcD_Tri()", "asm dCcD_Tri::dCcD_Tri()", "asm cM3dGTri::~cM3dGTri()", "asm void cCcD_ObjHitInf::OnCoSetBit()", "asm void cXyz::abs()", "asm dCcD_Cps::~dCcD_Cps()", "asm dCcD_Cps::dCcD_Cps()" } include_line = False i = len(lines) - 1 while i >= 0: line = lines[i] if any(struct in line for struct in remove_structs): print(f"Removing struct at line {i}: {line}") include_line = True # Find the end of the struct data end_index = None brace_count = 0 for j in range(i, len(lines)): brace_count += lines[j].count('{') brace_count -= lines[j].count('}') if brace_count == 0: end_index = j break # Remove the struct data if end_index is not None: del lines[i:end_index+2] # rm struct and trailing newline i = end_index + 1 # Adjust i to skip over deleted lines elif any(function in line for function in remove_functions): print(f"Removing function at line {i}: {line}") include_line = True del lines[i] elif any(function in line for function in extern_c_replacements) and not line.startswith("//"): print(f"Replacing function at line {i}: {line}") include_line = True # Grab the mangled name from 4 lines above if "asm" in line: symbol_line = lines[i-4] else: symbol_line = lines[i-1] match = re.search(r'(\S+)\s+\*/$', symbol_line) if match: symbol = match.group(1) print("SYMBOL:", symbol) else: print("Symbol not found") # comment out original line lines[i] = f"// {lines[i]}" # Add new line after with extern "C" asm void lines.insert(i+1, f'extern "C" asm void {symbol}() {{\n') i -= 1 if include_line: # Find the first #include line include_index = next((i for i, line in enumerate(lines) if line.strip().startswith("#include")), None) if include_index is not None: # Insert the new header after the first #include line lines.insert(include_index + 1, '#include "d/cc/d_cc_d.h"\n') else: # If no #include line is found, insert at the beginning (or handle as you see fit) lines.insert(0, '#include "d/cc/d_cc_d.h"\n') # Write the modified lines back to the file with open(filename, 'w') as f: f.writelines(lines) def search_files(shape, size): ignore_files = [''] directories = ['rel', 'src'] pattern = re.compile(f'(SECTION_DATA|SECTION_RODATA).*static\s+u8\s+(const\s+)?(\w*{shape}\w*)\[{size}\]', re.I) file_matches = [] for directory in directories: for root, dirs, files in os.walk(directory): for file in files: if file.endswith('.cpp') and file not in ignore_files: filepath = os.path.join(root, file) with open(filepath, 'r') as f: contents = f.read() matches = pattern.findall(contents) if matches: for match in matches: # Extract the desired part of the match and append it to the file_matches list variable_name = match[2] file_matches.append((filepath, variable_name)) return file_matches def run_make_command(): command = "make all rels -j$(nproc) WINE=~/git/c/wibo/build/wibo" result = subprocess.run(command, shell=True) if result.returncode != 0: print("Failed to run make command") sys.exit(1) @click.command() @click.option('--shape', required=True, help='Shape to unpack. Should be on of: triangle, sphere, cylinder or capsule.') def process_file(shape): filenames = [] match shape.lower(): case "cylinder": filenames = search_files("cyl", 68) for filename in filenames: cylinder_data = None f_name = filename[0] variable_name = filename[1] data = fetch_shape_data(f_name, variable_name) if data is not None: cylinder_data = unpack_cylinder_data(data["data"]) if cylinder_data is not None: print("Updating", f_name) write_cylinder_shape_data(f_name, cylinder_data, variable_name, data["section_rodata_present"], data["start_index"], data["end_index"]) post_process(f_name) run_make_command() case "sphere": filenames = search_files("sph", 64) for filename in filenames: sphere_data = None f_name = filename[0] variable_name = filename[1] data = fetch_shape_data(f_name, variable_name) if data is not None: sphere_data = unpack_sphere_data(data["data"]) if sphere_data is not None: print("Updating", f_name) write_sphere_shape_data(f_name, sphere_data, variable_name, data["section_rodata_present"], data["start_index"], data["end_index"]) post_process(f_name) run_make_command() case "triangle": filenames = search_files("tri", 84) for filename in filenames: triangle_data = None f_name = filename[0] variable_name = filename[1] data = fetch_shape_data(f_name, variable_name) if data is not None: triangle_data = unpack_triangle_data(data["data"]) if triangle_data is not None: print("Updating", f_name) write_triangle_shape_data(f_name, triangle_data, variable_name, data["section_rodata_present"], data["start_index"], data["end_index"]) post_process(f_name) run_make_command() case "capsule": filenames = search_files("cps", 76) for filename in filenames: capsule_data = None f_name = filename[0] variable_name = filename[1] data = fetch_shape_data(f_name, variable_name) if data is not None: capsule_data = unpack_capsule_data(data["data"]) if capsule_data is not None: print("Updating", f_name) write_capsule_shape_data(f_name, capsule_data, variable_name, data["section_rodata_present"], data["start_index"], data["end_index"]) post_process(f_name) run_make_command() case _: raise ValueError(f"Unknown shape: {shape}") if __name__ == '__main__': process_file()