Pilot sees the escape-pod/wreck interior at death instead of the portal ride. Findings (DEATH-SEQUENCE-NOTES.md): two death variants exist -- respawn deaths transit the chain camera to the portal at the origin (fp_cam's <100m vehicle-distance guard rejects exactly that ride = the fix target); mission-end deaths (tonight's capture) have no transit on the wire at all, just the fog fade at the wreck. At death the 0x1f articulation batches switch to driving origin-anchored nodes = the portal diorama animating; type-3 view flushes decode as projection+fog only (hither/yon at floats 12/13). Reference capture captures/netdeath-20260708.fifodump (full networked mission incl. death) + replay probes in probes/. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
91 lines
3.5 KiB
Python
91 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Death-camera forensics on the saved networked death:
|
|
per draw frame, where is the CHAIN camera eye vs the player vehicle root?
|
|
Does the chain legitimately transit >100m away (portal ride) -- i.e. is the
|
|
fp_cam <100m sanity guard what forces the escape-pod-interior view?
|
|
Also log view-flush params (fog near/far/rgb + full float head) around the
|
|
transit to find a robust 'death sequence active' gate."""
|
|
import struct, sys, os
|
|
sys.path.insert(0, r'c:\VWE\TeslaRel410\dpl3-revive\patha')
|
|
os.environ.setdefault('SDL_VIDEODRIVER', 'dummy')
|
|
import numpy as np
|
|
from vrboard import VirtualBoard, Msg
|
|
from vrview import Renderer
|
|
|
|
path = os.path.join(os.path.dirname(__file__), '..', 'captures', 'netdeath-20260708.fifodump')
|
|
data = open(path, 'rb').read()
|
|
board = VirtualBoard()
|
|
r = Renderer(w=64, h=40)
|
|
|
|
frames = 0
|
|
created = {}
|
|
fogs = [] # (frame, floats[:24])
|
|
track = [] # (frame, chain_eye, veh_t, dist)
|
|
o = 0
|
|
while o + 8 <= len(data):
|
|
if data[o:o+4] != b'VPXM':
|
|
o += 1; continue
|
|
ln = struct.unpack_from('<I', data, o+4)[0]
|
|
if o + 8 + ln > len(data): break
|
|
body = data[o+8:o+8+ln]; o += 8 + ln
|
|
if len(body) < 4: continue
|
|
a = struct.unpack_from('<I', body, 0)[0]
|
|
if a >= 0x100: continue
|
|
p = body[4:]
|
|
if a == 1 and len(p) >= 8:
|
|
created[struct.unpack_from('<I', p, 4)[0]] = struct.unpack_from('<I', p, 0)[0]
|
|
elif a == 3 and len(p) >= 96:
|
|
h = struct.unpack_from('<I', p, 0)[0]
|
|
if created.get(h) == 3:
|
|
fogs.append((frames, struct.unpack_from('<24f', p, 4)))
|
|
try: board.handle(Msg(False, 0xff, a, p))
|
|
except Exception: pass
|
|
if a == 9:
|
|
frames += 1
|
|
try:
|
|
r.cache.maybe_rebuild(board)
|
|
Mc = np.asarray(r.cam_matrix(board), float)
|
|
ec = Mc[3, :3]
|
|
except Exception:
|
|
ec = None
|
|
anim = board.anim_abs
|
|
t = None
|
|
chain = getattr(r.cache, 'cam_chain', None)
|
|
h = None
|
|
if chain and chain[-1] in anim:
|
|
h = chain[-1]
|
|
elif anim:
|
|
h = max(anim, key=lambda k: float(np.abs(np.array(anim[k][9:12])).sum()))
|
|
if h is not None:
|
|
t = np.array(anim[h][9:12])
|
|
if ec is not None:
|
|
d = float(np.linalg.norm(ec - t)) if t is not None else -1.0
|
|
track.append((frames, ec.copy(), None if t is None else t.copy(), d))
|
|
|
|
print(f"total draw frames: {frames}, tracked: {len(track)}")
|
|
|
|
# find where the chain eye leaves the vehicle by >100m (the guard threshold)
|
|
first_far = next((i for i, (f, ec, t, d) in enumerate(track) if d > 100.0), None)
|
|
print(f"first frame with chain-vehicle distance >100m: "
|
|
+ (f"f{track[first_far][0]}" if first_far is not None else "NONE"))
|
|
|
|
# print the trajectory every ~30 frames over the last 1200 frames
|
|
print("\n-- chain eye vs vehicle root (tail):")
|
|
tail = track[-1200:]
|
|
for i in range(0, len(tail), 30):
|
|
f, ec, t, d = tail[i]
|
|
ts = "None" if t is None else f"({t[0]:8.1f},{t[1]:7.1f},{t[2]:8.1f})"
|
|
print(f" f{f}: eye=({ec[0]:8.1f},{ec[1]:7.1f},{ec[2]:8.1f}) veh={ts} dist={d:8.1f}")
|
|
|
|
# fog/view flushes in the tail window, with the full float head for gate hunting
|
|
if track:
|
|
cut = track[-1200][0] if len(track) >= 1200 else track[0][0]
|
|
print(f"\n-- view flushes after f{cut} (floats 14..23):")
|
|
last = None
|
|
for f, fl in fogs:
|
|
if f < cut: continue
|
|
k = tuple(round(x, 2) for x in fl[14:24])
|
|
if k != last:
|
|
print(f" f{f}: " + " ".join(f"{x:.2f}" for x in k))
|
|
last = k
|