Volumes: a candidate table found, explicitly not called volumes

Volumes were the only type never located, so this is a search report rather than
a result, and it is recorded as a candidate on purpose.

Ruled out first: no engine-side name exists. No level file contains "Volume"
outside UI text ("Music volume", "Volume de la musique") and Italian item
descriptions. The format cannot be found by label and has to be structural.

gameplay.bin is already-decompressed level data. Its head is a count (336 on
level 0) then 16-byte records from byte 416, carrying (type, pad, offset, id).
The id groups them -- each id has exactly two records pointing into two parallel
offset arrays -- and those offsets resolve into a text pool, the first ones
landing mid-string in dialogue ("it Megacorp Lab"). So that part of the file is
dialogue and class dispatch, not geometry.

The structural hit: a table of 144-byte float records. Level 0 has one at
799204, 20 records of which 19 are populated and one is an all-zero terminator,
with 34-35 of each record's 36 float slots world-plausible and +0x0c holding a
varying world position:

    (206.5, 284.1, 116.0)   (265.0, 445.3, 131.7)   (244.0, 407.2, 128.0)
    (219.3, 247.0, 107.5)   (185.1, 282.6, 104.9)   (260.8, 423.6, 130.9)
    (248.2, 198.4,  51.8)   (185.8, 282.7, 102.6)   (247.0, 211.5, 100.6)

A 144-byte record with world positions and float radii is the shape a volume
trigger region should have, and a matching table is present in every level
examined (0-9), each preceded by an all-zero record, counts 23 to 612.

It is NOT called volumes. Nothing ties this table to volumes. Camera bounds,
spawn points and path nodes would present exactly the same thing: float records,
world coordinates, no label. The discriminating evidence has not been gathered,
and writing "volumes" in the roadmap because the shape fits would be the exact
error this log keeps catching.

Two detector bugs, both mine, both confident before they were caught:

1. The validity test accepted zero as a world-plausible float, so every
   zero-filled region scored perfectly and the cross-level check returned runs of
   225 to 1,514 records that were obviously padding. Requiring non-zero floats
   (>=20 of 36) separated real tables from memory immediately.

2. The 144-byte stride came from four offsets I eyeballed as being 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 much longer runs,
   which is the opposite of what the eyeball version implied.

Same shape as every other correction here: a clean small plausible number read as
conclusive because nothing was checked against a control that could disagree.

To actually settle it, the table needs to be correlated with something known --
if a count matches a level's visible trigger regions, or if an id in the record
resolves through the class table to a named object, that is the discriminator.
Until then volumes remain open and the roadmap says so.
This commit is contained in:
2026-10-13 07:33:26 +02:00
parent 28ab7e094b
commit ca277a0a01
2 changed files with 72 additions and 1 deletions
+61
View File
@@ -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.