Identify the container the class tables point into: core_data itself
assets_compressed_size and assets_decompressed_size at index offsets 0x88 and 0x8c are 9,738,678 and 16,969,296 on level 0 -- exactly the sizes of core_data before and after decompression. There is no separate asset container. The "asset WAD" is core_data, and offset_in_asset_wad indexes the decompressed form directly. Checked rather than assumed, on all 27 levels: the decompressed size equals core_data's exact length, every class offset is either 0 or inside it, and the moby, tie and shrub spans do not overlap each other. An offset of 0 means the slot has no geometry, not the start of the lump; level 0's ninth moby class is 4909 at offset 0. Two assumptions worth discarding while here -- the tables are not sorted by class number (level 0's run 0, 1, 2, 14 ... 4909) and the offsets within a table are not monotonic. Neither is needed, but both look true from the first few entries. The chunk descriptors after the named extents are not it: they exist on only 3 of 27 levels, because level 0's four named extents tile the container exactly. An asset blob there would be missing almost everywhere. What sits at the offsets is raw GS/VIF packet data rather than a further container -- moby[0] begins 00 00 00 00 3f 16 02 55 6f 6f and tie[0] 00 01 00 00 70 50 00 00, which read as packet headers rather than a magic number. None of the three is decoded yet and this does not start that. Moby is skeletal and is the largest single piece left before the rest of a level can draw. Also: the pipeline now writes each level's chunk descriptors where they exist, and LevelCoreHeader decodes the asset lump's two sizes.
This commit is contained in:
@@ -237,6 +237,14 @@ pub struct LevelCoreHeader {
|
||||
pub shrub_textures: ArrayRange,
|
||||
/// Byte offset of texture pixel data within `core_data`.
|
||||
pub textures_base: i32,
|
||||
/// Compressed size of `core_data`'s WAD stream, and its decompressed size.
|
||||
///
|
||||
/// These describe the whole asset lump, not a separate container: on level
|
||||
/// 0 they are 9,738,678 and 16,969,296, exactly the sizes of `core_data`
|
||||
/// before and after decompression. The moby, tie and shrub class tables
|
||||
/// name geometry by byte offset into the *decompressed* form.
|
||||
pub assets_compressed_size: i32,
|
||||
pub assets_decompressed_size: i32,
|
||||
}
|
||||
|
||||
impl LevelCoreHeader {
|
||||
@@ -262,6 +270,13 @@ impl LevelCoreHeader {
|
||||
// 0x50..0x60: particle and effect texture tables, then the banks.
|
||||
b.skip(0x60 - 0x50, "particle texture tables")?;
|
||||
let textures_base = b.i32("textures base")?;
|
||||
// 0x60..0x80: particle/effect banks and defs, sound remap, then the
|
||||
// ratchet sequence table and the scene view size.
|
||||
b.skip(0x80 - 0x64, "particle banks")?;
|
||||
// 0x80: gadget table, then the asset lump's two sizes.
|
||||
b.skip(0x88 - 0x80, "gadget table")?;
|
||||
let assets_compressed_size = b.i32("assets compressed size")?;
|
||||
let assets_decompressed_size = b.i32("assets decompressed size")?;
|
||||
Ok(LevelCoreHeader {
|
||||
gs_ram,
|
||||
tfrags,
|
||||
@@ -276,6 +291,8 @@ impl LevelCoreHeader {
|
||||
tie_textures,
|
||||
shrub_textures,
|
||||
textures_base,
|
||||
assets_compressed_size,
|
||||
assets_decompressed_size,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -286,7 +303,7 @@ mod tests {
|
||||
|
||||
/// A header as measured on level 0.
|
||||
fn header() -> Vec<u8> {
|
||||
let mut v = vec![0u8; 0x64];
|
||||
let mut v = vec![0u8; 0x90];
|
||||
v[0x00..0x04].copy_from_slice(&404i32.to_le_bytes());
|
||||
v[0x04..0x08].copy_from_slice(&18_704i32.to_le_bytes());
|
||||
v[0x08..0x0c].copy_from_slice(&0i32.to_le_bytes());
|
||||
@@ -296,6 +313,8 @@ mod tests {
|
||||
v[0x30..0x34].copy_from_slice(&93i32.to_le_bytes());
|
||||
v[0x34..0x38].copy_from_slice(&10_512i32.to_le_bytes());
|
||||
v[0x60..0x64].copy_from_slice(&3_518_848i32.to_le_bytes());
|
||||
v[0x88..0x8c].copy_from_slice(&9_738_678i32.to_le_bytes());
|
||||
v[0x8c..0x90].copy_from_slice(&16_969_296i32.to_le_bytes());
|
||||
v
|
||||
}
|
||||
|
||||
@@ -321,11 +340,14 @@ mod tests {
|
||||
}
|
||||
);
|
||||
assert_eq!(h.textures_base, 3_518_848);
|
||||
assert_eq!(h.assets_compressed_size, 9_738_678);
|
||||
assert_eq!(h.assets_decompressed_size, 16_969_296);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_short_header_is_an_error() {
|
||||
assert!(LevelCoreHeader::parse(&[0u8; 0x20]).is_err());
|
||||
assert!(LevelCoreHeader::parse(&[0u8; 0x8c]).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user