Commit graph

3257 commits

Author SHA1 Message Date
Kelsi
5df007b7b9 feat(editor): random rotation, placed object list, quality of life
- Random Rotation checkbox: each placed object gets a random Y rotation
  (great for natural-looking tree/rock placement without manual tweaking)
- Placed Object List: collapsible list in Object panel showing all placed
  objects with name and position, click to select
- Both features reduce repetitive manual work when building dense zones
2026-05-05 04:57:42 -07:00
Kelsi
89312120f4 feat(editor): heightmap export, help overlay, keyboard reference
- Export Heightmap: File > Export Heightmap saves terrain as 16-bit
  RAW grayscale (129x129) for use in external terrain editors or
  as a backup. Configurable max height scale.
- Help overlay (F1 or Help menu): lists all keyboard shortcuts
  organized by category (navigation, editing, object transform, view)
- Round-trip heightmap workflow: import → edit → export
2026-05-05 04:52:36 -07:00
Kelsi
2f96f112bd feat(editor): heightmap import, toast notifications, workflow polish
- Import Heightmap: File > Import Heightmap loads RAW 8/16-bit grayscale
  files (129x129 or 257x257) and maps to terrain heights with configurable
  scale. Supports standard terrain editor heightmap formats.
- Toast notifications: non-intrusive green popup at bottom center for
  user feedback (save confirmations, import results, errors)
- Toasts fade out after 3 seconds with alpha animation
- Auto-save now shows toast on save
- Quick-save (Ctrl+S) shows toast confirmation
2026-05-05 04:49:43 -07:00
Kelsi
a91233a6ec feat(editor): erosion brush, NPC load, auto-save
- Erode brush mode: simulates water erosion by moving height downhill
  based on slope, creating natural drainage patterns and gullies
- NPC JSON loader: File > Load NPCs parses saved creatures.json back
  into the spawn list (round-trip save/load now works)
- Auto-save: every 5 minutes when unsaved changes exist, exports the
  full zone (ADT + WDT + creatures) to the output directory
- Sculpt mode now has 6 brush types: Raise/Lower/Smooth/Flatten/Level/Erode
2026-05-05 04:44:54 -07:00
Kelsi
42749e9b58 feat(editor): procedural noise generator, sky presets, viewport lighting
- Noise Generator in Sculpt panel: applies procedural value noise
  with configurable frequency, amplitude, octaves, and seed
  to create hills/valleys across entire tile instantly
- Sky/Lighting presets: View > Sky menu with Day (blue sky, high sun),
  Dusk (orange, low sun), Night (dark blue, moonlight)
- Viewport clear color and light direction now configurable at runtime
- Noise uses smoothstep interpolation with octave fractal layering
2026-05-05 04:40:37 -07:00
Kelsi
f5fe9a0101 feat(editor): terrain holes, recent textures, sculpt panel polish
- Punch Hole / Fill Hole buttons in Sculpt panel: creates terrain
  holes (4x4 bitmask) for cave entrances, mine shafts, etc.
  Uses brush radius to determine affected area.
- Recent Textures: paint panel shows last 6 used textures as quick-
  select buttons (no need to re-search the full list)
- Holes saved in ADT format (MCNK holes field) and respected by
  the mesh generator (triangles skipped at hole positions)
2026-05-05 04:34:03 -07:00
Kelsi
cc6a72e7b2 feat(editor): minimap, patrol path editing, flatten height picker
- Minimap window: 16x16 chunk grid colored by average height
  (blue=low, green=mid, brown=high, blue overlay=water)
- NPC patrol path UI: add waypoints at cursor, view path list,
  delete individual points or clear entire path
- Sculpt flatten "Pick" button: click to set target height from
  cursor position instead of typing manually
- Height range displayed in minimap footer
2026-05-05 04:28:44 -07:00
Kelsi
ba96de7138 fix(editor): normal recalculation after sculpt, mode switch cleanup
- Terrain normals recalculated after height changes (smooth lighting
  on sculpted terrain instead of flat-shaded appearance)
- Ghost preview and brush indicator cleared when switching modes
  (prevents stale model instances or circles persisting)
- File > Clear All resets undo history and selections
- Normal computation uses finite differences from neighbor heights,
  handles both outer (9x9) and inner (8x8) vertex grid positions
2026-05-05 04:24:20 -07:00
Kelsi
5daa359e74 feat(editor): object scatter, camera bookmarks, shortcut hints
- Object scatter tool: place N copies of selected M2/WMO in a radius
  with random rotation and scale range (Min/Max Scale slider)
- Camera bookmarks: F5 saves current position, View > Load Bookmark
  to jump back — useful for working on different parts of a large zone
- Shortcut hints shown at bottom of Object panel
  (G=move, R=rotate, T=scale, Del=remove)
- DragFloatRange2 for min/max scale in scatter UI
2026-05-05 04:20:26 -07:00
Kelsi
48026421c9 feat(editor): NPC scatter tool, adjacent tile creation, multi-tile prep
- Scatter tool: place N creatures in a radius around cursor position
  with random rotation and uniform disk distribution
- File > Add Adjacent Tile: creates and exports a blank tile N/S/E/W
  of current (foundation for multi-tile zone editing)
- Scatter UI: count slider (1-30), radius slider (10-200)
- Scatter places all copies with same stats/behavior as template
2026-05-05 04:14:29 -07:00
Kelsi
6e24e08818 feat(editor): brush radius circle indicator on terrain
- Yellow circle renders at cursor position showing brush radius
- Visible in Sculpt, Paint, and Water modes
- Built from 48-segment quad strip slightly above terrain surface
- Renders through the water pipeline (alpha-blended, depth-tested)
- Disappears when cursor leaves terrain or in Object/NPC modes
- Brush VB cleaned up properly on shutdown
2026-05-05 04:10:46 -07:00
Kelsi
d28c5ec842 feat(editor): unified Export Zone, quick-save, cursor world coords
- Ctrl+S quick-saves entire zone (ADT + WDT + creatures.json) to output/
- File > Export Zone dialog saves all data to chosen directory
- exportZone() bundles ADT, WDT, and NPC spawns in one operation
- Info panel shows cursor world coordinates for placement debugging
- Info panel shows NPC count alongside object count
- Save state indicator: "Saved" (green) vs "* Unsaved (Ctrl+S)" (yellow)
- File menu reorganized: Quick Save + Export Zone replaces separate ADT/WDT
2026-05-05 04:06:19 -07:00
Kelsi
88abbfb564 feat(editor): undo object placement, snap to ground, keyboard shortcuts
- Ctrl+Z in Object/NPC mode undoes last placement (50-deep stack)
- "Snap Ground" button raycasts straight down to place object on terrain
- Useful for objects placed too high or moved off terrain surface
- Undo stack adjusts indices when objects are removed mid-stack
2026-05-05 04:01:06 -07:00
Kelsi
ace6173401 fix(editor): terrain raycast on rough terrain, keyboard shortcuts, context menu
- Raycast AABB now uses actual min/max vertex heights per chunk
  instead of fixed ±200 padding (fixes misses on sculpted terrain)
- Right-click context menu opens correctly (deferred popup via flag
  since ImGui::OpenPopup must be called within ImGui frame)
- Keyboard shortcuts: G=Move, R=Rotate, T=Scale, X/Y=axis lock,
  Escape=deselect, Delete works in any mode for objects/NPCs
- Delete key now removes selected NPC in NPC mode too
2026-05-05 03:55:53 -07:00
Kelsi
f38884856f fix(editor): NPC ghost preview, scale control, frame sync for M2 rendering
- Ghost preview now shows in NPC mode (follows cursor with creature model)
- Added scale field to CreatureSpawn (default 1.0, slider 0.5-10x)
- NPC instances render at their configured scale
- Scale included in JSON save format
- M2Renderer::update() now runs AFTER beginFrame() so getCurrentFrame()
  returns the correct frame index — fixes instance SSBO mismatch that
  caused draws=0 despite loaded models
2026-05-05 03:52:43 -07:00
Kelsi
2980ca83e7 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
Kelsi
d138269a35 fix(movement): reject server teleports to corrupted near-origin positions
Some checks failed
Build / Build (arm64) (push) Has been cancelled
Build / Build (x86-64) (push) Has been cancelled
Build / Build (macOS arm64) (push) Has been cancelled
Build / Build (windows-arm64) (push) Has been cancelled
Build / Build (windows-x86-64) (push) Has been cancelled
Security / CodeQL (C/C++) (push) Has been cancelled
Security / Semgrep (push) Has been cancelled
Security / Sanitizer Build (ASan/UBSan) (push) Has been cancelled
The server can persist a corrupted near-origin position on map 0 (from a
faulty area-trigger destination) across sessions. On re-login it sends the
bad position via LOGIN_VERIFY_WORLD; if the player walks into the offending
trigger again the server re-teleports there, and our heartbeats reinforce
the bad save — creating a permanent teleport loop.

Defenses added:
- handleTeleportAck rejects MSG_MOVE_TELEPORT to near-origin on map 0
  (no position update, no ACK, no world reload)
- applyPlayerTransportState rejects player UPDATE_OBJECT MOVEMENT blocks
  pushing the same bad position
- sendMovement blocks heartbeats originating from near-origin so the
  server cannot persist the bad save
- 10-second area-trigger cooldown after teleport / world entry / login
  (replaces the one-shot suppress flag that re-fired on jitter)
- Immediate STOP+HEARTBEAT after teleport ACK / WORLDPORT ACK / login
  to sync the real position with the server promptly
- CMSG_AREATRIGGER firing now logged at WARNING level for diagnosis
2026-04-24 17:48:49 -07:00
Kelsi
f9f02569d6 fix(vulkan): re-allocate megaBoneSet_ after descriptor pool reset and fix PlayerFrame ImGui crash
Some checks failed
Build / Build (arm64) (push) Has been cancelled
Build / Build (x86-64) (push) Has been cancelled
Build / Build (macOS arm64) (push) Has been cancelled
Build / Build (windows-arm64) (push) Has been cancelled
Build / Build (windows-x86-64) (push) Has been cancelled
Security / CodeQL (C/C++) (push) Has been cancelled
Security / Semgrep (push) Has been cancelled
Security / Sanitizer Build (ASan/UBSan) (push) Has been cancelled
Re-allocate megaBoneSet_[0..1] in M2Renderer::clear() after vkResetDescriptorPool invalidates all
sets from boneDescPool_. Stale handles were bound to command buffers during rendering, causing
cascading validation errors. Also add ImGui::Dummy() after SetCursorScreenPos in the shaman totem
bar to satisfy ImGui's window boundary extension assertion.
2026-04-15 13:22:30 -07:00
Kelsi
01fecbf3e0 fix(parsing): correct UPDATE_OBJECT PackedGuid, cape textures, and missing asset guards
Some checks failed
Build / Build (arm64) (push) Has been cancelled
Build / Build (x86-64) (push) Has been cancelled
Build / Build (macOS arm64) (push) Has been cancelled
Build / Build (windows-arm64) (push) Has been cancelled
Build / Build (windows-x86-64) (push) Has been cancelled
Security / CodeQL (C/C++) (push) Has been cancelled
Security / Semgrep (push) Has been cancelled
Security / Sanitizer Build (ASan/UBSan) (push) Has been cancelled
- Fix MOVEMENT update type to use readPackedGuid() instead of readUInt64() (WotLK 3.3.5a)
- Add desync diagnostic logging to UPDATE_OBJECT parser for future debugging
- Register MSG_MOVE_SET_COLLISION_HGT (0x518) as skip handler
- Fix cape texture lookup to only try .blp extension variants (4 files)
- Add fileExists() guards for underwear textures referencing missing BLP files (4 files)
- Add spell visual impact→cast M2 path fallback
- Skip WMO doodad instance creation when model load fails
- Demote spell caster position warning to debug level
2026-04-14 06:06:50 -07:00
Kelsi
83eef878fb fix: validate displayId range and skip missing equipment textures
Reject displayId values >100k (corrupted update-field data) to avoid
pointless DBC lookups and log spam. Add fileExists() guard before
using base texture path in 4 equipment compositing code paths that
were falling through without checking, causing excessive "Texture not
found" warnings when users have incomplete MPQ extractions.
2026-04-14 04:20:28 -07:00
Kelsi
2f3a973444 docs: update documentation for PRs #59-63 refactors
- architecture.md: add chat system modules (src/ui/chat/), world map
  modules (src/rendering/world_map/), CatmullRomSpline (src/math/),
  transport decomposition, and updated namespace list
- status.md: update timestamp to 2026-04-14, add recent refactors
  section and world map known gaps
- CHANGELOG.md: add detailed entries for PRs #58-63 covering
  architecture, features, bug fixes, and 19 new test files
- TESTING.md: expand test suite layout from 8 to 27 files organized
  by category (core, animation, transport, world map, chat)
- CONTRIBUTING.md: update namespace table, testing section, and key
  files list to reflect new module directories
- README.md: update status timestamp to 2026-04-14
2026-04-14 03:42:46 -07:00
Kelsi
3be40c3b69 fix: resolve 7 code quality issues across PRs #59-63
- Remove stale kVOffset (-0.15) from zone_highlight_layer hover detection;
  the offset was removed from rendering but left in the hit-test path,
  shifting hover ~15% vertically
- Add null guard for cachedGameHandler_ in ChatPanel::inputTextCallback
  to prevent dereference before first render frame
- Zero WindowBorderSize in world map ImGui window to eliminate gap
  between window edge and map content
- Replace hardcoded cosmic highlight multipliers with displayH×displayH
  square rendering, preserving 1:1 aspect ratio at any resolution
- Skip transport waypoints where serverToCanonical zeroes nonzero input
  instead of silently building paths with broken (0,0,0) coordinates
- Use length-squared check (posLenSq > 1.0) for spline endpoint
  validation instead of per-component != 0 comparison, so entities
  near the world origin are no longer skipped
- Fix off-by-one in ChatPanel::insertChatLink buffer capacity check
2026-04-14 02:41:55 -07:00
Kelsi Rae Davis
9547feabf9
Merge pull request #63 from ldmonster/fix/map-fixes
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
[chore] fix: World Map: ZMP pixel-accurate hover
2026-04-13 21:51:03 -07:00
Kelsi Rae Davis
3c8736449a
Merge pull request #62 from ldmonster/chore/chat-system
[chore] refactor(chat): decompose ChatPanel into modular architecture
2026-04-13 21:50:32 -07:00
Pavel Okhlopkov
97c95941f4 feat(world-map): remove kVOffset hack, ZMP hover, textured player arrow
- Remove the -0.15 vertical offset (kVOffset) from coordinate_projection,
  coordinate_display, and zone_highlight_layer; continent UV math is now
  identical to zone UV math
- Switch world_map_facade aspect ratio to MAP_W/MAP_H (1002×668) and crop
  the FBO image with MAP_U_MAX/MAP_V_MAX instead of stretching the full
  1024×768 FBO
- Account for ImGui title bar height (GetFrameHeight) in window sizing and
  zone highlight screen-space rect coordinates
- Add ZMP 128×128 grid pixel-accurate hover detection in zone_highlight_layer;
  falls back to AABB when ZMP data is unavailable
- Upgrade PlayerMarkerLayer with full Vulkan lifecycle (initialize,
  clearTexture, destructor); loads MinimapArrow.blp and renders a rotated
  32×32 textured quad via AddImageQuad; red triangle retained as fallback
- Expose arrowRotation_ / arrowDS_ accessors on Minimap; clean up arrow DS
  and texture in Minimap::shutdown()
- Wire PlayerMarkerLayer::initialize() into WorldMapFacade::initialize()
- Update coordinate-projection test: continent and zone UV are now equal

Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
2026-04-12 20:02:50 +03:00
Pavel Okhlopkov
ada019e0d4 refactor(chat): extract ItemTooltipRenderer, slim render(), consolidate utils
- Extract renderItemTooltip() (510 LOC) from ChatMarkupRenderer into
  dedicated ItemTooltipRenderer class; chat_markup_renderer.cpp 766→192 LOC
- Extract formatChatMessage(), detectChannelPrefix(), inputTextCallback()
  from render(); render() 711→376 LOC
- Consolidate replaceGenderPlaceholders() from 3 copies into
  chat_utils::replaceGenderPlaceholders(); remove 118 LOC duplicate from
  quest_log_screen.cpp, update 8 call sites in window_manager.cpp
- Delete chat_panel_commands.cpp (359 LOC) — absorb sendChatMessage,
  executeMacroText, PortBot helpers into chat_panel.cpp; move
  evaluateMacroConditionals to macro_eval_convenience.cpp
- Delete chat_panel_utils.cpp (229 LOC) — absorb small utilities into
  chat_panel.cpp
- Replace 3 forward declarations of evaluateMacroConditionals with
  #include "ui/chat/macro_evaluator.hpp"

Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
2026-04-12 15:46:03 +03:00
Pavel Okhlopkov
42f1bb98ea refactor(chat): decompose into modular architecture, add GM commands, fix protocol
- Extract ChatPanel monolith into 15+ focused modules under ui/chat/
  (ChatInput, ChatTabManager, ChatTabCompleter, ChatMarkupParser,
  ChatMarkupRenderer, ChatCommandRegistry, ChatBubbleManager,
  ChatSettings, MacroEvaluator, GameStateAdapter, InputModifierAdapter)
- Split 2700-line chat_panel_commands.cpp into 11 command modules
- Add GM command handling: 190-command data table, dot-prefix interception,
  tab-completion, /gmhelp with category filter
- Fix ChatType enum to match WoW wire protocol (SAY=0x01 not 0x00);
  values 0x00-0x1B shared across Vanilla/TBC/WotLK
- Fix BG_SYSTEM_* values from 82-84 (UB in bitmask shifts) to 0x24-0x26
- Fix infinite Enter key loop after teleport (disable TOGGLE_CHAT repeat,
  add 2-frame input cooldown)
- Add tests: chat_markup_parser, chat_tab_completer, gm_commands,
  macro_evaluator

Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
2026-04-12 14:59:56 +03:00
Kelsi Rae Davis
09c4a9a04a
Merge pull request #61 from ldmonster/feat/map-system
Some checks failed
Build / Build (arm64) (push) Has been cancelled
Build / Build (x86-64) (push) Has been cancelled
Build / Build (macOS arm64) (push) Has been cancelled
Build / Build (windows-arm64) (push) Has been cancelled
Build / Build (windows-x86-64) (push) Has been cancelled
Security / CodeQL (C/C++) (push) Has been cancelled
Security / Semgrep (push) Has been cancelled
Security / Sanitizer Build (ASan/UBSan) (push) Has been cancelled
[chore] refactor: Decompose World Map into Modular Component Architecture
2026-04-12 00:10:01 -07:00
Pavel Okhlopkov
fff06fc932 refactor: decompose world map into modular component architecture
Break the monolithic 1360-line world_map.cpp into 16 focused modules
under src/rendering/world_map/:

Architecture:
- world_map_facade: public API composing all components (PIMPL)
- world_map_types: Vulkan-free domain types (Zone, ViewLevel, etc.)
- data_repository: DBC zone loading, ZMP pixel map, POI/overlay storage
- coordinate_projection: UV projection, zone/continent lookups
- composite_renderer: Vulkan tile pipeline + off-screen compositing
- exploration_state: server mask + local exploration tracking
- view_state_machine: COSMIC→WORLD→CONTINENT→ZONE navigation
- input_handler: keyboard/mouse input → InputAction mapping
- overlay_renderer: layer-based ImGui overlay system (OCP)
- map_resolver: cross-map navigation (Outland, Northrend, etc.)
- zone_metadata: level ranges and faction data

Overlay layers (each an IOverlayLayer):
- player_marker, party_dot, taxi_node, poi_marker, quest_poi,
  corpse_marker, zone_highlight, coordinate_display, subzone_tooltip

Fixes:
- Player marker no longer bleeds across continents (only shown when
  player is in a zone belonging to the displayed continent)
- Zone hover uses DBC-projected AABB rectangles (restored from
  original working behavior)
- Exploration overlay rendering for zone view subzones

Tests:
- 6 new test files covering coordinate projection, exploration state,
  map resolver, view state machine, zone metadata, and integration

Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
2026-04-12 09:52:51 +03:00
Kelsi Rae Davis
db3f65a87e
Merge pull request #60 from ldmonster/chore/transport-manager
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
[chore] refactor: extract spline math, decompose TransportManager
2026-04-11 03:48:42 -07:00
Kelsi Rae Davis
5e82464658
Merge pull request #59 from ldmonster/fix/minor-bugs
[fix] minor-bugs: UI, animation, quest, rendering & movement fixes
2026-04-11 03:47:02 -07:00
Pavel Okhlopkov
f156876f46 bump
Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
2026-04-11 10:11:47 +03:00
Pavel Okhlopkov
39719cac82 refactor: decompose TransportManager and upgrade Entity to CatmullRom splines
TransportManager decomposition:
- Extract TransportClockSync: server clock offset, yaw flip detection,
  velocity bootstrap, client/server mode switching
- Extract TransportAnimator: spline evaluation, Z clamping, orientation
  from server yaw or spline tangent
- Slim TransportManager to thin orchestrator delegating to ClockSync and
  Animator; add pushTransform() helper to deduplicate WMO/M2 renderer calls
- Remove legacy orientationFromSplineTangent (now uses
  CatmullRomSpline::orientationFromTangent)

Entity path following upgrade:
- Replace pathPoints_/pathSegDists_ linear lerp with
  std::optional<CatmullRomSpline> activeSpline_
- startMoveAlongPath builds SplineKeys with distance-proportional timing
- updateMovement evaluates CatmullRomSpline for smooth Catmull-Rom
  interpolation matching server-side creature movement
- Reset activeSpline_ on setPosition/startMoveTo to prevent stale state

Tests:
- Add test_transport_components (9 cases): ClockSync client/server/reverse
  modes, yaw flip detection, Animator position eval, server yaw, Z clamping
- Link spline.cpp into test_entity for CatmullRomSpline dependency

Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
2026-04-11 09:50:38 +03:00
Pavel Okhlopkov
de0383aa6b refactor: extract spline math, consolidate packet parsing, decompose TransportManager
Extract CatmullRomSpline (include/math/spline.hpp, src/math/spline.cpp) as a
standalone, immutable, thread-safe spline module with O(log n) binary segment
search and fused position+tangent evaluation — replacing the duplicated O(n)
evalTimedCatmullRom/orientationFromTangent pair in TransportManager.

Consolidate 7 copies of spline packet parsing into shared functions in
game/spline_packet.{hpp,cpp}: parseMonsterMoveSplineBody (WotLK/TBC),
parseMonsterMoveSplineBodyVanilla, parseClassicMoveUpdateSpline,
parseWotlkMoveUpdateSpline, and decodePackedDelta. Named SplineFlag constants
replace magic hex literals throughout.

Extract TransportPathRepository (game/transport_path_repository.{hpp,cpp}) from
TransportManager — owns path data, DBC loading, and path inference. Paths stored
as PathEntry wrapping CatmullRomSpline + metadata (zOnly, fromDBC, worldCoords).
TransportManager reduced from ~1200 to ~500 lines, focused on transport lifecycle
and server sync.

Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
2026-04-11 08:30:28 +03:00
Pavel Okhlopkov
535cc20afe fix state gate races and robust spline
Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
2026-04-10 23:30:55 +03:00
Pavel Okhlopkov
6ba0edc2fb change weapon for ranged skills
Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
2026-04-10 23:01:16 +03:00
Pavel Okhlopkov
fe1dc5e02b make a user friendly delete message
Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
2026-04-10 22:22:14 +03:00
Pavel Okhlopkov
5b47d034c5 fix(movement): multi-segment path interpolation, waypoint parsing & terrain Z clamping
Add proper waypoint support to entity movement:

- Parse intermediate waypoints from MonsterMove packets in both WotLK
  and Vanilla paths. Uncompressed paths store absolute float3 waypoints;
  compressed paths decode TrinityCore's packed uint32 deltas (11-bit
  signed x/y, 10-bit signed z, ×0.25 scale, waypoint = midpoint − delta)
  with correct 2's-complement sign extension.

- Entity::startMoveAlongPath() interpolates along cumulative-distance-
  proportional segments instead of a single straight line.

- MovementHandler builds the full path (start → waypoints → destination)
  in canonical coords and dispatches to startMoveAlongPath() when
  waypoints are present.

- Snap entity x/y/z to moveEnd in the dead-reckoning overrun phase
  before starting a new movement, preventing visible teleports when the
  renderer was showing the entity at its destination.

- Clamp creature and player entity Z to the terrain surface via
  TerrainManager::getHeightAt() during active movement. Idle entities
  keep their server-authoritative Z to avoid breaking flight masters,
  elevator riders, etc.

Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
2026-04-10 20:35:18 +03:00
Pavel Okhlopkov
e07983b7f6 fix(rendering): crash on window resize due to stale swapchain
- Mark swapchain dirty in Application's SDL resize handler (was only done
  in Window::pollEvents which is never called)
- Skip swapchain recreation when window is minimized (0×0 extent violates
  Vulkan spec and crashes vmaCreateImage)
- Guard aspect ratio division by zero when height is 0

Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
2026-04-10 19:51:13 +03:00
Pavel Okhlopkov
759d6046bb fix(quest): quest log population, NPC marker updates on accept/abandon
- Delegate GameHandler::getQuestGiverStatus() to QuestHandler instead of
  reading from GameHandler's own empty npcQuestStatus_ map
- Immediately add quest to local log in acceptQuest() instead of waiting
  for field updates, fixing quests not appearing after accept
- Handle duplicate accept path (server already has quest) by also adding
  to local log
- Remove early return on empty questLog_ in applyQuestStateFromFields()
- Re-query nearby quest giver NPC statuses on abandon so markers refresh

Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
2026-04-10 19:50:56 +03:00
Pavel Okhlopkov
9c1ffae140 fix(ui): add keyboard navigation to character selection screen
Add Up/Down arrow keys to cycle through character list and Enter to
select. Claim arrow key ownership via SetKeyOwner to prevent ImGui nav
from moving focus to other widgets. Lock Enter key until release to
prevent the keypress from activating chat on the game screen.

Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
2026-04-10 19:50:40 +03:00
Pavel Okhlopkov
826a22eed3 fix(animation): prevent creature walk/run animation persisting after arriving
Use destination position (getLatest) instead of dead-reckoned position
(getX/Y/Z) during the overrun window to avoid visible forward-drift and
backward-snap. Only fall back to position-change movement detection for
entities without active movement tracking, preventing residual velocity
drift from keeping walk/run animation playing after arrival.

Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
2026-04-10 19:50:24 +03:00
Pavel Okhlopkov
4ba19d53d7 fix(ui): preserve auto-connect state when navigating back from character screen
Add resetForBack() to RealmScreen that clears selection state without
resetting autoSelectAttempted, preventing single-realm auto-connect from
re-firing when the user navigates back from the character screen.

Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
2026-04-10 19:50:06 +03:00
Kelsi
fce8ccdc45 fix(rendering): restore NPC back panel and apply cape textures (#57)
Some checks failed
Build / Build (arm64) (push) Has been cancelled
Build / Build (x86-64) (push) Has been cancelled
Build / Build (macOS arm64) (push) Has been cancelled
Build / Build (windows-arm64) (push) Has been cancelled
Build / Build (windows-x86-64) (push) Has been cancelled
Security / CodeQL (C/C++) (push) Has been cancelled
Security / Semgrep (push) Has been cancelled
Security / Sanitizer Build (ASan/UBSan) (push) Has been cancelled
The geoset normalization stripped all group 15 (cloak) submeshes but
only re-added them when a cape was equipped. NPCs without capes lost
the "no cape" back panel (geoset 1501), exposing the single-sided
torso mesh. Always add either the cape or no-cape geoset.

Also load and apply cape texture overrides for NPCs that do have capes
equipped via CreatureDisplayInfoExtra, matching the player path.
2026-04-07 03:20:13 -07:00
Kelsi Rae Davis
b41b3d2c71
Merge pull request #58 from ldmonster/feat/add-spells-animation
[feat] rendering: spell visual effects system
2026-04-07 02:19:00 -07:00
Pavel Okhlopkov
b79d9b8fea feat(rendering): implement spell visual effects with bone-tracked ribbons and particles
Add complete spell visual pipeline resolving the DBC chain
(Spell → SpellVisual → SpellVisualKit → SpellVisualEffectName → M2)
with precast/cast/impact phases, bone-attached positioning, and
automatic dual-hand mirroring.

Ribbon rendering fixes:
- Parse visibility track as uint8 (was read as float, suppressing
  all ribbon edges due to ~1.4e-45 failing the >0.5 check)
- Filter garbage emitters with bone=UINT_MAX unconditionally
- Guard against NaN spine positions from corrupt bone data
- Resolve ribbon textures via direct index, not textureLookup table
- Fall back to bone 0 when ribbon bone index is out of range

Particle rendering fixes:
- Reduce spell particle scale from 5x to 1.5x (was oversized)
- Exempt spell effect instances from position-based deduplication

Spell handler integration:
- Trigger precast visuals on SMSG_SPELL_START with server castTimeMs
- Trigger cast/impact visuals on SMSG_SPELL_GO
- Cancel precast visuals on cast interrupt/failure/movement

M2 classifier expansion:
- Add AmbientEmitterType enum for sound system integration
- Add 20+ foliage tokens, 4 spell effect tokens, isSmallFoliage flag
- Add markModelAsSpellEffect() to override disableAnimation

DBC layouts:
- Add SpellVisualID field to Spell.dbc for all expansion configs

Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
2026-04-07 11:27:59 +03:00
Kelsi
0a33e3081c fix(rendering): disable HiZ pyramid, fix WMO interior shadow clamping
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
HiZ occlusion culling built ~11 mip levels with per-level barriers
behind a blocking vkWaitForFences every frame — the main frame-rate
bottleneck.  Disable the pyramid build and fall back to GPU frustum-
only culling which is nearly free behind the fence.

WMO interiors now receive full-strength directional shadows but clamp
minimum brightness at 0.45 with a 0.35 ambient floor, so interiors
get real shadow contrast without going too dark.
2026-04-06 19:36:30 -07:00
Kelsi
4dcea08b90 Revert "fix(rendering): enable backface culling for one-sided M2 materials (#57)"
This reverts commit 7b746a3045.
2026-04-06 18:27:52 -07:00
Kelsi
70a0be9e79 fix(ci): bundle FFmpeg dylibs in macOS app artifact (#53)
dylibbundler misses Homebrew's FFmpeg libraries, causing a launch crash:
  Library not loaded: libavformat.62.12.100.dylib

Add a manual copy block for libavformat, libavcodec, libavutil,
libswscale, and libswresample — same pattern already used for Vulkan
and OpenSSL.  Applied to both build.yml and release.yml.
2026-04-06 18:18:19 -07:00
Kelsi
faf1d70c34 fix(rendering): reduce terrain chunk edge seams (#56)
Two sources of visible chunk-boundary squares:

1. Derivative-based bump mapping (bumpStrength=9) used dFdx/dFdy which
   are invalid across draw-call boundaries, producing strong normal
   discontinuities at every chunk edge.  Fade bump to zero near chunk
   edges using LayerUV as the chunk-space distance metric.

2. sampleAlpha used an abrupt step() to switch between point-sampled
   and 4-tap-blurred alpha, creating a visible ring 2 texels from each
   chunk edge.  Replace with smoothstep transition and a 5-tap average
   that includes the center sample.
2026-04-06 18:18:14 -07:00