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/structures/regn-map-grid.md
Sylpheed RE agent 7482142abf re: find the mission wave data — stage records and the UnitGroup squadron roster
Sweeping the 811 unnamed IDXD objects in GP_MAIN_GAME_E.pak by schema turned up
schema 3c9ae32e: the per-stage definition record. 23 of them, one per stage,
each naming its background, resource package, collision set, message set,
nameplates, MapMesh/MapPath and EnumerateSquadron = UnitGroup_S<NN>.tbl.

That resolves two open threads at once:

  - MapPath = test.rgn hashes to 0x3506e972, a REGN object in MiscBin.pak, and
    MapMesh = test.col to 0x2cf7eb47, an MCOL object. REGN is a stage's map
    path data; MCOL is its collision mesh.

  - stage\UnitGroup_S02.tbl (0x019fd129, in all six language paks) is the
    Stage 02 squadron roster: 112 records, 112 squadron IDs, and a field
    vocabulary of FormationID / AIID / SideID / Count / DisableInterval, plus
    the unit model (UN_e010_ADAN_Attacker_S and friends, which match the XBG7
    mesh names we already decode), the MessageSet and the pilot character.

DisableInterval is the first direct evidence of the arrival-timing knob, which
is what the user's reframing predicted: the mission has a schedule with
parameters, not a fixed roster.

Container layout is only partly read. The 112x16 entry array was confirmed by
its boundary — keys increase for exactly 112 entries and break at 0x708, where
the next section header sits — not assumed. pak dump mislabels this file's
first key as its schema.

Refuted and recorded: the 16-byte record key is not the squadron ID's name
hash. name_hash("TCN001") = 0xd639f1a4 but the keys start 0x659aff47; 0 of 112
match.

Still open: the per-record payload fields, the meaning of the key, where the
interval values actually live, and the missing S17-S23 stage records.
2026-08-24 10:52:35 +00:00

146 lines
6.2 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.
# `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: 878998 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.