SBlk head characterised: four constants and one word that is not a count
sound_bank's head was parsed but never characterised. Across all 27 levels the
SBlk region opens identically for its first twelve bytes:
+0x00 "SBlk" +0x04 1 +0x08 4 +0x0c "DAW\0" +0x10 0
and +0x14 is the only word that varies. It varies with its low sixteen bits zero
on all 27, leaving 0x0092..0x0103 -- 146 to 259.
That is the shape of a record count, and it tracks the body length at close to
100 bytes per unit. It is not one:
body / field_14 91.2 .. 110.8 across 27 levels
any stride 0..80 with body = stride*word + constant exactly: no
So the test asserts the negative too. If a stride ever makes the relation exact
on all 27, sound_bank_sblk_head_is_constant_apart_from_one_word fails and asks
for the record size to be revisited. A near-miss at 100 bytes/record is exactly
what hardens into a name the next time somebody glances at it; the constants are
also checked individually so a real deviation names which one moved.
The DAW region begins with sixteen zero bytes then block-structured data with
16-byte periodicity and slowly varying nibbles -- consistent with block
compressed audio, not decoded. Recorded as such.
Two mistakes, both mine, both the same shape as earlier ones:
1. The constructor bound `format_tag` with a `let` BEFORE the two words that
precede it in the file, consuming bytes 4..8 and shifting every field after
it. The struct literal listed the names in the right order; the statements did
not. A scratch script reading the same bytes gave the opposite answer, which
is what exposed it. Fixed, with a comment, because "read the lets in file
order" gets undone otherwise.
2. Inserting the new test ahead of an existing one stranded that test's #[test]
on my doc comment -- silently unregistering
tie_vertex_element_is_16_bytes_with_fixed_texcoords. This is the SAME mistake
as two commits ago and I made it again. It again surfaced only as clippy's
"never used" rather than as a missing test. Restored and verified by listing
the registered tests rather than trusting the count.
240 tests, clippy clean, both tie vertex tests confirmed present.
This commit is contained in:
@@ -3484,6 +3484,86 @@ fn tie_vertex_slots_0_to_2_are_shared_positions() {
|
||||
);
|
||||
}
|
||||
|
||||
/// The `SBlk` head's constant fields, and the one field that is not a count.
|
||||
///
|
||||
/// The first twelve bytes are identical on all 27 levels. The word at `+0x14`
|
||||
/// varies, with its low sixteen bits always zero. It tracks the body length at
|
||||
/// ~100 bytes per unit, which is the shape of a record count -- and is not one:
|
||||
/// the ratio runs 91.2..110.8 and no stride makes the relation exact on all 27.
|
||||
/// Both halves are asserted so the near-miss cannot quietly harden into a name.
|
||||
#[test]
|
||||
fn sound_bank_sblk_head_is_constant_apart_from_one_word() {
|
||||
require_disc!();
|
||||
|
||||
let data = std::env::var_os("GC_EXTRACTED")
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|| {
|
||||
let home = std::env::var("HOME").unwrap_or_else(|_| ".".to_string());
|
||||
PathBuf::from(home).join("Documents/gc-extracted")
|
||||
});
|
||||
if !data.exists() {
|
||||
eprintln!("skipped: unpack the disc first");
|
||||
return;
|
||||
}
|
||||
|
||||
use gc_formats::sound_bank::{parse_sound_bank, SBlkHeader};
|
||||
|
||||
let mut values: Vec<u32> = Vec::new();
|
||||
let mut bodies: Vec<usize> = Vec::new();
|
||||
let mut levels = 0usize;
|
||||
for lv in 0..27usize {
|
||||
let Ok(bytes) = std::fs::read(data.join(format!("level{lv}/sound_bank.bin"))) else {
|
||||
continue;
|
||||
};
|
||||
let bank = parse_sound_bank(&bytes).expect("sound bank");
|
||||
let h = SBlkHeader::parse(bank.sblk).expect("SBlk head");
|
||||
assert!(
|
||||
h.constants_hold(),
|
||||
"level {lv}: SBlk constants moved: {h:?}"
|
||||
);
|
||||
values.push(h.field_14);
|
||||
bodies.push(bank.sblk.len() - 24);
|
||||
levels += 1;
|
||||
}
|
||||
assert_eq!(levels, 27, "only {levels} sound banks parsed");
|
||||
|
||||
for &v in &values {
|
||||
assert_eq!(v & 0xffff, 0, "field_14 gained low bits: {v:#x}");
|
||||
assert!(
|
||||
(0x92..=0x103).contains(&(v >> 16)),
|
||||
"field_14 moved: {v:#x}"
|
||||
);
|
||||
}
|
||||
// correlated with body length, but not a count at any fixed stride
|
||||
let ratios: Vec<f64> = bodies
|
||||
.iter()
|
||||
.zip(&values)
|
||||
.map(|(b, &v)| *b as f64 / (v >> 16) as f64)
|
||||
.collect();
|
||||
let lo = ratios.iter().cloned().fold(f64::MAX, f64::min);
|
||||
let hi = ratios.iter().cloned().fold(0.0f64, f64::max);
|
||||
let exact = (0..=80).any(|k| {
|
||||
let rems: Vec<i64> = bodies
|
||||
.iter()
|
||||
.zip(&values)
|
||||
.map(|(b, &v)| *b as i64 - k * (v >> 16) as i64)
|
||||
.collect();
|
||||
rems.windows(2).all(|w| w[0] == w[1])
|
||||
});
|
||||
eprintln!(
|
||||
"SBlk head: constants hold on 27/27; field_14 in 0x0092..0x0103 with low 16 bits 0; \
|
||||
body/word ratio {lo:.1}..{hi:.1}; any stride making it exact: {exact}"
|
||||
);
|
||||
assert!(
|
||||
lo > 85.0 && hi < 115.0,
|
||||
"body/word ratio left its band: {lo:.1}..{hi:.1}"
|
||||
);
|
||||
assert!(
|
||||
!exact,
|
||||
"field_14 now satisfies a fixed stride -- revisit the record size"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tie_vertex_element_is_16_bytes_with_fixed_texcoords() {
|
||||
require_disc!();
|
||||
|
||||
Reference in New Issue
Block a user