tp/tools/setup_shape_data.py

677 lines
28 KiB
Python

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()