mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-04-03 20:03:50 +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
401
include/game/inventory_handler.hpp
Normal file
401
include/game/inventory_handler.hpp
Normal file
|
|
@ -0,0 +1,401 @@
|
|||
#pragma once
|
||||
|
||||
#include "game/world_packets.hpp"
|
||||
#include "game/opcode_table.hpp"
|
||||
#include "game/inventory.hpp"
|
||||
#include "game/handler_types.hpp"
|
||||
#include "network/packet.hpp"
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <deque>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace wowee {
|
||||
namespace game {
|
||||
|
||||
class GameHandler;
|
||||
|
||||
class InventoryHandler {
|
||||
public:
|
||||
using PacketHandler = std::function<void(network::Packet&)>;
|
||||
using DispatchTable = std::unordered_map<LogicalOpcode, PacketHandler>;
|
||||
|
||||
explicit InventoryHandler(GameHandler& owner);
|
||||
|
||||
void registerOpcodes(DispatchTable& table);
|
||||
|
||||
// ---- Item text (books / readable items) ----
|
||||
bool isItemTextOpen() const { return itemTextOpen_; }
|
||||
const std::string& getItemText() const { return itemText_; }
|
||||
void closeItemText() { itemTextOpen_ = false; }
|
||||
void queryItemText(uint64_t itemGuid);
|
||||
|
||||
// ---- Trade ----
|
||||
enum class TradeStatus : uint8_t {
|
||||
None = 0, PendingIncoming, Open, Accepted, Complete
|
||||
};
|
||||
|
||||
static constexpr int TRADE_SLOT_COUNT = 6;
|
||||
|
||||
struct TradeSlot {
|
||||
uint32_t itemId = 0;
|
||||
uint32_t displayId = 0;
|
||||
uint32_t stackCount = 0;
|
||||
uint64_t itemGuid = 0;
|
||||
};
|
||||
|
||||
TradeStatus getTradeStatus() const { return tradeStatus_; }
|
||||
bool hasPendingTradeRequest() const { return tradeStatus_ == TradeStatus::PendingIncoming; }
|
||||
bool isTradeOpen() const { return tradeStatus_ == TradeStatus::Open; }
|
||||
const std::string& getTradePeerName() const { return tradePeerName_; }
|
||||
const std::array<TradeSlot, TRADE_SLOT_COUNT>& getMyTradeSlots() const { return myTradeSlots_; }
|
||||
const std::array<TradeSlot, TRADE_SLOT_COUNT>& getPeerTradeSlots() const { return peerTradeSlots_; }
|
||||
uint64_t getMyTradeGold() const { return myTradeGold_; }
|
||||
uint64_t getPeerTradeGold() const { return peerTradeGold_; }
|
||||
void acceptTradeRequest();
|
||||
void declineTradeRequest();
|
||||
void acceptTrade();
|
||||
void cancelTrade();
|
||||
void setTradeItem(uint8_t tradeSlot, uint8_t srcBag, uint8_t srcSlot);
|
||||
void clearTradeItem(uint8_t tradeSlot);
|
||||
void setTradeGold(uint64_t amount);
|
||||
|
||||
// ---- Loot ----
|
||||
void lootTarget(uint64_t targetGuid);
|
||||
void lootItem(uint8_t slotIndex);
|
||||
void closeLoot();
|
||||
bool isLootWindowOpen() const { return lootWindowOpen_; }
|
||||
const LootResponseData& getCurrentLoot() const { return currentLoot_; }
|
||||
void setAutoLoot(bool enabled) { autoLoot_ = enabled; }
|
||||
bool isAutoLoot() const { return autoLoot_; }
|
||||
void setAutoSellGrey(bool enabled) { autoSellGrey_ = enabled; }
|
||||
bool isAutoSellGrey() const { return autoSellGrey_; }
|
||||
void setAutoRepair(bool enabled) { autoRepair_ = enabled; }
|
||||
bool isAutoRepair() const { return autoRepair_; }
|
||||
|
||||
// Master loot candidates (from SMSG_LOOT_MASTER_LIST)
|
||||
const std::vector<uint64_t>& getMasterLootCandidates() const { return masterLootCandidates_; }
|
||||
bool hasMasterLootCandidates() const { return !masterLootCandidates_.empty(); }
|
||||
void lootMasterGive(uint8_t lootSlot, uint64_t targetGuid);
|
||||
|
||||
// Group loot roll (aliased from handler_types.hpp)
|
||||
using LootRollEntry = game::LootRollEntry;
|
||||
bool hasPendingLootRoll() const { return pendingLootRollActive_; }
|
||||
const LootRollEntry& getPendingLootRoll() const { return pendingLootRoll_; }
|
||||
void sendLootRoll(uint64_t objectGuid, uint32_t slot, uint8_t rollType);
|
||||
|
||||
// ---- Equipment Sets (aliased from handler_types.hpp) ----
|
||||
using EquipmentSetInfo = game::EquipmentSetInfo;
|
||||
const std::vector<EquipmentSetInfo>& getEquipmentSets() const { return equipmentSetInfo_; }
|
||||
bool supportsEquipmentSets() const;
|
||||
void useEquipmentSet(uint32_t setId);
|
||||
void saveEquipmentSet(const std::string& name, const std::string& iconName = "INV_Misc_QuestionMark",
|
||||
uint64_t existingGuid = 0, uint32_t setIndex = 0xFFFFFFFF);
|
||||
void deleteEquipmentSet(uint64_t setGuid);
|
||||
|
||||
// ---- Vendor ----
|
||||
struct BuybackItem {
|
||||
uint64_t itemGuid = 0;
|
||||
ItemDef item;
|
||||
uint32_t count = 1;
|
||||
};
|
||||
void openVendor(uint64_t npcGuid);
|
||||
void closeVendor();
|
||||
void buyItem(uint64_t vendorGuid, uint32_t itemId, uint32_t slot, uint32_t count);
|
||||
void sellItem(uint64_t vendorGuid, uint64_t itemGuid, uint32_t count);
|
||||
void sellItemBySlot(int backpackIndex);
|
||||
void sellItemInBag(int bagIndex, int slotIndex);
|
||||
void buyBackItem(uint32_t buybackSlot);
|
||||
void repairItem(uint64_t vendorGuid, uint64_t itemGuid);
|
||||
void repairAll(uint64_t vendorGuid, bool useGuildBank = false);
|
||||
const std::deque<BuybackItem>& getBuybackItems() const { return buybackItems_; }
|
||||
void autoEquipItemBySlot(int backpackIndex);
|
||||
void autoEquipItemInBag(int bagIndex, int slotIndex);
|
||||
void useItemBySlot(int backpackIndex);
|
||||
void useItemInBag(int bagIndex, int slotIndex);
|
||||
void openItemBySlot(int backpackIndex);
|
||||
void openItemInBag(int bagIndex, int slotIndex);
|
||||
void destroyItem(uint8_t bag, uint8_t slot, uint8_t count = 1);
|
||||
void splitItem(uint8_t srcBag, uint8_t srcSlot, uint8_t count);
|
||||
void swapContainerItems(uint8_t srcBag, uint8_t srcSlot, uint8_t dstBag, uint8_t dstSlot);
|
||||
void swapBagSlots(int srcBagIndex, int dstBagIndex);
|
||||
void unequipToBackpack(EquipSlot equipSlot);
|
||||
void useItemById(uint32_t itemId);
|
||||
bool isVendorWindowOpen() const { return vendorWindowOpen_; }
|
||||
const ListInventoryData& getVendorItems() const { return currentVendorItems_; }
|
||||
void setVendorCanRepair(bool v) { currentVendorItems_.canRepair = v; }
|
||||
uint64_t getVendorGuid() const { return currentVendorItems_.vendorGuid; }
|
||||
|
||||
// ---- Mail ----
|
||||
static constexpr int MAIL_MAX_ATTACHMENTS = 12;
|
||||
struct MailAttachSlot {
|
||||
uint64_t itemGuid = 0;
|
||||
game::ItemDef item;
|
||||
uint8_t srcBag = 0xFF;
|
||||
uint8_t srcSlot = 0;
|
||||
bool occupied() const { return itemGuid != 0; }
|
||||
};
|
||||
bool isMailboxOpen() const { return mailboxOpen_; }
|
||||
const std::vector<MailMessage>& getMailInbox() const { return mailInbox_; }
|
||||
int getSelectedMailIndex() const { return selectedMailIndex_; }
|
||||
void setSelectedMailIndex(int idx) { selectedMailIndex_ = idx; }
|
||||
bool isMailComposeOpen() const { return showMailCompose_; }
|
||||
void openMailCompose() { showMailCompose_ = true; clearMailAttachments(); }
|
||||
void closeMailCompose() { showMailCompose_ = false; clearMailAttachments(); }
|
||||
bool hasNewMail() const { return hasNewMail_; }
|
||||
void closeMailbox();
|
||||
void sendMail(const std::string& recipient, const std::string& subject,
|
||||
const std::string& body, uint64_t money, uint64_t cod = 0);
|
||||
bool attachItemFromBackpack(int backpackIndex);
|
||||
bool attachItemFromBag(int bagIndex, int slotIndex);
|
||||
bool detachMailAttachment(int attachIndex);
|
||||
void clearMailAttachments();
|
||||
const std::array<MailAttachSlot, 12>& getMailAttachments() const { return mailAttachments_; }
|
||||
int getMailAttachmentCount() const;
|
||||
void mailTakeMoney(uint32_t mailId);
|
||||
void mailTakeItem(uint32_t mailId, uint32_t itemGuidLow);
|
||||
void mailDelete(uint32_t mailId);
|
||||
void mailMarkAsRead(uint32_t mailId);
|
||||
void refreshMailList();
|
||||
|
||||
// ---- Bank ----
|
||||
void openBank(uint64_t guid);
|
||||
void closeBank();
|
||||
void buyBankSlot();
|
||||
void depositItem(uint8_t srcBag, uint8_t srcSlot);
|
||||
void withdrawItem(uint8_t srcBag, uint8_t srcSlot);
|
||||
bool isBankOpen() const { return bankOpen_; }
|
||||
uint64_t getBankerGuid() const { return bankerGuid_; }
|
||||
int getEffectiveBankSlots() const { return effectiveBankSlots_; }
|
||||
int getEffectiveBankBagSlots() const { return effectiveBankBagSlots_; }
|
||||
|
||||
// ---- Guild Bank ----
|
||||
void openGuildBank(uint64_t guid);
|
||||
void closeGuildBank();
|
||||
void queryGuildBankTab(uint8_t tabId);
|
||||
void buyGuildBankTab();
|
||||
void depositGuildBankMoney(uint32_t amount);
|
||||
void withdrawGuildBankMoney(uint32_t amount);
|
||||
void guildBankWithdrawItem(uint8_t tabId, uint8_t bankSlot, uint8_t destBag, uint8_t destSlot);
|
||||
void guildBankDepositItem(uint8_t tabId, uint8_t bankSlot, uint8_t srcBag, uint8_t srcSlot);
|
||||
bool isGuildBankOpen() const { return guildBankOpen_; }
|
||||
const GuildBankData& getGuildBankData() const { return guildBankData_; }
|
||||
uint8_t getGuildBankActiveTab() const { return guildBankActiveTab_; }
|
||||
void setGuildBankActiveTab(uint8_t tab) { guildBankActiveTab_ = tab; }
|
||||
|
||||
// ---- Auction House ----
|
||||
void openAuctionHouse(uint64_t guid);
|
||||
void closeAuctionHouse();
|
||||
void auctionSearch(const std::string& name, uint8_t levelMin, uint8_t levelMax,
|
||||
uint32_t quality, uint32_t itemClass, uint32_t itemSubClass,
|
||||
uint32_t invTypeMask, uint8_t usableOnly, uint32_t offset = 0);
|
||||
void auctionSellItem(uint64_t itemGuid, uint32_t stackCount, uint32_t bid,
|
||||
uint32_t buyout, uint32_t duration);
|
||||
void auctionPlaceBid(uint32_t auctionId, uint32_t amount);
|
||||
void auctionBuyout(uint32_t auctionId, uint32_t buyoutPrice);
|
||||
void auctionCancelItem(uint32_t auctionId);
|
||||
void auctionListOwnerItems(uint32_t offset = 0);
|
||||
void auctionListBidderItems(uint32_t offset = 0);
|
||||
bool isAuctionHouseOpen() const { return auctionOpen_; }
|
||||
uint64_t getAuctioneerGuid() const { return auctioneerGuid_; }
|
||||
const AuctionListResult& getAuctionBrowseResults() const { return auctionBrowseResults_; }
|
||||
const AuctionListResult& getAuctionOwnerResults() const { return auctionOwnerResults_; }
|
||||
const AuctionListResult& getAuctionBidderResults() const { return auctionBidderResults_; }
|
||||
int getAuctionActiveTab() const { return auctionActiveTab_; }
|
||||
void setAuctionActiveTab(int tab) { auctionActiveTab_ = tab; }
|
||||
float getAuctionSearchDelay() const { return auctionSearchDelayTimer_; }
|
||||
|
||||
// ---- Trainer ----
|
||||
struct TrainerTab {
|
||||
std::string name;
|
||||
std::vector<const TrainerSpell*> spells;
|
||||
};
|
||||
bool isTrainerWindowOpen() const { return trainerWindowOpen_; }
|
||||
const TrainerListData& getTrainerSpells() const { return currentTrainerList_; }
|
||||
void trainSpell(uint32_t spellId);
|
||||
void closeTrainer();
|
||||
const std::vector<TrainerTab>& getTrainerTabs() const { return trainerTabs_; }
|
||||
void resetTradeState();
|
||||
|
||||
// ---- Methods moved from GameHandler ----
|
||||
void initiateTrade(uint64_t targetGuid);
|
||||
uint32_t getTempEnchantRemainingMs(uint32_t slot) const;
|
||||
void addMoneyCopper(uint32_t amount);
|
||||
|
||||
// ---- Inventory field / rebuild methods (moved from GameHandler) ----
|
||||
void queryItemInfo(uint32_t entry, uint64_t guid);
|
||||
uint64_t resolveOnlineItemGuid(uint32_t itemId) const;
|
||||
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 rebuildOnlineInventory();
|
||||
void maybeDetectVisibleItemLayout();
|
||||
void updateOtherPlayerVisibleItems(uint64_t guid, const std::map<uint16_t, uint32_t>& fields);
|
||||
void emitOtherPlayerEquipment(uint64_t guid);
|
||||
void emitAllOtherPlayerEquipment();
|
||||
void handleItemQueryResponse(network::Packet& packet);
|
||||
|
||||
private:
|
||||
// --- Packet handlers ---
|
||||
void handleLootResponse(network::Packet& packet);
|
||||
void handleLootReleaseResponse(network::Packet& packet);
|
||||
void handleLootRemoved(network::Packet& packet);
|
||||
void handleListInventory(network::Packet& packet);
|
||||
void handleTrainerList(network::Packet& packet);
|
||||
void handleItemTextQueryResponse(network::Packet& packet);
|
||||
void handleTradeStatus(network::Packet& packet);
|
||||
void handleTradeStatusExtended(network::Packet& packet);
|
||||
void handleLootRoll(network::Packet& packet);
|
||||
void handleLootRollWon(network::Packet& packet);
|
||||
void handleShowBank(network::Packet& packet);
|
||||
void handleBuyBankSlotResult(network::Packet& packet);
|
||||
void handleGuildBankList(network::Packet& packet);
|
||||
void handleAuctionHello(network::Packet& packet);
|
||||
void handleAuctionListResult(network::Packet& packet);
|
||||
void handleAuctionOwnerListResult(network::Packet& packet);
|
||||
void handleAuctionBidderListResult(network::Packet& packet);
|
||||
void handleAuctionCommandResult(network::Packet& packet);
|
||||
void handleShowMailbox(network::Packet& packet);
|
||||
void handleMailListResult(network::Packet& packet);
|
||||
void handleSendMailResult(network::Packet& packet);
|
||||
void handleReceivedMail(network::Packet& packet);
|
||||
void handleQueryNextMailTime(network::Packet& packet);
|
||||
void handleEquipmentSetList(network::Packet& packet);
|
||||
|
||||
void categorizeTrainerSpells();
|
||||
void handleTrainerBuySucceeded(network::Packet& packet);
|
||||
void handleTrainerBuyFailed(network::Packet& packet);
|
||||
|
||||
GameHandler& owner_;
|
||||
|
||||
// ---- Item text state ----
|
||||
bool itemTextOpen_ = false;
|
||||
std::string itemText_;
|
||||
|
||||
// ---- Trade state ----
|
||||
TradeStatus tradeStatus_ = TradeStatus::None;
|
||||
uint64_t tradePeerGuid_= 0;
|
||||
std::string tradePeerName_;
|
||||
std::array<TradeSlot, TRADE_SLOT_COUNT> myTradeSlots_{};
|
||||
std::array<TradeSlot, TRADE_SLOT_COUNT> peerTradeSlots_{};
|
||||
uint64_t myTradeGold_ = 0;
|
||||
uint64_t peerTradeGold_ = 0;
|
||||
|
||||
// ---- Loot state ----
|
||||
bool lootWindowOpen_ = false;
|
||||
bool autoLoot_ = false;
|
||||
bool autoSellGrey_ = false;
|
||||
bool autoRepair_ = false;
|
||||
LootResponseData currentLoot_;
|
||||
std::vector<uint64_t> masterLootCandidates_;
|
||||
|
||||
// Group loot roll state
|
||||
bool pendingLootRollActive_ = false;
|
||||
LootRollEntry pendingLootRoll_;
|
||||
struct LocalLootState {
|
||||
LootResponseData data;
|
||||
bool moneyTaken = false;
|
||||
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;
|
||||
float timer = 0.0f;
|
||||
};
|
||||
std::vector<PendingLootOpen> pendingGameObjectLootOpens_;
|
||||
uint64_t lastInteractedGoGuid_ = 0;
|
||||
uint64_t pendingLootMoneyGuid_ = 0;
|
||||
uint32_t pendingLootMoneyAmount_ = 0;
|
||||
float pendingLootMoneyNotifyTimer_ = 0.0f;
|
||||
std::unordered_map<uint64_t, float> recentLootMoneyAnnounceCooldowns_;
|
||||
|
||||
// ---- Vendor state ----
|
||||
bool vendorWindowOpen_ = false;
|
||||
ListInventoryData currentVendorItems_;
|
||||
std::deque<BuybackItem> buybackItems_;
|
||||
std::unordered_map<uint64_t, BuybackItem> pendingSellToBuyback_;
|
||||
int pendingBuybackSlot_ = -1;
|
||||
uint32_t pendingBuybackWireSlot_ = 0;
|
||||
uint32_t pendingBuyItemId_ = 0;
|
||||
uint32_t pendingBuyItemSlot_ = 0;
|
||||
|
||||
// ---- Mail state ----
|
||||
bool mailboxOpen_ = false;
|
||||
uint64_t mailboxGuid_ = 0;
|
||||
std::vector<MailMessage> mailInbox_;
|
||||
int selectedMailIndex_ = -1;
|
||||
bool showMailCompose_ = false;
|
||||
bool hasNewMail_ = false;
|
||||
std::array<MailAttachSlot, MAIL_MAX_ATTACHMENTS> mailAttachments_{};
|
||||
|
||||
// ---- Bank state ----
|
||||
bool bankOpen_ = false;
|
||||
uint64_t bankerGuid_ = 0;
|
||||
std::array<uint64_t, 28> bankSlotGuids_{};
|
||||
std::array<uint64_t, 7> bankBagSlotGuids_{};
|
||||
int effectiveBankSlots_ = 28;
|
||||
int effectiveBankBagSlots_ = 7;
|
||||
|
||||
// ---- Guild Bank state ----
|
||||
bool guildBankOpen_ = false;
|
||||
uint64_t guildBankerGuid_ = 0;
|
||||
GuildBankData guildBankData_;
|
||||
uint8_t guildBankActiveTab_ = 0;
|
||||
|
||||
// ---- Auction House state ----
|
||||
bool auctionOpen_ = false;
|
||||
uint64_t auctioneerGuid_ = 0;
|
||||
uint32_t auctionHouseId_ = 0;
|
||||
AuctionListResult auctionBrowseResults_;
|
||||
AuctionListResult auctionOwnerResults_;
|
||||
AuctionListResult auctionBidderResults_;
|
||||
int auctionActiveTab_ = 0;
|
||||
float auctionSearchDelayTimer_ = 0.0f;
|
||||
struct AuctionSearchParams {
|
||||
std::string name;
|
||||
uint8_t levelMin = 0, levelMax = 0;
|
||||
uint32_t quality = 0xFFFFFFFF;
|
||||
uint32_t itemClass = 0xFFFFFFFF;
|
||||
uint32_t itemSubClass = 0xFFFFFFFF;
|
||||
uint32_t invTypeMask = 0;
|
||||
uint8_t usableOnly = 0;
|
||||
uint32_t offset = 0;
|
||||
};
|
||||
AuctionSearchParams lastAuctionSearch_;
|
||||
enum class AuctionResultTarget { BROWSE, OWNER, BIDDER };
|
||||
AuctionResultTarget pendingAuctionTarget_ = AuctionResultTarget::BROWSE;
|
||||
|
||||
// ---- Trainer state ----
|
||||
bool trainerWindowOpen_ = false;
|
||||
TrainerListData currentTrainerList_;
|
||||
std::vector<TrainerTab> trainerTabs_;
|
||||
|
||||
// ---- Equipment set state ----
|
||||
struct EquipmentSet {
|
||||
uint64_t setGuid = 0;
|
||||
uint32_t setId = 0;
|
||||
std::string name;
|
||||
std::string iconName;
|
||||
uint32_t ignoreSlotMask = 0;
|
||||
std::array<uint64_t, 19> itemGuids{};
|
||||
};
|
||||
std::vector<EquipmentSet> equipmentSets_;
|
||||
std::string pendingSaveSetName_;
|
||||
std::string pendingSaveSetIcon_;
|
||||
std::vector<EquipmentSetInfo> equipmentSetInfo_;
|
||||
};
|
||||
|
||||
} // namespace game
|
||||
} // namespace wowee
|
||||
Loading…
Add table
Add a link
Reference in a new issue