Commit graph

1561 commits

Author SHA1 Message Date
Kelsi
acbfe99401 anim: also trigger animation update on walk/run transitions for creatures
Extend the locomotion state-change detection to include the WALKING
movement flag. Previously a creature that switched from walking to
running (or vice versa) while staying in the moving state would keep
playing the wrong animation because only the moving/idle transition
was tracked.

Add creatureWasWalking_ alongside creatureWasSwimming_ and
creatureWasFlying_; guard the walking check with isMovingNow to avoid
spurious triggers when the flag flips while the creature is idle.
Clear and erase the new map at world reset and creature/player despawn.
2026-03-10 12:04:59 -07:00
Kelsi
2717018631 anim: fix creature animation not updating on swim/fly state transitions
Previously, the animation update for other entities (creatures, players)
was only triggered when the moving/idle state changed. This meant a
creature landing while still moving would stay in FlyForward instead of
switching to Run, and a flying-idle creature touching down would keep
the FlyIdle animation instead of returning to Stand.

Fix: track creatureWasSwimming_ and creatureWasFlying_ alongside
creatureWasMoving_, and fire the animation update whenever any of the
three locomotion flags change. Clean up the new maps on world reset and
on per-creature despawn.
2026-03-10 12:03:33 -07:00
Kelsi
8a20ccb69d anim: fix fly animation IDs to 158/159 (FlyIdle/FlyForward) 2026-03-10 11:58:19 -07:00
Kelsi
30a65320fb anim: add flying state tracking and Fly/FlyIdle animation selection for entities
Previously the move-flags callback only tracked SWIMMING and WALKING,
so flying players/mounts always played Run(5) or Stand(0) animations
instead of Fly(61)/FlyIdle(60).

Changes:
- Add creatureFlyingState_ (mirroring creatureSwimmingState_) set by
  the FLYING flag (0x01000000) in unitMoveFlagsCallback_.
- Update animation selection: moving+flying → 61 (Fly/FlyForward),
  idle+flying → 60 (FlyIdle/hover). Flying takes priority over swim
  in the priority chain: fly > swim > walk > run.
- Clear creatureFlyingState_ on world reset.
2026-03-10 11:56:50 -07:00
Kelsi
a33119c070 net: dispatch MSG_MOVE_ROOT and MSG_MOVE_UNROOT for other entities 2026-03-10 11:54:15 -07:00
Kelsi
1180f0227c rendering: fix WMO portal AABB transform for rotated WMOs
isPortalVisible() was computing the world-space AABB by directly
transforming pMin/pMax with the model matrix. This is incorrect for
rotated WMOs — when the model matrix includes rotations, components can
be swapped or negated, yielding an inverted AABB (worldMin.x >
worldMax.x) that causes frustum.intersectsAABB() to fail.

Fix: transform all 8 corners of the portal bounding box and take the
component-wise min/max, which gives the correct world-space AABB for any
rotation/scale. This was the root cause of portals being incorrectly
culled in rotated WMO instances (e.g. many dungeon and city WMOs).

Also squash the earlier spline-speed no-op fix (parse guid + float
instead of consuming the full packet for SMSG_SPLINE_SET_FLIGHT_SPEED
and friends) into this commit.
2026-03-10 11:51:43 -07:00
Kelsi
8152314ba8 net: dispatch MSG_MOVE_SET_PITCH, GRAVITY_CHNG, UPDATE_CAN_FLY, UPDATE_CAN_TRANSITION_SWIM_FLY
These four movement-broadcast opcodes (server relaying another player's
movement packet) were not dispatched at all, causing nearby entity
positions to be silently dropped for pitch changes and gravity/fly state
broadcasts. Also add them to the kMoveOpcodes batch-parse table used by
SMSG_COMPRESSED_MOVES, and parse SMSG_SPLINE_SET_FLIGHT/WALK/etc. speeds
properly instead of consuming the whole packet.
2026-03-10 11:44:57 -07:00
Kelsi
cfc6dc37c8 net: fix SMSG_SPLINE_MOVE_UNSET_FLYING and parse UNROOT/UNSET_HOVER/WATER_WALK
Previously these four spline-move opcodes were silently consumed with
packet.setReadPos(getSize()), skipping even the packed-GUID read.

- SMSG_SPLINE_MOVE_UNSET_FLYING: now reads packed guid and fires
  unitMoveFlagsCallback_(guid, 0) to clear the flying animation state on
  nearby entities (counterpart to SMSG_SPLINE_MOVE_SET_FLYING).
- SMSG_SPLINE_MOVE_UNROOT, SMSG_SPLINE_MOVE_UNSET_HOVER,
  SMSG_SPLINE_MOVE_WATER_WALK: now properly parse the packed guid instead
  of consuming the full packet; no animation-state callback needed.
2026-03-10 11:42:54 -07:00
Kelsi
84558fda69 net: ack SMSG_MOVE_SET/UNSET_CAN_TRANSITION_SWIM_FLY and SMSG_MOVE_SET_COLLISION_HGT
These three server-push opcodes were silently consumed without sending
the required client acks, causing the server to stall waiting for
confirmation before granting the capability.

- SMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY →
  CMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY_ACK (via handleForceMoveFlagChange)
- SMSG_MOVE_UNSET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY →
  same ack opcode (no separate unset ack exists in WotLK 3.3.5a)
- SMSG_MOVE_SET_COLLISION_HGT → CMSG_MOVE_SET_COLLISION_HGT_ACK via new
  handleMoveSetCollisionHeight() which appends the float height after the
  standard movement block (required by server-side ack validation)
2026-03-10 11:40:46 -07:00
Kelsi
c72186fd11 net: ack SMSG_MOVE_GRAVITY_DISABLE/ENABLE and fix fall-through bug
These opcodes were inadvertently falling through to the LAND_WALK
handler (same case label), causing incorrect CMSG_MOVE_WATER_WALK_ACK
acks to be sent for gravity changes. Split into dedicated cases that
send CMSG_MOVE_GRAVITY_DISABLE_ACK and CMSG_MOVE_GRAVITY_ENABLE_ACK
respectively, as required by the server protocol.
2026-03-10 11:36:06 -07:00
Kelsi
b3441ee9ce net: ack SMSG_MOVE_LAND_WALK and SMSG_MOVE_NORMAL_FALL
These are the removal counterparts to SMSG_MOVE_WATER_WALK and
SMSG_MOVE_FEATHER_FALL. The server expects the matching ack with the
flag cleared; previously these packets were consumed silently which
could leave the server's state machine waiting for an acknowledgement.
2026-03-10 11:34:56 -07:00
Kelsi
ca141bb131 net: send CMSG_MOVE_FLIGHT_ACK in response to SMSG_MOVE_SET/UNSET_FLIGHT
SMSG_MOVE_SET_FLIGHT and SMSG_MOVE_UNSET_FLIGHT were previously consumed
silently without sending the required ack. Most server implementations
expect CMSG_MOVE_FLIGHT_ACK before toggling the FLYING movement flag on
the player; without it the server may not grant or revoke flight state.
Also updates movementInfo.flags so subsequent movement packets reflect
the FLYING flag correctly.
2026-03-10 11:33:47 -07:00
Kelsi
71cabddbd6 net: add MSG_MOVE_START_DESCEND to other-player movement dispatch
The complement to MSG_MOVE_START_ASCEND was missing from both the
main dispatch switch and the compressed-moves opcode table, causing
downward vertical movement of flying players to be dropped.
2026-03-10 11:30:55 -07:00
Kelsi
785df23f1b net: dispatch flying movement opcodes (pitch up/down, ascend/descend) for other players
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
MSG_MOVE_START_PITCH_UP, MSG_MOVE_START_PITCH_DOWN, MSG_MOVE_STOP_PITCH,
MSG_MOVE_START_ASCEND, MSG_MOVE_STOP_ASCEND were defined in the opcode
table but never routed. The server relays these when another player
pitches or ascends/descends while flying. Without dispatch, position
updates embedded in these packets were silently dropped, causing flying
players to appear to not move vertically. Also adds these to the
compressed-moves opcode recognition array.
2026-03-10 11:29:13 -07:00
Kelsi
274419584e net: add MSG_MOVE_SET_WALK/RUN_MODE to compressed-moves batch dispatch
handleCompressedMoves uses a hardcoded opcode array to recognise which
sub-packets should be routed to handleOtherPlayerMovement. The two newly
dispatched opcodes were not in this list, so walk/run mode transitions
embedded in SMSG_COMPRESSED_MOVES / SMSG_MULTIPLE_MOVES batches were
silently dropped.
2026-03-10 11:25:58 -07:00
Kelsi
d96a87aafc net: dispatch MSG_MOVE_SET_WALK_MODE and MSG_MOVE_SET_RUN_MODE through handleOtherPlayerMovement
These two opcodes were defined in the opcode table but never routed to
handleOtherPlayerMovement. The server sends them when another player
explicitly toggles walk/run mode. Without dispatch, the WALKING flag
from these packets was never processed, so other players appeared to
always run even after switching to walk mode (until the next heartbeat).
2026-03-10 11:24:15 -07:00
Kelsi
ec665bae25 net: store moveFlags in UpdateBlock for Classic and TBC parsers
Extends the cold-join fix (block.moveFlags) to the Classic and TBC
parseMovementBlock implementations so that SMSG_UPDATE_OBJECT CREATE
packets on Classic/TBC servers also initialise entity swim/walk state
from the spawn-time movement flags via unitMoveFlagsCallback_.
2026-03-10 11:21:13 -07:00
Kelsi
48d21f97bd net: correct pitch condition to use FLYING=0x01000000 not SPLINE_ELEVATION=0x02000000
The previous fix added SWIMMING (0x00200000) correctly but kept 0x02000000
which is SPLINE_ELEVATION (smooth vertical spline offset), not the FLYING
flag. WotLK 3.3.5a FLYING = 0x01000000; pitch should be read when SWIMMING
or FLYING are active. This corrects the condition and updates the comment.
2026-03-10 11:16:40 -07:00
Kelsi
863ea742f6 net/game: initialise entity swim/walk state from spawn packet and SPLINE_MOVE opcodes
UpdateBlock now stores moveFlags from the LIVING movement block so the
cold-join problem is fixed: entities already swimming or walking when the
client joins get their animation state correctly initialised from the
SMSG_UPDATE_OBJECT CREATE_OBJECT packet rather than waiting for the next
MSG_MOVE_* heartbeat.

Additionally, SMSG_SPLINE_MOVE_START_SWIM, SMSG_SPLINE_MOVE_STOP_SWIM,
SMSG_SPLINE_MOVE_SET_WALK_MODE, SMSG_SPLINE_MOVE_SET_RUN_MODE, and
SMSG_SPLINE_MOVE_SET_FLYING now fire unitMoveFlagsCallback_ with
synthesised flags so explicit server-driven mode transitions update
animation state immediately without waiting for a heartbeat.
2026-03-10 11:14:58 -07:00
Kelsi
3439df0333 net: fix UPDATEFLAG_LIVING pitch misalignment for swimming entities
parseMovementBlock was checking moveFlags & 0x02000000 for the pitch
field, but SWIMMING is 0x00200000 in WotLK 3.3.5a. Swimming NPCs and
players in SMSG_UPDATE_OBJECT packets never triggered the pitch read,
so the fallTime/jumpData/splineElevation fields were read from the wrong
offsets, producing incorrect positions and orientations.

Fix: check both SWIMMING (0x00200000) and FLYING (0x02000000), matching
the WotLK format — same condition used in the write path.
2026-03-10 11:03:33 -07:00
Kelsi
d7ebc5c8c7 game/rendering: drive Walk(4) and swim state from movement flags
Add UnitMoveFlagsCallback fired on every MSG_MOVE_* with the raw
movement flags field. Application.cpp uses it to update swimming
and walking state from any packet, not just explicit START_SWIM/
STOP_SWIM opcodes — fixing cold-join cases where a player is already
swimming when we enter the world.

Per-frame animation sync now selects Walk(4) when the WALKING flag is
set, Run(5) otherwise, and Swim(42)/SwimIdle(41) when swimming.
UnitAnimHintCallback is simplified to jump (38=JumpMid) only.
2026-03-10 10:55:23 -07:00
Kelsi
333ada8eb6 rendering/game: track per-entity swim state for correct water animations
- Add creatureSwimmingState_ map to track which units are swimming
- unitAnimHintCallback with animId=42 (Swim): marks entity as swimming
- unitAnimHintCallback with animId=0 (MSG_MOVE_STOP_SWIM): clears swim state
- Per-frame sync: uses Swim(42)/SwimIdle(41) when swimming, Run(5)/Stand(0) otherwise
  — creatures/players now show SwimIdle when standing still in water
- Clear creatureSwimmingState_ on creature/player despawn and world reset
2026-03-10 10:36:45 -07:00
Kelsi
14c2bc97b1 rendering/game: fix other-player movement animations and add jump/swim hints
- MSG_MOVE_STOP/STOP_STRAFE/STOP_TURN/STOP_SWIM/FALL_LAND: snap entity to
  stop position (duration=0) and pass durationMs=0 to renderer so the
  Run-animation flash is suppressed; per-frame sync plays Stand on next frame
- MSG_MOVE_JUMP: fire new UnitAnimHintCallback with anim 38 (JumpMid) so
  other players and NPCs visually leave the ground during jumps
- MSG_MOVE_START_SWIM: fire UnitAnimHintCallback with anim 42 (Swim)
- Wire up UnitAnimHintCallback in application.cpp; skips Death (anim 1)
2026-03-10 10:30:50 -07:00
Kelsi
137b25f318 rendering: fix NPC movement animation IDs and remove redundant player anim
The renderer's CharAnimState machine already drives player character
animations (Run=5, Walk=4, Jump, Swim, etc.) — remove the conflicting
camera controller code added in the previous commit.

Fix creature movement animations to use the correct WoW M2 IDs:
4=Walk, 5=Run. Both the per-frame sync loop and the SMSG_MONSTER_MOVE
spline callback now use Run (5) for NPC movement.
2026-03-10 10:19:13 -07:00
Kelsi
279c30367a rendering: use Walk (anim 5) vs Run (anim 4) based on movement pace
CameraController now plays Walk (5) for backpedal/slow pace and Run (4)
for forward running (runPace), matching WoW's animation convention.
Also handles transitions between Walk and Run while already moving.
2026-03-10 10:10:46 -07:00
Kelsi
baaa063342 rendering: play Run animation during SMSG_MONSTER_MOVE spline paths
creatureMoveCallback now plays anim 4 (Run) when a spline move begins
(durationMs > 0), mirroring the per-frame sync logic so NPC/player
characters animate correctly during server-driven path moves as well
as position-sync moves.
2026-03-10 10:09:02 -07:00
Kelsi
4e137c4061 rendering: drive Run/Stand animations from actual movement state
CameraController now transitions the player character to Run (anim 4)
on movement start and back to Stand (anim 0) on stop, guarded by a
prevPlayerMoving_ flag so animation time is not reset every frame.
Death animation (anim 1) is never overridden.

Application creature sync similarly switches creature models to Run (4)
when they move between server positions and Stand (0) when they stop,
with per-guid creatureWasMoving_ tracking to avoid per-frame resets.
2026-03-10 10:06:56 -07:00
Kelsi
c8d9d6b792 rendering/game: make player model semi-transparent in ghost form
Add GhostStateCallback to GameHandler, fired when PLAYER_FLAGS_GHOST
transitions on or off in UPDATE_OBJECT / login detection. Add
setInstanceOpacity() to CharacterRenderer to directly set opacity
without disturbing fade-in state. Application wires the callback to
set opacity 0.5 on ghost entry and 1.0 on resurrect.
2026-03-10 09:57:24 -07:00
Kelsi
366321042f rendering/game: sync camera sit state from server-confirmed stand state
Add CameraController::setSitting() and call it from the StandStateCallback
so the camera blocks movement when the server confirms the player is
sitting or kneeling (stand states 1-6, 8). This prevents the player
from sliding across the ground after sitting.

Death (state 7) deliberately leaves sitting=false so the player can
still respawn/move after death without input being blocked.
2026-03-10 09:51:15 -07:00
Kelsi
9f3c236c48 game/rendering: drive player stand-state animation from SMSG_STANDSTATE_UPDATE
Add StandStateCallback to GameHandler, fired when the server confirms
a stand state change (SMSG_STANDSTATE_UPDATE). Connect in Application
to map the WoW stand state (0-8) to M2 animation IDs on the player
character model:
  - 0 = Stand → anim 0 (Stand)
  - 1-6 = Sit variants → anim 27 (SitGround)
  - 7 = Dead → anim 1 (Death)
  - 8 = Kneel → anim 72 (Kneel)

Sit and Kneel animations are looped so the held-pose frame stays
visible; Death stays on the final frame.
2026-03-10 09:46:46 -07:00
Kelsi
59c50e3beb game/rendering: play SpellCast animation during SMSG_SPELL_START
Add SpellCastAnimCallback to GameHandler, triggered on SMSG_SPELL_START
(start=true) and cleared on SMSG_SPELL_GO / SMSG_SPELL_FAILURE
(start=false) for both the player and other units.

Connect the callback in Application to play animation 3 (SpellCast) on
the player character, NPCs, and other players when they begin a cast.
The cast animation is one-shot (loop=false) so it auto-returns to Stand
when complete via the existing return-to-idle logic.

Also fire stop-cast on spell failure to cancel any stuck cast pose.
2026-03-10 09:42:17 -07:00
Kelsi
c20d7c2638 rendering: return to Stand after one-shot emote animations complete
When a non-looping animation (e.g. wave, cheer, laugh emote) reaches
its end, transition back to Stand (animation 0) rather than freezing
on the last frame. Death (animation 1) is excluded — it stays on the
final frame as expected.

Fixes NPCs and players getting stuck in emote poses after SMSG_EMOTE.
2026-03-10 09:36:58 -07:00
Kelsi
60b93cdfd9 rendering/game: remove leftover debug dump I/O from hot paths
Remove active file-I/O debug block in character_renderer.cpp that
wrote composite textures as raw binary files to /tmp on every texture
composite generation. Remove the now-unused <fstream> include.

Remove the 10-shot hex dump of decompressed SMSG_MONSTER_MOVE payloads
in game_handler.cpp (dumpCount static); format has been confirmed.
2026-03-10 09:30:59 -07:00
Kelsi
55895340e9 game: connect emote animation callback to creature/player renderers
SMSG_EMOTE packets for NPCs and other players were received but the
emoteAnimCallback_ was never wired to the rendering layer.  Register
the callback in application.cpp so that when the server sends an emote
animation ID, the corresponding CharacterRenderer instance plays it as
a one-shot animation (loop=false), falling back to idle on completion.

Lookups check creatureInstances_ first, then playerInstances_ so both
NPCs and other online players respond to server emote packets.
2026-03-10 09:25:58 -07:00
Kelsi
b2dccca58c rendering: re-enable WMO camera collision with asymmetric smoothing
Previously disabled because the per-frame raycast caused erratic zoom
snapping at doorway transitions.  Re-enable using an asymmetrically-
smoothed collision limit: pull-in reacts quickly (τ≈60 ms) to prevent
the camera from ever visibly clipping through walls, while recovery is
slow (τ≈400 ms) so walking through a doorway zooms back out gradually
instead of snapping.

Uses wmoRenderer->raycastBoundingBoxes() which already has strict wall
filters (|normal.z|<0.20, surface-alignment check, ±0.9 height band)
to ignore floors, ramps, and arch geometry.
2026-03-10 09:13:31 -07:00
Kelsi
c622e547c9 game: clear in-flight NPC/GO query sets on disconnect
pendingCreatureQueries and pendingGameObjectQueries_ were never cleared on
disconnect. If a query was sent but the response lost (e.g. server
disconnect mid-flight), the entry would remain in the pending set after
reconnect, causing queryCreatureInfo/queryGameObjectInfo to silently skip
re-issuing the query — leaving NPC and GO names unpopulated for those
entries.

Clear both sets on disconnect so reconnect sees them as unqueried and
re-sends the queries as needed. creatureInfoCache/gameObjectInfoCache_ are
intentionally preserved across sessions to avoid re-querying entries whose
responses did arrive.
2026-03-10 09:01:34 -07:00
Kelsi
6763cfcda0 game: fix log level for GameObject CREATE messages (WARNING → DEBUG)
Every GameObject CREATE block was logged at WARNING level, spamming the
warning log with doors, chests, and other world objects. Demote to DEBUG
since this is routine spawn traffic; keep transport detection at INFO since
those are noteworthy.
2026-03-10 09:00:17 -07:00
Kelsi
4f51103cdb game: clear permanent-failure and dead-creature caches on same-map reconnect
After reconnect, `creaturePermanentFailureGuids_` and `deadCreatureGuids_`
could retain stale entries for GUIDs not tracked in `creatureInstances_`
(creatures that failed to load or died before being spawned).  These stale
entries would silently block re-spawning or cause wrong death state on the
fresh CREATE_OBJECTs the server sends after reconnect.

Clear both caches in the reconnect-to-same-map path so server state is
authoritative after every reconnect.
2026-03-10 08:55:23 -07:00
Kelsi
a06ac018ea game: use targeted entity cleanup on reconnect to same map, preserving terrain
The previous reconnect fix caused loadOnlineWorldTerrain to run, which
cleared and reloaded all terrain tiles — unnecessarily heavy for a
reconnect where the map hasn't changed.

New path: when isInitialEntry=true and mapId==loadedMapId_, despawn all
tracked creature/player/GO instances from the renderer (proper cleanup),
clear all pending spawn queues, update player position, and return — the
terrain stays loaded and the server's fresh CREATE_OBJECTs repopulate
entities normally.
2026-03-10 08:50:25 -07:00
Kelsi
d22f4b30ac game: process partial UPDATE_OBJECT packets when a block parse fails
Previously, if any single block in an SMSG_UPDATE_OBJECT packet failed
to parse (e.g. unusual spline flags), the entire packet was dropped and
all entities in it were lost. On busy zones with many CREATE_OBJECTs in
one packet, one bad NPC movement block would silently suppress all NPCs
that followed it in the same packet.

- parseUpdateObject: break instead of return false on block failure,
  so already-parsed blocks are returned to the caller
- handleUpdateObject: fall through to process partial data when parsing
  returns false but some blocks were successfully parsed
2026-03-10 08:38:39 -07:00
Kelsi
54246345bb game: fix NPCs not spawning on reconnect to same map
On disconnect/reconnect to the same map, entityManager was not cleared
and creatureInstances_ still held old entries from the previous session.
When the server re-sent CREATE_OBJECT for the same GUIDs, the spawn
callback's early-return guard (creatureInstances_.count(guid)) silently
dropped every NPC re-spawn, leaving the world empty.

Fixes:
- disconnect() now calls entityManager.clear() to purge stale entities
- WorldEntryCallback gains a bool isInitialEntry parameter (true on first
  login or reconnect, false on in-world teleport/flight landing)
- Same-map optimization path skipped when isInitialEntry=true, so
  loadOnlineWorldTerrain runs its full cleanup and properly despawns old
  creature/player instances before the server refreshes them
2026-03-10 08:35:36 -07:00
Kelsi
baab997da8 ui: fix XP bar overlapping second action bar by positioning above both bars 2026-03-10 08:28:48 -07:00
Kelsi
0a157d3255 game: add area name cache from WorldMapArea.dbc for /who zone display and exploration messages
- Load WorldMapArea.dbc lazily on first use to build areaId→name lookup
- /who results now show [Zone Name] alongside level: 'Name - Level 70 [Stormwind City]'
- SMSG_EXPLORATION_EXPERIENCE now shows 'Discovered Elwynn Forest! Gained X experience.'
  instead of generic 'Discovered new area!' message when the zone name is available
- Cache is populated once per session and shared across both callsites
2026-03-10 08:06:21 -07:00
Kelsi
846ba58d2e ui,game: show creature names in quest kill count tracker and progress messages
Quest kill count tracker in the HUD now resolves creature names from the
cached creature query results and displays them as "Name: x/y" instead
of bare "x/y". The system chat progress message on kill also includes
the creature name when available, matching retail client behavior.
2026-03-10 07:45:53 -07:00
Kelsi
03c4d59592 game: fix talent state not resetting across login sessions
Replace static-local firstSpecReceived with talentsInitialized_ member
variable, reset in handleLoginVerifyWorld alongside other per-session
state. Also clear learnedTalents_, unspentTalentPoints_, and
activeTalentSpec_ at world entry so reconnects and character switches
start from a clean talent state instead of carrying over stale data.
2026-03-10 07:41:27 -07:00
Kelsi
2a9d26e1ea game,ui: add rest state tracking and rested XP bar overlay
- Track PLAYER_REST_STATE_EXPERIENCE update field for all expansions
  (WotLK=636, Classic=718, TBC=928, Turtle=718)
- Set isResting_ flag from SMSG_SET_REST_START packet
- XP bar shows rested bonus as a lighter purple overlay extending
  beyond the current fill to (currentXp + restedXp) position
- Tooltip text changes to "%u / %u XP  (+%u rested)" when bonus exists
- "zzz" indicator shown at bar right edge while resting
2026-03-10 07:35:30 -07:00
Kelsi
0ea8e55ad4 ui,game,pipeline: player nameplates always-on, level-up ring effect, vanilla tile fallback, warden null guard
- Nameplates: player names always rendered regardless of V-key toggle;
  separate cull distance 40u (players/target) vs 20u (NPCs); cyan name
  color for other players; fade alpha scales with cull distance
- Level-up: add expanding golden ring burst (3 staggered waves, 420u
  max radius) + full-screen flash to renderDingEffect(); M2 LevelUp.m2
  is still attempted as a bonus on top
- Vanilla tile loading: add AssetManager::setBaseFallbackPath() so that
  when the primary manifest is an expansion-specific DBC-only subset
  (e.g. Data/expansions/vanilla/), world terrain files fall back to
  the base Data/ extraction; wired in Application::initialize()
- Warden: map a null guard page at address 0x0 in the Unicorn emulator
  so NULL-pointer reads in the module don't crash with UC_ERR_MAP;
  execution continues past the NULL read for better diagnostics
2026-03-10 07:25:04 -07:00
Kelsi
3cdaf78369 game,warden,assets: fix unknown player names, warden heap overlap, and Vanilla Item.dbc
- game: clear pendingNameQueries on player out-of-range and DESTROY_OBJECT so
  re-entering players get a fresh name query instead of being silently skipped
- game: add 5s periodic name resync scan that re-queries players with empty names
  and no pending query, recovering from dropped CMSG_NAME_QUERY responses
- warden: fix UC_ERR_MAP by moving HEAP_BASE from 0x200000 to 0x20000000; the old
  heap [0x200000, 0x1200000) overlapped the module at 0x400000, causing Unicorn to
  reject the heap mapping and abort emulator initialisation
- warden: add early overlap check between module and heap regions to catch future
  layout bugs at init time
- assets: add loadDBCOptional() which logs at DEBUG level when a DBC is absent,
  for files that are not distributed on all expansions
- assets: use loadDBCOptional for Item.dbc (absent on Vanilla 1.12 clients) and
  fall back to server-sent itemInfoCache displayInfoId for NPC weapon resolution
2026-03-10 07:00:43 -07:00
Kelsi
dc2aab5e90 perf: limit NPC composite texture processing to 2ms per frame
processAsyncNpcCompositeResults() had no per-frame budget cap, so when
many NPCs finished async skin compositing simultaneously (e.g. right
after world load), all results were finalized in a single frame causing
up to 284ms frame stalls. Apply the same 2ms budget pattern used by
processAsyncCreatureResults. Load screen still processes all pending
composites without the cap (unlimited=true).
2026-03-10 06:47:33 -07:00
Kelsi
ac0fe1bd61 game: clear target auras when switching targets
setTarget() was not clearing targetAuras, leaving stale buff/debuff
icons from the previous target visible on the buff bar until the server
sent SMSG_AURA_UPDATE_ALL for the new target. Reset all slots to empty
on target change so the display is immediately correct.
2026-03-10 06:43:16 -07:00