mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-04-04 04:03:52 +00:00
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/.
This commit is contained in:
parent
3762dceaa6
commit
b2710258dc
21 changed files with 20771 additions and 17858 deletions
191
include/game/combat_handler.hpp
Normal file
191
include/game/combat_handler.hpp
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
#pragma once
|
||||
|
||||
#include "game/world_packets.hpp"
|
||||
#include "game/opcode_table.hpp"
|
||||
#include "game/spell_defines.hpp"
|
||||
#include "network/packet.hpp"
|
||||
#include <chrono>
|
||||
#include <deque>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace wowee {
|
||||
namespace game {
|
||||
|
||||
class GameHandler;
|
||||
class Entity;
|
||||
|
||||
class CombatHandler {
|
||||
public:
|
||||
using PacketHandler = std::function<void(network::Packet&)>;
|
||||
using DispatchTable = std::unordered_map<LogicalOpcode, PacketHandler>;
|
||||
|
||||
explicit CombatHandler(GameHandler& owner);
|
||||
|
||||
void registerOpcodes(DispatchTable& table);
|
||||
|
||||
// --- Public API (delegated from GameHandler) ---
|
||||
void startAutoAttack(uint64_t targetGuid);
|
||||
void stopAutoAttack();
|
||||
bool isAutoAttacking() const { return autoAttacking_; }
|
||||
bool hasAutoAttackIntent() const { return autoAttackRequested_; }
|
||||
bool isInCombat() const { return autoAttacking_ || !hostileAttackers_.empty(); }
|
||||
bool isInCombatWith(uint64_t guid) const {
|
||||
return guid != 0 &&
|
||||
((autoAttacking_ && autoAttackTarget_ == guid) ||
|
||||
(hostileAttackers_.count(guid) > 0));
|
||||
}
|
||||
uint64_t getAutoAttackTargetGuid() const { return autoAttackTarget_; }
|
||||
bool isAggressiveTowardPlayer(uint64_t guid) const { return hostileAttackers_.count(guid) > 0; }
|
||||
uint64_t getLastMeleeSwingMs() const { return lastMeleeSwingMs_; }
|
||||
|
||||
// Floating combat text
|
||||
const std::vector<CombatTextEntry>& getCombatText() const { return combatText_; }
|
||||
void updateCombatText(float deltaTime);
|
||||
|
||||
// Combat log (persistent rolling history)
|
||||
const std::deque<CombatLogEntry>& getCombatLog() const { return combatLog_; }
|
||||
void clearCombatLog() { combatLog_.clear(); }
|
||||
|
||||
// Threat
|
||||
struct ThreatEntry {
|
||||
uint64_t victimGuid = 0;
|
||||
uint32_t threat = 0;
|
||||
};
|
||||
const std::vector<ThreatEntry>* getThreatList(uint64_t unitGuid) const {
|
||||
auto it = threatLists_.find(unitGuid);
|
||||
return (it != threatLists_.end()) ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
// Hostile attacker tracking
|
||||
bool isHostileAttacker(uint64_t guid) const { return hostileAttackers_.count(guid) > 0; }
|
||||
void clearHostileAttackers() { hostileAttackers_.clear(); }
|
||||
|
||||
// Forced faction reactions
|
||||
const std::unordered_map<uint32_t, uint8_t>& getForcedReactions() const { return forcedReactions_; }
|
||||
|
||||
// Auto-attack timing state (read by GameHandler::update for retry/resend logic)
|
||||
bool& autoAttackOutOfRangeRef() { return autoAttackOutOfRange_; }
|
||||
float& autoAttackOutOfRangeTimeRef() { return autoAttackOutOfRangeTime_; }
|
||||
float& autoAttackRangeWarnCooldownRef() { return autoAttackRangeWarnCooldown_; }
|
||||
float& autoAttackResendTimerRef() { return autoAttackResendTimer_; }
|
||||
float& autoAttackFacingSyncTimerRef() { return autoAttackFacingSyncTimer_; }
|
||||
bool& autoAttackRetryPendingRef() { return autoAttackRetryPending_; }
|
||||
|
||||
// Combat text creation (used by other handlers, e.g. spell handler for periodic damage)
|
||||
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);
|
||||
|
||||
// Spellsteal dedup (used by aura update handler)
|
||||
bool shouldLogSpellstealAura(uint64_t casterGuid, uint64_t victimGuid, uint32_t spellId);
|
||||
|
||||
// Called from GameHandler::update() each frame
|
||||
void updateAutoAttack(float deltaTime);
|
||||
|
||||
// --- Targeting ---
|
||||
void setTarget(uint64_t guid);
|
||||
void clearTarget();
|
||||
std::shared_ptr<Entity> getTarget() const;
|
||||
void setFocus(uint64_t guid);
|
||||
void clearFocus();
|
||||
std::shared_ptr<Entity> getFocus() const;
|
||||
void setMouseoverGuid(uint64_t guid);
|
||||
void targetLastTarget();
|
||||
void targetEnemy(bool reverse);
|
||||
void targetFriend(bool reverse);
|
||||
void tabTarget(float playerX, float playerY, float playerZ);
|
||||
void assistTarget();
|
||||
|
||||
// --- PvP ---
|
||||
void togglePvp();
|
||||
|
||||
// --- Death / Resurrection ---
|
||||
void releaseSpirit();
|
||||
bool canReclaimCorpse() const;
|
||||
float getCorpseReclaimDelaySec() const;
|
||||
void reclaimCorpse();
|
||||
void useSelfRes();
|
||||
void activateSpiritHealer(uint64_t npcGuid);
|
||||
void acceptResurrect();
|
||||
void declineResurrect();
|
||||
|
||||
// --- XP ---
|
||||
static uint32_t killXp(uint32_t playerLevel, uint32_t victimLevel);
|
||||
void handleXpGain(network::Packet& packet);
|
||||
|
||||
// State management (for resets, entity cleanup)
|
||||
void resetAllCombatState();
|
||||
void removeHostileAttacker(uint64_t guid);
|
||||
void clearCombatText();
|
||||
void removeCombatTextForGuid(uint64_t guid);
|
||||
|
||||
private:
|
||||
// --- Packet handlers ---
|
||||
void handleAttackStart(network::Packet& packet);
|
||||
void handleAttackStop(network::Packet& packet);
|
||||
void handleAttackerStateUpdate(network::Packet& packet);
|
||||
void handleSpellDamageLog(network::Packet& packet);
|
||||
void handleSpellHealLog(network::Packet& packet);
|
||||
void handleSetForcedReactions(network::Packet& packet);
|
||||
void handleHealthUpdate(network::Packet& packet);
|
||||
void handlePowerUpdate(network::Packet& packet);
|
||||
void handleUpdateComboPoints(network::Packet& packet);
|
||||
void handlePvpCredit(network::Packet& packet);
|
||||
void handleProcResist(network::Packet& packet);
|
||||
void handleEnvironmentalDamageLog(network::Packet& packet);
|
||||
void handleSpellDamageShield(network::Packet& packet);
|
||||
void handleSpellOrDamageImmune(network::Packet& packet);
|
||||
void handleResistLog(network::Packet& packet);
|
||||
void handlePetTameFailure(network::Packet& packet);
|
||||
void handlePetActionFeedback(network::Packet& packet);
|
||||
void handlePetCastFailed(network::Packet& packet);
|
||||
void handlePetBroken(network::Packet& packet);
|
||||
void handlePetLearnedSpell(network::Packet& packet);
|
||||
void handlePetUnlearnedSpell(network::Packet& packet);
|
||||
void handlePetMode(network::Packet& packet);
|
||||
void handleResurrectFailed(network::Packet& packet);
|
||||
|
||||
void autoTargetAttacker(uint64_t attackerGuid);
|
||||
|
||||
GameHandler& owner_;
|
||||
|
||||
// --- Combat state ---
|
||||
bool autoAttacking_ = false;
|
||||
bool autoAttackRequested_ = false;
|
||||
bool autoAttackRetryPending_ = false;
|
||||
uint64_t autoAttackTarget_ = 0;
|
||||
bool autoAttackOutOfRange_ = false;
|
||||
float autoAttackOutOfRangeTime_ = 0.0f;
|
||||
float autoAttackRangeWarnCooldown_ = 0.0f;
|
||||
float autoAttackResendTimer_ = 0.0f;
|
||||
float autoAttackFacingSyncTimer_ = 0.0f;
|
||||
std::unordered_set<uint64_t> hostileAttackers_;
|
||||
std::vector<CombatTextEntry> combatText_;
|
||||
static constexpr size_t MAX_COMBAT_LOG = 500;
|
||||
std::deque<CombatLogEntry> combatLog_;
|
||||
|
||||
struct RecentSpellstealLogEntry {
|
||||
uint64_t casterGuid = 0;
|
||||
uint64_t victimGuid = 0;
|
||||
uint32_t spellId = 0;
|
||||
std::chrono::steady_clock::time_point timestamp{};
|
||||
};
|
||||
static constexpr size_t MAX_RECENT_SPELLSTEAL_LOGS = 32;
|
||||
std::deque<RecentSpellstealLogEntry> recentSpellstealLogs_;
|
||||
|
||||
uint64_t lastMeleeSwingMs_ = 0;
|
||||
|
||||
// unitGuid → sorted threat list (descending by threat value)
|
||||
std::unordered_map<uint64_t, std::vector<ThreatEntry>> threatLists_;
|
||||
|
||||
// Forced faction reactions
|
||||
std::unordered_map<uint32_t, uint8_t> forcedReactions_;
|
||||
};
|
||||
|
||||
} // namespace game
|
||||
} // namespace wowee
|
||||
Loading…
Add table
Add a link
Reference in a new issue