Files
ThordekkCore/PLAYERBOT_ARCHITECTURE.md
T
2026-01-20 21:33:16 -03:00

1105 lines
50 KiB
Markdown

# 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<BotSession>(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<uint32> │ │ │
│ │ └──────────────┴────────────────────────┘ │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 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<WorldPkt> │ │ │
│ │ │_outgoingPkts │ queue<WorldPkt> │ │ │
│ │ └──────────────┴──────────────────┘ │ │
│ │ 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<bool> _active │ │
│ │ - atomic<bool> _destroyed │ │
│ │ - atomic<LoginState> _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<string, unique_ptr<Strategy>>│ │ │
│ │ │ _activeStrategies: vector<string> │ │ │
│ │ │ │ │ │
│ │ │ Default Strategies: │ │ │
│ │ │ - "follow" (LeaderFollowBehavior) │ │ │
│ │ │ - "group_combat" (GroupCombatStrategy) │ │ │
│ │ │ │ │ │
│ │ │ Activated when bot joins group │ │ │
│ │ └──────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Action System (Command Pattern) │ │
│ │ ┌──────────────────────────────────────────────┐ │ │
│ │ │ _actionQueue: queue<Action, Context> │ │ │
│ │ │ _currentAction: shared_ptr<Action> │ │ │
│ │ │ │ │ │
│ │ │ Execution Priority: │ │ │
│ │ │ 1. Triggered actions (from triggers) │ │ │
│ │ │ 2. Queued actions (explicit requests) │ │ │
│ │ └──────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Trigger System │ │
│ │ ┌──────────────────────────────────────────────┐ │ │
│ │ │ _triggers: vector<shared_ptr<Trigger>> │ │ │
│ │ │ _triggeredActions: priority_queue<Result> │ │ │
│ │ │ │ │ │
│ │ │ 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<std::recursive_timed_mutex> lock(_packetMutex);
// Spawn queue
std::lock_guard<std::mutex> 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<BotAI> _ai;
std::unique_ptr<Strategy> _strategy;
std::unique_ptr<Action> _action;
// Shared pointers for shared ownership
std::shared_ptr<BotSession> session;
std::shared_ptr<Action> 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<T> {
std::vector<std::unique_ptr<T>> _pool;
std::queue<T*> _available;
public:
T* Acquire();
void Release(T* obj);
};
// Usage
ObjectPool<WorldPacket> 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<BotAI> CreateAI(Player* bot) {
uint8 classId = bot->GetClass();
switch (classId) {
case CLASS_WARRIOR:
return std::make_unique<WarriorAI>(bot);
case CLASS_PALADIN:
return std::make_unique<PaladinAI>(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<HealAction>());
```
### 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<uint32> _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<BotSession> 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<uint32, SpellInfo const*> _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<WorldServer*> _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.