chore(refactor): god-object decomposition and mega-file splits

Split all mega-files by single-responsibility concern and
partially extracting AudioCoordinator and
OverlaySystem from the Renderer facade. No behavioral changes.

Splits:
- game_handler.cpp (5,247 LOC) → core + callbacks + packets (3 files)
- world_packets.cpp (4,453 LOC) → economy/entity/social/world (4 files)
- game_screen.cpp  (5,786 LOC) → core + frames + hud + minimap (4 files)
- m2_renderer.cpp  (3,343 LOC) → core + instance + particles + render (4 files)
- chat_panel.cpp   (3,140 LOC) → core + commands + utils (3 files)
- entity_spawner.cpp (2,750 LOC) → core + player + processing (3 files)

Extractions:
- AudioCoordinator: include/audio/ + src/audio/ (owned by Renderer)
- OverlaySystem: include/rendering/ + src/rendering/overlay_system.*

CMakeLists.txt: registered all 17 new translation units.
Related handler/callback files: minor include fixups post-split.
This commit is contained in:
Paul 2026-04-05 19:30:44 +03:00
parent 6dcc06697b
commit 34c0e3ca28
49 changed files with 29113 additions and 28109 deletions

View file

@ -1,9 +1,13 @@
#pragma once
#include <cstdint>
#include <memory>
#include <string>
#include <glm/vec3.hpp>
namespace wowee {
namespace pipeline { class AssetManager; }
namespace game { class ZoneManager; }
namespace audio {
class MusicManager;
@ -17,6 +21,26 @@ class CombatSoundManager;
class SpellSoundManager;
class MovementSoundManager;
/// Flat context passed from Renderer into updateZoneAudio() each frame.
/// All values are pre-queried so AudioCoordinator needs no rendering pointers.
struct ZoneAudioContext {
float deltaTime = 0.0f;
glm::vec3 cameraPosition{0.0f};
bool isSwimming = false;
bool insideWmo = false;
uint32_t insideWmoId = 0;
// Visual weather state for ambient audio sync
int weatherType = 0; // 0=none, 1=rain, 2=snow, 3=storm
float weatherIntensity = 0.0f;
// Terrain tile for offline zone lookup
int tileX = 0, tileY = 0;
bool hasTile = false;
// Server-authoritative zone (from SMSG_INIT_WORLD_STATES); 0 = offline
uint32_t serverZoneId = 0;
// Zone manager pointer (for zone info and music queries)
game::ZoneManager* zoneManager = nullptr;
};
/// Coordinates all audio subsystems.
/// Extracted from Renderer to separate audio lifecycle from rendering.
/// Owned by Application; Renderer and UI components access through Application.
@ -35,6 +59,13 @@ public:
/// Shutdown all audio managers and engine.
void shutdown();
/// Per-frame zone detection, music transitions, and ambient weather sync.
/// Called from Renderer::update() with a pre-filled context.
void updateZoneAudio(const ZoneAudioContext& ctx);
const std::string& getCurrentZoneName() const { return currentZoneName_; }
uint32_t getCurrentZoneId() const { return currentZoneId_; }
// Accessors for all audio managers (same interface as Renderer had)
MusicManager* getMusicManager() { return musicManager_.get(); }
FootstepManager* getFootstepManager() { return footstepManager_.get(); }
@ -48,6 +79,8 @@ public:
MovementSoundManager* getMovementSoundManager() { return movementSoundManager_.get(); }
private:
void playZoneMusic(const std::string& music);
std::unique_ptr<MusicManager> musicManager_;
std::unique_ptr<FootstepManager> footstepManager_;
std::unique_ptr<ActivitySoundManager> activitySoundManager_;
@ -60,6 +93,13 @@ private:
std::unique_ptr<MovementSoundManager> movementSoundManager_;
bool audioAvailable_ = false;
// Zone/music state — moved from Renderer
uint32_t currentZoneId_ = 0;
std::string currentZoneName_;
bool inTavern_ = false;
bool inBlacksmith_ = false;
float musicSwitchCooldown_ = 0.0f;
};
} // namespace audio

View file

@ -1825,7 +1825,11 @@ public:
}
// Convenience: invoke a callback with a sound manager obtained from the renderer.
template<typename ManagerGetter, typename Callback>
void withSoundManager(ManagerGetter getter, Callback cb);
void withSoundManager(ManagerGetter getter, Callback cb) {
if (auto* ac = services_.audioCoordinator) {
if (auto* mgr = (ac->*getter)()) cb(mgr);
}
}
// Reputation change toast: factionName, delta, new standing
using RepChangeCallback = std::function<void(const std::string& factionName, int32_t delta, int32_t standing)>;
@ -2138,17 +2142,370 @@ public:
*/
void resetDbcCaches();
private:
friend class ChatHandler;
friend class MovementHandler;
friend class CombatHandler;
friend class SpellHandler;
friend class InventoryHandler;
friend class SocialHandler;
friend class QuestHandler;
friend class WardenHandler;
friend class EntityController;
// ═══════════════════════════════════════════════════════════════════
// Domain handler access — public accessors for friend-class elimination
// ═══════════════════════════════════════════════════════════════════
// ── Handler & Subsystem Accessors (unique_ptr → raw pointer) ─────
network::WorldSocket* getSocket() { return socket.get(); }
const network::WorldSocket* getSocket() const { return socket.get(); }
ChatHandler* getChatHandler() { return chatHandler_.get(); }
CombatHandler* getCombatHandler() { return combatHandler_.get(); }
MovementHandler* getMovementHandler() { return movementHandler_.get(); }
SpellHandler* getSpellHandler() { return spellHandler_.get(); }
// ── Mutable Accessors for Members with Existing Const Getters ────
void setTargetGuidRaw(uint64_t g) { targetGuid = g; }
uint64_t& lastTargetGuidRef() { return lastTargetGuid; }
uint64_t& focusGuidRef() { return focusGuid; }
uint64_t& mouseoverGuidRef() { return mouseoverGuid_; }
MovementInfo& movementInfoRef() { return movementInfo; }
Inventory& inventoryRef() { return inventory; }
// ── Core / Session ───────────────────────────────────────────────
uint32_t getBuild() const { return build; }
const std::vector<uint8_t>& getSessionKey() const { return sessionKey; }
auto& charactersRef() { return characters; }
auto& updateFieldTableRef() { return updateFieldTable_; }
auto& lastPlayerFieldsRef() { return lastPlayerFields_; }
auto& timeSinceLastPingRef() { return timeSinceLastPing; }
auto& activeCharacterGuidRef() { return activeCharacterGuid_; }
// ── Character & Appearance ───────────────────────────────────────
auto& chosenTitleBitRef() { return chosenTitleBit_; }
auto& cloakVisibleRef() { return cloakVisible_; }
auto& helmVisibleRef() { return helmVisible_; }
auto& currentMountDisplayIdRef() { return currentMountDisplayId_; }
auto& mountAuraSpellIdRef() { return mountAuraSpellId_; }
auto& shapeshiftFormIdRef() { return shapeshiftFormId_; }
auto& playerRaceRef() { return playerRace_; }
auto& serverPlayerLevelRef() { return serverPlayerLevel_; }
// ── AFK / DND ────────────────────────────────────────────────────
auto& afkMessageRef() { return afkMessage_; }
auto& afkStatusRef() { return afkStatus_; }
auto& dndMessageRef() { return dndMessage_; }
auto& dndStatusRef() { return dndStatus_; }
// ── Movement & Transport ─────────────────────────────────────────
auto& followRenderPosRef() { return followRenderPos_; }
auto& followTargetGuidRef() { return followTargetGuid_; }
auto& serverRunSpeedRef() { return serverRunSpeed_; }
auto& onTaxiFlightRef() { return onTaxiFlight_; }
auto& taxiLandingCooldownRef() { return taxiLandingCooldown_; }
auto& taxiMountActiveRef() { return taxiMountActive_; }
auto& taxiStartGraceRef() { return taxiStartGrace_; }
auto& vehicleIdRef() { return vehicleId_; }
auto& playerTransportGuidRef() { return playerTransportGuid_; }
auto& playerTransportOffsetRef() { return playerTransportOffset_; }
auto& playerTransportStickyGuidRef() { return playerTransportStickyGuid_; }
auto& playerTransportStickyTimerRef() { return playerTransportStickyTimer_; }
auto& transportAttachmentsRef() { return transportAttachments_; }
// ── Inventory & Equipment ────────────────────────────────────────
auto& actionBarRef() { return actionBar; }
auto& backpackSlotGuidsRef() { return backpackSlotGuids_; }
auto& equipSlotGuidsRef() { return equipSlotGuids_; }
auto& keyringSlotGuidsRef() { return keyringSlotGuids_; }
auto& containerContentsRef() { return containerContents_; }
auto& invSlotBaseRef() { return invSlotBase_; }
auto& packSlotBaseRef() { return packSlotBase_; }
auto& visibleItemEntryBaseRef() { return visibleItemEntryBase_; }
auto& visibleItemLayoutVerifiedRef() { return visibleItemLayoutVerified_; }
auto& visibleItemStrideRef() { return visibleItemStride_; }
auto& itemInfoCacheRef() { return itemInfoCache_; }
auto& lastEquipDisplayIdsRef() { return lastEquipDisplayIds_; }
auto& onlineEquipDirtyRef() { return onlineEquipDirty_; }
auto& onlineItemsRef() { return onlineItems_; }
auto& inspectedPlayerItemEntriesRef() { return inspectedPlayerItemEntries_; }
auto& otherPlayerVisibleDirtyRef() { return otherPlayerVisibleDirty_; }
auto& otherPlayerVisibleItemEntriesRef() { return otherPlayerVisibleItemEntries_; }
auto& otherPlayerMoveTimeMsRef() { return otherPlayerMoveTimeMs_; }
auto& pendingItemPushNotifsRef() { return pendingItemPushNotifs_; }
auto& pendingItemQueriesRef() { return pendingItemQueries_; }
auto& pendingMoneyDeltaRef() { return pendingMoneyDelta_; }
auto& pendingMoneyDeltaTimerRef() { return pendingMoneyDeltaTimer_; }
auto& pendingAutoInspectRef() { return pendingAutoInspect_; }
auto& pendingGameObjectLootRetriesRef() { return pendingGameObjectLootRetries_; }
auto& tempEnchantTimersRef() { return tempEnchantTimers_; }
auto& localLootStateRef() { return localLootState_; }
static const auto& getTempEnchantSlotNames() { return kTempEnchantSlotNames; }
// ── Combat & Player Stats ────────────────────────────────────────
auto& comboPointsRef() { return comboPoints_; }
auto& comboTargetRef() { return comboTarget_; }
auto& isRestingRef() { return isResting_; }
auto& playerArenaPointsRef() { return playerArenaPoints_; }
auto& playerArmorRatingRef() { return playerArmorRating_; }
auto& playerBlockPctRef() { return playerBlockPct_; }
auto& playerCombatRatingsRef() { return playerCombatRatings_; }
auto& playerCritPctRef() { return playerCritPct_; }
auto& playerDodgePctRef() { return playerDodgePct_; }
auto& playerHealBonusRef() { return playerHealBonus_; }
auto& playerHonorPointsRef() { return playerHonorPoints_; }
auto& playerMeleeAPRef() { return playerMeleeAP_; }
auto& playerMoneyCopperRef() { return playerMoneyCopper_; }
auto& playerNextLevelXpRef() { return playerNextLevelXp_; }
auto& playerParryPctRef() { return playerParryPct_; }
auto& playerRangedAPRef() { return playerRangedAP_; }
auto& playerRangedCritPctRef() { return playerRangedCritPct_; }
auto* playerResistancesArr() { return playerResistances_; }
auto& playerRestedXpRef() { return playerRestedXp_; }
auto* playerSpellCritPctArr() { return playerSpellCritPct_; }
auto* playerSpellDmgBonusArr() { return playerSpellDmgBonus_; }
auto& playerStatsArr() { return playerStats_; }
auto& playerXpRef() { return playerXp_; }
// ── Skills ───────────────────────────────────────────────────────
auto& playerSkillsRef() { return playerSkills_; }
auto& skillLineAbilityLoadedRef() { return skillLineAbilityLoaded_; }
auto& skillLineCategoriesRef() { return skillLineCategories_; }
auto& skillLineDbcLoadedRef() { return skillLineDbcLoaded_; }
auto& skillLineNamesRef() { return skillLineNames_; }
auto& spellToSkillLineRef() { return spellToSkillLine_; }
// ── Spells & Talents ─────────────────────────────────────────────
auto& activeTalentSpecRef() { return activeTalentSpec_; }
auto* unspentTalentPointsArr() { return unspentTalentPoints_; }
auto* learnedTalentsArr() { return learnedTalents_; }
auto& learnedGlyphsRef() { return learnedGlyphs_; }
auto& talentsInitializedRef() { return talentsInitialized_; }
auto& spellFlatModsRef() { return spellFlatMods_; }
auto& spellPctModsRef() { return spellPctMods_; }
auto& spellNameCacheRef() { return spellNameCache_; }
auto& spellNameCacheLoadedRef() { return spellNameCacheLoaded_; }
// ── Quests & Achievements ────────────────────────────────────────
auto& completedQuestsRef() { return completedQuests_; }
auto& npcQuestStatusRef() { return npcQuestStatus_; }
auto& achievementDatesRef() { return achievementDates_; }
auto& achievementNameCacheRef() { return achievementNameCache_; }
auto& earnedAchievementsRef() { return earnedAchievements_; }
// ── Social, Chat & Contacts ──────────────────────────────────────
auto& contactsRef() { return contacts_; }
auto& friendGuidsRef() { return friendGuids_; }
auto& friendsCacheRef() { return friendsCache; }
auto& ignoreCacheRef() { return ignoreCache; }
auto& ignoreListGuidsRef() { return ignoreListGuids_; }
auto& lastContactListCountRef() { return lastContactListCount_; }
auto& lastContactListMaskRef() { return lastContactListMask_; }
auto& lastWhisperSenderRef() { return lastWhisperSender_; }
auto& lastWhisperSenderGuidRef() { return lastWhisperSenderGuid_; }
auto& mailInboxRef() { return mailInbox_; }
// ── World, Map & Zones ───────────────────────────────────────────
auto& currentMapIdRef() { return currentMapId_; }
auto& inInstanceRef() { return inInstance_; }
auto& worldStateMapIdRef() { return worldStateMapId_; }
auto& worldStatesRef() { return worldStates_; }
auto& worldStateZoneIdRef() { return worldStateZoneId_; }
auto& minimapPingsRef() { return minimapPings_; }
auto& gossipPoisRef() { return gossipPois_; }
auto& playerExploredZonesRef() { return playerExploredZones_; }
auto& hasPlayerExploredZonesRef() { return hasPlayerExploredZones_; }
auto& factionStandingsRef() { return factionStandings_; }
auto& initialFactionsRef() { return initialFactions_; }
auto& watchedFactionIdRef() { return watchedFactionId_; }
// ── Corpse & Home Bind ───────────────────────────────────────────
auto& corpseGuidRef() { return corpseGuid_; }
auto& corpseMapIdRef() { return corpseMapId_; }
auto& corpseReclaimAvailableMsRef() { return corpseReclaimAvailableMs_; }
auto& corpseXRef() { return corpseX_; }
auto& corpseYRef() { return corpseY_; }
auto& corpseZRef() { return corpseZ_; }
auto& hasHomeBindRef() { return hasHomeBind_; }
auto& homeBindMapIdRef() { return homeBindMapId_; }
auto& homeBindPosRef() { return homeBindPos_; }
// ── Area Triggers ────────────────────────────────────────────────
auto& activeAreaTriggersRef() { return activeAreaTriggers_; }
auto& areaTriggerCheckTimerRef() { return areaTriggerCheckTimer_; }
auto& areaTriggerDbcLoadedRef() { return areaTriggerDbcLoaded_; }
auto& areaTriggerMsgsRef() { return areaTriggerMsgs_; }
auto& areaTriggersRef() { return areaTriggers_; }
auto& areaTriggerSuppressFirstRef() { return areaTriggerSuppressFirst_; }
// ── Death & Resurrection ─────────────────────────────────────────
auto& playerDeadRef() { return playerDead_; }
auto& releasedSpiritRef() { return releasedSpirit_; }
auto& repopPendingRef() { return repopPending_; }
auto& lastRepopRequestMsRef() { return lastRepopRequestMs_; }
auto& pendingSpiritHealerGuidRef() { return pendingSpiritHealerGuid_; }
auto& resurrectCasterGuidRef() { return resurrectCasterGuid_; }
auto& resurrectIsSpiritHealerRef() { return resurrectIsSpiritHealer_; }
auto& resurrectPendingRef() { return resurrectPending_; }
auto& resurrectRequestPendingRef() { return resurrectRequestPending_; }
auto& selfResAvailableRef() { return selfResAvailable_; }
// ── Summon & Battlefield ─────────────────────────────────────────
auto& pendingSummonRequestRef() { return pendingSummonRequest_; }
auto& summonerGuidRef() { return summonerGuid_; }
auto& summonerNameRef() { return summonerName_; }
auto& summonTimeoutSecRef() { return summonTimeoutSec_; }
auto& bfMgrInvitePendingRef() { return bfMgrInvitePending_; }
// ── Pet & Stable ─────────────────────────────────────────────────
auto& petActionSlotsRef() { return petActionSlots_; }
auto& petAutocastSpellsRef() { return petAutocastSpells_; }
auto& petCommandRef() { return petCommand_; }
auto& petGuidRef() { return petGuid_; }
auto& petReactRef() { return petReact_; }
auto& petSpellListRef() { return petSpellList_; }
auto& stabledPetsRef() { return stabledPets_; }
auto& stableMasterGuidRef() { return stableMasterGuid_; }
auto& stableNumSlotsRef() { return stableNumSlots_; }
auto& stableWindowOpenRef() { return stableWindowOpen_; }
// ── Trainer, GM & Misc ───────────────────────────────────────────
auto& currentTrainerListRef() { return currentTrainerList_; }
auto& trainerTabsRef() { return trainerTabs_; }
auto& gmTicketActiveRef() { return gmTicketActive_; }
auto& gmTicketTextRef() { return gmTicketText_; }
auto& bookPagesRef() { return bookPages_; }
auto& activeTotemSlotsRef() { return activeTotemSlots_; }
auto& unitAurasCacheRef() { return unitAurasCache_; }
auto& lastInteractedGoGuidRef() { return lastInteractedGoGuid_; }
auto& pendingGameObjectInteractGuidRef() { return pendingGameObjectInteractGuid_; }
// ── Tab Cycling ──────────────────────────────────────────────────
auto& tabCycleIndexRef() { return tabCycleIndex; }
auto& tabCycleListRef() { return tabCycleList; }
auto& tabCycleStaleRef() { return tabCycleStale; }
// ── UI & Event Callbacks ─────────────────────────────────────────
auto& achievementEarnedCallbackRef() { return achievementEarnedCallback_; }
auto& addonChatCallbackRef() { return addonChatCallback_; }
auto& addonEventCallbackRef() { return addonEventCallback_; }
auto& appearanceChangedCallbackRef() { return appearanceChangedCallback_; }
auto& autoFollowCallbackRef() { return autoFollowCallback_; }
auto& chargeCallbackRef() { return chargeCallback_; }
auto& chatBubbleCallbackRef() { return chatBubbleCallback_; }
auto& creatureDespawnCallbackRef() { return creatureDespawnCallback_; }
auto& creatureMoveCallbackRef() { return creatureMoveCallback_; }
auto& creatureSpawnCallbackRef() { return creatureSpawnCallback_; }
auto& emoteAnimCallbackRef() { return emoteAnimCallback_; }
auto& gameObjectDespawnCallbackRef() { return gameObjectDespawnCallback_; }
auto& gameObjectMoveCallbackRef() { return gameObjectMoveCallback_; }
auto& gameObjectSpawnCallbackRef() { return gameObjectSpawnCallback_; }
auto& gameObjectStateCallbackRef() { return gameObjectStateCallback_; }
auto& ghostStateCallbackRef() { return ghostStateCallback_; }
auto& hearthstonePreloadCallbackRef() { return hearthstonePreloadCallback_; }
auto& hitReactionCallbackRef() { return hitReactionCallback_; }
auto& itemLootCallbackRef() { return itemLootCallback_; }
auto& knockBackCallbackRef() { return knockBackCallback_; }
auto& lootWindowCallbackRef() { return lootWindowCallback_; }
auto& meleeSwingCallbackRef() { return meleeSwingCallback_; }
auto& mountCallbackRef() { return mountCallback_; }
auto& npcAggroCallbackRef() { return npcAggroCallback_; }
auto& npcDeathCallbackRef() { return npcDeathCallback_; }
auto& npcFarewellCallbackRef() { return npcFarewellCallback_; }
auto& npcGreetingCallbackRef() { return npcGreetingCallback_; }
auto& npcRespawnCallbackRef() { return npcRespawnCallback_; }
auto& npcSwingCallbackRef() { return npcSwingCallback_; }
auto& npcVendorCallbackRef() { return npcVendorCallback_; }
auto& openLfgCallbackRef() { return openLfgCallback_; }
auto& otherPlayerLevelUpCallbackRef() { return otherPlayerLevelUpCallback_; }
auto& playerDespawnCallbackRef() { return playerDespawnCallback_; }
auto& playerEquipmentCallbackRef() { return playerEquipmentCallback_; }
auto& playerHealthCallbackRef() { return playerHealthCallback_; }
auto& playerSpawnCallbackRef() { return playerSpawnCallback_; }
auto& pvpHonorCallbackRef() { return pvpHonorCallback_; }
auto& questCompleteCallbackRef() { return questCompleteCallback_; }
auto& questProgressCallbackRef() { return questProgressCallback_; }
auto& repChangeCallbackRef() { return repChangeCallback_; }
auto& spellCastAnimCallbackRef() { return spellCastAnimCallback_; }
auto& spellCastFailedCallbackRef() { return spellCastFailedCallback_; }
auto& sprintAuraCallbackRef() { return sprintAuraCallback_; }
auto& stealthStateCallbackRef() { return stealthStateCallback_; }
auto& stunStateCallbackRef() { return stunStateCallback_; }
auto& taxiFlightStartCallbackRef() { return taxiFlightStartCallback_; }
auto& taxiOrientationCallbackRef() { return taxiOrientationCallback_; }
auto& taxiPrecacheCallbackRef() { return taxiPrecacheCallback_; }
auto& transportMoveCallbackRef() { return transportMoveCallback_; }
auto& unitAnimHintCallbackRef() { return unitAnimHintCallback_; }
auto& unitMoveFlagsCallbackRef() { return unitMoveFlagsCallback_; }
auto& worldEntryCallbackRef() { return worldEntryCallback_; }
// ── Methods moved from private (domain handler use) ──────────────
void addCombatText(CombatTextEntry::Type type, int32_t amount, uint32_t spellId,
bool isPlayerSource, uint8_t powerType = 0,
uint64_t srcGuid = 0, uint64_t dstGuid = 0);
bool shouldLogSpellstealAura(uint64_t casterGuid, uint64_t victimGuid, uint32_t spellId);
void addSystemChatMessage(const std::string& message);
void sendPing();
void setTransportAttachment(uint64_t childGuid, ObjectType type,
uint64_t transportGuid, const glm::vec3& localOffset,
bool hasLocalOrientation, float localOrientation);
void clearTransportAttachment(uint64_t childGuid);
std::string guidToUnitId(uint64_t guid) const;
Unit* getUnitByGuid(uint64_t guid);
uint64_t resolveOnlineItemGuid(uint32_t itemId) const;
void rebuildOnlineInventory();
void maybeDetectVisibleItemLayout();
void updateOtherPlayerVisibleItems(uint64_t guid, const std::map<uint16_t, uint32_t>& fields);
void detectInventorySlotBases(const std::map<uint16_t, uint32_t>& fields);
bool applyInventoryFields(const std::map<uint16_t, uint32_t>& fields);
void extractContainerFields(uint64_t containerGuid, const std::map<uint16_t, uint32_t>& fields);
void extractSkillFields(const std::map<uint16_t, uint32_t>& fields);
void extractExploredZoneFields(const std::map<uint16_t, uint32_t>& fields);
void applyQuestStateFromFields(const std::map<uint16_t, uint32_t>& fields);
void sanitizeMovementForTaxi();
void loadSpellNameCache() const;
void loadFactionNameCache() const;
void loadAchievementNameCache();
void loadSkillLineDbc();
void loadSkillLineAbilityDbc();
std::string getFactionName(uint32_t factionId) const;
std::string getLfgDungeonName(uint32_t dungeonId) const;
void queryItemInfo(uint32_t entry, uint64_t guid);
// --- Inner types exposed for former friend classes ---
struct TransportAttachment {
ObjectType type = ObjectType::OBJECT;
uint64_t transportGuid = 0;
glm::vec3 localOffset{0.0f};
float localOrientation = 0.0f;
bool hasLocalOrientation = false;
};
struct AreaTriggerEntry {
uint32_t id = 0;
uint32_t mapId = 0;
float x = 0, y = 0, z = 0;
float radius = 0;
float boxLength = 0, boxWidth = 0, boxHeight = 0;
float boxYaw = 0;
};
struct PendingLootRetry {
uint64_t guid = 0;
float timer = 0.0f;
uint8_t remainingRetries = 0;
bool sendLoot = false;
};
struct SpellNameEntry {
std::string name; std::string rank; std::string description;
uint32_t schoolMask = 0; uint8_t dispelType = 0; uint32_t attrEx = 0;
int32_t effectBasePoints[3] = {0, 0, 0};
float durationSec = 0.0f;
};
static constexpr size_t PLAYER_EXPLORED_ZONES_COUNT = 128;
std::string getAreaName(uint32_t areaId) const;
struct OnlineItemInfo {
uint32_t entry = 0;
uint32_t stackCount = 1;
uint32_t curDurability = 0;
uint32_t maxDurability = 0;
uint32_t permanentEnchantId = 0;
uint32_t temporaryEnchantId = 0;
std::array<uint32_t, 3> socketEnchantIds{};
};
bool isHostileFaction(uint32_t factionTemplateId) const {
auto it = factionHostileMap_.find(factionTemplateId);
return it != factionHostileMap_.end() ? it->second : true;
}
private:
// Dead: autoTargetAttacker moved to CombatHandler
/**
@ -2223,16 +2580,8 @@ private:
void handlePong(network::Packet& packet);
void handleItemQueryResponse(network::Packet& packet);
void queryItemInfo(uint32_t entry, uint64_t guid);
void rebuildOnlineInventory();
void maybeDetectVisibleItemLayout();
void updateOtherPlayerVisibleItems(uint64_t guid, const std::map<uint16_t, uint32_t>& fields);
void emitOtherPlayerEquipment(uint64_t guid);
void emitAllOtherPlayerEquipment();
void detectInventorySlotBases(const std::map<uint16_t, uint32_t>& fields);
bool applyInventoryFields(const std::map<uint16_t, uint32_t>& fields);
void extractContainerFields(uint64_t containerGuid, const std::map<uint16_t, uint32_t>& fields);
uint64_t resolveOnlineItemGuid(uint32_t itemId) const;
// handleAttackStart, handleAttackStop, handleAttackerStateUpdate,
// handleSpellDamageLog, handleSpellHealLog removed
@ -2257,8 +2606,6 @@ private:
void clearPendingQuestAccept(uint32_t questId);
void triggerQuestAcceptResync(uint32_t questId, uint64_t npcGuid, const char* reason);
bool hasQuestInLog(uint32_t questId) const;
std::string guidToUnitId(uint64_t guid) const;
Unit* getUnitByGuid(uint64_t guid);
std::string getQuestTitle(uint32_t questId) const;
const QuestLogEntry* findQuestLogEntry(uint32_t questId) const;
int findQuestLogSlotIndexFromServer(uint32_t questId) const;
@ -2302,15 +2649,7 @@ private:
// ---- Logout handlers ----
void addCombatText(CombatTextEntry::Type type, int32_t amount, uint32_t spellId, bool isPlayerSource, uint8_t powerType = 0,
uint64_t srcGuid = 0, uint64_t dstGuid = 0);
bool shouldLogSpellstealAura(uint64_t casterGuid, uint64_t victimGuid, uint32_t spellId);
void addSystemChatMessage(const std::string& message);
/**
* Send CMSG_PING to server (heartbeat)
*/
void sendPing();
/**
* Send CMSG_AUTH_SESSION to server
@ -2332,10 +2671,6 @@ private:
*/
void fail(const std::string& reason);
void updateAttachedTransportChildren(float deltaTime);
void setTransportAttachment(uint64_t childGuid, ObjectType type, uint64_t transportGuid,
const glm::vec3& localOffset, bool hasLocalOrientation,
float localOrientation);
void clearTransportAttachment(uint64_t childGuid);
// Explicit service dependencies (owned by Application)
GameServices& services_;
@ -2487,15 +2822,6 @@ private:
uint64_t lastWhisperSenderGuid_ = 0;
// ---- Online item tracking ----
struct OnlineItemInfo {
uint32_t entry = 0;
uint32_t stackCount = 1;
uint32_t curDurability = 0;
uint32_t maxDurability = 0;
uint32_t permanentEnchantId = 0; // ITEM_ENCHANTMENT_SLOT 0 (enchanting)
uint32_t temporaryEnchantId = 0; // ITEM_ENCHANTMENT_SLOT 1 (sharpening stones, poisons)
std::array<uint32_t, 3> socketEnchantIds{}; // ITEM_ENCHANTMENT_SLOT 2-4 (gems)
};
std::unordered_map<uint64_t, OnlineItemInfo> onlineItems_;
std::unordered_map<uint32_t, ItemQueryResponseData> itemInfoCache_;
std::unordered_set<uint32_t> pendingItemQueries_;
@ -2576,13 +2902,6 @@ private:
VehicleStateCallback vehicleStateCallback_;
// Transport tracking
struct TransportAttachment {
ObjectType type = ObjectType::OBJECT;
uint64_t transportGuid = 0;
glm::vec3 localOffset{0.0f};
float localOrientation = 0.0f;
bool hasLocalOrientation = false;
};
std::unordered_map<uint64_t, TransportAttachment> transportAttachments_;
// Transport GUID tracking moved to EntityController
uint64_t playerTransportGuid_ = 0; // Transport the player is riding (0 = none)
@ -2606,14 +2925,6 @@ private:
bool talentsInitialized_ = false; // Reset on world entry; guards first-spec selection
// ---- Area trigger detection ----
struct AreaTriggerEntry {
uint32_t id = 0;
uint32_t mapId = 0;
float x = 0, y = 0, z = 0; // canonical WoW coords (converted from DBC)
float radius = 0;
float boxLength = 0, boxWidth = 0, boxHeight = 0;
float boxYaw = 0;
};
bool areaTriggerDbcLoaded_ = false;
std::vector<AreaTriggerEntry> areaTriggers_;
std::unordered_set<uint32_t> activeAreaTriggers_; // triggers player is currently inside
@ -2709,8 +3020,6 @@ private:
// factionId → repListId reverse mapping
mutable std::unordered_map<uint32_t, uint32_t> factionIdToRepList_;
mutable bool factionNameCacheLoaded_ = false;
void loadFactionNameCache() const;
std::string getFactionName(uint32_t factionId) const;
// ---- Group ----
GroupListData partyData;
@ -2800,12 +3109,6 @@ private:
bool itemAutoLootSent = false;
};
std::unordered_map<uint64_t, LocalLootState> localLootState_;
struct PendingLootRetry {
uint64_t guid = 0;
float timer = 0.0f;
uint8_t remainingRetries = 0;
bool sendLoot = false;
};
std::vector<PendingLootRetry> pendingGameObjectLootRetries_;
struct PendingLootOpen {
uint64_t guid = 0;
@ -2879,10 +3182,6 @@ private:
// Faction hostility lookup (populated from FactionTemplate.dbc)
std::unordered_map<uint32_t, bool> factionHostileMap_;
bool isHostileFaction(uint32_t factionTemplateId) const {
auto it = factionHostileMap_.find(factionTemplateId);
return it != factionHostileMap_.end() ? it->second : true; // default hostile if unknown
}
// Vehicle (WotLK): non-zero when player is seated in a vehicle
uint32_t vehicleId_ = 0;
@ -2916,7 +3215,6 @@ private:
bool taxiMaskInitialized_ = false; // First SMSG_SHOWTAXINODES seeds mask without alerts
std::unordered_map<uint32_t, uint32_t> taxiCostMap_; // destNodeId -> total cost in copper
uint32_t nextMovementTimestampMs();
void sanitizeMovementForTaxi();
void updateClientTaxi(float deltaTime);
// Mail
@ -2980,12 +3278,6 @@ private:
// Trainer
bool trainerWindowOpen_ = false;
TrainerListData currentTrainerList_;
struct SpellNameEntry {
std::string name; std::string rank; std::string description;
uint32_t schoolMask = 0; uint8_t dispelType = 0; uint32_t attrEx = 0;
int32_t effectBasePoints[3] = {0, 0, 0};
float durationSec = 0.0f; // resolved from DurationIndex → SpellDuration.dbc
};
mutable std::unordered_map<uint32_t, SpellNameEntry> spellNameCache_;
mutable bool spellNameCacheLoaded_ = false;
@ -3004,7 +3296,6 @@ private:
std::unordered_map<uint32_t, std::string> achievementDescCache_;
std::unordered_map<uint32_t, uint32_t> achievementPointsCache_;
bool achievementNameCacheLoaded_ = false;
void loadAchievementNameCache();
// Set of achievement IDs earned by the player (populated from SMSG_ALL_ACHIEVEMENT_DATA)
std::unordered_set<uint32_t> earnedAchievements_;
// Earn dates: achievementId → WoW PackedTime (from SMSG_ACHIEVEMENT_EARNED / SMSG_ALL_ACHIEVEMENT_DATA)
@ -3021,7 +3312,6 @@ private:
mutable std::unordered_map<uint32_t, std::string> areaNameCache_;
mutable bool areaNameCacheLoaded_ = false;
void loadAreaNameCache() const;
std::string getAreaName(uint32_t areaId) const;
// Map name cache (lazy-loaded from Map.dbc; maps mapId → localized display name)
mutable std::unordered_map<uint32_t, std::string> mapNameCache_;
@ -3032,9 +3322,7 @@ private:
mutable std::unordered_map<uint32_t, std::string> lfgDungeonNameCache_;
mutable bool lfgDungeonNameCacheLoaded_ = false;
void loadLfgDungeonDbc() const;
std::string getLfgDungeonName(uint32_t dungeonId) const;
std::vector<TrainerTab> trainerTabs_;
void loadSpellNameCache() const;
void preloadDBCCaches() const;
void categorizeTrainerSpells();
@ -3127,15 +3415,9 @@ private:
bool spellBookTabsDirty_ = true;
bool skillLineDbcLoaded_ = false;
bool skillLineAbilityLoaded_ = false;
static constexpr size_t PLAYER_EXPLORED_ZONES_COUNT = 128;
std::vector<uint32_t> playerExploredZones_ =
std::vector<uint32_t>(PLAYER_EXPLORED_ZONES_COUNT, 0u);
bool hasPlayerExploredZones_ = false;
void loadSkillLineDbc();
void loadSkillLineAbilityDbc();
void extractSkillFields(const std::map<uint16_t, uint32_t>& fields);
void extractExploredZoneFields(const std::map<uint16_t, uint32_t>& fields);
void applyQuestStateFromFields(const std::map<uint16_t, uint32_t>& fields);
// Apply packed kill counts from player update fields to a quest entry that has
// already had its killObjectives populated from SMSG_QUEST_QUERY_RESPONSE.
void applyPackedKillCountsFromFields(QuestLogEntry& quest);

View file

@ -0,0 +1,73 @@
#pragma once
#include <glm/vec3.hpp>
#include <glm/vec4.hpp>
#include <glm/mat4x4.hpp>
#include <vulkan/vulkan.h>
#include <vk_mem_alloc.h>
#include <functional>
#include <optional>
namespace wowee {
namespace rendering {
class VkContext;
/// Manages selection circle and fullscreen overlay Vulkan pipelines.
/// Extracted from Renderer to isolate overlay rendering resources.
class OverlaySystem {
public:
/// Height query callable: returns floor height at (x, y) or (x, y, probeZ).
using HeightQuery2D = std::function<std::optional<float>(float x, float y)>;
using HeightQuery3D = std::function<std::optional<float>(float x, float y, float probeZ)>;
explicit OverlaySystem(VkContext* ctx);
~OverlaySystem();
OverlaySystem(const OverlaySystem&) = delete;
OverlaySystem& operator=(const OverlaySystem&) = delete;
// Selection circle
void setSelectionCircle(const glm::vec3& pos, float radius, const glm::vec3& color);
void clearSelectionCircle();
void renderSelectionCircle(const glm::mat4& view, const glm::mat4& projection,
VkCommandBuffer cmd,
HeightQuery2D terrainHeight,
HeightQuery3D wmoHeight,
HeightQuery3D m2Height);
// Fullscreen color overlay (underwater tint, etc.)
void renderOverlay(const glm::vec4& color, VkCommandBuffer cmd);
/// Destroy all Vulkan resources (called before VkContext teardown).
void cleanup();
/// Recreate pipelines after swapchain resize / MSAA change.
void recreatePipelines();
private:
void initSelectionCircle();
void initOverlayPipeline();
VkContext* vkCtx_ = nullptr;
// Selection circle resources
VkPipeline selCirclePipeline_ = VK_NULL_HANDLE;
VkPipelineLayout selCirclePipelineLayout_ = VK_NULL_HANDLE;
::VkBuffer selCircleVertBuf_ = VK_NULL_HANDLE;
VmaAllocation selCircleVertAlloc_ = VK_NULL_HANDLE;
::VkBuffer selCircleIdxBuf_ = VK_NULL_HANDLE;
VmaAllocation selCircleIdxAlloc_ = VK_NULL_HANDLE;
int selCircleVertCount_ = 0;
glm::vec3 selCirclePos_{0.0f};
glm::vec3 selCircleColor_{1.0f, 0.0f, 0.0f};
float selCircleRadius_ = 1.5f;
bool selCircleVisible_ = false;
// Fullscreen overlay resources
VkPipeline overlayPipeline_ = VK_NULL_HANDLE;
VkPipelineLayout overlayPipelineLayout_ = VK_NULL_HANDLE;
};
} // namespace rendering
} // namespace wowee

View file

@ -53,11 +53,11 @@ class AmdFsr3Runtime;
class SpellVisualSystem;
class PostProcessPipeline;
class AnimationController;
enum class RangedWeaponType : uint8_t;
class LevelUpEffect;
class ChargeEffect;
class SwimEffects;
class RenderGraph;
class OverlaySystem;
class Renderer {
public:
@ -139,7 +139,8 @@ public:
WorldMap* getWorldMap() const { return worldMap.get(); }
QuestMarkerRenderer* getQuestMarkerRenderer() const { return questMarkerRenderer.get(); }
SkySystem* getSkySystem() const { return skySystem.get(); }
const std::string& getCurrentZoneName() const { return currentZoneName; }
const std::string& getCurrentZoneName() const;
uint32_t getCurrentZoneId() const;
bool isPlayerIndoors() const { return playerIndoors_; }
VkContext* getVkContext() const { return vkCtx; }
VkDescriptorSetLayout getPerFrameSetLayout() const { return perFrameSetLayout; }
@ -152,52 +153,17 @@ public:
float getCharacterYaw() const { return characterYaw; }
void setCharacterYaw(float yawDeg) { characterYaw = yawDeg; }
// Emote support — delegates to AnimationController (§4.2)
void playEmote(const std::string& emoteName);
void triggerLevelUpEffect(const glm::vec3& position);
void cancelEmote();
// Screenshot capture — copies swapchain image to PNG file
bool captureScreenshot(const std::string& outputPath);
// Spell visual effects (SMSG_PLAY_SPELL_VISUAL / SMSG_PLAY_SPELL_IMPACT)
// Delegates to SpellVisualSystem (owned by Renderer)
void playSpellVisual(uint32_t visualId, const glm::vec3& worldPosition,
bool useImpactKit = false);
SpellVisualSystem* getSpellVisualSystem() const { return spellVisualSystem_.get(); }
bool isEmoteActive() const;
static std::string getEmoteText(const std::string& emoteName, const std::string* targetName = nullptr);
static uint32_t getEmoteDbcId(const std::string& emoteName);
static std::string getEmoteTextByDbcId(uint32_t dbcId, const std::string& senderName, const std::string* targetName = nullptr);
static uint32_t getEmoteAnimByDbcId(uint32_t dbcId);
// Targeting support — delegates to AnimationController (§4.2)
void setTargetPosition(const glm::vec3* pos);
void setInCombat(bool combat);
// Combat visual state (compound: resets AnimationController + SpellVisualSystem)
void resetCombatVisualState();
bool isMoving() const;
void triggerMeleeSwing();
void setEquippedWeaponType(uint32_t inventoryType, bool is2HLoose = false,
bool isFist = false, bool isDagger = false,
bool hasOffHand = false, bool hasShield = false);
void triggerSpecialAttack(uint32_t spellId);
void setEquippedRangedType(RangedWeaponType type);
void triggerRangedShot();
RangedWeaponType getEquippedRangedType() const;
void setCharging(bool charging);
bool isCharging() const;
void startChargeEffect(const glm::vec3& position, const glm::vec3& direction);
void emitChargeEffect(const glm::vec3& position, const glm::vec3& direction);
void stopChargeEffect();
// Mount rendering — delegates to AnimationController (§4.2)
void setMounted(uint32_t mountInstId, uint32_t mountDisplayId, float heightOffset, const std::string& modelPath = "");
void setTaxiFlight(bool onTaxi);
void setMountPitchRoll(float pitch, float roll);
void clearMount();
bool isMounted() const;
// AnimationController access (§4.2)
// Sub-system accessors (§4.2)
AnimationController* getAnimationController() const { return animationController_.get(); }
LevelUpEffect* getLevelUpEffect() const { return levelUpEffect.get(); }
ChargeEffect* getChargeEffect() const { return chargeEffect.get(); }
@ -286,33 +252,8 @@ public:
// Post-process pipeline API — delegates to PostProcessPipeline (§4.3)
PostProcessPipeline* getPostProcessPipeline() const;
void setFXAAEnabled(bool enabled);
bool isFXAAEnabled() const;
void setFSREnabled(bool enabled);
bool isFSREnabled() const;
void setFSRQuality(float scaleFactor);
void setFSRSharpness(float sharpness);
float getFSRScaleFactor() const;
float getFSRSharpness() const;
void setFSR2Enabled(bool enabled);
bool isFSR2Enabled() const;
void setFSR2DebugTuning(float jitterSign, float motionVecScaleX, float motionVecScaleY);
void setAmdFsr3FramegenEnabled(bool enabled);
bool isAmdFsr3FramegenEnabled() const;
float getFSR2JitterSign() const;
float getFSR2MotionVecScaleX() const;
float getFSR2MotionVecScaleY() const;
bool isAmdFsr2SdkAvailable() const;
bool isAmdFsr3FramegenSdkAvailable() const;
bool isAmdFsr3FramegenRuntimeActive() const;
bool isAmdFsr3FramegenRuntimeReady() const;
const char* getAmdFsr3FramegenRuntimePath() const;
const std::string& getAmdFsr3FramegenRuntimeError() const;
size_t getAmdFsr3UpscaleDispatchCount() const;
size_t getAmdFsr3FramegenDispatchCount() const;
size_t getAmdFsr3FallbackCount() const;
void setBrightness(float b);
float getBrightness() const;
void setWaterRefractionEnabled(bool enabled);
bool isWaterRefractionEnabled() const;
@ -332,12 +273,7 @@ private:
// Post-process pipeline — owns all FSR/FXAA/FSR2 state (extracted §4.3)
std::unique_ptr<PostProcessPipeline> postProcessPipeline_;
uint32_t currentZoneId = 0;
std::string currentZoneName;
bool inTavern_ = false;
bool inBlacksmith_ = false;
bool playerIndoors_ = false; // Cached WMO inside state for macro conditionals
float musicSwitchCooldown_ = 0.0f;
bool deferredWorldInitEnabled_ = true;
bool deferredWorldInitPending_ = false;
uint8_t deferredWorldInitStage_ = 0;
@ -350,26 +286,8 @@ private:
// Selection circle rendering (Vulkan)
VkPipeline selCirclePipeline = VK_NULL_HANDLE;
VkPipelineLayout selCirclePipelineLayout = VK_NULL_HANDLE;
::VkBuffer selCircleVertBuf = VK_NULL_HANDLE;
VmaAllocation selCircleVertAlloc = VK_NULL_HANDLE;
::VkBuffer selCircleIdxBuf = VK_NULL_HANDLE;
VmaAllocation selCircleIdxAlloc = VK_NULL_HANDLE;
int selCircleVertCount = 0;
void initSelectionCircle();
void renderSelectionCircle(const glm::mat4& view, const glm::mat4& projection, VkCommandBuffer overrideCmd = VK_NULL_HANDLE);
glm::vec3 selCirclePos{0.0f};
glm::vec3 selCircleColor{1.0f, 0.0f, 0.0f};
float selCircleRadius = 1.5f;
bool selCircleVisible = false;
// Fullscreen color overlay (underwater tint)
VkPipeline overlayPipeline = VK_NULL_HANDLE;
VkPipelineLayout overlayPipelineLayout = VK_NULL_HANDLE;
void initOverlayPipeline();
void renderOverlay(const glm::vec4& color, VkCommandBuffer overrideCmd = VK_NULL_HANDLE);
// Selection circle + overlay rendering (owned by OverlaySystem)
std::unique_ptr<OverlaySystem> overlaySystem_;