- FXAA path: repurpose _pad field as 'desaturate' push constant; when
ghostMode_ is true, convert final pixel to grayscale with slight cool
blue tint using luma(0.299,0.587,0.114) mix
- Non-FXAA path: apply a high-opacity gray overlay (rgba 0.5,0.5,0.55,0.82)
over the scene for a washed-out look
- Both parallel (SEC_POST) and single-threaded render paths covered
- ghostMode_ flag set each frame from gameHandler->isPlayerGhost()
TalentsInfoParser used a completely wrong byte layout (expected big-endian
counts, wrong field order), causing unspentTalentPoints to always be misread.
This made canLearn always false so clicking talents did nothing.
New format matches the actual WoW 3.3.5a wire format:
uint8 talentType, uint32 unspentTalents, uint8 groupCount, uint8 activeGroup,
per-group: uint8 talentCount, [uint32 id + uint8 rank]×N, uint8 glyphCount, [uint16]×M
Matches the proven parsing logic in handleInspectResults.
Implements SMSG_SET_FLAT_SPELL_MODIFIER and SMSG_SET_PCT_SPELL_MODIFIER
(previously consumed silently). Parses per-group (uint8 groupIndex, uint8
SpellModOp, int32 value) tuples sent by the server after login and talent
changes, and stores them in spellFlatMods_/spellPctMods_ maps keyed by
(SpellModOp, groupIndex).
Exposes getSpellFlatMod(op)/getSpellPctMod(op) accessors and a static
applySpellMod() helper. Clears both maps on character login alongside
spellCooldowns. Surfaces talent-modified mana cost and cast time in the
spellbook tooltip via SpellModOp::Cost and SpellModOp::CastingTime lookups.
Previously the arena path in handlePvpLogData consumed the packet and
returned early with no data. Now the two-team header is parsed (rating
change, new rating, team name), followed by the same player list and
winner fields as battlegrounds.
The BgScoreboardData struct gains ArenaTeamScore fields (teamName,
ratingChange, newRating) populated when isArena=true.
The BG scoreboard UI is updated to:
- Use "Arena Score" window title for arenas
- Show each team's name and rating delta at the top
- Identify the winner by team name instead of faction label
- Parse SMSG_SET_FACTION_ATWAR (uint32 repListId + uint8 set) to track
per-faction at-war flags in initialFactions_ flags byte
- Parse SMSG_SET_FACTION_VISIBLE (uint32 repListId + uint8 visible) to
track faction visibility changes from the server
- Add FACTION_FLAG_* constants (VISIBLE, AT_WAR, HIDDEN, etc.) to GameHandler
- Build repListId <-> factionId bidirectional maps when loading Faction.dbc
(ReputationListID field 1); used to correlate flag packets with standings
- Fix Faction.dbc field layout comment: field 1=ReputationListID, field 23=Name
(was incorrectly documented as field 22 with no ReputationListID field)
- Add isFactionAtWar(), isFactionVisible(), getFactionIdByRepListId(),
getRepListIdByFactionId() accessors on GameHandler
- Reputation panel now shows watched faction at top, highlights at-war
factions in red with "(At War)" label, and marks tracked faction in gold
When the player inspects another player on WotLK 3.3.5a, also send
CMSG_QUERY_INSPECT_ACHIEVEMENTS so the server responds with
SMSG_RESPOND_INSPECT_ACHIEVEMENTS. The new handler parses the
achievement-id/date sentinel-terminated block (same layout as
SMSG_ALL_ACHIEVEMENT_DATA but prefixed with a packed guid) and stores
the earned achievement IDs keyed by GUID in
inspectedPlayerAchievements_. The new public getter
getInspectedPlayerAchievements(guid) exposes this data for the inspect
UI. The cache is cleared on world entry to prevent stale data.
QueryInspectAchievementsPacket::build() handles the CMSG wire format
(uint64 guid + uint8 unk=0).
- Effect 10 (POWER_DRAIN): show PERIODIC_DAMAGE text on victim, ENERGIZE on caster;
handles Drain Mana, Viper Sting, Fel Drain, etc.
- Effect 11 (HEALTH_LEECH): show SPELL_DAMAGE on victim, HEAL on caster;
handles Drain Life, Death Coil, etc.
- Effect 24/114 (CREATE_ITEM/CREATE_ITEM2): existing profession crafting feedback
extended to also cover CREATE_ITEM2 (engineering/enchanting recipes using alt effect)
- Effect 26 (INTERRUPT_CAST): clear the interrupted unit's cast bar from unitCastStates_
so the cast bar dismisses immediately rather than waiting for the next update packet
- Effect 49 (FEED_PET): show "You feed your pet <item>." message for hunter pet feeding
All effects are expansion-aware: TBC/Classic use full uint64 GUIDs, WotLK uses packed GUIDs.
- Implement SMSG_SPELLLOGEXECUTE handler with expansion-aware caster GUID reading
(packed_guid for WotLK/Classic, full uint64 for TBC)
- Parse effect type 24 (SPELL_EFFECT_CREATE_ITEM): show "You create <item> using
<spell>." in chat when the player uses a profession or any create-item spell
- Look up item name via ensureItemInfo/getItemInfo and spell name via spellNameCache_
- Fall back to "You create: <item>." when the spell name is not cached
- Safely consume unknown effect types by stopping parse at first unrecognized effect
to avoid packet misalignment on variable-length sub-records
- Adds visible crafting feedback complementary to SMSG_ITEM_PUSH_RESULT (which shows
"Received:" for looted/obtained items) with a profession-specific "create" message
- Post-FXAA unsharp mask: when FSR2 is active alongside FXAA, forward
the FSR2 sharpness value (0–2) to the FXAA fragment shader via a new
vec4 push constant. A contrast-adaptive sharpening step (unsharp mask
scaled to 0–0.3) is applied after FXAA blending, recovering the
crispness that FXAA's sub-pixel blend removes. At sharpness=2.0 the
output matches RCAS quality; at sharpness=0 the step is a no-op.
- MSAA guard: setFXAAEnabled() refuses to activate FXAA when hardware
MSAA is in use. FXAA's role is to supplement FSR temporal AA, not to
stack on top of MSAA which already resolves jaggies during the scene
render pass.
- Fix bug where SMSG_REDIRECT_CLIENT, SMSG_PVP_QUEUE_STATS, SMSG_PLAYER_SKINNED, etc.
were incorrectly falling through to handleQuestPoiQueryResponse instead of being
silently consumed; add separate setReadPos break for those opcodes
- Implement SMSG_SERVERTIME: sync gameTime_ from server's unix timestamp
- Implement SMSG_KICK_REASON: show player a chat message with reason for group removal
- Implement SMSG_GROUPACTION_THROTTLED: notify player of rate-limit with wait time
- Implement SMSG_GMRESPONSE_RECEIVED: display GM ticket response in chat and UI error
- Implement SMSG_GMRESPONSE_STATUS_UPDATE: show ticket status changes in chat
- Silence voice chat, dance, commentator, and debug/cheat opcodes with explicit consume
cases rather than falling to the unhandled-opcode warning log
Previously SMSG_GMTICKET_GETTICKET and SMSG_GMTICKET_SYSTEMSTATUS were
silently consumed. Now both are fully parsed:
- SMSG_GMTICKET_GETTICKET decodes all four status codes (no ticket,
open ticket, closed, suspended), extracts ticket text, age and
server-estimated wait time, and stores them on GameHandler.
- SMSG_GMTICKET_SYSTEMSTATUS shows a chat message when GM support
goes offline/online.
- Added requestGmTicket() (sends CMSG_GMTICKET_GETTICKET) called
automatically when the GM Ticket UI window is opened, so the player
sees their existing open ticket text and wait time on first open.
- GM Ticket UI window now shows current-ticket status bar, estimated
wait time, and hides the Delete button when no ticket is active.
Also implements SMSG_SPELLINSTAKILLLOG (previously silently consumed):
parses caster/victim/spellId for all expansions and emits combat text
when the local player is involved in an instant-kill spell event (e.g.
Execute, Obliterate).
Add handlers for 14 previously-unhandled server opcodes:
LFG error/timeout states (WotLK Dungeon Finder):
- SMSG_LFG_TIMEDOUT: invite timed out, shows message and re-opens LFG UI
- SMSG_LFG_OTHER_TIMEDOUT: another player's response timed out
- SMSG_LFG_AUTOJOIN_FAILED: auto-join failed with reason code
- SMSG_LFG_AUTOJOIN_FAILED_NO_PLAYER: no players available for auto-join
- SMSG_LFG_LEADER_IS_LFM: party leader is in LFM mode
Meeting Stone (Classic/TBC era group-finding feature):
- SMSG_MEETINGSTONE_SETQUEUE: shows zone and level range in chat
- SMSG_MEETINGSTONE_COMPLETE: group ready notification
- SMSG_MEETINGSTONE_IN_PROGRESS: search ongoing notification
- SMSG_MEETINGSTONE_MEMBER_ADDED: player name resolved and shown in chat
- SMSG_MEETINGSTONE_JOINFAILED: localized error message (4 reason codes)
- SMSG_MEETINGSTONE_LEAVE: queue departure notification
Other:
- SMSG_WHOIS: displays GM /whois result line-by-line in system chat
- SMSG_MIRRORIMAGE_DATA: parses WotLK mirror image unit display ID and
applies it to the entity so mirror images render with correct appearance
FSR EASU and FSR2 sharpen fragment shaders had a manual Y-flip to undo
the now-removed postprocess.vert flip. Strip those since the vertex
shader no longer flips, making all postprocess paths consistent.
Also flip the default mouse Y-axis to match user expectation (mouse
down = look up / flight-sim style) and make FSR1 disable MSAA on
enable, matching FSR2 behaviour (FSR provides its own spatial AA).
Parse the battleground availability list sent by the server when the
player opens the BG finder. Handles all three expansion wire formats:
- Classic: bgTypeId + isRegistered + count + instanceIds
- TBC: adds isHoliday byte
- WotLK: adds minLevel/maxLevel for bracket display
Stores results in availableBgs_ (public via getAvailableBgs()) so the
UI can show available battlegrounds and running instance counts without
an additional server round-trip.
postprocess.vert.glsl had `TexCoord.y = 1.0 - TexCoord.y` which
inverted the vertical sampling of the scene texture. Vulkan textures
use v=0 at the top, matching framebuffer row 0, so no flip is needed.
The camera already flips the projection matrix (mat[1][1] *= -1) so
the scene is rendered correctly oriented; the extra inversion in the
postprocess pass flipped FXAA output upside down.
Fixes: FXAA shows camera upside down
Also fixes: FSR1 upscale and FSR3 sharpen passes (same vertex shader)
TBC aura packets (SMSG_INIT_EXTRA_AURA_INFO_OBSOLETE / SMSG_SET_EXTRA_AURA_INFO_OBSOLETE)
use flag bit 0x02 for harmful (debuff) auras, same as Classic 1.12. The UI checks bit 0x80
for debuff display, following the WotLK SMSG_AURA_UPDATE convention. Without normalization,
all TBC debuffs were displayed in the buff bar instead of the debuff bar.
Normalize using (flags & 0x02) ? 0x80 : 0, matching the fix applied to Classic in 9b09278.
The buff/debuff bar uses 0x80 (WotLK convention) to identify debuffs.
Classic UNIT_FIELD_AURAFLAGS uses 0x02 for harmful auras instead.
Map Classic 0x02 → 0x80 during aura rebuild so the UI correctly
separates buffs from debuffs for Classic players.
Classic WoW stores aura flags in UNIT_FIELD_AURAFLAGS (12 uint32 fields
packed 4 bytes per uint32, one byte per aura slot). Flag bit 0x02 = harmful
(debuff), 0x04 = helpful (buff).
- Add UNIT_FIELD_AURAFLAGS to update_field_table.hpp (Classic wire index 98)
- Add wire index 98 to Classic and Turtle WoW JSON update field tables
- Both Classic aura rebuild paths (CREATE_OBJECT and VALUES) now read the
flag byte for each aura slot to populate AuraSlot.flags, enabling the
buff/debuff bar to correctly separate buffs from debuffs on Classic
- SMSG_ACHIEVEMENT_DELETED: removes achievement from earnedAchievements_ and
achievementDates_ so the achievements UI stays accurate after revocation
- SMSG_CRITERIA_DELETED: removes criteria from criteriaProgress_ tracking
- SMSG_FORCED_DEATH_UPDATE: sets playerDead_ when server force-kills the
player (GM command, scripted events) instead of silently consuming
Implements MSG_INSPECT_ARENA_TEAMS (WotLK): reads the inspected player's
arena team data (2v2/3v3/5v5 bracket, team name, personal rating,
week/season W-L) and stores it in InspectResult.arenaTeams.
The inspect window now shows an "Arena Teams" section below the gear list
when arena team data is available, displaying bracket, team name, rating,
and win/loss record.
Also implement SMSG_COMPLAIN_RESULT with user-visible feedback for
report-player results.
Previously SMSG_OPEN_LFG_DUNGEON_FINDER was consumed silently with no UI
response. Now it fires an OpenLfgCallback wired to openDungeonFinder() on
the GameScreen, so the dungeon finder window opens as the server requests.
Classic WoW (1.12) does not use SMSG_AURA_UPDATE like WotLK or TBC.
Instead, active aura spell IDs are sent via 48 consecutive UNIT_FIELD_AURAS
slots in SMSG_UPDATE_OBJECT CREATE_OBJECT and VALUES blocks.
Previously these fields were only used for mount spell ID detection.
Now on CREATE_OBJECT and VALUES updates for the player entity (Classic
only), any changed UNIT_FIELD_AURAS slot triggers a full rebuild of
playerAuras from the entity's accumulated field state, enabling the
buff/debuff bar to display active auras for Classic players.
- SMSG_GROUP_SET_LEADER: parse leader name, update partyData.leaderGuid
by name lookup, display system message announcing the new leader
- SMSG_BATTLEGROUND_PLAYER_JOINED: parse guid, show named entry message
when player is in nameCache
- SMSG_BATTLEGROUND_PLAYER_LEFT: parse guid, show named exit message
when player is in nameCache
Replaces three LOG_INFO/ignore stubs with functional packet handlers.
SDL yrel > 0 means the mouse moved downward. In WoW, moving the mouse
down should decrease pitch (look down), but the previous code did
+= yrel which increased pitch (look up). This made the camera appear
inverted — moving the mouse down tilted the view upward. The invertMouse
option accidentally produced the correct WoW-default behaviour.
Fix: negate the default invert factor so mouse-down = look down without
InvertMouse, and mouse-down = look up when InvertMouse is enabled.
Add ArenaTeamMember / ArenaTeamRoster structs, parse the WotLK 3.3.5a
roster packet (guid, online flag, name, per-player week/season W/L,
personal rating), store per-teamId, and render a 4-column table
(Name / Rating / Week / Season) inside the existing Arena social tab.
Online members are highlighted green; offline members are greyed out.
Display Defense Rating, Dodge Rating, Parry Rating, Block Rating,
Block Value, Armor Penetration, and Spell Penetration from equipped
items in the Stats tab. Previously these stat types (12-15, 44, 47,
48) were parsed from item data but silently dropped.
- Change maxRow/maxCol from uint8_t to int in renderTalentTree to prevent
infinite loop: uint8_t col <= 255 never exits since col wraps 255→0.
Add sanity cap of 15 rows/cols to guard against corrupt DBC data.
- Fix dangling reference warning in getFormattedTitle (lambda reference)
- Raise MAX_PITCH from 35° to 88° to match WoW standard upward look range
Lists all saved equipment sets from SMSG_EQUIPMENT_SET_LIST with
icon placeholder and an Equip button per set. Clicking either the
icon or the Equip button sends CMSG_EQUIPMENT_SET_USE to swap the
player's gear to that set. Window toggled with the ` (backtick) key.
Track player titles from SMSG_TITLE_EARNED into knownTitleBits_ set,
read active title from PLAYER_CHOSEN_TITLE update field (WotLK index
1349), expose via getFormattedTitle()/sendSetTitle() on GameHandler.
Add SetTitlePacket builder (CMSG_SET_TITLE: int32 titleBit, -1=clear).
Titles window (H key) lists all earned titles from CharTitles.dbc,
highlights the active one in gold, and lets the player click to equip
or unequip a title with a single server round-trip.
Shows a thin progress bar below the player health/power bars whenever
the player is auto-attacking. The bar fills from the last swing timestamp
to the next expected swing based on the main-hand weapon's delay (from
ItemQueryResponseData::delayMs). Falls back to 2.0s for unarmed. Turns
gold and shows "Swing!" when the timer is complete to signal readiness.
Hides when not auto-attacking.
When SMSG_WEATHER sets storm (type 3) with intensity > 0.3,
fire a low-frequency (6Hz) camera shake to simulate thunder.
Magnitude scales with intensity: 0.03–0.07 world units.
- Add triggerShake(magnitude, frequency, duration) to CameraController
- Apply envelope-decaying sinusoidal XYZ offset to camera in update()
- Handle SMSG_CAMERA_SHAKE opcode in GameHandler dispatch
- Translate shakeId to magnitude (minor <50: 0.04, larger: 0.08 world units)
- Wire CameraShakeCallback from GameHandler through to CameraController
- Shake uses 18Hz oscillation with 30% fade-out envelope at end of duration
- Remove fsr2Active guard that prevented FXAA when FSR3 was active
- FXAA checkbox now always enabled; tooltip adapts to explain FSR3+FXAA combo
when FSR3 is active ('recommended ultra-quality combination')
- Performance HUD shows 'FXAA: ON (FSR3+FXAA combined)' when both active
- Ultra graphics preset now enables FXAA (8x MSAA + FXAA for max smoothness)
- Preset detection updated to require FXAA for Ultra match
- Parse MSG_LIST_STABLED_PETS (SMSG): populate StabledPet list with
petNumber, entry, level, name, displayId, and active status
- Detect stable master via gossip option text/keyword matching and
auto-send MSG_LIST_STABLED_PETS request to open the stable UI
- Refresh list automatically after SMSG_STABLE_RESULT to reflect state
- New packet builders: ListStabledPetsPacket, StablePetPacket, UnstablePetPacket
- New public API: requestStabledPetList(), stablePet(slot), unstablePet(petNumber)
- Stable window UI: shows active/stabled pets with store/retrieve buttons,
slot count, refresh, and close; opens when server sends pet list
- Clear stable state on world logout/disconnect
Previously SMSG_TITLE_EARNED only showed the numeric bit index.
Now it lazy-loads CharTitles.dbc and formats the full title string
with the player's name (e.g. "Title earned: Commander Kelsi!").
- Add CharTitles layout to WotLK (TitleBit=36) and TBC (TitleBit=20) layouts
- loadTitleNameCache() maps each titleBit to its English title string
- SMSG_TITLE_EARNED substitutes %s placeholder with local player's name
- Falls back to "Title earned (bit N)!" if DBC is unavailable
cleanupUnusedModels() runs every 5 seconds and freed vertex/index buffers
without waiting for the GPU to finish the previous frame's command buffer.
This caused VK_ERROR_DEVICE_LOST (-4) after extended gameplay when tiles
stream out and their models are freed mid-render.
Add vkDeviceWaitIdle() before the buffer destroy loop in both M2Renderer
and WMORenderer cleanupUnusedModels(). The wait only happens when there are
models to remove, so quiet sessions have no overhead.
- Remove !fsr_.enabled / !fsr2_.enabled guards that blocked FXAA init
- FXAA can now coexist with FSR1 and FSR3 simultaneously
- Priority: FSR3 > FXAA > FSR1
- FSR3 + FXAA: scene renders at FSR3 internal res, temporal AA runs,
then FXAA reads FSR3 history and applies spatial AA to swapchain
(replaces RCAS sharpening for ultra-quality native mode)
- FXAA + FSR1: scene renders at native res, FXAA post-processes;
FSR1 resources exist but are idle (FXAA wins for better quality)
- FSR3 only / FSR1 only: unchanged paths
- Fix missing fxaa.frag.spv: shader was present but uncompiled; the
CMake compile_shaders() function will now pick it up on next build
Parse pet action feedback opcodes and display messages in system chat:
dead, nothing_to_attack, cant_attack_target, target_too_far,
no_path, cant_attack_immune. Replaces consume stub.
handlePageTextQueryResponse() now collects pages into bookPages_ vector
instead of dumping lines to system chat. Multi-page items (nextPageId != 0)
are automatically chained by requesting subsequent pages. The book window
opens automatically when pages arrive, shows formatted text in a parchment-
styled ImGui window with Prev/Next page navigation and a Close button.
SMSG_READ_ITEM_OK clears bookPages_ so each item read starts fresh;
handleGameObjectPageText() does the same before querying the first page.
Closes the long-standing issue where reading scrolls and tattered notes
spammed many separate chat messages instead of showing a readable UI.
Classic 1.12 SMSG_INSPECT (wire 0x115): parse PackedGUID + 19×uint32
itemEntries to populate InspectResult and inspectedPlayerItemEntries_ cache,
enabling gear inspection of other players on Classic servers. Triggers item
queries for all filled slots so the inspect window shows names/ilevels.
SMSG_ITEM_ENCHANT_TIME_UPDATE: parse itemGuid/slot/durationSec/playerGuid and
store per-slot expire timestamps in tempEnchantTimers_. Fires 5min/1min
chat warnings before expiry. getTempEnchantRemainingMs() helper queries live
remaining time. Buff bar renders timed slot buttons (gold/teal/purple per
slot) that pulse red below 60s — useful for Shaman imbues, Rogue poisons,
whetstones and oils across all three expansions.
Parse master loot candidate GUIDs from SMSG_LOOT_MASTER_LIST and display
a "Give to..." popup menu on item click when master loot is active.
Sends CMSG_LOOT_MASTER_GIVE with loot GUID, slot, and target GUID.
Clears candidates when loot window is closed.
Parse hp/mana/str/agi/sta/int/spi deltas from SMSG_LEVELUP_INFO payload
and display them in green below the "You have reached level X!" banner.
Extends DING_DURATION to 4s to give players time to read the gains.
Store glyph IDs from SMSG_TALENTS_INFO (previously discarded) in
learnedGlyphs_[2][6] per talent spec. Load GlyphProperties.dbc to
map glyphId to spellId and major/minor type. Add a Glyphs tab to
the talent screen showing all 6 slots with spell icons and names.
Also clear vehicleId_ on SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA.
Parse SMSG_PLAYER_VEHICLE_DATA (PackedGuid + uint32 vehicleId) and
track in-vehicle state. Add sendRequestVehicleExit() which sends
CMSG_REQUEST_VEHICLE_EXIT. Render a floating red "Leave Vehicle"
button above the action bar whenever vehicleId_ is non-zero.
State cleared on world leave and zone transfer.
Remove the redundant renderObjectiveTracker (simpler, fixed-position) and
apply draggable position tracking to renderQuestObjectiveTracker (the primary
tracker with context menus, item icons, and click-to-open-quest-log).
- questTrackerPos_ / questTrackerPosInit_ now drive the primary tracker
- Default position is top-right (below minimap at y=320)
- Drag saves to settings.cfg immediately (quest_tracker_x/y keys)
- Both trackers were rendering simultaneously — this eliminates the duplicate