re: REMAINING OB's address is run-dependent -- cross-run stability refuted
The doc carried a 🟡 saying cross-run stability was untested. Tested now on a fresh guarded Stage 02 run (stage asserted): the HUD reads "Remaining OB : 004" while RAM at the documented 0xbdb59668 reads 95748078, constant over four samples 12s apart. Not 4, not near 4, not moving. So the address belongs to that run's heap, as the corpus's own heap-reallocation warning predicts. No constant-shift shortcut either: a BE u32 equal to 4 occurs 1654 times within +-1 MB of the old address and 11202 times within +-16 MB, far too many to isolate without the transition filter. The durable result is the METHOD (ob_scan.py: scan at one value, filter against live memory at a DIFFERENT value), not the number. Also fixes a contradiction in INDEX.md, which said in one row that the address is "still ❔" while another row linked the doc that had already CONFIRMED it.
This commit is contained in:
@@ -39,7 +39,7 @@ Promote to a prose `structures/…md` file when a format needs behavioural notes
|
||||
| Live guest-memory read | ✅ | [`tools/re-capture/gmem.py`](../../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`](../../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`](../../tools/re-capture/own_state.py) · [autopilot](autopilot-memory-driven.md) | 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`](../../tools/re-capture/mission_state.py) · [escort state](mission-escort-state.md) | `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 ❔ |
|
||||
| Mission / escort state, every entity's hull | ✅ | [`tools/re-capture/mission_state.py`](../../tools/re-capture/mission_state.py) · [escort state](mission-escort-state.md) | `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 found** — see [mission-objective-counter](structures/mission-objective-counter.md) — but it is **run-dependent** and must be re-derived per run (refuted as a constant 2026-08-26) |
|
||||
| In-flight control mapping | ✅/🟡 | [`tools/re-capture/fire_probe.sh`](../../tools/re-capture/fire_probe.sh) · [controls](flight-controls-runtime.md) | 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 |
|
||||
| Throttle → speed law | ✅/🟡 | [flight-speed-law](flight-speed-law.md) | **The throttle selects a TARGET SPEED**, it does not add thrust: no input settles at ~420 (`CruisingVelocity` 350), `RT` at ~1 530 (`MaximumVelocity` 1200), `LT` at ~125 (`MinimumVelocity` 100), and releasing either returns to cruise. `Acceleration`/`Deceleration` govern the convergence rate (measured ~440–560 units/s² against 500/600). 🟡 measured world speeds run ≈1.2–1.3× the definition numbers while the HUD shows the definition value exactly, so world units are a constant (~1.25) multiple of the definition's velocity unit |
|
||||
| Input → dynamics calibration | ✅ | [`tools/re-capture/ctrl_probe.py`](../../tools/re-capture/ctrl_probe.py) · [`binq.py`](../../tools/re-capture/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 |
|
||||
|
||||
Reference in New Issue
Block a user