Store structured friend data (online status, level, area, class) that
was previously discarded in handleFriendList/handleContactList. New
ContactEntry struct lives in game_handler.hpp; getContacts() exposes it.
UI: the O-key Social window (formerly guild-only) now has a Friends tab.
- Shows online/offline status dot, name, level, and AFK/DND label
- Pressing O when not in a guild opens Social directly on the Friends tab
- The window title changed from "Guild" to "Social" for accuracy
- Non-guild players no longer get a "not in a guild" rejection on O press
Raid frames:
- When groupType=1 (raid), render compact grid-style raid frames instead
of the vertical party list that would overflow for 25/40-man groups
- Members organized by subgroup (G1-G8), up to 5 rows per subgroup column
- Each cell shows: name, health bar (green/yellow/red), power bar (class color)
- Clicking a cell targets the member; border highlight for current target
- Frames anchored above action bar area, centered horizontally
Quest log scroll-to-quest:
- openAndSelectQuest(questId) selects the quest AND scrolls the list pane
to show it (SetScrollHereY on the first render frame after open)
- One-shot scroll: scrollToSelected_ cleared after first use so normal
scroll behavior is unaffected afterward
Quest tracker:
- Clicking a tracked quest now calls openAndSelectQuest() — opens the log
AND jumps to that specific quest rather than just opening to top
Renders a compact top-centre overlay showing Alliance vs Horde scores
when the player is in a recognised battleground map. Score values are
read directly from the world state map maintained by SMSG_INIT_WORLD_STATES
and SMSG_UPDATE_WORLD_STATE, so no extra server packets are needed.
Supported maps:
489 – Warsong Gulch (flag captures, max 3)
529 – Arathi Basin (resources, max 1600)
30 – Alterac Valley (reinforcements, max 600)
566 – Eye of the Storm (resources, max 1600)
607 – Strand of Ancients
When a player releases spirit, the server sends SMSG_DEATH_RELEASE_LOC
with the corpse map and position. Store this so the ghost can reclaim.
New flow:
- SMSG_DEATH_RELEASE_LOC now stores corpseMapId_/corpseX_/Y_/Z_ instead
of logging and discarding
- canReclaimCorpse(): true when ghost is on same map within 40 yards of
stored corpse position
- reclaimCorpse(): sends CMSG_RECLAIM_CORPSE (no payload)
- renderReclaimCorpseButton(): shows "Resurrect from Corpse" button at
bottom-center when canReclaimCorpse() is true
Socket fixes (fixes Windows-only connection failure):
- WorldSocket::connect() now waits for non-blocking connect to complete with
select() before returning, preventing WSAENOTCONN on the first recv() call
on Windows (Linux handles this implicitly but Windows requires writability
poll after non-blocking connect)
- Add net::isConnectionClosed() helper: treats WSAENOTCONN/WSAECONNRESET/
WSAESHUTDOWN/WSAECONNABORTED as graceful peer-close rather than recv errors
- Apply isConnectionClosed() in both WorldSocket and TCPSocket recv loops
UI:
- Add renderBossFrames(): displays boss unit health bars in top-right corner
when SMSG_UPDATE_INSTANCE_ENCOUNTER_UNIT has active slots; supports
click-to-target and color-coded health bars (red→orange→yellow as HP drops)
Parse SMSG_RESYNC_RUNES, SMSG_ADD_RUNE_POWER, and SMSG_CONVERT_RUNE to
track the state of all 6 DK runes (Blood/Unholy/Frost/Death type,
ready flag, and cooldown fraction). Render a six-square rune bar below
the Runic Power bar when the player is class 6, with per-type colors
(Blood=red, Unholy=green, Frost=blue, Death=purple) and client-side
fill animation so runes visibly refill over the 10s cooldown.
Shows active pet name, level, health bar, and power bar (mana/focus/rage/energy)
when the player has an active pet. Clicking the pet name targets it. A Dismiss
button sends CMSG_PET_ACTION to dismiss the pet. Frame uses green border to
visually distinguish it from the player/target frames.
Polls the renderer's currentZoneName each frame and triggers a 5-second
fade-in/hold/fade-out toast at the upper-centre of screen when the zone
changes. Matches WoW's standard zone transition display.
For each visible Unit entity within 40 yards, projects the canonical WoW
position (converted to render space) through the camera view-projection
matrix to screen pixels. Draws a health bar (hostile=red, friendly=green,
target=gold border) and name label with drop shadow using ImGui's background
draw list. Fades out smoothly in the last 5 yards of range.
- Add Escape Menu → Instance Lockouts button opening a new panel
that lists active lockouts with instance name (from Map.dbc),
difficulty, time-until-reset countdown, and locked/extended status.
map name lookup is cached on first open.
- Fix uninitialized ChatType in sendChatMessage (default to SAY)
- Remove unused startWorld variable in handleMonsterMoveTransport
- Remove unused modelCached variable in spawnOnlineCreature
Eliminates all -Wunused-but-set-variable and -Wmaybe-uninitialized
warnings in the main translation units.
- Show up to 5 active quests with objective progress (kills, items, text)
- Gold title for complete quests, white for in-progress
- Item objectives show item name via getItemInfo() lookup
- Transparent semi-opaque background, docked below minimap on right
- Add Reputation tab in character screen tab bar (Equipment/Stats/Reputation/Skills)
- Implement renderReputationPanel() showing all tracked factions sorted alphabetically
- Progress bars colored per WoW reputation tier: Hated/Hostile/Unfriendly/Neutral/Friendly/Honored/Revered/Exalted
- Add public getFactionNamePublic() backed by DBC name cache with lazy load
- Implement renderReadyCheckPopup() showing initiator name with Ready/Not Ready buttons
- Fix MSG_RAID_READY_CHECK fallback: use partyData.leaderGuid instead of non-existent isLeader field
- Add faction standing handler with loadFactionNameCache() (Faction.dbc field 22)
- Add gossip POI handler writing canonical WoW coords to gossipPois_ for minimap rendering
- SMSG_HEALTH_UPDATE / SMSG_POWER_UPDATE: update entity HP/power via entityManager
- SMSG_UPDATE_WORLD_STATE: single world state variable update (companion to INIT)
- SMSG_UPDATE_COMBO_POINTS: store comboPoints_/comboTarget_ in GameHandler
- SMSG_START_MIRROR_TIMER / SMSG_STOP_MIRROR_TIMER / SMSG_PAUSE_MIRROR_TIMER: breath/fatigue/feign timer state
- MirrorTimer struct + getMirrorTimer() public getter; renderMirrorTimers() draws colored breath/fatigue bars above cast bar
- SMSG_CAST_RESULT: WotLK extended cast result; clear cast bar and show reason on failure (result != 0)
- SMSG_SPELL_FAILED_OTHER / SMSG_PROCRESIST: consume silently
- SMSG_LOOT_START_ROLL: correct trigger for Need/Greed popup (replaces rollType=128 heuristic)
- SMSG_STABLE_RESULT: show pet stable feedback in system chat (store/retrieve/buy slot/error)
- SMSG_TITLE_EARNED: system chat notification for title earned/removed
- SMSG_PLAYERBOUND / SMSG_BINDER_CONFIRM: hearthstone binding notification
- SMSG_SET_PHASE_SHIFT: consume (WotLK phasing, no client action needed)
- SMSG_TOGGLE_XP_GAIN: system chat notification
- Parse SMSG_ITEM_TEXT_QUERY_RESPONSE (guid + isEmpty + string text),
store in itemText_ and open book window when non-empty
- queryItemText(guid) sends CMSG_ITEM_TEXT_QUERY for readable items
- renderItemTextWindow(): scrollable book window with parchment-toned
text, "Close" button; opens via isItemTextOpen() flag
- Parse SMSG_QUEST_CONFIRM_ACCEPT (questId + title + sharerGuid),
show chat notification with quest title and sharer name
- acceptSharedQuest() sends CMSG_QUEST_CONFIRM_ACCEPT with questId
- renderSharedQuestPopup(): shows sharer name, gold quest title,
Accept/Decline buttons (stacked below other social popups)
- 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)
- AmdFsr3Runtime now probes both the legacy ffxFsr3* API and the newer
generic ffxCreateContext/ffxDispatch API; selects whichever the loaded
runtime library exports (GenericApi takes priority fallback)
- Generic API path implements full upscale + frame-generation context
creation, configure, dispatch, and destroy lifecycle
- dlopen error captured and surfaced in lastError_ on Linux so runtime
initialization failures are actionable
- FSR3 runtime init failure log now includes path kind, error string,
and loaded library path for easier debugging
- tools/generate_ffx_sdk_vk_permutations.sh added: auto-bootstraps
missing VK permutation headers; DXC auto-downloaded on Linux/Windows
MSYS2; macOS reads from PATH (CI installs via brew dxc)
- CMakeLists: add upscalers/include to probe include dirs, invoke
permutation script before SDK build, scope FFX pragma/ODR warning
suppressions to affected TUs, add runtime-copy dependency on wowee
- UI labels updated from "FSR2" → "FSR3" in settings, tuning panel,
performance HUD, and combo boxes
- CI macOS job now installs dxc via Homebrew for permutation codegen
- Overlap M2 and character animation updates via std::async (~2-5ms saved)
- Thread-local collision scratch buffers for concurrent floor queries
- Parallel terrain/WMO/M2 floor queries in camera controller
- Seed new M2 instance bones from existing siblings to eliminate pop-in flash
- Fix shadow flicker: snap center along stable light axes instead of in view space
- Increase shadow distance default to 300 units (slider max 500)
- Add movementSuppressTimer to camera controller that forces all movement
keys to read as false, preventing held W key from carrying through
loading screens (fixes always-running-forward after instance portals)
- Increase shadow frustum default from 60 to 72 units (+20%)
- Make shadow distance configurable via setShadowDistance() (40-200 range)
- Add shadow distance slider in Video settings tab (persisted to config)
Fix VK_ERROR_DEVICE_LOST crash by allocating per-frame scene history
images (color + depth) instead of a single shared image that raced
between frames in flight. Water refraction can now be toggled via
Settings > Video > Water Refraction.
Without refraction: richer blue base colors, animated caustic shimmer,
and normal-based color shifts give the water visible life. With
refraction: clean screen-space refraction with Beer-Lambert absorption.
Disabling clears scene history to black for immediate fallback.
- 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
lookupSpellName() (called by action bar tooltips) was triggering
loadSpellDBC() early, setting dbcLoadAttempted=true before the
spellbook opened. This caused loadSkillLineDBCs() to be skipped,
so all spells were categorized into "General". Fixed by checking
each DBC's own loaded flag independently and re-categorizing when
skill line data becomes available.
- 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
Talent screen:
- Remove all debug text and per-frame LOG_INFO spam
- Show class name in window title (e.g. "Warrior Talents")
- Display point distribution in header (0/31/20) and per-tab counts
- Highlighted active spec button with styled spec switcher
- Load and render tree background textures from TalentTab.dbc
- Draw prerequisite arrows with arrowheads (green=met, gray=unmet)
- Fix rank display (was showing rank+1, now correct 1-indexed values)
- Rank counter with dark background pill for readability
- Hover glow effect, rounded corners, centered grid layout
- Wider window (680x600) for 4-column WoW talent grid
Spellbook:
- Add search/filter bar for finding spells by name
- Add spell descriptions from Spell.dbc tooltip field
- Rich tooltips with name, rank, passive indicator, cooldown, description
- Visual icon borders: yellow=passive, red=cooldown, default=active
- Cooldown overlay on icon with countdown number
- Hover highlight on spell rows
- Tab counts update to reflect search filter results
- Rounded corners on icons and hover states
- Extracted renderSpellTooltip helper for consistent tooltip rendering
- 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
Bank window slots now act as drop targets when holding an item from
inventory. Empty bank slots highlight green, and clicking drops the
held item via CMSG_SWAP_ITEM. Occupied bank slots accept swaps too.
Works for both main bank slots (39-66) and bank bag slots (67+).
Remove isInterior restriction from WMO shadow sampling so city
buildings (flagged as interior groups) correctly receive shadows.
Apply shadow to interior-lit surfaces. Enable shadows by default
and persist the setting across sessions.
Zoom speed now scales with distance for fine control near the character.
Default max zoom out reduced from 50 to 33 units. New "Extended Camera
Zoom" toggle in Gameplay settings restores the full 50-unit range.
POM fixes: use blurred height only for ray march (keep crisp Sobel for
normals), reduce pomScale 0.03→0.012, clamp grazing angle denominator
to 0.15, hard-limit max UV offset, smooth fadeout at steep view angles.
Add Normal Map Strength slider (0.0-2.0) in Video settings for user
control over surface detail intensity. Persisted across sessions.
Generate normal+height maps from diffuse textures at load time using
luminance-to-height and Sobel 3x3 filtering. Compute per-vertex tangents
via Lengyel's method for TBN basis construction.
Fragment shader uses screen-space UV derivatives (dFdx/dFdy) for smooth
LOD crossfade and angle-adaptive POM sample counts. Flat textures
naturally produce low height variance, causing POM to self-select off.
Settings: Normal Mapping on by default, POM off by default with
Low/Medium/High quality presets. Persisted across sessions.
Replace all glGenTextures/glTexImage2D calls in UI code with Vulkan texture
uploads via new VkContext::uploadImGuiTexture() helper. This fixes segfaults
from calling OpenGL functions without a GL context (null GLEW function pointers).
- Add uploadImGuiTexture() to VkContext with staging buffer upload pattern
- Convert game_screen, inventory_screen, spellbook_screen, talent_screen
from GLuint/GL calls to VkDescriptorSet/Vulkan uploads
- Fix loading_screen clearValueCount (was 1, needs 2 or 3 for MSAA)