diff --git a/docs/plan/level-assets.md b/docs/plan/level-assets.md index 4df1776..f0d0f65 100644 --- a/docs/plan/level-assets.md +++ b/docs/plan/level-assets.md @@ -884,3 +884,31 @@ Note the LOD distances already decoded sit *before* this point (12.0, 25.0, negative values, and a repeated leading 40.0. Unresolved. The packet geometry remains the open question, unchanged. + +## Shrub body (2026-10-11, later) + +Stride-fitting the body failed three times, so this came from a different +angle: group spans by `(count, data_offset, tail_length)` and byte-diff every +member of each group. Byte positions that differ across a group are geometry; +positions that never differ are structure. + +The result is blunt. **144 bytes vary in every group**, whether the group has +count 1, 2, 3, 5 or 6 and a tail of 192, 208 or 240 bytes. So the varying data +is not sized by `count` at all, and the three strides that failed were fitting +the wrong thing. + +Those 144 bytes sit in runs of 6, every 8 bytes: `(0..5), (8..13), (16..21), +...`. The body is an array of **8-byte records, 6 varying and 2 constant**. + +The payload is not half-floats. Decoding the 6 bytes as a `half3` gives 245.25 +and -168.375, which no shrub has. The bit patterns (`7ea5`, `1ab6`, `43d9`, +`af80`) and their repetition are VIF-packed data -- the same quadruple-word +packing moby and tfrag use, which is what the first three stride attempts were +really circling. + +Filler around it is the PS2 NaN `0x7fff0000` rather than zeros, which is why +the body looked like noise in the earlier dumps. + +So the shrub body is a VIF packet stream in 8-byte units, and the real +question is the code assignment, not the stride. Reusing the VIF decoder +already written for tfrag is the next step.