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.
This commit is contained in:
2026-10-11 02:44:15 +02:00
parent 517f0b63fa
commit 572753e7c1
+28
View File
@@ -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. negative values, and a repeated leading 40.0.
Unresolved. The packet geometry remains the open question, unchanged. 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.