The mission's objective counter is a big-endian u32 at guest VA 0xbdb59668 in a Stage 02 run on the upstream baseline. It was selected on an 18->24 transition and then tracked 24->23->22 against the HUD on its own - four readings, two changes it was not filtered on. That last point is the whole discipline here, because the first attempt failed it. An earlier differential over 19->18 also produced exactly one candidate, 0xbc22e83c, which matched the transition it was selected on and was still wrong: read live it held 26 while the HUD showed 017. One matching transition is not evidence. A second trap is recorded too: a three-snapshot filter requiring 19 -> 19 -> 18 left ZERO survivors, because the value moves between the memory copy and the screenshot that reads it. Filtering on the next DISTINCT value instead found the counter on the first try. ob_scan.py carries the method: scan one snapshot, then filter the candidate set against live /dev/shm/xenia_memory_* at each new value, so only the first pass needs a 4.8 GB copy. Stated plainly as unsettled: the ADDRESS is from one run and cross-run stability is untested, so the durable result is the method rather than the number. And what the counter counts - whether every OB-badged entity is one of them, and whether that badge is a flag in the entity object - is the follow-on the pilot actually needs to CHOOSE targets rather than just know how many remain.
Runtime-capture harness (sylph-re container)
Screenshot-driven scripts for reading the running retail game's menus under Xenia
Canary + lavapipe, headless. They assume the container helpers screenshot,
vgamepad, pad are on $PATH and HOME=/sylph-home/re.
| Script | What it does |
|---|---|
skip_intro.sh |
Boot → main menu, unattended. Taps A only while the intro movie is actually playing (frame-to-frame RMSE), then once at the PRESS Ⓐ BUTTON title. Static logo screens are left alone, so a stray tap can never land on NEW GAME. |
wait_title.sh |
Older variant: wait for the title (green Ⓐ glyph at px 625,618) and tap A. Superseded by skip_intro.sh. |
step.sh |
One Arsenal navigation step (down/up/next/prev/none) + a compact capture: weapon list stacked over the DATA SHEET. |
sweep.sh |
Walk a whole weapon-type list, capturing only rows that show a DATA SHEET — locked rows (a "Conditions to Develop" panel) are detected by the brightness of the Range Class label box and skipped. |
type.sh |
Change weapon-type tab N times (RB) and report the header strip. |
hp.sh / cyc.sh |
Hangar hard-point carousel: cyc.sh steps it (d-pad down, not left/right) and captures the Name + DATA SHEET. |
Input timing under lavapipe: the game polls input at its own low frame rate, so a 60 ms d-pad tap is dropped roughly half the time. 200 ms is reliable; 300 ms starts to auto-repeat (two rows per press).
Findings produced with these: docs/re/weapon-datasheet-runtime.md.
Guest-memory tools (no screenshots)
| Script | What it does |
|---|---|
gmem.py |
Read the live guest address space out of /dev/shm/xenia_memory_* (Xenia's backing file), addressed by guest VA. find / read / words. |
weapon_runtime.py |
Solve the Weapon/Shell struct layouts against the disc records and read the fields the disc defaults. |
unit_discover.py |
Find which runtime class carries a set of ID strings, assuming no vtable: tallies the word at pointer_site - k across distinct IDs. |
unit_runtime.py |
Same solver for the unit\UN_*.tbl definition objects (vtable 0x820af844). Unions several snapshots — unit definitions are per-stage. |
schema_order.py |
Merge a sub-record's field-declaration order across all tables (topological sort); the layout check that pins fields no table ever values. |
order_check.py |
Test offset = base + 4*index for one table's sub-record against solver output. |
grab_tutorial.sh |
Cold-boot Canary, walk to the Nth TUTORIAL entry, wait for the stage load, snapshot guest RAM. One emulator per capture — backing out of a loaded mission wedges it. |
Snapshot first — cp --sparse=always /dev/shm/xenia_memory_* snap.bin (~2 s) — and
point $GMEM_FILE at the copy; the running emulator pegs every core under lavapipe.