Commit graph

1400 commits

Author SHA1 Message Date
Kelsi
f37994cc1b fix: trade accept dialog not showing (stale state from domain handler split)
GameHandler::hasPendingTradeRequest() and all trade getters were reading
GameHandler's own tradeStatus_/tradeSlots_ which are never written after
the PR #23 split. InventoryHandler owns the canonical trade state.

Delegate all trade getters to InventoryHandler:
- getTradeStatus, hasPendingTradeRequest, isTradeOpen, getTradePeerName
- getMyTradeSlots, getPeerTradeSlots, getMyTradeGold, getPeerTradeGold

Also fix InventoryHandler::isTradeOpen() to include Accepted state.
2026-03-28 11:58:02 -07:00
Kelsi
5a8ab87a78 fix: warmup checks WMO floor proximity, not just terrain existence
Stormwind players stand on WMO floors ~95m above terrain. The previous
check only tested if terrain existed at the spawn XY (it did — far below).
Now checks WMO floor first, then terrain, requiring the ground to be within
15 units of spawn Z. Falls back to tile count after 10s.

Also adds diagnostic logging for useItemBySlot (hearthstone debug).
2026-03-28 11:34:07 -07:00
Kelsi
15f6aaadb2 fix: revert stride to 2 (correct for WotLK visible items), add re-emit tracing
Stride 4 was wrong — the raw dump shows entries at 284, 288, 292 which
are slots 0, 2, 4 with stride 2 (slot 1=NECK is zero because necks are
invisible). Stride 2 with base 284 correctly maps 19 equipment slots.

Added WARNING-level log when item query responses trigger equipment
re-emit for other players, to confirm the re-emit chain works.

The falling-through-world issue is likely terrain chunks not loading
fast enough — the terrain streaming stalls are still present.
2026-03-28 11:07:17 -07:00
Kelsi
05ab9922c4 fix: visible item stride 2→4 (confirmed from raw field dump)
RAW FIELDS dump shows equipment entries at indices 284, 288, 292, 296, 300
— stride 4, not 2. Each visible item slot occupies 4 fields (entry +
enchant + 2 padding), not 2 as previously assumed.

Field dump evidence:
  [284]=3817(Reinforced Buckler) [288]=3808(Double Mail Boots)
  [292]=3252 [296]=3823 [300]=3845 [312]=3825 [314]=3827

With stride 2, slots 0-18 read indices 284,286,288,290... which interleaves
entries with enchant/padding values, producing mostly zeros for equipment.
With stride 4, slots correctly map to entry-only fields.
2026-03-28 11:04:29 -07:00
Kelsi
37300d65ce fix: remove Classic spline fallback, add no-parabolic WotLK variant
The Classic fallback silently succeeded on WotLK data by false-positive
matching, consuming wrong bytes and producing corrupt entity data that
was silently dropped — resulting in zero other players/NPCs visible.

Now tries 4 WotLK-only variants in order:
1. Full WotLK (durationMod+durationModNext+vertAccel+effectStart+compressed)
2. Full WotLK uncompressed
3. WotLK without parabolic fields (durationMod+durationModNext+points)
4. WotLK without parabolic, compressed

This covers servers that don't unconditionally send vertAccel+effectStart
(the MEMORY.md says AzerothCore does, but other cores may not).
2026-03-28 10:55:46 -07:00
Kelsi
559f100204 fix: restore Classic spline fallback to prevent UPDATE_OBJECT packet loss
The previous fix (b8a9efb7) that returned false on spline failure was too
aggressive — it aborted the ENTIRE UPDATE_OBJECT packet, not just one
block. Since many entity spawns (NPCs, other players) share the same
packet, a single spline parse failure killed ALL entities in the batch.

Restored the Classic-format fallback as a last resort after WotLK format
fails. The key difference from the original bug is that WotLK is now
tried FIRST (with proper position save/restore), and Classic only fires
if WotLK fails. This prevents the false-positive match that originally
caused corruption while still handling edge-case spline formats.
2026-03-28 10:52:26 -07:00
Kelsi
f4a2a631ab fix: visible item field base 284→408 (was reading quest log, not equipment)
PLAYER_VISIBLE_ITEM_1_ENTRYID for WotLK 3.3.5a is at UNIT_END(148) + 260
= field index 408 with stride 2. The previous default of 284 (UNIT_END+136)
was in the quest log field range, causing item IDs like "Lesser Invisibility
Potion" and "Deathstalker Report" to be read as equipment entries.

This was the root cause of other players appearing naked — item queries
returned valid responses but for the WRONG items (quest log entries instead
of equipment), so displayInfoIds were consumable/quest item appearances.

The heuristic auto-detection still overrides for Classic/TBC (different
stride per expansion), so this only affects the WotLK default before
detection runs.

Also filter addon whispers (GearScore GS_*, DBM, oRA, BigWigs, tab-prefixed)
from chat display — these are invisible in the real WoW client.
2026-03-28 10:49:00 -07:00
Kelsi
1bcb05aac4 fix: only show fishing message for player's own bobber, not others'
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
SMSG_GAMEOBJECT_CUSTOM_ANIM with animId=0 on a fishing node (type 17)
was triggering "A fish is on your line!" for ALL fishing bobbers in
range, including other players'. Now checks OBJECT_FIELD_CREATED_BY
(fields 6-7) matches the local player GUID before showing the message.
2026-03-28 10:35:53 -07:00
Kelsi
b8a9efb721 fix: abort movement block on spline parse failure instead of corrupting stream
When both WotLK compressed and uncompressed spline point parsing fail,
the parser was silently continuing with a corrupted read position (16
bytes of WotLK spline header already consumed). This caused the update
mask to read garbage (maskBlockCount=40), corrupting the current entity
AND all remaining blocks in the same UPDATE_OBJECT packet.

Now returns false on spline failure, cleanly aborting the single block
parse and allowing the remaining blocks to be recovered (if the parser
can resync). Also logs the failing GUID and spline flags for debugging.

This fixes:
- Entities spawning with displayId=0/entry=0 (corrupted parse)
- "Unknown update type: 128" errors from reading garbage
- Falling through the ground (terrain entities lost in corrupted batch)
- Phantom "fish on your line" from fishing bobber entity parse failure
2026-03-28 10:31:53 -07:00
Kelsi
ed8ff5c8ac fix: increase packet parse/callback budgets to fix Warden module stall
Warden module download (18756 bytes, 38 chunks of 500 bytes) stalled at
32 chunks because the per-pump packet parse budget was 16 — after two
2ms pump cycles (32 packets), the TCP receive buffer filled and the
server stopped sending. Character list never arrived.

- kDefaultMaxParsedPacketsPerUpdate: 16 → 64
- kDefaultMaxPacketCallbacksPerUpdate: 6 → 48

Also adds WARNING-level diagnostic logs for auth pipeline packets and
Warden module download progress (previously DEBUG-only, invisible in
production logs).
2026-03-28 10:28:20 -07:00
Paul
888a78d775 fixin critical bugs, non critical bugs, sendmail implementation 2026-03-28 11:35:10 +03:00
Paul
b2710258dc refactor(game): split GameHandler into domain handlers
Extract domain-specific logic from the monolithic GameHandler into
dedicated handler classes, each owning its own opcode registration,
state, and packet parsing:

- CombatHandler: combat, XP, kill, PvP, loot roll (~26 methods)
- SpellHandler: spells, auras, pet stable, talent (~3+ methods)
- SocialHandler: friends, guild, groups, BG, RAF, PvP AFK (~14+ methods)
- ChatHandler: chat messages, channels, GM tickets, server messages,
               defense/area-trigger messages (~7+ methods)
- InventoryHandler: items, trade, loot, mail, vendor, equipment sets,
                    read item (~3+ methods)
- QuestHandler: gossip, quests, completed quest response (~5+ methods)
- MovementHandler: movement, follow, transport (~2 methods)
- WardenHandler: Warden anti-cheat module

Each handler registers its own dispatch table entries via
registerOpcodes(DispatchTable&), called from
GameHandler::registerOpcodeHandlers(). GameHandler retains core
orchestration: auth/session handshake, update-object parsing,
opcode routing, and cross-handler coordination.

game_handler.cpp reduced from ~10,188 to ~9,432 lines.

Also add a POST_BUILD CMake step to symlink Data/ next to the
executable so expansion profiles and opcode tables are found at
runtime when running from build/bin/.
2026-03-28 09:42:37 +03:00
Kelsi
3762dceaa6 docs: add CONTRIBUTING.md and CHANGELOG.md; optimize chat parser allocation
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
CONTRIBUTING.md: code style, PR process, architecture pointers, packet
handler pattern, key files for new contributors.

CHANGELOG.md: grouped changes since v1.8.1-preview into Performance,
Bug Fixes, Features, Security, and Code Quality sections.

Chat parser: use stack-allocated std::array<char, 256> for typical chat
messages instead of heap-allocated std::string. Only falls back to heap
for messages > 256 bytes. Reduces allocator pressure on high-frequency
chat packet handling.
2026-03-27 18:47:35 -07:00
Kelsi
e2383725f0 security: path traversal rejection, packet length validation; code quality
Security:
- Asset loader rejects paths containing ".." sequences (path traversal)
- Chat message parser validates length against remaining packet bytes
  before resize(), preventing memory exhaustion from malformed packets

Code quality:
- Extract 11 named geoset constants (kGeosetBareForearms, kGeosetWithCape,
  etc.) replacing ~40 magic number sites across 4 code paths
- Add build-debug/ and .claude/ to .gitignore
- Remove .claude/scheduled_tasks.lock from tracking
2026-03-27 18:42:48 -07:00
Kelsi
e61b23626a perf: entity/skill/DBC/warden maps to unordered_map; fix 3x contacts scan
Entity storage: std::map<uint64_t, shared_ptr<Entity>> → unordered_map for
O(1) entity lookups instead of O(log n). No code depends on GUID ordering.

Player skills: std::map<uint32_t, PlayerSkill> → unordered_map.
DBC ID cache: std::map<uint32_t, uint32_t> → unordered_map.
Warden: apiHandlers_ and allocations_ → unordered_map (freeBlocks_ kept
as std::map since its coalescing logic requires ordered iteration).

Contacts: handleFriendStatus() did 3 separate O(n) find_if scans per
packet. Consolidated to single find_if with iterator reuse. O(3n) → O(n).
2026-03-27 18:28:36 -07:00
Kelsi
2af3594ce8 perf: eliminate per-frame heap allocs in M2 renderer; UI polish and report
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
M2 renderer: move 3 per-frame local containers to member variables:
- particleGroups_ (unordered_map): reuse bucket structure across frames
- ribbonDraws_ (vector): reuse draw call buffer
- shadowTexSetCache_ (unordered_map): reuse descriptor cache
Eliminates ~3 heap allocations per frame in particle/ribbon/shadow passes.

UI polish:
- Nameplate hover tooltip showing level, class (players), guild name
- Bag window titles show slot counts: "Backpack (12/16)"

Player report: CMSG_COMPLAIN packet builder and reportPlayer() method.
"Report Player" option in target frame right-click menu for other players.
Server response handler (SMSG_COMPLAIN_RESULT) was already implemented.
2026-03-27 18:21:47 -07:00
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