# `REGN` — a per-map spatial grid (and `MCOL` beside it) **Status: ✅ `CONFIRMED` for the header**, which self-checks on all 11 objects on the disc. ❔ the four data sections are undecoded. **New to this corpus** — no document mentioned `REGN`, `MCOL` or `hidden/MiscBin.pak` before 2026-08-24. ## Where it is `hidden/MiscBin.pak` — 40 entries, **none** name-resolved, in three groups: | magic | count | sizes | |---|---|---| | `REGN` | **11** | 49 KB … 3.1 MB | | `MCOL` | **11** | 37 KB … 81 KB | | (other) | 18 | — | Eleven of each, which pairs them: one `REGN` and one `MCOL` per map. `MCOL` is untouched here; the name and the size range read like mesh collision. ## The header, and why it is believable ``` 0x00 char[4] 'REGN' 0x04 u32 size of the data area (the POF0 table starts at 0x04-value + 16) 0x10 f32[4] bbox min (x, y, z, 1.0) 0x20 f32[4] bbox max (x, y, z, 1.0) 0x30 f32[4] extent (max - min) 0x40 f32[4] cell size 0x50 u32[4] grid dimensions 0x60 u16[6] six counts 0x70 u32[4] four section offsets (the first is always 0x80) ``` **The check that makes this a decode rather than a guess** — over all 11 objects: * `extent == cell × dims` holds **11 of 11**, exactly; * `counts[3]` equals the **cell count**: `1000` on every 10×10×10 map and `125` on every 5×5×5 one. Two independent fields reproducing the grid is what rules out coincidence. ## The three map sizes on the disc | half-extent | cell | dims | objects | |---|---|---|---| | 250 000 | 50 000 | 10×10×10 | 2 | | 50 000 | 10 000 | 10×10×10 | 6 | | 25 000 | 10 000 | 5×5×5 | 3 | So every map is a cube partitioned into 125 or 1 000 uniform cells — 10 km cells in a 100 km cube for the common case, and one pair of maps five times larger. ## ✅ Section 3 is the cell index — and it self-checks 11/11 The fourth section is a **one entry per cell** table of 8-byte records `(count, offset)`, immediately followed by the records those offsets point at: ``` index = offsets[3] .. offsets[3] + cells*8 payload = align16(index end) .. record = 32 bytes (offsets step by 0x20) ``` Checked over all 11 objects: the lowest offset any cell refers to equals **`align16(offsets[3] + cells × 8)` — 11 of 11**. On the six 10×10×10 maps `cells × 8` is already 16-aligned and the payload butts straight up against the index; on the three 5×5×5 maps `125 × 8 = 1000` is not, and the payload starts 8 bytes later, which is what makes the alignment rule visible rather than assumed. Two more invariants from the same sweep: * every occupied cell has count **exactly 1** — total items equals occupied cells on all 11 objects, so this is "one record per cell", not a bucket list; * **`counts[4] = occupied cells + 2`**, exactly, on all 11 (e.g. 997/995, 880/878, 125/123). The `+2` is unexplained — two sentinels, or two cells counted differently. Most cells are occupied: 878–998 of 1 000, 123 of 125. ## ✅ It is a serialised object graph with a `POF0` fixup table Every one of the 11 objects contains the tag **`POF0`**, always near the tail, and its position is exactly **`header[0x04] + 16`** — on **11 of 11**: ``` e993b93e header +0x04 = 0x0b100 POF0 at 45328 = 45312 + 16 e4155d94 header +0x04 = 0x235d70 POF0 at 2317696 = 2317680 + 16 … 11 of 11 identical relation ``` `POF0` is a **pointer-offset (fixup) table**: the file is a serialised C++ object graph, and the loader patches the recorded slots into real pointers. That explains a detail that would otherwise be odd — the "offsets" inside the cell index are absolute **file** offsets, because that is what a fixup table rewrites. So `header[0x04]` is the size of the data area, and everything past `header[0x04] + 16` is relocation bookkeeping rather than content. ## 🔴 Two readings of the cell payload, both refuted by generalising Both came from the smallest object and both died the moment they were checked against the other ten — recorded because the temptation to keep them was real: * **"the `f32` at record `+0x1c` is the grid's bounding-sphere radius."** On `e993b93e` it is 86 689 against `√3 × 50 000 = 86 603`, a ratio of **1.001**. On the other ten the ratio runs **0.13 – 0.27**. Fitted to one sample. * **"a record's `(count, offset)` pairs point at leaf arrays of `count × 4` bytes."** True for the first record of `e993b93e`; across the objects the offset deltas fail that rule on **every** object checked (0 of 11 clean). What survives is only descriptive: the payload area is dominated by **float data** — the "strings" a printable-run scan finds are all byte patterns like `0x46`/`0x47` high bytes, i.e. medium-magnitude floats, not text. ## ❔ The other three sections Their offsets scale with the object, and `counts[0..2]` scale with them — `(318, 1172, 2584)` for the 350 KB map against `(2936, 14967, 31155)` for the 3.1 MB one, a roughly `1 : 4.5 : 10` ratio that holds across all eleven. The smallest object (49 KB) is nearly empty by comparison — `(8, 6, 18)` — which makes it the cheapest one to decode first. ## Why this matters, stated without overclaiming A mission's enemy count **rises and falls** as waves arrive and are destroyed, so somewhere there is a scheduler with parameters — what spawns, where, and on what trigger. A per-map uniform grid indexed by cell is exactly the structure such a thing is indexed *by*. 🔴 **But nothing here shows spawn parameters yet.** The header is a spatial partition and no more; the sections are unread. Treat this as the location of the world's spatial data, not as the wave table. ## ✅ Update: `REGN` is a stage's **MapPath** The per-stage definition record (see [stage-definition-table.md](stage-definition-table.md)) has a field `MapPath = test.rgn`, and `name_hash("test.rgn") = 0x3506e972`, which is one of the `REGN` objects in `MiscBin.pak`. The sibling field `MapMesh = test.col` hashes to `0x2cf7eb47`, an `MCOL` object in the same pak. So `.rgn`/`REGN` is stage navigation/path data referenced by the stage record, and `.col`/`MCOL` is the stage collision mesh. This does not by itself validate either of the two refuted cell-payload readings recorded above, but it does explain why the payload looks like a grid of route data. ## ✅ Sections 0, 1 and 2 have record strides — and section 2 is a PLANE list **2026-08-26.** The three sections the page called undecoded are fixed-stride record arrays, and `counts[0..2]` are their record counts. Dividing each section's byte span by its count over all 11 objects: | section | stride | evidence | |---|---|---| | 0 | **12 bytes** | `count × 12` fits with a remainder of 0–12 in **11 / 11** | | 1 | **96 bytes** | `count × 96` fits with a remainder of **exactly 0 in 11 / 11** | | 2 | **48 bytes** | `count × 48` fits with a remainder of **exactly 96 in 11 / 11** | Section 1 landing on a zero remainder in every object, and section 2 on the same 96-byte tail in every object, is what makes these strides rather than a coincidence of division. ### ✅ Section 0 is a point list 12 bytes is three `f32`. Over **13 467** records across all 11 objects, **every one lies inside that object's own header bounding box — 13 467 / 13 467 (100 %)**. Values land on the box corners (`±250 000`) and inside. ### ✅ Section 2 is a plane list — 48 bytes, and the plane equation closes Read as twelve `f32`: [0..3] zero [4..6] unit normal |n| = 1 ± 0.02 in 133 573 / 133 573 (100 %) [7] signed distance d [8..10] a point on the plane, inside the bbox in 133 573 / 133 573 (100 %) [11] 1.0 exactly in 133 573 / 133 573 (100 %) **The check that makes this a decode**: for a genuine plane, `n·p + d` must be zero. Over all **133 573** records: |n·p + d| / scale : median 2.29e-08 p90 6.78e-08 max 2.15e-07 That is float round-off, not a fit — the relation holds to the last bits of a 32-bit float in **every record on the disc**. Three independent 100 % properties (unit normal, point in bbox, trailing 1.0) and an exact algebraic identity are well past what a wrong reading survives. So a `REGN` object carries, alongside its uniform grid, a **point list** and a **plane list** — which is the shape of collision or region-boundary geometry, and consistent with `MCOL` sitting beside it. ### ❔ Still open * **Section 1** (96 bytes/record, **63 410** records disc-wide) — a per-slot census is below, but what the record *means* is still ❔. * **What the planes are for.** "Collision or region boundary" is a reading of the shape; nothing here shows what queries them. * The **zeros at `[0..3]`** of every plane record, and the constant `96`-byte tail after section 2, are unexplained. ## 🟡 Section 1, slot by slot — measured, but not read **2026-08-26.** 96 bytes is 24 slots. Censusing every one of the **63 410** records across all 11 objects gives a clear regional structure, even though the record's purpose is not settled: | slots | what the values are | reading | |---|---|---| | 0–3 | slots 2 and 3 are zero in ~100 %; 0 and 1 mostly small | ❔ | | **4–6** | 96 % have \|v\| > 1 000, range **±250 000** — the header bbox range | 🟡 a **position** | | **7** | 99.9 % > 1 000, always positive, 519 … 107 600 | 🟡 a **radius or extent** | | 8–11 | as `f32` these are **denormals** (1.4 × 10⁻⁴⁵ upward) — i.e. they are **integers**, not floats | ✅ integer fields | | 12–23 | six **pairs**: the even slot 200 … 67 000 and never zero, the odd 0 … 212 000 and zero in 7–13 % | ❔ | The denormal signature in slots 8–11 is worth stating plainly: a float field never holds `1.4e-45`, so those four words are integers that a float reader would silently turn into near-zero garbage. A position plus a positive scalar plus integer links is the shape of a **bounding-volume hierarchy node**, which would fit a file that also carries a point list and a plane list. That is a reading of the shape and nothing more. ### ❌ The index test has no discriminating power I tried to confirm the integer slots are indices by splitting each into two `u16`s and checking them against each section's record count. The result is useless, and the reason is worth recording: | slot | halves valid for section 0 | section 1 | section 2 | |---|---|---|---| | 8 | 100.00 % | 100.00 % | 100.00 % | | 9 | 100.00 % | 99.99 % | 100.00 % | | 10 | 8.78 % | 44.19 % | 100.00 % | | 11 | 8.76 % | 44.16 % | 100.00 % | **A test that accepts every hypothesis rejects none.** Section 2 has tens of thousands of records, so "is this `u16` below the plane count" is satisfied by almost any small number — it measures the size of the section, not the meaning of the field. Only slots 10 and 11 discriminate at all, and they merely rule *out* section 0. `slot 11`'s halves are consecutive (`n`, `n+1`) in 54 % of records and slot 10's in 12 % — suggestive of paired links, but 54 % is not a rule and I am not promoting it. ❔ So section 1 stays open. What would settle it is a test with power: pick a record, follow a candidate index, and check that the thing it lands on is spatially consistent with that record's own position and radius. That needs the tree walked, not the fields counted. ## ❌ The BVH reading is refuted — and slot 7 is a *local* scale **2026-08-26.** Last iteration I wrote that "position + positive scalar + integer links is the shape of a bounding-volume hierarchy node", explicitly as a reading of the shape. Tested with a design that has power, it fails. **The containment test.** If slots 8–11 hold child indices, a child's sphere should sit inside its parent's. Following every `u16` half of every integer slot and checking `|C_child − C_parent| + R_child ≤ R_parent` (2 % slack): RANDOM control 0 of 126 787 = 0.00 % slot 8 half 0 63 389 tried 0.00 % slot 8 half 1 63 395 tried 0.00 % …every candidate… 0.00 % **The random control is the informative row.** It is also 0.00 %, which means no node's sphere contains any other node's sphere *anywhere in the file* — so there is no nesting for an index to point at, whatever the indices mean. The hypothesis fails before the indices are even in question. **Why**: slot 7 is far too small to bound neighbours. | | median | p10 | p90 | |---|---|---|---| | slot 7 | **3 139** | 1 965 | 9 275 | | pairwise centre distance | **45 457** | 19 071 | 126 295 | Slot 7 is **14× smaller** than the typical distance between nodes, and a random other centre falls within it only **0.40 %** of the time. It is also smaller than the smallest grid cell on any map (10 000). So ✅ **slot 7 is a local scale, not a hierarchy radius** — sub-cell sized, with a narrow spread. Together with 63 410 scattered centres across a 500 km cube, that is the shape of **many small independent volumes**, not a tree. 🟡 That fits per-object collision volumes — 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. ❔ Still open: what slots 8–11 index, and what the six pairs in 12–23 are. What this iteration removed is a wrong frame — the file is not a tree, so tree-shaped tests will keep returning nothing. ## ❌ The cell index does not reference section 1 — two powered tests, both negative **2026-08-26.** The obvious coupling in a file with a uniform grid and a list of small volumes is that the grid indexes the volumes. It does not, by the only test that could show it: **spatial agreement**. **Test 1 — the cell payload as indices.** For every occupied cell, read its 32-byte payload record and try each `u16` in it as a section-1 index, then check whether that node's centre lies **inside the cell that referenced it**: RANDOM control 0.138 % +0 0.08 % +2 0.18 % +4 0.11 % +8 0.08 % +10 0.10 % +12 0.08 % +14 0.08 % … Every field sits at the chance rate. **Nothing points at section 1.** **Test 2 — the cell payload as coordinates.** 32 bytes is eight floats, so a position could be in there. Trying every float triple and asking whether it lies inside its own cell: +0 0.81 % +4 0.81 % +8 0.15 % +12 0.16 % +16 0.26 % +20 0.78 % Also chance. ### ⚠️ And the tempting number in that table is worthless The same run reported those triples lie **inside the object's bounding box in 100.00 %** of cases, at five different offsets. That looks like a decode and is not: the bbox spans the entire 500 km map, so *any* mid-range float triple passes, and overlapping windows starting at +0 and +4 both scoring 100 % is the tell — a real field would not survive being read at a four-byte shift. It measures the size of the box, not the meaning of the bytes. This is the third time in this file's investigation that a containment test against something large has produced a meaningless 100 %, so it is recorded rather than quietly dropped. ❔ So the grid and section 1 have no demonstrated link, and how a cell reaches its geometry is unknown. What is now excluded: the cell payload holding section-1 indices, and holding cell-local coordinates. ✅ Incidental, from the same sweep: `u32` slots at **+0, +8 and +12** of the payload record are below `0x10000` in **100 %** of records, while +4, +16, +20 and +24 are in only 11 % and +28 never — so the record has three index-shaped fields and four wide ones, whatever they refer to.