From 3ca8522be191f9bca220b9d8717304fef1618de8 Mon Sep 17 00:00:00 2001 From: ReaperOfVeriod Date: Sun, 11 Oct 2026 02:32:55 +0200 Subject: [PATCH] Record shrub geometry findings and the per-table entry strides The three class tables do not share an entry size. Measured by how many entries give a geometry offset inside core_data plus a plausible o_class, over all 27 levels: moby stride 0x20 5769 / 5796 tie stride 0x20 1864 / 1864 shrub stride 0x30 356 / 358 Reading shrub at 0x20 still yields 231 sane-looking entries out of 358, which is the hazard: wrong often enough to look right. The committed code already handles this -- ShrubClassEntry is 48 bytes and carries billboard texture fields the other two lack -- so this is measurement, not a fix. Shrub geometry is not moby's part-table format: all 358 spans have a leading word of 0 or one too large to index a table into, so none contain a moby-style part table. Two header fields do self-identify, both exact across all 358 spans: +0x24 equals the class entry's own o_class, and +0x2c is a data offset landing inside the span. +0x10 reads 5.0f on 281 of 358, so it is a value rather than a marker and carries no structural weight. Rest of the shrub header undecoded. --- docs/plan/level-assets.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/docs/plan/level-assets.md b/docs/plan/level-assets.md index 4162c6f..9352053 100644 --- a/docs/plan/level-assets.md +++ b/docs/plan/level-assets.md @@ -823,3 +823,34 @@ geometry. Vertices are 16 bytes of VIF-packed half-float quads, cycling through four distinct 32-bit words. Not unpacked -- handed back raw. + +## Shrub geometry (2026-10-11) + +Class entry strides differ between the three tables. Measured by how many +entries yield a geometry offset inside `core_data` and a plausible `o_class`, +across all 27 levels: + +| table | stride | sane entries | +|-------|--------|--------------| +| moby | 0x20 | 5769 / 5796 | +| tie | 0x20 | 1864 / 1864 | +| shrub | 0x30 | 356 / 358 | + +Reading shrub at 0x20 still yields 231 sane-looking entries out of 358, which +is the problem: it is wrong often enough to look right. The stride is already +handled -- `ShrubClassEntry` is 48 bytes, carrying billboard texture fields the +other two do not have. + +Shrub geometry is **not** the moby part-table format. All 358 spans have a +leading word of 0 or one too large to index a table into, so none of them +contain a moby-style part table. + +The header does self-identify in two places, both exact across all 358 spans: + +- `span + 0x24` is a `u32` equal to the class entry's own `o_class`. 358/358. +- `span + 0x2c` is a `u32` data offset that lands inside the span. 358/358. + +`span + 0x10` reads 5.0f on 281 of 358 spans, so it is a value rather than a +constant marker and carries no structural weight. The header is otherwise +undecoded: the first 0x20 bytes are packed data rather than floats, despite +`+0x10` landing exactly on 5.0.