Files
benilla-octo/crates/benilla-formats/examples/srci_dump.rs
T
SamandClaude Fable 5 6b980b9efb the player build: one binary that carries its content
- a player build ships beside the dev one — dev chords and probe surfaces go dark, and a gate enforces what a player can still reach, by medium not by module
- the binary carries its own shaders and its shipped UI, finds the WoW folder by itself, and keeps its local state in one benilla-config folder
- the glue screens get a capture shutter, and the engine stops depending on the protocol crate

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 18:18:02 +07:00

65 lines
2.8 KiB
Rust

//! Throwaway: dump `SkillRaceClassInfo.dbc` rows admitting a race/class, with the flags word in
//! hex — the table the client's `GetSkillLineInfo` reads for its 0x400 single-rank cap and 0x20
//! unlearnable bit. Usage: `cargo run -p benilla-formats --example srci_dump -- <race> <class>`.
fn main() -> anyhow::Result<()> {
let mut args = std::env::args().skip(1);
let race: u32 = args.next().unwrap_or_else(|| "4".into()).parse()?;
let class: u32 = args.next().unwrap_or_else(|| "3".into()).parse()?;
let data = benilla_formats::wow_data().expect("no WoW install found (set $WOW_DATA)");
let mut chain = benilla_formats::open_chain(&data)?;
// Skill line names, so the dump reads.
let lines = chain.read_file("DBFilesClient\\SkillLine.dbc")?;
let name_of = |id: u32| -> String {
let g = |b: &[u8], o: usize| u32::from_le_bytes(b[o..o + 4].try_into().unwrap());
let (rows, _fields, rec) = (g(&lines, 4), g(&lines, 8), g(&lines, 12) as usize);
let sb = 20 + rows as usize * rec;
for r in 0..rows as usize {
let base = 20 + r * rec;
if g(&lines, base) == id {
let off = sb + g(&lines, base + 3 * 4) as usize;
let end = lines[off..].iter().position(|&c| c == 0).unwrap_or(0) + off;
return format!(
"{} (cat {})",
String::from_utf8_lossy(&lines[off..end]),
g(&lines, base + 4)
);
}
}
"?".into()
};
let bytes = chain.read_file("DBFilesClient\\SkillRaceClassInfo.dbc")?;
let g = |o: usize| u32::from_le_bytes(bytes[o..o + 4].try_into().unwrap());
let (rows, _fields, rec) = (g(4), g(8), g(12) as usize);
let (rmask, cmask) = (
1u32.checked_shl(race.wrapping_sub(1)).unwrap_or(0),
1u32.checked_shl(class.wrapping_sub(1)).unwrap_or(0),
);
println!("race {race} (mask {rmask:#x}) class {class} (mask {cmask:#x})");
let mut seen: Vec<u32> = Vec::new();
for r in 0..rows as usize {
let base = 20 + r * rec;
let (skill, race_mask, class_mask, flags, req_level, tier) = (
g(base + 4),
g(base + 8),
g(base + 12),
g(base + 16),
g(base + 20),
g(base + 24),
);
// race/class 0 = dump EVERY row (masks unfiltered, duplicates kept).
let all = race == 0 || class == 0;
if !all && (race_mask & rmask == 0 || class_mask & cmask == 0 || seen.contains(&skill)) {
continue;
}
seen.push(skill);
println!(
"skill {skill:>4} flags {flags:#07x} (0x400={}) reqLevel {req_level} tier {tier} {}",
flags & 0x400 != 0,
name_of(skill)
);
}
Ok(())
}