- SMSG_SERVER_MESSAGE: parse type+string, show as [Server] chat message
- SMSG_CHAT_SERVER_MESSAGE: parse type+string, show as [Announcement]
- SMSG_AREA_TRIGGER_MESSAGE: parse len+string, display as system chat
- SMSG_TRIGGER_CINEMATIC: consume silently (no cinematic playback)
- Parse SMSG_LOOT_ROLL: if rollType==128 and it's our player, store
pending roll (itemId, slot, name from itemInfoCache_) and show popup;
otherwise show chat notification of another player's roll result
- Parse SMSG_LOOT_ROLL_WON: show winner announcement in chat with item
name and roll type/value
- sendLootRoll() sends CMSG_LOOT_ROLL (objectGuid+slot+rollType) and
clears pending roll state
- SMSG_LOOT_MASTER_LIST consumed silently (no UI yet)
- renderLootRollPopup(): ImGui window with Need/Greed/Disenchant/Pass
buttons; item name colored by quality (poor/common/uncommon/rare/epic/
legendary color scale)
- Parse SMSG_DUEL_REQUESTED: store challenger guid/name, set
pendingDuelRequest_ flag, show chat notification
- Parse SMSG_DUEL_COMPLETE: clear pending flag, notify on cancel
- Parse SMSG_DUEL_WINNER: show "X defeated Y in a duel!" chat message
- Handle SMSG_DUEL_OUTOFBOUNDS with warning message
- Add acceptDuel() method sending CMSG_DUEL_ACCEPTED (new builder)
- Wire forfeitDuel() to clear pendingDuelRequest_ on decline
- Add renderDuelRequestPopup() ImGui window (Accept/Decline buttons)
positioned near group invite popup; shown when challenge is pending
- Add DuelAcceptPacket builder to world_packets.hpp/cpp
- Parse SMSG_ACHIEVEMENT_EARNED (guid + achievementId + PackedTime date)
and fire AchievementEarnedCallback for self, chat notify for others
- Add renderAchievementToast() to GameScreen: slides in from right,
gold-bordered panel with "Achievement Earned!" title + ID, 5s duration
with 0.4s slide-in/out animation and fade at end
- Add triggerAchievementToast(uint32_t) public method on GameScreen
- Wire AchievementEarnedCallback in application.cpp
- Add playAchievementAlert() to UiSoundManager, loads
Sound\Interface\AchievementSound.wav with level-up fallback
- SMSG_ALL_ACHIEVEMENT_DATA silently consumed (no tracker UI yet)
- Add renderDungeonFinderWindow() with status display (not queued /
role check / queued+wait time / proposal / in dungeon / finished)
- Role checkboxes (Tank/Healer/DPS) and dungeon combo (25 entries
covering Vanilla, TBC, and WotLK including Random/Heroic)
- Accept/Decline buttons during Proposal state, Teleport button
while InDungeon, Leave Queue button while Queued/RoleCheck
- Store lfgProposalId_ on GameHandler so UI can pass it to
lfgAcceptProposal(); expose getLfgProposalId() and
getLfgTimeInQueueMs() getters
- Toggle window with I key (when chat input is not active)
SMSG_CLEAR_COOLDOWN: remove spell cooldown from cache and clear action bar
slot's remaining cooldown immediately (e.g. after item use, trinket proc).
SMSG_MODIFY_COOLDOWN: adjust an existing cooldown duration by a signed delta
in milliseconds (used by glyphs, Borrowed Time, etc.).
- SMSG_INSTANCE_SAVE_CREATED: notify player they are saved to instance
- SMSG_RAID_INSTANCE_MESSAGE: surface warning/save/welcome notifications
- SMSG_INSTANCE_RESET: clear matching lockout from cache + notify
- SMSG_INSTANCE_RESET_FAILED: report reset failure reason to player
- SMSG_INSTANCE_LOCK_WARNING_QUERY: auto-confirm with CMSG_INSTANCE_LOCK_RESPONSE
(entering a saved instance; sends acceptance so the player can proceed)
Parse and store dungeon/raid lockout data sent on login:
- mapId, difficulty, resetTime (Unix timestamp), locked, extended flags
- Stored in instanceLockouts_ vector for UI / LFG / dungeon state queries
- Public InstanceLockout struct + getInstanceLockouts() accessor
Add full client-side handling for the Looking For Dungeon system:
- SMSG_LFG_JOIN_RESULT: parse join success/failure, surface error message
- SMSG_LFG_QUEUE_STATUS: track dungeon ID, avg wait time, time in queue
- SMSG_LFG_PROPOSAL_UPDATE: detect proposal state (active/passed/failed)
- SMSG_LFG_ROLE_CHECK_UPDATE: surface role check progress/failure
- SMSG_LFG_UPDATE_PLAYER/PARTY: track queue state transitions
- SMSG_LFG_PLAYER_REWARD: show dungeon completion reward in chat
- SMSG_LFG_BOOT_PROPOSAL_UPDATE: show vote-kick status in chat
- SMSG_LFG_TELEPORT_DENIED: surface reason for teleport failure
- SMSG_LFG_DISABLED/OFFER_CONTINUE and informational packets consumed
Outgoing: lfgJoin(), lfgLeave(), lfgAcceptProposal(), lfgTeleport()
State: LfgState enum + lfgState_/lfgDungeonId_/lfgAvgWaitSec_ members
SMSG_MONSTER_MOVE_TRANSPORT (handleMonsterMoveTransport):
- Parse full WotLK 3.3.5a spline payload after the transport-local start
position: splineId, moveType, facing data (spot/target/angle), splineFlags,
Animation flag block, duration, Parabolic flag block, pointCount, waypoints
- Extract destination in transport-local server coords, compose to world
space via TransportManager, then call entity->startMoveTo() with the
spline duration so NPC movement interpolates smoothly instead of teleporting
- Handle all facing modes (FacingSpot/Target/Angle/normal) in transport space
- Degenerate cases (no spline data, moveType==1 stop, no transport manager)
fall back to snapping start position as before
SMSG_QUESTLOG_FULL:
- This opcode is a zero-payload notification meaning the quest log is at
capacity (25 quests); it does not carry quest log data
- Replace placeholder LOG_INFO stubs with a proper "Your quest log is full."
chat notification and a single LOG_INFO
SMSG_STANDSTATE_UPDATE:
- Parse uint8 stand state from server confirmation packet
- Store in standState_ member (0=stand, 7=dead, 8=kneel, etc.)
- Expose getStandState(), isSitting(), isDead(), isKneeling() accessors
SMSG_ITEM_PUSH_RESULT:
- Parse full WotLK 3.3.5a payload: guid, received, created, showInChat,
bagSlot, itemSlot, itemId, suffixFactor, randomPropertyId, count, totalCount
- Show "Received: <name> x<count>" chat notification when showInChat=1
- Queue item info lookup via queryItemInfo so name resolves asap
- Replace per-frame VMA alloc/free of material UBOs with a ring buffer in
CharacterRenderer (~500 allocations/frame eliminated)
- Batch all ready terrain tiles into a single GPU upload during load screen
(processAllReadyTiles instead of one-at-a-time with individual fence waits)
- Lift per-frame creature/GO spawn budgets during load screen warmup phase
- Add background world preloader: saves last world position to disk, pre-warms
AssetManager file cache with ADT files starting at app init (login screen)
so terrain workers get instant cache hits when Enter World is clicked
- Distance-filter expensive collision guard to 8-unit melee range
- Merge 3 CharacterRenderer update loops into single pass
- Time-budget instrumentation for slow update stages (>3ms threshold)
- Count-based async creature model upload budget (max 3/frame in-game)
- 1-per-frame game object spawn + per-doodad time budget for transport loading
- Use deque for creature spawn queue to avoid O(n) front-erase
- Fix NULL renderer pointers by moving TransportManager connection after
initializeRenderers for WMO-only maps
- Fix tram direction by negating DBC TransportAnimation X/Y local offsets
before serverToCanonical conversion
- Implement client-side M2 transport boarding via proximity detection
(server doesn't send transport attachment for trams)
- Use position-delta approach: player keeps normal movement while
transport's frame-to-frame motion is applied on top
- Prevent server movement packets from clearing client-side M2 transport
state (isClientM2Transport guard)
- Fix getPlayerWorldPosition for M2 transports: simple canonical addition
instead of render-space matrix multiplication
Classify light shafts, portals, spotlights, bubbles, and similar M2
doodads as spell effects so they render with additive blending instead
of as solid opaque objects.
Set camera yaw from server orientation on world load so teleports face
the correct direction.
Reduce area trigger minimum radius (3.0 sphere, 4.0 box) to prevent
premature portal firing near tram entrances.
WMO interior doodads (gears, decorations) were blocking player movement
via M2 collision. Skip collision for all WMO doodad M2 instances since
the WMO itself handles wall collision.
Also filter WMO wall collision using MOPY per-triangle flags: only
rendered+collidable triangles block the player, skipping invisible
collision hulls.
Revert tram portal extended range (no longer needed with collision fix).
Parse MOPY per-triangle flags in WMO groups and exclude detail/decorative
triangles (flag 0x04) from collision detection. This prevents invisible
walls from objects like gears and railings in WMO interiors.
Add WotLK area trigger IDs 2173/2175 to extended-range tram triggers.
Two bugs in SMSG_MESSAGECHAT parser for MONSTER_SAY/YELL/EMOTE:
1. Sender name included trailing null byte from server (nameLen includes
null terminator). The embedded null in std::string caused ImGui to
truncate the concatenated display string at the NPC name, hiding
" says: <message>" entirely.
2. Missing NamedGuid receiver name for non-player/non-pet targets. When
the receiver GUID is a creature, the server writes an additional
SizedCString (target name) that we weren't reading, shifting all
subsequent field reads.
Also adds MONSTER_WHISPER, MONSTER_PARTY, RAID_BOSS_EMOTE, RAID_BOSS_WHISPER
chat types with proper parsing and display formatting (says/yells/whispers).
Root cause: LOGIN_VERIFY_WORLD path did not set areaTriggerCheckTimer_ or
areaTriggerSuppressFirst_, so the Stockades exit portal (AT 503) fired
immediately on login, teleporting the player back to Stormwind and crashing
the GPU during the unexpected map transition.
Fixes:
- Set 5s area trigger cooldown + suppress-first in handleLoginVerifyWorld
(same as SMSG_NEW_WORLD handler already did for teleports)
- Add deviceLost_ flag to VkContext so beginFrame returns immediately once
VK_ERROR_DEVICE_LOST is detected, preventing infinite retry loops
- Track device lost from both fence wait and queue submit paths
- Extract initializeRenderers() from loadTestTerrain() so WMO-only maps
(dungeons/raids) initialize renderers directly without a dummy ADT path
- Defer setState(IN_GAME) until after processing any pending deferred world
entry, preventing brief IN_GAME flicker on the wrong map
- Remove verbose area trigger debug logging (every-second position spam)
- Fix WDT chunk magic constants to big-endian ASCII (matching ADTLoader)
- Add minimum effective size for box area triggers (90 units, like sphere 45-unit radius)
- Add areaTriggerSuppressFirst_ flag to prevent portal ping-pong on map transfer
- Add WMORenderer::clearAll() to clear models/textures on map change (prevents GPU crash)
- Increase WMO texture cache default to 8GB
- Fix setMapName called after loadTestTerrain so WMO renderer exists
- Save/restore player position around CMSG_AREATRIGGER to prevent bad DB persistence
- Fix shutdown hang: skip vmaDestroyAllocator (walked thousands of allocations),
replace unsafe pthread_timedjoin_np with plain join + early-exit checks in workers
- Bank window: full icon rendering, click-and-hold pickup (0.10s), drag-drop for
all bank slots including bank bag equip slots, same-slot drop detection
- Loading screen: process one tile per frame for live progress updates
- Camera reset: trust server position in online mode to avoid spawning under WMOs
- Fix PLAYER_BYTES/PLAYER_BYTES_2 field indices, preserve purchasedBankBagSlots
across inventory rebuilds, fix bank slot purchase result codes
Parse SMSG_PARTY_MEMBER_STATS and SMSG_PARTY_MEMBER_STATS_FULL packets
so party frames display health, power, level, and online status even
when group members are not nearby. Expansion-aware field sizes: uint16
health for Classic/TBC, uint32 for WotLK, plus per-expansion aura and
vehicle seat handling.
Implement generic handlers for force speed changes (walk, run back,
swim, swim back, flight, flight back, turn rate, pitch rate),
movement flag toggles (CAN_FLY, HOVER, feather fall, water walk),
and knockback ACKs. Fix SMSG_TIME_SYNC_REQ to respond with
CMSG_TIME_SYNC_RESP instead of silently dropping.
- Fix SMSG_ITEM_QUERY_SINGLE_RESPONSE parsing: read statsCount stat
pairs instead of always 10, use 2 damage entries (MAX_ITEM_PROTO_DAMAGES),
and parse item spell data (spellId + spellTrigger per slot)
- Pass item spell ID in CMSG_USE_ITEM packet so server processes item
use requests (spellId=0 caused silent server rejection)
- Add spellId parameter to buildUseItem interface across all expansions
- Fix spellbook mount tab to use SkillLine 777 (Mounts) instead of 762
(Riding), so known mount summon spells appear correctly
- Fix inventory right-click: use IsItemHovered+IsMouseClicked instead
of IsItemClicked for InvisibleButton (which only tracks left-clicks)
- Fix SlotKind enum declaration order in inventory_screen.hpp
- Add item class/subclass category filters (Weapon, Armor, etc.) with correct WoW 3.3.5a IDs
- Add sell item picker dropdown with icons and Create Auction button
- Add pagination (Prev/Next) for browse results with filter preservation
- Add Buy/Bid action buttons to Bids tab
- Add item icons and stat tooltips on hover across all three tabs
- Add Enter-to-search from name field and search delay countdown
- Parse SMSG_AUCTION_OWNER/BIDDER_NOTIFICATION into chat messages
- Auto-refresh browse results after bid/buyout using saved search params
- Clamp level range inputs to 0-80
- CMSG_SEND_MAIL now includes item GUIDs (up to 12 per WotLK)
- Right-click items in bags to attach when mail compose is open
- Compose window shows 12-slot attachment grid with item icons
- Click attached items to remove them
- Classic/Vanilla falls back to single item GUID format
Strip ~30 chrono::now() calls per frame from Application::update() and
GameHandler::update() that existed only for periodic LOG_DEBUG dumps.
Retain renderer timing used by the live performance HUD overlay.
Raise all texture cache defaults from 1GB to 4GB to reduce rejections.
Cap cache-full warnings (texture + model) to 3 messages per renderer,
and cap update block parse errors to 5 messages.
Strip 26 chrono::now() timing calls per frame from renderer update loop,
periodic LOG_INFO/LOG_DEBUG from terrain/character/quest/heartbeat paths,
and dead m2ProfileCounter variable.
- Cache non-renderable creature display IDs and fail-fast future spawn attempts
- Mark GUIDs tied to non-renderable displays as permanent failures to avoid long retry loops
- Skip queued spawn retry work immediately for known non-renderable display IDs
- Clear non-renderable display cache on expansion reload/logout
- Downgrade high-volume UNIT spawn logs to debug and fix mislabeled time-sync log