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"
|
refactor(editor): extract gen-audio-* handlers into cli_gen_audio.cpp
main.cpp had grown past 28k lines, with each new procedural-
generation command adding 100-200 lines to the inline if/else
dispatch chain. This commit starts breaking that up by moving
the four audio-related handlers (--gen-audio-tone, -noise,
-sweep, --gen-zone-audio-pack) into their own translation unit.
Pattern established here for future family extractions:
- Family lives in cli_<family>.{hpp,cpp}
- Single dispatch entry point: bool handle<Family>(int& i, int argc,
char** argv, int& outRc) — true if matched (writes outRc), false
to fall through.
- main.cpp's argv loop calls each family's dispatcher first and
returns its outRc on match, before the legacy in-line chain.
Side-benefit: consolidated the duplicated 25-line WAV header
writer + 5ms attack/release envelope into shared helpers
(writeWavMono16, applyEdgeEnvelope) at the top of the new file.
main.cpp drops from 28,943 → 28,329 lines (-614). Audio family
is fully self-contained (~440 lines), behavior unchanged
(verified by re-running tone/noise/sweep + zone-audio-pack).
2026-05-08 16:19:30 -07:00
|
|
|
#include "cli_gen_audio.hpp"
|
2026-05-08 16:46:14 -07:00
|
|
|
#include "cli_zone_packs.hpp"
|
2026-05-08 17:12:10 -07:00
|
|
|
#include "cli_audits.hpp"
|
2026-05-08 17:36:10 -07:00
|
|
|
#include "cli_readmes.hpp"
|
2026-05-08 18:24:01 -07:00
|
|
|
#include "cli_zone_inventory.hpp"
|
2026-05-08 18:47:06 -07:00
|
|
|
#include "cli_project_inventory.hpp"
|
refactor(editor): extract printUsage into cli_help.cpp
Pulls the 597-line block of printf calls that emits the --help
text out of main.cpp into its own translation unit. printUsage
is the longest single function in main.cpp by far and was pure
boilerplate (no logic, just a flat list of help lines).
Function moved verbatim to wowee::editor::cli::printUsage; all
6 in-tree callers (--list-commands, --info-cli-stats,
--info-cli-categories, --info-cli-help, --validate-cli-help,
and the bare --help/-h handler) updated to the namespaced name.
The CLI-meta commands continue to capture printUsage's stdout
the same way, so behavior is identical (verified by re-running
--validate-cli-help, --info-cli-stats, --list-commands).
main.cpp drops 26,650 → 26,286 lines (-364 net; -597 from the
removal, +233 from the include and namespace-prefixing the
six call sites... wait, no, +6). Actually main.cpp net delta
matches the body extraction.
2026-05-08 20:12:15 -07:00
|
|
|
#include "cli_help.hpp"
|
2026-05-08 20:59:02 -07:00
|
|
|
#include "cli_gen_texture.hpp"
|
refactor(editor): extract 12 composite mesh primitives into cli_gen_mesh.cpp
Moves the recently-added composite-prop mesh handlers (rock,
pillar, bridge, tower, house, fountain, statue, altar, portal,
archway, barrel, chest) into their own translation unit. These
12 handlers were the most contiguous block of similar-shaped
mesh code in main.cpp.
Other mesh handlers (--gen-mesh dispatcher, fence, tree, grid,
stairs, disc, tube, capsule, arch, pyramid, from-heightmap,
textured) still live in main.cpp and may be migrated in
subsequent batches.
main.cpp drops 24,270 → 22,681 lines (-1,589). Behavior
verified by re-running rock/chest/archway/fountain.
2026-05-08 22:19:41 -07:00
|
|
|
#include "cli_gen_mesh.hpp"
|
2026-05-09 00:04:27 -07:00
|
|
|
#include "cli_mesh_io.hpp"
|
2026-05-09 00:36:51 -07:00
|
|
|
#include "cli_mesh_edit.hpp"
|
2026-05-09 01:18:09 -07:00
|
|
|
#include "cli_wom_info.hpp"
|
2026-05-09 01:57:37 -07:00
|
|
|
#include "cli_format_validate.hpp"
|
2026-05-09 02:25:05 -07:00
|
|
|
#include "cli_convert.hpp"
|
2026-05-09 02:48:58 -07:00
|
|
|
#include "cli_format_info.hpp"
|
2026-05-09 03:12:09 -07:00
|
|
|
#include "cli_pack.hpp"
|
2026-05-09 03:33:40 -07:00
|
|
|
#include "cli_content_info.hpp"
|
2026-05-09 03:52:44 -07:00
|
|
|
#include "cli_zone_info.hpp"
|
2026-05-09 04:14:32 -07:00
|
|
|
#include "cli_data_tree.hpp"
|
2026-05-09 04:35:08 -07:00
|
|
|
#include "cli_diff.hpp"
|
2026-05-09 05:05:22 -07:00
|
|
|
#include "cli_spawn_audit.hpp"
|
2026-05-09 05:19:04 -07:00
|
|
|
#include "cli_items.hpp"
|
2026-05-09 05:32:27 -07:00
|
|
|
#include "cli_extract_info.hpp"
|
2026-05-09 05:45:00 -07:00
|
|
|
#include "cli_export.hpp"
|
2026-05-09 05:57:25 -07:00
|
|
|
#include "cli_bake.hpp"
|
2026-05-09 06:13:41 -07:00
|
|
|
#include "cli_migrate.hpp"
|
2026-05-09 06:25:04 -07:00
|
|
|
#include "cli_convert_single.hpp"
|
refactor(editor): extract interop --validate-* into cli_validate_interop.cpp
Moves the four structural validators for INTEROP file formats
(--validate-stl, --validate-png, --validate-blp, --validate-jsondbc)
out of main.cpp into a new cli_validate_interop.{hpp,cpp} module.
These check files coming in/out of wowee from third-party tools,
distinct from cli_format_validate.cpp which validates the native
open formats (WOM, WOB, WOC, WHM).
main.cpp shrinks by 524 lines (10,644 to 10,121). Each validator
preserves its --json output mode for machine-readable reports.
2026-05-09 06:36:02 -07:00
|
|
|
#include "cli_validate_interop.hpp"
|
2026-05-09 06:46:02 -07:00
|
|
|
#include "cli_glb_inspect.hpp"
|
refactor(editor): extract WOM <-> OBJ/GLB/STL into cli_wom_io.cpp
Moves the four WOM interchange-format handlers (--export-obj,
--export-glb, --export-stl, --import-stl) out of main.cpp into
a new cli_wom_io.{hpp,cpp} module. WOM is our open M2
replacement; these are the bridge that lets it round-trip
through every external 3D tool — Blender, Three.js, slicers,
CAD packages — so the open format is actually useful.
main.cpp shrinks by 467 lines (9,464 to 8,997). The five WOB
and WHM exporters (--export-wob-glb, --export-whm-glb, etc.)
remain inline for a follow-up extraction.
2026-05-09 06:55:00 -07:00
|
|
|
#include "cli_wom_io.hpp"
|
refactor(editor): extract WOB/WHM/WOC IO into cli_world_io.cpp
Moves all six world-asset interchange handlers (--export-wob-glb,
--export-wob-obj, --import-wob-obj, --export-whm-glb,
--export-whm-obj, --export-woc-obj) out of main.cpp into a new
cli_world_io.{hpp,cpp} module. WOB / WHM / WOC are our open
replacements for proprietary WMO / ADT-heightmap / ADT-collision
data; these are the bridge that lets the open formats round-trip
through Blender, MeshLab, Three.js, and the rest of the standard
3D toolchain.
main.cpp shrinks by 858 lines (8,997 to 8,140). The single-mesh
--import-obj handler stays inline for now -- it shadow-mirrors
cli_wom_io's --import-stl semantics and will move there next.
2026-05-09 07:03:14 -07:00
|
|
|
#include "cli_world_io.hpp"
|
refactor(editor): extract --info-{zone,project}-tree into cli_info_tree.cpp
Moves the two tree-style content browser handlers
(--info-zone-tree, --info-project-tree) out of main.cpp into
a new cli_info_tree.{hpp,cpp} module. Both render
Unix-`tree`-style hierarchical views — one drilling into a
single zone (manifest, tiles, creatures, objects, quests,
files) and one giving a bird's-eye view of every zone in a
project with bake/viewer status.
main.cpp shrinks by 201 lines (8,140 to 7,939). The remaining
info-zone/-project-* pairs (bytes, extents, water, density,
audio) form the next natural extraction batch.
2026-05-09 07:10:12 -07:00
|
|
|
#include "cli_info_tree.hpp"
|
2026-05-09 07:16:27 -07:00
|
|
|
#include "cli_info_bytes.hpp"
|
2026-05-09 07:22:06 -07:00
|
|
|
#include "cli_info_extents.hpp"
|
2026-05-09 07:28:15 -07:00
|
|
|
#include "cli_info_water.hpp"
|
2026-05-09 07:33:40 -07:00
|
|
|
#include "cli_info_density.hpp"
|
2026-05-09 07:38:36 -07:00
|
|
|
#include "cli_info_audio.hpp"
|
2026-05-09 07:44:57 -07:00
|
|
|
#include "cli_world_info.hpp"
|
2026-05-09 07:56:16 -07:00
|
|
|
#include "cli_quest_objective.hpp"
|
2026-05-09 08:01:28 -07:00
|
|
|
#include "cli_quest_reward.hpp"
|
2026-05-09 08:06:20 -07:00
|
|
|
#include "cli_clone.hpp"
|
2026-05-09 08:11:50 -07:00
|
|
|
#include "cli_remove.hpp"
|
2026-05-09 08:16:52 -07:00
|
|
|
#include "cli_add.hpp"
|
2026-05-09 08:22:06 -07:00
|
|
|
#include "cli_random.hpp"
|
2026-05-09 08:26:52 -07:00
|
|
|
#include "cli_items_export.hpp"
|
2026-05-09 08:33:59 -07:00
|
|
|
#include "cli_items_mutate.hpp"
|
2026-05-09 08:42:49 -07:00
|
|
|
#include "cli_zone_create.hpp"
|
2026-05-09 08:47:32 -07:00
|
|
|
#include "cli_tiles.hpp"
|
2026-05-09 08:52:19 -07:00
|
|
|
#include "cli_zone_mgmt.hpp"
|
2026-05-09 08:56:47 -07:00
|
|
|
#include "cli_strip.hpp"
|
2026-05-09 08:59:51 -07:00
|
|
|
#include "cli_repair.hpp"
|
2026-05-09 09:04:44 -07:00
|
|
|
#include "cli_makefile.hpp"
|
2026-05-09 09:09:06 -07:00
|
|
|
#include "cli_zone_list.hpp"
|
2026-05-09 09:14:01 -07:00
|
|
|
#include "cli_tilemap.hpp"
|
2026-05-09 09:16:26 -07:00
|
|
|
#include "cli_deps.hpp"
|
2026-05-09 09:23:23 -07:00
|
|
|
#include "cli_for_each.hpp"
|
2026-05-09 09:25:41 -07:00
|
|
|
#include "cli_check.hpp"
|
refactor(editor): extract CLI introspection handlers into cli_introspect.cpp
Moves five self-discovery handlers (--list-commands,
--info-cli-stats, --info-cli-categories, --info-cli-help,
--gen-completion) out of main.cpp into a new
cli_introspect.{hpp,cpp} module. All five auto-discover
commands by parsing printUsage's stdout via tmpfile capture,
so the surface stays self-describing as new flags are added.
Useful for shell completion scripts that re-exec the binary
at completion time, IDE plugins, and 'is there a flag for X?'
search workflows. main.cpp shrinks by 276 lines (2,298 to
2,022). --validate-cli-help stays inline because it needs
direct access to the static-local kArgRequired array.
2026-05-09 09:31:31 -07:00
|
|
|
#include "cli_introspect.hpp"
|
2026-05-09 09:34:19 -07:00
|
|
|
#include "cli_texture_helpers.hpp"
|
refactor(editor): extract WOM/WOB info handlers into cli_mesh_info.cpp
Moves three mesh-aggregate info handlers (--info-zone-models-total,
--list-zone-meshes-detail, --info-mesh) out of main.cpp into a
new cli_mesh_info.{hpp,cpp} module. The first aggregates
WOM/WOB stats across a zone; the second tabulates per-mesh
metrics sorted by triangle count; the third dumps single-WOM
detail (bounds, version, batches, bones, animations, textures).
main.cpp shrinks by 285 lines (1,826 to 1,541). All three
preserve --json output for capacity-planning pipelines.
2026-05-09 09:40:03 -07:00
|
|
|
#include "cli_mesh_info.hpp"
|
2026-05-09 09:44:52 -07:00
|
|
|
#include "cli_zone_data.hpp"
|
2026-05-09 09:54:17 -07:00
|
|
|
#include "cli_project_actions.hpp"
|
2026-05-09 10:01:33 -07:00
|
|
|
#include "cli_zone_export.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++) {
|
refactor(editor): extract gen-audio-* handlers into cli_gen_audio.cpp
main.cpp had grown past 28k lines, with each new procedural-
generation command adding 100-200 lines to the inline if/else
dispatch chain. This commit starts breaking that up by moving
the four audio-related handlers (--gen-audio-tone, -noise,
-sweep, --gen-zone-audio-pack) into their own translation unit.
Pattern established here for future family extractions:
- Family lives in cli_<family>.{hpp,cpp}
- Single dispatch entry point: bool handle<Family>(int& i, int argc,
char** argv, int& outRc) — true if matched (writes outRc), false
to fall through.
- main.cpp's argv loop calls each family's dispatcher first and
returns its outRc on match, before the legacy in-line chain.
Side-benefit: consolidated the duplicated 25-line WAV header
writer + 5ms attack/release envelope into shared helpers
(writeWavMono16, applyEdgeEnvelope) at the top of the new file.
main.cpp drops from 28,943 → 28,329 lines (-614). Audio family
is fully self-contained (~440 lines), behavior unchanged
(verified by re-running tone/noise/sweep + zone-audio-pack).
2026-05-08 16:19:30 -07:00
|
|
|
// Modular handler families: extracted from the in-line if/else
|
|
|
|
|
// chain below to keep main.cpp from sprawling further. Each
|
|
|
|
|
// family lives in its own .cpp; if it matches argv[i] it
|
|
|
|
|
// sets outRc and we exit. Otherwise fall through to the
|
|
|
|
|
// legacy in-line dispatch.
|
|
|
|
|
{
|
|
|
|
|
int outRc = 0;
|
|
|
|
|
if (wowee::editor::cli::handleGenAudio(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-08 16:46:14 -07:00
|
|
|
if (wowee::editor::cli::handleZonePacks(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-08 17:12:10 -07:00
|
|
|
if (wowee::editor::cli::handleAudits(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-08 17:36:10 -07:00
|
|
|
if (wowee::editor::cli::handleReadmes(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-08 18:24:01 -07:00
|
|
|
if (wowee::editor::cli::handleZoneInventory(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-08 18:47:06 -07:00
|
|
|
if (wowee::editor::cli::handleProjectInventory(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-08 20:59:02 -07:00
|
|
|
if (wowee::editor::cli::handleGenTexture(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
refactor(editor): extract 12 composite mesh primitives into cli_gen_mesh.cpp
Moves the recently-added composite-prop mesh handlers (rock,
pillar, bridge, tower, house, fountain, statue, altar, portal,
archway, barrel, chest) into their own translation unit. These
12 handlers were the most contiguous block of similar-shaped
mesh code in main.cpp.
Other mesh handlers (--gen-mesh dispatcher, fence, tree, grid,
stairs, disc, tube, capsule, arch, pyramid, from-heightmap,
textured) still live in main.cpp and may be migrated in
subsequent batches.
main.cpp drops 24,270 → 22,681 lines (-1,589). Behavior
verified by re-running rock/chest/archway/fountain.
2026-05-08 22:19:41 -07:00
|
|
|
if (wowee::editor::cli::handleGenMesh(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 00:04:27 -07:00
|
|
|
if (wowee::editor::cli::handleMeshIO(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 00:36:51 -07:00
|
|
|
if (wowee::editor::cli::handleMeshEdit(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 01:18:09 -07:00
|
|
|
if (wowee::editor::cli::handleWomInfo(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 01:57:37 -07:00
|
|
|
if (wowee::editor::cli::handleFormatValidate(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 02:25:05 -07:00
|
|
|
if (wowee::editor::cli::handleConvert(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 02:48:58 -07:00
|
|
|
if (wowee::editor::cli::handleFormatInfo(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 03:12:09 -07:00
|
|
|
if (wowee::editor::cli::handlePack(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 03:33:40 -07:00
|
|
|
if (wowee::editor::cli::handleContentInfo(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 03:52:44 -07:00
|
|
|
if (wowee::editor::cli::handleZoneInfo(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 04:14:32 -07:00
|
|
|
if (wowee::editor::cli::handleDataTree(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 04:35:08 -07:00
|
|
|
if (wowee::editor::cli::handleDiff(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 05:05:22 -07:00
|
|
|
if (wowee::editor::cli::handleSpawnAudit(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 05:19:04 -07:00
|
|
|
if (wowee::editor::cli::handleItems(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 05:32:27 -07:00
|
|
|
if (wowee::editor::cli::handleExtractInfo(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 05:45:00 -07:00
|
|
|
if (wowee::editor::cli::handleExport(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 05:57:25 -07:00
|
|
|
if (wowee::editor::cli::handleBake(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 06:13:41 -07:00
|
|
|
if (wowee::editor::cli::handleMigrate(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 06:25:04 -07:00
|
|
|
if (wowee::editor::cli::handleConvertSingle(i, argc, argv,
|
|
|
|
|
dataPath, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
refactor(editor): extract interop --validate-* into cli_validate_interop.cpp
Moves the four structural validators for INTEROP file formats
(--validate-stl, --validate-png, --validate-blp, --validate-jsondbc)
out of main.cpp into a new cli_validate_interop.{hpp,cpp} module.
These check files coming in/out of wowee from third-party tools,
distinct from cli_format_validate.cpp which validates the native
open formats (WOM, WOB, WOC, WHM).
main.cpp shrinks by 524 lines (10,644 to 10,121). Each validator
preserves its --json output mode for machine-readable reports.
2026-05-09 06:36:02 -07:00
|
|
|
if (wowee::editor::cli::handleValidateInterop(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 06:46:02 -07:00
|
|
|
if (wowee::editor::cli::handleGlbInspect(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
refactor(editor): extract WOM <-> OBJ/GLB/STL into cli_wom_io.cpp
Moves the four WOM interchange-format handlers (--export-obj,
--export-glb, --export-stl, --import-stl) out of main.cpp into
a new cli_wom_io.{hpp,cpp} module. WOM is our open M2
replacement; these are the bridge that lets it round-trip
through every external 3D tool — Blender, Three.js, slicers,
CAD packages — so the open format is actually useful.
main.cpp shrinks by 467 lines (9,464 to 8,997). The five WOB
and WHM exporters (--export-wob-glb, --export-whm-glb, etc.)
remain inline for a follow-up extraction.
2026-05-09 06:55:00 -07:00
|
|
|
if (wowee::editor::cli::handleWomIo(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
refactor(editor): extract WOB/WHM/WOC IO into cli_world_io.cpp
Moves all six world-asset interchange handlers (--export-wob-glb,
--export-wob-obj, --import-wob-obj, --export-whm-glb,
--export-whm-obj, --export-woc-obj) out of main.cpp into a new
cli_world_io.{hpp,cpp} module. WOB / WHM / WOC are our open
replacements for proprietary WMO / ADT-heightmap / ADT-collision
data; these are the bridge that lets the open formats round-trip
through Blender, MeshLab, Three.js, and the rest of the standard
3D toolchain.
main.cpp shrinks by 858 lines (8,997 to 8,140). The single-mesh
--import-obj handler stays inline for now -- it shadow-mirrors
cli_wom_io's --import-stl semantics and will move there next.
2026-05-09 07:03:14 -07:00
|
|
|
if (wowee::editor::cli::handleWorldIo(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
refactor(editor): extract --info-{zone,project}-tree into cli_info_tree.cpp
Moves the two tree-style content browser handlers
(--info-zone-tree, --info-project-tree) out of main.cpp into
a new cli_info_tree.{hpp,cpp} module. Both render
Unix-`tree`-style hierarchical views — one drilling into a
single zone (manifest, tiles, creatures, objects, quests,
files) and one giving a bird's-eye view of every zone in a
project with bake/viewer status.
main.cpp shrinks by 201 lines (8,140 to 7,939). The remaining
info-zone/-project-* pairs (bytes, extents, water, density,
audio) form the next natural extraction batch.
2026-05-09 07:10:12 -07:00
|
|
|
if (wowee::editor::cli::handleInfoTree(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 07:16:27 -07:00
|
|
|
if (wowee::editor::cli::handleInfoBytes(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 07:22:06 -07:00
|
|
|
if (wowee::editor::cli::handleInfoExtents(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 07:28:15 -07:00
|
|
|
if (wowee::editor::cli::handleInfoWater(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 07:33:40 -07:00
|
|
|
if (wowee::editor::cli::handleInfoDensity(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 07:38:36 -07:00
|
|
|
if (wowee::editor::cli::handleInfoAudio(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 07:44:57 -07:00
|
|
|
if (wowee::editor::cli::handleWorldInfo(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 07:56:16 -07:00
|
|
|
if (wowee::editor::cli::handleQuestObjective(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 08:01:28 -07:00
|
|
|
if (wowee::editor::cli::handleQuestReward(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 08:06:20 -07:00
|
|
|
if (wowee::editor::cli::handleClone(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 08:11:50 -07:00
|
|
|
if (wowee::editor::cli::handleRemove(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 08:16:52 -07:00
|
|
|
if (wowee::editor::cli::handleAdd(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 08:22:06 -07:00
|
|
|
if (wowee::editor::cli::handleRandom(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 08:26:52 -07:00
|
|
|
if (wowee::editor::cli::handleItemsExport(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 08:33:59 -07:00
|
|
|
if (wowee::editor::cli::handleItemsMutate(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 08:42:49 -07:00
|
|
|
if (wowee::editor::cli::handleZoneCreate(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 08:47:32 -07:00
|
|
|
if (wowee::editor::cli::handleTiles(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 08:52:19 -07:00
|
|
|
if (wowee::editor::cli::handleZoneMgmt(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 08:56:47 -07:00
|
|
|
if (wowee::editor::cli::handleStrip(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 08:59:51 -07:00
|
|
|
if (wowee::editor::cli::handleRepair(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 09:04:44 -07:00
|
|
|
if (wowee::editor::cli::handleMakefile(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 09:09:06 -07:00
|
|
|
if (wowee::editor::cli::handleZoneList(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 09:14:01 -07:00
|
|
|
if (wowee::editor::cli::handleTilemap(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 09:16:26 -07:00
|
|
|
if (wowee::editor::cli::handleDeps(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 09:23:23 -07:00
|
|
|
if (wowee::editor::cli::handleForEach(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 09:25:41 -07:00
|
|
|
if (wowee::editor::cli::handleCheck(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
refactor(editor): extract CLI introspection handlers into cli_introspect.cpp
Moves five self-discovery handlers (--list-commands,
--info-cli-stats, --info-cli-categories, --info-cli-help,
--gen-completion) out of main.cpp into a new
cli_introspect.{hpp,cpp} module. All five auto-discover
commands by parsing printUsage's stdout via tmpfile capture,
so the surface stays self-describing as new flags are added.
Useful for shell completion scripts that re-exec the binary
at completion time, IDE plugins, and 'is there a flag for X?'
search workflows. main.cpp shrinks by 276 lines (2,298 to
2,022). --validate-cli-help stays inline because it needs
direct access to the static-local kArgRequired array.
2026-05-09 09:31:31 -07:00
|
|
|
if (wowee::editor::cli::handleIntrospect(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 09:34:19 -07:00
|
|
|
if (wowee::editor::cli::handleTextureHelpers(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
refactor(editor): extract WOM/WOB info handlers into cli_mesh_info.cpp
Moves three mesh-aggregate info handlers (--info-zone-models-total,
--list-zone-meshes-detail, --info-mesh) out of main.cpp into a
new cli_mesh_info.{hpp,cpp} module. The first aggregates
WOM/WOB stats across a zone; the second tabulates per-mesh
metrics sorted by triangle count; the third dumps single-WOM
detail (bounds, version, batches, bones, animations, textures).
main.cpp shrinks by 285 lines (1,826 to 1,541). All three
preserve --json output for capacity-planning pipelines.
2026-05-09 09:40:03 -07:00
|
|
|
if (wowee::editor::cli::handleMeshInfo(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 09:44:52 -07:00
|
|
|
if (wowee::editor::cli::handleZoneData(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 09:54:17 -07:00
|
|
|
if (wowee::editor::cli::handleProjectActions(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
2026-05-09 10:01:33 -07:00
|
|
|
if (wowee::editor::cli::handleZoneExport(i, argc, argv, outRc)) {
|
|
|
|
|
return outRc;
|
|
|
|
|
}
|
refactor(editor): extract gen-audio-* handlers into cli_gen_audio.cpp
main.cpp had grown past 28k lines, with each new procedural-
generation command adding 100-200 lines to the inline if/else
dispatch chain. This commit starts breaking that up by moving
the four audio-related handlers (--gen-audio-tone, -noise,
-sweep, --gen-zone-audio-pack) into their own translation unit.
Pattern established here for future family extractions:
- Family lives in cli_<family>.{hpp,cpp}
- Single dispatch entry point: bool handle<Family>(int& i, int argc,
char** argv, int& outRc) — true if matched (writes outRc), false
to fall through.
- main.cpp's argv loop calls each family's dispatcher first and
returns its outRc on match, before the legacy in-line chain.
Side-benefit: consolidated the duplicated 25-line WAV header
writer + 5ms attack/release envelope into shared helpers
(writeWavMono16, applyEdgeEnvelope) at the top of the new file.
main.cpp drops from 28,943 → 28,329 lines (-614). Audio family
is fully self-contained (~440 lines), behavior unchanged
(verified by re-running tone/noise/sweep + zone-audio-pack).
2026-05-08 16:19:30 -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 (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;
|
|
|
|
|
}
|