27 KiB
TrinityCore Playerbot API Reference
Version: WoW 11.2 Compatible
Target: 5000 concurrent bots
Module Location: src/modules/Playerbot/
Table of Contents
Core APIs
BotSpawner
File: src/modules/Playerbot/Lifecycle/BotSpawner.h
Singleton Access: sBotSpawner or BotSpawner::instance()
Bot lifecycle manager responsible for creating, spawning, and despawning bots with support for 5000 concurrent bots.
Core Methods
Initialize()
bool BotSpawner::Initialize()
Initializes the bot spawner system.
Returns: true on success, false on failure
Example:
if (!sBotSpawner->Initialize()) {
TC_LOG_ERROR("module.playerbot", "Failed to initialize BotSpawner");
return false;
}
SpawnBot(SpawnRequest const& request)
bool BotSpawner::SpawnBot(SpawnRequest const& request)
Spawns a single bot based on a spawn request.
Parameters:
request- Spawn request containing zone, level, class requirements
Returns: true if spawn initiated successfully
Thread Safety: Thread-safe with internal mutex protection
Example:
SpawnRequest request;
request.type = SpawnRequest::SPECIFIC_ZONE;
request.zoneId = 12; // Elwynn Forest
request.minLevel = 1;
request.maxLevel = 10;
if (sBotSpawner->SpawnBot(request)) {
TC_LOG_INFO("module.playerbot", "Bot spawn request submitted");
}
Spawn Request Types:
enum SpawnRequestType {
RANDOM, // Spawn random bot in any zone
SPECIFIC_ZONE, // Spawn in specific zone
SPECIFIC_MAP, // Spawn in specific map
FOLLOW_PLAYER // Spawn near player for following
};
SpawnBots(std::vector<SpawnRequest> const& requests)
uint32 BotSpawner::SpawnBots(std::vector<SpawnRequest> const& requests)
Batch spawn multiple bots for better performance.
Parameters:
requests- Vector of spawn requests
Returns: Number of successfully queued requests
Performance: Optimized for batch processing with configurable batch size (default: 10 bots/batch)
Example:
std::vector<SpawnRequest> batch;
for (uint32 i = 0; i < 50; ++i) {
SpawnRequest req;
req.type = SpawnRequest::RANDOM;
batch.push_back(req);
}
uint32 queued = sBotSpawner->SpawnBots(batch);
TC_LOG_INFO("module.playerbot", "Queued {} bot spawn requests", queued);
DespawnBot(ObjectGuid guid, bool forced = false)
void BotSpawner::DespawnBot(ObjectGuid guid, bool forced = false)
Despawns a specific bot.
Parameters:
guid- Character GUID of bot to despawnforced- If true, force immediate despawn regardless of state
Thread Safety: Thread-safe
Example:
ObjectGuid botGuid = ...; // Get from player
sBotSpawner->DespawnBot(botGuid, false);
GetActiveBotCount()
uint32 BotSpawner::GetActiveBotCount() const
Returns the total number of active bots.
Returns: Number of currently active bots
Performance: Lock-free atomic operation - safe to call frequently
Example:
uint32 activeBots = sBotSpawner->GetActiveBotCount();
TC_LOG_INFO("module.playerbot", "Currently {} bots active", activeBots);
CreateAndSpawnBot()
bool BotSpawner::CreateAndSpawnBot(
uint32 masterAccountId,
uint8 classId,
uint8 race,
uint8 gender,
std::string const& name,
ObjectGuid& outCharacterGuid)
Creates a new bot character and spawns it immediately.
Parameters:
masterAccountId- Owner account IDclassId- Character class (1-13)race- Character racegender- Character gender (0=male, 1=female)name- Character nameoutCharacterGuid- Output parameter for created character GUID
Returns: true on success, false on failure
Used By: .bot spawn command
Example:
ObjectGuid characterGuid;
if (sBotSpawner->CreateAndSpawnBot(
accountId,
CLASS_WARRIOR,
RACE_HUMAN,
GENDER_MALE,
"BotWarrior",
characterGuid))
{
TC_LOG_INFO("module.playerbot", "Created and spawned bot: {}", characterGuid.ToString());
}
GetStats()
SpawnStats const& BotSpawner::GetStats() const
Retrieves spawn statistics for monitoring.
Returns: Reference to spawn statistics structure
Statistics Available:
struct SpawnStats {
std::atomic<uint32> totalSpawned; // Total bots spawned
std::atomic<uint32> totalDespawned; // Total bots despawned
std::atomic<uint32> currentlyActive; // Currently active
std::atomic<uint32> peakConcurrent; // Peak concurrent count
std::atomic<uint32> failedSpawns; // Failed spawn attempts
std::atomic<uint64> totalSpawnTime; // Total spawn time (µs)
std::atomic<uint32> spawnAttempts; // Total attempts
float GetAverageSpawnTime() const; // Average time in ms
float GetSuccessRate() const; // Success rate %
};
Example:
SpawnStats const& stats = sBotSpawner->GetStats();
TC_LOG_INFO("module.playerbot", "Bot Statistics:");
TC_LOG_INFO("module.playerbot", " Total Spawned: {}", stats.totalSpawned.load());
TC_LOG_INFO("module.playerbot", " Currently Active: {}", stats.currentlyActive.load());
TC_LOG_INFO("module.playerbot", " Success Rate: {:.2f}%", stats.GetSuccessRate());
TC_LOG_INFO("module.playerbot", " Avg Spawn Time: {:.2f}ms", stats.GetAverageSpawnTime());
Configuration
struct SpawnConfig {
uint32 maxBotsTotal = 500; // Global bot limit
uint32 maxBotsPerZone = 50; // Per-zone limit
uint32 maxBotsPerMap = 200; // Per-map limit
uint32 spawnBatchSize = 10; // Batch processing size
uint32 spawnDelayMs = 100; // Delay between batches
bool enableDynamicSpawning = true; // Auto-spawn based on players
bool respectPopulationCaps = true; // Enforce limits
float botToPlayerRatio = 2.0f; // Bots per player
};
Access:
SpawnConfig const& config = sBotSpawner->GetConfig();
Modify:
sBotSpawner->SetMaxBots(1000);
sBotSpawner->SetBotToPlayerRatio(3.0f);
BotSession
File: src/modules/Playerbot/Session/BotSession.h
Inherits: WorldSession
Represents a bot's world session without network socket.
Core Methods
Create(uint32 bnetAccountId)
static std::shared_ptr<BotSession> BotSession::Create(uint32 bnetAccountId)
Factory method to create a bot session.
Parameters:
bnetAccountId- Battle.net account ID
Returns: Shared pointer to created session
Thread Safety: Thread-safe
Example:
auto session = BotSession::Create(accountId);
if (!session) {
TC_LOG_ERROR("module.playerbot", "Failed to create bot session");
return;
}
LoginCharacter(ObjectGuid characterGuid)
bool BotSession::LoginCharacter(ObjectGuid characterGuid)
Asynchronously loads and logs in a bot character.
Parameters:
characterGuid- Character GUID to login
Returns: true if login initiated successfully
Async: Uses TrinityCore's async query holder pattern
Example:
if (botSession->LoginCharacter(characterGuid)) {
TC_LOG_INFO("module.playerbot", "Bot login initiated for {}", characterGuid.ToString());
// Login completes asynchronously via HandleBotPlayerLogin callback
}
Update(uint32 diff, PacketFilter& updater)
bool BotSession::Update(uint32 diff, PacketFilter& updater)
Updates bot session (called every frame).
Parameters:
diff- Time since last update (milliseconds)updater- Packet filter for processing
Returns: true if session is still active
Called By: BotWorldSessionMgr::Update()
Performance: Includes comprehensive memory safety checks
GetAI()
BotAI* BotSession::GetAI() const
Retrieves the bot's AI controller.
Returns: Pointer to BotAI or nullptr
Example:
if (BotAI* ai = botSession->GetAI()) {
ai->SetAIState(BotAIState::COMBAT);
}
SendPacket(WorldPacket const* packet, bool forced = false)
void BotSession::SendPacket(WorldPacket const* packet, bool forced = false) override
Sends a packet to the bot (stored in queue, no network).
Parameters:
packet- Packet to sendforced- Ignored for bots (no network)
Special Handling: Intercepts SMSG_PARTY_INVITE for automatic group joining
Example:
WorldPacket packet(SMSG_PARTY_INVITE);
// ... build packet
botSession->SendPacket(&packet);
Login State Management
enum class LoginState : uint8 {
NONE, // Not logging in
LOGIN_IN_PROGRESS, // Async login in progress
LOGIN_COMPLETE, // Login successful
LOGIN_FAILED // Login failed
};
State Queries:
LoginState state = botSession->GetLoginState();
bool loggedIn = botSession->IsLoginComplete();
bool failed = botSession->IsLoginFailed();
BotAI
File: src/modules/Playerbot/AI/BotAI.h
Factory: sBotAIFactory->CreateAI(Player* bot)
Base AI controller for all bots with strategy-based behavior system.
Core Methods
UpdateAI(uint32 diff)
virtual void BotAI::UpdateAI(uint32 diff)
Main update method - SINGLE entry point for all AI updates.
Parameters:
diff- Time since last update (milliseconds)
Update Flow:
- Update core behaviors (strategies, movement, idle)
- Check combat state transitions
- If in combat, call
OnCombatUpdate()for class-specific logic
Performance: Runs every frame - no throttling for smooth movement
Override: Do NOT override - use OnCombatUpdate() instead
OnCombatUpdate(uint32 diff)
virtual void BotAI::OnCombatUpdate(uint32 diff)
Virtual method for class-specific COMBAT ONLY updates.
Parameters:
diff- Time since last update (milliseconds)
Called When: Bot is in combat state
Override: ClassAI implementations should override for combat rotations
Must Not:
- Control movement (handled by strategies)
- Throttle updates (causes following issues)
- Call base UpdateAI (would cause recursion)
Example (in ClassAI):
void WarriorAI::OnCombatUpdate(uint32 diff) {
Unit* target = GetTargetUnit();
if (!target)
return;
// Execute rotation
UpdateRotation(target);
// Update cooldowns
UpdateCooldowns(diff);
}
Strategy Management
AddStrategy(std::unique_ptr<Strategy> strategy)
void BotAI::AddStrategy(std::unique_ptr<Strategy> strategy)
Registers a new strategy with the AI.
Parameters:
strategy- Unique pointer to strategy (ownership transferred)
Example:
auto followStrategy = std::make_unique<LeaderFollowBehavior>();
botAI->AddStrategy(std::move(followStrategy));
ActivateStrategy(std::string const& name)
void BotAI::ActivateStrategy(std::string const& name)
Activates a registered strategy.
Parameters:
name- Strategy name
Thread Safety: Thread-safe with mutex
Example:
botAI->ActivateStrategy("follow");
DeactivateStrategy(std::string const& name)
void BotAI::DeactivateStrategy(std::string const& name)
Deactivates an active strategy.
Parameters:
name- Strategy name
Example:
botAI->DeactivateStrategy("follow");
Group Management
OnGroupJoined(Group* group)
void BotAI::OnGroupJoined(Group* group)
Called when bot joins a group.
Parameters:
group- Group joined
Actions:
- Activates "follow" strategy
- Activates "group_combat" strategy
- Sets AI state to FOLLOWING
Example:
if (Group* group = bot->GetGroup()) {
botAI->OnGroupJoined(group);
}
OnGroupLeft()
void BotAI::OnGroupLeft()
Called when bot leaves a group.
Actions:
- Deactivates "follow" strategy
- Deactivates "group_combat" strategy
- Sets AI state to IDLE
State Management
GetAIState()
BotAIState BotAI::GetAIState() const
Returns current AI state.
AI States:
enum class BotAIState {
IDLE, // Doing nothing
COMBAT, // In combat
DEAD, // Dead
TRAVELLING, // Moving to destination
QUESTING, // Doing quests
GATHERING, // Gathering resources
TRADING, // At vendor/trading
FOLLOWING, // Following group leader
FLEEING, // Running away
RESTING // Resting for health/mana
};
SetAIState(BotAIState state)
void BotAI::SetAIState(BotAIState state)
Sets AI state with logging.
Parameters:
state- New AI state
Action System
QueueAction(std::shared_ptr<Action> action, ActionContext const& context)
void BotAI::QueueAction(std::shared_ptr<Action> action, ActionContext const& context = {})
Queues an action for execution.
Parameters:
action- Shared pointer to actioncontext- Optional action context
Example:
auto healAction = std::make_shared<HealAction>(targetGuid, spellId);
botAI->QueueAction(healAction);
CancelCurrentAction()
void BotAI::CancelCurrentAction()
Cancels currently executing action.
Performance Metrics
struct PerformanceMetrics {
std::atomic<uint32> totalUpdates;
std::atomic<uint32> actionsExecuted;
std::atomic<uint32> triggersProcessed;
std::atomic<uint32> strategiesEvaluated;
std::chrono::microseconds averageUpdateTime;
std::chrono::microseconds maxUpdateTime;
std::chrono::steady_clock::time_point lastUpdate;
};
Access:
PerformanceMetrics const& metrics = botAI->GetPerformanceMetrics();
TC_LOG_INFO("module.playerbot", "AI Performance:");
TC_LOG_INFO("module.playerbot", " Total Updates: {}", metrics.totalUpdates.load());
TC_LOG_INFO("module.playerbot", " Avg Update Time: {}µs", metrics.averageUpdateTime.count());
ClassAI
File: src/modules/Playerbot/AI/ClassAI/ClassAI.h
Inherits: BotAI
Factory: ClassAIFactory::CreateClassAI(Player* bot)
Base class for class-specific combat AI implementations.
Design Principles
- Combat Only: ClassAI handles ONLY combat specialization
- No Base Override: Never override
UpdateAI()- useOnCombatUpdate() - No Movement Control: Let BotAI strategies handle movement
- No Throttling: Don't throttle updates - causes following issues
Pure Virtual Methods
UpdateRotation(Unit* target)
virtual void ClassAI::UpdateRotation(::Unit* target) = 0
Executes class-specific combat rotation.
Parameters:
target- Current combat target
Must Implement: All derived ClassAI classes
Example (Warrior):
void WarriorAI::UpdateRotation(Unit* target) {
// Execute warrior rotation
if (CanUseAbility(SPELL_MORTAL_STRIKE) && IsSpellReady(SPELL_MORTAL_STRIKE)) {
CastSpell(target, SPELL_MORTAL_STRIKE);
return;
}
if (GetBot()->GetRage() > 30 && CanUseAbility(SPELL_HEROIC_STRIKE)) {
CastSpell(target, SPELL_HEROIC_STRIKE);
}
}
UpdateBuffs()
virtual void ClassAI::UpdateBuffs() = 0
Applies class-specific buffs.
Called: When not in combat or between combats
Example (Paladin):
void PaladinAI::UpdateBuffs() {
// Maintain seal
if (!HasAura(SPELL_SEAL_OF_RIGHTEOUSNESS)) {
CastSpell(SPELL_SEAL_OF_RIGHTEOUSNESS);
}
// Apply blessing
if (Group* group = GetBot()->GetGroup()) {
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) {
Player* member = ref->GetSource();
if (member && !HasAura(SPELL_BLESSING_OF_KINGS, member)) {
CastSpell(member, SPELL_BLESSING_OF_KINGS);
}
}
}
}
HasEnoughResource(uint32 spellId)
virtual bool ClassAI::HasEnoughResource(uint32 spellId) = 0
Checks if bot has sufficient resources for a spell.
Parameters:
spellId- Spell to check
Returns: true if sufficient resources
GetOptimalRange(Unit* target)
virtual float ClassAI::GetOptimalRange(::Unit* target) = 0
Returns optimal combat range for the class.
Parameters:
target- Combat target
Returns: Preferred combat range in yards
Example:
float MageAI::GetOptimalRange(Unit* target) {
return 30.0f; // Ranged caster - maintain distance
}
float RogueAI::GetOptimalRange(Unit* target) {
return 5.0f; // Melee - close combat
}
Utility Methods
Spell Casting
bool CastSpell(::Unit* target, uint32 spellId); // Cast on target
bool CastSpell(uint32 spellId); // Self-cast
bool IsSpellReady(uint32 spellId); // Check cooldown
bool IsInRange(::Unit* target, uint32 spellId); // Check range
bool IsSpellUsable(uint32 spellId); // Check usability
uint32 GetSpellCooldown(uint32 spellId); // Get remaining CD
Example:
if (IsSpellReady(SPELL_FIREBALL) && IsInRange(target, SPELL_FIREBALL)) {
if (CastSpell(target, SPELL_FIREBALL)) {
TC_LOG_DEBUG("module.playerbot", "Cast Fireball on {}", target->GetName());
}
}
Target Selection
::Unit* GetBestAttackTarget(); // Best DPS target
::Unit* GetBestHealTarget(); // Lowest health ally
::Unit* GetNearestEnemy(float maxRange = 30.0f); // Nearest enemy
::Unit* GetLowestHealthAlly(float maxRange = 40.0f); // For healing
Example:
Unit* healTarget = GetBestHealTarget();
if (healTarget && healTarget->GetHealthPct() < 50.0f) {
CastSpell(healTarget, SPELL_HEAL);
}
Aura Management
bool HasAura(uint32 spellId, ::Unit* target = nullptr);
uint32 GetAuraStacks(uint32 spellId, ::Unit* target = nullptr);
uint32 GetAuraRemainingTime(uint32 spellId, ::Unit* target = nullptr);
Example:
if (HasAura(SPELL_BLOODLUST)) {
// Execute burst rotation
}
uint32 stacks = GetAuraStacks(SPELL_SUNDER_ARMOR, target);
if (stacks < 5) {
CastSpell(target, SPELL_SUNDER_ARMOR);
}
Subsystems
Group Coordination
File: src/modules/Playerbot/Group/GroupInvitationHandler.h
GroupInvitationHandler
Handles automatic group invitation acceptance for bots.
class GroupInvitationHandler {
public:
bool HandleInvitation(WorldPackets::Party::PartyInvite const& invite);
void Update(uint32 diff);
void ProcessPendingInvitations();
};
Usage:
if (BotAI* ai = botSession->GetAI()) {
GroupInvitationHandler* handler = ai->GetGroupInvitationHandler();
handler->Update(diff);
}
Movement & Positioning
File: src/modules/Playerbot/Movement/LeaderFollowBehavior.h
LeaderFollowBehavior
Strategy for following group leader.
class LeaderFollowBehavior : public Strategy {
public:
void UpdateFollowBehavior(BotAI* ai, uint32 diff);
float GetFollowDistance() const;
void SetFollowDistance(float distance);
};
Default Distances:
- Melee: 5 yards
- Ranged: 15 yards
- Healers: 20 yards
Usage:
auto* followStrategy = botAI->GetStrategy("follow");
if (auto* followBehavior = dynamic_cast<LeaderFollowBehavior*>(followStrategy)) {
followBehavior->SetFollowDistance(10.0f);
}
Combat Mechanics
File: src/modules/Playerbot/AI/Combat/InterruptCoordinator.h
InterruptCoordinator
Coordinates spell interrupts across multiple bots to prevent overlap.
class InterruptCoordinator {
public:
bool RegisterInterrupt(ObjectGuid botGuid, ObjectGuid targetGuid, uint32 spellId);
bool CanInterrupt(ObjectGuid botGuid, ObjectGuid targetGuid);
void ClearInterrupts(ObjectGuid targetGuid);
};
Usage:
if (sInterruptCoordinator->CanInterrupt(bot->GetGUID(), target->GetGUID())) {
CastSpell(target, SPELL_KICK);
sInterruptCoordinator->RegisterInterrupt(bot->GetGUID(), target->GetGUID(), SPELL_KICK);
}
Database Integration
File: src/modules/Playerbot/Database/PlayerbotCharacterDBInterface.h
PlayerbotCharacterDBInterface
Provides safe async/sync database access routing.
class PlayerbotCharacterDBInterface {
public:
PreparedQueryResult ExecuteSync(CharacterDatabasePreparedStatement* stmt);
void ExecuteAsync(CharacterDatabasePreparedStatement* stmt, std::function<void(PreparedQueryResult)> callback);
CharacterDatabaseTransaction BeginTransaction();
void CommitTransaction(CharacterDatabaseTransaction transaction);
};
Singleton: sPlayerbotCharDB
Example:
CharacterDatabasePreparedStatement* stmt = sPlayerbotCharDB->GetPreparedStatement(CHAR_SEL_CHARACTER);
stmt->setUInt64(0, characterGuid.GetCounter());
sPlayerbotCharDB->ExecuteAsync(stmt, [](PreparedQueryResult result) {
if (result) {
// Process result
}
});
Performance Monitoring
File: src/modules/Playerbot/Performance/BotPerformanceMonitor.h
BotPerformanceMonitor
Monitors bot performance metrics.
class BotPerformanceMonitor {
public:
void RecordBotUpdate(ObjectGuid botGuid, uint32 updateTimeMs);
void RecordMemoryUsage(ObjectGuid botGuid, uint64 memoryBytes);
PerformanceReport GenerateReport();
};
Metrics Tracked:
- Update time per bot
- Memory usage per bot
- CPU usage estimation
- Database query performance
- AI decision time
Example:
auto report = sBotPerformanceMonitor->GenerateReport();
TC_LOG_INFO("module.playerbot", "Performance Report:");
TC_LOG_INFO("module.playerbot", " Average Update Time: {:.2f}ms", report.avgUpdateTime);
TC_LOG_INFO("module.playerbot", " Total Memory: {} MB", report.totalMemoryMB);
Configuration
File: playerbots.conf
C++ API: src/modules/Playerbot/Config/PlayerbotConfig.h
Configuration Access
bool enabled = sPlayerbotConfig->GetBool("Playerbot.Enable", false);
uint32 maxBots = sPlayerbotConfig->GetUInt("Playerbot.MaxBotsPerAccount", 10);
float ratio = sPlayerbotConfig->GetFloat("Playerbot.BotToPlayerRatio", 2.0f);
std::string logFile = sPlayerbotConfig->GetString("Playerbot.Log.File", "Playerbot.log");
Key Configuration Options
# Core Settings
Playerbot.Enable = 1
Playerbot.MaxBotsPerAccount = 10
Playerbot.GlobalMaxBots = 1000
# Performance
Playerbot.UpdateInterval = 100
Playerbot.AIDecisionTimeLimit = 50
Playerbot.SpawnBatchSize = 10
# Database
Playerbot.Database.Timeout = 30
Playerbot.Database.EnablePooling = 1
# Logging
Playerbot.Log.Level = 4
Playerbot.Log.File = "Playerbot.log"
Performance Cache
Frequently accessed config values are cached for performance:
template<typename T>
T GetCached(std::string const& key, T defaultValue) const;
Example:
// Fast cached access - no mutex lock
uint32 maxBots = sPlayerbotConfig->GetCached<uint32>("Playerbot.MaxBotsPerAccount", 10);
Extension Points
Creating Custom Strategies
File: src/modules/Playerbot/AI/Strategy/Strategy.h
class MyCustomStrategy : public Strategy {
public:
std::string GetName() const override { return "my_custom"; }
bool IsActive(BotAI const* ai) const override {
// Determine if strategy should be active
return true;
}
void UpdateBehavior(BotAI* ai, uint32 diff) override {
// Implement custom behavior
}
void OnActivate(BotAI* ai) override {
TC_LOG_INFO("module.playerbot", "Custom strategy activated");
}
void OnDeactivate(BotAI* ai) override {
TC_LOG_INFO("module.playerbot", "Custom strategy deactivated");
}
};
// Register and use
auto customStrategy = std::make_unique<MyCustomStrategy>();
botAI->AddStrategy(std::move(customStrategy));
botAI->ActivateStrategy("my_custom");
Creating Custom Actions
File: src/modules/Playerbot/AI/Actions/Action.h
class MyCustomAction : public Action {
public:
bool IsPossible(BotAI* ai) override {
// Check if action can be executed
return true;
}
bool IsUseful(BotAI* ai) override {
// Check if action should be executed
return true;
}
ActionResult Execute(BotAI* ai, ActionContext const& context) override {
// Execute action logic
TC_LOG_INFO("module.playerbot", "Executing custom action");
return ActionResult::SUCCESS;
}
};
// Queue action
auto action = std::make_shared<MyCustomAction>();
botAI->QueueAction(action);
Creating Custom Triggers
File: src/modules/Playerbot/AI/Triggers/Trigger.h
class MyCustomTrigger : public Trigger {
public:
bool Check(BotAI const* ai) override {
// Fast pre-check
return ai->GetBot()->GetHealthPct() < 50.0f;
}
TriggerResult Evaluate(BotAI* ai) override {
TriggerResult result;
result.triggered = true;
result.urgency = 100.0f;
result.suggestedAction = std::make_shared<MyCustomAction>();
return result;
}
};
// Register trigger
auto trigger = std::make_shared<MyCustomTrigger>();
botAI->RegisterTrigger(trigger);
Performance Considerations
Thread Safety
Thread-Safe Components:
- BotSpawner (internal mutex)
- BotSession (packet queue mutex)
- BotAI (strategy mutex)
Lock-Free Components:
GetActiveBotCount()(atomic)- Spawn statistics (atomic counters)
- Bot state tracking (atomic flags)
Memory Optimization
Target: <10MB per bot
Strategies:
- Object pooling for frequently created objects
- Shared spell info caching
- Lazy loading of AI components
- Smart pointer usage for RAII cleanup
Database Optimization
Async Pattern:
// GOOD - Async with callback
sPlayerbotCharDB->ExecuteAsync(stmt, [](PreparedQueryResult result) {
// Process result on callback thread
});
// BAD - Synchronous blocking
PreparedQueryResult result = CharacterDatabase.Query(stmt); // Blocks!
Connection Pooling:
- Dedicated connection pool for bot operations
- Configurable pool size
- Automatic connection recycling
Error Handling
Common Patterns
// Validate inputs
if (!bot || !bot->IsInWorld()) {
TC_LOG_ERROR("module.playerbot", "Invalid bot state");
return false;
}
// Handle async failures
sPlayerbotCharDB->ExecuteAsync(stmt, [this](PreparedQueryResult result) {
if (!result) {
TC_LOG_ERROR("module.playerbot", "Database query failed");
return;
}
// Process result
});
// Memory safety checks
if (!_active.load() || _destroyed.load()) {
return; // Session being destroyed
}
Logging Categories
TC_LOG_ERROR("module.playerbot.spawner", "Spawn failed");
TC_LOG_WARN("module.playerbot.session", "Session timeout");
TC_LOG_INFO("module.playerbot.ai", "AI state changed");
TC_LOG_DEBUG("module.playerbot.combat", "Spell cast: {}", spellId);
TC_LOG_TRACE("module.playerbot.movement", "Position updated");
Version History
Current: WoW 11.2 Compatible Last Updated: 2025-10-03 API Stability: Stable (production-ready)
For bug reports and feature requests, see project issue tracker.