Record core index field order, sky and moby findings
Three things this session that are cheap to rediscover wrongly and expensive to rediscover wrongly twice. The core index interleaves single-word region offsets with count/offset pairs, so gs_ram and the three class tables are two words each while tfrags..collision are one. Treating the pairs as single words shifts every field after them, which is how collision got read as sky and produced a page of implausible collision headers on all 27 levels. Sky is not uniform. Most levels share a header shape, but level 2 carries extra fields and the count word at +0x0a over-reports against the number of real offset slots, so no single fixed header fits. Moby geometry starts with zero words rather than a header and then packed half-float VIF data. Not decoded; recorded so the next attempt starts from the data instead of re-deriving the layout.
This commit is contained in:
@@ -730,3 +730,71 @@ A tfrag can now be turned into positioned, UV-mapped, textured, lit triangles,
|
||||
told which LOD to draw, and morphed toward its parents at the right rate.
|
||||
Everything needed for a first frame is parsed, and the frame is verified by
|
||||
screenshot rather than by assertion.
|
||||
|
||||
## Core index field order (2026-10-11)
|
||||
|
||||
Repeatedly re-deriving these by hand wasted real time this session, so the
|
||||
order is written out. It matches `LevelCoreHeader::parse` in
|
||||
`crates/gc-formats/src/level_core.rs`:
|
||||
|
||||
| offset | field |
|
||||
|--------|-------|
|
||||
| 0x00 | gs_ram count |
|
||||
| 0x04 | gs_ram offset |
|
||||
| 0x08 | tfrags |
|
||||
| 0x0c | occlusion |
|
||||
| 0x10 | sky |
|
||||
| 0x14 | collision |
|
||||
| 0x18 | moby_classes count |
|
||||
| 0x1c | moby_classes offset |
|
||||
| 0x20 | tie_classes count |
|
||||
| 0x24 | tie_classes offset |
|
||||
| 0x28 | shrub_classes count |
|
||||
| 0x2c | shrub_classes offset |
|
||||
|
||||
Note `gs_ram` and the three class tables are **count/offset pairs**, so every
|
||||
one of them is two words. The region offsets (`tfrags` through `collision`) are
|
||||
single words. Counting the class tables as one word each shifts every field
|
||||
after them, which is how `collision` got read as `sky` and produced a page of
|
||||
implausible collision headers on all 27 levels.
|
||||
|
||||
## Sky (2026-10-11)
|
||||
|
||||
Region is `[sky, collision)` and is well defined, but the header is **not**
|
||||
yet decoded and the layout is not uniform.
|
||||
|
||||
Reading `u16` at the head, most levels give:
|
||||
|
||||
```
|
||||
+0x00 0
|
||||
+0x02 0
|
||||
+0x04 4 or 6 varies per level
|
||||
+0x06 0
|
||||
+0x08 0 level 2 is the exception
|
||||
+0x0a 3..6 looks like a layer count
|
||||
+0x0c 0
|
||||
+0x0e 64 (0x40)
|
||||
+0x10 128 or 192 varies
|
||||
+0x12 64 (0x40)
|
||||
```
|
||||
|
||||
Level 2 breaks the pattern: `+0x08` is 0x0109 and the three words after the
|
||||
apparent count are shifted and different (`80 00 00 00 00 01 00 00 40 00`).
|
||||
So a single fixed header does not fit every level, and the count at `+0x0a`
|
||||
cannot be trusted to be one.
|
||||
|
||||
A table of offsets follows at `+0x20` for the layers. The offsets ascend and
|
||||
sit in the last 8-15% of the region, but the count of *non-zero* offsets is
|
||||
sometimes less than the declared count (level 26 declares 6, has 4 real
|
||||
offsets and 2 zero slots). Unresolved.
|
||||
|
||||
## Moby geometry (2026-10-11)
|
||||
|
||||
Class entries are 0x20 bytes in `core_index.bin`, fields
|
||||
`geom_offset, o_class, unknown_8, unknown_c, textures[16]`; all 238 level-0
|
||||
moby classes carry `textures == ffff..ff`, i.e. no texture slots.
|
||||
|
||||
`geom_offset` points into `core_data`, and the spans tile without overlap. The
|
||||
data at that offset does not start with a recognisable header -- it opens with
|
||||
zero words and then packed half-float VIF data (`55 55 15 3e` shows up 4 bytes
|
||||
in). Not decoded.
|
||||
|
||||
Reference in New Issue
Block a user