Show region bounds in probe, which exposed an unnamed 6.2 MB region

Printing the region table next to the header fields makes the gap visible
without having to remember to consult core_layout, and it paid for itself
immediately.

On level 0 the collision region comes out 6216960 bytes, from 2615232 to
the first moby class at 8832192. Collision's own header declares a payload
of 903,248. So roughly 6.2 MB sits between the collision header and the
first moby class, and almost none of it is collision.

The successor rule is correct -- a region does end where the next one
begins -- but "the next" is not yet known there. collision..moby is
really collision + <something unnamed> .. moby. The name is wrong, not
the bound.

Candidates for the space, rough order of likelihood: moby and tie model
animation data, which is what moby_anim would need, then volumes, then
per-class runtime structures. Tfrag texture texels are already placed and
sit earlier in the lump.

Worth resolving before starting moby_anim, since that format is the most
likely tenant. Until then, any probe reading between the collision header
and the first moby class is reading something the region table does not
describe.
This commit is contained in:
2026-10-11 03:03:46 +02:00
parent cb38b8c279
commit 8b98d388f7
3 changed files with 56 additions and 0 deletions
+21
View File
@@ -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!();
+6
View File
@@ -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<gc_formats::regions::Region>,
/// The three class tables, in the order the header lists them.
pub classes: Vec<ClassTable>,
}
@@ -92,6 +95,8 @@ pub fn probe_level(dir: &Path, level: u32) -> Result<LevelProbe> {
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<LevelProbe> {
core_len: core.len(),
index_len: index.len(),
header,
regions,
classes,
})
}
+29
View File
@@ -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 + <something unnamed> .. 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.