Skip to content

Instantly share code, notes, and snippets.

@Dragorn421
Created September 4, 2020 18:12
Show Gist options
  • Save Dragorn421/d4bfc1d2afb241faf7daee4ab6252a87 to your computer and use it in GitHub Desktop.
Save Dragorn421/d4bfc1d2afb241faf7daee4ab6252a87 to your computer and use it in GitHub Desktop.
oot decomp's ichaindis.py but it outputs (hardcoded) struct member names
#!/usr/bin/python3
import os
import sys
import struct
import argparse
ICHAIN_MACROS = [
'ICHAIN_U8',
'ICHAIN_S8',
'ICHAIN_U16',
'ICHAIN_S16',
'ICHAIN_U32',
'ICHAIN_S32',
'ICHAIN_F32',
'ICHAIN_F32_DIV1000',
'ICHAIN_VEC3F',
'ICHAIN_VEC3F_DIV1000',
'ICHAIN_VEC3S',
]
# dictionary mapping offset in Actor struct to the member name
# for example 0 -> id
# generated from the actor struct source with following regex replacement:
# " *\/\* +(0x[0-9a-fA-F]+) +\*\/[^\n;]*[ *]([^ *\n[]+)(?:\[[0-9a-fA-Fx]+\])?;(?: *\/\/[^\n]*)?" -> "\1: '\2',"
# then some substructs were split (PosRot), partly split (ActorShape) or removed (CollisionCheckInfo)
FIELD_NAMES = {
0x000: 'id',
0x002: 'type',
0x003: 'room',
0x004: 'flags',
0x008: 'initPosRot.pos',
0x014: 'initPosRot.rot',
0x01C: 'params',
0x01E: 'objBankIndex',
0x01F: 'unk_1F',
0x020: 'sfx',
0x024: 'posRot.pos',
0x030: 'posRot.rot',
0x038: 'posRot2.pos',
0x044: 'posRot2.rot',
0x04C: 'unk_4C',
0x050: 'scale',
0x05C: 'velocity',
0x068: 'speedXZ',
0x06C: 'gravity',
0x070: 'minVelocityY',
0x074: 'wallPoly',
0x078: 'floorPoly',
0x07C: 'wallPolySource',
0x07D: 'floorPolySource',
0x07E: 'wallPolyRot',
0x080: 'groundY',
0x084: 'waterY',
0x088: 'bgCheckFlags',
0x08A: 'yawTowardsLink',
0x08C: 'xyzDistFromLinkSq',
0x090: 'xzDistFromLink',
0x094: 'yDistFromLink',
0x0B4: 'shape.rot',
0x0CC: 'unk_CC',
0x0E4: 'projectedPos',
0x0F0: 'projectedW',
0x0F4: 'uncullZoneForward',
0x0F8: 'uncullZoneScale',
0x0FC: 'uncullZoneDownward',
0x100: 'pos4',
0x10C: 'unk_10C',
0x10D: 'unk_10D',
0x10E: 'textId',
0x110: 'freezeTimer',
0x112: 'dmgEffectParams',
0x114: 'dmgEffectTimer',
0x115: 'isDrawn',
0x116: 'unk_116',
0x117: 'naviEnemyId',
0x118: 'parent',
0x11C: 'child',
0x120: 'prev',
0x124: 'next',
0x128: 'init',
0x12C: 'destroy',
0x130: 'update',
0x134: 'draw',
0x138: 'overlayEntry',
}
def main():
parser = argparse.ArgumentParser(description='Decompiles an InitChain')
parser.add_argument('filename', help='ROM file path')
parser.add_argument('offset', help='ROM offset to an InitChain')
parser.add_argument('--no-names', help='Do not use struct names', action='store_true')
args = parser.parse_args()
romOff = int(args.offset, 16)
try:
with open(args.filename, 'rb') as f:
romData = f.read()
except IOError:
print('failed to read file ' + args.filename)
sys.exit(1)
print ('static InitChainEntry sInitChain[] = {')
while True:
entry = struct.unpack('>I', romData[romOff:romOff+4])[0]
romOff += 4
cont = entry >> 31
t = (entry >> 27) & 0xF
offset = ((entry) >> 16) & 0x7FF
value = (entry) & 0xFFFF
field_name = None
if not args.no_names:
field_name = FIELD_NAMES.get(offset)
if field_name is None:
field_name = 'unk_{:X}'.format(offset)
print(' {0}({1}, {2}, {3}),'.format(ICHAIN_MACROS[t], field_name, value, ('ICHAIN_CONTINUE' if cont == 1 else 'ICHAIN_STOP')))
if cont == 0:
break
print ('};')
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment