#!/usr/bin/env python3 import struct import argparse from filemap import FileResult, GetFromVRam, GetFromRom T_DEFAULT = '' T_SET3 = '_Set3' T_ACTOR = '_Actor' TYPE_ENUM = [ "COLTYPE_UNK0", "COLTYPE_UNK1", "COLTYPE_UNK2", "COLTYPE_UNK3", "COLTYPE_UNK4", "COLTYPE_UNK5", "COLTYPE_UNK6", "COLTYPE_UNK7", "COLTYPE_UNK8", "COLTYPE_METAL_SHIELD", "COLTYPE_UNK10", "COLTYPE_WOODEN_SHIELD", "COLTYPE_UNK12", "COLTYPE_UNK13" ] SHAPE_ENUM = [ "COLSHAPE_JNTSPH", "COLSHAPE_CYLINDER", "COLSHAPE_TRIS", "COLSHAPE_QUAD" ] sf_ColliderInit = ">BBBBBB" sf_ColliderInit_Set3 = ">BBBBB" sf_ColliderInit_Actor = ">IBBBB" sf_ColliderBodyInit = ">B3xIBB2xIBB2xBBB" sf_JntSph = ">II" sf_JntSphItem = ">Bx5h" sf_Cylinder16 = ">6h" sf_Tris = ">II" sf_TrisItem = ">9f" sf_Quad = ">12f" f_ColliderInit = "{{ {0}, 0x{1:02X}, 0x{2:02X}, 0x{3:02X}, 0x{4:02X}, {5} }}" f_ColliderInit_Set3 = "{{ {0}, 0x{1:02X}, 0x{2:02X}, 0x{3:02X}, {4} }}" f_ColliderInit_Actor = "{{ {0}, 0x{1:02X}, 0x{2:02X}, 0x{3:02X}, {4} }}" f_ColliderBodyInit = "{{ 0x{0:02X}, {{ 0x{1:08X}, 0x{2:02X}, 0x{3:02X} }}, {{ 0x{4:08X}, 0x{5:02X}, 0x{6:02X} }}, 0x{7:02X}, 0x{8:02X}, 0x{9:02X} }}" f_JntSph = "{0}, D_{1:08X}" f_JntSphItem = "{{ {0}, {{ {{ {1}, {2}, {3} }}, {4} }}, {5} }}" f_Cylinder16 = "{{ {0}, {1}, {2}, {{ {3}, {4}, {5} }} }}" f_Tris = "{0}, D_{1:08X}" f_TrisItem = "{{ {{ {{ {0}f, {1}f, {2}f }}, {{ {3}f, {4}f, {5}f }}, {{ {6}f, {7}f, {8}f }} }} }}" f_Quad = "{{ {{ {{ {0}f, {1}f, {2}f }}, {{ {3}f, {4}f, {5}f }}, {{ {6}f, {7}f, {8}f }}, {{ {9}f, {10}f, {11}f }} }} }}" def GetColliderFormat(type): if type == T_DEFAULT: return (sf_ColliderInit, f_ColliderInit) if type == T_SET3: return (sf_ColliderInit_Set3, f_ColliderInit_Set3) if type == T_ACTOR: return (sf_ColliderInit_Actor, f_ColliderInit_Actor) return None def GetColliderStr(data, off, type): cf = GetColliderFormat(type) cBase = list(struct.unpack_from(cf[0], data, off)) if type == T_ACTOR: if cBase[0] == 0: cBase[0] = 'NULL' else: cBase[0] = '0x{0:08X}'.format(cBase[0]) else: if cBase[0] < 14: cBase[0] = TYPE_ENUM[cBase[0]] else: cBase[0] = '0x{0:02X}'.format(cBase[0]) i = 4 if type == T_DEFAULT: i = 5 if cBase[i] < 4: cBase[i] = SHAPE_ENUM[cBase[i]] else: cBase[i] = '0x{0:02X}'.format(cBase[i]) return cf[1].format(*cBase); def GetItems(data, off, count, structf, fmt, size): result = '' for i in range(count): ioff = (i * size) cBody = struct.unpack_from(sf_ColliderBodyInit, data, off + ioff) cItem = struct.unpack_from(structf, data, off + 0x18 + ioff) result += ''' {{ {0}, {1}, }},'''.format(f_ColliderBodyInit.format(*cBody), fmt.format(*cItem)) return result def GetJntSphItems(data, off, count): items = GetItems(data, off, count, sf_JntSphItem, f_JntSphItem, 0x24) print(''' static ColliderJntSphItemInit sJntSphItemsInit[{0}] = {{{1} }}; '''.format(count, items)) def GetJntSph(data, off, type): sBase = GetColliderStr(data, off, type) cJntSph = struct.unpack_from(sf_JntSph, data, off + 8) print(''' static ColliderJntSphInit{0} sJntSphInit = {{ {1}, {2}, }}; '''.format(type, sBase, f_JntSph.format(*cJntSph))) def GetTrisItems(data, off, count): items = GetItems(data, off, count, sf_TrisItem, f_TrisItem, 0x24) print(''' static ColliderTrisItemInit sTrisItemsInit[{0}] = {{{1} }}; '''.format(count, items)) def GetCylinder(data, off, type): sBase = GetColliderStr(data, off, type) cBody = struct.unpack_from(sf_ColliderBodyInit, data, off + 0x08) cCyl16 = struct.unpack_from(sf_Cylinder16, data, off + 0x20) print(''' static ColliderCylinderInit{0} sCylinderInit = {{ {1}, {2}, {3}, }}; '''.format(type, sBase, f_ColliderBodyInit.format(*cBody),f_Cylinder16.format(*cCyl16))) def GetTris(data, off, type): sBase = GetColliderStr(data, off, type) cTris = struct.unpack_from(sf_Tris, data, off + 8) print(''' static ColliderTrisInit{0} sTrisInit = {{ {1}, {2}, }}; '''.format(type, sBase, f_Tris.format(*cTris))) def GetQuad(data, off, type): sBase = GetColliderStr(data, off, type) cBody = struct.unpack_from(sf_ColliderBodyInit, data, off + 0x08) cQuad = struct.unpack_from(sf_Quad, data, off + 0x20) print(''' static ColliderQuadInit{0} sQuadInit = {{ {1}, {2}, {3}, }}; '''.format(type, sBase, f_ColliderBodyInit.format(*cBody), f_Quad.format(*cQuad))) TYPE_DICT = { 'ColliderJntSphInit' : (GetJntSph, 'Shape', T_DEFAULT), 'ColliderCylinderInit' : (GetCylinder, 'Shape', T_DEFAULT), 'ColliderTrisInit': (GetTris, 'Shape', T_DEFAULT), 'ColliderQuadInit': (GetQuad, 'Shape', T_DEFAULT), 'ColliderJntSphItemInit' : (GetJntSphItems, 'Item'), 'ColliderTrisItemInit' : (GetTrisItems, 'Item') } update = [(k, v[0]) for k,v in TYPE_DICT.items() if v[1] == 'Shape'] for i in update: for j in (T_SET3, T_ACTOR): TYPE_DICT[i[0] + j] = (i[1], 'Shape', j) #ovlName = 'ovl_Obj_Comb' #address = 0x000780 #inputType = 'ColliderJntSphItemInit' #ovlName = 'ovl_En_Boom' #address = 0x0007D0 #inputType = 'ColliderQuadInit' #ovlName = input("Overlay Name (baserom): ") def HexParse(s): return int(s, 16) parser = argparse.ArgumentParser() parser.add_argument('address', help="VRam or Rom address of the struct", type=HexParse) parser.add_argument('type', help="Type name (e.g. ColliderQuadInit)") parser.add_argument('num', nargs='?', default=0, type=HexParse, help="Number of elements. Only applies to ItemInit types") args = parser.parse_args() fileResult = None if args.address >= 0x80000000: fileResult = GetFromVRam(args.address) else: fileResult = GetFromRom(args.address) if fileResult is None: print("Invalid address") exit() print(fileResult) selectedType = TYPE_DICT[args.type] arg2 = None if selectedType[1] == 'Shape': arg2 = selectedType[2] elif args.num > 0: arg2 = args.num else: print("ItemInit type must specify number of elements") exit() ovlFile = open("../../baserom/" + fileResult.name, "rb") ovlData = bytearray(ovlFile.read()) ovlFile.close() selectedType[0](ovlData, fileResult.offset, arg2)