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:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user