Last iteration I ruled the speed route out because the emulator is not real-time so the wall-clock denominator is unknown. Wrong: the game prints its own clock, and flight-speed-law.md had already used it -- mission TIME across a wall interval gives 1.26x, turning 443.6 units/wall-second into 352 per game-second against a HUD 350. Withdrawn in place, with the reasoning, rather than deleted. Closes the backlog item: one world unit is one metre, by two independent routes.
106 lines
4.8 KiB
Markdown
106 lines
4.8 KiB
Markdown
# World-unit measurement — ✅ two blockers removed, ❔ the unit itself still not measured
|
||
|
||
Measured 2026-08-26, Canary on the retail disc, save slot 01, Stage 01 in flight
|
||
with a live HUD.
|
||
|
||
## ✅ The title-screen CONTROL is now paired, in the SAME process
|
||
|
||
The [entity roster](entities-live-roster.md) owed a control. Taken this run,
|
||
same process (pid 898128), before anything was loaded:
|
||
|
||
| state | `DEF_VTABLE` | `INST_VTABLE` |
|
||
|---|---|---|
|
||
| title screen | **0** | **0** |
|
||
| Stage 01, in flight | **13** | **42** |
|
||
|
||
Neither vtable resolves anything at the title. The roster result stands with both
|
||
arms of its control measured in one process.
|
||
|
||
## ✅ A live flight HUD is reachable — and the recipe has two undocumented steps
|
||
|
||

|
||
|
||
Previous runs read `green 0.03 %` after take-off and concluded the HUD was not up.
|
||
It was not — but not because the mission had failed to start. Two things sit in
|
||
the way, neither of them in any script:
|
||
|
||
1. **A cutscene.** `START` skips it. Take-off → HUD took ~70 s with two skips.
|
||
2. **A modal objective dialog** — *"Do you want Rhino Leader to tell you your
|
||
objective?"* YES/NO, cursor on YES. It **dims the whole frame**, so the
|
||
classifier reads `other` and a naive liveness check reads it as a stall. It is
|
||
not a stall: `dpad down` + Ⓐ answers NO and the HUD comes up at
|
||
`green 0.0145`, inside the documented 1.3–1.5 % flight band.
|
||
|
||
## ✅ `entities2.py`'s committed VA window points at the wrong region
|
||
|
||
`ENT_VA_LO, ENT_VA_HI = 0xBD000000, 0xBE000000`. Measured this run, the 42 live
|
||
instances occupy **`0xBC384CE0`–`0xBC9BAC20`** — entirely below that window.
|
||
|
||
The window is not merely stale, it is aimed at the wrong *kind* of object: the 13
|
||
**definitions** sit at `0xBD3B5180`-and-up, i.e. inside it. So `moving()` scans
|
||
the definition region, and `find_delta` was pairing movers there with definition
|
||
pointers. Rescoped to the instance region it reports **8819 movers and zero
|
||
delta votes** — the `±0x400` radius never reaches from an instance's moving
|
||
triple to its definition pointer.
|
||
|
||
## ✅ `gworld.py`'s `WINDOW = 0x600` is far too small
|
||
|
||
The file says as much — *"its real size is unknown"*. Measured: nothing inside
|
||
the first `0x600` bytes of **any** of the 42 instances moves like a position.
|
||
Widening to `0x4000` finds one immediately.
|
||
|
||
## 🟡 A candidate player position
|
||
|
||
At **`+0x29d0`** in the `_Player` instance, sampled 0.6 s apart:
|
||
|
||
```
|
||
UN_f001_TCAF_DeltaSaber_T_Player (44965.4, 10.0, 33542.2) moved 116.6
|
||
UN_e106_ADAN_Destroyer +0x1d88 ( -0.0, 0.0, 26.3) moved 0.7
|
||
```
|
||
|
||
🟡 not ✅: this is one offset in one instance over one 0.6 s sample. The second
|
||
destroyer produced no candidate at all, so the offset is not yet shown to be
|
||
uniform across instances — and `+0x29d4` in the same object is the same bytes
|
||
read one float over, which is an artifact, not a second hit.
|
||
|
||
> ### ❌ WITHDRAWN — "the speed cannot be used" was wrong
|
||
>
|
||
> This section originally said the speed route was unusable because the emulator
|
||
> does not run at real time under lavapipe, so the wall-clock denominator is
|
||
> unknown. **The denominator is not unknown: the game prints its own clock.**
|
||
> [`flight-speed-law.md`](flight-speed-law.md) had already done exactly this
|
||
> measurement, and more carefully — mission `TIME` read off the HUD across a
|
||
> wall-clock interval gives the ratio (**1.26×**), and 443.6 units per
|
||
> wall-second becomes **352 per game-second** against a HUD reading of **350**.
|
||
>
|
||
> I wrote the route off instead of checking whether the corpus had already
|
||
> walked it. That is the *same* mistake logged twice above on this page, so it
|
||
> is recorded here rather than quietly deleted.
|
||
|
||
## ✅ SETTLED — the unit is the metre
|
||
|
||
Measured this run, statically: the `mapmesh_box_500km` hull is a cube of
|
||
**exactly 500 000.0 units** on every axis (`−250 000 … +250 000`), and the only
|
||
other box-shaped MCOL is exactly **100 000.0** — the same ruler at a different
|
||
size. Together with the dynamic confirmation above (352 units per game-second
|
||
against a HUD 350) and the dismantling of the `rob_`/`rou_` size objection in
|
||
[`structures/mcol-collision.md`](structures/mcol-collision.md):
|
||
|
||
> **one world unit is one metre.**
|
||
|
||
The paragraph below is kept as written, because it is what was still open at the
|
||
time and it records the plan that turned out to be unnecessary.
|
||
|
||
## ❔ (superseded) Still not measured: the unit
|
||
|
||
The measurement needs a **locked target**, so the HUD prints a numeric range to a
|
||
specific entity whose position can be read at the same moment. This run never
|
||
locked one. Both candidate answers remain live:
|
||
|
||
* `mapmesh_box_500km` → 1 unit = 1 m
|
||
* `CollisionSet` extents → a "small" attacker is 133 m, which 1 unit = 1 m makes
|
||
implausible
|
||
|
||
Next attempt: lock a target in flight, then read the HUD range and both position
|
||
triples in the same second.
|