grom, after a night's play: "make the map look a lot nicer, it would be really nice if the darkened areas were not just massive squares on the map, and should fit into the actual edges of the terrian if that makes sense, also I shouldn't see this dark squares on the fully zoomed out world map, also make it so the world map can't move out of the frame." **The darkening.** OpenMapClassic washed a never-visited zone through its land mask, and those masks are Voronoi-dilated by construction — "so that the forty of them tile each continent with no gap" — so for any zone that is not on a coast the mask *is* the rectangle. Measured at zoom 2.5 over the Eastern Kingdoms: a grid of flat grey boxes. Nothing could have been softened into a fix; it was the wrong mask. It was also drawn at full strength from every zoom, and at the whole-world view the zones' own art is not drawn at all, so the only thing on the world map was the fog's rectangles. A land mask for every map now comes from the client's own data. `bake_zone_land` unions a map's `WorldMapOverlay` alpha — the pieces the game reveals as you explore, cut to the shape of the ground — into one 256×256 mask; `overlay-land-index.py` writes the list the addon reads, because Lua cannot test for a file and a *missing* mask is dropped by the engine so the whole rectangle draws, which is the defect itself. 53 maps have overlays (the 40 stock zones, Hyjal, Alterac Valley and 11 of the realm's own); 76 have none and keep a wide feather. `clip-zone-masks-to-coast.py` then takes the open sea off the dilated sheet masks — the same dilation was painting parchment out on the ocean — by closing the continent's own land by 500 yards (above the 466-yard inradius of the widest enclosed gap, so seams fill and the sea does not) and keeping a 300-yard coastal margin. Twelve landlocked zones lose 0.0%; Darkshore loses 53%, all of it water. `tga.rs` gains the writer that needed, `script::uimap` and `ui_world_map::build_catalog` become public so an example can reach the uiMapID graph, and `WorldMapUiData` grows the accessor so the VM push and an outside caller cannot build different lists. **The glyph sheet.** His four-minute session reset it 27 times, each dropping every cached glyph. The producer is Atlas-CFM's cursor coordinate readout: a 12 px FontString on `WorldMapDetailFrame`, rewritten every frame, and the canvas zooms by scaling that frame — 140 device px a digit at a canvas scale of 6.9. Nothing about the addon is wrong, so the fix is ours: `raster_ppem` rasterizes exactly up to 64 device px and snaps to a third-octave ladder above it, with `cell()` scaling the cached bitmap and metrics left keyed on the true ppem, so advances and `GetStringWidth` are bit-for-bit unchanged. Same 1,200-frame reproduction: 3 resets and 6,623 rasters before, **0 and 1,424** after, with occupancy climbing once to 30% and stopping. A reset no longer clears the metric cache either, and `note_loud_cell` names the string that asked for an outsized cell. **Four more from the same log.** `SetOwner`'s unknown-anchor line named a forwarding wrapper rather than the addon that chose the anchor (two `debugstack` frames now); the nine reference anchor names are written down with the binary evidence, because `ANCHOR_TOP` is not one of them. The `CreateFrame(kind, …, inherits=<other kind>)` warning fired in both directions and only one drops content — `kind_subsumes` makes it directional, and `type_chain` moves out of `install` so `IsObjectType` and the loader read one table. A string that is not UTF-8 now names the Lua line that cut it, and both glyph warnings quote the string the character came out of. The three world-map CVars stay unregistered, with the argument written down beside `REGISTERED` so it is not re-litigated from the warning. **`World.zmp`.** The realm's `WorldMapArea` carries a third `areaID == 0` row, `694 World`, with an all-zero rect; the reference ships no bitmap for it and neither the graph nor the realm's own `Overrides.lua` lets it reach a player. The miss is a `debug!` line now, and the `warn!` is kept for a continent that *has* a rectangle and is missing its bitmap. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn
76 lines
2.9 KiB
Python
Executable File
76 lines
2.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Write OpenMapClassic's `Data/OverlayLand.lua` from the baked `MapOverlayLand` masks.
|
|
|
|
`cargo run -p benilla-app --example bake_zone_land` writes one 256x256 alpha mask per map, the
|
|
union of that map's own `WorldMapOverlay` art -- the shape of the ground it paints. Lua cannot ask
|
|
whether a texture file exists (a missing one draws as a white quad, or, as a *mask*, is silently
|
|
dropped and the whole rectangle shows), so the addon needs a table of which ids were baked. That
|
|
is all this writes.
|
|
|
|
Run it after the baker, any time the mask set changes:
|
|
|
|
python3 scripts/overlay-land-index.py
|
|
|
|
`--dir` points at another mask folder, `--out` at another destination.
|
|
"""
|
|
import argparse
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
ADDON = Path(__file__).resolve().parent.parent / "benilla-config/AddOns/OpenMapClassic"
|
|
|
|
HEAD = """--------------------------------------------------------------------------------
|
|
-- Which maps have a generated land mask (Media/Textures/MapOverlayLand/<uiMapID>.tga).
|
|
--
|
|
-- GENERATED -- do not edit. `cargo run -p benilla-app --example bake_zone_land` writes the masks,
|
|
-- `scripts/overlay-land-index.py` writes this list.
|
|
--
|
|
-- Each mask is the union of that map's own `WorldMapOverlay` alpha: the pieces the game reveals
|
|
-- as you explore, cut to the shape of the ground, so the union is the map's land and nothing
|
|
-- else. `Map/Stitch.lua` cuts the unexplored darkening to it, and falls back to it for the art of
|
|
-- any map the hand-made `MapZoneSoft` set has no file for -- this realm has 175 `WorldMapArea`
|
|
-- rows against that set's 40.
|
|
--
|
|
-- A file list, not a file test, because Lua has no way to ask whether a texture exists: a mask
|
|
-- whose art is missing is dropped by the engine and the whole rectangle draws, which is the
|
|
-- "massive squares" this set exists to remove.
|
|
--------------------------------------------------------------------------------
|
|
|
|
local _, ns = ...
|
|
|
|
ns.MapOverlayLand = {
|
|
"""
|
|
|
|
|
|
def main() -> int:
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("--dir", default=str(ADDON / "Media/Textures/MapOverlayLand"))
|
|
ap.add_argument("--out", default=str(ADDON / "Data/OverlayLand.lua"))
|
|
args = ap.parse_args()
|
|
|
|
folder = Path(args.dir)
|
|
if not folder.is_dir():
|
|
print(f"overlay-land-index: no mask folder at {folder}", file=sys.stderr)
|
|
return 1
|
|
ids = sorted(
|
|
int(m.group(1))
|
|
for p in folder.iterdir()
|
|
if (m := re.fullmatch(r"(\d+)\.tga", p.name, re.IGNORECASE))
|
|
)
|
|
if not ids:
|
|
print(f"overlay-land-index: {folder} holds no <id>.tga masks", file=sys.stderr)
|
|
return 1
|
|
|
|
body = []
|
|
for i in range(0, len(ids), 8):
|
|
body.append("\t" + " ".join(f"[{n}] = true," for n in ids[i : i + 8]))
|
|
text = HEAD + "\n".join(body) + "\n}\n"
|
|
Path(args.out).write_text(text, encoding="utf-8")
|
|
print(f"overlay-land-index: {len(ids)} masks -> {args.out}")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|