Capture triage: parse-only census of every wire capture
capture_triage.py parses each capture's first slice (no emulation) and reports the embedded firmware build, action census, init config, and any actions outside cap7's known-good set. Results: all captures share build 0x31440 + the same init config; ravtest (RAV = the walled terrain map), dtest, cap6/cap8/capture/ sharksval are clean cap7-profile candidates; sdemo/duane/fishspls add morph; bt3/munga7 add act31/43/45/list_remove. cap6's earlier "boot derail" was likely just an under-budgeted run (87K cmds to parse), not a fault. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
"""Triage captures for battle-scene replay: for each capture, WITHOUT emulation,
|
||||
parse the first slice of the wire log and report (a) embedded firmware build header,
|
||||
(b) action census, (c) the init config string, (d) actions outside cap7's known-good
|
||||
set. Cheap parse-only pass to pick the best replay candidates."""
|
||||
import sys, os, struct
|
||||
sys.path.insert(0, r'C:\VWE\TeslaRel410\emulator\firmware-decomp')
|
||||
sys.path.insert(0, r'C:\VWE\TeslaRel410\dpl3-revive\patha')
|
||||
from vrboard import Assembler, A
|
||||
|
||||
P = r'C:\VWE\TeslaRel410\dpl3-revive\patha'
|
||||
BOOT = {int(A.hspcode), int(A.code860), int(A.data860), int(A.bss860), int(A.args860)}
|
||||
|
||||
def parse_slice(path, slice_bytes=6_000_000):
|
||||
with open(path, 'rb') as f:
|
||||
data = f.read(slice_bytes)
|
||||
start = None
|
||||
for i in range(0, len(data) - 8):
|
||||
w = struct.unpack_from('<I', data, i)[0]
|
||||
if (w & 0xffff0000) == 0x40ff0000 and 8 <= (w & 0xffff) <= 4096:
|
||||
act = struct.unpack_from('<I', data, i + 4)[0]
|
||||
if act in (A.init, A.code860, A.args860, A.data860, A.bss860):
|
||||
start = i; break
|
||||
if start is None:
|
||||
return None, None
|
||||
asm = Assembler(); asm.feed(data[start:])
|
||||
out = []
|
||||
for m in asm:
|
||||
if not m.iserver:
|
||||
out.append((int(m.action), m.payload))
|
||||
return out, start
|
||||
|
||||
def fw_hdr(cmds):
|
||||
for a, pl in cmds:
|
||||
if a == int(A.code860) and len(pl) == 40:
|
||||
return struct.unpack_from('<7I', pl, 0)
|
||||
return None
|
||||
|
||||
def name(a):
|
||||
try: return A(a).name
|
||||
except Exception: return 'act%d' % a
|
||||
|
||||
# build cap7's reference action set first
|
||||
ref_cmds, _ = parse_slice(os.path.join(P, 'cap7.raw.bin'))
|
||||
ref_set = set(a for a, _ in ref_cmds if a not in BOOT)
|
||||
print("cap7 reference actions:", sorted(name(a) for a in ref_set))
|
||||
print("=" * 100)
|
||||
|
||||
CAPS = ['ravtest', 'solo1', 'batest', 'cap6', 'cap8', 'capture', 'sdemo4', 'sdemo5',
|
||||
'munga7', 'fxtest', 'glblade', 'trek', 'klngvid', 'dtest', 'duane', 'bt3',
|
||||
'fishspls', 'sharksval', 'blade']
|
||||
import collections
|
||||
for cap in CAPS:
|
||||
path = os.path.join(P, cap + '.raw.bin')
|
||||
if not os.path.exists(path) or os.path.getsize(path) == 0:
|
||||
continue
|
||||
try:
|
||||
cmds, start = parse_slice(path)
|
||||
if not cmds:
|
||||
print("%-12s UNPARSEABLE" % cap); continue
|
||||
h = fw_hdr(cmds)
|
||||
fw = ("fw:text=%#x" % h[0]) if h else "fw:none-in-slice"
|
||||
census = collections.Counter(a for a, _ in cmds if a not in BOOT)
|
||||
extra = set(census) - ref_set
|
||||
draws = census.get(int(A.draw_scene), 0)
|
||||
# init config string
|
||||
cfg = ""
|
||||
for a, pl in cmds:
|
||||
if a == int(A.init) and pl:
|
||||
cfg = pl.split(b'\0')[0][:90].decode('latin1', 'replace')
|
||||
break
|
||||
print("%-12s %8dB %s cmds:%d draws:%d" %
|
||||
(cap, os.path.getsize(path), fw, len(cmds), draws))
|
||||
print(" actions: %s" % {name(a): n for a, n in census.most_common(10)})
|
||||
if extra:
|
||||
print(" EXTRA (not in cap7): %s" % sorted(name(a) for a in extra))
|
||||
if cfg:
|
||||
print(" init: %s" % cfg)
|
||||
except Exception as e:
|
||||
print("%-12s ERR %s" % (cap, e))
|
||||
Reference in New Issue
Block a user