# `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`](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`](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`](../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.