From 572753e7c12204b76760055dc73b988236554ae6 Mon Sep 17 00:00:00 2001 From: ReaperOfVeriod Date: Sun, 11 Oct 2026 02:44:15 +0200 Subject: [PATCH] Find the shrub body stride by diffing spans instead of fitting it Stride-fitting the shrub body failed three times, so this attacks it from the other side: group spans by (count, data_offset, tail length) and byte diff every member of each group. Positions that differ across a group are geometry; positions that never differ are structure. The answer is blunt. 144 bytes vary in every group, whether that group has count 1, 2, 3, 5 or 6 and a tail of 192, 208 or 240 bytes. The varying data is not sized by count at all, which is why three stride guesses were fitting the wrong thing -- and why they kept looking nearly plausible. Those 144 bytes fall in runs of 6, every 8 bytes. The body is an array of 8-byte records: 6 varying bytes and 2 constant. The payload is not half-floats -- decoding as half3 gives 245.25 and -168.375, which no shrub has. The patterns (7ea5, 1ab6, 43d9, af80) and their repetition are VIF-packed data, the same quadruple-word packing moby and tfrag use. Filler around it is the PS2 NaN 0x7fff0000 rather than zeros, which is why the body read as noise in the earlier dumps. So the open question is the VIF code assignment, not the stride, and the decoder written for tfrag is the obvious place to start. --- docs/plan/level-assets.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) 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.