diff --git a/docs/formats/core-data-regions.md b/docs/formats/core-data-regions.md index 7f88d98..c79967e 100644 --- a/docs/formats/core-data-regions.md +++ b/docs/formats/core-data-regions.md @@ -2184,3 +2184,64 @@ it in the file -- consuming bytes 4..8 and shifting everything after. The struct literal named the fields in the right order; the statements did not. It is fixed with a comment saying so, since "read the `let`s in file order" is the kind of thing that gets undone. + +## Volumes: a candidate table, and why it is not yet called one + +Volumes were the only asset type never located at all, so this is a search +report rather than a result. + +**Ruled out first: there is no engine-side name.** No level file contains the +string `Volume` outside UI text ("Music volume", "Volume de la musique") and +Italian item descriptions. So the format cannot be identified by a label and +must be found structurally. + +`gameplay.bin` on disc is the already-decompressed level gameplay data. Its head +is a count (`336` on level 0) and then 16-byte records from byte `416`. Those +records carry `(type, pad, offset, id)`; the `id` field groups them, each id +having exactly two records pointing into two parallel offset arrays. The offsets +they point at resolve into a text pool -- the first ones land mid-string in +dialogue ("it Megacorp Lab"), so this is the dialogue and class-dispatch side of +the file, not geometry. + +The structural hit is a table of **144-byte float records**. Level 0 has one at +`799204`: + + 20 records of 144 bytes, 19 populated and one all-zero terminator + 34-35 of every record's 36 float slots are world-plausible + +0x0c holds a world position, varying per record: + + [0] (206.5, 284.1, 116.0) [6] (244.0, 407.2, 128.0) + [1] (219.3, 247.0, 107.5) [7] (265.3, 443.7, 13548.6) + [2] (248.2, 198.4, 51.8) [8] (185.1, 282.6, 104.9) + [3] (247.2, 203.6, 82.4) [9] (185.8, 282.7, 102.6) + [4] (155.7, 372.7, 121.1) [10] (260.8, 423.6, 130.9) + [5] (265.0, 445.3, 131.7) [11] (247.0, 211.5, 100.6) + +A 144-byte record with world-space positions and float radii is exactly the shape +a volume trigger region should have, and a matching table exists in every level +examined (levels 0-9), each preceded by an all-zero record, with counts from 23 +to 612. + +**It is not called volumes here.** Nothing yet ties this table to volumes +specifically. It could equally be camera bounds, spawn points, or path nodes -- +all of which would present 144-byte float records with world positions and no +label. The distinguishing evidence has not been gathered, and the honest state +is *candidate*. + +### Two detector bugs worth recording + +Both were mine, and both produced confident nonsense before being caught. + +1. The first validity test accepted zero as a world-plausible float. Every + zero-filled region then scores perfectly, and the cross-level check returned + runs of 225 to 1,514 records -- obviously padding. Requiring **non-zero** + floats (>=20 of 36) immediately separated real tables from memory. +2. The stride claim rested on four eyeballed offsets 144 apart. Gap 144 was not + in the top eight gaps of the detector that found them; it survived because + three consecutive observations agreed, not because the measurement supported + it. The corrected detector then found longer runs, which is the opposite of + what the eyeball version claimed. + +The same shape as every other correction in this log: a clean, small, plausible +number read as conclusive because it was not checked against a control that +could have disagreed. diff --git a/docs/roadmap.md b/docs/roadmap.md index b71b71d..e95716e 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -407,7 +407,17 @@ Phase 1 hands over the extents; this phase works out what each one contains. `+0x20` is self-limiting: entries run while strictly inside the region. **The word at `+0x0c` is not a count** -- it disagrees with the table on most levels and reads 196,617 on level 2 against 4 sub-objects. -- [ ] `volumes` — **not located.** Nothing examined so far presents itself as a +- [~] `volumes` — **still not identified, but a candidate exists.** Every level's + `gameplay.bin` carries a table of **144-byte float records** with world + positions at `+0x0c`, preceded by an all-zero record (levels 0-9: 23 to 612 + records). That is the shape of a volume trigger region and it is not tied + to anything else in the file -- but camera bounds, spawn points and path + nodes would look identical, and there is no engine-side `Volume` string to + discriminate with. **Recorded as candidate, not volumes.** Two detector + bugs on the way are written up: a validity test that counted zero as + world-plausible scored zero-filled memory perfectly, and the 144-byte stride + rested on four eyeballed offsets that the gap histogram did not support. + Not located. Nothing examined so far presents itself as a volume: `core_data`, the chunk region and `gameplay.bin` all yield structures that are accounted for by something else. - [~] `level_overlay` — header, constant block and level data parsed