Files
BT411/scratchpad/geom_cop.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

67 lines
2.8 KiB
Python

import struct
d=open("content/VIDEO/GEO/BLX_COP.BGF","rb").read()
def walk(d,p,end,depth,out):
while p+3<=end:
tw=struct.unpack_from("<H",d,p)[0]; p+=2
cid=tw&0x2fff
lw=4 if(tw&0x8000)else(2 if(tw&0x4000)else 1)
if p+lw>end:return
ln=d[p] if lw==1 else (struct.unpack_from("<H",d,p)[0] if lw==2 else struct.unpack_from("<I",d,p)[0])
p+=lw
if p+ln>end:return
out.append((depth,cid,p,ln,d[p:p+ln]))
if cid in (0x03,0x40,0x41,0x42,0x46,0x20,0x30,0x31,0x10,0x70,0x48,0x21):
walk(d,p,p+ln,depth+1,out)
p+=ln
if cid==0x0005:break
out=[]; walk(d,8,len(d),0,out)
# For each PMESH: read verts (XYZ_UV, stride20), faces from PCONN(ppf) + CONN(tris)
# Collect global stats: uv range, bbox, boundary edges per pmesh
import collections
pm_idx=0
tot_uv_min=[1e9,1e9]; tot_uv_max=[-1e9,-1e9]
bbmin=[1e9]*3; bbmax=[-1e9]*3
i=0
while i < len(out):
depth,cid,p,ln,body=out[i]
if cid==0x88: # vertex XYZ_UV inside a pmesh
cnt=ln//20
verts=[struct.unpack_from("<5f",body,k*20) for k in range(cnt)]
# gather following face chunks until next vertex/pmesh boundary
faces=[]
j=i+1
while j<len(out):
d2,c2,p2,l2,b2=out[j]
if c2 in (0x88,0x89,0x8A,0x80,0x81,0x82): break
if c2==0x004d and l2>=1: # PCONN
ppf=b2[0]; n=(l2-1)//4
idx=[struct.unpack_from("<i",b2,1+k*4)[0] for k in range(n)]
for f in range(0,n-ppf+1,ppf):
faces.append(idx[f:f+ppf])
elif c2==0x0047 and l2>=12: # CONN trilist
n=l2//4
idx=[struct.unpack_from("<i",b2,k*4)[0] for k in range(n)]
for f in range(0,n-2,3):
faces.append(idx[f:f+3])
elif c2 in (0x42,0x46,0x40,0x41): break
j+=1
pm_idx+=1
# stats
for v in verts:
for a in range(3):
bbmin[a]=min(bbmin[a],v[a]); bbmax[a]=max(bbmax[a],v[a])
tot_uv_min[0]=min(tot_uv_min[0],v[3]); tot_uv_max[0]=max(tot_uv_max[0],v[3])
tot_uv_min[1]=min(tot_uv_min[1],v[4]); tot_uv_max[1]=max(tot_uv_max[1],v[4])
# boundary edges
edge=collections.Counter()
for f in faces:
for k in range(len(f)):
a,b=f[k],f[(k+1)%len(f)]
edge[(min(a,b),max(a,b))]+=1
boundary=[e for e,c in edge.items() if c==1]
print(f"PMESH#{pm_idx}: verts={cnt} faces={len(faces)} edges={len(edge)} boundary_edges={len(boundary)}")
i+=1
print(f"\nGLOBAL bbox X[{bbmin[0]:.2f},{bbmax[0]:.2f}] Y[{bbmin[1]:.2f},{bbmax[1]:.2f}] Z[{bbmin[2]:.2f},{bbmax[2]:.2f}]")
print(f"GLOBAL UV U[{tot_uv_min[0]:.4f},{tot_uv_max[0]:.4f}] V[{tot_uv_min[1]:.4f},{tot_uv_max[1]:.4f}]")