Files
Syplheed-Reborn/docs/re/INDEX.md
Claude (auto-RE) 69b4a2e569 re: a unit field left unset on disc is not a global constant — Size_Y inherits Size_X
Attacks the 21/110 unit-coverage limit from the cheap side: if a defaulted field
always took one runtime value, the captured units would pin it for all 110. Only
6 of 24 confirmed defaulted fields behave that way. The other 18 vary per unit,
so the default is computed.

Asking which OTHER field of the same unit holds that value — counting only
non-zero cases, and checking the two fields sit at different offsets so the
layout solver cannot be aliasing them — gives four rules. Size_Y <- Size_X is
solid: seven unrelated ships (e105 600, e106 300, e108 80, e201 300, f101 400,
f105 700, f106 200) each omit it on disc and each shows its own Size_X live,
while the two fields differ freely when both are on disc. Size_Radius fits both
min(X,Z) and the median of the three axes and cannot yet be separated;
e010_ADAN_Attacker_S is what rules out the simpler Size_X rule. FCSRange and
DefencePoint rest on two independent units each and ship as HYPOTHESIS.

Applied across the disc the rules recover 65 (unit, field) values in units that
have never been visited. Falsification test recorded: load any uncaptured stage
and compare one predicted value.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 19:44:24 +00:00

7.8 KiB
Raw Blame History

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 — but a defaulted field is not a global constant: Size_Y provably inherits Size_X (7 independent units, 6 distinct values), and three more sibling rules are recorded , recovering 65 values in units never visited — 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
Mission / escort state, every entity's hull tools/re-capture/mission_state.py · escort state hull = position + 0x154 is a property of the entity class, not of the player object: at t=0 it equals each entity's own definition HP across 7 classes and 5 distinct HP values (turret 100, fighter 500, destroyer 10000, cruiser 30000, ACROPOLIS 25000), falls under fire (780 damage events in 240 s), goes negative at death, and the object then leaves the heap. So an escort objective is scoreable live — UN_f101_TCAF_Acropolis measured at 25000 → 23038 over 240 s, attack starting only at t≈170 s. REMAINING OB counts objectives, not hostiles (012 on the HUD vs 118 live ADAN); its address is still
In-flight control mapping /🟡 tools/re-capture/fire_probe.sh · controls Measured by holding each pad input and photographing the HUD ammo counters: RB = nose gun (6000→5956 in 4 s, ~11 rounds/s, HEAT rises), Y = main mount (missiles, 300→299), d-pad = tactical map overlay, nothing else moves a counter. No target-cycle input exists — the TARGET marker is present with nothing pressed, so targeting is automatic and a missile lock is time-on-target. That, not target choice or ballistics, is what caps lethality at 2 kills per 98 missiles
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