Commit graph

1234 commits

Author SHA1 Message Date
Kelsi
cccd52b32f fix: equipment visibility (remove layout verification gate), follow uses run speed
Equipment: removed the visibleItemLayoutVerified_ gate from
updateOtherPlayerVisibleItems(). The default WotLK field layout (base=284,
stride=2) is correct and should be used immediately. The verification
heuristic was silently blocking ALL other-player equipment rendering by
queuing for auto-inspect (which doesn't return items in WotLK anyway).

Follow: auto-follow now uses run speed (autoRunning) instead of walk speed.
Also uses squared distance for the distance checks.

Commands: /quit, /exit aliases for /logout; /difficulty normal/heroic/25/25heroic
sends CMSG_CHANGEPLAYER_DIFFICULTY.
2026-03-27 18:05:42 -07:00
Kelsi
b366773f29 fix: inspect (packed GUID), follow (client-side auto-walk); add loot/raid commands
Inspect: CMSG_INSPECT was writing full uint64 GUID instead of packed GUID.
Server silently rejected the malformed packet. Fixed both InspectPacket and
QueryInspectAchievementsPacket to use writePackedGuid().

Follow: was a no-op (only stored GUID). Added client-side auto-follow system:
camera controller walks toward followed entity, faces target, cancels on
WASD/mouse input, stops within 3 units, cancels at 40+ units distance.

Party commands:
- /lootmethod (ffa/roundrobin/master/group/nbg) sends CMSG_LOOT_METHOD
- /lootthreshold (0-5 or quality name) sets minimum loot quality
- /raidconvert converts party to raid (leader only)

Equipment diagnostic logging still active for debugging naked players.
2026-03-27 17:54:56 -07:00
Kelsi
16fc3ebfdf feat: target frame right-click context menu; add equipment diagnostic logging
Target frame: add Follow, Clear Target, and Set Raid Mark submenu to the
right-click context menu (Inspect, Trade, Duel were already present).

Equipment diagnostics: add LOG_INFO traces to updateOtherPlayerVisibleItems()
and emitOtherPlayerEquipment() to debug why other players appear naked.
Logs the visible item entry IDs received from the server and the resolved
displayIds from itemInfoCache. Check the log for "emitOtherPlayerEquipment"
to see if entries arrive as zeros (server not sending fields) or if
displayIds are zero (item templates not cached yet).
2026-03-27 17:41:37 -07:00
Kelsi
50a3eb7f07 fix: mail money uint64, other-player cape textures, zone toast dedup, TCP_NODELAY
Mail: change money/COD fields from uint32 to uint64 in CMSG_SEND_MAIL and
SMSG_MAIL_LIST_RESULT for WotLK 3.3.5a. Classic keeps uint32 on the wire.
Fixes money truncation and packet misalignment causing mail failures.

Other-player capes: add cape texture loading to setOnlinePlayerEquipment().
The cape geoset was enabled but no texture was loaded, leaving capes blank.
Now mirrors the local-player path: looks up ItemDisplayInfo.dbc, finds cape
texture candidates, applies via setGroupTextureOverride/setTextureSlotOverride.

Zone toasts: suppress duplicate zone toast when the zone text overlay is
already showing the same zone name. Fixes double "Entering: Stormwind City".

Network: enable TCP_NODELAY on both auth and world sockets after connect(),
disabling Nagle's algorithm to eliminate up to 200ms buffering delay on
small packets (movement, spell casts, chat).

Rendering: track material and bone descriptor sets in M2 renderer to skip
redundant vkCmdBindDescriptorSets calls between batches sharing same textures.
2026-03-27 17:20:31 -07:00
Kelsi
6f2c8962e5 fix: use expansion context for spline parsing; preload DBC caches at world entry
Spline parsing: remove Classic format fallback from the WotLK parser. The
PacketParsers hierarchy already dispatches to expansion-specific parsers
(Classic/TBC/WotLK/Turtle), so the WotLK parseMovementBlock should only
attempt WotLK spline format. The Classic fallback could false-positive when
durationMod bytes resembled a valid point count, corrupting downstream parsing.

Preload DBC caches: call loadSpellNameCache() and 5 other lazy DBC caches
during handleLoginVerifyWorld() on initial world entry. This moves the ~170ms
Spell.csv load from the first SMSG_SPELL_GO handler to the loading screen,
eliminating the mid-gameplay stall.

WMO portal culling: move per-instance portalVisibleGroups vector and
portalVisibleGroupSet to reusable member variables, eliminating heap
allocations per WMO instance per frame.
2026-03-27 16:58:39 -07:00
Kelsi
a795239e77 fix: spline parse order (WotLK-first) fixes missing NPCs; bound WMO liquid loading
Spline auto-detection: try WotLK format before Classic to prevent false-positive
matches where durationMod float bytes resemble a valid Classic pointCount. This
caused the movement block to consume wrong byte count, corrupting the update mask
read (maskBlockCount=57/129/203 instead of ~5) and silently dropping NPC spawns.

Terrain latency: bound WMO liquid group loading to 4 groups per advanceFinalization
call. Large WMOs (e.g., Stormwind canals with 40+ liquid groups) previously loaded
all groups in one unbounded loop, blowing past the 8ms frame budget and causing
stalls up to 1300ms. Now yields back to processReadyTiles() after 4 groups so the
time budget check can break out.
2026-03-27 16:51:13 -07:00
Kelsi
d26eed1e7c perf: constexpr reciprocals, cache redundant lookups, consolidate texture maps
- Hoist DBC field index lookups before loops in game_handler (7 DBC iteration loops)
- Cache getSkybox()/getPosition() calls instead of redundant per-frame queries
- Merge textureHasAlphaByPtr_ + textureColorKeyBlackByPtr_ into single map
- Add constexpr for DEG_TO_RAD, reciprocal constants, physics delta
- Add reserve() for WMO/M2 collision grid queries and portal BFS
- Frustum plane normalize: inversesqrt instead of length+divide
- M2 particle emission: inversesqrt for direction normalization
- Parse creature display IDs from query response
- UI: show spell names/IDs as fallback instead of "Unknown"
2026-03-27 16:47:30 -07:00
Kelsi
b0466e9029 perf: eliminate ~70 unnecessary sqrt ops per frame, optimize caches and threading
Squared distance optimizations across 30 files:
- Convert glm::length() comparisons to glm::dot() (no sqrt)
- Use glm::inversesqrt() for check-then-normalize patterns (1 rsqrt vs 2 sqrt)
- Defer sqrt to after early-out checks in collision/movement code
- Hottest paths: camera_controller (21), weather particles, WMO collision,
  transport movement, creature interpolation, nameplate culling

Container and algorithm improvements:
- std::map<string> → std::unordered_map for asset/DBC/MPQ/warden caches
- std::mutex → std::shared_mutex for asset_manager and mpq_manager caches
- std::sort → std::partial_sort in lighting_manager (top-2 of N volumes)
- Double-lookup find()+operator[] → insert_or_assign in game_handler
- Add reserve() for per-frame vectors: weather, swim_effects, WMO/M2 collision

Threading and synchronization:
- Replace 1ms busy-wait polling with condition_variable in character_renderer
- Move timestamp capture before mutex in logger
- Use memory_order_acquire/release for normal map completion signaling

API additions:
- DBC getStringView()/getStringViewByOffset() for zero-copy string access
- Parse creature display IDs from SMSG_CREATURE_QUERY_SINGLE_RESPONSE
2026-03-27 16:33:16 -07:00
Kelsi
cbb42ac58f fix: guard spline point loop against unsigned underflow when pointCount==1
The uncompressed spline skip loop used `pointCount - 1` in its bound
without guarding pointCount > 1. While pointCount==0 is already handled
by an early return, pointCount==1 would correctly iterate 0 times, but
the explicit guard makes the intent clearer and prevents future issues
if the early return is ever removed.
2026-03-27 14:20:28 -07:00
Kelsi
be694be558 fix: resolve infinite recursion, operator precedence bugs, and compiler warnings
- isPreWotlk() was calling itself instead of checking expansion (infinite recursion)
- luaReturnNil/Zero/False were calling themselves instead of pushing Lua values
- hasRemaining(N) * M had wrong operator precedence (should be hasRemaining(N * M))
- Misleading indentation in PARTY_LEADER_CHANGED handler (fireAddonEvent always fires)
- Remove unused standalone hasFullPackedGuid() (superseded by Packet method)
- Suppress unused-parameter warnings in fish/cancel-auto-repeat lambdas
- Remove unused settings default variables
2026-03-27 10:08:22 -07:00
Kelsi
a491202f93 refactor: convert final 7 getRemainingSize() comparisons to hasRemaining()
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
Fix extra-paren variants in world_packets and packet_parsers_tbc.
getRemainingSize() is now exclusively arithmetic across the entire
codebase — all bounds checks use hasRemaining().
2026-03-25 16:32:38 -07:00
Kelsi
d50bca21c4 refactor: migrate remaining getRemainingSize() comparisons to hasRemaining()
Convert 33 remaining getRemainingSize() comparison patterns including
ternary expressions and extra-paren variants. getRemainingSize() is
now only used for arithmetic (byte counting), never for bounds checks.
2026-03-25 16:27:42 -07:00
Kelsi
618b479818 refactor: migrate 521 getRemainingSize() comparisons to hasRemaining()
Replace getRemainingSize()>=N with hasRemaining(N) and
getRemainingSize()<N with !hasRemaining(N) across all 4 packet files.
hasRemaining() is now the canonical bounds-check idiom with 680+ uses.
2026-03-25 16:22:47 -07:00
Kelsi
ca08d4313a refactor: replace 13 remaining getReadPos()+N bounds checks in game_handler
Convert final getReadPos()+N>getSize() patterns to hasRemaining(N),
completing the migration across all 5 packet-handling files.
2026-03-25 16:17:36 -07:00
Kelsi
e9d0a58e0a refactor: replace 47 getReadPos()+N bounds checks in packet parsers
Replace verbose bounds checks with hasRemaining(N) in
packet_parsers_classic (7) and packet_parsers_tbc (40), completing
the migration across all packet-handling files.
2026-03-25 16:12:46 -07:00
Kelsi
2b4d910a4a refactor: replace 79 getReadPos()+N bounds checks with hasRemaining(N)
Replace verbose getReadPos()+N>getSize() patterns in world_packets.cpp
with the existing Packet::hasRemaining(N) method, matching the style
already used in game_handler.cpp.
2026-03-25 16:10:48 -07:00
Kelsi
b1a87114ad refactor: extract updateAutoAttack() from update()
Move 98 lines of auto-attack leash range, melee resync, facing
alignment, and hostile attacker orientation into a dedicated method.
update() is now ~180 lines (74% reduction from original 704).
2026-03-25 15:37:19 -07:00
Kelsi
3215832fed refactor: extract updateTaxiAndMountState() from update()
Move 131 lines of taxi flight detection, mount reconciliation, taxi
activation timeout, and flight recovery into a dedicated method.
update() is now ~277 lines (61% reduction from original 704).
2026-03-25 15:32:51 -07:00
Kelsi
123a19ce1c refactor: extract updateEntityInterpolation() from update()
Move entity movement interpolation loop (distance-culled per-entity
update) into its own method. update() is now ~406 lines (down from
original 704, a 42% reduction across 3 extractions).
2026-03-25 15:27:31 -07:00
Kelsi
6343ceb151 refactor: extract updateTimers() from GameHandler::update()
Move 164 lines of timer/pending-state logic into updateTimers():
auction delay, quest accept timeouts, money delta, GO loot retries,
name query resync, loot money notifications, auto-inspect throttling.
update() is now ~430 lines (down from original 704).
2026-03-25 15:23:31 -07:00
Kelsi
7066062136 refactor: extract updateNetworking() from GameHandler::update()
Move socket update, packet processing, Warden async drain, RX silence
detection, disconnect handling, and Warden gate logging into a separate
updateNetworking() method. Reduces update() from ~704 to ~591 lines.
2026-03-25 15:19:03 -07:00
Kelsi
b2e2ad12c6 refactor: add registerWorldHandler() for state-guarded dispatch entries
Add registerWorldHandler() that wraps handler calls with an IN_WORLD
state check. Replaces 8 state-guarded lambda dispatch entries with
concise one-line registrations.
2026-03-25 15:11:15 -07:00
Kelsi
6694a0aa66 refactor: add registerHandler() to replace 120 lambda dispatch wrappers
Add registerHandler() using member function pointers, replacing 120
single-line lambda dispatch entries of the form
[this](Packet& p) { handleFoo(p); } with concise
registerHandler(Opcode::X, &GameHandler::handleFoo) calls.
2026-03-25 15:08:22 -07:00
Kelsi
d73c84d98d refactor: convert remaining 6 skipAll lambdas to registerSkipHandler
Replace all remaining inline skipAll dispatch lambdas with
registerSkipHandler() calls, including 2 standalone entries and
3 for-loop groups covering ~96 opcodes total.
2026-03-25 14:58:34 -07:00
Kelsi
5fe12f3f62 refactor: deduplicate 4 NPC window distance checks in update()
Replace 4 identical 10-line NPC distance check blocks (vendor, gossip,
taxi, trainer) with a shared lambda, reducing 40 lines to 16.
2026-03-25 14:53:16 -07:00
Kelsi
313a1877d5 refactor: add registerSkipHandler/registerErrorHandler for dispatch table
Add helpers for common dispatch table patterns: registerSkipHandler()
for opcodes that just discard data (14 sites), registerErrorHandler()
for opcodes that show an error message (3 sites). Reduces boilerplate
in registerOpcodeHandlers().
2026-03-25 14:50:18 -07:00
Kelsi
12355316b3 refactor: add Packet::hasData(), replace 52 position checks and 14 more Lua guards
Add Packet::hasData() for 'has remaining data' checks, replacing 52
verbose getReadPos()<getSize() comparisons across 3 files. Also replace
14 more standalone Lua return patterns with luaReturnNil/Zero helpers.
2026-03-25 14:39:01 -07:00
Kelsi
0d9aac2656 refactor: add Packet::skipAll() to replace 186 setReadPos(getSize()) calls
Add skipAll() convenience method and replace 186 instances of the
verbose 'discard remaining packet data' idiom across game_handler
and world_packets.
2026-03-25 14:27:26 -07:00
Kelsi
4309c8c69b refactor: add isPreWotlk() helper to replace 24 compound expansion checks
Extract isPreWotlk() = isClassicLikeExpansion() || isActiveExpansion("tbc")
to replace 24 instances of the repeated compound check across packet
handlers. Clarifies intent: these code paths handle pre-WotLK packet
format differences.
2026-03-25 14:24:03 -07:00
Kelsi
e4194b1fc0 refactor: add isInWorld() and replace 119 inline state+socket checks
Add GameHandler::isInWorld() helper that encapsulates the repeated
'state == IN_WORLD && socket' guard. Replace 99 negative checks and
20 positive checks across game_handler.cpp, plus fix 2 remaining
C-style casts.
2026-03-25 14:21:19 -07:00
Kelsi
43caf7b5e6 refactor: add Packet::writePackedGuid, remove redundant static methods
Add writePackedGuid() to Packet class for read/write symmetry. Remove
now-redundant UpdateObjectParser::readPackedGuid and
MovementPacket::writePackedGuid static methods. Replace 6 internal
readPackedGuid calls, 9 writePackedGuid calls, and 1 inline 14-line
transport GUID write with Packet method calls.
2026-03-25 14:06:42 -07:00
Kelsi
2c79d82446 refactor: add Packet::readPackedGuid() and replace 121 static method calls
Move packed GUID reading into Packet class alongside readUInt8/readFloat.
Replace 121 UpdateObjectParser::readPackedGuid(packet) calls with
packet.readPackedGuid() across 4 files, reducing coupling between
Packet and UpdateObjectParser.
2026-03-25 13:58:48 -07:00
Kelsi
3f54d8bcb8 refactor: replace 37 reinterpret_cast writeBytes with writeFloat
Replace 37 verbose reinterpret_cast<const uint8_t*> float writes with
the existing Packet::writeFloat() method across world_packets,
packet_parsers_classic, and packet_parsers_tbc.
2026-03-25 13:54:10 -07:00
Kelsi
0f19ed40f8 refactor: convert 15 more renderer+sound patterns to withSoundManager
Replace 15 additional 3-line renderer acquisition + sound manager
null-check blocks with single-line withSoundManager() calls. Total
22 sites now use the helper; 11 remaining have complex multi-line
bodies or non-sound renderer usage.
2026-03-25 13:45:05 -07:00
Kelsi
ea15740e17 refactor: add withSoundManager() template to reduce renderer boilerplate
Add GameHandler::withSoundManager() that encapsulates the repeated
getInstance()->getRenderer()->getSoundManager() null-check chain.
Replace 6 call sites, with helper available for future consolidation
of remaining 25 sites.
2026-03-25 13:35:29 -07:00
Kelsi
a0267e6e95 refactor: consolidate 26 playerNameCache.find() calls to use lookupName()
Replace 26 direct playerNameCache lookups with the existing lookupName()
helper, which also provides entity-name fallback. Eliminates duplicate
cache+entity lookup patterns in chat, social, loot, and combat handlers.
Simplifies getCachedPlayerName() to delegate to lookupName().
2026-03-25 13:29:10 -07:00
Kelsi
f02fa10126 refactor: make DBC name caches mutable to eliminate 13 const_cast hacks
Mark spellNameCache_, titleNameCache_, factionNameCache_, areaNameCache_,
mapNameCache_, lfgDungeonNameCache_ and their loaded flags as mutable.
Update 6 lazy-load methods to const. Removes all 13 const_cast<GameHandler*>
calls, allowing const getters to lazily populate caches without UB.
2026-03-25 13:21:02 -07:00
Kelsi
fe043b5da8 refactor: extract getUnitByGuid() to replace 10 entity lookup + dynamic_cast patterns
Add GameHandler::getUnitByGuid() that combines entityManager.getEntity()
with dynamic_cast<Unit*>. Replaces 10 two-line lookup+cast blocks with
single-line calls.
2026-03-25 13:12:51 -07:00
Kelsi
c8617d20c8 refactor: use getSpellName/getSpellSchoolMask helpers instead of raw cache access
Replace 8 direct spellNameCache_.find() patterns with existing helper
methods: getSpellName() for name lookups, getSpellSchoolMask() for
school mask checks. Eliminates redundant loadSpellNameCache() calls
and 3-line cache lookup boilerplate at each site.
2026-03-25 13:08:10 -07:00
Kelsi
03aa915a05 refactor: move packetHasRemaining into Packet::hasRemaining method
Add Packet::hasRemaining(size_t) and remove free function from
game_handler.cpp. Replaces 8 call sites with method calls.
2026-03-25 13:02:49 -07:00
Kelsi
40dd39feed refactor: move hasFullPackedGuid into Packet class, deduplicate 2 definitions
Add Packet::hasFullPackedGuid() method and remove identical standalone
definitions from game_handler.cpp and packet_parsers_classic.cpp.
Replace 53 free-function calls with method calls.
2026-03-25 12:46:44 -07:00
Kelsi
376d0a0f77 refactor: add Packet::getRemainingSize() to replace 656 arithmetic expressions
Add getRemainingSize() one-liner to Packet class and replace all 656
instances of getSize()-getReadPos() across game_handler, world_packets,
and both packet parser files.
2026-03-25 12:42:56 -07:00
Kelsi
b66033c6d8 fix: toLowerInPlace infinite recursion + remove redundant callback guards
Fix toLowerInPlace() which was accidentally self-recursive (would stack
overflow on any Lua string lowering). Remove 30 redundant
if(addonEventCallback_) wrappers around pure fireAddonEvent blocks.
Extract color constants in performance_hud.cpp (24 inline literals).
2026-03-25 12:37:29 -07:00
Kelsi
eea205ffc9 refactor: extract toHexString utility, more color constants, final cast cleanup
Add core::toHexString() utility in logger.hpp to replace 11 duplicate
hex-dump loops across world_packets, world_socket, and game_handler.
Add kColorBrightGreen/kColorDarkGray constants in game_screen.cpp
replacing 26 inline literals. Replace remaining ~37 C-style casts in
16 files. Normalize keybinding_manager.hpp to #pragma once.
2026-03-25 12:12:03 -07:00
Kelsi
ba99d505dd refactor: remaining C-style casts, color constants, and header guard cleanup
Replace ~37 remaining C-style casts with static_cast across 16 files.
Extract named color constants (kColorRed/Green/Yellow/Gray) and dialog
window flags (kDialogFlags) in game_screen.cpp, replacing 72 inline
literals. Normalize keybinding_manager.hpp to #pragma once.
2026-03-25 11:57:22 -07:00
Kelsi
05f2bedf88 refactor: replace C-style casts with static_cast and extract toLowerInPlace
Replace ~300 C-style casts ((int), (float), (uint32_t), etc.) with
static_cast across 15 source files. Extract toLowerInPlace() helper in
lua_engine.cpp to replace 72 identical tolower loop patterns.
2026-03-25 11:40:49 -07:00
Kelsi
d646a0451d refactor: add fireAddonEvent() helper to eliminate 170+ null checks
Add inline fireAddonEvent() that wraps the addonEventCallback_ null
check. Replace ~120 direct addonEventCallback_ calls with fireAddonEvent,
eliminating redundant null checks at each callsite and reducing
boilerplate by ~30 lines.
2026-03-25 11:34:22 -07:00
Kelsi
98b9e502c5 refactor: extract guidToUnitId/getQuestTitle helpers and misc cleanup
- Extract guidToUnitId(), getQuestTitle(), findQuestLogEntry() helpers
  to replace 14 duplicated GUID-to-unitId patterns and 7 quest log
  search patterns in game_handler.cpp
- Remove duplicate #include in renderer.cpp
- Remove commented-out model cleanup code in terrain_manager.cpp
- Replace C-style casts with static_cast in auth and transport code
2026-03-25 11:25:44 -07:00
Kelsi
087e42d7a1 fix: remove 12 duplicate dispatch registrations and fix addonEventCallback null-check bugs
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 duplicate opcode registrations introduced during the switch-to-dispatch-table
refactor (PR #22), keeping the better-commented second copies. Fix 4 instances where
addonEventCallback_("UNIT_QUEST_LOG_CHANGED") was either called unconditionally
(missing braces) or had incorrect indentation inside braces.
2026-03-24 23:33:00 -07:00
Paul
fa2e8ad0fe Merge commit '6bfa3dc402' into chore/split-mega-switch-to-map 2026-03-25 07:27:03 +03:00