Three results, two of them against my own earlier claims: - REFUTED: position = instance - 0x12c. The corpus anchors on position (def ptr at +0x130, orientation at -0x70, hull at +0x154) and name_of reads the def ptr at instance+4, which predicts -0x12c. Measured over all 42 named instances: almost every read is (0,0,0), three are garbage, and 0/42 move. The vtable object and the position block are different structures. - WITHDRAWN: last iteration's claim that entities2.py's ENT_VA window is aimed at the definitions rather than the instances. entities2 does not look for vtable objects at all -- it hunts moving position triples and checks +0x130, the documented anchor -- and it had worked minutes earlier (6914 movers, +0x130 voted 92x; then 6634/138x). I built the defect report on the single sample in between that returned zero. The +0x29d0 position candidate falls with it. - FOUND: sampling 64 spots across the 505 extents (357 MB) twice, 2.5s apart, with the mission visibly running, only 5 change. The megabyte holding all 42 instances is byte-identical over seconds, as is its primary-VA counterpart. The mapping IS live (5 regions prove it); what is undetermined is whether the entity records are simply static or whether writes land in a different alias. Either way: verify a region changes before measuring through it.
87 lines
4.2 KiB
Markdown
87 lines
4.2 KiB
Markdown
# ❌ Two of my own claims, refuted — and a live-memory trap behind both
|
||
|
||
Measured 2026-08-26, Canary on the retail disc, save slot 01, Stage 01, **in
|
||
flight with a live HUD** (`TIME 00:28.42`, speed 350, target on radar, dialogue
|
||
mid-render — the game was unambiguously running throughout).
|
||
|
||
## ❌ Refuted: `position = instance − 0x12c`
|
||
|
||
The corpus anchors the entity layout on **position**:
|
||
[`autopilot-memory-driven.md`](autopilot-memory-driven.md) gives the definition
|
||
pointer at `position + 0x130`, orientation at `position − 0x70`, hull at
|
||
`position + 0x154`. `gworld.py`'s `name_of()` reads the definition pointer at
|
||
`instance + 4`. If those name the same field, `instance + 4 = position + 0x130`,
|
||
so `position = instance − 0x12c`.
|
||
|
||
They do not. Read at `instance − 0x12c` for all **42** named instances:
|
||
|
||
```
|
||
UN_f001_TCAF_DeltaSaber_T_Player ( 0.0, 0.9, 0.1) moved 0.00
|
||
UN_e106_ADAN_Destroyer ( -48.9, 0.0, 0.0) moved 0.00
|
||
UN_S01_Asteroid_cmesh_01a (2.07e11, 0.0, 0.0) moved 0.00
|
||
...
|
||
moved in 0.8 s : 0/42
|
||
```
|
||
|
||
Almost every read is `(0, 0, 0)`, three are garbage, and **nothing moves**. The
|
||
vtable-bearing object and the position block are two different structures that
|
||
merely name the same units. The prediction was clean and it was wrong.
|
||
|
||
## ❌ Withdrawn: "`entities2.py`'s VA window is aimed at the wrong region"
|
||
|
||
[Last iteration](world-unit-attempt-2026-08-26.md) I recorded `ENT_VA_LO/HI =
|
||
0xBD000000–0xBE000000` as a defect, on the grounds that the live instances sit at
|
||
`0xBC384CE0–0xBC9BAC20` and the window "covers the definitions instead".
|
||
|
||
That reasoning was wrong. It assumed the thing the window *should* contain is the
|
||
vtable-bearing instance — but `entities2.py` does not look for those. It hunts
|
||
**moving position triples** and checks `+0x130` for a definition pointer, exactly
|
||
the documented anchor. And in the run where I called it broken it had *worked*
|
||
moments earlier: **6914 movers, `+0x130` voted 92×**, then 6634 and 138× on a
|
||
re-run. I built a defect report on the one sample in between that returned zero —
|
||
the same single-sample error this corpus keeps logging.
|
||
|
||
The window may still be imperfect (it is hardcoded, and the heap moves). But it
|
||
is not "aimed at the definitions", and nothing here shows it needs changing.
|
||
|
||
## 🟡→❌ The `+0x29d0` position candidate is not trustworthy either
|
||
|
||
It was read through the same region that is shown below not to be updating, so
|
||
what it captured is load-time data, not a live position. Withdrawn pending a
|
||
re-measurement through a region that demonstrably changes.
|
||
|
||
## ✅ The trap: most of guest memory is not changing while the game runs
|
||
|
||
Sampling **64 spots of 64 KB** spread across the mapping's **505 extents
|
||
(357 MB)**, twice, 2.5 s apart, with the mission visibly running:
|
||
|
||
```
|
||
CHANGING: 5 / 64
|
||
0x007006f000 0x00704db000 0x0070557b000 0x00705df000 0x0080240000
|
||
```
|
||
|
||
Everything else — including the megabyte containing all 42 live instances
|
||
(`0x11c37d780`), and that region's primary-VA counterpart at `0x00bc300000` — is
|
||
**byte-identical over seconds**. So:
|
||
|
||
* The mapping is live. Five regions prove it, so "the shm view is stale" as a
|
||
blanket claim is refuted.
|
||
* The entity-object region genuinely does not change on a seconds timescale.
|
||
* ❔ **Not determined**: whether that is because those records are static
|
||
metadata and the moving state lives elsewhere, or because the guest physical
|
||
page is aliased at several file offsets and writes land in a different one.
|
||
Both fit the evidence. `gmem.primary_va(0x11c384ce0) = 0xbc384ce0` shows the
|
||
alias relationship exists; it does not show which copy the guest writes.
|
||
|
||
**Consequence for anyone reading guest memory here:** verify the specific region
|
||
you are sampling actually changes before drawing conclusions from it. A scan that
|
||
finds correct, name-resolving records can still be reading a snapshot.
|
||
|
||
## Still open
|
||
|
||
* Where the live position blocks are. The five changing offsets above are the
|
||
place to start, but `moving()` takes **VAs** and converts with
|
||
`gmem.va_to_off`, while those five are **file offsets** — they are not the same
|
||
number and must be converted before they can be scanned.
|
||
* Whether `entities2.py`'s window needs any change at all.
|