app: WOW_MAP_TRACE, because no instrument here can see the map
A player's report about how the map *looks* is the one question this side cannot answer. The offline addon harness seats no renderer, the capture harness seats no UI or addons, and a scripted login would kick the player off their own account — so a full audit (art present and correct, catalog right, canvas geometry right, overlay tiling arithmetic right, addon setup complete) still could not say why grom's Dun Morogh map came up magnified, clipped and grey. Every number that decides the picture is readable from the VM. `WOW_MAP_TRACE=1` prints them once per map change: the detail frame's rect and effective scale, then per tile its rect, the texture path it holds, and the decoded size of that file. The file size is measured through a scratch texture with no size of its own, because the tile declares 256x256 in `WorldMapFrame.xml` and would answer that whatever the file holds — and this install's map art is a 512 upscale pack, which is exactly the disagreement worth seeing. Off unless the variable is set: it runs a Lua chunk per map change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn
This commit is contained in:
@@ -64,6 +64,50 @@ struct DirectAreaEntry {
|
||||
view: WorldMapZoneView,
|
||||
}
|
||||
|
||||
/// `WOW_MAP_TRACE=1`, read once: the map-art trace below is off unless a player is being asked
|
||||
/// to reproduce something, since it runs a Lua chunk per map change.
|
||||
fn map_trace_on() -> bool {
|
||||
static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
|
||||
*ON.get_or_init(|| std::env::var_os("WOW_MAP_TRACE").is_some())
|
||||
}
|
||||
|
||||
/// The chunk [`map_trace_on`] runs. Pure reads; `GetTexture` answers the path the stock repaint
|
||||
/// set, and a texture created with no size of its own answers the file's own extent through the
|
||||
/// host's size probe, which is why a scratch region is used to measure the file rather than the
|
||||
/// tile (the tile declares 256x256 in `WorldMapFrame.xml` and would answer that whatever the file
|
||||
/// holds).
|
||||
const MAP_ART_TRACE: &str = r#"
|
||||
local d = WorldMapDetailFrame
|
||||
if not d then return "no WorldMapDetailFrame" end
|
||||
local function num(v) return v and string.format("%.0f", v) or "?" end
|
||||
local out = { string.format("detail %sx%s @(%s,%s) scale %.2f shown=%s",
|
||||
num(d:GetWidth()), num(d:GetHeight()), num(d:GetLeft()), num(d:GetTop()),
|
||||
d:GetEffectiveScale() or 1, tostring(d:IsShown())) }
|
||||
-- One scratch texture, re-pointed per tile: with no size of its own it answers the file's extent.
|
||||
if not BenillaMapTraceProbe then
|
||||
BenillaMapTraceProbe = UIParent:CreateTexture(nil, "BACKGROUND")
|
||||
BenillaMapTraceProbe:Hide()
|
||||
end
|
||||
local probe = BenillaMapTraceProbe
|
||||
for i = 1, 12 do
|
||||
local t = _G["WorldMapDetailTile" .. i]
|
||||
if t then
|
||||
local path = t:GetTexture()
|
||||
local fw, fh = "?", "?"
|
||||
if path then
|
||||
probe:SetWidth(0) probe:SetHeight(0)
|
||||
probe:SetTexture(path)
|
||||
fw, fh = num(probe:GetWidth()), num(probe:GetHeight())
|
||||
end
|
||||
out[#out + 1] = string.format("%d %sx%s @(%s,%s) file %sx%s %s", i,
|
||||
num(t:GetWidth()), num(t:GetHeight()), num(t:GetLeft()), num(t:GetTop()),
|
||||
fw, fh, tostring(path))
|
||||
end
|
||||
end
|
||||
out[#out + 1] = "overlays " .. tostring(GetNumMapOverlays and GetNumMapOverlays() or "?")
|
||||
return table.concat(out, " | ")
|
||||
"#;
|
||||
|
||||
fn zone_rect(a: &WorldMapArea) -> ZoneRect {
|
||||
ZoneRect {
|
||||
left: a.loc_left,
|
||||
@@ -647,6 +691,9 @@ struct FeedMemos {
|
||||
/// line prints on change rather than every frame — the selection is in the key because a
|
||||
/// selection that stops following the player is the thing the line exists to show.
|
||||
zone_logged: Option<(u32, u32, u32, u32, u32, u32, u32)>,
|
||||
/// The map selection the `WOW_MAP_TRACE` art line last reported, so it prints once per map
|
||||
/// rather than once per frame.
|
||||
art_logged: Option<(u32, u32, Option<u32>)>,
|
||||
/// The resolved pair last seen, so the watchdog in [`feed_world_map`] can tell the player
|
||||
/// moving to a new zone from the map being browsed away from the player's.
|
||||
last_resolved: Option<(u32, u32, Option<u32>)>,
|
||||
@@ -981,6 +1028,25 @@ fn feed_world_map(
|
||||
}
|
||||
}
|
||||
|
||||
// `WOW_MAP_TRACE=1`: what the map's base art actually is, once per map change. A player's
|
||||
// report about how the map *looks* cannot be answered from this side — the offline harness
|
||||
// seats no renderer and the capture harness seats no UI — and every number that decides the
|
||||
// picture is readable from the VM, so this prints them rather than guessing from a
|
||||
// screenshot: the detail frame's own rect and effective scale, then per tile its rect, the
|
||||
// texture path it holds and the decoded size of that file. A tile whose rect is not 256x256
|
||||
// at a 256 pitch, or whose file is not the size the layout assumes, names the fault outright.
|
||||
if map_trace_on() {
|
||||
let key = script.world_map_selection();
|
||||
let memo = memo.get(&script);
|
||||
if memo.art_logged != Some(key) {
|
||||
memo.art_logged = Some(key);
|
||||
match script.eval::<String>(MAP_ART_TRACE) {
|
||||
Ok(line) => info!("world map art: {line}"),
|
||||
Err(e) => warn!("world map art: trace failed: {e}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// First world enter: the zone updater `0x494780` (`crate::area`), finding the cached zone id
|
||||
// 0, selects the player's zone itself through `0x4a6650` and the setter `0x4a67a0` before any
|
||||
// Lua asks. Once per VM, each login being a first enter.
|
||||
|
||||
Reference in New Issue
Block a user