Commit graph

819 commits

Author SHA1 Message Date
Kelsi
db068d480b feat(wob): tryLoadByGamePath helper, used by editor + terrain_manager
Mirrors the WOM tryLoadByGamePath API: probes custom_zones/buildings/ +
output/buildings/ by default, with optional extraPrefixes (e.g. per-zone
output/<map>/buildings/) checked first. Both the editor and the main
game's terrain_manager now use the helper, removing duplicate inline
lookup loops in two more places.
2026-05-06 04:10:12 -07:00
Kelsi
f36309a96f feat(wom): tryLoadByGamePath accepts extraPrefixes for per-zone search roots
The shared helper only probed custom_zones/models/ + output/models/, but
the editor's exportZone writes to output/<map>/models/. Added an
extraPrefixes parameter that's tried before the defaults — main game's
terrain_manager now passes ['output/<map>/models/', 'custom_zones/<map>/
models/'] so per-zone WOM exports override globals. Also removes the
last duplicate WOM-loading code from terrain_manager.
2026-05-06 04:07:16 -07:00
Kelsi
1d05bb0f13 fix(terrain): main game also propagates MODF scale to WMO instances
Mirrors the editor's WMO scale fix. WMOReady gains a scale field that
is computed from the loaded MODF placement.scale (u16 / 1024) and
forwarded to wmoRenderer->createInstance(). Without this the main
game ignored MODF scale even on WotLK ADTs that use it.
2026-05-06 03:55:14 -07:00
Kelsi
5241bbd669 perf(editor): cache M2/WMO models across rebuilds, only clear instances
The editor's rebuildObjects path was destroying every cached model and
re-uploading it on every (debounced) change. Added M2Renderer::clearInstances
that drops only the instance list while keeping models loaded. Editor's
clearObjects switches to clearInstances (M2) + clearInstances (WMO),
and persistent path->modelId maps survive across rebuilds. clearTerrain
fully evicts when loading a new zone.
2026-05-06 03:23:06 -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
e342f2ba55 chore(wmo): demote 'cleared all WMO models' message to INFO level 2026-05-06 01:16:18 -07:00
Kelsi
1c3307a0b6 fix(editor): unload ghost preview model when path changes
setGhostPreview reused modelId 59999 for every preview, but loadModel
returns true without doing anything when the ID is already cached. So
selecting a new NPC kept the old ghost model in GPU memory and createInstance
used the stale model. Added M2Renderer::unloadModel public API and call it
from clearGhostPreview.
2026-05-06 00:51:22 -07:00
Kelsi
ca630c4e87 chore(editor): remove debug logging now that NPC rendering works 2026-05-06 00:48:41 -07:00
Kelsi
a6d6e0168a fix(editor): add filtered-out instance diagnostic in M2 render path 2026-05-06 00:38:41 -07:00
Kelsi
b1162a2ac5 fix(editor): add GPU buffer validation logging in M2 render path 2026-05-06 00:26:36 -07:00
Kelsi
67f4097e74 fix: resolve all GitHub CodeQL security/quality alerts
Fix 9 integer-multiplication-cast-to-long warnings across 6 files:
- wmo_renderer.cpp: grid cell count and height variance calculation
- composite_renderer.cpp: overlay tile grid allocation
- vk_texture.cpp: image size calculation (width*height*bpp)
- m2_renderer.cpp: collision grid cell allocation
- character_renderer.cpp: normal map buffer and height variance
- world_entry_callback_handler.cpp: tile reserve count

All fixes cast operands to size_t/double before multiplication to
prevent integer overflow when dimensions are large.
2026-05-05 22:49:21 -07:00
Kelsi
b439f12c36 fix: WOM2 bone data in client renderer, WOM tests, docs update
- Fix WOM→M2Model conversion: copy boneWeights/boneIndices from WOM2
  vertices (was dropping skeletal binding data, breaking animation)
- Copy bone hierarchy and animation sequences from WOM2 to M2Model
  so animated WOM2 models render with proper skeletal deformation
- Add 3 WOM format tests: WOM1 binary structure, WOM2 magic check,
  invalid magic rejection (6 new assertions)
- CHANGELOG: document WOM1/WOM2 animated model support
- README: clarify WOM1 (static) vs WOM2 (animated) models
- 334 total assertions across 87 test cases
2026-05-05 16:23:22 -07:00
Kelsi
cff8d359e4 feat: client-side WOC collision loading + walkability queries
- TerrainManager loads WOC collision meshes alongside WOT/WHM terrain
  from both custom_zones/ and output/ directories
- CollisionData stored per-tile with triangle array + bounds
- isPositionWalkable(x, y): returns whether a world position is on
  walkable terrain (barycentric point-in-triangle test)
- getCollisionFlags(x, y): returns per-triangle flags (walkable,
  water, steep, indoor) for movement system integration
- Defaults to walkable when no collision data is loaded (backward compat)
- Custom zone players now have proper terrain physics boundaries
2026-05-05 15:32:48 -07:00
Kelsi
ad67700cb6 feat: WOM renderable batches, JSON DBC test coverage
- WOM→M2 conversion now creates proper render batch (indexStart,
  indexCount, vertexStart, vertexCount), texture references, material
  with opaque blend mode — WOM models are now actually visible in the
  client renderer instead of being invisible geometry-only shells
- 5 new JSON DBC test cases: basic load with strings/ints, float values,
  empty records rejection, missing records key rejection, findRecordById
  lookup across 3 records
- Total: 278 assertions across 80 test cases, all passing
2026-05-05 15:03:01 -07:00
Kelsi
4fc0361f7a feat: complete client integration for all 6 open formats
- Wire WOB buildings into WMO render pipeline (loads→converts→renders)
- Implement JSON DBC loading in DBCFile::loadJSON() with nlohmann/json
- Wire JSON DBC override into AssetManager (custom_zones/output scan)
- Add WMO→WOB conversion with full geometry (fromWMO)
- Replace placeholder WOB export with real WMO→WOB conversion in editor
- Add --convert-wmo CLI flag for batch WMO→WOB conversion
- Store discovered custom zones on Renderer with getCustomZones() accessor
- Add isCustomZone_ member to TerrainManager

All 6 Blizzard format replacements now fully load in the client:
  ADT→WOT/WHM, WDT→zone.json, BLP→PNG, DBC→JSON, M2→WOM, WMO→WOB
2026-05-05 12:41:19 -07:00
Kelsi
01d3638835 feat: WOB→WMO conversion and loading in client terrain manager
- WoweeBuildingLoader::toWMOModel() converts WOB groups to WMOModel
  with vertices, indices, normals, texCoords, and vertex colors
- TerrainManager now loads WOB files from custom_zones/buildings/
  and converts to WMOModel for the WMO renderer pipeline
- WMOGroup indices converted from uint32 to uint16 for renderer compat

Client open format support — 4 of 6 now loading:
- FULL: WOT/WHM terrain, PNG textures, WOM models
- LOAD: WOB buildings (converts to WMOModel, render pipeline TODO)
- DETECT: zone.json (scanned), JSON DBC (scanned)
2026-05-05 12:12:26 -07:00
Kelsi
aac854c8ad feat: client scans and logs available custom zones at startup
- Renderer::initializeRenderers() now scans custom_zones/ and output/
  for zone.json manifests on first initialization
- Logs all discovered custom zones with name, directory, and
  NPC/quest availability indicators
- One-time scan (cached after first run)
- Foundation for custom zone selection menu in client UI

Client open format support:
- FULL: WOT/WHM terrain, PNG textures, WOM models (load + render)
- DETECT: zone.json (scanned at startup), WOB buildings, JSON DBC
2026-05-05 12:05:00 -07:00
Kelsi
2d417aa125 feat: client detects WOB buildings and JSON DBCs from custom zones
- TerrainManager now checks for .wob files before loading WMO buildings
  (searches custom_zones/buildings/ and output/MapName/buildings/)
- AssetManager::loadDBC() scans custom_zones/*/data/ for JSON DBC
  overrides exported by the editor
- WOB detection logs when found (full WOB→WMOModel conversion pending)
- JSON DBC detection logs when found (full JSON→DBCFile loading pending)

Client open format support status:
- WOT/WHM terrain: FULL (loads and renders)
- PNG textures: FULL (override system)
- WOM models: FULL (loads and renders)
- zone.json: DETECTION (CustomZoneDiscovery scans)
- WOB buildings: DETECTION (found, conversion pending)
- JSON DBC: DETECTION (found, loading pending)
2026-05-05 12:00:31 -07:00
Kelsi
8517ae3778 feat: client loads WOM open models from custom zones automatically
- TerrainManager now checks for .wom files before loading M2 models
- Searches custom_zones/models/ and output/MapName/models/ directories
- Converts WOM vertices/indices to M2Model struct for the renderer
- Full pipeline: editor exports M2→WOM → client loads WOM directly
- Falls back to standard M2 loading if no WOM found

The client can now render custom zone content using entirely
open formats: WOT/WHM terrain + WOM models + PNG textures
2026-05-05 10:36:46 -07:00
Kelsi
954894460e feat: integrate Wowee Open Terrain loader into client terrain pipeline
The wowee client can now load custom zones exported from the editor
using the novel WOT/WHM format — no Blizzard files needed.

Loading priority in TerrainManager::prepareTile():
1. Check custom_zones/{mapName}/{mapName}_{x}_{y}.wot/.whm
2. Check output/{mapName}/{mapName}_{x}_{y}.wot/.whm (editor output)
3. Fall back to World\Maps\...\*.adt (standard extracted data)

Pipeline:
- WoweeTerrainLoader in src/pipeline/ (shared between client + editor)
- Loads .whm binary heightmap (WHM1 magic, 256 chunks × 145 floats)
- Loads .wot JSON metadata (textures, layers, holes, water)
- Populates the same ADTTerrain struct the mesh generator uses
- obj0 merge only runs for ADT-loaded tiles (custom zones have no obj0)

To use: export zone from editor → files appear in output/ → client
loads them automatically on next terrain request for that map name.
2026-05-05 09:56:24 -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
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
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
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
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
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
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
7b746a3045 fix(rendering): enable backface culling for one-sided M2 materials (#57)
All M2 pipelines used VK_CULL_MODE_NONE, so back-facing polygons always
rendered.  On NPCs whose torso meshes are single-layer geometry this
made the interior cavity visible through the back.

Create backface-culled pipeline variants (VK_CULL_MODE_BACK_BIT) and
select them at draw time unless the material has the TwoSided flag
(0x04).  Foliage/ground-detail forceCutout batches and the shadow
pipeline keep VK_CULL_MODE_NONE since those cards are inherently
two-sided.
2026-04-06 18:18:05 -07:00
Kelsi
f79110cb14 fix(rendering): clear M2 texture cache on character switch
M2Renderer::clear() reset descriptor pools but left the texture cache
and failed-texture tracking intact.  On re-login the stale cache filled
the budget, failedTextureRetryAt_ blocked reloads, and the client
entered an infinite model-load loop.  Match the cleanup already done in
shutdown() and CharacterRenderer::clear().
2026-04-06 18:06:03 -07:00
Kelsi Rae Davis
996dc56691
Merge pull request #55 from ldmonster/chore/code-quality-cleaup
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] Code Quality & DRY/KISS Cleanup
2026-04-06 13:46:35 -07:00
Kelsi Rae Davis
20e016798f
Merge pull request #54 from ldmonster/fix/memory-pressure-and-hardening
[fix] Memory, Threading & Network Hardening
2026-04-06 13:45:31 -07:00
Kelsi Rae Davis
5d0d140c61
Merge pull request #52 from ldmonster/feat/hiz-occlusion-culling
[feat] rendering: Hierarchical-Z occlusion culling
2026-04-06 13:44:44 -07:00
Pavel Okhlopkov
97106bd6ae fix(render): code quality cleanup
Magic number elimination:
- Create protocol_constants.hpp, warden_constants.hpp,
  render_constants.hpp, ui_constants.hpp
- Replace ~55 magic numbers across game_handler, warden_handler,
  m2_renderer_render

Reduce nesting depth:
- Extract 5 parseEffect* methods from handleSpellLogExecute
  (max indent 52 → 16 cols)
- Extract resolveSpellSchool/playSpellCastSound/playSpellImpactSound
  from 3× duplicate audio blocks in handleSpellGo
- Flatten SMSG_INVENTORY_CHANGE_FAILURE with early-return guards
- Extract drawScreenEdgeVignette() for 3 duplicate vignette blocks

DRY extract patterns:
- Replace 12 compound expansion checks with isPreWotlk() across
  movement_handler (9), chat_handler (1), social_handler (1)

const to constexpr:
- Promote 23+ static const arrays/scalars to static constexpr across
  12 source files

Error handling:
- Convert PIN auth from exceptions to std::optional<PinProof>
- Add [[nodiscard]] to 15+ initialize/parse methods
- Wrap ~20 unchecked initialize() calls with LOG_WARNING/LOG_ERROR

Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
2026-04-06 22:43:13 +03:00
Pavel Okhlopkov
312994be83 world loading memory pressure detector
Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
2026-04-06 21:05:20 +03:00
Pavel Okhlopkov
4b9b3026f4 feat(rendering): add HiZ occlusion culling & fix WMO interior shadows
Implement GPU-driven Hierarchical-Z occlusion culling for M2 doodads
using a depth pyramid built from the previous frame's depth buffer.
The cull shader projects bounding spheres via prevViewProj (temporal
reprojection) and samples the HiZ pyramid to reject hidden objects
before the main render pass.

Key implementation details:
- Separate early compute submission (beginSingleTimeCommands + fence
  wait) eliminates 2-frame visibility staleness
- Conservative safeguards prevent false culls: screen-edge guard,
  full VP row-vector AABB projection (Cauchy-Schwarz), 50% sphere
  inflation, depth bias, mip+1, min screen size threshold, camera
  motion dampening (auto-disable on fast rotations), and per-instance
  previouslyVisible flag tracking
- Graceful fallback to frustum-only culling if HiZ init fails

Fix dark WMO interiors by gating shadow map sampling on isInterior==0
in the WMO fragment shader. Interior groups (flag 0x2000) now rely
solely on pre-baked MOCV vertex-color lighting + MOHD ambient color.
Disable interiorDarken globally (was incorrectly darkening outdoor M2s
when camera was inside a WMO). Use isInsideInteriorWMO() instead of
isInsideWMO() for correct indoor detection.

New files:
- hiz_system.hpp/cpp: pyramid image management, compute pipeline,
  descriptors, mip-chain build dispatch, resize handling
- hiz_build.comp.glsl: MAX-depth 2x2 reduction compute shader
- m2_cull_hiz.comp.glsl: frustum + HiZ occlusion cull compute shader
- test_indoor_shadows.cpp: 14 unit tests for shadow/interior contracts

Modified:
- CullUniformsGPU expanded 128->272 bytes (HiZ params, viewProj,
  prevViewProj)
- Depth buffer images gain VK_IMAGE_USAGE_SAMPLED_BIT for HiZ reads
- wmo.frag.glsl: interior branch before unlit, shadow skip for 0x2000
- Render graph: hiz_build + compute_cull disabled (run in early compute)
- .gitignore: ignore compiled .spv binaries
- MEGA_BONE_MAX_INSTANCES: 2048 -> 4096

Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
2026-04-06 16:40:59 +03:00
Kelsi
758f7b27b9 fix(logging): downgrade remaining emote registry diagnostics to DEBUG
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
Remove temporary NPC death diagnostic from entity_controller and
downgrade emote override/load-count messages from WARNING to DEBUG.
2026-04-05 20:58:11 -07:00
Kelsi
c2681eead1 refactor: downgrade shutdown, warden, and misc diagnostics to DEBUG
Demote 44 more LOG_WARNING messages to LOG_DEBUG: warden module chunk
progress, entire shutdown/teardown sequence, transport manager connect,
inventory right-click slot, and warden handshake diagnostics. Keeps real
warnings (texture not found, slow handlers, stalls, integrity hash)
visible in the log.
2026-04-05 20:18:39 -07:00
Kelsi
069dd36698 fix(parsing): bail on suspicious maskBlockCount in CREATE_OBJECT blocks
When spline parsing consumes the wrong number of bytes, the subsequent
blockCount read lands on garbage data (e.g. 71 instead of ~5 for UNIT).
Previously the parser logged a warning but continued, reading garbage
mask/field data until hitting truncation. Now it returns false for
CREATE_OBJECT blocks with suspicious counts, letting the block loop
skip cleanly to the next entity.

Also downgrade ~44 diagnostic LOG_WARNING messages to LOG_DEBUG across
17 files (equipment, transport, DBC, heartbeat, chat, GO raypick, etc.)
to reduce log noise and make real warnings visible.
2026-04-05 20:12:17 -07:00
Kelsi
e32f4fbff9 Merge master into chore/god-object-decomposition-2nd
Resolve conflicts:
- audio_callback_handler.cpp: keep PR's animation_controller include
- movement_handler.cpp: use PR accessors with master's transportResolved logic
- world_packets.cpp: keep PR's decomposed version (functions moved to split files)

Apply overkill field fix to world_packets_entity.cpp (WotLK
SMSG_ATTACKERSTATEUPDATE missing uint32 overkill between damage and
subDamageCount).
2026-04-05 19:42:25 -07:00
Kelsi
0a22b0d41a refactor: remove debug diagnostics from combat and animation code 2026-04-05 19:10:42 -07:00
Kelsi
53639f9592 fix(animation): re-probe capabilities on melee swing, add combat diagnostics
If the capability probe ran before the model was fully loaded, all melee
animation IDs would be 0 and auto-attack swings would silently fall back
to STAND (no visible animation). Now re-probes when a melee swing fires
but hasMelee is false.

Added WARNING-level logging to triggerMeleeSwing and CombatFSM to
diagnose the night elf stationary combat animation issue.
2026-04-05 17:52:18 -07:00
Kelsi
722c065089 fix(emotes): use EMOTE_TALK for /fart and /stink (no dedicated anim in DBC) 2026-04-05 17:33:42 -07:00
Kelsi
aff545edef fix(rendering): emote animations, WMO portal culling, transport teleport
Emote animations: fix DBC chain for /laugh, /flirt, /sleep, /fart, /stink.
Previously all emotes with AnimID=0 used emoteRef as animId (wrong DBC
record IDs). Now resolves through Emotes.dbc properly, with per-emote
overrides for emotes whose DBC chain yields 0. Adds Emotes.dbc load
failure warning and diagnostic logging.

WMO culling: skip portal culling when camera is outside all groups (fixes
vanishing Stormwind ground tiles). Also handle indoor/outdoor AABB overlap
by showing all groups when position is in both indoor and outdoor AABBs.

Transport: clear ONTRANSPORT flag and transport state when transport not
found, preventing stale transport data from teleporting player to map
origin. Add area trigger safety net near (0,0,0) on Eastern Kingdoms.
2026-04-05 17:25:25 -07:00
Paul
52098cc704 ARM64 fix 2026-04-05 20:41:33 +03:00
Paul
34c0e3ca28 chore(refactor): god-object decomposition and mega-file splits
Split all mega-files by single-responsibility concern and
partially extracting AudioCoordinator and
OverlaySystem from the Renderer facade. No behavioral changes.

Splits:
- game_handler.cpp (5,247 LOC) → core + callbacks + packets (3 files)
- world_packets.cpp (4,453 LOC) → economy/entity/social/world (4 files)
- game_screen.cpp  (5,786 LOC) → core + frames + hud + minimap (4 files)
- m2_renderer.cpp  (3,343 LOC) → core + instance + particles + render (4 files)
- chat_panel.cpp   (3,140 LOC) → core + commands + utils (3 files)
- entity_spawner.cpp (2,750 LOC) → core + player + processing (3 files)

Extractions:
- AudioCoordinator: include/audio/ + src/audio/ (owned by Renderer)
- OverlaySystem: include/rendering/ + src/rendering/overlay_system.*

CMakeLists.txt: registered all 17 new translation units.
Related handler/callback files: minor include fixups post-split.
2026-04-05 19:30:44 +03:00
Kelsi Davis
8bb3702af4 perf(rendering): reduce GPU cull buffer and add CPU fallback for overflow
Halve MAX_CULL_INSTANCES to 32768 and iterate all instances in render,
falling back to CPU frustum culling for any beyond the GPU buffer.
2026-04-05 03:25:27 -07:00
Kelsi Davis
b62df70d09 fix(rendering): game objects invisible due to GPU cull instance limit
MAX_CULL_INSTANCES was 16384 but game object instances were allocated
at indices 20000+, beyond the cull buffer. Increased to 65536.
Also compute fallback boundRadius from vertex extents when M2 header
reports 0, and seed bones for global-sequence-only animated models.
2026-04-05 03:18:52 -07:00