The recovered system: fire channels = LBE4ControlsManager buttonGroups (0x40/0x45/0x46/0x47); default groups = the per-mech type-6 controls-map resource in BTL4.RES, installed by the T0 CreateStreamedMappings the port already called -- it needed only the TriggerState attribute (id 0x13 PINNED to the binary value; fireImpulse@0x31C is the binary's TriggerState) and an input feed. Keyboard/harness now push press/release edges into the button groups; the gBT*Trigger bypasses, per-type keyboard split and 1,0 pulse hack are retired -- weapons sharing a button fire TOGETHER (madcat Trigger = 4 weapons). Myomers @4b9550/@4b95b8 misattribution corrected (they are MechWeapon ConfigureMappables/ChooseButton). Verified 2-node: kill through the authentic chain (12 hits vs ~36 pre-groups). Config-mode session (regrouping UI) = the remaining stage, KB-scoped. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
52 lines
2.0 KiB
Python
52 lines
2.0 KiB
Python
import struct,sys
|
|
|
|
def rdU16(b,p): return struct.unpack_from('<H',b,p)[0]
|
|
def rdU32(b,p): return struct.unpack_from('<I',b,p)[0]
|
|
def rdF32(b,p): return struct.unpack_from('<f',b,p)[0]
|
|
|
|
TAGNAME={0x0003:'HEADER',0x0005:'BIZ_DONE',0x0040:'OBJECT',0x0041:'LOD',0x0042:'PATCH',
|
|
0x0046:'PMESH',0x0047:'CONN_LIST',0x0048:'SPHERE_LIST',0x004d:'PCONN_LIST',0x0070:'BOUND',
|
|
0x0080:'VTX_XYZ',0x0081:'VTX_XYZ_N',0x0082:'VTX_XYZ_RGBA',0x0088:'VTX_XYZ_UV',
|
|
0x0089:'VTX_XYZ_N_UV',0x008A:'VTX_XYZ_RGBA_UV',0x2030:'SV_F_MATERIAL',0x2037:'SV_SPECIAL',
|
|
0x0010:'TEXTURE',0x0011:'TEXTURE_MAP',0x0018:'BITSLICE',0x0020:'MATERIAL',
|
|
0x0021:'MAT_TEXTURE',0x0023:'AMBIENT',0x0024:'DIFFUSE',0x0026:'EMISSIVE',
|
|
0x0028:'RAMP_REF',0x0030:'RAMP',0x0031:'RAMP_DATA',0x2008:'NAME',
|
|
0x0043:'FACE',0x0044:'FACE?',0x0045:'FACE?'}
|
|
CONTAINERS={0x0003,0x0070,0x0040,0x0041,0x0042,0x0046,0x0048,0x0010,0x0020,0x0030}
|
|
|
|
def parse(b,p,end,depth,out):
|
|
while p+3<=end:
|
|
tw=rdU16(b,p); p+=2
|
|
idv=tw & 0x2fff
|
|
lw=4 if (tw&0x8000) else (2 if (tw&0x4000) else 1)
|
|
if p+lw>end: break
|
|
ln = b[p] if lw==1 else (rdU16(b,p) if lw==2 else rdU32(b,p))
|
|
p+=lw
|
|
if p+ln>end: break
|
|
out.append((depth,idv,p,ln))
|
|
if idv in CONTAINERS:
|
|
parse(b,p,p+ln,depth+1,out)
|
|
p+=ln
|
|
if idv==0x0005: break
|
|
return
|
|
|
|
fn=sys.argv[1]
|
|
b=open(fn,'rb').read()
|
|
assert b[:8]==b'DIV-BIZ2', b[:8]
|
|
out=[]
|
|
parse(b,8,len(b),0,out)
|
|
for depth,idv,p,ln in out:
|
|
nm=TAGNAME.get(idv,'?%04x'%idv)
|
|
extra=''
|
|
if idv==0x2008 or idv==0x0011 or idv==0x0028:
|
|
s=b[p:p+ln].split(b'\0')[0].decode('latin1',errors='replace')
|
|
extra=' "%s"'%s
|
|
if idv==0x2037: # SV_SPECIAL
|
|
s=b[p:p+ln].split(b'\0')[0].decode('latin1',errors='replace')
|
|
extra=' SPECIAL="%s"'%s
|
|
if idv==0x2030: # SV_F_MATERIAL
|
|
s=b[p:p+ln].split(b'\0')[0].decode('latin1',errors='replace')
|
|
extra=' MAT="%s" (len %d)'%(s,ln)
|
|
if idv==0x0018 and ln>=1: extra=' slice=%d'%b[p]
|
|
print(' '*depth + '%-14s off=0x%04x len=%d%s'%(nm,p,ln,extra))
|