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:
@@ -137,6 +137,26 @@ pub fn unpack(iso_path: &Path, out_dir: &Path) -> Result<Vec<Extracted>, String>
|
||||
}
|
||||
parts += 1;
|
||||
}
|
||||
// Chunk descriptors follow the named extents. One of them
|
||||
// is the level's asset WAD, which the moby/tie/shrub class
|
||||
// tables point into by byte offset.
|
||||
for (i, range) in header.present_chunks() {
|
||||
let Some(offset) = range.byte_offset() else {
|
||||
continue;
|
||||
};
|
||||
let len = range.byte_len() as usize;
|
||||
if offset + len as u64 > raw.len() as u64 {
|
||||
continue;
|
||||
}
|
||||
write_file(
|
||||
out_dir,
|
||||
&format!("{stem}/chunk{i}.bin"),
|
||||
&raw[offset as usize..offset as usize + len],
|
||||
&mut written,
|
||||
);
|
||||
parts += 1;
|
||||
}
|
||||
|
||||
// The `data` extent is itself a container of byte ranges.
|
||||
// Split out the geometry directory and the geometry, so the
|
||||
// latter is usable without re-deriving the layout later.
|
||||
|
||||
Reference in New Issue
Block a user