re: the two enumerations are different structures; only the vtable scan is complete
Same moment, same stage: the INST_VTABLE scan sees 116 objects across 14 types; the moving+0x130 method sees 30 across 4. Every capital ship, station, missile and the objective-critical Acropolis reads ZERO in the +0x130 method. The absence is structural, not a filter artifact -- both obvious explanations were tested and failed. Dropping the speed floor to 0 raised the count 30 -> 59 and recovered the _Player but still only 4 types; scanning the WHOLE map with no floor gives 181824 movers and still 4 types. And 0/116 vtable instances lie inside the window where the +0x130 blocks are found (instances 0xbc372cc0-0xbc9bc720, window 0xbd000000-0xbe000000), independently confirming these are separate allocations. Consequence: an autopilot that must protect the Acropolis cannot find it via the +0x130 method at all. Also found: LOAD GAME -> slot 01 no longer restores the S01 training area but a Stage-02-style escort mission (Acropolis, SchlosBase, cruisers, frigates). Slot 01 is the AUTO-SAVE, so the restored mission moves as the save is written -- which invalidates the earlier "101 vs 42" comparison outright, since those came from different stages. Corrects the previous note: entities2 prints its count AFTER dedup, so the 101 was already deduplicated; the gap was the stage change, not duplication.
This commit is contained in:
BIN
docs/re/captures/stage-this-run.png
Normal file
BIN
docs/re/captures/stage-this-run.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 914 KiB |
98
docs/re/two-entity-enumerations.md
Normal file
98
docs/re/two-entity-enumerations.md
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
# ✅ The two enumerations are two different structures — and only one is complete
|
||||||
|
|
||||||
|
Measured 2026-08-26, live flight HUD, movers precondition checked (18 002).
|
||||||
|
|
||||||
|
## The stage changed between runs — earlier cross-run comparisons were invalid
|
||||||
|
|
||||||
|
`LOAD GAME → slot 01` did **not** land on the same mission it did earlier today.
|
||||||
|
This run's definition table has **14** entries and no asteroids at all:
|
||||||
|
|
||||||
|
```
|
||||||
|
UN_bf001_TCAF_SchlosBase UN_f101_TCAF_Acropolis UN_f201_TCAF_Tanker
|
||||||
|
UN_e105_ADAN_Cruiser UN_e106_ADAN_Destroyer UN_e108_ADAN_ASFrigate
|
||||||
|
UN_e201_ADAN_ISCMissile UN_f003_TCAF_ArrowHead UN_f105/f106 TCAF ...
|
||||||
|
```
|
||||||
|
|
||||||
|
That is the **Stage 02 escort mission** (the `ACROPOLIS` of
|
||||||
|
[`autopilot-memory-driven.md`](autopilot-memory-driven.md)), not the S01 training
|
||||||
|
area with `UN_S01_Asteroid_cmesh_*` that earlier runs loaded. Slot 01 is the
|
||||||
|
**auto-save**, so the mission it restores moves as the save is written.
|
||||||
|
|
||||||
|
❌ **This invalidates the earlier "101 vs 42" comparison outright** — those two
|
||||||
|
numbers came from *different stages*, not merely different moments. And it means
|
||||||
|
no runtime roster is reproducible across runs unless the stage is verified first.
|
||||||
|
|
||||||
|
## Same moment, same stage, both methods
|
||||||
|
|
||||||
|
| type | `INST_VTABLE` scan | moving + `+0x130` |
|
||||||
|
|---|---|---|
|
||||||
|
| `UN_e007_ADAN_Turret` | 21 | 14 |
|
||||||
|
| `UN_e010_ADAN_Attacker_S` | 9 | 8 |
|
||||||
|
| `UN_f001_TCAF_DeltaSaber_T` | 7 | 7 |
|
||||||
|
| `UN_f001_TCAF_DeltaSaber_T_Player` | 1 | 1 |
|
||||||
|
| `UN_e106_ADAN_Destroyer` | 19 | **0** |
|
||||||
|
| `UN_f106_TCAF_Destroyer` | 14 | **0** |
|
||||||
|
| `UN_f105_TCAF_Cruiser` | 11 | **0** |
|
||||||
|
| `UN_e105_ADAN_Cruiser` | 7 | **0** |
|
||||||
|
| `UN_e108_ADAN_ASFrigate` | 9 | **0** |
|
||||||
|
| `UN_e201_ADAN_ISCMissile` | 9 | **0** |
|
||||||
|
| `UN_f003_TCAF_ArrowHead` | 6 | **0** |
|
||||||
|
| `UN_f101_TCAF_Acropolis` / `bf001_SchlosBase` / `f201_Tanker` | 1 each | **0** |
|
||||||
|
| **total** | **116** | **30** |
|
||||||
|
|
||||||
|
## ✅ The absence is structural, not a filter artifact
|
||||||
|
|
||||||
|
The obvious explanations were tested and **both fail**:
|
||||||
|
|
||||||
|
* **Speed band.** `moving()` filters displacement to `lo=1.0 … hi=4000.0` per
|
||||||
|
0.5 s, which would exclude a slow capital ship. Dropping the floor to **0** and
|
||||||
|
the ceiling to 1e12 raised the count 30 → 59 and recovered the `_Player` — but
|
||||||
|
still **only 4 types**. Capital ships never appear.
|
||||||
|
* **Address window.** `moving()` defaults to `0xBD000000–0xBE000000`. Scanning
|
||||||
|
the **whole map** with no speed floor gives 181 824 movers and **still 4 types**.
|
||||||
|
|
||||||
|
So the ten missing types do not have a definition pointer at `position + 0x130`
|
||||||
|
anywhere in memory that a moving-triple scan can reach. **The `+0x130` block is
|
||||||
|
not the universal entity record — it belongs to a subset.**
|
||||||
|
|
||||||
|
🟡 The subset is *nearly* "small craft": every type it does cover is a fighter,
|
||||||
|
attacker or turret. But `UN_f003_TCAF_ArrowHead` is a TCAF fighter and reads
|
||||||
|
**0**, so "small craft" is not the rule. ❔ What actually distinguishes them is
|
||||||
|
not established — plausibly an active-flight-model flag, with parked wingmen and
|
||||||
|
capital ships handled by a different update path.
|
||||||
|
|
||||||
|
## ✅ They live in different regions, which is why they are different structures
|
||||||
|
|
||||||
|
```
|
||||||
|
vtable instances : 0xbc372cc0 .. 0xbc9bc720 (116)
|
||||||
|
ENT_VA window : 0xbd000000 .. 0xbe000000
|
||||||
|
instances inside that window : 0/116
|
||||||
|
```
|
||||||
|
|
||||||
|
**Zero** of the 116 vtable objects lie in the window where the `+0x130` position
|
||||||
|
blocks are found. This is independent confirmation of
|
||||||
|
[the earlier refutation](entity-position-anchor-refuted.md): the vtable object and
|
||||||
|
the position block are separate allocations in separate regions, not two views of
|
||||||
|
one record.
|
||||||
|
|
||||||
|
## Which list to use
|
||||||
|
|
||||||
|
* **Completeness** — the `INST_VTABLE` scan. It sees all 14 types including
|
||||||
|
stations, capital ships and the objective-critical `Acropolis`.
|
||||||
|
* **Motion state** — the `+0x130` blocks. They carry position, speed, orientation
|
||||||
|
(`pos−0x70`, stride 16) and hull (`pos+0x154`), but only for ~4 types.
|
||||||
|
* An autopilot that must protect the `Acropolis` **cannot** locate it through the
|
||||||
|
`+0x130` method at all. That is a concrete limit on the existing approach.
|
||||||
|
|
||||||
|
## Also confirmed
|
||||||
|
|
||||||
|
The exact **2× duplication** reappeared: def-pointer hits come in pairs `0x1000`
|
||||||
|
apart with byte-identical positions (`0x011db3bd80` / `0x011db3cd80`, both
|
||||||
|
`(-1654.7, -3992.7, 458.2)`, both moving 424.482). ❌ It is **not** page aliasing
|
||||||
|
in `gmem.MAP` terms — aliased VAs share one *file offset*, and these differ by
|
||||||
|
`0x1000` in the offset itself, so they are genuinely two copies.
|
||||||
|
|
||||||
|
❌ **Correction to [the previous note](entity-count-discrepancy-resolved.md):** it
|
||||||
|
said "at least one of the counts was un-deduplicated". That is wrong —
|
||||||
|
`entities2.py` prints its count *after* `ents = list(uniq.values())`, so the 101
|
||||||
|
was already deduplicated. The gap was the stage change, not duplication.
|
||||||
Reference in New Issue
Block a user