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/mcol-collision.md
Sylpheed RE agent 8df3624b70 re: MCOL's pointer layout, read from POF0
Used the known-good decoder rather than my own broken one. My version had three
errors: the delta stream starts at table+16 not +8, the tag bits are
0x40/0x80/0xC0 rather than 0/1/2, and slots carry the +16 fixup base. Sanity
check passes -- on REGN the tool returns header slots 0x70-0x84 exactly.

On MCOL, over all 11: the header-region relocated slots are exactly 0x54, 0x58,
0x5C and 0x74 (11/11); 0x5C resolves to 0x80, the first byte after the header
(11/11); and 0x74 resolves to eight bytes before the first array pointer (10/11).
So MCOL has four top-level pointers where REGN has six.

92.7% of gaps between consecutive relocated words are 32 bytes, in 7-127
contiguous runs per object, which with the 0x74 offset reads as arrays of
32-byte records each carrying a pointer at +8.

The four targets are two float blocks, a block of small ints / u16 pairs, and
counts followed by the record array -- the shape of a mesh, stated as a reading
of the shape since none of the blocks is decoded.

Open: the record layout, what the index block indexes, the one object where 0x74
does not land 8 before the array, and whether the 7.3% non-32 gaps are just run
boundaries.
2026-08-26 08:25:29 +00:00

3.9 KiB
Raw Blame History

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.
  • Everything past 0x40 — but see below; the pointer layout is now known.

✅ The pointer layout, from POF0

2026-08-26. Running the known-good decoder (regn_decode.py on auto/regn-reader) rather than my own broken one. Sanity check first: on REGN it returns header slots 0x70–0x84 exactly — the six section pointers — so the tool and my use of it are right.

On MCOL, over all 11 objects:

header-region relocated slots are exactly 0x54, 0x58, 0x5C, 0x74 11 / 11
slot 0x5C resolves to 0x80 — the first byte after the header 11 / 11
slot 0x74 resolves to (first array pointer − 8) 10 / 11

So MCOL has four top-level pointers where REGN has six, and one of them (0x5C) always addresses the data immediately following the header.

The bulk of the relocations form record arrays. 92.7 % of the gaps between consecutive relocated words are 32 bytes, arranged in 7–127 contiguous runs per object. Combined with 0x74 landing 8 bytes before the first of them, the reading is an array of 32-byte records each carrying one pointer at +8.

What the four targets look like:

0x5C -> 0x80     c685620b 4596789d 4694b3b5 44a9a634   floats
0x54 -> …        c6826964 456b1aa4 469ab065 c685cfe8   floats
0x58 -> …        00000001 00020003 00040005 00050004   small ints / u16 pairs
0x74 -> …        00000001 00000001 00007710 00000000   counts, then the array

Two float blocks, an index block and a record array is the shape of a mesh — which is what a name like MCOL beside a navigation mesh would suggest. 🟡 That is a reading of the shape; none of the four blocks has been decoded.

❔ Still open: the record layout, what the index block indexes, the one object in eleven where 0x74 does not land 8 before the array, and the 7.3 % of gaps that are not 32 (they are the boundaries between runs, but that has not been checked).