Parse the level container header, naming each level's four extents
The first typed structure read from real data. Every one of the 27 level containers begins with the same 0x60-byte header, which turns the generic pair table into named assets: data, sound_bank, gameplay and occlusion, plus three chunk descriptors. Two things about this header are worth stating because both are silent failures rather than errors. Sizes here are sector counts, not byte counts. The generic G/ pair table on the same disc uses byte counts, so both readings type-check and the wrong one is off by a factor of 2048. The tiling check settles it: read as sectors, the four extents tile every one of the 27 containers exactly; read as bytes they overlap each other. Level id is not container order. LEVEL21.WAD reports id 30, so a level was cut from the disc and its number left a gap. Anything keying off file order -- a save slot, the planet select screen -- would mislabel that planet. There is also a second trap in the same area: the ISO filesystem sorts names alphabetically, so LEVEL10 precedes LEVEL2, and any tool needing order has to sort numerically. The header's field at 0x04 is zero on all 27 levels. It is not the container size despite looking like one, so the code reads it as a runtime field and takes the container length from the ISO entry instead. Measured across all 27 levels, three invariants now hold in tests: extents tile in file order; extent coverage plus chunks reaches at least the end of the container (21 levels land exactly on its length, 6 leave 134 to 689 sectors of trailing data); and exactly one level's id differs from its container index. The coverage assertion is >= rather than == on purpose -- 21 levels end one sector past the file end because the header occupies sector 0, and asserting equality would truncate a level's tail. gameplay is left unparsed and that is recorded rather than hidden. It begins "WAD" plus a per-level byte and does not decode with the WAD LZ77 decoder: all 27 levels produce plausible output for the first packet and then fail on a rule the format's own encoder never breaks, which means the input is wrong rather than the decoder. docs/plan/level-assets.md records what is ruled out and what to try next. 66 unit tests, plus 7 integration tests against the real disc. The unpack hash table is unchanged, so this adds parsing without altering the pipeline.
This commit is contained in:
+24
-3
@@ -16,7 +16,10 @@ early, while they are still cheap to retire.
|
||||
- [x] **Phase 1 complete.** The disc pipeline runs end to end and is verified
|
||||
against a committed hash table: 5,135 files, 4,500,106,960 bytes, every
|
||||
one of the 92 asset containers parsing.
|
||||
- [ ] Phase 2 next: the asset format parsers.
|
||||
- [x] **Phase 2 started.** The level container header is parsed and typed, which
|
||||
names the `data`, `sound_bank`, `gameplay` and `occlusion` extents inside
|
||||
each of the 27 level containers.
|
||||
- [ ] Phase 2 next: the `gameplay` extent, then `data`.
|
||||
|
||||
The disc being the exact build the reference projects pin is the single
|
||||
biggest favourable fact so far: no disc conversion, no regional timing work,
|
||||
@@ -85,8 +88,26 @@ failing, which is the failure mode worth guarding against.
|
||||
disc data.
|
||||
|
||||
Phase 1 hands over the extents; this phase works out what each one contains.
|
||||
`global_wad.md` records which pair in each container corresponds to which asset,
|
||||
and that table starts empty.
|
||||
|
||||
**Done so far:**
|
||||
|
||||
- [x] `level_wad.rs` — the 0x60-byte header on all 27 level containers, naming
|
||||
four extents plus three chunk descriptors. Verified: extents tile each
|
||||
container in file order (27 of 27).
|
||||
- [x] Two facts the format documentation does not state, both measured here:
|
||||
sizes in this header are **sector counts** where the generic `G/` table
|
||||
uses byte counts, and **`LEVEL21.WAD` reports level id 30**, so container
|
||||
order is not level identity.
|
||||
|
||||
**In progress:**
|
||||
|
||||
- [ ] `gameplay` — begins `WAD` + a per-level byte, and does *not* decode with
|
||||
the WAD LZ77 decoder. All 27 levels fail identically, so the input is
|
||||
wrong rather than the decoder. Ruled out: bit order, header length, the
|
||||
LZ77 framing. Hypotheses queued in `plan/level-assets.md`.
|
||||
- [ ] `occlusion` — 2 to 25 sectors, small enough to read whole.
|
||||
- [ ] `sound_bank` — `SBlk` and `DAW` signatures found in all 27.
|
||||
- [ ] `data` — the large one: 4.2 to 21.9 MB of geometry per level.
|
||||
|
||||
- [ ] `tfrag` — terrain: LOD chains, strips, morph targets
|
||||
- [ ] `tie` — instanced environment geometry, fat vertices
|
||||
|
||||
Reference in New Issue
Block a user