Files
benilla-octo/crates/benilla-formats/src/zone_map.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

63 lines
2.8 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! `Interface\WorldMap\<Continent>.zmp` — the continent area bitmap: a 128×128 grid of
//! `AreaTable.dbc` row ids (16384 little-endian u32, row-major, exactly 65536 bytes) covering the
//! whole 64×64-ADT world at half-ADT granularity. The client's world-map hover/click resolves a
//! cursor cell to a zone through it (`0x4a6ec0`; the loader `0x4a5d00` remaps cells to
//! WorldMapArea ids at load — benilla's remap lives with the catalog build, `ui_world_map`).
//!
//! Mechanism VERIFIED by wow-re (Q1 §5 cross-check, 2026-07-07, recorded in
//! `system/ui/scratch/geometry.md` "Worldmap data model"): path format string @0x845374
//! (`Interface\WorldMap\%s.zmp`, `%s` = the continent WorldMapArea row's AreaName), 0x10000 bytes
//! read raw into the record. Corroborated against the shipped file this session: Azeroth.zmp's
//! cell at the recorded index law for Goldshire's world position holds 12 = Elwynn Forest.
//! 5875 ships `Azeroth.zmp` + `Kalimdor.zmp` (and a dead `Expansion01.zmp`).
use anyhow::{bail, Context, Result};
use crate::chain::Chain;
/// Cells per grid edge (half-ADT: 128 cells over 64 tiles).
pub const ZONE_MAP_EDGE: usize = 128;
/// Load `Interface\WorldMap\<area_name>.zmp` — 16384 raw `AreaTable.dbc` ids, row-major.
/// A continent without a shipped bitmap is an error (the client leaves its grid zeroed; callers
/// decide whether that's tolerable).
pub fn load_zone_map(chain: &mut Chain, area_name: &str) -> Result<Vec<u32>> {
let path = format!("Interface\\WorldMap\\{area_name}.zmp");
let bytes = chain
.read_file(&path)
.with_context(|| format!("reading {path}"))?;
if bytes.len() != ZONE_MAP_EDGE * ZONE_MAP_EDGE * 4 {
bail!(
"{path}: expected {} bytes (128×128 u32), got {}",
ZONE_MAP_EDGE * ZONE_MAP_EDGE * 4,
bytes.len()
);
}
Ok(bytes
.chunks_exact(4)
.map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]))
.collect())
}
#[cfg(test)]
mod tests {
use super::*;
/// The real Azeroth bitmap: the Goldshire cell (index by the byte law: col from wy=60, row
/// from wx=−9450 ⇒ cell 12735) holds Elwynn Forest's AreaTable id — the end-to-end pin of
/// path, layout, and index law against shipped data. Skips without client data.
#[test]
fn real_azeroth_zone_map_goldshire_cell() {
let data = crate::wow_data_or_skip!();
let mut chain = crate::open_chain(&data).expect("open chain");
let grid = load_zone_map(&mut chain, "Azeroth").expect("load Azeroth.zmp");
assert_eq!(grid.len(), 16384);
assert_eq!(grid[12735], 12, "the Goldshire cell is Elwynn Forest");
let nonzero = grid.iter().filter(|&&v| v != 0).count();
assert!(
(2000..6000).contains(&nonzero),
"land cells in a plausible band, got {nonzero}"
);
}
}