diff --git a/docs/re/INDEX.md b/docs/re/INDEX.md index c5e1cd48..d1a0f0d4 100644 --- a/docs/re/INDEX.md +++ b/docs/re/INDEX.md @@ -101,6 +101,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/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 | | [`structures/sound-slb.md`](structures/sound-slb.md) | Sound bank audio — `sound.pak` / `.slb` / XMA1 | — | diff --git a/docs/re/structures/mcol-collision.md b/docs/re/structures/mcol-collision.md new file mode 100644 index 00000000..e9102f04 --- /dev/null +++ b/docs/re/structures/mcol-collision.md @@ -0,0 +1,59 @@ +# `MCOL` — the same container as `REGN`, and the same map parameters + +**🟡 Opened 2026-08-26.** `MCOL` sits beside `REGN` in `hidden/MiscBin.pak`, 11 +of each, and has never been decoded. This page establishes what it shares with +`REGN` — which is a lot, and gives the next attempt a large head start. + +## ✅ Same container + +Over all **11** objects: + +| | | +|---|---| +| `POF0` fixup table at `data_size@+4` + 16 | **11 / 11** | +| bbox pad words are `1.0` / `1.0` / `0.0` at `+0x1C`, `+0x2C`, `+0x3C` | **11 / 11** | +| `extent == max − min` for the `0x30` block | **11 / 11** | + +So the header prefix is byte-for-byte the same shape as `REGN`'s: magic, data +size, then bbox min / bbox max / extent as `f32[4]`, then a triple at `0x40`. +The `POF0` mechanism applies, which means **the `chunk + 0x10` base and the +loader's own pointer list are available here too** — the two things that cracked +`REGN`. + +## ✅ And the same map parameters, exactly + +The bounding boxes and the `0x40` triple are not merely similar — the +distributions are **identical**: + +| | `MCOL` | `REGN` | +|---|---|---| +| bbox ±250 000 | 2 | 2 | +| bbox ±50 000 | 6 | 6 | +| bbox ±25 000 | 3 | 3 | +| `0x40` = 50 000 | 2 | 2 | +| `0x40` = 10 000 | 9 | 9 | + +Eleven maps, and for each one an `MCOL` and a `REGN` describing the same volume +at the same cell size. `0x40` is the **cell size** in `REGN`; the same values in +the same multiplicities here is strong evidence it is the cell size in `MCOL` +too — though note this is a match of *distributions*, not a demonstrated +object-to-object pairing, which would need the two linked by name or by a stage's +tables. + +## ❔ What is not yet known + +* **Everything past `0x40`.** `MCOL`'s words at `0x50`–`0x84` do **not** look + like `REGN`'s (`REGN` has grid dims at `0x50`, six `u16` counts at `0x60` and + six section pointers at `0x70`; `MCOL` has a large value, two mid-range values + and `112` at `0x50`, mostly zeros at `0x60`, and `0x05050501` at `0x70`). The + headers agree on the spatial prefix and diverge after it. +* **My `POF0` delta decoder is wrong here** — it emits eight leading zero deltas + before plausible offsets, so either the stream has a preamble I am not + skipping or my 6/14/22-bit reading is off. The working decoder is + `tools/re-capture/regn_decode.py` on branch `auto/regn-reader`; **use that + rather than re-deriving it**, which is the mistake I made here. + +**First step for whoever continues**: run the known-good `POF0` reader over an +`MCOL`, list which words are relocated, and read the header slots those pointers +occupy. That is exactly the move that turned `REGN` from twenty failed +correlations into a decode.