diff --git a/docs/re/BACKLOG.md b/docs/re/BACKLOG.md index d7d28d20..02ebb6e8 100644 --- a/docs/re/BACKLOG.md +++ b/docs/re/BACKLOG.md @@ -5752,3 +5752,44 @@ map to their objects' pak entry keys under `name_hash`, nor under that key reduced `mod 0x00FFF9D7` or masked to 24 bits. The join above is by frame prefix, which is direct evidence; either those keys are not name hashes or [[archive-naming]]'s resolver differs from `unitgroup.name_hash`. Not chased. + +--- + +## ✅✅ 2026-08-28 — `EnumAsteroid` counts the rocks, and the hash join was mine to fix + +Item (a), both open questions from the asteroid write-up, settled. + +✅ **`EnumAsteroid` is the frame record's `FrameCount` — 57 / 57, zero +mismatches.** Each `AsteroidFrameName` is itself an IDXD **record name**; those +records carry one named field, `FrameCount`, plus a run of anonymous ones, and +the anonymous fields number **exactly 8 × `FrameCount` on all 384 occurrences** +(ratio histogram `{8.0: 384}`). The frame record is the **placement table — 8 +values per asteroid** — and `EnumAsteroid` counts the rocks in it. The +frame-name → `EnumAsteroid` map is single-valued for all 64 names. + +[[mission-wave-arrivals]] already met these records — they were the outliers that +broke its route-speed measurement, filtered out by name, with "the corpus already +records that the 8-value frame is not universal". [[regn-map-grid]] already +guessed the link and said so honestly: "stated as a reading, not a measurement; +nothing here counts objects." **What neither says is that the count is exact.** + +🔑 **The abandoned table lost its placement data too.** Exactly **7 of 64** frame +names have no record, and they are exactly the seven groups of the unreferenced +tenth object — `Frame_Alpha_S01_Asteroid_{01,02,04}`, +`Frame_Alpha_S01_Haze_{01,02,03}`, `Frame_TAlpha_S01_Asteroid_03`. `57 + 7 = 64`, +zero partials either way. + +✅ **Withdrawing yesterday's 🔴: the hash join works, my call was wrong.** +`AsteroidDefinition` values resolve to their objects' pak entry keys as +**`name_hash("stage\" + name)` — 9 of 9**, each landing on the object the +frame-prefix join independently predicted. I had hashed the **bare file name**; +[[archive-naming]]'s resolver hashes `prefix + name` over a list of path +prefixes, and `stage\` is the one that works here (`Stage\` scores identically — +the hash lower-cases). **Two independent joins, 9/9 agreement**, both leaving the +same tenth object unreferenced. Lesson: before calling a corpus routine's result +a discrepancy, **read how the corpus routine calls it** — the prefix list was in +`archive_naming.py` the whole time. + +🟡 Not settled: what the 8 values per asteroid are (position/rotation/scale is the +obvious reading, untested — [[regn-map-grid]] has the neighbouring work); why +`S28_p1` has an asteroid volume and no definition. diff --git a/docs/re/INDEX.md b/docs/re/INDEX.md index 31b64a87..53ce8cdd 100644 --- a/docs/re/INDEX.md +++ b/docs/re/INDEX.md @@ -119,7 +119,7 @@ files, which is how the same ground got covered twice. | [`structures/isl-message-dialogue-link.md`](structures/isl-message-dialogue-link.md) | Mission scripts as dialogue — built-in 64 -> message id -> caption text | ✅ CONFIRMED total, 2 683/2 683 call sites across all 28 stages resolve, no residue | | [`structures/mission-objective-counter.md`](structures/mission-objective-counter.md) | `REMAINING OB` — the mission's own objective counter, in RAM | ✅ CONFIRMED for one Stage 02 run: a big-endian u32 whose value | | [`structures/movie-subtitles.md`](structures/movie-subtitles.md) | Movie subtitles & the movie ↔ mission ↔ text chain | — | -| [`structures/asteroid-fields.md`](structures/asteroid-fields.md) | `AsteroidGroup_00N` — the asteroid-field tables a `Phase_N.AsteroidDefinition` names | ✅ 10 objects/pack, 384 group records, 3 fields each (`AsteroidModelName`, `AsteroidFrameName`, `EnumAsteroid` = a count 1…588); `Enum` counts while `Enumerate` names a table (54/60); 🔑 a tenth `Frame_Alpha_S01_*` object nothing references — and it is the one that miscounts; 🔑 **S28_p1 has an asteroid volume but no definition** | +| [`structures/asteroid-fields.md`](structures/asteroid-fields.md) | `AsteroidGroup_00N` — the asteroid-field tables a `Phase_N.AsteroidDefinition` names | ✅ 10 objects/pack, 384 group records, 3 fields each (`AsteroidModelName`, `AsteroidFrameName`, `EnumAsteroid` = **the frame record's `FrameCount`, 57/57**, and the frame holds 8 anonymous values per asteroid); `Enum` counts while `Enumerate` names a table (54/60); the join resolves as `name_hash("stage\" + name)` 9/9; 🔑 a tenth `Frame_Alpha_S01_*` object nothing references — it miscounts AND its 7 frames have no placement records; 🔑 **S28_p1 has an asteroid volume but no definition** | | [`structures/mcol-collision.md`](structures/mcol-collision.md) | `MCOL` — same container and map parameters as `REGN` | 🟡 OPENED — `POF0` at `data_size+16` 11/11, bbox pad words 11/11, `extent == max−min` 11/11, and bbox + cell-size distributions identical to `REGN` (2/6/3 and 2/9); everything past `0x40` ❔ | | [`structures/regn-map-grid.md`](structures/regn-map-grid.md) | `REGN` — a per-map spatial grid (and `MCOL` beside it) | ✅ CONFIRMED for the header, which self-checks on all 11 objects on | | [`structures/savegame-format.md`](structures/savegame-format.md) | Save file (`savedata`) — container ✅ exact, 3 fields named ✅, rest ❔ (2026-08-11) | ✅ CONFIRMED for the container and the chunk layout — parsed off the | diff --git a/docs/re/structures/asteroid-fields.md b/docs/re/structures/asteroid-fields.md index 348a119f..79bdf441 100644 --- a/docs/re/structures/asteroid-fields.md +++ b/docs/re/structures/asteroid-fields.md @@ -73,14 +73,48 @@ the two sets share eight and differ by one each: **`S28_p1` has the collision volume for an asteroid field but no table saying which rocks to scatter in it**, while `test_s8p1` has a table with no volume of its own. +## ✅ `EnumAsteroid` is the frame record's `FrameCount` — 57/57 (2026-08-28) + +Each `AsteroidFrameName` is itself an **IDXD record name**. Those records carry +one named field, **`FrameCount`**, and a run of anonymous ones: + +* **`EnumAsteroid` equals that record's `FrameCount` in 57 of 57** frames that + have a record — **zero mismatches**, and the map is single-valued for all 64 + frame names. +* The anonymous fields number **exactly 8 × `FrameCount`, on all 384 occurrences** + (ratio histogram: `{8.0: 384}`). So the frame record is a table of + **8 values per asteroid** — the placement data — and `EnumAsteroid` counts the + rocks. + +[[mission-wave-arrivals]] already met these records: they were the outliers that +broke its route-speed measurement, and it filtered them out by name, noting "the +corpus already records that the 8-value frame is not universal". [[regn-map-grid]] +already guessed the link — "a map's asteroids and debris, which the mission +`Route` tables independently show as `Frame_S_Asteroid` records… stated as a +reading, not a measurement; nothing here counts objects." **What neither says is +that the count is exact.** Now it is measured. + +🔑 **The abandoned table lost its placement data too.** Exactly **7 of the 64** +frame names have no record, and they are exactly the seven groups of the +unreferenced object: `Frame_Alpha_S01_Asteroid_{01,02,04}`, +`Frame_Alpha_S01_Haze_{01,02,03}`, `Frame_TAlpha_S01_Asteroid_03`. `57 + 7 = 64`, +zero partials on either side. + +## ✅ The name→object join DOES reproduce by hash — with the path prefix + +Withdrawing the 🔴 from the first write-up. `AsteroidDefinition` values resolve +to their objects' pak entry keys as **`name_hash("stage\" + name)`**, **9 of 9**, +each landing on the object the frame-prefix join independently predicted. My +first attempt hashed the bare file name; [[archive-naming]]'s resolver hashes +`prefix + name` over a list of path prefixes, and `stage\` is the one that +works here. (`Stage\` scores identically — the hash lower-cases.) + +**Two independent joins, 9/9 agreement**, and both leave the same tenth object +unreferenced. + ## 🟡 Not settled -* What `EnumAsteroid` counts *of* — instances per frame is the obvious reading - and the 1…588 range fits, but it is untested. -* Why `S28_p1` has a volume and no definition (S28 is the challenge mission that - alone flies `rou_f004`, see [[stage-numbering-and-player-craft]]). -* 🔴 **The name→object join did not reproduce by hash.** `AsteroidDefinition` - values do not map to their objects' pak entry keys under `name_hash`, nor under - that key reduced `mod 0x00FFF9D7` or masked to 24 bits — the join above is by - frame prefix, which is direct. Either these keys are not name hashes or - [[archive-naming]]'s resolver differs from `unitgroup.name_hash`; not chased. +* What the 8 values per asteroid are — position/rotation/scale is the obvious + reading, untested here; [[regn-map-grid]] has the neighbouring work. +* Why `S28_p1` has an asteroid volume and no definition (S28 is the challenge + mission that alone flies `rou_f004`, see [[stage-numbering-and-player-craft]]).