feat(editor): add standalone world editor (rough/WIP)
Standalone wowee_editor tool for creating custom WoW zones.
This is a rough initial implementation — many features work but
M2/WMO rendering still has issues (frame sync, texture layout
transitions) and needs further polish.
Terrain:
- Create new blank terrain with 10 biome types (Grassland, Forest,
Jungle, Desert, Barrens, Snow, Swamp, Rocky, Beach, Volcanic)
- Load existing ADT tiles from extracted game data
- Sculpt brushes: Raise, Lower, Smooth, Flatten, Level
- Chunk edge stitching prevents seams between tiles
- Undo/redo (100-deep stack, Ctrl+Z/Ctrl+Shift+Z)
- Save to WoW ADT/WDT format
Texture Painting:
- Paint/Erase/Replace Base modes
- Full tileset texture browser (1285 textures from manifest)
- Per-zone directory filtering and search
- Alpha map editing with 4-layer limit (auto-replaces weakest)
Object Placement:
- M2 and WMO model placement with full manifest browser (11k M2s, 2k WMOs)
- M2Renderer + WMORenderer integrated (loads .skin files for WotLK)
- Ghost preview follows cursor before placing
- Ctrl+click selection, right-click context menu
- Transform gizmo (Move/Rotate/Scale with axis constraints)
- Position/rotation/scale editing in properties panel
NPC/Monster System:
- 631 creature presets scanned from manifest, categorized
(Critters, Beasts, Humanoids, Undead, Demons, etc.)
- Stats editor: level, health, mana, damage, armor, faction
- Behavior: Stationary, Patrol, Wander, Scripted
- Aggro/leash radius, respawn time, flags (hostile/vendor/etc.)
- Save creature spawns to JSON
Water:
- Place water at configurable height per chunk
- Liquid types: Water, Ocean, Magma, Slime
- Rendered as translucent colored quads
- Saved in ADT MH2O format
Infrastructure:
- Free-fly camera (WASD/QE, right-drag look, scroll speed)
- 5-mode toolbar: Sculpt | Paint | Objects | Water | NPCs
- Asset browser indexes full manifest on startup
- Editor water/marker shaders (pos+color vertex format)
- forceNoCull added to M2Renderer for editor use
- AssetManifest::getEntries() and AssetManager::getManifest() exposed
Known issues:
- M2/WMO rendering may not display on first placement (frame index
sync between update/render was misaligned — now fixed but untested
end-to-end)
- Validation layer errors on shutdown (resource cleanup ordering)
- Object placement on steep terrain can miss raycast
- No undo for texture painting or object placement yet
2026-05-05 03:47:03 -07:00
|
|
|
#include "editor_app.hpp"
|
2026-05-09 10:15:51 -07:00
|
|
|
#include "cli_dispatch.hpp"
|
2026-05-09 06:25:04 -07:00
|
|
|
#include "cli_convert_single.hpp"
|
2026-05-09 10:08:14 -07:00
|
|
|
#include "cli_arg_required.hpp"
|
2026-05-06 03:09:56 -07:00
|
|
|
#include "content_pack.hpp"
|
2026-05-06 07:14:42 -07:00
|
|
|
#include "npc_spawner.hpp"
|
2026-05-06 07:15:40 -07:00
|
|
|
#include "object_placer.hpp"
|
2026-05-06 07:16:27 -07:00
|
|
|
#include "quest_editor.hpp"
|
2026-05-06 08:17:33 -07:00
|
|
|
#include "wowee_terrain.hpp"
|
|
|
|
|
#include "zone_manifest.hpp"
|
|
|
|
|
#include "terrain_editor.hpp"
|
|
|
|
|
#include "terrain_biomes.hpp"
|
|
|
|
|
#include <filesystem>
|
feat(editor): add --export-obj for WOM -> Wavefront OBJ conversion
WOM is our open M2 replacement, but it's still a custom binary format
no DCC tool understands out of the box. OBJ is the universally
supported text format that opens directly in Blender, MeshLab,
ZBrush, Maya — basically every 3D tool ever made:
wowee_editor --export-obj Tree # writes Tree.obj
wowee_editor --export-obj Tree out.obj # custom output path
This closes the loop for content authors:
asset_extract -> WOM (open binary) -> OBJ (universal text) ->
edit in Blender -> back to WOM via a future --import-obj.
Layout details that matter for downstream tools:
- 1-based face indices (OBJ standard)
- UV V flipped (1.0 - v) so texturing matches between Vulkan
top-left and Blender bottom-left conventions
- Per-batch groups when WOM3 batches exist, named with the
texture basename so material assignment carries through
- Single 'mesh' group for WOM1/WOM2 models
- Header comment preserves provenance (source, version, counts)
Verified on a synthesized 5-vert pyramid (4 base + apex, 6 tris):
output OBJ has 5 v / 5 vt / 5 vn entries, 6 f lines, opens cleanly
in MeshLab. Build green, ctest 31/31.
2026-05-06 12:05:41 -07:00
|
|
|
#include <fstream>
|
2026-05-08 10:58:28 -07:00
|
|
|
#include <iomanip>
|
feat(editor): add --import-obj to round-trip Wavefront OBJ back into WOM
Closes the open-format authoring loop:
asset_extract # M2 -> WOM (open binary)
--export-obj # WOM -> OBJ (universal text)
... edit in Blender / MeshLab / ZBrush / Maya ...
--import-obj # OBJ -> WOM (back to engine format)
The same WOM file ships in custom zones, gets validated by
--validate-wom, and renders identically through the existing pipeline
— no proprietary M2 ever needs to touch the authoring path.
Parser handles:
- v / vt / vn pools, deduped on (pos, uv, normal) triples so the
resulting WOM vertex buffer stays compact
- 1-based AND negative (relative) face indices
- f tokens in v, v/t, v//n, and v/t/n forms
- Triangles, quads, and convex n-gons (fan-triangulated)
- CRLF line endings
- Reverses --export-obj's V flip (1.0 - v) so UVs round-trip exactly
- Auto-computes boundMin/Max/Radius from positions (renderer culls
by these — wrong values make the model disappear)
- Output WOM is WOM1 (static); bones/anims/material flags don't
exist in OBJ and stay empty by design
Verified end-to-end: WOM -> OBJ -> WOM -> validate-wom yields a
5-vert, 6-tri pyramid back identical to the input. Bounds, vertex
count, index count, and name all preserved.
2026-05-06 12:07:55 -07:00
|
|
|
#include <sstream>
|
2026-05-05 10:50:36 -07:00
|
|
|
#include "pipeline/wowee_model.hpp"
|
2026-05-05 12:41:19 -07:00
|
|
|
#include "pipeline/wowee_building.hpp"
|
2026-05-06 03:17:10 -07:00
|
|
|
#include "pipeline/wowee_collision.hpp"
|
2026-05-06 06:58:34 -07:00
|
|
|
#include "pipeline/wowee_terrain_loader.hpp"
|
2026-05-05 12:41:19 -07:00
|
|
|
#include "pipeline/wmo_loader.hpp"
|
feat(editor): add --info-m2 and --info-wmo proprietary inspectors
Round out the format-inspector lineup. The wowee open formats had
inspectors (--info-wom, --info-wob); these are the proprietary
counterparts that pair with --convert-m2 / --convert-wmo so users
can verify what the conversion preserves vs drops:
wowee_editor --info-m2 Character/Human/Male/HumanMale.m2
wowee_editor --info-wmo World/wmo/Stormwind/Stormwind.wmo
--info-m2 reports verts/tris, bones, sequences (animations),
batches, textures, materials, attachments, particles, ribbons,
collision tris, and bound radius. Auto-merges <base>00.skin if
present (WotLK+ M2s store geometry there) so vertex/index counts
match what gets rendered.
--info-wmo reports group count + portals + lights + doodads +
materials + textures + total verts/tris across loaded groups.
Auto-merges matching <base>_NNN.wmo group files; pre-resizes the
groups vector so loadGroup populates the right slots.
Verified against real WoW assets:
nexusraid_skya.m2: v264, 20917 verts, 22940 tris, 44 bones,
1 sequence, 44 batches, 28 textures, 42 materials.
ed_zd_ziggurat.wmo: v17, 1 group (1 loaded), 8 materials, 7
textures, 4609 verts, 3650 tris from the group file.
Bug caught during testing: initial snprintf used an 8-byte buffer
for '_NNN.wmo' (which is 8 chars + NUL = 9), silently truncating
to '_000.wm' and failing every group lookup. Bumped to 16 bytes
with a comment so the trap doesn't get re-stepped.
2026-05-06 12:51:40 -07:00
|
|
|
#include "pipeline/m2_loader.hpp"
|
feat(editor): add --info-adt proprietary terrain inspector
Completes the proprietary-format inspector lineup. Pairs naturally
with --info-wot / --info-whm (the open WOT/WHM equivalents) so users
can verify the conversion preserves chunk counts, doodad placements,
and WMO references:
wowee_editor --info-adt World/Maps/Azeroth/Azeroth_32_48.adt
ADT: ...
version : 18
file bytes : 450192
coord : (0, 0)
chunks loaded : 256/256
height range : [-0.00, 0.00]
hole chunks : 0 (with cave/gap masks)
water chunks : 0
textures : 0
doodad names : 0 (0 placements)
wmo names : 1 (1 placements)
Reports loaded chunk count (out of fixed 256), height min/max across
all loaded chunks (with NaN guard so corrupted heights don't poison
the range), hole chunks (cave/gap masks), water chunks, texture and
doodad/WMO name table sizes, and placement counts.
Verified on a real WoW ADT (ahnqirajtemple_29_46.adt, 450KB):
correctly reports 256/256 chunks loaded, 1 WMO name + 1 placement.
JSON mode emits structured output for CI scripts.
The format-inspector lineup is now complete:
Proprietary: BLP / DBC / M2 / WMO / ADT
Open: PNG / JSON DBC / WOM / WOB / WOC / WOT/WHM / WCP
Every format on both sides of the open-format bridge has an inspector.
2026-05-06 12:55:31 -07:00
|
|
|
#include "pipeline/adt_loader.hpp"
|
2026-05-05 10:50:36 -07:00
|
|
|
#include "pipeline/asset_manager.hpp"
|
2026-05-05 12:18:31 -07:00
|
|
|
#include "pipeline/custom_zone_discovery.hpp"
|
feat(editor): add standalone world editor (rough/WIP)
Standalone wowee_editor tool for creating custom WoW zones.
This is a rough initial implementation — many features work but
M2/WMO rendering still has issues (frame sync, texture layout
transitions) and needs further polish.
Terrain:
- Create new blank terrain with 10 biome types (Grassland, Forest,
Jungle, Desert, Barrens, Snow, Swamp, Rocky, Beach, Volcanic)
- Load existing ADT tiles from extracted game data
- Sculpt brushes: Raise, Lower, Smooth, Flatten, Level
- Chunk edge stitching prevents seams between tiles
- Undo/redo (100-deep stack, Ctrl+Z/Ctrl+Shift+Z)
- Save to WoW ADT/WDT format
Texture Painting:
- Paint/Erase/Replace Base modes
- Full tileset texture browser (1285 textures from manifest)
- Per-zone directory filtering and search
- Alpha map editing with 4-layer limit (auto-replaces weakest)
Object Placement:
- M2 and WMO model placement with full manifest browser (11k M2s, 2k WMOs)
- M2Renderer + WMORenderer integrated (loads .skin files for WotLK)
- Ghost preview follows cursor before placing
- Ctrl+click selection, right-click context menu
- Transform gizmo (Move/Rotate/Scale with axis constraints)
- Position/rotation/scale editing in properties panel
NPC/Monster System:
- 631 creature presets scanned from manifest, categorized
(Critters, Beasts, Humanoids, Undead, Demons, etc.)
- Stats editor: level, health, mana, damage, armor, faction
- Behavior: Stationary, Patrol, Wander, Scripted
- Aggro/leash radius, respawn time, flags (hostile/vendor/etc.)
- Save creature spawns to JSON
Water:
- Place water at configurable height per chunk
- Liquid types: Water, Ocean, Magma, Slime
- Rendered as translucent colored quads
- Saved in ADT MH2O format
Infrastructure:
- Free-fly camera (WASD/QE, right-drag look, scroll speed)
- 5-mode toolbar: Sculpt | Paint | Objects | Water | NPCs
- Asset browser indexes full manifest on startup
- Editor water/marker shaders (pos+color vertex format)
- forceNoCull added to M2Renderer for editor use
- AssetManifest::getEntries() and AssetManager::getManifest() exposed
Known issues:
- M2/WMO rendering may not display on first placement (frame index
sync between update/render was misaligned — now fixed but untested
end-to-end)
- Validation layer errors on shutdown (resource cleanup ordering)
- Object placement on steep terrain can miss raycast
- No undo for texture painting or object placement yet
2026-05-05 03:47:03 -07:00
|
|
|
#include "core/logger.hpp"
|
|
|
|
|
#include <string>
|
2026-05-05 16:54:03 -07:00
|
|
|
#include <cstdio>
|
feat(editor): add standalone world editor (rough/WIP)
Standalone wowee_editor tool for creating custom WoW zones.
This is a rough initial implementation — many features work but
M2/WMO rendering still has issues (frame sync, texture layout
transitions) and needs further polish.
Terrain:
- Create new blank terrain with 10 biome types (Grassland, Forest,
Jungle, Desert, Barrens, Snow, Swamp, Rocky, Beach, Volcanic)
- Load existing ADT tiles from extracted game data
- Sculpt brushes: Raise, Lower, Smooth, Flatten, Level
- Chunk edge stitching prevents seams between tiles
- Undo/redo (100-deep stack, Ctrl+Z/Ctrl+Shift+Z)
- Save to WoW ADT/WDT format
Texture Painting:
- Paint/Erase/Replace Base modes
- Full tileset texture browser (1285 textures from manifest)
- Per-zone directory filtering and search
- Alpha map editing with 4-layer limit (auto-replaces weakest)
Object Placement:
- M2 and WMO model placement with full manifest browser (11k M2s, 2k WMOs)
- M2Renderer + WMORenderer integrated (loads .skin files for WotLK)
- Ghost preview follows cursor before placing
- Ctrl+click selection, right-click context menu
- Transform gizmo (Move/Rotate/Scale with axis constraints)
- Position/rotation/scale editing in properties panel
NPC/Monster System:
- 631 creature presets scanned from manifest, categorized
(Critters, Beasts, Humanoids, Undead, Demons, etc.)
- Stats editor: level, health, mana, damage, armor, faction
- Behavior: Stationary, Patrol, Wander, Scripted
- Aggro/leash radius, respawn time, flags (hostile/vendor/etc.)
- Save creature spawns to JSON
Water:
- Place water at configurable height per chunk
- Liquid types: Water, Ocean, Magma, Slime
- Rendered as translucent colored quads
- Saved in ADT MH2O format
Infrastructure:
- Free-fly camera (WASD/QE, right-drag look, scroll speed)
- 5-mode toolbar: Sculpt | Paint | Objects | Water | NPCs
- Asset browser indexes full manifest on startup
- Editor water/marker shaders (pos+color vertex format)
- forceNoCull added to M2Renderer for editor use
- AssetManifest::getEntries() and AssetManager::getManifest() exposed
Known issues:
- M2/WMO rendering may not display on first placement (frame index
sync between update/render was misaligned — now fixed but untested
end-to-end)
- Validation layer errors on shutdown (resource cleanup ordering)
- Object placement on steep terrain can miss raycast
- No undo for texture painting or object placement yet
2026-05-05 03:47:03 -07:00
|
|
|
#include <cstring>
|
2026-05-06 04:36:40 -07:00
|
|
|
#include <unordered_map>
|
2026-05-06 13:27:18 -07:00
|
|
|
#include <unordered_set>
|
2026-05-06 13:24:27 -07:00
|
|
|
#include <map>
|
2026-05-06 13:59:54 -07:00
|
|
|
#include <set>
|
|
|
|
|
#include <cctype>
|
|
|
|
|
#include <cstdio>
|
2026-05-06 18:03:55 -07:00
|
|
|
#include <chrono>
|
2026-05-06 19:17:42 -07:00
|
|
|
#include <functional>
|
|
|
|
|
#include <memory>
|
2026-05-06 07:30:26 -07:00
|
|
|
#include <algorithm>
|
feat(editor): --info-extract --json for machine-readable coverage output
Adds an optional --json flag that emits a structured nlohmann JSON
object instead of the human-readable text. Schema:
{
"dir": "...",
"totalBytes": N, "proprietaryBytes": N, "openBytes": N,
"overallCoverage": 100.0,
"blp_png": { "proprietary": N, "sidecar": N, "coverage": % },
"dbc_json": { ... },
"m2_wom": { ... },
"wmo_wob": { ... },
"adt_whm": { ... }
}
Lets CI scripts gate on coverage:
cov=$(wowee_editor --info-extract Data --json | jq .overallCoverage)
if [ "$cov" != "100" ]; then asset_extract --upgrade-extract Data; fi
2026-05-06 11:07:11 -07:00
|
|
|
#include <nlohmann/json.hpp>
|
2026-05-06 12:38:14 -07:00
|
|
|
#include "stb_image_write.h"
|
2026-05-07 08:19:37 -07:00
|
|
|
#include "stb_image.h" // implementation in stb_image_impl.cpp
|
feat(editor): add standalone world editor (rough/WIP)
Standalone wowee_editor tool for creating custom WoW zones.
This is a rough initial implementation — many features work but
M2/WMO rendering still has issues (frame sync, texture layout
transitions) and needs further polish.
Terrain:
- Create new blank terrain with 10 biome types (Grassland, Forest,
Jungle, Desert, Barrens, Snow, Swamp, Rocky, Beach, Volcanic)
- Load existing ADT tiles from extracted game data
- Sculpt brushes: Raise, Lower, Smooth, Flatten, Level
- Chunk edge stitching prevents seams between tiles
- Undo/redo (100-deep stack, Ctrl+Z/Ctrl+Shift+Z)
- Save to WoW ADT/WDT format
Texture Painting:
- Paint/Erase/Replace Base modes
- Full tileset texture browser (1285 textures from manifest)
- Per-zone directory filtering and search
- Alpha map editing with 4-layer limit (auto-replaces weakest)
Object Placement:
- M2 and WMO model placement with full manifest browser (11k M2s, 2k WMOs)
- M2Renderer + WMORenderer integrated (loads .skin files for WotLK)
- Ghost preview follows cursor before placing
- Ctrl+click selection, right-click context menu
- Transform gizmo (Move/Rotate/Scale with axis constraints)
- Position/rotation/scale editing in properties panel
NPC/Monster System:
- 631 creature presets scanned from manifest, categorized
(Critters, Beasts, Humanoids, Undead, Demons, etc.)
- Stats editor: level, health, mana, damage, armor, faction
- Behavior: Stationary, Patrol, Wander, Scripted
- Aggro/leash radius, respawn time, flags (hostile/vendor/etc.)
- Save creature spawns to JSON
Water:
- Place water at configurable height per chunk
- Liquid types: Water, Ocean, Magma, Slime
- Rendered as translucent colored quads
- Saved in ADT MH2O format
Infrastructure:
- Free-fly camera (WASD/QE, right-drag look, scroll speed)
- 5-mode toolbar: Sculpt | Paint | Objects | Water | NPCs
- Asset browser indexes full manifest on startup
- Editor water/marker shaders (pos+color vertex format)
- forceNoCull added to M2Renderer for editor use
- AssetManifest::getEntries() and AssetManager::getManifest() exposed
Known issues:
- M2/WMO rendering may not display on first placement (frame index
sync between update/render was misaligned — now fixed but untested
end-to-end)
- Validation layer errors on shutdown (resource cleanup ordering)
- Object placement on steep terrain can miss raycast
- No undo for texture painting or object placement yet
2026-05-05 03:47:03 -07:00
|
|
|
|
2026-05-06 11:54:54 -07:00
|
|
|
// ─── Open-format consistency checks ─────────────────────────────
|
|
|
|
|
// Both validators are called from the per-file CLI commands AND
|
|
|
|
|
// from --validate-all which walks a zone dir. Returning a vector
|
|
|
|
|
// of error strings (empty == passed) keeps callers simple.
|
2026-05-06 15:51:50 -07:00
|
|
|
// Minimal SHA-256 implementation (FIPS 180-4) used by --export-zone-checksum
|
|
|
|
|
// to produce hashes that interoperate with `sha256sum -c`. Not exposed beyond
|
|
|
|
|
// this file — about 90 LoC, no external deps. See RFC 6234 for the algorithm.
|
|
|
|
|
|
feat(editor): add --validate-woc + --validate-whm and roll into validate-all
Round out the per-format validator suite. Open-format zone validation
now covers all four binary formats:
--validate-wom Tree
--validate-wob House
--validate-woc terrain.woc
--validate-whm Zone_28_30
--validate-all custom_zones/Zone1 # runs everything
WOC checks: finite vertex coords on every triangle, no degenerate
triangles (two verts identical), known flag bits only (0x0F mask),
tile coords within WoW grid (< 64), bounds.min <= bounds.max.
WHM/WOT checks: finite heights across all 145 verts/chunk, finite
chunk position vectors, tile coord in [0, 64), reasonable height
envelope ([-10000, 10000] is a generous outer bound — beyond that
suggests units confusion), placements have finite positions and
nameId within doodadNames/wmoNames table size.
validate-all now reports all four format counts (WOM/WOB/WOC/WHM)
and aggregates errors. Verified end-to-end: a fresh scaffolded zone
with --build-woc yields 256/256 chunks loaded, 32768 walkable
triangles, validate-all PASSED. Synthesized WOC with 0xFF flags
correctly fails with 'unknown flag bits 0xFF' and exit 1.
2026-05-06 11:58:20 -07:00
|
|
|
|
feat(editor): add standalone world editor (rough/WIP)
Standalone wowee_editor tool for creating custom WoW zones.
This is a rough initial implementation — many features work but
M2/WMO rendering still has issues (frame sync, texture layout
transitions) and needs further polish.
Terrain:
- Create new blank terrain with 10 biome types (Grassland, Forest,
Jungle, Desert, Barrens, Snow, Swamp, Rocky, Beach, Volcanic)
- Load existing ADT tiles from extracted game data
- Sculpt brushes: Raise, Lower, Smooth, Flatten, Level
- Chunk edge stitching prevents seams between tiles
- Undo/redo (100-deep stack, Ctrl+Z/Ctrl+Shift+Z)
- Save to WoW ADT/WDT format
Texture Painting:
- Paint/Erase/Replace Base modes
- Full tileset texture browser (1285 textures from manifest)
- Per-zone directory filtering and search
- Alpha map editing with 4-layer limit (auto-replaces weakest)
Object Placement:
- M2 and WMO model placement with full manifest browser (11k M2s, 2k WMOs)
- M2Renderer + WMORenderer integrated (loads .skin files for WotLK)
- Ghost preview follows cursor before placing
- Ctrl+click selection, right-click context menu
- Transform gizmo (Move/Rotate/Scale with axis constraints)
- Position/rotation/scale editing in properties panel
NPC/Monster System:
- 631 creature presets scanned from manifest, categorized
(Critters, Beasts, Humanoids, Undead, Demons, etc.)
- Stats editor: level, health, mana, damage, armor, faction
- Behavior: Stationary, Patrol, Wander, Scripted
- Aggro/leash radius, respawn time, flags (hostile/vendor/etc.)
- Save creature spawns to JSON
Water:
- Place water at configurable height per chunk
- Liquid types: Water, Ocean, Magma, Slime
- Rendered as translucent colored quads
- Saved in ADT MH2O format
Infrastructure:
- Free-fly camera (WASD/QE, right-drag look, scroll speed)
- 5-mode toolbar: Sculpt | Paint | Objects | Water | NPCs
- Asset browser indexes full manifest on startup
- Editor water/marker shaders (pos+color vertex format)
- forceNoCull added to M2Renderer for editor use
- AssetManifest::getEntries() and AssetManager::getManifest() exposed
Known issues:
- M2/WMO rendering may not display on first placement (frame index
sync between update/render was misaligned — now fixed but untested
end-to-end)
- Validation layer errors on shutdown (resource cleanup ordering)
- Object placement on steep terrain can miss raycast
- No undo for texture painting or object placement yet
2026-05-05 03:47:03 -07:00
|
|
|
|
|
|
|
|
int main(int argc, char* argv[]) {
|
|
|
|
|
std::string dataPath;
|
|
|
|
|
std::string adtMap;
|
|
|
|
|
int adtX = -1, adtY = -1;
|
|
|
|
|
|
2026-05-06 08:08:05 -07:00
|
|
|
// Detect non-GUI options that are missing their argument and bail out
|
|
|
|
|
// with a helpful message instead of silently dropping into the GUI.
|
|
|
|
|
for (int i = 1; i < argc; i++) {
|
2026-05-09 10:08:14 -07:00
|
|
|
for (std::size_t k = 0; k < wowee::editor::cli::kArgRequiredSize; ++k) {
|
|
|
|
|
const char* opt = wowee::editor::cli::kArgRequired[k];
|
2026-05-06 08:08:05 -07:00
|
|
|
if (std::strcmp(argv[i], opt) == 0 && i + 1 >= argc) {
|
|
|
|
|
std::fprintf(stderr, "%s requires an argument\n", opt);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (std::strcmp(argv[i], "--adt") == 0 && i + 3 >= argc) {
|
|
|
|
|
std::fprintf(stderr, "--adt requires <map> <x> <y>\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2026-05-06 12:10:22 -07:00
|
|
|
if (std::strcmp(argv[i], "--diff-zone") == 0 && i + 2 >= argc) {
|
|
|
|
|
std::fprintf(stderr,
|
|
|
|
|
"--diff-zone requires <zoneA> <zoneB>\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2026-05-06 13:57:25 -07:00
|
|
|
if (std::strcmp(argv[i], "--diff-glb") == 0 && i + 2 >= argc) {
|
|
|
|
|
std::fprintf(stderr,
|
|
|
|
|
"--diff-glb requires <a.glb> <b.glb>\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2026-05-06 14:13:07 -07:00
|
|
|
if (std::strcmp(argv[i], "--diff-wom") == 0 && i + 2 >= argc) {
|
|
|
|
|
std::fprintf(stderr,
|
|
|
|
|
"--diff-wom requires <a-base> <b-base>\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2026-05-06 14:25:40 -07:00
|
|
|
if (std::strcmp(argv[i], "--diff-wob") == 0 && i + 2 >= argc) {
|
|
|
|
|
std::fprintf(stderr,
|
|
|
|
|
"--diff-wob requires <a-base> <b-base>\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
feat(editor): add --diff-whm and --diff-woc completing the open-format diff suite
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.
2026-05-06 14:35:03 -07:00
|
|
|
if (std::strcmp(argv[i], "--diff-whm") == 0 && i + 2 >= argc) {
|
|
|
|
|
std::fprintf(stderr,
|
|
|
|
|
"--diff-whm requires <a-base> <b-base>\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (std::strcmp(argv[i], "--diff-woc") == 0 && i + 2 >= argc) {
|
|
|
|
|
std::fprintf(stderr,
|
|
|
|
|
"--diff-woc requires <a.woc> <b.woc>\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2026-05-06 14:41:32 -07:00
|
|
|
if (std::strcmp(argv[i], "--diff-jsondbc") == 0 && i + 2 >= argc) {
|
|
|
|
|
std::fprintf(stderr,
|
|
|
|
|
"--diff-jsondbc requires <a.json> <b.json>\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2026-05-06 15:25:18 -07:00
|
|
|
if (std::strcmp(argv[i], "--diff-extract") == 0 && i + 2 >= argc) {
|
|
|
|
|
std::fprintf(stderr,
|
|
|
|
|
"--diff-extract requires <dirA> <dirB>\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2026-05-06 16:32:55 -07:00
|
|
|
if (std::strcmp(argv[i], "--diff-checksum") == 0 && i + 2 >= argc) {
|
|
|
|
|
std::fprintf(stderr,
|
|
|
|
|
"--diff-checksum requires <a.sha256> <b.sha256>\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2026-05-06 08:29:21 -07:00
|
|
|
if (std::strcmp(argv[i], "--diff-wcp") == 0 && i + 2 >= argc) {
|
|
|
|
|
std::fprintf(stderr, "--diff-wcp requires two paths\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2026-05-06 11:35:07 -07:00
|
|
|
if (std::strcmp(argv[i], "--add-creature") == 0 && i + 5 >= argc) {
|
|
|
|
|
std::fprintf(stderr,
|
|
|
|
|
"--add-creature requires <zoneDir> <name> <x> <y> <z>\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2026-05-06 11:37:10 -07:00
|
|
|
if (std::strcmp(argv[i], "--add-object") == 0 && i + 6 >= argc) {
|
|
|
|
|
std::fprintf(stderr,
|
|
|
|
|
"--add-object requires <zoneDir> <m2|wmo> <gamePath> <x> <y> <z>\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2026-05-06 11:41:11 -07:00
|
|
|
if (std::strcmp(argv[i], "--add-quest") == 0 && i + 2 >= argc) {
|
|
|
|
|
std::fprintf(stderr,
|
|
|
|
|
"--add-quest requires <zoneDir> <title>\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2026-05-06 12:12:06 -07:00
|
|
|
if (std::strcmp(argv[i], "--add-quest-objective") == 0 && i + 4 >= argc) {
|
|
|
|
|
std::fprintf(stderr,
|
|
|
|
|
"--add-quest-objective requires <zoneDir> <questIdx> <type> <targetName>\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2026-05-06 12:35:10 -07:00
|
|
|
if (std::strcmp(argv[i], "--remove-quest-objective") == 0 && i + 3 >= argc) {
|
|
|
|
|
std::fprintf(stderr,
|
|
|
|
|
"--remove-quest-objective requires <zoneDir> <questIdx> <objIdx>\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2026-05-06 12:53:23 -07:00
|
|
|
if (std::strcmp(argv[i], "--clone-quest") == 0 && i + 2 >= argc) {
|
|
|
|
|
std::fprintf(stderr,
|
|
|
|
|
"--clone-quest requires <zoneDir> <questIdx>\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2026-05-06 12:57:31 -07:00
|
|
|
if (std::strcmp(argv[i], "--clone-creature") == 0 && i + 2 >= argc) {
|
|
|
|
|
std::fprintf(stderr,
|
|
|
|
|
"--clone-creature requires <zoneDir> <idx>\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2026-05-06 13:10:25 -07:00
|
|
|
if (std::strcmp(argv[i], "--clone-object") == 0 && i + 2 >= argc) {
|
|
|
|
|
std::fprintf(stderr,
|
|
|
|
|
"--clone-object requires <zoneDir> <idx>\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2026-05-06 12:18:20 -07:00
|
|
|
if (std::strcmp(argv[i], "--add-quest-reward-item") == 0 && i + 3 >= argc) {
|
|
|
|
|
std::fprintf(stderr,
|
|
|
|
|
"--add-quest-reward-item requires <zoneDir> <questIdx> <itemPath>\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (std::strcmp(argv[i], "--set-quest-reward") == 0 && i + 2 >= argc) {
|
|
|
|
|
std::fprintf(stderr,
|
|
|
|
|
"--set-quest-reward requires <zoneDir> <questIdx> [--xp N] [--gold N] [--silver N] [--copper N]\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2026-05-06 12:33:32 -07:00
|
|
|
if (std::strcmp(argv[i], "--add-tile") == 0 && i + 3 >= argc) {
|
|
|
|
|
std::fprintf(stderr,
|
|
|
|
|
"--add-tile requires <zoneDir> <tx> <ty>\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2026-05-06 12:40:19 -07:00
|
|
|
if (std::strcmp(argv[i], "--remove-tile") == 0 && i + 3 >= argc) {
|
|
|
|
|
std::fprintf(stderr,
|
|
|
|
|
"--remove-tile requires <zoneDir> <tx> <ty>\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
feat(editor): add --copy-zone CLI for templating zones
Duplicate an existing zone to a new slug:
wowee_editor --copy-zone custom_zones/Original "My New Zone"
Workflow this enables: scaffold one base zone, populate it with
creatures/objects/quests, then copy-zone N times to create variants
without re-scaffolding each. Designers can template a 'forest base'
zone and stamp it into Dark Forest, Frozen Forest, etc.
What it does:
- Recursive copy preserves any subdirs (e.g. data/ for DBC sidecars)
- Reads source slug from zone.json (not the dir name) to know what
prefix to rewrite — handles users who renamed dirs without
touching the manifest
- Renames slug-prefixed files (Original_28_30.whm -> NewSlug_28_30.whm,
matches both _-suffixed and .-suffixed forms)
- Saves a fresh zone.json via ZoneManifest::save which rebuilds the
files-block from mapName, so the manifest references the renamed
files correctly
Verified end-to-end: scaffolded Original, added creature + quest,
copied to 'My New Zone'. Result: 2 files renamed, zone.json
mapName/displayName/files all updated, creatures.json + quests.json
copied verbatim.
2026-05-06 11:44:31 -07:00
|
|
|
if (std::strcmp(argv[i], "--copy-zone") == 0 && i + 2 >= argc) {
|
|
|
|
|
std::fprintf(stderr,
|
|
|
|
|
"--copy-zone requires <srcDir> <newName>\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2026-05-06 12:24:36 -07:00
|
|
|
if (std::strcmp(argv[i], "--rename-zone") == 0 && i + 2 >= argc) {
|
|
|
|
|
std::fprintf(stderr,
|
|
|
|
|
"--rename-zone requires <srcDir> <newName>\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2026-05-06 12:01:52 -07:00
|
|
|
for (const char* opt : {"--remove-creature", "--remove-object",
|
|
|
|
|
"--remove-quest"}) {
|
|
|
|
|
if (std::strcmp(argv[i], opt) == 0 && i + 2 >= argc) {
|
|
|
|
|
std::fprintf(stderr, "%s requires <zoneDir> <index>\n", opt);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-05-06 08:08:05 -07:00
|
|
|
}
|
|
|
|
|
|
feat(editor): add standalone world editor (rough/WIP)
Standalone wowee_editor tool for creating custom WoW zones.
This is a rough initial implementation — many features work but
M2/WMO rendering still has issues (frame sync, texture layout
transitions) and needs further polish.
Terrain:
- Create new blank terrain with 10 biome types (Grassland, Forest,
Jungle, Desert, Barrens, Snow, Swamp, Rocky, Beach, Volcanic)
- Load existing ADT tiles from extracted game data
- Sculpt brushes: Raise, Lower, Smooth, Flatten, Level
- Chunk edge stitching prevents seams between tiles
- Undo/redo (100-deep stack, Ctrl+Z/Ctrl+Shift+Z)
- Save to WoW ADT/WDT format
Texture Painting:
- Paint/Erase/Replace Base modes
- Full tileset texture browser (1285 textures from manifest)
- Per-zone directory filtering and search
- Alpha map editing with 4-layer limit (auto-replaces weakest)
Object Placement:
- M2 and WMO model placement with full manifest browser (11k M2s, 2k WMOs)
- M2Renderer + WMORenderer integrated (loads .skin files for WotLK)
- Ghost preview follows cursor before placing
- Ctrl+click selection, right-click context menu
- Transform gizmo (Move/Rotate/Scale with axis constraints)
- Position/rotation/scale editing in properties panel
NPC/Monster System:
- 631 creature presets scanned from manifest, categorized
(Critters, Beasts, Humanoids, Undead, Demons, etc.)
- Stats editor: level, health, mana, damage, armor, faction
- Behavior: Stationary, Patrol, Wander, Scripted
- Aggro/leash radius, respawn time, flags (hostile/vendor/etc.)
- Save creature spawns to JSON
Water:
- Place water at configurable height per chunk
- Liquid types: Water, Ocean, Magma, Slime
- Rendered as translucent colored quads
- Saved in ADT MH2O format
Infrastructure:
- Free-fly camera (WASD/QE, right-drag look, scroll speed)
- 5-mode toolbar: Sculpt | Paint | Objects | Water | NPCs
- Asset browser indexes full manifest on startup
- Editor water/marker shaders (pos+color vertex format)
- forceNoCull added to M2Renderer for editor use
- AssetManifest::getEntries() and AssetManager::getManifest() exposed
Known issues:
- M2/WMO rendering may not display on first placement (frame index
sync between update/render was misaligned — now fixed but untested
end-to-end)
- Validation layer errors on shutdown (resource cleanup ordering)
- Object placement on steep terrain can miss raycast
- No undo for texture painting or object placement yet
2026-05-05 03:47:03 -07:00
|
|
|
for (int i = 1; i < argc; i++) {
|
2026-05-09 10:15:51 -07:00
|
|
|
// CLI handlers live in cli_dispatch.cpp's table-driven
|
|
|
|
|
// dispatcher. handleConvertSingle is the one outlier
|
|
|
|
|
// because it needs dataPath threaded in; everything else
|
|
|
|
|
// goes through tryDispatchAll. Either return path captures
|
|
|
|
|
// the handler's exit code via outRc.
|
|
|
|
|
int outRc = 0;
|
|
|
|
|
if (wowee::editor::cli::handleConvertSingle(i, argc, argv,
|
|
|
|
|
dataPath, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
|
|
|
|
if (wowee::editor::cli::tryDispatchAll(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
|
|
|
|
// GUI-state args don't return — they're absorbed and
|
|
|
|
|
// applied to the EditorApp after argv parsing finishes.
|
feat(editor): add standalone world editor (rough/WIP)
Standalone wowee_editor tool for creating custom WoW zones.
This is a rough initial implementation — many features work but
M2/WMO rendering still has issues (frame sync, texture layout
transitions) and needs further polish.
Terrain:
- Create new blank terrain with 10 biome types (Grassland, Forest,
Jungle, Desert, Barrens, Snow, Swamp, Rocky, Beach, Volcanic)
- Load existing ADT tiles from extracted game data
- Sculpt brushes: Raise, Lower, Smooth, Flatten, Level
- Chunk edge stitching prevents seams between tiles
- Undo/redo (100-deep stack, Ctrl+Z/Ctrl+Shift+Z)
- Save to WoW ADT/WDT format
Texture Painting:
- Paint/Erase/Replace Base modes
- Full tileset texture browser (1285 textures from manifest)
- Per-zone directory filtering and search
- Alpha map editing with 4-layer limit (auto-replaces weakest)
Object Placement:
- M2 and WMO model placement with full manifest browser (11k M2s, 2k WMOs)
- M2Renderer + WMORenderer integrated (loads .skin files for WotLK)
- Ghost preview follows cursor before placing
- Ctrl+click selection, right-click context menu
- Transform gizmo (Move/Rotate/Scale with axis constraints)
- Position/rotation/scale editing in properties panel
NPC/Monster System:
- 631 creature presets scanned from manifest, categorized
(Critters, Beasts, Humanoids, Undead, Demons, etc.)
- Stats editor: level, health, mana, damage, armor, faction
- Behavior: Stationary, Patrol, Wander, Scripted
- Aggro/leash radius, respawn time, flags (hostile/vendor/etc.)
- Save creature spawns to JSON
Water:
- Place water at configurable height per chunk
- Liquid types: Water, Ocean, Magma, Slime
- Rendered as translucent colored quads
- Saved in ADT MH2O format
Infrastructure:
- Free-fly camera (WASD/QE, right-drag look, scroll speed)
- 5-mode toolbar: Sculpt | Paint | Objects | Water | NPCs
- Asset browser indexes full manifest on startup
- Editor water/marker shaders (pos+color vertex format)
- forceNoCull added to M2Renderer for editor use
- AssetManifest::getEntries() and AssetManager::getManifest() exposed
Known issues:
- M2/WMO rendering may not display on first placement (frame index
sync between update/render was misaligned — now fixed but untested
end-to-end)
- Validation layer errors on shutdown (resource cleanup ordering)
- Object placement on steep terrain can miss raycast
- No undo for texture painting or object placement yet
2026-05-05 03:47:03 -07:00
|
|
|
if (std::strcmp(argv[i], "--data") == 0 && i + 1 < argc) {
|
|
|
|
|
dataPath = argv[++i];
|
|
|
|
|
} else if (std::strcmp(argv[i], "--adt") == 0 && i + 3 < argc) {
|
|
|
|
|
adtMap = argv[++i];
|
|
|
|
|
adtX = std::atoi(argv[++i]);
|
|
|
|
|
adtY = std::atoi(argv[++i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-05 12:41:19 -07:00
|
|
|
|
feat(editor): add standalone world editor (rough/WIP)
Standalone wowee_editor tool for creating custom WoW zones.
This is a rough initial implementation — many features work but
M2/WMO rendering still has issues (frame sync, texture layout
transitions) and needs further polish.
Terrain:
- Create new blank terrain with 10 biome types (Grassland, Forest,
Jungle, Desert, Barrens, Snow, Swamp, Rocky, Beach, Volcanic)
- Load existing ADT tiles from extracted game data
- Sculpt brushes: Raise, Lower, Smooth, Flatten, Level
- Chunk edge stitching prevents seams between tiles
- Undo/redo (100-deep stack, Ctrl+Z/Ctrl+Shift+Z)
- Save to WoW ADT/WDT format
Texture Painting:
- Paint/Erase/Replace Base modes
- Full tileset texture browser (1285 textures from manifest)
- Per-zone directory filtering and search
- Alpha map editing with 4-layer limit (auto-replaces weakest)
Object Placement:
- M2 and WMO model placement with full manifest browser (11k M2s, 2k WMOs)
- M2Renderer + WMORenderer integrated (loads .skin files for WotLK)
- Ghost preview follows cursor before placing
- Ctrl+click selection, right-click context menu
- Transform gizmo (Move/Rotate/Scale with axis constraints)
- Position/rotation/scale editing in properties panel
NPC/Monster System:
- 631 creature presets scanned from manifest, categorized
(Critters, Beasts, Humanoids, Undead, Demons, etc.)
- Stats editor: level, health, mana, damage, armor, faction
- Behavior: Stationary, Patrol, Wander, Scripted
- Aggro/leash radius, respawn time, flags (hostile/vendor/etc.)
- Save creature spawns to JSON
Water:
- Place water at configurable height per chunk
- Liquid types: Water, Ocean, Magma, Slime
- Rendered as translucent colored quads
- Saved in ADT MH2O format
Infrastructure:
- Free-fly camera (WASD/QE, right-drag look, scroll speed)
- 5-mode toolbar: Sculpt | Paint | Objects | Water | NPCs
- Asset browser indexes full manifest on startup
- Editor water/marker shaders (pos+color vertex format)
- forceNoCull added to M2Renderer for editor use
- AssetManifest::getEntries() and AssetManager::getManifest() exposed
Known issues:
- M2/WMO rendering may not display on first placement (frame index
sync between update/render was misaligned — now fixed but untested
end-to-end)
- Validation layer errors on shutdown (resource cleanup ordering)
- Object placement on steep terrain can miss raycast
- No undo for texture painting or object placement yet
2026-05-05 03:47:03 -07:00
|
|
|
if (dataPath.empty()) {
|
|
|
|
|
dataPath = "Data";
|
|
|
|
|
LOG_INFO("No --data path specified, using default: ", dataPath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wowee::editor::EditorApp app;
|
|
|
|
|
if (!app.initialize(dataPath)) {
|
|
|
|
|
LOG_ERROR("Failed to initialize editor");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!adtMap.empty()) {
|
|
|
|
|
app.loadADT(adtMap, adtX, adtY);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
app.run();
|
|
|
|
|
app.shutdown();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|