# TrinityCore Playerbot Architecture **Version:** WoW 11.2 Compatible **Target:** 5000 concurrent bots **Module Location:** `src/modules/Playerbot/` --- ## Table of Contents 1. [System Overview](#system-overview) 2. [Module Structure](#module-structure) 3. [Core vs Module Separation](#core-vs-module-separation) 4. [Component Architecture](#component-architecture) 5. [Data Flow](#data-flow) 6. [Thread Model](#thread-model) 7. [Memory Management](#memory-management) 8. [Design Patterns](#design-patterns) 9. [Performance Architecture](#performance-architecture) 10. [Scalability](#scalability) --- ## System Overview ### High-Level Architecture ``` ┌─────────────────────────────────────────────────────────────────┐ │ TrinityCore Server │ │ │ │ ┌────────────┐ ┌────────────┐ ┌─────────────────────────┐ │ │ │ bnetserver│ │ worldserver│ │ MySQL 9.4 Database │ │ │ │ (unchanged)│ │ │ │ ┌──────┬──────┬──────┐ │ │ │ └────────────┘ │ ┌────────┐ │ │ │ auth │ char │ world│ │ │ │ │ │ Core │ │ │ └──────┴──────┴──────┘ │ │ │ │ │Systems │ │ │ │ │ │ │ └────┬───┘ │ └─────────────────────────┘ │ │ │ │ │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────┐ │ │ │ │ Playerbot Module (Optional) │ │ │ │ │ │ │ │ │ │ ┌────────────┬──────────────┐ │ │ │ │ │ │ BotSpawner │ BotWorldMgr │ │ │ │ │ │ └─────┬──────┴──────┬───────┘ │ │ │ │ │ │ │ │ │ │ │ │ ┌─────▼─────┐ ┌────▼────────┐ │ │ │ │ │ │BotSessions│ │ Bot AI │ │ │ │ │ │ │(Socketless)│ │ System │ │ │ │ │ │ └───────────┘ └─────────────┘ │ │ │ │ └────────────────────────────────────┘ │ │ └───────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ``` ### Design Philosophy 1. **Module-First Approach**: All functionality in `src/modules/Playerbot/` 2. **Zero Core Modification**: TrinityCore compiles and runs with/without module 3. **Optional Compilation**: `-DBUILD_PLAYERBOT=1` flag enables module 4. **Backward Compatible**: No breaking changes to existing TrinityCore APIs 5. **Performance First**: Designed for 5000 concurrent bots from ground up --- ## Module Structure ### Directory Organization ``` src/modules/Playerbot/ ├── Account/ # Bot account management │ ├── BotAccountMgr.h/cpp # Account pool manager │ └── BotCharacterDistribution.h/cpp │ ├── AI/ # AI decision making │ ├── BotAI.h/cpp # Base AI controller │ ├── BotAIFactory.cpp # AI factory │ ├── Actions/ # Action system │ │ ├── Action.h │ │ ├── CommonActions.h/cpp │ │ └── SpellInterruptAction.h/cpp │ ├── ClassAI/ # Class-specific AI │ │ ├── ClassAI.h/cpp # Base class AI │ │ ├── Warriors/ # Warrior AI (3 specs) │ │ ├── Paladins/ # Paladin AI (3 specs) │ │ ├── Hunters/ # Hunter AI (3 specs) │ │ ├── Rogues/ # Rogue AI (3 specs) │ │ ├── Priests/ # Priest AI (3 specs) │ │ ├── DeathKnights/ # DK AI (3 specs) │ │ ├── Shamans/ # Shaman AI (3 specs) │ │ ├── Mages/ # Mage AI (3 specs) │ │ ├── Warlocks/ # Warlock AI (3 specs) │ │ ├── Monks/ # Monk AI (3 specs) │ │ ├── Druids/ # Druid AI (4 specs) │ │ ├── DemonHunters/ # DH AI (2 specs) │ │ └── Evokers/ # Evoker AI (3 specs) │ ├── Combat/ # Combat systems │ │ ├── InterruptCoordinator.h/cpp │ │ ├── ThreatManager.h/cpp │ │ ├── TargetSelector.h/cpp │ │ └── PositionManager.h/cpp │ ├── Learning/ # Machine learning adaptation │ │ ├── BehaviorAdaptation.h/cpp │ │ └── PlayerPatternRecognition.h/cpp │ ├── Strategy/ # Strategy pattern system │ │ ├── Strategy.h/cpp │ │ └── GroupCombatStrategy.h/cpp │ ├── Triggers/ # Trigger system │ │ └── Trigger.h/cpp │ └── Values/ # Value cache │ └── Value.h/cpp │ ├── Commands/ # Chat command handlers │ └── PlayerbotCommands.cpp │ ├── Config/ # Configuration system │ ├── PlayerbotConfig.h/cpp # Config manager │ └── PlayerbotLog.h # Logging macros │ ├── Database/ # Database integration │ ├── PlayerbotDatabase.h # Database connection │ ├── PlayerbotCharacterDBInterface.h/cpp │ ├── BotDatabasePool.h/cpp # Connection pooling │ └── PlayerbotDatabaseStatements.h │ ├── Dungeon/ # Dungeon automation │ ├── DungeonBehavior.h/cpp │ └── EncounterStrategy.h/cpp │ ├── Group/ # Group coordination │ ├── GroupInvitationHandler.h/cpp │ ├── GroupCoordination.h/cpp │ ├── GroupFormation.h/cpp │ └── RoleOptimizer.h/cpp │ ├── Lifecycle/ # Bot lifecycle │ ├── BotSpawner.h/cpp # Main spawner (5000 bot capacity) │ ├── BotScheduler.h/cpp # Update scheduling │ ├── BotLifecycleMgr.h/cpp │ ├── BotCharacterCreator.h/cpp │ └── SpawnRequest.h # Spawn request structure │ ├── Movement/ # Movement behaviors │ ├── LeaderFollowBehavior.h/cpp │ ├── FormationManager.h/cpp │ └── PathfindingManager.h/cpp │ ├── Performance/ # Performance monitoring │ ├── BotPerformanceMonitor.h/cpp │ ├── BotProfiler.h/cpp │ ├── BotMemoryManager.h/cpp │ └── MLPerformanceTracker.h/cpp │ ├── Quest/ # Quest automation │ ├── QuestPickup.h/cpp │ ├── QuestCompletion.h/cpp │ └── QuestAutomation.h/cpp │ ├── Session/ # Session management │ ├── BotSession.h/cpp # Socketless session │ ├── BotSessionMgr.h/cpp # Legacy session manager │ ├── BotWorldSessionMgr.h/cpp # Native session manager │ └── BotLoginQueryHolder.h │ ├── Social/ # Social features │ ├── AuctionAutomation.h/cpp │ ├── TradeAutomation.h/cpp │ ├── GuildIntegration.h/cpp │ └── VendorInteraction.h/cpp │ ├── Scripts/ # World script integration │ └── PlayerbotWorldScript.cpp │ └── CMakeLists.txt # Module build configuration ``` ### Key Files by Function **Bot Creation & Spawning:** - `BotSpawner.cpp` - Central spawner (1494 lines) - `BotCharacterCreator.cpp` - Character creation - `BotAccountMgr.cpp` - Account management **Session Management:** - `BotSession.cpp` - Socketless session (1172 lines) - `BotWorldSessionMgr.cpp` - Native TrinityCore integration **AI System:** - `BotAI.cpp` - Base AI logic (831 lines) - `ClassAI.cpp` - Class-specific base - Individual class files (e.g., `WarriorAI.cpp`) **Configuration:** - `PlayerbotConfig.cpp` - Config loading/validation (563 lines) - `playerbots.conf` - Configuration file --- ## Core vs Module Separation ### Module-Only Implementation (Preferred) **Zero Core Modifications:** ```cpp // All code in src/modules/Playerbot/ namespace Playerbot { class BotSpawner { /* ... */ }; class BotSession : public WorldSession { /* ... */ }; class BotAI { /* ... */ }; } ``` **Integration via CMake:** ```cmake # src/modules/Playerbot/CMakeLists.txt if (BUILD_PLAYERBOT) add_library(playerbot STATIC # All module source files ) target_link_libraries(game PUBLIC playerbot) endif() ``` ### Core Integration Points (Minimal) **1. World Script Hook (Single Point of Entry)** ```cpp // src/modules/Playerbot/scripts/PlayerbotWorldScript.cpp class PlayerBotWorldScript : public WorldScript { public: void OnStartup() override { // Initialize playerbot systems sBotSpawner->Initialize(); } void OnUpdate(uint32 diff) override { // Update bot systems sBotWorldSessionMgr->Update(diff); } }; ``` **Registration:** ```cpp void AddSC_PlayerBotScripts() { new PlayerBotWorldScript(); } ``` **2. Session Creation Hook** ```cpp // BotWorldSessionMgr creates WorldSession instances // Uses standard TrinityCore session manager APIs bool AddPlayerBot(ObjectGuid characterGuid, uint32 accountId) { auto session = std::make_shared(accountId); // Add to WorldSessionFilter (standard TrinityCore API) return true; } ``` **3. Database Extensions (Optional)** ```sql -- Separate playerbot database or tables in characters DB CREATE TABLE IF NOT EXISTS `playerbot_accounts` ( `account_id` INT UNSIGNED NOT NULL, `max_bots` INT UNSIGNED DEFAULT 10, PRIMARY KEY (`account_id`) ); ``` ### Compilation Flags **Enable Module:** ```bash cmake .. -DBUILD_PLAYERBOT=1 ``` **Disable Module (Default):** ```bash cmake .. # Module not compiled ``` --- ## Component Architecture ### BotSpawner Architecture ``` ┌─────────────────────────────────────────────────────────┐ │ BotSpawner │ │ (Singleton) │ │ │ │ ┌─────────────────┐ ┌──────────────────┐ │ │ │ Configuration │ │ Spawn Queue │ │ │ │ - Max bots │ │ - Async queue │ │ │ │ - Batch size │ │ - Lock-free │ │ │ │ - Ratios │ │ - Priority │ │ │ └─────────────────┘ └──────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────┐ │ │ │ Bot Tracking (Thread-Safe) │ │ │ │ ┌──────────────┬────────────────────────┐ │ │ │ │ │_activeBots │ ObjectGuid → ZoneID │ │ │ │ │ │_botsByZone │ ZoneID → [ObjectGuid] │ │ │ │ │ │_activeBotCount│ atomic │ │ │ │ │ └──────────────┴────────────────────────┘ │ │ │ └─────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────┐ │ │ │ Population Management │ │ │ │ - Zone population tracking │ │ │ │ - Dynamic spawn calculations │ │ │ │ - Bot-to-player ratio enforcement │ │ │ └─────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────┐ │ │ │ Character Management │ │ │ │ - BotAccountMgr integration │ │ │ │ - BotCharacterCreator │ │ │ │ - Character GUID allocation │ │ │ └─────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────┘ │ │ ▼ ▼ ┌─────────────┐ ┌───────────────┐ │BotWorldMgr │ │ BotSession │ │(Native TC) │ │ Factory │ └─────────────┘ └───────────────┘ ``` ### BotSession Architecture ``` ┌──────────────────────────────────────────────────────┐ │ BotSession (Socketless) │ │ extends WorldSession │ │ │ │ ┌─────────────────────────────────────────────┐ │ │ │ Constructor (No Socket) │ │ │ │ - nullptr socket parameter │ │ │ │ - Overrides PlayerDisconnected() → false │ │ │ │ - No network packet processing │ │ │ └─────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────┐ │ │ │ Packet Queues (Simulated Network) │ │ │ │ ┌──────────────┬──────────────────┐ │ │ │ │ │_incomingPkts │ queue │ │ │ │ │ │_outgoingPkts │ queue │ │ │ │ │ └──────────────┴──────────────────┘ │ │ │ │ Mutex: _packetMutex (recursive_timed) │ │ │ └─────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────┐ │ │ │ Login System (Async Query Holder) │ │ │ │ - BotLoginQueryHolder (58 queries) │ │ │ │ - HandleBotPlayerLogin() callback │ │ │ │ - Atomic state: LOGIN_IN_PROGRESS │ │ │ └─────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────┐ │ │ │ AI Integration │ │ │ │ - BotAI* _ai (owned pointer) │ │ │ │ - Created after successful login │ │ │ │ - Updated every frame │ │ │ └─────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────┐ │ │ │ State Management (Thread-Safe) │ │ │ │ - atomic _active │ │ │ │ - atomic _destroyed │ │ │ │ - atomic _loginState │ │ │ └─────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────┘ ``` ### BotAI Architecture (Strategy Pattern) ``` ┌──────────────────────────────────────────────────────────┐ │ BotAI (Base) │ │ │ │ ┌────────────────────────────────────────────────────┐ │ │ │ UpdateAI(diff) - SINGLE ENTRY POINT │ │ │ │ ┌──────────────────────────────────────────────┐ │ │ │ │ │ 1. UpdateValues(diff) │ │ │ │ │ │ 2. UpdateStrategies(diff) ←─ EVERY FRAME │ │ │ │ │ │ 3. ProcessTriggers() │ │ │ │ │ │ 4. UpdateActions(diff) │ │ │ │ │ │ 5. UpdateMovement(diff) ←─ EVERY FRAME │ │ │ │ │ │ 6. UpdateCombatState(diff) │ │ │ │ │ │ 7. if (InCombat) OnCombatUpdate(diff) │ │ │ │ │ │ 8. UpdateIdleBehaviors(diff) │ │ │ │ │ └──────────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ ┌────────────────────────────────────────────────────┐ │ │ │ Strategy System │ │ │ │ ┌──────────────────────────────────────────────┐ │ │ │ │ │ _strategies: map>│ │ │ │ │ │ _activeStrategies: vector │ │ │ │ │ │ │ │ │ │ │ │ Default Strategies: │ │ │ │ │ │ - "follow" (LeaderFollowBehavior) │ │ │ │ │ │ - "group_combat" (GroupCombatStrategy) │ │ │ │ │ │ │ │ │ │ │ │ Activated when bot joins group │ │ │ │ │ └──────────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ ┌────────────────────────────────────────────────────┐ │ │ │ Action System (Command Pattern) │ │ │ │ ┌──────────────────────────────────────────────┐ │ │ │ │ │ _actionQueue: queue │ │ │ │ │ │ _currentAction: shared_ptr │ │ │ │ │ │ │ │ │ │ │ │ Execution Priority: │ │ │ │ │ │ 1. Triggered actions (from triggers) │ │ │ │ │ │ 2. Queued actions (explicit requests) │ │ │ │ │ └──────────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ ┌────────────────────────────────────────────────────┐ │ │ │ Trigger System │ │ │ │ ┌──────────────────────────────────────────────┐ │ │ │ │ │ _triggers: vector> │ │ │ │ │ │ _triggeredActions: priority_queue │ │ │ │ │ │ │ │ │ │ │ │ Each frame: │ │ │ │ │ │ 1. Check() - Fast pre-check │ │ │ │ │ │ 2. Evaluate() - Full evaluation │ │ │ │ │ │ 3. Queue action with urgency │ │ │ │ │ └──────────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────┐ │ ClassAI (Derived) │ │ │ │ OnCombatUpdate(diff) │ │ - UpdateRotation() │ │ - UpdateBuffs() │ │ - UpdateCooldowns() │ │ │ │ NO base UpdateAI override! │ │ NO movement control! │ └──────────────────────────────┘ ``` ### Group Coordination Architecture ``` ┌────────────────────────────────────────────────────┐ │ Group Invitation Flow │ │ │ │ Player sends invite │ │ │ │ │ ▼ │ │ ┌──────────────────────────────────────────┐ │ │ │ SMSG_PARTY_INVITE packet │ │ │ └──────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────────────────────────────┐ │ │ │ BotSession::SendPacket() intercepts │ │ │ │ Calls HandleGroupInvitation() │ │ │ └──────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────────────────────────────┐ │ │ │ Parse packet (inviter, roles, etc.) │ │ │ │ Call Group::AddInvite(bot) │ │ │ │ Sets bot->SetGroupInvite() │ │ │ └──────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────────────────────────────┐ │ │ │ GroupInvitationHandler::HandleInvitation()│ │ │ │ Queue invitation for processing │ │ │ └──────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────────────────────────────┐ │ │ │ GroupInvitationHandler::Update() │ │ │ │ Auto-accept after delay │ │ │ └──────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────────────────────────────┐ │ │ │ Group::AddMember(bot) │ │ │ │ Standard TrinityCore group joining │ │ │ └──────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────────────────────────────┐ │ │ │ BotAI::OnGroupJoined() │ │ │ │ - ActivateStrategy("follow") │ │ │ │ - ActivateStrategy("group_combat") │ │ │ │ - SetAIState(FOLLOWING) │ │ │ └──────────────────────────────────────────┘ │ └────────────────────────────────────────────────────┘ ``` --- ## Data Flow ### Bot Spawn Flow ``` Player → .bot spawn command │ ▼ PlayerbotCommands::HandlePlayerbotSpawnCommand() │ ├─→ Validate input (class, race, gender, name) │ ▼ BotSpawner::CreateAndSpawnBot() │ ├─→ BotCharacterCreator::CreateBotCharacter() │ ├─→ Generate character GUID │ ├─→ Allocate unique name │ ├─→ Create Player object │ ├─→ Player::Create() (TrinityCore API) │ ├─→ SaveToDB() (async transaction) │ └─→ Return ObjectGuid │ ├─→ BotWorldSessionMgr::AddPlayerBot() │ ├─→ Create BotSession │ ├─→ BotSession::LoginCharacter() (async) │ │ ├─→ Create BotLoginQueryHolder (58 queries) │ │ ├─→ CharacterDatabase.DelayQueryHolder() │ │ └─→ Callback: HandleBotPlayerLogin() │ │ ├─→ Create Player object │ │ ├─→ LoadFromDB(holder) (async) │ │ ├─→ AddPlayerToMap() │ │ ├─→ ObjectAccessor::AddObject() │ │ ├─→ SendInitialPackets() │ │ └─→ Create BotAI │ │ └─→ BotAIFactory::CreateAI() │ │ └─→ ClassAIFactory::CreateClassAI() │ │ │ └─→ Add to WorldSessionFilter (TrinityCore) │ └─→ Update spawn statistics ├─→ totalSpawned++ ├─→ currentlyActive++ └─→ peakConcurrent (if new peak) ``` ### Bot Update Flow (Every Frame) ``` WorldServerUpdate (10ms tick) │ ▼ PlayerbotWorldScript::OnUpdate(diff) │ ▼ BotWorldSessionMgr::Update(diff) │ ├─→ For each BotSession: │ │ │ ├─→ BotSession::Update(diff, filter) │ │ │ │ │ ├─→ ProcessPendingLogin() (if logging in) │ │ │ │ │ ├─→ ProcessQueryCallbacks() (async DB callbacks) │ │ │ │ │ ├─→ ProcessBotPackets() (packet queue) │ │ │ ├─→ Extract packets (lock-free batch) │ │ │ └─→ Process through WorldSession │ │ │ │ │ └─→ if (AI && Player && IsInWorld): │ │ └─→ AI->UpdateAI(diff) │ │ │ │ │ ├─→ UpdateValues(diff) │ │ │ │ │ ├─→ UpdateStrategies(diff) ← EVERY FRAME │ │ │ └─→ For each active strategy: │ │ │ ├─→ IsActive() check │ │ │ └─→ UpdateBehavior(ai, diff) │ │ │ └─→ (e.g., LeaderFollowBehavior) │ │ │ ├─→ Find group leader │ │ │ ├─→ Calculate follow position │ │ │ └─→ MotionMaster::MoveFollow() │ │ │ │ │ ├─→ ProcessTriggers() │ │ │ └─→ For each trigger: │ │ │ ├─→ Check() (fast) │ │ │ └─→ if true: Evaluate() (full) │ │ │ └─→ Queue action with urgency │ │ │ │ │ ├─→ UpdateActions(diff) │ │ │ ├─→ Execute current action │ │ │ └─→ OR select next from queue │ │ │ │ │ ├─→ UpdateMovement(diff) ← EVERY FRAME │ │ │ │ │ ├─→ UpdateCombatState(diff) │ │ │ ├─→ Detect combat entry/exit │ │ │ └─→ Call OnCombatStart/End │ │ │ │ │ ├─→ if (IsInCombat()): │ │ │ └─→ OnCombatUpdate(diff) [virtual] │ │ │ └─→ ClassAI override: │ │ │ ├─→ UpdateTargeting() │ │ │ ├─→ UpdateRotation(target) │ │ │ └─→ UpdateCooldowns(diff) │ │ │ │ │ ├─→ GroupInvitationHandler::Update(diff) │ │ │ │ │ └─→ if (!InCombat && !Following): │ │ └─→ UpdateIdleBehaviors(diff) │ │ ├─→ QuestAutomation (5s throttle) │ │ ├─→ TradeAutomation (10s throttle) │ │ └─→ AuctionAutomation (30s throttle) │ │ │ └─→ Record performance metrics │ └─→ ProcessGlobalCallbacks() ``` --- ## Thread Model ### Thread Safety Guarantees **World Update Thread (Main Thread):** - All BotSession updates - All BotAI updates - Strategy execution - Action execution **Async Thread Pool (TrinityCore):** - Database queries (async query holders) - Character loading - Login query processing **Lock-Free Operations:** ```cpp // Atomic counters - safe to access from any thread uint32 count = sBotSpawner->GetActiveBotCount(); // atomic load // Statistics - atomic operations _stats.totalSpawned.fetch_add(1); _stats.currentlyActive.fetch_sub(1); ``` **Mutex-Protected Operations:** ```cpp // Strategy management std::shared_lock lock(_mutex); // Read lock std::unique_lock lock(_mutex); // Write lock // Packet queues std::lock_guard lock(_packetMutex); // Spawn queue std::lock_guard lock(_spawnQueueMutex); ``` ### Deadlock Prevention **Lock Ordering:** 1. `_zoneMutex` (BotSpawner) 2. `_botMutex` (BotSpawner) 3. `_packetMutex` (BotSession) 4. `_mutex` (BotAI) **Lock-Free Batch Processing:** ```cpp // Phase 1: Extract data with minimal lock time { std::lock_guard lock(_mutex); // Quick copy of data dataCopy = _data; } // Lock released // Phase 2: Process without holding lock ProcessData(dataCopy); // Phase 3: Update results with minimal lock time { std::lock_guard lock(_mutex); // Quick update _results = processed; } ``` --- ## Memory Management ### Memory Budget (Per Bot) ``` Total per bot: ~8-10 MB Breakdown: - Player object: ~2 MB (TrinityCore standard) - BotSession: ~1 MB (packet queues, state) - BotAI: ~0.5 MB (strategies, actions, triggers) - ClassAI: ~0.5 MB (class-specific data) - WorldSession data: ~2 MB (TrinityCore standard) - Strategy data: ~0.5 MB (follow, combat, etc.) - Misc overhead: ~1.5 MB (allocator overhead, cache) ``` ### RAII Patterns ```cpp // Unique pointers for ownership std::unique_ptr _ai; std::unique_ptr _strategy; std::unique_ptr _action; // Shared pointers for shared ownership std::shared_ptr session; std::shared_ptr action; // Smart pointers prevent memory leaks { auto session = BotSession::Create(accountId); // Automatic cleanup on scope exit } ``` ### Object Pooling (Future Optimization) ```cpp // Planned for 5000 bot scalability class ObjectPool { std::vector> _pool; std::queue _available; public: T* Acquire(); void Release(T* obj); }; // Usage ObjectPool packetPool; WorldPacket* packet = packetPool.Acquire(); // ... use packet packetPool.Release(packet); ``` --- ## Design Patterns ### 1. Singleton Pattern **Used For:** Global managers ```cpp class BotSpawner { public: static BotSpawner* instance() { static BotSpawner instance; return &instance; } private: BotSpawner() = default; }; #define sBotSpawner BotSpawner::instance() ``` ### 2. Factory Pattern **Used For:** AI creation ```cpp class BotAIFactory { public: std::unique_ptr CreateAI(Player* bot) { uint8 classId = bot->GetClass(); switch (classId) { case CLASS_WARRIOR: return std::make_unique(bot); case CLASS_PALADIN: return std::make_unique(bot); // ... other classes } } }; ``` ### 3. Strategy Pattern **Used For:** Behavior composition ```cpp class Strategy { public: virtual std::string GetName() const = 0; virtual bool IsActive(BotAI const* ai) const = 0; virtual void UpdateBehavior(BotAI* ai, uint32 diff) = 0; }; class LeaderFollowBehavior : public Strategy { public: std::string GetName() const override { return "follow"; } void UpdateBehavior(BotAI* ai, uint32 diff) override { // Follow logic } }; ``` ### 4. Command Pattern **Used For:** Action system ```cpp class Action { public: virtual bool IsPossible(BotAI* ai) = 0; virtual bool IsUseful(BotAI* ai) = 0; virtual ActionResult Execute(BotAI* ai, ActionContext const& ctx) = 0; }; // Queue and execute actions botAI->QueueAction(std::make_shared()); ``` ### 5. Observer Pattern **Used For:** Event handling ```cpp class Trigger { public: virtual bool Check(BotAI const* ai) = 0; virtual TriggerResult Evaluate(BotAI* ai) = 0; }; // Triggers observe bot state and suggest actions class LowHealthTrigger : public Trigger { bool Check(BotAI const* ai) override { return ai->GetBot()->GetHealthPct() < 30.0f; } }; ``` ### 6. Adapter Pattern **Used For:** TrinityCore integration ```cpp class BotSession : public WorldSession { // Adapts WorldSession for socketless operation bool PlayerDisconnected() const override { return false; } void SendPacket(WorldPacket const* packet, bool forced) override { // Queue packet instead of sending over network } }; ``` --- ## Performance Architecture ### Scalability Design (5000 Bots) **Current State (500-800 bots):** - Linear scaling - ~0.1% CPU per bot - ~10 MB memory per bot - Single-threaded update loop **Target State (5000 bots):** ``` Performance Targets: - CPU: <10% total for 5000 bots - Memory: <50 GB total - Update rate: 100ms per bot (10 Hz) - Database: <1000 queries/sec ``` **Optimization Strategies:** 1. **Lock-Free Data Structures** ```cpp // Atomic operations instead of mutex std::atomic _activeBotCount; uint32 count = _activeBotCount.load(std::memory_order_acquire); ``` 2. **Batch Processing** ```cpp // Process bots in batches constexpr size_t BATCH_SIZE = 100; for (size_t i = 0; i < sessions.size(); i += BATCH_SIZE) { ProcessBatch(sessions, i, std::min(i + BATCH_SIZE, sessions.size())); } ``` 3. **Async Database Operations** ```cpp // Non-blocking queries sPlayerbotCharDB->ExecuteAsync(stmt, [](PreparedQueryResult result) { // Process on callback thread }); ``` 4. **Object Pooling** ```cpp // Reuse expensive objects WorldPacket* packet = _packetPool->Acquire(); // Use packet _packetPool->Release(packet); ``` 5. **Throttled Updates** ```cpp // Expensive operations run less frequently if (currentTime - _lastExpensiveUpdate > 500) { UpdateBuffs(); // Only every 500ms _lastExpensiveUpdate = currentTime; } ``` ### Performance Monitoring **Metrics Tracked:** - Update time per bot (µs) - Memory usage per bot (bytes) - Database query time (ms) - AI decision time (µs) - Spawn/despawn time (µs) **Access:** ```cpp SpawnStats const& stats = sBotSpawner->GetStats(); TC_LOG_INFO("module.playerbot", "Avg spawn time: {:.2f}ms", stats.GetAverageSpawnTime()); TC_LOG_INFO("module.playerbot", "Success rate: {:.2f}%", stats.GetSuccessRate()); ``` --- ## Scalability ### Current Capacity Analysis **Bottlenecks (500-800 bots):** 1. Single-threaded update loop 2. Database query overhead 3. Memory allocation patterns 4. Packet processing overhead **Observed Performance:** - 500 bots: ~5% CPU, stable - 800 bots: ~8% CPU, occasional lag spikes - 1000 bots: ~12% CPU, noticeable lag ### Roadmap to 5000 Bots **Phase 1: Multi-Threading (Target: 2000 bots)** ```cpp // Thread pool for bot updates ThreadPool updatePool(std::thread::hardware_concurrency()); void Update(uint32 diff) { for (auto& session : _sessions) { updatePool.QueueTask([session, diff]() { session->Update(diff); }); } updatePool.WaitAll(); } ``` **Phase 2: Advanced Caching (Target: 3500 bots)** ```cpp // Shared spell info cache class SpellInfoCache { static std::unordered_map _cache; public: static SpellInfo const* Get(uint32 spellId); }; // Reduce per-bot memory ``` **Phase 3: Load Balancing (Target: 5000 bots)** ```cpp // Distribute bots across multiple world servers class BotLoadBalancer { std::vector _servers; public: WorldServer* SelectServer(uint32 zoneId); void RebalanceBots(); }; ``` **Phase 4: Database Optimization (Target: 5000+ bots)** ```sql -- Partitioned tables for better query performance ALTER TABLE characters PARTITION BY RANGE (account) ( PARTITION p0 VALUES LESS THAN (10000), PARTITION p1 VALUES LESS THAN (20000), PARTITION p2 VALUES LESS THAN (30000) ); -- Optimized indexes CREATE INDEX idx_bot_sessions ON characters (account, online); ``` --- ## Component Interaction Diagram ``` ┌─────────────────────────────────────────────────────────────────┐ │ TrinityCore World Server │ │ │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ Main Update Loop (10ms) │ │ │ └────────┬─────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ PlayerbotWorldScript::OnUpdate() │ │ │ └────────┬─────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ BotWorldSessionMgr::Update(diff) │ │ │ │ ┌────────────────────────────────────────────────────┐ │ │ │ │ │ For each BotSession: │ │ │ │ │ │ session->Update(diff, filter) │ │ │ │ │ └─────────┬──────────────────────────────────────────┘ │ │ │ └────────────┼──────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ BotSession::Update(diff) │ │ │ │ ┌────────────────────────────────────────────────────┐ │ │ │ │ │ 1. ProcessQueryCallbacks() ─→ DB async results │ │ │ │ │ │ 2. ProcessBotPackets() ─────→ Packet queue │ │ │ │ │ │ 3. AI->UpdateAI(diff) ──────→ Main AI logic │ │ │ │ │ └─────────┬──────────────────────────────────────────┘ │ │ │ └────────────┼──────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ BotAI::UpdateAI(diff) │ │ │ │ ┌────────────────────────────────────────────────────┐ │ │ │ │ │ UpdateStrategies(diff) ───┐ │ │ │ │ │ │ ▼ │ │ │ │ │ │ ┌─────────────────┐ │ │ │ │ │ │ │ LeaderFollow │ │ │ │ │ │ │ │ GroupCombat │ │ │ │ │ │ │ │ ... more ... │ │ │ │ │ │ │ └─────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ ProcessTriggers() ────────┐ │ │ │ │ │ │ ▼ │ │ │ │ │ │ ┌─────────────────┐ │ │ │ │ │ │ │ LowHealth │ │ │ │ │ │ │ │ EnemyNearby │ │ │ │ │ │ │ │ ... more ... │ │ │ │ │ │ │ └─────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ if (InCombat): │ │ │ │ │ │ OnCombatUpdate(diff) [virtual] │ │ │ │ │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ │ │ ┌─────────────────────────────────────┐ │ │ │ │ │ │ │ ClassAI::OnCombatUpdate() │ │ │ │ │ │ │ │ - UpdateRotation(target) │ │ │ │ │ │ │ │ - UpdateCooldowns(diff) │ │ │ │ │ │ │ │ - UpdateBuffs() │ │ │ │ │ │ │ └─────────────────────────────────────┘ │ │ │ │ │ └────────────────────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ``` --- ## Conclusion The TrinityCore Playerbot module demonstrates a clean, modular architecture that: 1. **Separates Concerns**: Module-only implementation with minimal core touchpoints 2. **Scales Efficiently**: Designed from ground up for 5000 concurrent bots 3. **Follows Patterns**: Uses proven design patterns (Strategy, Factory, Command, Observer) 4. **Maintains Quality**: Thread-safe, memory-efficient, performance-monitored 5. **Stays Compatible**: Zero breaking changes to existing TrinityCore functionality The architecture is production-ready for 500-800 bots and has a clear roadmap to 5000+ bots through multi-threading, caching, and load balancing optimizations.