Commit graph

3570 commits

Author SHA1 Message Date
Kelsi
22c9bc354c feat(editor): placed-object list also has name filter (parity with NPC list) 2026-05-06 02:34:41 -07:00
Kelsi
590ec6b3a3 feat(editor): NPC spawn list has name filter for fast lookup
A zone with 50+ creatures made finding a specific spawn tedious. Added
a case-insensitive name-filter input above the list, capped at 200
visible entries with a 'refine filter' hint when exceeded.
2026-05-06 02:34:05 -07:00
Kelsi
eadb6a5886 feat(woc): add WMO collision meshes to exported zone collision
WoweeCollision previously only contained terrain triangles; placed WMO
buildings had no collision in the exported zone, so players could walk
through walls. Added WoweeCollisionBuilder::addMesh() that transforms a
local-space mesh into world space with slope-based walkability flags,
and the editor's exportZone now walks every placed WMO and feeds each
group's geometry through it. Indoor vs outdoor groups are tagged via
the WMO group flag.
2026-05-06 02:33:22 -07:00
Kelsi
fdd527b373 fix(build): asset_extract tool needs extern/ in include path for nlohmann/json
asset_extract pulls in src/pipeline/dbc_loader.cpp which #includes
<nlohmann/json.hpp>, but the tool's include directories didn't list
extern/ where the header lives. Build succeeded if asset_extract was
disabled (no StormLib) but failed otherwise. Added the extern/ system
include so the tool builds wherever StormLib is found.
2026-05-06 02:30:04 -07:00
Kelsi
88c105103b fix(content-pack): validateZone accepts WOM2/WOM3 as valid WOM files
ContentPacker.validateZone only matched WOM1 magic (0x314D4F57). Any zone
exported with animated (WOM2) or multi-batch (WOM3) models was scored as
having invalid WOM files, lowering the open-format score from 7/7 to 6/7
even though everything is correct. Now accepts the WOM family.
2026-05-06 02:18:37 -07:00
Kelsi
4578bbc0d1 fix(wom): toM2 converts .png texture paths back to .blp for renderer
Same fix as WoB: M2Renderer's PNG override is keyed on .blp extension.
fromM2 writes .png paths to signal intent (PNG export pipeline), but
toM2 must convert back so the runtime engages the override and finds
the actual texture file.
2026-05-06 02:16:28 -07:00
Kelsi
aa6b692a58 fix(wob): convert .png texture paths back to .blp in toWMOModel
WMORenderer's PNG override system only triggers when the requested
texture path ends in .blp — it strips the .blp and probes for .png.
WoB stores .png paths (because fromWMO converts .blp->.png at conversion
time), so passing them straight through to the WMOModel meant the
override wasn't engaged and textures didn't load. Now converts back to
.blp so the existing override pipeline picks up the PNG file.
2026-05-06 02:15:13 -07:00
Kelsi
9d200fbe7b fix(wom): fromM2 always merges .skin file regardless of M2 isValid state
WotLK M2s store the header in .m2 but geometry in .skin. fromM2 only
loaded the skin when isValid() returned false, which it does for those
WotLK files — but missed the case where M2Loader::load happened to
populate enough that isValid() was true (older format M2s with newer
features). Now always merges skin data when present, matching the
editor's viewport loader behaviour.
2026-05-06 02:12:45 -07:00
Kelsi
49b7268dc9 feat(editor): show camera (x,y,z) in status bar
Helpful for navigation and noting positions for spawn placement, plus
diagnostic value when debugging coordinate issues. Shown only after a
terrain is loaded.
2026-05-06 02:10:50 -07:00
Kelsi
318f255918 fix(wob): emit default doodadSet so WMO renderer draws WoB doodads
WMORenderer uses doodadSets[0] to select which slice of the doodads
array to render. Without a set entry the renderer skipped every doodad
even when toWMOModel populated them. Now emits a default set named
'Set_$DefaultGlobal' covering all doodads — matches Blizzard's default
set name and convention.
2026-05-06 02:09:24 -07:00
Kelsi
f2bbc8d60f feat(wob): toWMOModel restores doodad placements (interior props)
WoB stored doodad placements but toWMOModel never reconstructed them in
the WMOModel, so converted-back buildings rendered as empty shells.
Now rebuilds doodadNames + doodads with M2 path conversion (.wom -> .m2
for the runtime that hasn't picked up WOM-aware doodad loading yet) and
euler->quaternion rotation conversion.
2026-05-06 02:07:44 -07:00
Kelsi
7c506f582a feat(editor): flyToSelected places camera with proper aim and offset
Previously just teleported camera 30u directly above the target — the user
still had to manually look down to see anything. Now positions the camera
back along the current view direction, slightly elevated, and aims it at
the selection so the target is visible immediately. Removes the round-trip
through manual rotation after every Fly To.
2026-05-06 02:04:50 -07:00
Kelsi
f1223cfc69 chore(editor): cap texture-not-found warnings at 5 with suppression count
Some checks are pending
Build / Build (arm64) (push) Waiting to run
Build / Build (x86-64) (push) Waiting to run
Build / Build (macOS arm64) (push) Waiting to run
Build / Build (windows-arm64) (push) Waiting to run
Build / Build (windows-x86-64) (push) Waiting to run
Security / CodeQL (C/C++) (push) Waiting to run
Security / Semgrep (push) Waiting to run
Security / Sanitizer Build (ASan/UBSan) (push) Waiting to run
Character body/skin textures live in CharSections-composed paths that
don't exist as standalone BLPs. Exporting a zone with many character
NPCs would spam hundreds of warnings. Now logs the first 5, suppresses
the rest, and reports the total skipped count in the summary line.
2026-05-06 02:03:30 -07:00
Kelsi
bbdd48a78a fix(adt): MODF entry was 60 bytes but parser expects 64 — write nameSet+scale tail
Each MODF entry in ADT files is 64 bytes (per MODF spec). The writer was
emitting only 60 bytes, missing the trailing nameSet(u16) + scale(u16).
The loader uses entrySize=64 to advance per record, so any saved ADT with
more than one WMO placement misaligned every subsequent record on reload.
Now pads with nameSet=0 and scale=1024 (=1.0 fixed-point).
2026-05-06 02:02:01 -07:00
Kelsi
804c7d3d60 fix(wom): toM2 handles WOM3 batches with empty textureLookup safely
Previously `m.textureLookup.size() - 1` would underflow to UINT_MAX when
texturePaths was empty, then std::min would clamp the bad value into the
batch. Renderer would either crash or sample bogus memory. Now treats an
empty lookup as textureIndex=0 (white-texture fallback path).
2026-05-06 02:00:52 -07:00
Kelsi
f6187e7f9a feat(editor): expose Display ID field in selected-NPC editor
SQL export uses CreatureSpawn.displayId for creature_template.modelid1.
Without it AzerothCore can't render the creature in-game. Added an
InputInt + warning text so users can set the displayId manually until
auto-discovery from CreatureDisplayInfo.dbc lands.
2026-05-06 01:57:49 -07:00
Kelsi
7d3eb59893 fix(wob): toWMOModel restores materials, textures, portals, group flags
Previously toWMOModel only copied vertex/index data — materials and
textures were dropped, so a converted-back WMO would render textureless
white walls. Now rebuilds the global texture index from material paths,
emits one WMOMaterial per WoB material, copies group bounds + outdoor
flag, and reconstructs MOPR portal refs from groupA/groupB so PVS data
survives round-trip.
2026-05-06 01:56:47 -07:00
Kelsi
ac6038fe46 fix(editor): syncToTerrain inverts the load-time rotation transform too
ADT loading transforms placement rotations:
  obj.rot = (-dp.rot[2], -dp.rot[0], dp.rot[1] + 180)
syncToTerrain previously wrote them back unchanged, so save->load would
flip and shift orientation. Now applies the inverse:
  dp.rot = (-obj.rot.y, obj.rot.z - 180, -obj.rot.x)
which round-trips identically.
2026-05-06 01:54:10 -07:00
Kelsi
1f97cb957e fix(editor): syncToTerrain converts world coords back to ADT placement coords
ADT loading converts MDDF/MODF positions from ADT space to render/world
space via core::coords::adtToWorld, but syncToTerrain wrote object
positions back as raw render coords. So saving and reloading would
displace every placed object/WMO, accumulating each save cycle. Now
calls worldToAdt() to round-trip cleanly.
2026-05-06 01:53:32 -07:00
Kelsi
63fe5da04e feat(editor): selected NPC marker is larger and yellow-cyan tinted
Marker geometry now reacts to npc.selected: 2.5x base radius (vs 1.5x),
saturated yellow with cyan tinge, and full alpha. Marker rebuild also
fires on selection change so the highlight appears immediately rather
than only after the next placement.
2026-05-06 01:51:59 -07:00
Kelsi
b491ecb435 fix(editor): call WMORenderer::prepareRender before render
Mirror the M2 fix: the editor was skipping the WMO renderer's per-frame
state advance, so material UBO updates and frame ID tracking were stale
relative to the main game's render flow. Most visible effect is that
material setting toggles wouldn't propagate to the GPU.
2026-05-06 01:49:32 -07:00
Kelsi
2a2c217ae3 feat(editor): auto-save fires for any unsaved change (objects, NPCs, quests)
Auto-save was gated on terrainEditor.hasUnsavedChanges() so a session
where the user only edited NPCs or quests would lose data on crash.
Added autoSavePendingChanges_ flag flipped by every objectsDirty_ = true
site (and markObjectsDirty), cleared by quickSave. Auto-save now fires
on either dirty signal.
2026-05-06 01:48:34 -07:00
Kelsi
552e0d22e2 feat(editor): export creature/faction/item DBCs alongside zone DBCs
Spawned NPCs reference CreatureDisplayInfo, CreatureModelData, faction
templates, etc. Without exporting these the JSON DBC pack only covered
terrain data and exported zones couldn't resolve creature display IDs
on a clean install. Added: CreatureDisplayInfo, CreatureModelData,
CreatureType, CreatureFamily, FactionTemplate, Faction, ItemDisplayInfo.
2026-05-06 01:41:53 -07:00
Kelsi
4fd285b5c4 feat(editor): collectWMOTextures recurses into WMO doodad M2 textures
WMO buildings reference M2 doodads (chairs, candles, banners) via the
MODD chunk. Their textures live in those M2 files, not the WMO root.
Now collectWMOTextures walks every doodad name and collects M2 textures
recursively so exported buildings include all their interior decoration
textures.
2026-05-06 01:40:44 -07:00
Kelsi
f1d332825e feat(editor): export WMO textures with the zone
Placed WMO buildings reference textures (walls, floors, decorations) that
were not being exported alongside the WOB files. Added collectWMOTextures()
which loads the root WMO + all group files and gathers every texture path,
then folds these into the same PNG export pass that handles terrain and M2
textures. Exported zones now have every texture they need across all model
types.
2026-05-06 01:40:05 -07:00
Kelsi
a711a92875 refactor(terrain): use WoweeModelLoader::toM2 for WOM loading in main game
terrain_manager.cpp had a 70-line duplicate of the WOM->M2 conversion that
ignored WOM3 multi-batch support. Replaced with a single toM2() call.
Also extended toM2 to copy bones and animation sequence headers so the
shared helper now produces a fully renderable M2Model from any WOM
version, with main game and editor both using the same code path.
2026-05-06 01:38:31 -07:00
Kelsi
23951d4075 fix(wom): fromM2 sets version=3 when batches were extracted
Without this fromM2 always wrote version=2 even when batches were
populated, causing the version field on the in-memory model to lie
about its content. The save() magic-byte selection happens off the
batches/animation flags directly so the on-disk file is still correct,
but loaders that key off model.version saw stale info.
2026-05-06 01:36:37 -07:00
Kelsi
9eae67d574 feat(editor): NPC scatter snaps each spawn to ground when enabled
The scatter tool spawned creatures all at the cursor's z-height which
made them hover when scattered over uneven terrain. Added a Snap to
Ground checkbox (defaults to on) that raycasts each scattered NPC and
places it on the actual surface.
2026-05-06 01:35:26 -07:00
Kelsi
13a7adffab fix(wom): validate WOM3 batch ranges to reject corrupt files safely
Without bounds checks, a corrupted WOM3 file with invalid indexStart/
indexCount/textureIndex would feed bad ranges to the M2 renderer and
crash on draw. Now each batch is validated against the loaded indices
and texturePaths arrays; out-of-range batches are warned and dropped.
2026-05-06 01:32:59 -07:00
Kelsi
8daa81eecb feat(editor): transform gizmo works on selected NPCs
Selected NPCs now display the move/rotate/scale gizmo and respond to
drag operations. Rotate uses only the yaw axis (NPCs have a single
orientation field, not full euler rotation). Move/scale work the same
way as objects.
2026-05-06 01:31:34 -07:00
Kelsi
b49cb344ac feat(editor): NPC context menu adds Snap to Ground and Face Camera
Right-click context menu on a selected NPC now mirrors the object menu:
Snap to Ground drops it to terrain elevation, Face Camera rotates the NPC
to face the current camera position. Also annotates Duplicate with the
Ctrl+D shortcut hint.
2026-05-06 01:30:27 -07:00
Kelsi
ec50c41044 fix(sql): convert NPC orientation from degrees to radians for AzerothCore
The editor's orientation field is stored in degrees (matches the UI slider
and the M2 renderer's glm::radians() call), but AzerothCore's creature.
orientation column expects radians. Without conversion every exported NPC
faces the wrong direction in-game (off by 57x).
2026-05-06 01:28:46 -07:00
Kelsi
09f573c6ee feat(editor): patrol UI shows loop length and per-point wait time editor
The patrol list now shows total loop distance and gives each waypoint a
draggable wait-time field (0-60s). Helps tune patrol pacing without re-saving
the JSON manually.
2026-05-06 01:27:50 -07:00
Kelsi
59a6c22625 test(wom): add WOM3 magic-distinctness check 2026-05-06 01:27:14 -07:00
Kelsi
700416b2c7 feat(editor): scale slider in selected-NPC editor
Once an NPC is placed there was no way to resize it without removing and
re-placing. Added a Scale DragFloat in the selected-creature editor with
the same 0.1-50 range used for placed objects.
2026-05-06 01:23:42 -07:00
Kelsi
7c4afdbca4 feat(editor): double-click in NPC/object list flies camera to entry
Single-click selects, double-click also flies to. Removes the trip back to
the side panel to hit the Fly To button when navigating long lists.
2026-05-06 01:22:44 -07:00
Kelsi
6f88eb270a feat(wob): extract portals from WMO during conversion
WoweeBuildingLoader::fromWMO previously left the portals array empty,
losing portal/PVS data essential for indoor visibility culling. Now reads
the WMO portal vertex polygons and pairs them with their two adjacent
groups via MOPR refs, populating WoweeBuilding::Portal fully.
2026-05-06 01:20:29 -07:00
Kelsi
f39869ef6a docs(editor): document new shortcuts in F1 Keyboard Shortcuts dialog
Adds Ctrl+D duplicate, Ctrl+Wheel rotation, NPC click-to-select, and
W-for-waypoint to the help text so users discover the new bindings.
2026-05-06 01:17:57 -07:00
Kelsi
7d88c5f538 feat(editor): Ctrl+D duplicates the selected object or NPC at (10,10) offset 2026-05-06 01:17:25 -07:00
Kelsi
e342f2ba55 chore(wmo): demote 'cleared all WMO models' message to INFO level 2026-05-06 01:16:18 -07:00
Kelsi
53b2fc78fa feat(editor): patrol path visualization closes the loop back to start 2026-05-06 01:14:58 -07:00
Kelsi
f097763875 feat(editor): click on existing NPC marker selects it instead of placing duplicate
Plain left-click within 4u of an existing NPC now selects that NPC rather
than dropping a new spawn on top. Shift+click forces placement at the cursor
even if it overlaps an existing NPC, preserving the rapid-placement workflow.
2026-05-06 01:13:43 -07:00
Kelsi
7fcc923d2e feat(editor): W hotkey adds patrol waypoint at cursor in NPC mode
When an NPC with Patrol behavior is selected in NPC mode, pressing W
appends a waypoint at the current cursor position. Faster than clicking
the panel button for laying out long routes.
2026-05-06 01:12:51 -07:00
Kelsi
4b3375ac44 feat(editor): export NPC/M2 model textures as PNG with the zone
TextureExporter::collectUsedTextures only picked up terrain textures, so
exported zones were missing every texture referenced by NPC creature models
and placed M2 doodads. Added collectM2Textures() and unified the export
collection to include terrain + all referenced M2 paths, so the rendered
zone is fully self-contained in the PNG/WOM open formats.
2026-05-06 01:11:47 -07:00
Kelsi
732e58355a feat(editor): convert NPC creature models to WOM during zone export
Previously only placed M2 objects were converted to the WOM open format.
NPC creature models stayed as references to game M2/skin files, which
meant exported zones still depended on proprietary Blizzard assets to
render their NPCs. Now the exporter walks both placed objects and NPC
spawns and emits a WOM for every unique M2 path, making zones fully
self-contained.
2026-05-06 01:09:38 -07:00
Kelsi
35ad340ccc feat(editor): facing arrow on NPC markers + Ctrl+Wheel hint in object panel
NPC markers now show a yellow ground-triangle pointing in the orientation
direction so users can see facing without selecting. Object panel gained
the Ctrl+Wheel rotation hint to match the NPC panel.
2026-05-06 01:08:32 -07:00
Kelsi
b736c6b2e1 feat(wom): add WOM3 multi-batch format for material-aware models
WOM1/WOM2 had a single mesh with one texture, which lost the multi-submesh
structure of complex M2 models (body+hair+eyes+armor each need different
textures and blend modes).

WOM3 adds a Batch array: each batch has indexStart/indexCount + a textureIndex
into texturePaths + blendMode + flags. Loader is fully backward compatible:
WOM1/WOM2 files still load, and WOM3 with no batches block falls back to a
single full-mesh batch. fromM2 now extracts batches with materials, and toM2
emits matching M2 batches so the renderer can draw them correctly.
2026-05-06 01:07:00 -07:00
Kelsi
00c078a9af feat(editor): snapSelectedToGround now also snaps NPCs and their patrol waypoints 2026-05-06 01:03:50 -07:00
Kelsi
03a863abe1 refactor(wom): extract WOM->M2 conversion to shared helper
Adds WoweeModelLoader::toM2() and tryLoadByGamePath() to deduplicate the
identical conversion code that lived in editor_viewport for both objects
and NPCs. Cuts ~70 lines of duplicated logic and makes WOM->M2 reusable
across the codebase.
2026-05-06 01:02:56 -07:00
Kelsi
eb8f5a09b1 feat(editor): visualize patrol path of selected NPC as ribbon with waypoints
Adds setPatrolPath() that draws a multi-segment orange ribbon between the
NPC's spawn position and each waypoint, plus diamond markers at each point
(green for start = NPC home, white for waypoints). Renders only while the
NPC is selected and has a patrol path defined.
2026-05-06 00:58:30 -07:00