Decode the collision payload's leading two counts

Range measured: the first four bytes of the payload on all 19 levels that carry
a non-empty one.

Result: two u16 at payload +0 and +2, both non-zero on all 19, ranging 1..74 and
13..112, products 53 to 3256.

  level  0  11 x 33  =   363   payload   903248
  level  1  24 x 16  =   384   payload  2800496
  level  2   1 x 53  =    53   payload  2315296
  level  7  40 x 35  =  1400   payload  4049232
  level  9  74 x 44  =  3256   payload  2518352
  level 13   2 x 64  =   128   payload  3333520
  level 26  27 x 112 =  3024   payload   652176

Reported as two counts, not as a named grid. They have the shape of collision
grid dimensions -- bounded, both non-zero, products in the hundreds to thousands
-- but nothing measured ties the product to the payload size or to any per-cell
stride. Level 2's 1 x 53 giving a 2.3 MB payload and level 26's 27 x 112 giving
652 KB shows the product does not size the payload, so either cells vary wildly
in size or these are not grid dimensions. Naming them width and depth would be a
reading, not a measurement.

After the two counts comes a run of u16 that stays below 8192 for 30 to 58
entries depending on level, always an even count, and is not ascending. That is
where the per-cell table most likely starts, and it is the next thing to
resolve.

Exposed as CollisionHeader::first and ::second. They live in the payload rather
than the header, so CollisionHeader::region fills them in and the bare
CollisionHeader::parse leaves them zero -- documented at the call site so the
difference is not mistaken for an absence.
This commit is contained in:
2026-10-12 02:58:46 +02:00
parent 72bbd5da38
commit 2569cc06ab
2 changed files with 70 additions and 2 deletions
+37 -2
View File
@@ -36,19 +36,39 @@ pub struct CollisionHeader {
/// is a size, an offset, or a second block's length, and nothing here
/// distinguishes those.
pub field_08: u32,
/// The payload's first `u16`, at `+0x40`.
///
/// Measured on all **19** levels that carry a non-empty payload: the two
/// `u16` at `+0x40` and `+0x42` read 1..74 and 13..112 respectively, with
/// products from 53 to 3,256. Both are non-zero on every one of the 19,
/// and neither exceeds a size a collision grid would plausibly use.
///
/// Reported as two counts, not as a named grid: nothing measured here ties
/// the product to the payload size or to any per-cell stride, so calling it
/// width and depth would be a reading, not a measurement.
pub first: u16,
/// The payload's second `u16`, at `+0x42`. See [`CollisionHeader::first`].
pub second: u16,
}
impl CollisionHeader {
/// Parse the 8 meaningful bytes at the head.
///
/// The remaining 0x38 bytes are zero on all 27 levels, but they are not
/// required to be: only the two fields below are load-bearing.
/// The remaining 0x38 bytes are zero on 22 of 27 levels, but they are not
/// required to be -- five carry a large word at `+0x08` -- so only the
/// fields below are load-bearing.
///
/// `first` and `second` read the payload, not the header, so they are zero
/// here and filled in by [`CollisionHeader::region`], which is the only
/// entry point that knows where the payload starts.
pub fn parse(bytes: &[u8]) -> Result<CollisionHeader> {
let mut b = Buf::new(bytes);
Ok(CollisionHeader {
header_size: b.u32("collision header size")?,
payload_size: b.u32("collision payload size")?,
field_08: b.u32("collision +0x08")?,
first: 0,
second: 0,
})
}
}
@@ -92,6 +112,21 @@ impl CollisionHeader {
},
})?;
let pstart = start + hsize;
// The payload's own first two u16, read from the bytes past the header.
let lead = core.get(pstart..pstart + 4).ok_or(Error {
offset: pstart,
context: "collision payload is too short for its leading counts",
kind: ErrorKind::OutOfBounds {
needed: 4,
available: core.len().saturating_sub(pstart),
},
})?;
let header = CollisionHeader {
first: u16::from_le_bytes([lead[0], lead[1]]),
second: u16::from_le_bytes([lead[2], lead[3]]),
..header
};
let pend = pstart + header.payload_size as usize;
let payload = core.get(pstart..pend).ok_or(Error {
offset: pstart,