Project-wide companion to --info-zone-models-total. Walks every zone in
<projectDir>, sums verts/tris/bones/anims/batches per WOM and groups/
verts/tris/doodads/portals per WOB, then prints a per-zone breakdown
table plus a TOTAL row. Both human (table) and --json output modes.
Useful for capacity planning across an entire content project — e.g.
"how many bones across all my creatures" or "total triangles per frame
if every model loaded simultaneously."
Verified on the 2-zone migration test project: per-zone counts match
--info-zone-models-total output, totals row aggregates correctly,
JSON form parses cleanly. Brings command count to 170.
Project-wide companion to --export-zone-checksum. Walks every zone in
<projectDir>, hashes every source file, and emits PROJECT_SHA256SUMS in
the standard sha256sum format with paths kept relative to projectDir
(so entries look like "<hex> <zone>/<file>"). Also computes a single
SHA-256 fingerprint over the manifest body — a one-line identity for
the whole project, useful for CI release gates and reproducibility.
Verified: external 'sha256sum -c PROJECT_SHA256SUMS' passes all 9
entries on a 2-zone test project, and standalone 'sha256sum
PROJECT_SHA256SUMS' matches the emitted fingerprint byte-for-byte.
Adds wowee_sha256::hex(buf, len) helper. Brings command count to 169.
Wraps --migrate-zone across every zone under <projectDir>, so a single
invocation upgrades legacy WOM1/WOM2 files to WOM3 with batches[]
populated across an entire content project. Per-zone breakdown table
shows scanned/upgraded/already-v3/failed counts for visibility.
Verified end-to-end: scaffold 2 zones, drop 3 v1 cubes, run --migrate-
project once → 3/3 upgraded; second run → 0 upgraded, 3 already-v3
(idempotent). Brings total command count to 168.
Aggregates WOM/WOB stats across every model in a zone. Useful for
capacity planning and perf budgeting:
wowee_editor --info-zone-models-total custom_zones/MyZone
Zone models total: custom_zones/MyZone
WOM (open M2):
files : 47
vertices : 184320
triangles : 122880
bones : 612
anims : 94
batches : 188
WOB (open WMO):
files : 8
groups : 32
vertices : 28480
triangles : 18960
doodads : 156
portals : 24
Combined :
vertices : 212800
triangles : 141840
Per-format aggregation (WOM = open M2, WOB = open WMO) plus a
combined totals row. Catches:
- 'how many bones across all my creatures?' (rigging budget)
- 'total triangles per frame if all loaded?' (perf ceiling)
- 'do my models actually have multi-batch material support?'
(counts batch entries; 0 means everything is WOM1/WOM2)
Walks the zone dir recursively so models in subdirs (creatures/,
buildings/, props/) all roll up. JSON mode emits per-format records
for capacity dashboards.
Project-level cross-reference checker. Walks every zone and runs the
same model-path / NPC-id checks --check-zone-refs does, with per-zone
breakdown:
wowee_editor --check-project-refs custom_zones
check-project-refs: custom_zones
zones : 12 (2 failed)
total missing: 5
zone obj_chk obj_miss q_chk q_miss status
AshenForest 12 0 4 0 PASS
BoneOasis 17 2 6 0 FAIL
Stranglethorn 34 1 8 2 FAIL
...
2 zone(s) have dangling refs
Per-zone columns split objects vs quests so designers see at a
glance whether the issue is missing models (asset bundle drift) or
NPC IDs (creature definitions out of sync with quest references).
Pairs with --check-project-content (data quality) and
--validate-project (binary integrity). Together the three give a
complete pre-ship validation gate:
--validate-project binary structure
--check-project-content field plausibility
--check-project-refs cross-references resolve
Verified on a 2-zone project: Forest mvp-zone has 1 unresolved
object placement (no Tree.m2 on disk in test cwd), Bad zone has
1 missing object → 2 zones FAIL, exit 1.
Renders WOM bone hierarchy as Graphviz DOT. Mirrors --export-quest-graph
for skeleton trees: a 50-bone tree from --info-bones is hard to read in
text; pipe this through 'dot -Tpng' for the picture:
wowee_editor --export-bones-dot HumanMale
dot -Tpng HumanMale.bones.dot -o bones.png
Visual encoding:
- lightgreen fill: keybones (named anchor points referenced by gameplay
systems — head, hands, feet, etc.)
- lightgrey fill: internal/blend bones (non-key, used for shape only)
- goldenrod border: root bones (parent=-1, top of skeleton hierarchy)
Edges flow parent -> child (rankdir=TB so root is at top, leaves at
bottom).
Useful for skeleton-debugging:
- 'why is this finger not following its hand?' -> see the parent chain
- 'is this bone really a root or did its parent get deleted?' ->
goldenrod border makes intentional roots vs accidental ones obvious
- understanding which bones gameplay code can reference by key id
Verified on a 5-bone synthesized skeleton (3-deep chain + 1 detached
root + mix of key/internal): DOT correctly emits 5 nodes with the
right colors (3 lightgreen for key bones, 2 lightgrey for internal,
2 with goldenrod root borders), 3 edges traversing the chain.
Counterpart to --scaffold-zone / --copy-zone / --rename-zone — completes
the zone-lifecycle CRUD. Defense-in-depth against accidental
destruction:
wowee_editor --remove-zone custom_zones/Doomed
remove-zone: custom_zones/Doomed ('Doomed')
would delete: 6 file(s), 174.9 KB
re-run with --confirm to actually delete
wowee_editor --remove-zone custom_zones/Doomed --confirm
Removed custom_zones/Doomed ('Doomed')
deleted: 7 filesystem entries, 174.9 KB freed
Two-step safety:
1. Without --confirm: dry-run that lists what would be deleted
(file count + total bytes + zone display name from manifest).
2. With --confirm: actually wipes the directory.
Belt-and-suspenders refusal: even with --confirm, refuses to delete
anything that doesn't have a zone.json at the top level. Catches
typos like '--remove-zone .' that would otherwise nuke an entire
project.
Why not just 'rm -rf'? --remove-zone gives:
- Per-zone display name in the confirmation
- Byte-count audit before deletion
- The non-zone-dir guard (rm doesn't know what a zone is)
- Symmetric with the rest of the zone-lifecycle CLI
Verified: dry-run lists 6 files / 175 KB; '. --confirm' correctly
refused (no zone.json at top level); zone-dir --confirm wiped 7
fs entries with byte tally.
Tree view of a WCP archive's contents with per-file byte sizes.
--list-wcp shows the flat sorted file list; this gives the
hierarchical view that's easier to read for archives with
subdirectories:
wowee_editor --info-pack-tree custom_zones/MyZone.wcp
custom_zones/MyZone.wcp (47 files, 2348.21 KB)
├─ Forest_28_30.whm (150540 bytes)
├─ Forest_28_30.wot (26685 bytes)
├─ buildings/
│ ├─ inn.wob (45120 bytes)
│ └─ tavern.wob (38104 bytes)
├─ creatures.json (694 bytes)
├─ data/
│ ├─ Spell.json (15032 bytes)
│ └─ Item.json (8194 bytes)
├─ objects.json (234 bytes)
└─ zone.json (500 bytes)
Recursive renderer with UTF-8 box-drawing connectors. Files show
their byte size; directories show the subtree subtotal aggregated
from children. Children sorted alphabetically (std::map).
Pairs with --info-pack-budget (per-extension byte breakdown) and
--list-wcp (flat sorted list) — three lenses on the same archive:
hierarchy / extension cost / flat search.
Verified on a 6-file mvp-zone WCP: tree correctly shows top-level
files (no subdirs in mvp-zone output) with byte sizes and total
175 KB summary.
Project-level content sanity check. Walks every zone and runs the
same per-zone checks --check-zone-content does, aggregating warnings
per zone. Designed for CI gates before --pack-wcp:
wowee_editor --check-project-content custom_zones
check-project-content: custom_zones
zones : 12 (2 failed)
total warns : 7
zone creat object quest status
AshenForest 0 0 0 PASS
BoneOasis 3 0 1 FAIL
CrystalCaverns 0 0 0 PASS
Stranglethorn 2 1 0 FAIL
...
2 zone(s) have content warnings
Per-zone warning columns (creature/object/quest) make it instantly
clear which content category needs attention. Exit 1 if any zone
has any warning so CI can gate.
Pairs with --validate-project (binary integrity) — both needed for
release gates: a zone can have valid file structure (validate
passes) AND content data-quality issues (check-content fails).
Verified on a 2-zone project: mvp-zone Forest (all defaults sane)
PASS, Empty zone with displayId=0 creature FAIL with 1 warning,
exit 1.
Renders a top-down PNG showing creature + object spawn positions
colored by type. Bound by the zone's tile range so the image is
properly framed at zone scale:
wowee_editor --export-zone-spawn-png custom_zones/MyZone
# -> custom_zones/MyZone/MyZone_spawns.png
Layout:
- Tile-grid lines at tile boundaries (subtle grey on dark grey)
- Red 3×3 dots: creature spawns
- Green 3×3 dots: M2 object placements
- Blue 3×3 dots: WMO object placements
- 256 px per tile (so a 4-tile zone is 512×512); cap at 4096
largest dim for huge multi-tile projects
WoW coord -> image transform: +X world is north (up in image),
+Y world is west (left in image). Same convention --info-tilemap
uses, so the spawn map and the tilemap line up visually.
Useful for design review ('does the spawn distribution match the
encounter design?'), screenshot bait for blog posts, and instant
visual validation of new content before opening the GUI.
Verified on a 1-tile mvp-zone with 3 creatures + 1 object plotted:
256×256 RGB PNG, dots placed at expected positions, --info-png
confirms the output is well-formed (8-bit RGB, 2184 bytes).
Companion to --bench-validate-project. Times the WHM/WOT load step
(the dominant cost in --bake-zone-glb/obj/stl) per zone. The actual
write side adds ~constant cost proportional to vertex count, so
load time is a strong proxy for bake cost:
wowee_editor --bench-bake-project custom_zones
Bench bake (load-only): custom_zones
zones : 12
total : 4731.20 ms (terrain load)
per zone : avg=394.27 min=87.42 max=2103.55 ms
slowest : Stranglethorn (2103.55 ms)
Per-zone:
zone ms tiles chunks ms/tile
AshenForest 87.42 1 256 87.42
BoneOasis 245.10 4 1024 61.27
Stranglethorn 2103.55 9 2304 233.73
Useful for tracking 'has my latest geometry change made baking 3×
slower?' across releases. Per-tile timing surfaces zones with
high-variance chunk loads (e.g. dense doodad placements that
inflate ADT load time).
Pairs with --bench-validate-project (validation timing). Both use
std::chrono::steady_clock for monotonic measurement; JSON modes
emit per-zone records for CI dashboard consumption.
Verified on a 2-zone project (Forest 2 tiles + Desert 1 tile):
correctly reports per-zone timings + ms/tile ratio.
Drills into a .glb's byte composition. Pairs with --info-glb (counts)
and --info-glb-tree (structure) — three lenses on the same file:
wowee_editor --info-glb-bytes custom_zones/Z/Z.glb
GLB bytes: custom_zones/Z/Z.glb
total: 891736 bytes (0.85 MB)
Sections:
header : 12 bytes 0.00%
JSON hdr : 8 bytes 0.00%
JSON : 828 bytes 0.09%
BIN hdr : 8 bytes 0.00%
BIN : 890880 bytes 99.90%
BufferViews:
idx target bytes MB share-of-bin
0 vertex 248832 0.24 27.93%
1 vertex 248832 0.24 27.93%
2 index 393216 0.38 44.14%
By attribute:
INDICES 393216 bytes (44.14% of BIN)
NORMAL 248832 bytes (27.93% of BIN)
POSITION 248832 bytes (27.93% of BIN)
Three breakdowns:
- Section costs (header + JSON chunk + BIN chunk + their headers)
- Per-bufferView with target hints (vertex / index / other)
- Per-attribute (POSITION/NORMAL/TEXCOORD_0/INDICES/etc.) bucketed
by walking accessors referenced from primitives
Catches asymmetric BIN allocation ('why is INDICES 44% of my .glb?')
and helps tune vertex layout decisions (drop normals if synthesized,
quantize positions if precision allows). Verified on a single-tile
zone bake: header+JSON is 0.1% of total, BIN is 99.9%, attribute
breakdown shows POSITION/NORMAL each 28% and INDICES 44%.
Companion to --info-pack-budget (which operates on .wcp archives).
Per-extension byte breakdown of an extract dir, sorted largest-first.
Answers 'where did my 31 GB extract go?' with a flat sortable table:
wowee_editor --info-extract-budget /home/k/Desktop/wowee/Data
Extract budget: /home/k/Desktop/wowee/Data
total: 284613 file(s), 31482.11 MB
ext count bytes MB share
.adt 11213 11985924414 11430.7 36.3%
.wav 39396 8107038542 7731.5 24.6%
.blp 133742 4990640480 4759.4 15.1%
.m2 48466 2568180656 2449.2 7.8%
.wmo 16526 2286454107 2180.5 6.9%
.mp3 1222 1976864519 1885.3 6.0%
...
Caps to top 30 extensions with the rest rolled into '(other)' so
big extracts (this one has 30+ format types) don't drown the
output.
Pairs with --info-extract-tree (hierarchical view) and
--info-extract (sidecar coverage) — three lenses on an extract
directory: structure, formats, byte costs.
Verified on a real 31GB Data/ extract: ADT files dominate at 36%
(11GB), with WAV audio second at 25% (8GB).
Quest-side analytics paralleling --info-creatures-by-faction/-level.
Two distribution views for difficulty-curve and reward-pacing analysis:
wowee_editor --info-quests-by-level $Z/quests.json
Quests by required level: ... (47 total)
range : 1 to 60 (avg 22.4)
level count bar
1 8 ████████████████████████████████████████
5 6 ██████████████████████████████
...
60 1 █████
wowee_editor --info-quests-by-xp $Z/quests.json
Quests by XP reward: ... (47 total)
range : 100 to 5000 (avg 1462, 0 with 0 XP)
bucket (≥XP) count bar
0 8 ████████████████████████████████████████
250 6 ██████████████████████████████
500 4 ████████████████████
5000 1 █████
(bucket size: 250 XP)
--by-level: catches difficulty-curve gaps (every quest level 1 → no
mid-game; cluster at 60 → no early game) and outliers (level-30
quest dropped into a starter zone).
--by-xp: bucket size auto-grows with the max XP value so the
histogram stays readable for both starter zones (10-100 XP per bin)
and endgame (5000+ XP per bin). Surfaces no-reward quests
explicitly so designers spot ones they forgot to fill in.
JSON modes emit per-bucket records for dashboards. Verified on a
4-quest seed (xp 100/250/500/5000): bucket-size correctly auto-
selected as 250 XP, range and avg match.
Per-tile batch runner. Pairs with --for-each-zone (project-level
tile iteration is too coarse for tile-level commands like
--build-woc, --validate-whm, --info-whm).
wowee_editor --for-each-tile custom_zones/MyZone -- \
wowee_editor --build-woc {}
[custom_zones/MyZone/MyZone_30_30 (30, 30)]
WOC built: custom_zones/MyZone/MyZone_30_30.woc (32768 triangles, ...)
[custom_zones/MyZone/MyZone_31_30 (31, 30)]
WOC built: custom_zones/MyZone/MyZone_31_30.woc (32768 triangles, ...)
for-each-tile: 2 tiles, 0 failed
The {} substitution receives the tile-base path (zoneDir/mapName_TX_TY)
which is the form most tile-level commands accept. Sorts tiles by
(tx, ty) so output ordering is deterministic.
Use cases:
- Build WOC for every tile in one shot after editing terrain
- Validate WHM headers across all tiles
- Export per-tile previews via --export-whm-obj
- Per-tile data dump via --info-whm
Same shell-escaping + cmd-substitution machinery as --for-each-zone
(safe against names with spaces and quotes). Returns failed-run
count as exit code (capped at 255).
Verified on a 2-tile zone running --build-woc per tile: both
tiles built correctly, exit 0.
Times --validate-project per zone. Useful for catching unusually
slow zones (huge WHM/WOC pairs, lots of WOM batches) and tracking
validation overhead growth across releases:
wowee_editor --bench-validate-project custom_zones
Bench validate: custom_zones
zones : 12
total : 4731.20 ms
per zone : avg=394.27 min=87.42 max=2103.55 ms
slowest : Stranglethorn (2103.55 ms)
Per-zone timings:
zone ms files ms/file
AshenForest 87.42 8 10.928
BoneOasis 245.10 17 14.418
Stranglethorn 2103.55 94 22.378
...
Reports total + avg/min/max per zone + slowest zone callout. Per-
zone table with ms/file ratio surfaces formats that scale poorly
('this zone has only 5 files but takes 2 seconds — one is a 100MB
WHM that's slow to load').
Useful for:
- Pre-commit profiling: 'did my validator change make Stranglethorn
3× slower?'
- CI cycle time budgeting
- Catching pathological inputs (a 10000-creature creatures.json that
blows up validation cost)
JSON mode emits per-zone records + aggregate stats for dashboards.
Verified on a 2-zone project: per-zone timings make sense (Forest
with .woc takes 5× longer than Desert without).
Per-tile content density. Catches sparse zones (5 mobs across 16
tiles → boring) and over-stuffed ones (200 mobs in 1 tile → frame-
rate bomb). Reports overall averages plus per-tile bucket counts:
wowee_editor --info-zone-density custom_zones/MyZone
Zone density: custom_zones/MyZone
tiles : 4
totals : 47 creatures, 23 objects, 8 quests
per-tile : 11.75 creatures, 5.75 objects, 2.00 quests
Per-tile breakdown:
tile creatures objects
(28, 30) 12 7
(29, 30) 18 4
(29, 31) 9 8
(30, 30) 8 4
Spawn-to-tile bucketing reverses the WoW grid transform from world
position back to tile (tx, ty) coords. Out-of-zone spawns silently
drop (they show up in --check-zone-refs / --check-zone-content as
their own warning class).
Useful for difficulty-curve work ('how packed is this hub vs this
zone-edge?'), perf budgeting ('which tile do I need to lod-out
first?'), and content-pacing reviews ('is the early game too empty?').
JSON mode emits per-tile records for dashboards. Verified on a
1-tile mvp-zone: 1 creature + 1 object + 1 quest, all bucketed
into the correct tile (28, 30).
Object-side counterparts to --info-creatures-by-faction/-level. Two
analytics commands for placement audits:
wowee_editor --info-objects-by-path $Z/objects.json
Objects by path: ... (47 total, 12 unique)
count share path
18 38.3% World/Generic/Tree.m2
9 19.1% World/Generic/Lamp.m2
4 8.5% World/Building/Inn.wmo
...
wowee_editor --info-objects-by-type $Z/objects.json
Objects by type: ...
M2 : 38 (scale 0.80-2.50, avg 1.12)
WMO : 9 (scale 1.00-1.00, avg 1.00)
--info-objects-by-path: most-used model paths first. Catches
'this looks repetitive, diversify the doodads' design feedback
and surfaces texture-budget hot spots (one model used 50× pulls
its textures into the working set 50×).
--info-objects-by-type: M2 vs WMO split + per-type scale stats.
Catches scale outliers ('this WMO is at 0.001 scale, did you mean
1.0?') and gives composition sense (mostly props vs mostly
buildings).
JSON modes emit per-path / per-type records for dashboards.
Verified on a 4-object seed (3 M2 + 1 WMO with mixed scales):
correctly reports Tree.m2 used 2× (50%), M2 scale range 0.80-1.50
avg 1.10.
Aggregates water-layer stats across every tile in a zone. Useful for
confirming a 'lake zone' actually has water, budgeting water-heavy
zones, or auditing what liquid types appear (water vs ocean vs magma
vs slime affects gameplay rules):
wowee_editor --info-zone-water custom_zones/Z
Zone water: custom_zones/Z
loaded tiles : 1
water chunks : 0 (out of 256 possible)
total layers : 0
(no water in this zone)
wowee_editor --info-zone-water custom_zones/Stranglethorn
Zone water: custom_zones/Stranglethorn
loaded tiles : 4
water chunks : 387 (out of 1024 possible)
total layers : 412
height range : 12.40 to 18.50
By liquid type:
water (0): 380 layer(s)
ocean (1): 28 layer(s)
magma (2): 4 layer(s)
Per-chunk water can have multiple layers (different liquid types or
height regions overlapping). Liquid types: 0=water, 1=ocean, 2=magma,
3=slime — different gameplay rules apply (oceans are swimable, magma
is damage-over-time, etc.).
JSON mode emits per-type layer counts + height range for programmatic
audit. Verified on a freshly-scaffolded zone: correctly reports 0
water chunks.
Multi-zone wrapper around --validate-all. Walks every zone in a
project and runs the per-format validators (WOM/WOB/WOC/WHM).
Aggregates pass/fail per zone with file-level breakdown:
wowee_editor --validate-project custom_zones
validate-project: custom_zones
zones : 12 (1 failed)
zone files failed errors status
AshenForest 47 0 0 PASS
BoneOasis 31 0 0 PASS
CrystalCaverns 28 2 14 FAIL
...
1 zone(s) failed validation
Designed for CI gates before --pack-wcp (or before tagging a release):
one command checks the whole project's binary integrity, exits 1 if
anything's broken with a clear breakdown of which zone went wrong.
Pairs with --validate-all (single-zone, all formats) and the
per-format validators (--validate-wom etc.). Three levels of
granularity now:
--validate-{wom,wob,woc,whm} single file
--validate-all single zone (or any dir)
--validate-project entire project
JSON mode emits per-zone records (totalFiles + failedFiles +
totalErrors) for dashboard consumption. Verified on a 2-zone
project with one tile having .woc built and one without — both
zones PASS, exit 0.
Two analytics commands for combat-balance work. Where --info-creatures
gives totals + behavior counts, these give the distributions:
wowee_editor --info-creatures-by-faction $Z/creatures.json
Creatures by faction: ... (47 total)
faction count share
7 12 25.5%
14 29 61.7%
35 6 12.8%
(factions: 7=human, 14=monster, 35=neutral, etc.)
wowee_editor --info-creatures-by-level $Z/creatures.json
Creatures by level: ... (47 total)
range : 5 to 32 (avg 14.2)
level count bar
5 4 ████████████████████████████████████████
6 3 ██████████████████████████████
...
30 1 ██████████
Faction histogram catches single-faction zones (one giant melee) and
mixed-faction tuning issues. Level histogram catches difficulty-curve
problems (cluster at 5, gap, cluster at 30) and outlier spawns
(level-60 boss accidentally placed in starter area).
ASCII bar chart for level distribution since gameplay tuning is
visual — '60% of mobs are levels 8-12 with a long tail' is more
intuitive as a bar than as numbers. Bars scale to longest bin so
small zones still get usable visualization.
JSON mode emits per-faction / per-level records for dashboards.
Verified on a 4-creature seed (3×faction-14 + 1×faction-35; levels
7/8/12/30): faction percentages and level range/avg both correct.
Self-check that every flag in kArgRequired (the master list of
commands needing positional args) appears in the help text emitted
by printUsage. Catches drift where a handler+arg-check pair gets
added but the help line is forgotten:
wowee_editor --validate-cli-help
CLI help self-check
kArgRequired entries : 126
PASSED — every kArgRequired flag is documented
If it ever fails, the missing flags are listed:
FAILED — 2 flag(s) missing from help text:
- --new-thing-i-forgot-to-document
- --another-undocumented-flag
CI integration: add this to the test target so a PR that adds a
new command without docs can't merge. The --info-cli-stats command
gives the surface-size view; this gives the surface-completeness
view.
Verified: ran on the current binary (126 kArgRequired entries),
PASSED — every flag is documented.
Project-level tree view: every zone with quick counts + bake/viewer
artifact status. --info-zone-tree drills into one zone; this gives
the bird's-eye view across the whole project:
wowee_editor --info-project-tree custom_zones
custom_zones/ (2 zones, 2 tiles, 1 creatures, 1 objects, 1 quests)
├─ Empty/ (tiles=1, creat=0, obj=0, quest=0)
│ ├─ name : Empty
│ ├─ mapName : Empty
│ ├─ artifacts : (none)
│ └─ status : empty (only terrain)
└─ Forest/ (tiles=1, creat=1, obj=1, quest=1)
├─ name : Forest
├─ mapName : Forest
├─ artifacts : .glb
└─ status : populated
Per-zone summary line shows counts; sub-tree shows display name,
map slug, which derived artifacts have been baked (.glb / .obj /
.stl / .html / ZONE.md), and a populated/empty status.
Project-header line aggregates totals across all zones for the
'how big is my project?' answer in one glance.
Pairs with --info-tilemap (spatial coverage) and --zone-stats
(quantitative aggregate) — three different lenses on the project:
spatial, quantitative, and structural.
Markdown counterpart to --export-project-html. Generates a README.md
indexing every zone with counts + bake/viewer/doc artifact status.
GitHub renders it natively at the project root:
wowee_editor --export-project-md custom_zones
# Wowee Project — Zone Index
*Auto-generated. 2 zone(s) discovered in `custom_zones`.*
## Summary
| Metric | Total |
|---|---:|
| Zones | 2 |
| Tiles | 2 |
| Creatures | 2 |
| ...
## Zones
| Zone | Tiles | Creatures | Objects | Quests | Bake | Viewer | Docs |
|---|---:|---:|---:|---:|:---:|:---:|:---:|
| Desert | 1 | 1 | 1 | 1 | — | — | — |
| [Forest](Forest/ZONE.md) | 1 | 1 | 1 | 1 | ✓ | [view](Forest/Forest.html) | [md](Forest/ZONE.md) |
Per-zone row links to its ZONE.md (if --export-zone-summary-md was
run) and its HTML viewer (if --export-zone-html was run). The Bake
column shows ✓ if .glb exists. Status columns make it instantly
visible which zones are bake-ready vs documentation-only.
Pairs with --export-project-html (interactive viewer index) — same
data, different presentation: HTML for browsers, Markdown for
GitHub Pages READMEs and PR descriptions.
Verified on a 2-zone project where one zone had been baked +
viewer-exported + doc-exported and the other hadn't: README.md
correctly shows ✓/links for the baked zone, em-dashes for the
unbaked one.
Computes the zone's spatial bounding box: XY world coords from
manifest tile coords (each tile is 533.33 yards), Z height range
across all loaded chunks. Useful for sizing camera frustums,
planning where new tiles can fit contiguously, or quick sanity
checks ('this zone is 4km across? something's wrong'):
wowee_editor --info-zone-extents custom_zones/MyZone
Zone extents: custom_zones/MyZone
tile count : 3 (3 loaded, 0 missing on disk)
tile range : x=[30, 31] y=[30, 31]
world box : (0.0, 0.0, 98.5) - (1066.7, 1066.7, 101.5) yards
size : 1066.7 x 1066.7 x 3.0 yards (975m x 975m x 2.7m)
WoW grid math: tile (32, 32) is at world origin; +X tile = -X world
(north convention), +Y tile = -Y world (west convention). The
displayed world coords use the same transform the renderer uses
so they line up with --bake-zone-glb output bounds.
Per-axis size in yards + meters (0.9144 conversion) since some
designers think in metric, others in WoW-canonical yards.
Tracks loaded vs missing tiles in case the manifest references a
tile whose .whm got deleted — surfaces silently bad zones early.
JSON mode emits full bounding box + tile range + size for
programmatic consumption (camera autofit, layout planning).
Compares two SHA256SUMS files (from --export-zone-checksum). Reports
added / removed / changed entries between two zone snapshots — much
faster than walking the filesystem to recompute hashes of unchanged
content:
wowee_editor --export-zone-checksum custom_zones/Z /tmp/before.sha256
... edits happen ...
wowee_editor --export-zone-checksum custom_zones/Z /tmp/after.sha256
wowee_editor --diff-checksum /tmp/before.sha256 /tmp/after.sha256
Diff: /tmp/before.sha256 vs /tmp/after.sha256
added : 1
removed : 0
changed : 0
+ creatures.json
Standard diff-style markers (+/-/~) for added/removed/changed,
sorted within each category alphabetically.
Use cases:
- Audit what an editing session actually touched (snapshot before,
snapshot after, diff)
- Verify a zone bundle re-extracts identically (transfer integrity
beyond the per-file PASS/FAIL of sha256sum -c)
- CI gate: fail build if a refactor touches files it shouldn't
Diff family for content/integrity formats:
--diff-zone unpacked zone dir vs zone dir (high-level)
--diff-extract per-extension counts in two extracts
--diff-checksum per-file hash diff between two snapshots <- new
Verified: scaffold + export checksum, add creature, re-export,
diff correctly reports '+ creatures.json' (added) and exit 1.
Quick-start: scaffold a zone AND populate one of each content type
(1 creature, 1 object, 1 quest with objective + XP reward) in a
single command. Goes from empty filesystem to 'something to look at'
without 7 chained --add-* commands:
wowee_editor --mvp-zone 'Demo Land' 30 30
Created demo zone: custom_zones/Demo_Land
tile : (30, 30)
contents : 1 creature, 1 object, 1 quest (with objective + reward)
next : wowee_editor --info-zone-tree custom_zones/Demo_Land
Demo Land/
├─ Manifest ...
├─ Tiles (1) — (30, 30)
├─ Creatures (1) — lvl 5 Demo Wolf
├─ Objects (1) — m2 World/Generic/Tree.m2
├─ Quests (1) — [1] Welcome to Demo Land (lvl 1, 100 XP)
│ └─ kill ×1 Demo Wolf
Demo content is positioned roughly at tile center (533.33-yard
intervals from origin tile 32/32). Quest references the demo
creature's auto-id so --check-zone-refs passes immediately.
Use cases:
- Smoke-testing the bake/validate pipeline
- Screenshot bait for docs / blog posts
- Editor onboarding (open a zone in the GUI to see the format)
- CI sanity check (does our editor still produce a viewable zone?)
Verified end-to-end: --mvp-zone 'Demo Land' → --info-zone-tree
shows all 4 sections populated correctly, file list matches
expected 6 files.
Where --export-quest-graph visualizes the quest dependency graph,
this quantifies it. Useful for spotting authoring issues (orphan
quests that only appear as one-offs, broken chains via cycles)
and getting a sense of quest density:
wowee_editor --info-quest-graph-stats $Z/quests.json
Quest graph: $Z/quests.json
total quests : 4
roots : 2 (no inbound chain — entry points)
leaves : 2 (no outbound chain — terminal)
orphans : 1 (root AND leaf — one-shot)
cycles : 0
max depth : 3
avg depth : 2.00 (chain length per root)
Definitions:
roots = quests no other quest chains TO (player entry points)
leaves = quests with no nextQuestId or nextQuestId pointing to
a missing quest (terminal — chain ends here)
orphans = root AND leaf (one-shot quests with no neighbors)
cycles = number of roots whose forward walk hits a node twice
maxDepth = longest path from any root forward through the chain
avgDepth = mean path length across all roots
Cycle-guarded forward walk uses a visited-set per root, so the
cycle count is bounded even on intentionally-broken inputs.
Exit 1 if cycles > 0 so CI can gate before shipping a broken
chain. JSON mode emits all six stats for dashboard consumption.
Verified on 4-quest zone (Q1→Q2→Q3 chain + Loner orphan):
correctly reports 2 roots, 2 leaves, 1 orphan, 0 cycles, max
depth 3, avg depth 2.00.
Three project-bake formats now match the three zone-bake formats —
full project terrain reachable from every universal-3D ecosystem:
wowee_editor --bake-project-obj custom_zones # DCC tools
wowee_editor --bake-project-stl custom_zones # 3D printing
wowee_editor --bake-project-glb custom_zones # web viewers
Shared per-zone walking pass collects vertex+index pools per zone,
then the format-specific tail emits:
STL → per-triangle 'facet normal'+'outer loop'+vertex×3
GLB → packed BIN chunk + JSON describing per-zone meshes
GLB output gives one mesh+node per zone (named 'zone_NAME') so
viewers can toggle zones independently — same pattern as
--bake-zone-glb but at project scope. STL is single-solid since
slicers don't have a useful concept of multi-part STL.
Coords align across all three exporters and across zone vs project
scope, so:
- A zone .obj overlaid with its containing project .obj lines up
- A project .glb opened in three.js shows zones at the same coords
the renderer uses
Verified on a 2-zone project (Forest + Desert):
- project.stl: 2 zones, 2 tiles, 65536 facets
- project.glb: 2 zones, 2 tiles, 41472 verts, 65536 tris, 1.78MB BIN
- --validate-glb on project.glb: PASSED
Bake granularity matrix complete:
OBJ STL GLB
single model --export-obj --export-stl --export-glb
single zone --bake-zone-obj --bake-zone-stl --bake-zone-glb
whole project --bake-project-obj --bake-project-stl --bake-project-glb
Project-level OBJ bake — combines every zone's terrain into one
giant OBJ with one 'g zone_NAME' block per zone. Useful for
previewing an entire multi-zone project's terrain in MeshLab/
Blender at once, or for printing the full map:
wowee_editor --bake-project-obj custom_zones
Baked custom_zones -> custom_zones/project.obj
2 zone(s), 3 tiles, 62208 verts, 98304 tris
Layout: single global vertex pool (so OBJ indexing stays valid),
per-zone face groups so designers can hide individual zones in
their viewer for area-by-area inspection. Hole bits respected.
Coords match WoweeCollisionBuilder's outer-grid layout exactly so
zones spatially line up at WoW grid boundaries — adjacent tiles
across zones connect seamlessly.
Pairs with the existing --bake-zone-* family (single zone) and
--export-project-html (web index of per-zone viewers). Three
levels of granularity now available:
--export-glb / --export-obj / --export-stl single model/file
--bake-zone-glb / -obj / -stl single zone
--bake-project-obj entire project <- new
Verified: 2-zone project (Forest 2 tiles + Desert 1 tile) baked
to project.obj with 62208 verts (3 × 20736), 98304 tris (3 ×
32768), 2 'g' blocks correctly named (zone_Desert, zone_Forest).
Emits a SHA-256 manifest of every source file in a zone in the
standard sha256sum format. Lets users verify zone integrity after
download/transfer using the standard system tool — no custom
verifier needed:
wowee_editor --export-zone-checksum custom_zones/MyZone
3298c35a... Z_30_30.whm
f81e3d37... Z_30_30.wot
6a49519f... creatures.json
4625e30b... zone.json
sha256sum -c custom_zones/MyZone/SHA256SUMS
Z_30_30.whm: OK
Z_30_30.wot: OK
...
Source-only by design — derived outputs (.glb/.obj/.stl/.html/.png/
ZONE.md/DEPS.md/quests.dot/SHA256SUMS itself/Makefile) are excluded
since they're regeneratable and would invalidate the checksum on
every rebuild.
Includes a self-contained 90-LoC SHA-256 (FIPS 180-4 / RFC 6234)
in an internal namespace — no OpenSSL/Crypto++ dependency added.
Streaming hash (16KB chunks) so it scales to giant terrain WHMs
without holding the whole file in memory.
Verified end-to-end: scaffolded zone with 1 creature → checksum
manifest of 4 source files (zone.json, creatures.json, .whm, .wot)
in standard format → sha256sum -c reports all 4 OK.
130+ commands. 'Is there a thing for X?' is a common question.
Scrolling --help to find out is slow. This searches:
wowee_editor --info-cli-help quest
--add-quest <zoneDir> <title> [giverId] [turnInId] [xp] [level]
Append one quest to <zoneDir>/quests.json and exit
--add-quest-objective <zoneDir> <questIdx> <kill|collect|...> ...
Append one objective to a quest by index
--remove-quest-objective <zoneDir> <questIdx> <objIdx>
Remove the objective at given 0-based index from a quest
--clone-quest <zoneDir> <questIdx> [newTitle]
Duplicate a quest (with all objectives + rewards)
...
32 line(s) matched 'quest'
Case-insensitive substring match. Continuation lines (the indented
description right after a flag) are emitted along with their flag
line for context. Match-count summary on stderr so it doesn't
contaminate piped output.
Pairs with --list-commands (full list) and --info-cli-stats (counts
by category). Three meta commands now cover the discovery loop:
'how many?' (--info-cli-stats), 'which ones?' (--list-commands),
'what does X do?' (--info-cli-help X).
Pairs with --gen-makefile (per-zone) — generates a project-level
Makefile that delegates to each zone's per-zone Makefile, enabling
parallel rebuilds across zones:
wowee_editor --gen-project-makefile custom_zones
make -C custom_zones -j$(nproc) # all zones in parallel
make Forest-bake # one zone
make clean # strip every zone
make validate # validate every zone
make index # rebuild project HTML index
make stats / tilemap # project-level reports
Per-zone targets (one set per zone):
ZONE-bake -> ensures ZONE/Makefile exists then `make -C ZONE all`
ZONE-clean -> --strip-zone ZONE
ZONE-validate -> --validate-all ZONE
Auto-generates the per-zone Makefile if missing (so the project
Makefile bootstraps a fresh project without an extra setup step).
Top-level utility targets reuse the existing project-level commands:
- index -> --export-project-html (HTML zone index)
- stats -> --zone-stats (aggregate counts)
- tilemap -> --info-tilemap (ADT grid visualization)
Verified: 2-zone project (Forest + Desert) generates a Makefile
with 6 zone-level targets (3 per zone) + 5 top-level targets, sorted
alphabetically by zone name.
Sanity-checks creature/object/quest fields for plausible values.
Where --check-zone-refs catches dangling references, this catches
data-quality issues that pass technical validation but break
gameplay:
wowee_editor --check-zone-content custom_zones/MyZone
Zone content: custom_zones/MyZone
creature warnings: 1
object warnings : 0
quest warnings : 2
FAILED — 3 total warning(s):
- creature[0] 'Wolf' has displayId=0 (will render invisibly)
- quest[0] 'Hunt' has no objectives (uncompletable)
- quest[0] 'Hunt' has no reward at all
Per-type checks:
Creatures:
- empty name
- 0 health (dies on spawn)
- level 0
- minDamage > maxDamage (broken combat math)
- non-positive or non-finite scale
- displayId=0 (invisible at runtime)
Objects:
- empty path
- non-positive or non-finite scale
- non-finite position
Quests:
- empty title
- no objectives (player can never complete)
- no reward at all (XP=0, items=[], coins all 0)
- requiredLevel=0
Both --check-zone-refs (link integrity) and --check-zone-content
(data quality) needed — a quest can have valid NPC IDs (refs OK)
AND no objectives (content broken). Run both before --pack-wcp.
Verified end-to-end: zone with displayId=0 creature + objective-
less + rewardless quest reports 3 warnings; after fixing all three,
PASSED.
Compares two extracted asset directories side-by-side per file
extension. Useful for diffing a fresh asset_extract run against
a previous baseline (did the new MPQ add files? did any get
dropped?), or comparing what each WoW expansion contributes:
wowee_editor --diff-extract baseline/ new/
Diff: baseline/ vs new/
totals: 4 files / 0.0 MB vs 4 files / 0.0 MB
Per-extension (count then bytes):
ext a count b count a bytes b bytes status
.blp 2 2 0 0
.dbc 1 0 0 0 -A
.m2 1 2 0 0 DIFF
2 extension(s) differ
Status column flags imbalance:
-A only in A (extension dropped going B-ward)
+B only in B (extension added)
DIFF count differs but both sides have some
Recursive walk so subdirectories aggregate into the parent's
extension counts. JSON mode emits per-extension {count,bytes}
pairs for both sides plus union diff count for CI consumption.
Diff family for directory-shaped formats:
--diff-zone unpacked zone dir vs zone dir
--diff-extract extracted asset dir vs extract dir <- new
Verified on synthesized 4-file dirs (a: 2 blp + 1 dbc + 1 m2;
b: 2 blp + 0 dbc + 2 m2): correctly flags -A on .dbc, DIFF on
.m2, exit 1.
130 commands and counting — surface inspection has graduated from
'nice to have' to 'necessary to plan'. This drops a per-category
breakdown:
wowee_editor --info-cli-stats
CLI surface stats
total commands : 130
longest flag : 24 chars
Categories (by verb prefix, sorted by count):
--info 33
--export 15
--list 12
--validate 11
--diff 8
--add 6
--remove 5
--convert 5
--bake 3
--migrate 3
--clone 3
...
Pulls the command list via the same printUsage-parser as
--list-commands so it auto-tracks new flags. Buckets by the verb
prefix (text between '--' and the next '-') so '--info-zone-tree'
counts under 'info'. JSON mode emits the histogram as an object
for dashboard consumption.
Useful for spotting category imbalances ('we have 33 inspectors
but only 5 add commands — should consider more authoring CRUD?'),
tracking growth over releases, and planning where to invest.
Generates a Makefile that rebuilds every derived output for a zone
with proper dependency tracking. Designers can `make` to refresh
glb/obj/stl/html/csv/md from sources after editing creatures.json
or terrain — without remembering which wowee_editor flag does what,
and without rebuilding outputs that haven't changed:
wowee_editor --gen-makefile custom_zones/MyZone
cd custom_zones/MyZone && make
make all # rebuild everything that's stale
make glb # just the glTF bake
make clean # nuke derived outputs (calls --strip-zone)
make validate # run --validate-all on the zone
Targets generated:
glb obj stl html docs csv graph all clean validate
Dependency tracking:
- terrain bakes (.glb/.obj/.stl) depend on zone.json + WHM tiles
- HTML viewer depends on the .glb (forces glb rebuild first)
- docs (ZONE.md/DEPS.md) depend on content JSONs
- csv/graph use '-' prefix so missing-content failures don't
block 'make all' (zone with no quests still bakes terrain)
Uses /proc/self/exe absolute path so the Makefile works from any
cwd (run via `make -C custom_zones/MyZone` from anywhere). Falls
back to PATH lookup if /proc not available.
Verified end-to-end: scaffolded zone, generated Makefile, ran
`make all` from inside the zone dir — all derived outputs (.glb,
.obj, .stl, .html, ZONE.md, DEPS.md) generated; csv+graph
gracefully skipped due to no content; make exit 0.
After asset_extract finishes, '142k files across 17 dirs' is hard
to reason about. This groups them visually by top-level subdir +
file format with byte totals — instant orientation:
wowee_editor --info-extract-tree Data
Data/ (13 dirs, 284612 files, 31451.1 MB)
├─ expansions/ (85141 files, 12871.2 MB)
│ ├─ .adt 5469 files 6226626.7 KB
│ ├─ .wav 19517 files 3567936.9 KB
│ ├─ .m2 26354 files 1477702.1 KB
│ ├─ .wmo 5195 files 744940.1 KB
│ ├─ .blp 26911 files 691248.5 KB
│ ├─ .dbc 282 files 92373.6 KB
│ ├─ ...
├─ terrain/ (...)
├─ character/ (...)
Top-level dirs sorted by total bytes descending (heaviest first
so the high-impact directories surface immediately). Per-dir
extension breakdown also sorted by bytes. Walks recursively into
each top-level dir so 'expansions/wotlk/world/...' rolls up into
the expansions/ row.
Companion to --info-extract (counts + sidecar coverage) — that
one's wide-format JSON-friendly; this one's a tall tree-style
quick-look. Verified on a real 31GB extract of Data/ — output
makes the size distribution immediately clear (ADT files are
6GB of 13GB total for expansions/, etc.).
Companion to --validate-png — validates BLP textures without paying
the DXT decompress cost. Useful for spot-checking thousands of BLPs
in an extract dir:
wowee_editor --validate-blp Texture.blp
BLP: Texture.blp
magic : BLP2
size : 128 x 128
valid mips : 8
file bytes : 23044
PASSED
Checks (header-only, no pixel decode):
- 4-byte magic is 'BLP1' or 'BLP2'
- Width/height non-zero and within 8192 (texture exporter cap)
- mipOffsets[16] / mipSizes[16] tables: each non-zero pair refers
to a byte range within the file; mismatched (off=0 with size!=0
or vice versa) flagged
- Stops at first zero offset (BLP convention for unused slots)
Per-version layout differences (BLP1 has compression+alphaBits as
uint32; BLP2 has compression/alphaDepth/alphaEncoding/hasMips as
uint8) handled inline.
Verified on real BLP (pvp-banner-emblem-1.blp): 8 valid mips,
PASSED. Non-BLP file (manifest.json starting with '{'): correctly
flags 'magic is {' error and exits 1.
Format-validator lineup is now exhaustive across both proprietary
and open formats:
Proprietary: BLP / DBC (via --convert-dbc-json round-trip)
Open binary: WOM / WOB / WOC / WHM / GLB
Open text: JSON DBC / STL / PNG (BLP sidecar)
Generates an index.html linking to every zone's HTML viewer in a
project. Pairs with --export-zone-html (per-zone) and --bake-zone-glb
(terrain bake). Designed for github-pages / static-hosting style
'all my zones' showcase:
wowee_editor --export-project-html custom_zones
# -> custom_zones/index.html
Each zone gets a card showing:
- Display name (or mapName fallback)
- Counts: tiles · creatures · objects · quests (singular/plural
agreement)
- 'Open viewer →' link if HTML exists
- Helpful nudge if HTML missing ('No HTML viewer (run --export-zone-html)')
- Or 'No .glb (run --bake-zone-glb)' if not even baked yet
Self-contained CSS (dark theme matching --export-zone-html), no
external dependencies. Responsive grid layout (300px-min cards
auto-flowing across viewport).
Verified on a 2-zone project (Forest with .glb+.html + Desert
without): index lists both, Forest gets a working link, Desert
gets the 'run --bake-zone-glb' hint.
Renders the WoW 64x64 ADT coordinate grid as ASCII art showing which
tiles are claimed by which zones. Useful for spotting tile-coord
collisions before two zones ship overlapping content, and for
'where am I working?' overview of multi-zone projects:
wowee_editor --info-tilemap custom_zones
Tilemap: custom_zones
zones : 2
tiles used : 5
collisions : 0 (multiple zones claiming same tile)
legend : D=Desert F=Forest
0 1 2 3 4 5 6
0123456789012345678901234567890123456789012345678901234567890123
y=30 ..............................FFDD..............................
y=31 ...............................F................................
Glyphs are first-letter-of-zone uppercased; collision tiles render
as '*'. Empty rows are skipped to keep output bounded for projects
in one corner of the map (skipping all 60+ blank rows of the full
64x64 grid).
Exit 1 on collisions so CI can gate before merging two PRs that
both add tiles in the same area. JSON mode emits per-tile claims
for programmatic consumption.
Verified on a 2-zone project: Forest (3 tiles) + Desert (2 tiles)
correctly rendered, no collisions detected, glyphs F/D placed at
the right grid coords.
When a zone is hand-edited, partially copied, or modified by tools
that don't re-write zone.json, the manifest can fall out of sync
with the on-disk reality. --repair-zone reconciles them:
wowee_editor --repair-zone custom_zones/MyZone --dry-run
would add tile (31, 30) to manifest
would set hasCreatures: false -> true
repair-zone: custom_zones/MyZone (dry-run)
fixes : 2
warnings : 0 (manual decision needed)
re-run without --dry-run to apply
Auto-fixes:
- WHM files on disk matching <mapName>_TX_TY.whm pattern but not
in manifest tiles[] -> add to tiles
- hasCreatures flag mismatched against actual creatures.json
presence + non-empty -> sync
Warns (no auto-fix — needs manual decision):
- Tiles in manifest but no .whm on disk (could be in-progress
work or genuinely deleted; user decides)
--dry-run flag previews changes. Pairs with --strip-zone (cleanup
derived) and --validate (open-format coverage) for the trio of
zone-health-maintenance commands.
Verified: scaffolded zone, hand-copied an extra .whm/.wot pair to
simulate disk-without-manifest drift, added a creature then flipped
hasCreatures=false in zone.json. --repair-zone correctly identifies
2 fixes, dry-run lists them, real run applies them, manifest now
shows correct tiles array + hasCreatures=true.
Removes the derived outputs (everything --bake/--export-* generates)
leaving only source files in a zone directory:
wowee_editor --strip-zone custom_zones/MyZone
removed: MyZone.obj (1099177 bytes)
removed: MyZone.glb (891736 bytes)
removed: DEPS.md (357 bytes)
removed: ZONE.md (534 bytes)
removed: quests.dot (198 bytes)
strip-zone: custom_zones/MyZone
removed : 5 file(s)
freed : 1945.3 KB
What gets deleted:
- .glb / .obj / .stl (3D format exports)
- .html (browser viewer)
- .dot (Graphviz quest graph)
- .csv (spreadsheet exports)
- ZONE.md / DEPS.md (markdown documentation)
- .png at zone root (heightmap previews — NOT inside data/, those
are source BLP→PNG sidecars)
What stays:
- zone.json + creatures.json + objects.json + quests.json
- *.whm / *.wot / *.woc (terrain + collision)
- *.wom / *.wob (open binary models/buildings)
- data/*.json (DBC sidecars — source, not derived)
Top-level only — does not recurse into subdirectories so source
sidecars under data/ are untouched.
--dry-run flag previews what would be removed without deleting.
Useful before committing to git so derived blobs don't bloat
history, or before --pack-wcp so the archive doesn't carry
redundant exports.
Verified: scaffolded zone, generated 5 derived files (glb/obj/
ZONE.md/DEPS.md/quests.dot), --dry-run lists all 5 with sizes,
real run deletes them and frees 1945 KB. Source files (whm/wot/
woc/zone.json/quests.json) all preserved.
Markdown counterpart to --list-zone-deps. PR reviewers see at a
glance whether every referenced model exists in either open or
proprietary form across the conventional asset roots:
wowee_editor --export-zone-deps-md custom_zones/MyZone
# -> custom_zones/MyZone/DEPS.md
# Dependencies — MyZone
*Auto-generated. Status is best-effort — checks zone-local, output/,
custom_zones/, Data/ roots in that order.*
## Direct M2 placements (12)
| Refs | Path | Status |
|---:|---|---|
| 8 | `World/Tree.m2` | open + proprietary |
| 3 | `World/Lamp.m2` | open only |
| 1 | `World/Banner.m2` | MISSING |
Status column resolves each path against zone-local + output/ +
custom_zones/ + Data/ roots, trying both .wob/.wmo for buildings
and .wom/.m2 for models. Catches missing assets BEFORE pack-wcp
would silently include broken refs.
GitHub-Flavored Markdown — sortable by Refs column once rendered,
backtick-wrapped paths so URLs/spaces don't confuse the viewer.
Verified: scaffolded zone with 2 M2 placements (one duplicated) +
1 WMO placement → DEPS.md has 3 sections (one per category) with
correct ref counts (Tree.m2 ×2) and MISSING status for paths that
don't resolve in any root.
Diff family is now exhaustively complete across every shippable
format:
--diff-wcp archive
--diff-zone unpacked zone dir
--diff-glb glTF binary
--diff-wom WOM model
--diff-wob WOB building
--diff-whm WHM/WOT terrain pair
--diff-woc WOC collision
--diff-jsondbc JSON DBC sidecar <- new
Schema-level compare:
- format tag
- source filename
- recordCount + fieldCount (header values)
- actualRecs (records[] array length)
Useful for catching schema regressions when a sidecar is regenerated
by a different tool version, or for verifying a --migrate-jsondbc
pass actually changed what it claimed.
Verified: same file vs itself reports IDENTICAL exit 0;
2-record vs 3-record (with same format/source/fieldCount) reports
2 DIFFs (recordCount + actualRecs) with exit 1.
Last two missing entries in the diff family — terrain heightmap pairs
and collision meshes:
wowee_editor --diff-whm Z1/Z1_30_30 Z2/Z2_31_30
Diff: ...
a b
tile : ( 30, 30) ( 31, 30) DIFF
loadedChunks : 256 256
doodadPlace : 0 0
wmoPlace : 0 0
heightRange : [-1.50,1.50] [-1.50,1.50]
wowee_editor --diff-woc tile_a.woc tile_b.woc
Diff: ...
a b
tile : ( 30, 30) ( 31, 30) DIFF
triangles : 32768 32768
walkable : 32768 32768
steep : 0 0
--diff-whm: tile coord, loaded chunk count, doodad/WMO placement
counts, texture/name table sizes, height range (min/max with float
epsilon). Pointwise height compare intentionally not done — float
perturbation from format round-trips would false-flag.
--diff-woc: tile coord, total triangles, walkable + steep counts.
Catches whether a --regen-collision pass actually changed something.
Diff family is now exhaustively complete for every shippable open
format:
--diff-wcp archive vs archive
--diff-zone unpacked zone dir vs zone dir
--diff-glb glTF binary vs glTF binary
--diff-wom WOM model vs WOM model
--diff-wob WOB building vs WOB building
--diff-whm WHM/WOT terrain pair vs pair
--diff-woc WOC collision vs collision
Verified: tile (30,30) vs (31,30) reports tile DIFF + identical
counts (since both are flat scaffolds); same-vs-self reports
IDENTICAL with exit 0.