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/collisionset.md
Sylpheed RE agent d677bcfd80 re: decode CollisionSet_*.bin -- the per-object collision-mesh library
All 18 blobs are byte-identical: the per-stage naming is nominal, and every
stage points at one shared 1675148-byte library stored eighteen times.  That
identical size was the reason to open the item, and it turned out to be the
answer to it.

Record layout: {u32 size, u32 name_len, char name[name_len], u32 nv, u32 nt,
f32[3] x nv, u32[3] x nt}, next record at off + 8 + size.  The indices are u32
here where MCOL uses u16 -- two different serialisers in one archive.

What makes this a decode rather than a plausible reading: the walk consumes the
file to the byte over 158 variable-length records, with the size word predicted
from the two counts 158/158.  A wrong field would desynchronise within a few
records and could not land exactly on the end.  All indices in range 158/158;
98.24% of edges shared by exactly two triangles; 147/158 fully manifold.

158 meshes, 90 836 triangles: per-part ship proxies (_bdy/_brg/_eng/_wep/_sld,
the XBG7 sub-part vocabulary) plus 46 stage asteroid meshes whose prefixes are
exactly the stages that have an _AsteroidVolume_wp MCOL.

Two things this file makes me walk back:

  * The "1 unit = 1 metre" reading from mapmesh_box_500km is downgraded to
    amber.  The 500000 arithmetic stands, but it implies that a craft the game's
    own tables call "small" is 133 m and that rob_f002 is 447 km -- 89% of the
    arena width.  The format check survives; the interpretation has no
    independent support.
  * The _cmesh <-> render-model name link is recorded as UNTESTED, not
    confirmed: only one .xbg build manifest survives on the disc, so matching
    stems against object names covers 4 of 158, which is no coverage at all.
2026-08-26 09:31:22 +00:00

4.9 KiB
Raw Blame History

CollisionSet_*.bin — the per-object collision-mesh library

Decoded 2026-08-26. The 18 remaining hidden/MiscBin.pak entries, named in the previous iteration as CollisionSet_S01…S16.bin, CollisionSet_Tutorial.bin and CollisionSet_test.bin from the StageResource objects' CollisionMeshes field. See mcol-collision.md for the naming and for MCOL, which is the map hull; this is the per-object library.

All 18 are byte-identical

CollisionSet blobs: 18   distinct contents: 1

The per-stage naming is nominal. Every stage points at the same 1 675 148-byte library, stored eighteen times — which is why the sizes were identical, the observation that made this worth opening.

The record layout

u32  size            bytes following this word's own 8-byte prefix
u32  name_len        16, 24 or 32 — the name field, padded to a multiple of 8
char name[name_len]
u32  vertex_count
u32  triangle_count
f32  vertex[3]  × vertex_count
u32  index[3]   × triangle_count

and the next record starts at offset + 8 + size. Note the indices are u32 here, where MCOL uses u16 — these are two different serialisers.

records 158
bytes consumed 1 675 148 / 1 675 148 — exact
size == 16 + name_len + 12·nv + 12·nt 8 158 / 158
every triangle index < vertex count 158 / 158

The walk consuming the file to the byte over 158 variable-length records, with the size word predicted from the two counts every time, is what makes this a decode rather than a plausible reading — a wrong field would desynchronise the walk within a few records and could not land exactly on the end.

And they are meshes

edges shared by exactly two triangles 132 167 / 134 529 = 98.24 %
fully manifold meshes (every edge shared by two) 147 / 158

92 of the 158 have Euler characteristic 2 — a single closed surface. The remainder are multi-component (χ = 4, 6, 8) or open shells, which is expected for parts like rou_e901_wing_01_L that are one piece of a larger hull.

What is in it

158 meshes, 48 241 vertices and 90 836 triangles, in four families:

prefix count what the names look like
rou_ 78 rou_e101_bdy, rou_e101_brg_01, rou_e106_eng, rou_f104_sld_02
mob_ 30 mob_n040, mob_n110_bdy, mob_n900_gear
rob_ 4 rob_e001, rob_e005_bdy, rob_f001_bdy, rob_f002
stage asteroids 46 S01_Asteroid_cmesh_01a, S14_p1_Asteroid_cmesh_05

The _bdy / _brg / _eng / _wep / _sld suffixes are body, bridge, engine, weapon and shield — the same sub-part vocabulary as the XBG7 render models, so these are per-part collision proxies. The asteroid meshes carry exactly the stage prefixes that have an _AsteroidVolume_wp MCOL.

🟡 The name correspondence to the render models is not demonstrated. Only one XBG2 build manifest survives on the disc (machines\rou_e104\…), so matching _cmesh stems against .xbg object names covers 4 of 158 — no coverage, and therefore no evidence either way. It is not a refutation; it is an untested claim.

🟡 The world unit — the metre reading does not survive this file

mcol-collision.md inferred 1 unit = 1 metre from mapmesh_box_500km.col spanning exactly 500 000 units. The arithmetic is exact, but this library is the first chance to check what that scale implies, and the implications are large:

mesh bbox diagonal, if 1 unit = 1 m
rou_e010 (e010_ADAN_Attacker_S — an "attacker, small") 133 m
rou_e106_bdy 2 368 m
rou_e101_bdy 9 371 m
rob_f001_bdy 50 179 m
S04_Asteroid_cmesh_04 84 714 m
rob_f002 447 522 m — 89 % of the arena's width

A craft the game's own tables call small would be 133 m, and the largest object would nearly span the arena. That is not impossible for the genre, but it is not the corroboration I claimed. Downgrading the scale claim to 🟡: either the game's units really are metres and its ships are kilometre-scale, or 500km in that filename names something other than the box's span. The 500 000 arithmetic stands; the interpretation does not have independent support.

An independent scale reference — the flight model's speed values against a measured traversal time in the running game — would settle it, and has not been run.

Reproduce with tools/re-capture/collisionset.py verify / list (../data/collisionset.txt); collisionset.py obj exports any named mesh.

Still open: the meshes carry no material, flag or surface-type field — the record is exactly counts, positions and indices — so whatever distinguishes a hull hit from a shield hit is not stored here. And the library is not indexed: lookup is presumably by name from the unit tables, which has not been traced.