Three measurements, then a pilot built on them. * Hull is position+0x154. Found by anchoring on a field the definition already had solved (HP = 1500) rather than scanning for a value that falls: an undamaged craft must contain its own definition's number. Confirmed by the trace across a death -- 30/60/90 per hit, negative at 0, GAME OVER on screen. * RT accelerates, LT brakes, and the throttle is a persistent setting (488 -> 1510 -> 174 units/s, measured as displacement per second of the craft's own position, so no speed field was needed). This overturns the earlier "RT is not the throttle", which came from assuming the control and hunting for a field. * Shield is probably position+0x430 (== definition MaxValue 400), not yet confirmed live -- nothing had damaged it. pilot.py is a state machine on damage (ENGAGE / EVADE / RETIRE) that treats turrets as keep-out zones instead of targets. It flew Stage 02 for 300 s with the hull untouched at 1500/1500 and took the first confirmed kill (WARPLANES 0001); every run the day before was dead inside 35 s. Two bugs the live run exposed and this fixes: gating the guns on the commanded direction keeps them cold whenever avoidance is steering (gate on the target instead), and an orbit-plus-brake rule made it circle one attacker for 40 s outside its own firing cone. Also: boot to in-flight is now ~100 s unattended, because wait_flight.sh waits for the HUD's own shield bar instead of a fixed 75 s sleep that lavapipe does not honour; entities2.py picks the attitude block by matching the measured flight path (taking the first orthonormal block gave a bone/camera frame); and the entity-heap scan is numpy instead of a per-word Python loop. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
6.2 KiB
6.2 KiB
RE knowledge index
Confidence: ✅ CONFIRMED · 🟡 PROBABLE · ❔ HYPOTHESIS. See README.
Formats we've already reversed are, for now, documented by their parser + disc round-trip
tests (the executable spec) rather than a prose file — the "Spec" column points there.
Promote to a prose structures/…md file when a format needs behavioural notes beyond layout.
Data structures / formats
| Format | Conf. | Spec (parser + tests) | Notes |
|---|---|---|---|
IPFB .pak archive |
✅ | sylpheed-formats/src/pak.rs + tests/pak_idxd_disc.rs |
header + 12-byte TOC, Z1/zlib payloads |
| name-hash (TOC keys) | ✅ | sylpheed-formats/src/hash.rs |
Barrett-reduction hash; recovers original paths |
| IDXD object/table | ✅ | sylpheed-formats/src/idxd.rs |
self-describing; ship/weapon stats verified vs known values |
| XPR2 texture + cubemap | 🟡 | sylpheed-formats/src/texture.rs |
de-tile + A8R8G8B8; colours unverified (dynamic item) |
| T8aD 2D texture | 🟡 | sylpheed-formats/src/t8ad.rs |
~85% decode; colours ✅ CONFIRMED (k8888); ~15% variants deferred |
| RATC bundle | 🟡 | sylpheed-formats/src/ratc.rs |
child listing confirmed; one level deep |
| LSTA sprite list | 🟡 | sylpheed-formats/src/lsta.rs |
inline T8aD frames |
| IXUD subtitle | 🟡 | sylpheed-formats/src/ixud.rs |
timed cues; movie↔track link unknown (dynamic item) |
| Fonts (ttf/otf/ttc) | ✅ | sylpheed-formats/src/font.rs |
standard OpenType, parsed via ttf-parser |
| XBG7 mesh | 🟡/❔ | sylpheed-formats/src/mesh.rs + tests/mesh_disc.rs (xbg7) |
weapons/props: declaration-driven variable stride (36 models), GPU-confirmed. Stage containers: 5662 sub-models across 22 stages via content-anchored grouped pools (stage_models). Quantized hero bodies (DeltaSaber f004) still declined |
| Capital-ship part placement | 🟡 | sylpheed-formats/src/ship.rs (static) + runtime capture |
hull placement static-exact; external parts approximate statically. Runtime capture (Canary F10 → VS-constant WorldView) gives ground truth — validated on e106 destroyer; not yet baked into the viewer |
| Weapon fields defaulted on disc | ✅ | runtime struct · DATA SHEET route | Solved. Canary maps guest RAM into /dev/shm, so the parsed Weapon/Shell objects are readable live; their layout is solved against disc ground truth (zero contradictions over 100+ records). All 126 weapons, exact numbers, no story progress needed — 4 393 values the disc does not carry. Supersedes the letter-bucket limit of the DATA SHEET route, which now serves as the independent cross-check |
| Unit (craft/vessel) fields defaulted on disc | ✅/🟡 | runtime struct | The parsed unit\UN_*.tbl definition object, vtable 0x820af844, ≥0x380 bytes, one per unit — discovered, not assumed (unit_discover.py), and distinguished from the spawned-entity class 0x820af030 by being one-per-ID and byte-constant within a run. Across runs only pointer words move — --crosscheck proves no reported field offset is run-dependent (two words, +0x2c8/+0x2d0, are stage-dependent and remain unidentified). 27 fields ✅ (21 units, 7 runs); the Maneuver block is schema declaration order, 4 bytes/field, base 0x9c with a two-slot gap after AA_Roll_Min (29 anchors, 0 conflicts), which also pins 5 fields no disc record ever values. Angles are radians at runtime, degrees on disc. Unlike weapons, unit definitions are instantiated per stage, so coverage (21/110) grows by visiting missions — values |
UI screen layout (.rat) |
✅/🟡 | ui-rat-layout | One pak per UI screen; each RATC = one (context × language) build; every <name>.t32 sprite has a <name>.rat layout record (BE u32; 1280×720 design space; scale/tint/X/Y, keyframes for animated elements, opt link to the focused state). The tutorial PAUSE menu and the title main menu both rebuild pixel-accurately from the disc. loop1.rat (screen-level draw order) not yet decoded |
Runtime / dynamic-capture technique
| Technique | Conf. | Spec | Notes |
|---|---|---|---|
| Live guest-memory read | ✅ | tools/re-capture/gmem.py |
Canary backs the guest address space with /dev/shm/xenia_memory_*; guest VAs map in through Xenia's fixed table. Full-RAM search ~0.2 s (sparse, SEEK_DATA). No debugger, no emulator patch, game keeps running |
| IDXD object layout solver | ✅ | tools/re-capture/weapon_runtime.py |
Scan RAM for a class's vtable → enumerate its objects → brute-force (field, offset, encoding) against the disc records. Accepts a binding only on zero contradictions. Generalizes to any IDXD-backed definition |
| Live entity state, anchored on the definition | ✅ | tools/re-capture/own_state.py · autopilot |
An undamaged craft holds its definition's own numbers, so a solved definition field locates the matching live field without a value scan: definition HP (1500) → hull at position+0x154, confirmed by a trace across a death (30/60/90 per hit, negative at 0). Reusable for any live counter whose maximum the definition carries |
| Input → dynamics calibration | ✅ | tools/re-capture/ctrl_probe.py · binq.py |
Hold each pad input in turn and measure the craft's speed as displacement/s of its own position triple — no speed field needed first. Settled the throttle: RT accelerates, LT brakes, and the setting persists (488 → 1510 → 174 units/s), overturning an earlier field-scan conclusion |
Functions / code paths
None documented yet — populated during the dynamic-RE phase.
| Function | Conf. | Reimpl. | Summary |
|---|---|---|---|
| — | — | — | — |