Files
benilla-octo/crates/benilla-formats/examples/emdump.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

51 lines
2.4 KiB
Rust

//! `emdump <internal\path.m2>` — every particle emitter one model authors, one line each.
//!
//! The per-emitter counterpart to `benilla-extract partcensus`, which answers "which models in the
//! corpus carry emitters matching this flag mask?" but never what an individual emitter *is*. B16
//! needed the other direction — the voidwalker's eye glow is emitters 1 and 2 of four, bone 60/61,
//! flags `0x0001` (plain anchored), `Add`/`GLOWBALL.BLP` — and reading that off a hex dump by hand
//! is exactly the kind of asset fact that should be one command.
//!
//! The header line carries the model's **reach** (how far its own transparent-pass batches sort
//! from its origin — `m2_owner_reach`) and the `Transparent3d` draw-order rung it produces
//! (`owner_last_rung`): the rung is what keeps a model's effects drawing after its own transparent
//! batches, and it is sized from that number, so the two belong on screen together.
fn main() -> anyhow::Result<()> {
let virt = std::env::args().nth(1).unwrap();
let data = benilla_formats::wow_data().expect("no WoW install found (set $WOW_DATA)");
let mut chain = benilla_formats::open_chain(&data)?;
let bytes = chain.read_file(&virt)?;
let dir = virt.rsplit_once('\\').map_or("", |(d, _)| d);
let subs = benilla_formats::parse_m2_render_submeshes(&bytes, dir, &[]).unwrap_or_default();
// The renderer's own bound and rung, not a re-derivation of them: a survey tool has to print
// what the renderer will actually do.
let reach = benilla_formats::m2_owner_reach(&subs);
let rung = benilla_formats::owner_last_rung(reach);
println!("{virt}: reach {reach:.3} yd -> draw-order rung {rung:.0}");
for (i, e) in benilla_formats::parse_m2_particle_emitters(&bytes)?
.iter()
.enumerate()
{
let now = e.params.sample(None, 0.0, 0.0);
println!(
"emitter {i}: bone {:>3} flags {:#06x} model_space={} pos ({:.4},{:.4},{:.4}) blend {:?} \
shape {:?} speed {:.4}±{:.4} grav {:.4} life {:.4} tex {:?}",
e.bone,
e.flags,
e.model_space(),
e.position[0],
e.position[1],
e.position[2],
e.blend,
e.shape,
now.emission_speed,
now.speed_variation,
now.gravity,
now.lifespan,
e.texture,
);
}
Ok(())
}