Files
BT411/scratchpad/dump_tsphere.py
arcattackandClaude Fable 5 8ed6184d65 Combat: AUTHENTIC weapon groups -- streamed per-mech button bindings + the real fire chain (task #5)
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>
2026-07-11 13:06:29 -05:00

55 lines
2.5 KiB
Python

import struct, math
data = open("content/VIDEO/GEO/TSPHERE.BGF","rb").read()
print("file bytes:", len(data))
TAGS = {0x0003:"HEADER",0x0005:"BIZ_DONE",0x0040:"OBJECT",0x0041:"LOD",0x0042:"PATCH",
0x0046:"PMESH",0x0047:"CONN",0x0048:"SPHERE_LIST",0x004d:"PCONN",0x0070:"BOUND",
0x0080:"V_XYZ",0x0081:"V_XYZ_N",0x0082:"V_XYZ_RGBA",0x0088:"V_XYZ_UV",0x0089:"V_XYZ_N_UV",
0x008A:"V_XYZ_RGBA_UV",0x2030:"SV_MATERIAL",0x2037:"SV_SPECIAL",0x2008:"NAME"}
CONTAINER={0x0003,0x0070,0x0040,0x0041,0x0042,0x0046,0x0048,0x0010,0x0020,0x0030}
verts=[] # (x,y,z,u,v)
def parse(p,end,depth):
while p+3<=end:
tagword=struct.unpack_from("<H",data,p)[0]; p+=2
cid=tagword&0x2fff
lw=4 if (tagword&0x8000) else (2 if (tagword&0x4000) else 1)
if p+lw>end: return
ln=data[p] if lw==1 else (struct.unpack_from("<H",data,p)[0] if lw==2 else struct.unpack_from("<I",data,p)[0])
p+=lw
if p+ln>end: return
name=TAGS.get(cid,hex(cid))
if cid in (0x0088,0x0089,0x008A,0x0080,0x0081,0x0082):
# vertex list
stride={0x0080:12,0x0081:24,0x0082:28,0x0088:20,0x0089:32,0x008A:36}[cid]
n=ln//stride
print(" "*depth+f"{name} verts={n} stride={stride} len={ln}")
for i in range(n):
off=p+i*stride
x,y,z=struct.unpack_from("<fff",data,off)
u=v=0.0
if cid==0x0089: u,v=struct.unpack_from("<ff",data,off+24)
elif cid==0x0088: u,v=struct.unpack_from("<ff",data,off+12)
elif cid==0x008A: u,v=struct.unpack_from("<ff",data,off+28)
verts.append((x,y,z,u,v))
else:
print(" "*depth+f"{name} id={hex(cid)} len={ln}")
if cid in CONTAINER:
parse(p,p+ln,depth+1)
p+=ln
if cid==0x0005: break
parse(8,len(data),0)
if verts:
xs=[v[0] for v in verts]; ys=[v[1] for v in verts]; zs=[v[2] for v in verts]
us=[v[3] for v in verts]; vs=[v[4] for v in verts]
print("\n=== GEOMETRY ===")
print(f"nverts={len(verts)}")
print(f"x [{min(xs):.2f},{max(xs):.2f}] y [{min(ys):.2f},{max(ys):.2f}] z [{min(zs):.2f},{max(zs):.2f}]")
print(f"u [{min(us):.3f},{max(us):.3f}] v [{min(vs):.3f},{max(vs):.3f}]")
# radius from axis (0,8.25,z) per z, to see cone vs sphere vs cylinder
print("\n=== per-vertex: z, radius_from_yaxis(@8.25), u, v (first 40) ===")
for (x,y,z,u,v) in verts[:40]:
dy=y-8.25; r=math.sqrt(x*x+dy*dy)
print(f" z={z:7.2f} r={r:7.2f} u={u:7.3f} v={v:7.3f} (x={x:6.2f} y={y:6.2f})")