Commit graph

11 commits

Author SHA1 Message Date
Kelsi
5538655383 fix(chat): resolve /r reply target when name arrives after whisper
Whisper sender name may not be in the player name cache when the packet
arrives. Store the sender GUID and lazily resolve the name from the
cache in getLastWhisperSender(). Also backfill lastWhisperSender_ when
the SMSG_NAME_QUERY_RESPONSE arrives.
2026-04-04 00:03:19 -07:00
Paul
0e6aaeb44e fix warnings, remove phases from commentaries 2026-03-31 20:11:28 +03:00
Kelsi
e8a4a7402f fix: clamp player percentage stats, add scale field why-comment
- entity_controller: clamp block/dodge/parry/crit/rangedCrit percentage
  fields to [0..100] after memcpy from update fields — guards against
  NaN/Inf from corrupted packets reaching the UI renderer
- entity_controller: add why-comment on OBJECT_FIELD_SCALE_X raw==0
  check — IEEE 754 0.0f is all-zero bits, so raw==0 means the field
  was never populated; keeping default 1.0f prevents invisible entities
2026-03-30 15:48:30 -07:00
Kelsi
e5b4e86600 fix: misleading indentation on BAG_UPDATE/UNIT_INVENTORY_CHANGED emits
The two emit calls were indented 12 spaces (suggesting a nested block)
instead of 8 (matching the enclosing if). Same class of maintenance
trap as the PLAYER_ALIVE/PLAYER_UNGHOST fix in b3abf04d.
2026-03-29 19:31:29 -07:00
Kelsi
35b952bc6f fix: SMSG_IGNORE_LIST read phantom string field after each GUID
The packet only contains uint8 count + count×uint64 GUIDs, but the
handler called readString() after each GUID. This consumed raw bytes of
subsequent GUIDs as a string, corrupting all entries after the first.
Now stores GUIDs in ignoreListGuids_ and resolves names asynchronously
via SMSG_NAME_QUERY_RESPONSE, matching the friends list pattern.

Also fixes unsafe static_pointer_cast in ready check (no type guard)
and removes redundant packetHasRemaining wrapper (duplicates Packet API).
2026-03-29 18:11:29 -07:00
Kelsi
298974ebc2 refactor: extract markPlayerDead to deduplicate death/corpse caching
Both the health==0 and dynFlags UNIT_DYNFLAG_DEAD paths duplicated the
same corpse-position caching and death-state logic with a subtle
asymmetry (only health path called stopAutoAttack). Extracted into
markPlayerDead() so coordinate swapping and state changes happen in one
place. stopAutoAttack remains at the health==0 call site since the
dynFlags path doesn't need it.
2026-03-29 17:59:44 -07:00
Kelsi
0aff4b155c fix: dismount cleared all indefinite auras instead of just mount aura
The dismount path wiped every aura with maxDurationMs < 0, which
includes racial passives, tracking, and zone buffs — not just the mount
spell. Now only clears the specific mountAuraSpellId_ so the buff bar
stays accurate without waiting for a server aura resync.
2026-03-29 17:56:59 -07:00
Kelsi
b3abf04dbb fix: misleading indentation on PLAYER_ALIVE/PLAYER_UNGHOST event emits
The emit calls were indented at a level suggesting they were outside the
if/else blocks, but braces placed them inside. Fixed to match the actual
control flow, preventing a future maintainer from "correcting" the
indentation and accidentally changing the logic.
2026-03-29 17:52:56 -07:00
Kelsi
d32b35c583 fix: restore Classic aura flag normalization and clean up EntityController
- Restore 0x02→0x80 Classic harmful-to-WotLK debuff bit mapping in
  syncClassicAurasFromFields so downstream checks work across expansions
- Extract handleDisplayIdChange helper to deduplicate identical logic
  in onValuesUpdateUnit and onValuesUpdatePlayer
- Remove unused newItemCreated parameter from handleValuesUpdate
- Fix indentation on PLAYER_DEAD/PLAYER_ALIVE/PLAYER_UNGHOST emit calls
2026-03-29 16:29:56 -07:00
Paul
b0a07c2472 refactor(game): apply SOLID phases 2-6 to EntityController
- split applyUpdateObjectBlock into handleCreateObject,
  handleValuesUpdate, handleMovementUpdate
-  extract concern helpers — createEntityFromBlock,
  applyPlayerTransportState, applyUnitFieldsOnCreate/OnUpdate,
  applyPlayerStatFields, dispatchEntitySpawn, trackItemOnCreate,
  updateItemOnValuesUpdate, syncClassicAurasFromFields,
  detectPlayerMountChange, updateNonPlayerTransportAttachment
- UnitFieldIndices, PlayerFieldIndices, UnitFieldUpdateResult
  structs with static resolve() — eliminate repeated fieldIndex() calls
- IObjectTypeHandler strategy interface; concrete handlers
  UnitTypeHandler, PlayerTypeHandler, GameObjectTypeHandler,
  ItemTypeHandler, CorpseTypeHandler registered in typeHandlers_ map;
  handleCreateObject and handleValuesUpdate now dispatch via
  getTypeHandler() — adding a new object type requires zero changes
  to existing handler methods
- PendingEvents member bus; all 27 inline owner_.fireAddonEvent()
  calls in the update path replaced with pendingEvents_.emit(); events
  flushed via flushPendingEvents() at the end of each handler, decoupling
  field-parse logic from the addon callback system

entity_controller.cpp: 1520-line monolith → longest method ~200 lines,
cyclomatic complexity ~180 → ~5; zero duplicated CREATE/VALUES blocks
2026-03-29 14:42:38 +03:00
Paul
f5757aca83 refactor(game): extract EntityController from GameHandler (step 1.3)
Moves entity lifecycle, name/creature/game-object caches, transport GUID
tracking, and the entire update-object pipeline out of GameHandler into a
new EntityController class (friend-class pattern, same as CombatHandler
et al.).

What moved:
- applyUpdateObjectBlock() — 1,520-line core of all entity creation,
  field updates, and movement application
- processOutOfRangeObjects() / finalizeUpdateObjectBatch()
- handleUpdateObject() / handleCompressedUpdateObject() / handleDestroyObject()
- handleNameQueryResponse() / handleCreatureQueryResponse()
- handleGameObjectQueryResponse() / handleGameObjectPageText()
- handlePageTextQueryResponse()
- enqueueUpdateObjectWork() / processPendingUpdateObjectWork()
- playerNameCache, playerClassRaceCache_, pendingNameQueries
- creatureInfoCache, pendingCreatureQueries
- gameObjectInfoCache_, pendingGameObjectQueries_
- transportGuids_, serverUpdatedTransportGuids_
- EntityManager (accessed by other handlers via getEntityManager())

8 opcodes re-registered by EntityController::registerOpcodes():
  SMSG_UPDATE_OBJECT, SMSG_COMPRESSED_UPDATE_OBJECT, SMSG_DESTROY_OBJECT,
  SMSG_NAME_QUERY_RESPONSE, SMSG_CREATURE_QUERY_RESPONSE,
  SMSG_GAMEOBJECT_QUERY_RESPONSE, SMSG_GAMEOBJECT_PAGETEXT,
  SMSG_PAGE_TEXT_QUERY_RESPONSE

Other handler files (combat, movement, social, spell, inventory, quest,
chat) updated to access EntityManager via getEntityManager() and the
name cache via getPlayerNameCache() — no logic changes.

Also included:
- .clang-tidy: add modernize-use-nodiscard,
  modernize-use-designated-initializers; set -std=c++20 in ExtraArgs
- test.sh: prepend clang's own resource include dir before GCC's to
  silence xmmintrin.h / ia32intrin.h conflicts during clang-tidy runs

Line counts:
  entity_controller.hpp  147 lines  (new)
  entity_controller.cpp  2172 lines (new)
  game_handler.cpp       8095 lines (was 10143, −2048)

Build: 0 errors, 0 warnings.
2026-03-29 08:21:27 +03:00