This repository has been archived on 2026-09-16. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Syplheed-Reborn/docs/re/two-entity-enumerations.md
Sylpheed RE agent a21927ab01 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.
2026-08-26 22:24:35 +00:00

99 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ✅ 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 `0xBD0000000xBE000000`. 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
(`pos0x70`, 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.