# TrinityCore PlayerBot Developer Guide **Version**: 1.0 **Last Updated**: 2025-11-18 **Target**: TrinityCore 3.3.5a (WotLK) --- ## Table of Contents 1. [Architecture Overview](#architecture-overview) 2. [Quest System](#quest-system) 3. [Profession Systems](#profession-systems) 4. [Economy Systems](#economy-systems) 5. [Combat Systems](#combat-systems) 6. [Movement System](#movement-system) 7. [Lifecycle Systems](#lifecycle-systems) 8. [Group Systems](#group-systems) 9. [Decision Systems](#decision-systems) 10. [Core Infrastructure](#core-infrastructure) 11. [Integration Guide](#integration-guide) 12. [Best Practices](#best-practices) --- ## Architecture Overview ### GameSystemsManager Facade The **GameSystemsManager** is a facade that consolidates all 21 bot manager instances, providing centralized ownership and lifecycle management. This architecture follows the **Facade Pattern** and **Dependency Injection** principles. ```cpp // Access pattern BotAI* botAI = ...; // Your bot AI instance auto* gameSystems = botAI->GetGameSystems(); // Use any system gameSystems->GetQuestManager()->AcceptQuest(questId); gameSystems->GetProfessionManager()->CraftItem(recipeId); gameSystems->GetCombatStateManager()->EnterCombat(target); ``` ### Manager Categories | Category | Managers | Purpose | |----------|----------|---------| | **Quest** | 1 | Quest tracking, acceptance, completion | | **Profession** | 8 | Gathering, crafting, material optimization | | **Economy** | 2 | Trading, auction house operations | | **Combat** | 2 | Combat state management, target selection | | **Movement** | 1 | Pathfinding, movement coordination | | **Lifecycle** | 1 | Death recovery, corpse retrieval | | **Group** | 2 | Group formation, invitation handling | | **Decision** | 4 | AI decision-making, behavior trees | | **Infrastructure** | 3 | Events, registry, priority management | **Total**: 21 managers --- ## Quest System ### QuestManager **Purpose**: Manages quest tracking, acceptance, turn-ins, and objective completion for bots. **Location**: `src/modules/Playerbot/Game/QuestManager.h` #### Key Responsibilities - Quest discovery and evaluation - Quest acceptance and turn-in automation - Objective tracking and completion - Reward selection optimization - Quest chain navigation #### Core Methods ##### Quest Discovery ```cpp /** * @brief Find available quests in the world * @param searchRadius Radius in yards to search for quest givers * @return Vector of available quest IDs */ std::vector FindAvailableQuests(float searchRadius = 100.0f); /** * @brief Check if a quest is available for the bot * @param questId Quest entry ID * @return true if quest can be accepted */ bool IsQuestAvailable(uint32 questId) const; ``` ##### Quest Management ```cpp /** * @brief Accept a quest from a quest giver * @param questId Quest entry ID * @param questGiverGuid GUID of the NPC or GameObject offering the quest * @return true if quest was accepted successfully */ bool AcceptQuest(uint32 questId, ObjectGuid questGiverGuid); /** * @brief Turn in a completed quest * @param questId Quest entry ID * @param rewardChoice Index of reward to select (0-based) * @return true if quest was turned in successfully */ bool TurnInQuest(uint32 questId, uint8 rewardChoice = 0); /** * @brief Abandon an active quest * @param questId Quest entry ID * @return true if quest was abandoned */ bool AbandonQuest(uint32 questId); ``` ##### Quest Tracking ```cpp /** * @brief Get all active quests for the bot * @return Vector of active quest IDs */ std::vector GetActiveQuests() const; /** * @brief Check if a quest is complete and ready for turn-in * @param questId Quest entry ID * @return true if all objectives are complete */ bool IsQuestComplete(uint32 questId) const; /** * @brief Get quest objective status * @param questId Quest entry ID * @return Map of objective index to completion status */ std::map GetQuestObjectives(uint32 questId) const; ``` ##### Reward Optimization ```cpp /** * @brief Select best reward from quest options * @param questId Quest entry ID * @return Index of optimal reward (considers item value, usability, class) */ uint8 SelectBestReward(uint32 questId) const; ``` #### Usage Example ```cpp // Quest workflow example auto* questMgr = gameSystems->GetQuestManager(); // 1. Find available quests auto availableQuests = questMgr->FindAvailableQuests(); // 2. Accept highest priority quest for (uint32 questId : availableQuests) { if (questMgr->IsQuestAvailable(questId)) { Creature* questGiver = FindNearestQuestGiver(questId); if (questGiver) { questMgr->AcceptQuest(questId, questGiver->GetGUID()); break; } } } // 3. Track active quests auto activeQuests = questMgr->GetActiveQuests(); for (uint32 questId : activeQuests) { if (questMgr->IsQuestComplete(questId)) { // Quest is complete, find turn-in NPC uint8 rewardChoice = questMgr->SelectBestReward(questId); questMgr->TurnInQuest(questId, rewardChoice); } } ``` --- ## Profession Systems The profession system consists of **8 managers** working together to provide automated profession management, material optimization, and economic decision-making. ### System Architecture ``` ProfessionManager (Core) ↓ GatheringManager ←→ GatheringMaterialsBridge ↓ ↓ └─────> AuctionMaterialsBridge ←─────┘ ↓ ProfessionAuctionBridge ↓ AuctionHouse (TrinityCore) ``` ### ProfessionManager **Purpose**: Core profession management - skill tracking, recipe learning, crafting automation. **Location**: `src/modules/Playerbot/Professions/ProfessionManager.h` **Architecture**: Per-bot instance (Phase 1B refactoring) #### Key Responsibilities - Profession skill tracking (current/max levels) - Recipe database management - Crafting automation - Profession leveling optimization - Material requirement calculations #### Core Methods ##### Profession Information ```cpp /** * @brief Get all professions for the bot * @return Vector of ProfessionInfo structures */ std::vector GetPlayerProfessions() const; /** * @brief Get profession skill level * @param profession Profession type * @return Current skill level (0 if not learned) */ uint32 GetProfessionSkill(ProfessionType profession) const; /** * @brief Check if bot has a specific profession * @param profession Profession type * @return true if profession is learned */ bool HasProfession(ProfessionType profession) const; ``` ##### Recipe Management ```cpp /** * @brief Get all recipes for a profession * @param profession Profession type * @return Vector of RecipeInfo structures */ std::vector GetRecipesForProfession(ProfessionType profession) const; /** * @brief Check if bot knows a recipe * @param recipeId Recipe spell ID * @return true if recipe is learned */ bool KnowsRecipe(uint32 recipeId) const; /** * @brief Learn a new recipe * @param recipeId Recipe spell ID * @return true if recipe was learned */ bool LearnRecipe(uint32 recipeId); ``` ##### Crafting ```cpp /** * @brief Craft an item from a recipe * @param recipeId Recipe spell ID * @param count Number of items to craft * @return true if crafting was initiated */ bool CraftItem(uint32 recipeId, uint32 count = 1); /** * @brief Check if bot has materials for a recipe * @param recipeId Recipe spell ID * @param count Number of items to craft * @return true if all materials are available */ bool HasMaterialsForRecipe(uint32 recipeId, uint32 count = 1) const; /** * @brief Get missing materials for a recipe * @param recipe RecipeInfo reference * @return Vector of pairs (itemId, quantity needed) */ std::vector> GetMissingMaterials(RecipeInfo const& recipe) const; ``` ##### Profession Leveling ```cpp /** * @brief Get optimal recipe for leveling a profession * @param profession Profession type * @return Pointer to RecipeInfo, nullptr if none available */ RecipeInfo const* GetOptimalLevelingRecipe(ProfessionType profession) const; /** * @brief Calculate skill-up chance for a recipe * @param recipeId Recipe spell ID * @return Probability of skill gain (0.0 - 1.0) */ float GetSkillUpChance(uint32 recipeId) const; ``` #### ProfessionInfo Structure ```cpp struct ProfessionInfo { ProfessionType profession; // Profession enum uint32 currentSkill; // Current skill level uint32 maxSkill; // Maximum skill level for expansion uint32 professionId; // WoW profession ID std::string name; // Profession name }; ``` #### RecipeInfo Structure ```cpp struct RecipeInfo { uint32 recipeId; // Recipe spell ID uint32 productItemId; // Crafted item ID uint32 productCount; // Items created per craft ProfessionType profession; // Required profession uint32 requiredSkill; // Minimum skill level uint32 yellowSkill; // Yellow skill threshold uint32 greenSkill; // Green skill threshold uint32 greySkill; // Grey skill threshold struct Reagent { uint32 itemId; // Material item ID uint32 quantity; // Quantity required }; std::vector reagents; // Required materials }; ``` #### Usage Example ```cpp auto* profMgr = gameSystems->GetProfessionManager(); // Check professions auto professions = profMgr->GetPlayerProfessions(); for (auto const& prof : professions) { TC_LOG_INFO("Profession: {} - Skill: {}/{}", prof.name, prof.currentSkill, prof.maxSkill); } // Craft items if (profMgr->HasProfession(ProfessionType::BLACKSMITHING)) { uint32 recipeId = 12345; // Iron Sword recipe if (profMgr->KnowsRecipe(recipeId)) { if (profMgr->HasMaterialsForRecipe(recipeId, 5)) { profMgr->CraftItem(recipeId, 5); // Craft 5 swords } else { // Get missing materials auto recipe = profMgr->GetRecipeInfo(recipeId); auto missing = profMgr->GetMissingMaterials(*recipe); // Purchase or gather missing materials } } } // Level profession efficiently if (profMgr->GetProfessionSkill(ProfessionType::ALCHEMY) < 300) { auto* recipe = profMgr->GetOptimalLevelingRecipe(ProfessionType::ALCHEMY); if (recipe) { float chance = profMgr->GetSkillUpChance(recipe->recipeId); TC_LOG_INFO("Crafting {} ({}% skill-up chance)", recipe->productItemId, chance * 100.0f); profMgr->CraftItem(recipe->recipeId); } } ``` --- ### GatheringManager **Purpose**: Automates resource gathering (Mining, Herbalism, Skinning). **Location**: `src/modules/Playerbot/Professions/GatheringManager.h` #### Key Responsibilities - Node detection and tracking - Gathering automation - Skill-up optimization - Route planning for gathering - Material stockpile management #### Core Methods ```cpp /** * @brief Find gathering nodes in range * @param gatheringType Type of gathering (Mining/Herbalism/Skinning) * @param searchRadius Search radius in yards * @return Vector of node GUIDs */ std::vector FindGatheringNodes(GatheringType type, float radius = 100.0f); /** * @brief Gather from a node * @param nodeGuid GameObject GUID of the node * @return true if gathering was successful */ bool GatherFrom(ObjectGuid nodeGuid); /** * @brief Check if bot can gather from a node * @param nodeGuid GameObject GUID of the node * @return true if skill level is sufficient and node is reachable */ bool CanGather(ObjectGuid nodeGuid) const; /** * @brief Get optimal gathering route * @param gatheringType Type of gathering * @param maxNodes Maximum nodes in route * @return Ordered vector of node positions */ std::vector GetGatheringRoute(GatheringType type, uint32 maxNodes = 10); ``` #### Usage Example ```cpp auto* gatherMgr = gameSystems->GetGatheringManager(); // Find and gather herbs if (profMgr->HasProfession(ProfessionType::HERBALISM)) { auto nodes = gatherMgr->FindGatheringNodes(GatheringType::HERBALISM, 50.0f); for (auto nodeGuid : nodes) { if (gatherMgr->CanGather(nodeGuid)) { // Move to node and gather gatherMgr->GatherFrom(nodeGuid); break; } } } ``` --- ### GatheringMaterialsBridge **Purpose**: Coordinates gathering priorities with crafting material needs. **Location**: `src/modules/Playerbot/Professions/GatheringMaterialsBridge.h` **Architecture**: Per-bot instance (Phase 4.1 refactoring) #### Key Responsibilities - Prioritize gathering targets based on crafting needs - Track material inventory vs requirements - Optimize gathering vs crafting workflow - Event-driven material demand handling #### Core Methods ```cpp /** * @brief Prioritize a gathering target based on material needs * @param itemId Material item ID * @return Priority score (higher = more important) */ float PrioritizeGatheringTarget(uint32 itemId); /** * @brief Get priority gathering targets * @param maxTargets Maximum number of targets to return * @return Ordered vector of material item IDs (highest priority first) */ std::vector GetPriorityMaterials(uint32 maxTargets = 5); /** * @brief Check if material is needed for active recipes * @param itemId Material item ID * @param quantity Quantity to check * @return true if material is needed */ bool IsMaterialNeeded(uint32 itemId, uint32 quantity) const; /** * @brief Get crafting recipes that need a specific material * @param itemId Material item ID * @return Vector of recipe IDs requiring this material */ std::vector GetRecipesRequiringMaterial(uint32 itemId) const; ``` #### Event Handling The bridge subscribes to `ProfessionEventBus` events: - `MATERIALS_NEEDED` - Triggered when crafting requires materials - `GATHERING_COMPLETED` - Triggered when gathering finishes ```cpp // Events are automatically filtered per-bot // Only events for THIS bot are processed ``` #### Usage Example ```cpp auto* bridge = gameSystems->GetGatheringMaterialsBridge(); // Check what materials are needed auto priorities = bridge->GetPriorityMaterials(5); for (uint32 itemId : priorities) { float priority = bridge->PrioritizeGatheringTarget(itemId); TC_LOG_INFO("Need material: {} (priority: {})", itemId, priority); // Check recipes needing this material auto recipes = bridge->GetRecipesRequiringMaterial(itemId); TC_LOG_INFO(" Used in {} recipes", recipes.size()); } ``` --- ### AuctionMaterialsBridge **Purpose**: Economic analysis for buy vs gather decisions. **Location**: `src/modules/Playerbot/Professions/AuctionMaterialsBridge.h` **Architecture**: Per-bot instance (Phase 4.2 refactoring) #### Key Responsibilities - Time-value analysis (gathering time vs buying cost) - Opportunity cost calculations - Market price tracking - Economic strategy execution (cost-optimized, time-optimized, hybrid) #### Core Methods ##### Economic Analysis ```cpp /** * @brief Determine best source for a material (gather vs buy) * @param itemId Material item ID * @param quantity Quantity needed * @return MaterialSourcingDecision with recommendation */ MaterialSourcingDecision GetBestMaterialSource(uint32 itemId, uint32 quantity); /** * @brief Check if buying is cheaper than gathering * @param itemId Material item ID * @param quantity Quantity needed * @return true if buying is more cost-effective */ bool IsBuyingCheaperThanGathering(uint32 itemId, uint32 quantity) const; /** * @brief Calculate time cost for gathering materials * @param itemId Material item ID * @param quantity Quantity needed * @return Estimated time in seconds */ uint32 CalculateGatheringTimeCost(uint32 itemId, uint32 quantity) const; /** * @brief Calculate gold cost for buying materials * @param itemId Material item ID * @param quantity Quantity needed * @return Estimated cost in copper */ uint32 CalculateBuyingCost(uint32 itemId, uint32 quantity) const; ``` ##### Strategy Management ```cpp /** * @brief Set economic strategy for the bot * @param strategy Strategy to use (COST_OPTIMIZED, TIME_OPTIMIZED, HYBRID, BALANCED) */ void SetStrategy(MaterialSourcingStrategy strategy); /** * @brief Get current economic strategy * @return Current MaterialSourcingStrategy */ MaterialSourcingStrategy GetStrategy() const; /** * @brief Set bot's gold per hour earning rate * @param goldPerHour Gold earned per hour (for time-value calculations) */ void SetBotGoldPerHour(uint32 goldPerHour); ``` #### MaterialSourcingDecision Structure ```cpp struct MaterialSourcingDecision { enum class Source { GATHER, // Gathering is optimal BUY, // Buying is optimal CRAFT, // Crafting is optimal VENDOR, // Available from vendor UNAVAILABLE // Not available }; Source recommendedSource; uint32 estimatedCost; // Cost in copper uint32 estimatedTime; // Time in seconds float confidence; // Confidence level (0.0 - 1.0) std::string reasoning; // Human-readable explanation }; ``` #### Usage Example ```cpp auto* bridge = gameSystems->GetAuctionMaterialsBridge(); // Set economic strategy bridge->SetStrategy(MaterialSourcingStrategy::HYBRID); bridge->SetBotGoldPerHour(100 * 10000); // 100g per hour // Analyze material sourcing uint32 itemId = 2447; // Peacebloom uint32 quantity = 20; auto decision = bridge->GetBestMaterialSource(itemId, quantity); switch (decision.recommendedSource) { case MaterialSourcingDecision::Source::GATHER: TC_LOG_INFO("Recommendation: Gather {} x{} (Time: {}s, Cost: {}c)", itemId, quantity, decision.estimatedTime, decision.estimatedCost); // Initiate gathering break; case MaterialSourcingDecision::Source::BUY: TC_LOG_INFO("Recommendation: Buy {} x{} from AH (Cost: {}c, Time: {}s)", itemId, quantity, decision.estimatedCost, decision.estimatedTime); // Purchase from auction house break; case MaterialSourcingDecision::Source::VENDOR: TC_LOG_INFO("Recommendation: Buy {} x{} from vendor (Cost: {}c)", itemId, quantity, decision.estimatedCost); // Buy from vendor break; } TC_LOG_INFO("Reasoning: {}", decision.reasoning); TC_LOG_INFO("Confidence: {}%", decision.confidence * 100.0f); ``` --- ### ProfessionAuctionBridge **Purpose**: Automates auction house operations for professions (selling/buying). **Location**: `src/modules/Playerbot/Professions/ProfessionAuctionBridge.h` **Architecture**: Per-bot instance (Phase 4.3 refactoring) #### Key Responsibilities - Automatic material selling (excess stockpile) - Automatic crafted item selling (profit margin analysis) - Automatic material purchasing (for leveling) - Stockpile management - Market price tracking #### Core Methods ##### Material Selling ```cpp /** * @brief Sell excess materials on auction house * Automatically lists materials exceeding stockpile limits */ void SellExcessMaterials(); /** * @brief Check if material should be sold * @param itemId Material item ID * @param currentCount Current inventory count * @return true if count exceeds stockpile maximum */ bool ShouldSellMaterial(uint32 itemId, uint32 currentCount) const; /** * @brief List material on auction house * @param itemGuid Item GUID to list * @param config Stockpile configuration for the material * @return true if listing was successful */ bool ListMaterialOnAuction(uint32 itemGuid, MaterialStockpileConfig const& config); /** * @brief Get optimal listing price for material * @param itemId Material item ID * @param stackSize Stack size to sell * @return Suggested listing price in copper */ uint32 GetOptimalMaterialPrice(uint32 itemId, uint32 stackSize) const; ``` ##### Crafted Item Selling ```cpp /** * @brief Sell crafted items on auction house * Automatically lists profitable crafted items */ void SellCraftedItems(); /** * @brief Check if crafted item should be sold * @param itemId Crafted item ID * @param materialCost Cost of materials used * @return true if profit margin meets minimum threshold */ bool ShouldSellCraftedItem(uint32 itemId, uint32 materialCost) const; /** * @brief Calculate profit margin for crafted item * @param itemId Crafted item ID * @param marketPrice Current market price * @param materialCost Cost of materials * @return Profit margin as percentage (0.0 - 1.0+) */ float CalculateProfitMargin(uint32 itemId, uint32 marketPrice, uint32 materialCost) const; ``` ##### Material Purchasing ```cpp /** * @brief Buy materials for profession leveling * @param profession Profession to level */ void BuyMaterialsForLeveling(ProfessionType profession); /** * @brief Purchase a specific material from auction house * @param itemId Material item ID * @param quantity Quantity to purchase * @param maxPricePerUnit Maximum price willing to pay per unit * @return true if purchase was successful */ bool PurchaseMaterial(uint32 itemId, uint32 quantity, uint32 maxPricePerUnit); /** * @brief Check if material is available at acceptable price * @param itemId Material item ID * @param quantity Quantity needed * @param maxPricePerUnit Maximum acceptable price * @return true if material is available within budget */ bool IsMaterialAvailableForPurchase(uint32 itemId, uint32 quantity, uint32 maxPricePerUnit) const; ``` ##### Stockpile Management ```cpp /** * @brief Set stockpile configuration for a material * @param itemId Material item ID * @param config Stockpile configuration (min/max quantities, auction settings) */ void SetMaterialStockpile(uint32 itemId, MaterialStockpileConfig const& config); /** * @brief Get current stockpile amount * @param itemId Material item ID * @return Current count in inventory */ uint32 GetCurrentStockpile(uint32 itemId) const; /** * @brief Check if stockpile target is met * @param itemId Material item ID * @return true if current count >= minimum stockpile */ bool IsStockpileTargetMet(uint32 itemId) const; ``` ##### Statistics ```cpp /** * @brief Get auction statistics for this bot * @return ProfessionAuctionStatistics structure */ ProfessionAuctionStatistics const& GetStatistics() const; /** * @brief Get global auction statistics (all bots) * @return Global ProfessionAuctionStatistics */ static ProfessionAuctionStatistics const& GetGlobalStatistics(); /** * @brief Reset auction statistics for this bot */ void ResetStatistics(); ``` #### Configuration Structures ```cpp struct MaterialStockpileConfig { uint32 itemId; // Material item ID uint32 minStackSize; // Minimum stockpile to maintain uint32 maxStackSize; // Maximum before selling excess uint32 auctionStackSize; // Stack size to sell on AH bool preferBuyout; // Use buyout price }; struct CraftedItemAuctionConfig { uint32 itemId; // Crafted item ID uint32 minProfitMargin; // Minimum profit in copper bool undercutCompetition; // Undercut existing auctions float undercutRate; // Undercut percentage (0.01 = 1%) uint32 maxListingDuration; // Auction duration in hours }; struct ProfessionAuctionProfile { bool autoSellEnabled; // Enable automatic selling bool buyMaterialsForLeveling; // Enable automatic buying uint32 auctionBudget; // Gold budget for purchases ProfessionAuctionStrategy strategy; // AGGRESSIVE, CONSERVATIVE, BALANCED std::unordered_map materialConfigs; std::unordered_map craftedItemConfigs; }; ``` #### Usage Example ```cpp auto* bridge = gameSystems->GetProfessionAuctionBridge(); // Configure stockpile for Copper Ore MaterialStockpileConfig copperConfig; copperConfig.itemId = 2770; copperConfig.minStackSize = 40; // Keep at least 40 copperConfig.maxStackSize = 100; // Sell when exceeds 100 copperConfig.auctionStackSize = 20; // Sell in stacks of 20 copperConfig.preferBuyout = true; bridge->SetMaterialStockpile(2770, copperConfig); // Configure crafted item selling CraftedItemAuctionConfig swordConfig; swordConfig.itemId = 12345; // Iron Sword swordConfig.minProfitMargin = 50 * 10000; // 50g minimum profit swordConfig.undercutCompetition = true; swordConfig.undercutRate = 0.05f; // 5% undercut swordConfig.maxListingDuration = 24; // 24 hours bridge->SetCraftedItemAuction(12345, swordConfig); // Enable automation auto profile = bridge->GetAuctionProfile(); profile.autoSellEnabled = true; profile.buyMaterialsForLeveling = true; profile.auctionBudget = 1000 * 10000; // 1000g budget bridge->SetAuctionProfile(profile); // Manual operations bridge->SellExcessMaterials(); // Sell excess materials now bridge->SellCraftedItems(); // Sell profitable crafted items bridge->BuyMaterialsForLeveling(ProfessionType::BLACKSMITHING); // Check statistics auto stats = bridge->GetStatistics(); TC_LOG_INFO("Materials listed: {}", stats.materialsListedCount); TC_LOG_INFO("Crafted items sold: {}", stats.craftedsListedCount); TC_LOG_INFO("Materials bought: {}", stats.materialsBought); TC_LOG_INFO("Gold spent: {}g", stats.goldSpentOnMaterials / 10000); ``` --- ## Economy Systems ### TradeManager **Purpose**: Manages player-to-player trading operations. **Location**: `src/modules/Playerbot/Social/TradeManager.h` #### Key Responsibilities - Trade initiation and acceptance - Item exchange management - Gold transactions - Trade window automation #### Core Methods ```cpp /** * @brief Initiate a trade with another player * @param targetGuid GUID of player to trade with * @return true if trade was initiated */ bool InitiateTrade(ObjectGuid targetGuid); /** * @brief Accept a trade request * @return true if trade was accepted */ bool AcceptTrade(); /** * @brief Add an item to the trade window * @param itemGuid Item GUID to add * @param slot Trade slot (0-5) * @return true if item was added */ bool AddItemToTrade(ObjectGuid itemGuid, uint8 slot); /** * @brief Set gold amount in trade * @param copper Amount of gold in copper */ void SetTradeGold(uint32 copper); /** * @brief Cancel current trade */ void CancelTrade(); ``` #### Usage Example ```cpp auto* tradeMgr = gameSystems->GetTradeManager(); // Initiate trade with nearby player Player* nearbyPlayer = FindNearestPlayer(); if (nearbyPlayer && tradeMgr->InitiateTrade(nearbyPlayer->GetGUID())) { // Add items to trade Item* item = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, 0); if (item) tradeMgr->AddItemToTrade(item->GetGUID(), 0); // Set gold tradeMgr->SetTradeGold(100 * 10000); // 100 gold // Accept trade tradeMgr->AcceptTrade(); } ``` --- ### AuctionManager **Purpose**: Manages auction house operations (buying, selling, market scanning). **Location**: `src/modules/Playerbot/Economy/AuctionManager.h` #### Key Responsibilities - Auction house access - Item listing and bidding - Market price analysis - Auction expiration tracking #### Core Methods ```cpp /** * @brief List an item on the auction house * @param itemGuid Item GUID to list * @param stackSize Stack size (for stackable items) * @param bidPrice Starting bid in copper * @param buyoutPrice Buyout price in copper (0 for no buyout) * @param duration Auction duration in hours (12, 24, or 48) * @return true if item was listed */ bool ListItem(ObjectGuid itemGuid, uint32 stackSize, uint32 bidPrice, uint32 buyoutPrice, uint32 duration); /** * @brief Place a bid on an auction * @param auctionId Auction ID * @param bidAmount Bid amount in copper * @return true if bid was placed */ bool PlaceBid(uint32 auctionId, uint32 bidAmount); /** * @brief Buyout an auction * @param auctionId Auction ID * @return true if buyout was successful */ bool BuyoutAuction(uint32 auctionId); /** * @brief Search for auctions of a specific item * @param itemId Item entry ID * @param maxResults Maximum number of results * @return Vector of AuctionInfo structures */ std::vector SearchAuctions(uint32 itemId, uint32 maxResults = 50); /** * @brief Get market price for an item * @param itemId Item entry ID * @return Average market price in copper (0 if no data) */ uint32 GetMarketPrice(uint32 itemId) const; /** * @brief Cancel an active auction * @param auctionId Auction ID * @return true if auction was cancelled */ bool CancelAuction(uint32 auctionId); ``` #### Usage Example ```cpp auto* auctionMgr = gameSystems->GetAuctionManager(); // Sell an item Item* item = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, 0); if (item) { uint32 marketPrice = auctionMgr->GetMarketPrice(item->GetEntry()); uint32 bidPrice = marketPrice * 0.95f; uint32 buyoutPrice = marketPrice; auctionMgr->ListItem(item->GetGUID(), 1, bidPrice, buyoutPrice, 24); } // Buy an item auto auctions = auctionMgr->SearchAuctions(2447, 10); // Search for Peacebloom for (auto const& auction : auctions) { if (auction.buyoutPrice > 0 && auction.buyoutPrice <= 10 * 10000) // Max 10g { auctionMgr->BuyoutAuction(auction.auctionId); break; } } ``` --- ## Combat Systems ### CombatStateManager **Purpose**: Manages combat state transitions and combat flow. **Location**: `src/modules/Playerbot/Combat/CombatStateManager.h` #### Key Responsibilities - Combat state tracking (in/out of combat) - Threat management - Combat target selection - Combat initiation and exit #### Core Methods ```cpp /** * @brief Check if bot is in combat * @return true if currently in combat */ bool IsInCombat() const; /** * @brief Enter combat with a target * @param targetGuid Target GUID * @return true if combat was initiated */ bool EnterCombat(ObjectGuid targetGuid); /** * @brief Exit combat * @return true if combat was exited */ bool ExitCombat(); /** * @brief Get current combat target * @return Target GUID (null if no target) */ ObjectGuid GetCurrentTarget() const; /** * @brief Set combat target * @param targetGuid Target GUID */ void SetTarget(ObjectGuid targetGuid); /** * @brief Get threat level for a target * @param targetGuid Target GUID * @return Threat value */ float GetThreat(ObjectGuid targetGuid) const; /** * @brief Check if bot should flee from combat * @return true if health/mana is critically low */ bool ShouldFlee() const; ``` #### Usage Example ```cpp auto* combatMgr = gameSystems->GetCombatStateManager(); // Enter combat Creature* enemy = FindNearestEnemy(); if (enemy && !combatMgr->IsInCombat()) { combatMgr->EnterCombat(enemy->GetGUID()); } // During combat if (combatMgr->IsInCombat()) { // Check if should flee if (combatMgr->ShouldFlee()) { combatMgr->ExitCombat(); // Run away logic } // Monitor threat ObjectGuid target = combatMgr->GetCurrentTarget(); float threat = combatMgr->GetThreat(target); TC_LOG_DEBUG("Current threat: {}", threat); } ``` --- ### TargetScanner **Purpose**: Scans for and evaluates potential targets. **Location**: `src/modules/Playerbot/Combat/TargetScanner.h` #### Key Responsibilities - Target detection - Target prioritization - Range checking - Line-of-sight validation #### Core Methods ```cpp /** * @brief Find all hostile targets in range * @param range Search radius in yards * @return Vector of hostile creature GUIDs */ std::vector FindHostileTargets(float range = 40.0f); /** * @brief Find best target based on criteria * @param range Search radius * @return GUID of best target (null if none found) */ ObjectGuid FindBestTarget(float range = 40.0f); /** * @brief Check if target is valid * @param targetGuid Target GUID * @return true if target exists, is alive, hostile, and in range */ bool IsValidTarget(ObjectGuid targetGuid) const; /** * @brief Get distance to target * @param targetGuid Target GUID * @return Distance in yards (0 if invalid) */ float GetDistanceToTarget(ObjectGuid targetGuid) const; /** * @brief Check if target is in line of sight * @param targetGuid Target GUID * @return true if LOS is clear */ bool HasLineOfSight(ObjectGuid targetGuid) const; /** * @brief Evaluate target priority * @param targetGuid Target GUID * @return Priority score (higher = better target) */ float EvaluateTargetPriority(ObjectGuid targetGuid) const; ``` #### Usage Example ```cpp auto* scanner = gameSystems->GetTargetScanner(); // Find and select best target ObjectGuid bestTarget = scanner->FindBestTarget(40.0f); if (bestTarget) { if (scanner->IsValidTarget(bestTarget) && scanner->HasLineOfSight(bestTarget)) { float distance = scanner->GetDistanceToTarget(bestTarget); TC_LOG_INFO("Engaging target at {} yards", distance); combatMgr->EnterCombat(bestTarget); } } // Find all hostiles for AOE auto hostiles = scanner->FindHostileTargets(10.0f); if (hostiles.size() >= 3) { // Use AOE abilities TC_LOG_INFO("Found {} enemies for AOE", hostiles.size()); } ``` --- ## Movement System ### UnifiedMovementCoordinator **Purpose**: Centralized movement control and pathfinding. **Location**: `src/modules/Playerbot/Movement/UnifiedMovementCoordinator.h` #### Key Responsibilities - Pathfinding - Movement to positions/targets - Formation management - Follow behavior - Obstacle avoidance #### Core Methods ```cpp /** * @brief Move to a position * @param destination Target position * @return true if movement was initiated */ bool MoveTo(Position const& destination); /** * @brief Move to a target * @param targetGuid Target GUID * @param distance Desired distance from target * @return true if movement was initiated */ bool MoveToTarget(ObjectGuid targetGuid, float distance = 0.0f); /** * @brief Follow a target * @param targetGuid Target GUID to follow * @param distance Follow distance * @return true if follow was initiated */ bool Follow(ObjectGuid targetGuid, float distance = 5.0f); /** * @brief Stop all movement */ void StopMovement(); /** * @brief Check if bot is currently moving * @return true if moving */ bool IsMoving() const; /** * @brief Get current destination * @return Destination position (null position if not moving) */ Position GetDestination() const; /** * @brief Calculate path to destination * @param destination Target position * @return Vector of waypoints (empty if no path) */ std::vector CalculatePath(Position const& destination); /** * @brief Check if position is reachable * @param position Target position * @return true if path exists */ bool IsReachable(Position const& position) const; ``` #### Usage Example ```cpp auto* movement = gameSystems->GetMovementCoordinator(); // Move to a position Position destination(1234.5f, 5678.9f, 123.4f); if (movement->IsReachable(destination)) { movement->MoveTo(destination); // Wait for arrival while (movement->IsMoving()) { // Update logic } } // Follow a player Player* leader = GetGroupLeader(); if (leader) { movement->Follow(leader->GetGUID(), 5.0f); // Follow at 5 yards } // Move to combat target ObjectGuid target = combatMgr->GetCurrentTarget(); if (target) { float optimalRange = 5.0f; // Melee range movement->MoveToTarget(target, optimalRange); } // Calculate and visualize path auto path = movement->CalculatePath(destination); for (auto const& waypoint : path) { TC_LOG_DEBUG("Waypoint: ({}, {}, {})", waypoint.GetPositionX(), waypoint.GetPositionY(), waypoint.GetPositionZ()); } ``` --- ## Lifecycle Systems ### DeathRecoveryManager **Purpose**: Handles bot death, corpse retrieval, and resurrection. **Location**: `src/modules/Playerbot/Lifecycle/DeathRecoveryManager.h` #### Key Responsibilities - Death detection - Spirit healer interaction - Corpse retrieval - Durability management - Resurrection coordination #### Core Methods ```cpp /** * @brief Check if bot is dead * @return true if dead or ghost */ bool IsDead() const; /** * @brief Handle death event * Called automatically when bot dies */ void OnDeath(); /** * @brief Retrieve corpse * @return true if corpse was retrieved */ bool RetrieveCorpse(); /** * @brief Resurrect at spirit healer * @return true if resurrection was successful */ bool ResurrectAtSpiritHealer(); /** * @brief Get distance to corpse * @return Distance in yards */ float GetDistanceToCorpse() const; /** * @brief Check if corpse is retrievable * @return true if bot is in range and can retrieve */ bool CanRetrieveCorpse() const; /** * @brief Repair equipment * @param repairCost Maximum gold to spend on repairs * @return true if repairs were made */ bool RepairEquipment(uint32 repairCost); ``` #### Usage Example ```cpp auto* deathMgr = gameSystems->GetDeathRecoveryManager(); if (deathMgr->IsDead()) { // Find and retrieve corpse float distance = deathMgr->GetDistanceToCorpse(); TC_LOG_INFO("Corpse is {} yards away", distance); if (deathMgr->CanRetrieveCorpse()) { deathMgr->RetrieveCorpse(); } else { // Move to corpse movement->MoveTo(GetCorpsePosition()); } } // After resurrection, repair equipment if (GetDurabilityPercent() < 50.0f) { uint32 maxRepairCost = 50 * 10000; // Max 50 gold deathMgr->RepairEquipment(maxRepairCost); } ``` --- ## Group Systems ### GroupCoordinator **Purpose**: Manages group/raid mechanics, role assignment, and coordination. **Location**: `src/modules/Playerbot/Advanced/GroupCoordinator.h` #### Key Responsibilities - Group formation and management - Role assignment (Tank/Healer/DPS) - Raid coordination - Dungeon/raid strategy execution #### Core Methods ```cpp /** * @brief Check if bot is in a group * @return true if in group or raid */ bool IsInGroup() const; /** * @brief Get bot's role in group * @return GroupRole enum (TANK, HEALER, DPS) */ GroupRole GetRole() const; /** * @brief Set bot's role * @param role GroupRole to assign */ void SetRole(GroupRole role); /** * @brief Get group members * @return Vector of player GUIDs in group */ std::vector GetGroupMembers() const; /** * @brief Get group leader * @return Leader GUID */ ObjectGuid GetGroupLeader() const; /** * @brief Check if bot is group leader * @return true if leader */ bool IsGroupLeader() const; /** * @brief Get tank in group * @return Tank GUID (null if no tank) */ ObjectGuid GetTank() const; /** * @brief Get healers in group * @return Vector of healer GUIDs */ std::vector GetHealers() const; ``` #### Usage Example ```cpp auto* groupCoord = gameSystems->GetGroupCoordinator(); if (groupCoord->IsInGroup()) { // Get role assignment GroupRole role = groupCoord->GetRole(); switch (role) { case GroupRole::TANK: // Tank behavior ObjectGuid target = scanner->FindBestTarget(); combatMgr->EnterCombat(target); break; case GroupRole::HEALER: // Healer behavior auto members = groupCoord->GetGroupMembers(); for (auto memberGuid : members) { Player* member = GetPlayer(memberGuid); if (member && member->GetHealthPct() < 70.0f) { // Heal member } } break; case GroupRole::DPS: // DPS behavior ObjectGuid tank = groupCoord->GetTank(); Unit* tankTarget = GetTankTarget(tank); if (tankTarget) combatMgr->EnterCombat(tankTarget->GetGUID()); break; } } ``` --- ### GroupInvitationHandler **Purpose**: Handles group invitation logic. **Location**: `src/modules/Playerbot/Group/GroupInvitationHandler.h` #### Core Methods ```cpp /** * @brief Invite a player to group * @param playerGuid Player GUID to invite * @return true if invitation was sent */ bool InvitePlayer(ObjectGuid playerGuid); /** * @brief Accept a group invitation * @param inviterGuid Inviter GUID * @return true if invitation was accepted */ bool AcceptInvitation(ObjectGuid inviterGuid); /** * @brief Decline a group invitation * @param inviterGuid Inviter GUID */ void DeclineInvitation(ObjectGuid inviterGuid); /** * @brief Check if bot has pending invitation * @return true if invitation is pending */ bool HasPendingInvitation() const; ``` #### Usage Example ```cpp auto* inviteHandler = gameSystems->GetGroupInvitationHandler(); // Accept invitations from friends if (inviteHandler->HasPendingInvitation()) { ObjectGuid inviter = GetPendingInviter(); if (IsFriend(inviter)) { inviteHandler->AcceptInvitation(inviter); } else { inviteHandler->DeclineInvitation(inviter); } } // Invite nearby players Player* nearbyPlayer = FindNearbyPlayer(); if (nearbyPlayer && !groupCoord->IsInGroup()) { inviteHandler->InvitePlayer(nearbyPlayer->GetGUID()); } ``` --- ## Decision Systems The decision system consists of **4 managers** implementing hybrid AI architecture. ### System Architecture ``` HybridAIController (Orchestrator) ↓ ├─→ DecisionFusionSystem (Strategic) ├─→ BehaviorTree (Tactical) └─→ ActionPriorityQueue (Execution) ↓ BehaviorPriorityManager (Priority) ``` ### DecisionFusionSystem **Purpose**: Strategic-level decision making using multiple AI techniques. **Location**: `src/modules/Playerbot/Decision/DecisionFusionSystem.h` #### Key Responsibilities - Long-term goal planning - State evaluation - Decision fusion from multiple sources - Strategy selection #### Core Methods ```cpp /** * @brief Evaluate current situation and make strategic decision * @return Strategic decision enum */ StrategicDecision EvaluateSituation(); /** * @brief Set strategic goal * @param goal Goal to pursue */ void SetGoal(StrategicGoal goal); /** * @brief Get current strategic goal * @return Current StrategicGoal */ StrategicGoal GetCurrentGoal() const; /** * @brief Check if goal is achieved * @return true if current goal is complete */ bool IsGoalAchieved() const; ``` --- ### BehaviorTree **Purpose**: Tactical-level behavior execution using behavior tree architecture. **Location**: `src/modules/Playerbot/Decision/BehaviorTree.h` #### Key Responsibilities - Behavior tree execution - Condition evaluation - Action selection - Tree traversal #### Core Methods ```cpp /** * @brief Execute behavior tree * @return Execution result (SUCCESS, FAILURE, RUNNING) */ BehaviorTreeResult Execute(); /** * @brief Set active behavior tree * @param treeId Tree identifier */ void SetActiveTree(uint32 treeId); /** * @brief Get current tree node * @return Current node ID */ uint32 GetCurrentNode() const; ``` --- ### ActionPriorityQueue **Purpose**: Action execution queue with priority management. **Location**: `src/modules/Playerbot/Decision/ActionPriorityQueue.h` #### Core Methods ```cpp /** * @brief Add action to queue * @param action Action to execute * @param priority Action priority */ void EnqueueAction(BotAction const& action, float priority); /** * @brief Get highest priority action * @return Next action to execute */ BotAction GetNextAction(); /** * @brief Clear all actions */ void ClearQueue(); /** * @brief Get queue size * @return Number of pending actions */ uint32 GetQueueSize() const; ``` --- ### HybridAIController **Purpose**: Orchestrates all decision systems for cohesive AI behavior. **Location**: `src/modules/Playerbot/Decision/HybridAIController.h` #### Core Methods ```cpp /** * @brief Update AI systems * @param diff Time delta */ void Update(uint32 diff); /** * @brief Set AI mode * @param mode AI behavior mode (PASSIVE, DEFENSIVE, AGGRESSIVE) */ void SetMode(AIMode mode); /** * @brief Get current AI mode * @return Current AIMode */ AIMode GetMode() const; ``` #### Usage Example ```cpp auto* hybridAI = gameSystems->GetHybridAI(); auto* decisionFusion = gameSystems->GetDecisionFusion(); auto* behaviorTree = gameSystems->GetBehaviorTree(); auto* actionQueue = gameSystems->GetActionPriorityQueue(); // Set strategic goal decisionFusion->SetGoal(StrategicGoal::LEVEL_UP); // Execute behavior tree BehaviorTreeResult result = behaviorTree->Execute(); // Process action queue if (actionQueue->GetQueueSize() > 0) { BotAction action = actionQueue->GetNextAction(); // Execute action } // Set AI mode hybridAI->SetMode(AIMode::AGGRESSIVE); ``` --- ## Core Infrastructure ### EventDispatcher **Purpose**: Event system for inter-manager communication. **Location**: `src/modules/Playerbot/Core/Events/EventDispatcher.h` #### Core Methods ```cpp /** * @brief Subscribe to an event type * @param eventType Event type to subscribe to * @param callback Callback function * @return Subscription ID */ uint32 Subscribe(EventType eventType, EventCallback callback); /** * @brief Unsubscribe from events * @param subscriptionId Subscription ID from Subscribe() */ void Unsubscribe(uint32 subscriptionId); /** * @brief Dispatch an event * @param event Event to dispatch */ void Dispatch(Event const& event); ``` #### Usage Example ```cpp auto* eventDispatcher = gameSystems->GetEventDispatcher(); // Subscribe to combat events uint32 subId = eventDispatcher->Subscribe( EventType::COMBAT_ENTER, [](Event const& event) { TC_LOG_INFO("Entered combat with {}", event.targetGuid); } ); // Dispatch custom event Event customEvent; customEvent.type = EventType::CUSTOM; customEvent.data = "example data"; eventDispatcher->Dispatch(customEvent); // Cleanup eventDispatcher->Unsubscribe(subId); ``` --- ### ManagerRegistry **Purpose**: Central registry for all managers (dependency injection). **Location**: `src/modules/Playerbot/Core/Managers/ManagerRegistry.h` #### Core Methods ```cpp /** * @brief Register a manager * @param managerName Manager identifier * @param manager Manager pointer */ void RegisterManager(std::string const& managerName, void* manager); /** * @brief Get a manager by name * @param managerName Manager identifier * @return Manager pointer (cast to appropriate type) */ void* GetManager(std::string const& managerName) const; /** * @brief Check if manager is registered * @param managerName Manager identifier * @return true if registered */ bool HasManager(std::string const& managerName) const; ``` --- ### BehaviorPriorityManager **Purpose**: Manages behavior priority and scheduling. **Location**: `src/modules/Playerbot/BehaviorPriorityManager.h` #### Core Methods ```cpp /** * @brief Set behavior priority * @param behaviorId Behavior identifier * @param priority Priority value (higher = more important) */ void SetPriority(uint32 behaviorId, float priority); /** * @brief Get behavior priority * @param behaviorId Behavior identifier * @return Priority value */ float GetPriority(uint32 behaviorId) const; /** * @brief Get highest priority behavior * @return Behavior ID */ uint32 GetHighestPriorityBehavior() const; ``` --- ## Integration Guide ### Initial Setup ```cpp // In BotAI constructor class BotAI { public: BotAI(Player* bot) { // Create GameSystemsManager facade _gameSystems = std::make_unique(bot, this); } void Initialize() { // Initialize all managers _gameSystems->Initialize(_bot); } void Update(uint32 diff) { // Update all managers _gameSystems->Update(diff); } private: std::unique_ptr _gameSystems; Player* _bot; }; ``` ### Accessing Managers ```cpp // Always access via GameSystemsManager facade auto* gameSystems = botAI->GetGameSystems(); // Get specific managers auto* questMgr = gameSystems->GetQuestManager(); auto* profMgr = gameSystems->GetProfessionManager(); auto* combatMgr = gameSystems->GetCombatStateManager(); ``` ### Complete Bot Behavior Example ```cpp void BotAI::ExecuteBehavior() { auto* gameSystems = GetGameSystems(); // 1. Check death status auto* deathMgr = gameSystems->GetDeathRecoveryManager(); if (deathMgr->IsDead()) { deathMgr->RetrieveCorpse(); return; } // 2. Check combat auto* combatMgr = gameSystems->GetCombatStateManager(); if (combatMgr->IsInCombat()) { ExecuteCombatBehavior(); return; } // 3. Process quests auto* questMgr = gameSystems->GetQuestManager(); auto activeQuests = questMgr->GetActiveQuests(); for (uint32 questId : activeQuests) { if (questMgr->IsQuestComplete(questId)) { questMgr->TurnInQuest(questId); } } // 4. Process professions auto* profMgr = gameSystems->GetProfessionManager(); auto professions = profMgr->GetPlayerProfessions(); for (auto const& prof : professions) { if (prof.currentSkill < prof.maxSkill) { // Level profession auto* recipe = profMgr->GetOptimalLevelingRecipe(prof.profession); if (recipe && profMgr->HasMaterialsForRecipe(recipe->recipeId, 1)) { profMgr->CraftItem(recipe->recipeId); } else { // Gather or buy materials auto* bridge = gameSystems->GetAuctionMaterialsBridge(); auto decision = bridge->GetBestMaterialSource(materialId, quantity); // Execute decision } } } // 5. Idle behavior ExecuteIdleBehavior(); } void BotAI::ExecuteCombatBehavior() { auto* gameSystems = GetGameSystems(); auto* combatMgr = gameSystems->GetCombatStateManager(); auto* scanner = gameSystems->GetTargetScanner(); auto* movement = gameSystems->GetMovementCoordinator(); // Get best target ObjectGuid target = scanner->FindBestTarget(); if (!target) { combatMgr->ExitCombat(); return; } // Move to target float distance = scanner->GetDistanceToTarget(target); if (distance > 5.0f) { movement->MoveToTarget(target, 5.0f); } // Execute rotation ExecuteCombatRotation(target); // Check for flee if (combatMgr->ShouldFlee()) { combatMgr->ExitCombat(); movement->StopMovement(); // Flee logic } } ``` --- ## Best Practices ### 1. Always Use Facade Pattern ```cpp // ✅ GOOD: Access via facade auto* manager = gameSystems->GetQuestManager(); // ❌ BAD: Direct singleton access auto* manager = QuestManager::instance(); // Don't do this! ``` ### 2. Check Null Pointers ```cpp auto* profMgr = gameSystems->GetProfessionManager(); if (profMgr) { profMgr->CraftItem(recipeId); } ``` ### 3. Use Per-Bot Instances ```cpp // ✅ GOOD: Per-bot methods (no Player* parameter) profMgr->CraftItem(recipeId); bridge->GetBestMaterialSource(itemId, quantity); // ❌ BAD: Old singleton pattern (deprecated) ProfessionManager::instance()->CraftItem(player, recipeId); ``` ### 4. Event Filtering When subscribing to events, remember that per-bot managers automatically filter events: ```cpp // Events are automatically filtered by playerGuid // Only events for THIS bot are processed void HandleEvent(ProfessionEvent const& event) { if (event.playerGuid != _bot->GetGUID()) return; // Already filtered by bridge // Process event } ``` ### 5. Resource Management Managers are owned by GameSystemsManager via `std::unique_ptr`: ```cpp // ✅ GOOD: Let unique_ptr handle cleanup // Automatically destroyed when GameSystemsManager destructs // ❌ BAD: Manual deletion delete manager; // Never do this! ``` ### 6. Update Frequency Not all managers need to update every frame: ```cpp void Update(uint32 diff) { _timer += diff; // Update every 1 second if (_timer >= 1000) { _timer = 0; ExpensiveOperation(); } } ``` ### 7. Thread Safety All managers are per-bot and single-threaded: ```cpp // ✅ GOOD: No mutex needed (per-bot isolation) _profile.autoSellEnabled = true; // ❌ BAD: Unnecessary mutex (old singleton pattern) std::lock_guard lock(_mutex); // Not needed anymore! ``` --- ## Troubleshooting ### Common Issues **Issue**: "Manager returns null" - **Solution**: Ensure GameSystemsManager is initialized before accessing managers **Issue**: "Events not firing" - **Solution**: Check that manager is subscribed to ProfessionEventBus **Issue**: "Compilation errors with Player* parameters" - **Solution**: Remove Player* parameters from method calls (per-bot refactoring) **Issue**: "Data not persisting across updates" - **Solution**: Ensure data is stored in per-bot members, not local variables --- ## API Reference For detailed API documentation, see: - `/src/modules/Playerbot/Core/Managers/IGameSystemsManager.h` - Interface definition - `/src/modules/Playerbot/Core/Managers/GameSystemsManager.h` - Facade implementation - Individual manager headers in respective directories --- ## Version History | Version | Date | Changes | |---------|------|---------| | 1.0 | 2025-11-18 | Initial comprehensive developer guide | | | | Documented all 21 managers systematically | | | | Added usage examples for each system | | | | Included best practices and integration guide | --- **Document Status**: ✅ Complete **Maintainer**: TrinityCore PlayerBot Team **Last Review**: 2025-11-18 --- ## Bot Creation and Spawning Systems ### Overview The bot creation and spawning system manages the entire lifecycle of PlayerBot instances, from initial creation through active gameplay to cleanup and removal. ### System Architecture ``` Bot Creation Flow: ↓ BotManager (Singleton) ↓ BotFactory → Creates Bot Player Instance ↓ BotSession → Creates Session for Bot ↓ BotAI → Creates AI Controller ↓ GameSystemsManager → Initializes 21 Managers ↓ Bot Active in World ``` --- ### BotManager **Purpose**: Central manager for all bot instances in the world. **Location**: `src/modules/Playerbot/Core/BotManager.h` **Architecture**: Global singleton (manages all bots server-wide) #### Key Responsibilities - Bot instance tracking and registry - Bot creation and deletion - Bot-to-player association - Bot command processing - Bot persistence (database save/load) #### Core Methods ##### Bot Creation ```cpp /** * @brief Create a new bot * @param owner Player who owns the bot * @param name Bot character name * @param race Race ID (1=Human, 2=Orc, etc.) * @param class_ Class ID (1=Warrior, 2=Paladin, etc.) * @param gender Gender (0=Male, 1=Female) * @return Pointer to created bot, nullptr on failure */ Player* CreateBot(Player* owner, std::string const& name, uint8 race, uint8 class_, uint8 gender); /** * @brief Spawn an existing bot character * @param botGuid GUID of bot character * @param owner Player who owns the bot * @return Pointer to spawned bot, nullptr on failure */ Player* SpawnBot(ObjectGuid botGuid, Player* owner); /** * @brief Load bot from database * @param botGuid GUID of bot character * @return true if bot was loaded successfully */ bool LoadBot(ObjectGuid botGuid); ``` ##### Bot Management ```cpp /** * @brief Get all bots owned by a player * @param ownerGuid Owner player GUID * @return Vector of bot player pointers */ std::vector GetPlayerBots(ObjectGuid ownerGuid) const; /** * @brief Get bot by GUID * @param botGuid Bot GUID * @return Pointer to bot, nullptr if not found */ Player* GetBot(ObjectGuid botGuid) const; /** * @brief Check if character is a bot * @param playerGuid Player GUID to check * @return true if player is a bot */ bool IsBot(ObjectGuid playerGuid) const; /** * @brief Get bot owner * @param botGuid Bot GUID * @return Owner player GUID (null if no owner) */ ObjectGuid GetBotOwner(ObjectGuid botGuid) const; ``` ##### Bot Removal ```cpp /** * @brief Remove bot from world (despawn) * @param botGuid Bot GUID * @return true if bot was removed */ bool RemoveBot(ObjectGuid botGuid); /** * @brief Delete bot permanently * @param botGuid Bot GUID * @return true if bot was deleted */ bool DeleteBot(ObjectGuid botGuid); /** * @brief Remove all bots owned by a player * @param ownerGuid Owner player GUID */ void RemoveAllPlayerBots(ObjectGuid ownerGuid); ``` ##### Bot Control ```cpp /** * @brief Set bot AI state * @param botGuid Bot GUID * @param state AI state (IDLE, ACTIVE, PAUSED, DISABLED) */ void SetBotAIState(ObjectGuid botGuid, BotAIState state); /** * @brief Teleport bot to owner * @param botGuid Bot GUID * @return true if teleport was successful */ bool TeleportBotToOwner(ObjectGuid botGuid); /** * @brief Update all bots * @param diff Time delta in milliseconds */ void Update(uint32 diff); ``` ##### Statistics ```cpp /** * @brief Get total number of active bots * @return Active bot count */ uint32 GetActiveBotCount() const; /** * @brief Get maximum allowed bots per player * @return Max bots per player */ uint32 GetMaxBotsPerPlayer() const; /** * @brief Set maximum allowed bots per player * @param maxBots Maximum number */ void SetMaxBotsPerPlayer(uint32 maxBots); ``` #### Usage Example ```cpp auto* botMgr = BotManager::instance(); // Create a new bot Player* owner = GetPlayer(); Player* bot = botMgr->CreateBot( owner, "MyBot", // Name 1, // Human 1, // Warrior 0 // Male ); if (bot) { TC_LOG_INFO("Created bot: {} (GUID: {})", bot->GetName(), bot->GetGUID()); // Get owner's bots auto bots = botMgr->GetPlayerBots(owner->GetGUID()); TC_LOG_INFO("{} has {} bots", owner->GetName(), bots.size()); // Control the bot botMgr->SetBotAIState(bot->GetGUID(), BotAIState::ACTIVE); // Teleport bot to owner botMgr->TeleportBotToOwner(bot->GetGUID()); } // Remove a bot botMgr->RemoveBot(bot->GetGUID()); // Get statistics uint32 activeBots = botMgr->GetActiveBotCount(); TC_LOG_INFO("Total active bots: {}", activeBots); ``` --- ### BotFactory **Purpose**: Factory pattern for creating bot instances with proper initialization. **Location**: `src/modules/Playerbot/Core/BotFactory.h` #### Core Methods ```cpp /** * @brief Create a bot player instance * @param name Bot character name * @param race Race ID * @param class_ Class ID * @param gender Gender * @param level Starting level (default: 1) * @return Pointer to created player instance */ Player* CreateBotPlayer( std::string const& name, uint8 race, uint8 class_, uint8 gender, uint8 level = 1 ); /** * @brief Initialize bot equipment * @param bot Bot player instance * @param level Bot level */ void InitializeBotEquipment(Player* bot, uint8 level); /** * @brief Initialize bot spells and abilities * @param bot Bot player instance */ void InitializeBotSpells(Player* bot); /** * @brief Set bot starting location * @param bot Bot player instance * @return Starting position */ Position GetBotStartingLocation(Player* bot) const; ``` #### Usage Example ```cpp auto* factory = BotFactory::instance(); // Create a level 20 warrior bot Player* bot = factory->CreateBotPlayer("WarriorBot", 1, 1, 0, 20); if (bot) { // Initialize equipment for level 20 factory->InitializeBotEquipment(bot, 20); // Initialize spells factory->InitializeBotSpells(bot); // Set starting location Position startPos = factory->GetBotStartingLocation(bot); bot->Relocate(startPos); } ``` --- ### BotSession **Purpose**: Session management for bot connections (mimics player sessions). **Location**: `src/modules/Playerbot/Core/BotSession.h` #### Key Responsibilities - Bot-server connection management - Packet handling (simulated) - Bot authentication - Session state tracking #### Core Methods ```cpp /** * @brief Create a bot session * @param bot Player instance for the bot * @param owner Owner player * @return Pointer to created session */ static BotSession* CreateSession(Player* bot, Player* owner); /** * @brief Get bot AI instance * @return Pointer to BotAI */ BotAI* GetBotAI() const; /** * @brief Update session * @param diff Time delta */ void Update(uint32 diff); /** * @brief Handle incoming packet (simulated) * @param packet WorldPacket to process */ void HandlePacket(WorldPacket& packet); /** * @brief Check if session is active * @return true if session is connected */ bool IsActive() const; /** * @brief Logout bot * @param save Save bot to database */ void LogoutBot(bool save = true); ``` --- ### BotAI **Purpose**: Core AI controller for bot behavior. **Location**: `src/modules/Playerbot/Core/BotAI.h` #### Initialization Flow ```cpp // BotAI constructor BotAI::BotAI(Player* bot) : _bot(bot) { // Create GameSystemsManager facade (owns all 21 managers) _gameSystems = std::make_unique(bot, this); } // Initialize all systems void BotAI::Initialize() { // Initialize all managers via facade _gameSystems->Initialize(_bot); TC_LOG_INFO("BotAI initialized for bot: {}", _bot->GetName()); } // Main update loop void BotAI::Update(uint32 diff) { // Update all managers _gameSystems->Update(diff); // Execute bot behavior ExecuteBehavior(); } ``` #### Core Methods ```cpp /** * @brief Get GameSystemsManager facade * @return Pointer to IGameSystemsManager */ IGameSystemsManager* GetGameSystems() const; /** * @brief Execute bot AI behavior * Called every update cycle */ void ExecuteBehavior(); /** * @brief Handle bot command * @param command Command string * @param args Command arguments */ void HandleCommand(std::string const& command, std::vector const& args); /** * @brief Set bot strategy * @param strategy Strategy type (FOLLOW, GRIND, QUEST, PVP, etc.) */ void SetStrategy(BotStrategy strategy); /** * @brief Get current strategy * @return Current BotStrategy */ BotStrategy GetStrategy() const; ``` --- ### Bot Command System **Purpose**: Handle player commands to control bots. **Location**: `src/modules/Playerbot/Commands/BotCommands.h` #### Available Commands ```cpp // Bot management commands .bot add // Create and spawn a new bot .bot remove // Remove a bot .bot delete // Permanently delete a bot .bot list // List all your bots // Bot control commands .bot summon // Teleport bot to you .bot follow // Make bots follow you .bot stay // Make bots stay at current position .bot attack // Make bots attack your target // Bot AI commands .bot ai // Enable/disable bot AI .bot strategy // Set bot strategy .bot autoloot // Enable/disable auto-looting // Bot profession commands .bot profession learn // Learn a profession .bot profession craft // Craft an item .bot gather // Enable/disable auto-gathering // Bot economy commands .bot sell // Sell junk items .bot repair // Repair equipment .bot auction // Auction house operations ``` #### Command Implementation Example ```cpp // .bot add command handler void HandleBotAddCommand(Player* player, std::string const& name, uint8 classId, uint8 raceId) { auto* botMgr = BotManager::instance(); // Validate inputs if (!IsValidClass(classId) || !IsValidRace(raceId)) { player->SendSystemMessage("Invalid class or race"); return; } // Check bot limit auto bots = botMgr->GetPlayerBots(player->GetGUID()); if (bots.size() >= botMgr->GetMaxBotsPerPlayer()) { player->SendSystemMessage("You have reached the maximum number of bots"); return; } // Create bot Player* bot = botMgr->CreateBot(player, name, raceId, classId, 0); if (bot) { player->SendSystemMessage("Bot created successfully: " + name); // Auto-summon to player botMgr->TeleportBotToOwner(bot->GetGUID()); } else { player->SendSystemMessage("Failed to create bot"); } } ``` --- ### Bot Database Schema #### Characters Table Extensions ```sql -- Bot-specific fields in characters table ALTER TABLE characters ADD COLUMN is_bot TINYINT(1) DEFAULT 0; ALTER TABLE characters ADD COLUMN bot_owner_guid BIGINT DEFAULT 0; ALTER TABLE characters ADD COLUMN bot_ai_state TINYINT DEFAULT 1; -- Bot configuration table CREATE TABLE IF NOT EXISTS bot_config ( bot_guid BIGINT PRIMARY KEY, owner_guid BIGINT NOT NULL, auto_loot TINYINT(1) DEFAULT 1, auto_gather TINYINT(1) DEFAULT 0, auto_quest TINYINT(1) DEFAULT 0, strategy VARCHAR(32) DEFAULT 'FOLLOW', FOREIGN KEY (bot_guid) REFERENCES characters(guid) ); -- Bot profession configuration CREATE TABLE IF NOT EXISTS bot_professions ( bot_guid BIGINT, profession_type SMALLINT, auto_craft TINYINT(1) DEFAULT 0, auto_sell TINYINT(1) DEFAULT 0, PRIMARY KEY (bot_guid, profession_type) ); ``` --- ### Bot Lifecycle States ```cpp enum class BotLifecycleState { UNINITIALIZED, // Bot created but not initialized INITIALIZING, // Bot systems initializing READY, // Bot ready to be spawned SPAWNING, // Bot being added to world ACTIVE, // Bot active in world PAUSED, // Bot AI paused DESPAWNING, // Bot being removed from world CLEANUP // Bot being deleted }; ``` #### State Transition Example ```cpp void BotManager::TransitionBotState(ObjectGuid botGuid, BotLifecycleState newState) { Player* bot = GetBot(botGuid); if (!bot) return; BotLifecycleState oldState = GetBotState(botGuid); // Validate state transition if (!IsValidStateTransition(oldState, newState)) { TC_LOG_ERROR("Invalid state transition: {} -> {}", StateToString(oldState), StateToString(newState)); return; } // Execute state transition switch (newState) { case BotLifecycleState::INITIALIZING: InitializeBot(bot); break; case BotLifecycleState::SPAWNING: SpawnBotInWorld(bot); break; case BotLifecycleState::ACTIVE: ActivateBotAI(bot); break; case BotLifecycleState::PAUSED: PauseBotAI(bot); break; case BotLifecycleState::DESPAWNING: DespawnBot(bot); break; case BotLifecycleState::CLEANUP: CleanupBot(bot); break; } SetBotState(botGuid, newState); TC_LOG_DEBUG("Bot {} transitioned: {} -> {}", bot->GetName(), StateToString(oldState), StateToString(newState)); } ``` --- ### Complete Bot Creation Example ```cpp /** * @brief Complete workflow for creating and spawning a bot */ Player* CreateAndSpawnBot(Player* owner, std::string const& name, uint8 race, uint8 class_, uint8 level) { auto* botMgr = BotManager::instance(); auto* factory = BotFactory::instance(); // 1. Create bot player instance Player* bot = factory->CreateBotPlayer(name, race, class_, 0, level); if (!bot) { TC_LOG_ERROR("Failed to create bot player instance"); return nullptr; } // 2. Initialize bot equipment and spells factory->InitializeBotEquipment(bot, level); factory->InitializeBotSpells(bot); // 3. Create bot session BotSession* session = BotSession::CreateSession(bot, owner); if (!session) { TC_LOG_ERROR("Failed to create bot session"); delete bot; return nullptr; } // 4. Create bot AI BotAI* botAI = new BotAI(bot); bot->SetBotAI(botAI); // 5. Initialize AI systems (GameSystemsManager + 21 managers) botAI->Initialize(); // 6. Register bot with manager botMgr->RegisterBot(bot, owner->GetGUID()); // 7. Save bot to database bot->SaveToDB(true, false); // 8. Add bot to world Position spawnPos = factory->GetBotStartingLocation(bot); bot->Relocate(spawnPos); if (!bot->IsInWorld()) { bot->AddToWorld(); } // 9. Set initial AI state botMgr->SetBotAIState(bot->GetGUID(), BotAIState::ACTIVE); // 10. Teleport to owner botMgr->TeleportBotToOwner(bot->GetGUID()); TC_LOG_INFO("Bot {} created and spawned successfully for owner {}", bot->GetName(), owner->GetName()); return bot; } ``` --- ### Bot Cleanup and Removal ```cpp /** * @brief Proper bot cleanup and removal */ void RemoveAndCleanupBot(ObjectGuid botGuid) { auto* botMgr = BotManager::instance(); Player* bot = botMgr->GetBot(botGuid); if (!bot) return; TC_LOG_INFO("Removing bot: {}", bot->GetName()); // 1. Pause AI botMgr->SetBotAIState(botGuid, BotAIState::PAUSED); // 2. Save to database bot->SaveToDB(false, false); // 3. Remove from group (if in group) if (Group* group = bot->GetGroup()) { group->RemoveMember(bot->GetGUID()); } // 4. Shutdown GameSystemsManager (destroys all 21 managers) if (BotAI* botAI = bot->GetBotAI()) { botAI->GetGameSystems()->Shutdown(); } // 5. Remove from world if (bot->IsInWorld()) { bot->RemoveFromWorld(); } // 6. Cleanup session if (BotSession* session = bot->GetBotSession()) { session->LogoutBot(true); delete session; } // 7. Cleanup AI if (BotAI* botAI = bot->GetBotAI()) { delete botAI; bot->SetBotAI(nullptr); } // 8. Unregister from manager botMgr->UnregisterBot(botGuid); TC_LOG_INFO("Bot {} removed and cleaned up", bot->GetName()); } ``` --- ### Bot Performance Considerations #### Memory Management ```cpp // Per-bot memory footprint estimate // - Player instance: ~2-4 KB // - BotAI instance: ~1 KB // - GameSystemsManager + 21 managers: ~5-10 KB // - Total per bot: ~8-15 KB // For 100 bots: ~800 KB - 1.5 MB // For 1000 bots: ~8-15 MB ``` #### Update Performance ```cpp // Bot update frequency const uint32 BOT_UPDATE_INTERVAL = 100; // Update every 100ms void BotManager::Update(uint32 diff) { _updateTimer += diff; if (_updateTimer < BOT_UPDATE_INTERVAL) return; _updateTimer = 0; // Update all active bots for (auto& [botGuid, bot] : _activeBots) { if (bot && bot->IsInWorld()) { bot->Update(BOT_UPDATE_INTERVAL); } } } ``` #### Optimization Tips ```cpp // 1. Limit bot count per player const uint32 MAX_BOTS_PER_PLAYER = 5; // 2. Throttle expensive operations const uint32 PROFESSION_CHECK_INTERVAL = 5000; // Every 5 seconds const uint32 AUCTION_CHECK_INTERVAL = 60000; // Every minute // 3. Use spatial partitioning for bot updates // Only update bots near players // 4. Lazy initialization // Don't initialize unused managers until needed // 5. Pool bot instances // Reuse deleted bot instances instead of creating new ones ``` --- ### Best Practices for Bot Systems #### 1. Always Check Bot Validity ```cpp // ✅ GOOD Player* bot = botMgr->GetBot(botGuid); if (bot && bot->IsInWorld()) { bot->Update(diff); } // ❌ BAD Player* bot = botMgr->GetBot(botGuid); bot->Update(diff); // Crash if bot is null! ``` #### 2. Proper Lifecycle Management ```cpp // ✅ GOOD: Follow complete lifecycle CreateBot() → InitializeBot() → SpawnBot() → ... → DespawnBot() → CleanupBot() // ❌ BAD: Skip initialization CreateBot() → SpawnBot() // Missing initialization! ``` #### 3. Resource Cleanup ```cpp // ✅ GOOD: Cleanup in reverse order of creation Shutdown GameSystemsManager → Cleanup BotAI → Cleanup BotSession → Remove from world → Delete bot instance // ❌ BAD: Skip cleanup steps delete bot; // Memory leaks! ``` #### 4. Thread Safety ```cpp // ✅ GOOD: Update bots on main thread only MainThread::Update() { botMgr->Update(diff); // Safe } // ❌ BAD: Update bots from multiple threads WorkerThread::Update() { botMgr->Update(diff); // NOT THREAD-SAFE! } ``` --- **Section Complete**: Bot Creation and Spawning Systems This documentation covers the complete bot lifecycle from creation to cleanup, including all management systems, commands, database schema, and best practices.