diff --git a/crates/gc-extract/src/main.rs b/crates/gc-extract/src/main.rs index a8b770f..3792666 100644 --- a/crates/gc-extract/src/main.rs +++ b/crates/gc-extract/src/main.rs @@ -352,6 +352,27 @@ fn run_probe(args: &[String]) -> ExitCode { for (k, v) in &p.header { println!(" {k:<22} {v:>14}"); } + println!(); + println!("core_data regions (end = next region's start, never core_data.len())"); + println!("{}", "-".repeat(64)); + for r in &p.regions { + let (lo, hi) = (r.start, r.start + p.core_len); + let _ = (lo, hi); + match r.end { + Some(e) => println!( + " {:<12} {:>10} .. {:<10} {:>10} bytes", + r.name, + r.start, + e, + e - r.start + ), + None => println!( + " {:<12} {:>10} .. {:<10} {:>10}", + r.name, r.start, "?", "end unresolved" + ), + } + } + for t in &p.classes { let sane = t.entries.iter().filter(|e| e.in_core(p.core_len)).count(); println!(); diff --git a/crates/gc-extract/src/probe.rs b/crates/gc-extract/src/probe.rs index 0694a06..dafd938 100644 --- a/crates/gc-extract/src/probe.rs +++ b/crates/gc-extract/src/probe.rs @@ -29,6 +29,9 @@ pub struct LevelProbe { pub index_len: usize, /// Rendered field-by-field dump of the core header. pub header: Vec<(String, String)>, + /// Region bounds, computed from successor boundaries. Shown next to the + /// header so a probe never re-derives them inline. + pub regions: Vec, /// The three class tables, in the order the header lists them. pub classes: Vec, } @@ -92,6 +95,8 @@ pub fn probe_level(dir: &Path, level: u32) -> Result { header.push((name.into(), range(v))); } + let regions = gc_formats::regions::core_layout(&index, &h); + let mut classes = Vec::new(); for (name, r, stride) in [ ("moby", h.moby_classes, CLASS_ENTRY_BYTES), @@ -110,6 +115,7 @@ pub fn probe_level(dir: &Path, level: u32) -> Result { core_len: core.len(), index_len: index.len(), header, + regions, classes, }) } diff --git a/docs/formats/core-data-regions.md b/docs/formats/core-data-regions.md index e109a24..e246b2c 100644 --- a/docs/formats/core-data-regions.md +++ b/docs/formats/core-data-regions.md @@ -48,3 +48,32 @@ that nothing yet accounts for. `core_layout` reports `end: None` for shrub on the 24 levels that have one, and the disc test asserts it, so the gap stays visible rather than being papered over by clamping to the end of the lump. + +## Found by printing it: an unnamed region between collision and moby + +Adding the region table to `gc-extract probe` made the gap visible +immediately, which is the point of printing it. + +On level 0: + +``` +collision 2615232 .. 8832192 6216960 bytes +``` + +but collision's own header declares a payload of 903,248 bytes. So the range +between the collision header and the first moby class is **6.2 MB**, and +almost none of it is collision. + +The successor rule is right -- a region does end where the next begins -- but +"the next" is not yet known here. `collision..moby` is really +`collision + .. moby`. The name is wrong, not the bound. + +Candidate homes for those 6.2 MB, in rough order of likelihood: the moby and +tie model *animation* data that `moby_anim` would need, volume data, or +per-class runtime structures. The tfrag texture texels are already accounted +for and sit earlier in the lump. + +Until that region is named, any per-format probe reading between the collision +header and the first moby class is reading something this table does not +describe. Worth resolving before starting `moby_anim`, since that format is the +most likely tenant of the space.