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

50 KiB

TrinityCore Playerbot Architecture

Version: WoW 11.2 Compatible Target: 5000 concurrent bots Module Location: src/modules/Playerbot/


Table of Contents

  1. System Overview
  2. Module Structure
  3. Core vs Module Separation
  4. Component Architecture
  5. Data Flow
  6. Thread Model
  7. Memory Management
  8. Design Patterns
  9. Performance Architecture
  10. 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:

// All code in src/modules/Playerbot/
namespace Playerbot {
    class BotSpawner { /* ... */ };
    class BotSession : public WorldSession { /* ... */ };
    class BotAI { /* ... */ };
}

Integration via 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)

// 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:

void AddSC_PlayerBotScripts() {
    new PlayerBotWorldScript();
}

2. Session Creation Hook

// 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)

-- 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:

cmake .. -DBUILD_PLAYERBOT=1

Disable Module (Default):

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:

// 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:

// 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:

// 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

// 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)

// 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

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

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

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

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

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

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
// Atomic operations instead of mutex
std::atomic<uint32> _activeBotCount;
uint32 count = _activeBotCount.load(std::memory_order_acquire);
  1. Batch Processing
// 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()));
}
  1. Async Database Operations
// Non-blocking queries
sPlayerbotCharDB->ExecuteAsync(stmt, [](PreparedQueryResult result) {
    // Process on callback thread
});
  1. Object Pooling
// Reuse expensive objects
WorldPacket* packet = _packetPool->Acquire();
// Use packet
_packetPool->Release(packet);
  1. Throttled Updates
// 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:

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)

// 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)

// 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)

// 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)

-- 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.