ui: the map's own art line, in every session's log

A play report about how the map looks arrives without the diagnostic that
answers it, and the only way to ask for the line again is to wait for the
player to play again. It cost a round trip on 2026-11-02, so the trace is
unconditional now: one line per world-map selection change, with the frame
the detail is drawn into added beside the detail frame's own rect, since a
canvas zoom and an oversized tile change the picture the same way and only
the two together say which one did it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn
This commit is contained in:
2026-11-02 18:42:45 -07:00
co-authored by Claude Opus 5
parent eef0d06852
commit 204184afb2
+26 -19
View File
@@ -64,16 +64,9 @@ 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
/// The chunk the art trace runs, once per map change. Pure reads; `GetTexture` answers the path
/// the stock repaint set, and a texture created with no size of its own answers its own extent
/// through the host's size probe, which is why a scratch region measures 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#"
@@ -83,6 +76,18 @@ 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())) }
-- What it is drawn into: a canvas zoom and a tile size both change the picture, and only the
-- two together say which one did.
local p = d:GetParent()
if p then
out[#out + 1] = string.format("in %s %sx%s @(%s,%s) scale %.2f", p:GetName() or "<unnamed>",
num(p:GetWidth()), num(p:GetHeight()), num(p:GetLeft()), num(p:GetTop()),
p:GetEffectiveScale() or 1)
end
if WorldMapFrame then
out[#out + 1] = string.format("frame %sx%s scale %.2f", num(WorldMapFrame:GetWidth()),
num(WorldMapFrame:GetHeight()), WorldMapFrame:GetEffectiveScale() or 1)
end
-- 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")
@@ -691,7 +696,7 @@ 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
/// The map selection the 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
@@ -1028,14 +1033,16 @@ 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() {
// 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
// rect and effective scale, the frame it is drawn into, 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. It was
// behind `WOW_MAP_TRACE` and that cost a round trip: a play report about the map arrives
// without it, and the next one cannot be asked for until the player plays again.
{
let key = script.world_map_selection();
let memo = memo.get(&script);
if memo.art_logged != Some(key) {