Files
ThordekkCore/PLAYERBOT_ARCHITECTURE_DEEP_ANALYSIS.md
T

1215 lines
43 KiB
Markdown
Raw Normal View History

2026-01-20 21:33:16 -03:00
# Playerbot Module - Deep Architecture Analysis
## Comprehensive Codebase Inventory for Refactoring
**Date**: 2025-10-08
**Branch**: playerbot-dev
**Purpose**: Complete inventory of movement, group, and strategy systems for architectural refactoring
---
## EXECUTIVE SUMMARY
This document provides a comprehensive analysis of the existing Playerbot module architecture, identifying:
- **Movement conflicts**: 3 competing movement systems causing bot stuttering/blinking
- **Group management fragmentation**: 4 different systems handling group operations
- **Strategy overlaps**: 6 strategies with overlapping responsibilities
- **Dead/duplicate code**: ~15% of codebase is redundant or conflicting
### Critical Issues Identified
1. **Movement System Conflicts** (Issue #2, #3): LeaderFollowBehavior + CombatMovementStrategy + ClassAI all issuing movement commands simultaneously
2. **Group State Desync**: BotSession, GroupInvitationHandler, and BotAI all manage group state independently
3. **Strategy Priority Confusion**: BehaviorPriorityManager exists but not consistently used across all strategies
---
## 1. MOVEMENT SYSTEMS INVENTORY
### 1.1 LeaderFollowBehavior (PRIMARY FOLLOW SYSTEM)
**Location**: `C:\TrinityBots\TrinityCore\src\modules\Playerbot\Movement\LeaderFollowBehavior.cpp` (1,497 lines)
**What It Does**:
- Implements formation-based following of group leader
- Handles distance-based positioning (tight/normal/loose/formation modes)
- Manages teleportation when bot falls too far behind
- Uses MotionMaster::MoveFollow() for smooth tracking
**TrinityCore APIs Used**:
- `MotionMaster::MoveFollow(leader, distance, angle)` - Primary movement API
- `PathGenerator::CalculatePath()` - Pathfinding
- `Player::GetGroup()` - Group membership
- `Group::GetMembers()` - Direct group iteration (DEADLOCK FIX #21)
- `Player::NearTeleportTo()` - Teleportation
**Activation Trigger**:
- Active when bot is in a group AND not the leader
- `GetRelevance()` returns 100.0f when in group, 0.0f in combat (FIX FOR ISSUE #2 & #3)
**Issues Identified**:
- ✅ **GOOD**: Returns 0.0f relevance during combat to avoid movement conflicts
- ✅ **GOOD**: Uses MoveFollow() instead of re-issuing MovePoint every frame
- ⚠️ **OVERLAP**: Movement logic duplicates what CombatMovementStrategy does
- ❌ **BUG**: `UpdateBehavior()` called EVERY FRAME (no throttling) - performance concern
**Conflicts With**:
- CombatMovementStrategy (both control movement in combat)
- GroupCombatStrategy (both handle group positioning)
- ClassAI positioning (each tries to position bot independently)
**Recommendation**: **REFACTOR**
- Keep core follow logic, BUT:
- Add proper throttling (100ms update interval, not every frame)
- Remove combat logic (delegate to CombatMovementStrategy)
- Simplify to ONLY handle out-of-combat following
---
### 1.2 BotMovementUtil (CENTRALIZED MOVEMENT API)
**Location**: `C:\TrinityBots\TrinityCore\src\modules\Playerbot\Movement\BotMovementUtil.cpp` (172 lines)
**What It Does**:
- Provides centralized movement deduplication
- Prevents re-issuing movement commands every frame
- Wrapper around MotionMaster with intelligent caching
**TrinityCore APIs Used**:
- `MotionMaster::MovePoint(pointId, destination)`
- `MotionMaster::MoveChase(target, distance)`
- `MotionMaster::GetCurrentMovementGeneratorType()` - Check current movement state
- `Player::GetExactDist2d()` - Distance calculation
- `Player::StopMoving()` - Stop movement
**Key Methods**:
```cpp
bool MoveToPosition(Player* bot, Position const& destination, uint32 pointId, float minDistanceChange = 3.0f);
bool MoveToTarget(Player* bot, WorldObject* target, uint32 pointId, float minDistanceChange = 3.0f);
bool MoveToUnit(Player* bot, Unit* unit, float distance, uint32 pointId);
bool ChaseTarget(Player* bot, Unit* target, float distance);
void StopMovement(Player* bot);
bool IsMoving(Player* bot);
bool IsMovingToDestination(Player* bot, Position const& destination, float tolerance);
```
**Deduplication Logic**:
```cpp
// CRITICAL FIX: Only re-issue movement if destination changed significantly
if (mm->GetCurrentMovementGeneratorType(MOTION_SLOT_ACTIVE) == POINT_MOTION_TYPE)
{
float distToDestination = bot->GetExactDist2d(destination);
if (distToDestination > minDistanceChange)
mm->MovePoint(pointId, destination); // Different destination
else
return true; // Already moving to same destination - don't re-issue
}
```
**Issues Identified**:
- ✅ **EXCELLENT**: Solves the "re-issue every frame" problem that causes stuttering
- ✅ **GOOD**: Thread-safe, simple, well-documented
- ⚠️ **UNDERUTILIZED**: Only used by some systems (LeaderFollowBehavior uses it, but CombatMovementStrategy doesn't)
**Conflicts With**: None (this is a utility, not a system)
**Recommendation**: **KEEP + EXPAND**
- Make this the SINGLE entry point for ALL bot movement
- Enforce usage in LeaderFollowBehavior, CombatMovementStrategy, ClassAI, and GroupCombatStrategy
- Add movement priority system (combat > follow > idle)
---
### 1.3 CombatMovementStrategy (COMBAT POSITIONING)
**Location**: `C:\TrinityBots\TrinityCore\src\modules\Playerbot\AI\Strategy\CombatMovementStrategy.cpp` (734 lines)
**What It Does**:
- Handles role-based combat positioning (tank, melee, ranged, healer)
- Detects dangerous ground effects (AreaTriggers, DynamicObjects)
- Calculates optimal positioning based on class/role
- Manages danger avoidance
**TrinityCore APIs Used**:
- `MotionMaster::MovePoint(1, position)` - Direct point movement
- `PathGenerator::CalculatePath()` - Pathfinding validation
- `Player::IsWithinLOS()` - Line of sight checks
- `Map::GetHeight()` - Terrain validation
- `Cell::VisitGridObjects()` - Area trigger scanning
**Role-Based Positioning**:
```cpp
Position CalculateTankPosition() - Front of target, 3.0f
Position CalculateMeleePosition() - Behind target, 3.0f
Position CalculateRangedPosition() - 25yd from target
Position CalculateHealerPosition() - 20yd, central to group
```
**Activation Trigger**:
- Priority: 80 (higher than follow=60, lower than critical=90)
- `IsActive()`: Returns true when bot is in combat with a valid target
**Issues Identified**:
- ✅ **GOOD**: Danger detection (fire, poison pools, etc.)
- ✅ **GOOD**: Role-based positioning logic
- ❌ **CONFLICT**: Directly calls `MotionMaster::MovePoint()` instead of using BotMovementUtil
- ❌ **OVERLAP**: Doesn't check if LeaderFollowBehavior or ClassAI already issued movement
- ⚠️ **PERFORMANCE**: Scans for danger EVERY FRAME (500μs overhead)
**Conflicts With**:
- LeaderFollowBehavior (both issue movement commands)
- ClassAI (ClassAI also calculates optimal range)
- GroupCombatStrategy (both handle combat positioning)
**Recommendation**: **REFACTOR**
- Replace direct `MotionMaster::MovePoint()` calls with `BotMovementUtil::MoveToPosition()`
- Add danger detection caching (1s TTL instead of every frame)
- Delegate role-specific positioning to ClassAI
- This should be a COORDINATOR, not an EXECUTOR
---
### 1.4 GroupCombatStrategy (GROUP ASSIST)
**Location**: `C:\TrinityBots\TrinityCore\src\modules\Playerbot\AI\Strategy\GroupCombatStrategy.cpp` (272 lines)
**What It Does**:
- Detects when group members enter combat
- Automatically targets and assists attacking group members
- Issues MoveChase commands to move to target
**TrinityCore APIs Used**:
- `MotionMaster::MoveChase(target, optimalRange)` - Chase movement
- `Player::Attack(target, true)` - Initiate melee attack
- `Player::SetTarget()` - Set target
- `Group::GetMemberSlots()` - Iterate group members
- `ObjectAccessor::FindPlayer()` - Find group member by GUID
**Movement Logic**:
```cpp
// CRITICAL FIX: Only issue MoveChase if NOT already chasing
if (mm->GetCurrentMovementGeneratorType(MOTION_SLOT_ACTIVE) != CHASE_MOTION_TYPE)
{
mm->MoveChase(target, optimalRange);
}
```
**Activation Trigger**:
- Relevance: 80.0f when group is in combat but bot is NOT in combat
- Returns 0.0f when bot is already in combat (lets ClassAI handle it)
**Issues Identified**:
- ✅ **GOOD**: Only assists when bot NOT in combat (avoids double-handling)
- ✅ **GOOD**: Checks current movement type before re-issuing (deduplication)
- ❌ **OVERLAP**: Delegates positioning to ClassAI but also issues MoveChase directly
- ⚠️ **DESIGN**: Should this be part of LeaderFollowBehavior instead of separate strategy?
**Conflicts With**:
- LeaderFollowBehavior (follow might interrupt combat assist)
- CombatMovementStrategy (both position bot in combat)
**Recommendation**: **REFACTOR**
- Merge into CombatMovementStrategy as "group assist" mode
- Use BotMovementUtil instead of direct MotionMaster calls
- Remove movement logic (just set target, let CombatMovementStrategy handle positioning)
---
### 1.5 ClassAI Positioning (INDIVIDUAL CLASS LOGIC)
**Location**: Multiple files in `C:\TrinityBots\TrinityCore\src\modules\Playerbot\AI\ClassAI\`
**What It Does**:
- Each ClassAI implementation has `GetOptimalRange(Unit* target)` method
- Calculates class-specific combat range (melee: 5yd, ranged: 25yd, etc.)
- Some ClassAI implementations directly call movement APIs
**Example - HunterAI**:
```cpp
float GetOptimalRange(Unit* target) override
{
return 25.0f; // Hunters want max range
}
```
**TrinityCore APIs Used** (varies by class):
- `MotionMaster::MoveChase()`
- `MotionMaster::MovePoint()`
- Direct distance checks
**Issues Identified**:
- ✅ **GOOD**: Class-specific range knowledge is correctly placed in ClassAI
- ❌ **CONFLICT**: Some ClassAI directly issues movement, others delegate to strategies
- ❌ **INCONSISTENT**: HunterAI uses MoveChase, MageAI uses MovePoint, WarriorAI delegates
**Conflicts With**:
- CombatMovementStrategy (both calculate positioning)
- GroupCombatStrategy (both issue movement in combat)
**Recommendation**: **REFACTOR**
- ClassAI should ONLY provide `GetOptimalRange()` and `GetOptimalAngle()`
- ClassAI should NEVER directly call MotionMaster
- All movement execution should flow through BotMovementUtil
---
### 1.6 Movement System Architecture Summary
| System | Lines | Purpose | Movement API | Issues | Recommendation |
|--------|-------|---------|--------------|--------|----------------|
| LeaderFollowBehavior | 1,497 | Follow group leader | MoveFollow() | Every-frame updates, combat overlap | **REFACTOR** - Keep core, remove combat, add throttling |
| BotMovementUtil | 172 | Movement deduplication | Wrapper | Underutilized | **KEEP + EXPAND** - Make mandatory entry point |
| CombatMovementStrategy | 734 | Combat positioning | MovePoint() | Doesn't use BotMovementUtil | **REFACTOR** - Use BotMovementUtil, cache danger checks |
| GroupCombatStrategy | 272 | Group assist | MoveChase() | Overlaps with CombatMovementStrategy | **MERGE** - Fold into CombatMovementStrategy |
| ClassAI Positioning | Various | Class-specific ranges | Mixed | Inconsistent | **STANDARDIZE** - Only provide ranges, never execute movement |
**Total Lines of Movement Code**: ~2,675 lines
**Estimated Redundant Code**: ~40% (~1,070 lines can be eliminated)
---
## 2. GROUP MANAGEMENT INVENTORY
### 2.1 BotSession::HandleGroupInvitation()
**Location**: `C:\TrinityBots\TrinityCore\src\modules\Playerbot\Session\BotSession.cpp`
**What It Does**:
- Receives `CMSG_GROUP_INVITE` packets from TrinityCore
- Parses invitation data (inviter GUID, proposed roles)
- Delegates to GroupInvitationHandler
**TrinityCore APIs Used**:
- Packet handlers (CMSG_GROUP_INVITE, CMSG_GROUP_ACCEPT, CMSG_GROUP_DECLINE)
- `Player::GetGroupInvite()`
- `Group::AddMember()`
**Issues Identified**:
- ✅ **GOOD**: Proper packet handling integration
- ⚠️ **FRAGMENTATION**: Group state tracked in both BotSession and BotAI
**Recommendation**: **KEEP** - This is the correct packet entry point
---
### 2.2 GroupInvitationHandler
**Location**: `C:\TrinityBots\TrinityCore\src\modules\Playerbot\Group\GroupInvitationHandler.cpp`
**What It Does**:
- Manages group invitation queue
- Auto-accept logic with configurable delays
- Anti-spam protection (max invitations per minute)
- Invitation validation
**Key Methods**:
```cpp
bool HandleInvitation(WorldPackets::Party::PartyInvite const& packet);
void Update(uint32 diff); // Process pending invitations
bool ShouldAcceptInvitation(ObjectGuid inviterGuid) const;
void AcceptInvitation(ObjectGuid inviterGuid);
void DeclineInvitation(ObjectGuid inviterGuid, std::string reason);
```
**TrinityCore APIs Used**:
- `ObjectAccessor::FindPlayer()` - Validate inviter
- `Player::GetGroup()` - Check if already grouped
- `Player::GetGroupInvite()` - Check pending invites
- `Group::AddMember()` - Join group
**Issues Identified**:
- ✅ **GOOD**: Comprehensive invitation validation
- ✅ **GOOD**: Thread-safe queue with mutex protection
- ❌ **DEADLOCK RISK**: Removed `GetGroupInvite()` polling to avoid cross-system mutex deadlock (FIXED)
- ⚠️ **DISCONNECT**: Does NOT notify BotAI when group join succeeds
**Recommendation**: **KEEP + FIX**
- Add event notification to BotAI when group join succeeds
- Use EventDispatcher to broadcast GROUP_JOINED event
---
### 2.3 BotAI::OnGroupJoined()
**Location**: `C:\TrinityBots\TrinityCore\src\modules\Playerbot\AI\BotAI.cpp` (line 429)
**What It Does**:
- Activates LeaderFollowBehavior when bot joins group
- Activates GroupCombatStrategy for group assist
- Deactivates IdleStrategy
**Code**:
```cpp
void BotAI::OnGroupJoined(Group* group)
{
if (!group)
return;
TC_LOG_INFO("playerbot", "Bot {} joined group {}",
_bot->GetName(), group->GetGUID().ToString());
// Activate group strategies
ActivateStrategy("follow");
ActivateStrategy("group_combat");
DeactivateStrategy("idle");
}
```
**TrinityCore APIs Used**:
- Strategy activation/deactivation
**Issues Identified**:
- ❌ **NEVER CALLED**: GroupInvitationHandler doesn't call this method when group join succeeds
- ❌ **PERIODIC CHECK WORKAROUND**: BotAI::UpdateAI() has a 1s periodic check to detect group join (lines 216-242)
**Current Workaround** (BotAI.cpp:216-242):
```cpp
// CRITICAL FIX: Periodically check if bot joined a group but follow not active
static uint32 groupCheckTimer = 0;
groupCheckTimer += diff;
if (groupCheckTimer >= 1000) // Check every 1 second
{
Group* group = _bot->GetGroup();
Strategy* followStrat = GetStrategy("follow");
bool hasFollowStrategy = (followStrat && followStrat->IsActive(this));
if (group && !hasFollowStrategy)
{
// Bot is in a group but not following - activate group strategies
TC_LOG_INFO("module.playerbot.ai", "Bot {} detected in group without follow active - activating group strategies", _bot->GetName());
ActivateStrategy("follow");
ActivateStrategy("group_combat");
}
}
```
**Recommendation**: **FIX**
- GroupInvitationHandler should dispatch GROUP_JOINED event
- BotAI subscribes to GROUP_JOINED event and calls OnGroupJoined()
- Remove 1s periodic check workaround
---
### 2.4 BotAI::OnGroupLeft()
**Location**: Referenced but not fully implemented
**What It Does** (intended):
- Deactivate LeaderFollowBehavior when bot leaves group
- Deactivate GroupCombatStrategy
- Activate IdleStrategy
**Issues Identified**:
- ❌ **MISSING**: No event handler for group leave
- ❌ **WORKAROUND**: BotAI::UpdateAI() periodic check handles this (lines 235-241)
**Current Workaround** (BotAI.cpp:235-241):
```cpp
else if (!group && hasFollowStrategy)
{
// Bot left group but still has follow active - deactivate
TC_LOG_INFO("module.playerbot.ai", "Bot {} not in group but follow active - deactivating group strategies", _bot->GetName());
DeactivateStrategy("follow");
DeactivateStrategy("group_combat");
ActivateStrategy("idle");
}
```
**Recommendation**: **IMPLEMENT**
- Add GROUP_LEFT event to EventDispatcher
- BotAI subscribes to GROUP_LEFT and properly cleans up
---
### 2.5 Group Management Architecture Summary
| Component | Purpose | Issues | Recommendation |
|-----------|---------|--------|----------------|
| BotSession::HandleGroupInvitation | Packet entry point | ✅ Works correctly | **KEEP** |
| GroupInvitationHandler | Invitation management | ❌ Doesn't notify BotAI | **FIX** - Add event dispatch |
| BotAI::OnGroupJoined() | Activate group strategies | ❌ Never called directly | **FIX** - Subscribe to event |
| BotAI::OnGroupLeft() | Deactivate group strategies | ❌ Not implemented | **IMPLEMENT** |
| BotAI periodic check | Workaround for missing events | ⚠️ 1s polling lag | **REMOVE** after event system works |
**Root Cause**: No event-based communication between GroupInvitationHandler and BotAI
**Solution**: Use existing EventDispatcher to broadcast:
- `GROUP_JOINED` event when GroupInvitationHandler::AcceptInvitation() succeeds
- `GROUP_LEFT` event when bot leaves group
---
## 3. STRATEGY SYSTEM INVENTORY
### 3.1 Strategy Base Class
**Location**: `C:\TrinityBots\TrinityCore\src\modules\Playerbot\AI\Strategy\Strategy.h`
**Interface**:
```cpp
class Strategy
{
public:
virtual void InitializeActions() = 0;
virtual void InitializeTriggers() = 0;
virtual void InitializeValues() = 0;
// Strategy evaluation
virtual float GetRelevance(BotAI* ai) const;
virtual bool IsActive(BotAI* ai) const { return _active; }
// Activation lifecycle
virtual void OnActivate(BotAI* ai) {}
virtual void OnDeactivate(BotAI* ai) {}
// Every-frame update
virtual void UpdateBehavior(BotAI* ai, uint32 diff) {}
// Priority
uint32 GetPriority() const { return _priority; }
void SetPriority(uint32 priority) { _priority = priority; }
};
```
**Issues Identified**:
- ✅ **GOOD**: Clean interface with lifecycle hooks
- ✅ **GOOD**: Priority system exists
- ⚠️ **INCONSISTENT**: Not all strategies set priority correctly
- ⚠️ **UNDERUTILIZED**: `UpdateBehavior()` added recently but not all strategies use it
---
### 3.2 LeaderFollowBehavior (Strategy)
**Priority**: 200 (set in constructor)
**Relevance**:
- 100.0f when in group and not leader
- 0.0f when in combat (CRITICAL FIX for Issue #2 & #3)
- 0.0f when not in group
**UpdateBehavior()**: ✅ Implemented, calls `UpdateFollowBehavior()` every frame
**Responsibilities**:
- Formation-based following
- Distance management
- Teleportation
- Leader lost detection
**Issues**:
- Priority 200 is HIGHER than combat (should be lower)
- Returns 0 relevance in combat but priority 200 could still override
**Recommendation**: **REFACTOR**
- Change priority to 50 (below combat=100)
- Keep 0.0f relevance in combat as safety net
---
### 3.3 CombatMovementStrategy (Strategy)
**Priority**: 80 (set in constructor)
**Relevance**:
- 0.0f if bot not in combat
- 100.0f if bot in combat with valid target
**UpdateBehavior()**: ✅ Implemented, handles combat positioning every frame
**Responsibilities**:
- Role-based positioning
- Danger detection and avoidance
- Optimal combat range maintenance
**Issues**:
- Priority 80 is LOWER than LeaderFollowBehavior (200) - incorrect
- Should have priority 100 (exclusive combat control)
**Recommendation**: **REFACTOR**
- Change priority to 100
- Mark as exclusive (no other strategies run during combat)
---
### 3.4 GroupCombatStrategy (Strategy)
**Priority**: Not set (defaults to 100)
**Relevance**:
- 80.0f when group in combat but bot NOT in combat
- 0.0f when bot in combat
**UpdateBehavior()**: ✅ Implemented, handles group assist
**Responsibilities**:
- Detect group members in combat
- Assist by targeting same enemy
- Initiate combat when group fights
**Issues**:
- Overlaps with CombatMovementStrategy
- Should this be part of CombatMovementStrategy instead?
**Recommendation**: **MERGE**
- Fold group assist logic into CombatMovementStrategy
- Remove as separate strategy
---
### 3.5 IdleStrategy (Strategy)
**Priority**: 50 (set in constructor)
**Relevance**:
- Active when NOT in group
- Deactivated when group joined
**UpdateBehavior()**: ✅ Implemented, uses observer pattern to check managers
**Responsibilities**:
- Query manager states (quest, trade, gathering, auction)
- Fallback wandering behavior (not yet implemented)
**Issues**:
- ✅ **EXCELLENT**: Uses observer pattern correctly
- ✅ **GOOD**: Atomic state queries (<0.001ms per query)
**Recommendation**: **KEEP**
- This is a good reference implementation
---
### 3.6 BehaviorPriorityManager (Priority Coordinator)
**Location**: `C:\TrinityBots\TrinityCore\src\modules\Playerbot\AI\BehaviorPriorityManager.h`
**What It Does**:
- Registers strategies with priority levels
- Enforces mutual exclusion rules (combat excludes follow)
- Selects highest priority active strategy
**Priority Levels Defined**:
```cpp
enum class BehaviorPriority : uint8_t {
DEAD = 0,
ERROR = 5,
IDLE = 10,
SOCIAL = 20,
TRADING = 30,
GATHERING = 40,
MOVEMENT = 45,
FOLLOW = 50,
CASTING = 80,
FLEEING = 90,
COMBAT = 100, // Highest - exclusive control
};
```
**Key Methods**:
```cpp
void RegisterStrategy(Strategy* strategy, BehaviorPriority priority, bool exclusive = false);
Strategy* SelectActiveBehavior(std::vector<Strategy*>& activeStrategies);
bool CanCoexist(Strategy* a, Strategy* b) const;
void AddExclusionRule(BehaviorPriority a, BehaviorPriority b);
```
**Issues Identified**:
- ✅ **EXCELLENT**: Exactly what we need to solve conflicts
- ❌ **NOT ENFORCED**: Strategies still set their own priorities directly
- ❌ **UNDERUTILIZED**: BotAI doesn't always use BehaviorPriorityManager to select strategies
**Recommendation**: **ENFORCE**
- Make BehaviorPriorityManager the ONLY way to select active strategy
- Remove direct priority setting from strategies
- Enforce exclusion rules in UpdateStrategies()
---
### 3.7 Strategy System Summary
| Strategy | Current Priority | Correct Priority | Exclusive? | Issues | Recommendation |
|----------|------------------|------------------|------------|--------|----------------|
| LeaderFollowBehavior | 200 | 50 | No | Priority too high | **REFACTOR** - Lower priority, add throttling |
| CombatMovementStrategy | 80 | 100 | Yes | Priority too low | **REFACTOR** - Raise priority, mark exclusive |
| GroupCombatStrategy | 100 | N/A | No | Overlaps combat | **MERGE** into CombatMovementStrategy |
| IdleStrategy | 50 | 10 | No | None | **KEEP** - Good implementation |
| BehaviorPriorityManager | N/A | N/A | N/A | Not enforced | **ENFORCE** - Make mandatory |
**Root Cause**: Strategies set their own priorities independently, BehaviorPriorityManager exists but isn't enforced
---
## 4. EVENT SYSTEM INVENTORY
### 4.1 EventDispatcher
**Location**: `C:\TrinityBots\TrinityCore\src\modules\Playerbot\Core\Events\EventDispatcher.h`
**What It Does**:
- Centralized event routing between observers and managers
- Thread-safe concurrent queue
- Priority-based event ordering
- Subscription management
**Interface**:
```cpp
void Subscribe(StateMachine::EventType eventType, IManagerBase* manager);
void Unsubscribe(StateMachine::EventType eventType, IManagerBase* manager);
void Dispatch(BotEvent const& event);
uint32 ProcessQueue(uint32 maxEvents = 100);
```
**Current Subscribers**:
- QuestManager: 16 quest events
- TradeManager: 11 trade/gold events
- AuctionManager: 5 auction events
- GatheringManager: Not yet subscribed
**Missing Events**:
- ❌ GROUP_JOINED - Should be dispatched by GroupInvitationHandler
- ❌ GROUP_LEFT - Should be dispatched when bot leaves group
- ❌ COMBAT_STARTED - Should be dispatched when entering combat
- ❌ COMBAT_ENDED - Should be dispatched when exiting combat
**Recommendation**: **EXPAND**
- Add group event types to BotEventTypes.h
- Add combat event types
- GroupInvitationHandler should dispatch events
- CombatMovementStrategy should dispatch combat events
---
### 4.2 Manager Event Subscriptions
| Manager | Subscribed Events | Missing Events | Recommendation |
|---------|-------------------|----------------|----------------|
| QuestManager | ✅ 16 quest events | None | Good |
| TradeManager | ✅ 11 trade events | None | Good |
| AuctionManager | ✅ 5 auction events | None | Good |
| GatheringManager | ❌ None | RESOURCE_DETECTED, GATHERING_STARTED | **FIX** - Subscribe to gathering events |
| GroupInvitationHandler | ❌ None | Should DISPATCH events | **FIX** - Dispatch GROUP_JOINED/LEFT |
---
## 5. CODE TO KEEP vs REMOVE vs REFACTOR
### 5.1 KEEP (Well-Designed Systems)
#### ✅ BotMovementUtil (172 lines)
- **Why**: Solves movement deduplication perfectly
- **Action**: Make this the ONLY movement entry point
- **Expand**: Add priority system (combat > follow > idle)
#### ✅ IdleStrategy (136 lines)
- **Why**: Excellent observer pattern implementation
- **Action**: Use as reference for other strategies
- **Expand**: Implement wandering behavior
#### ✅ EventDispatcher (full system)
- **Why**: Clean, thread-safe, high-performance
- **Action**: Expand event types (group, combat)
- **Integrate**: Use for group join/leave notifications
#### ✅ BehaviorPriorityManager (264 lines header)
- **Why**: Exactly what we need to solve conflicts
- **Action**: **ENFORCE** usage across all strategies
- **Fix**: Make it the mandatory strategy selector
#### ✅ GroupInvitationHandler (core logic)
- **Why**: Comprehensive invitation validation
- **Action**: Keep logic, add event dispatching
- **Fix**: Notify BotAI when group join succeeds
---
### 5.2 REFACTOR (Good Ideas, Poor Implementation)
#### ⚠️ LeaderFollowBehavior (1,497 lines → ~800 lines)
**Issues**:
- Every-frame updates (no throttling)
- Priority 200 (too high)
- Combat overlap (fixed but architecture still wrong)
**Refactoring Plan**:
```cpp
// BEFORE: Called every frame
void UpdateBehavior(BotAI* ai, uint32 diff)
{
// 1,497 lines of complex logic
}
// AFTER: Throttled updates
void UpdateBehavior(BotAI* ai, uint32 diff)
{
_updateTimer += diff;
if (_updateTimer < 100) // 10 Hz update rate
return;
_updateTimer = 0;
// Simplified logic (~800 lines):
// 1. Calculate follow position
// 2. Call BotMovementUtil::MoveToPosition()
// 3. Done
}
```
**Keep**:
- Formation calculation logic
- Role-based positioning
- Teleportation logic
**Remove**:
- Direct MotionMaster calls → Replace with BotMovementUtil
- Every-frame updates → Add throttling
- Combat positioning → Delegate to CombatMovementStrategy
**Estimated Reduction**: 1,497 → ~800 lines (47% reduction)
---
#### ⚠️ CombatMovementStrategy (734 lines → ~400 lines)
**Issues**:
- Priority 80 (should be 100)
- Doesn't use BotMovementUtil
- Danger detection every frame (expensive)
**Refactoring Plan**:
```cpp
// BEFORE: Direct MotionMaster calls
void MoveToPosition(Player* player, Position const& position)
{
player->GetMotionMaster()->Clear();
player->GetMotionMaster()->MovePoint(1, position);
}
// AFTER: Use BotMovementUtil
void MoveToPosition(Player* player, Position const& position)
{
BotMovementUtil::MoveToPosition(player, position, 1);
}
```
**Keep**:
- Role-based positioning algorithms
- Danger detection logic
- LOS checks
**Remove**:
- Direct MotionMaster calls → Replace with BotMovementUtil
- Every-frame danger checks → Cache for 1s
**Add**:
- Group assist logic from GroupCombatStrategy
**Estimated Reduction**: 734 → ~400 lines (45% reduction)
---
#### ⚠️ GroupCombatStrategy (272 lines → REMOVE, merge into CombatMovementStrategy)
**Why Remove**:
- 90% overlap with CombatMovementStrategy
- Both handle combat positioning
- Both issue movement commands
**Migration Plan**:
```cpp
// MOVE this logic INTO CombatMovementStrategy::UpdateBehavior()
bool IsGroupInCombat(BotAI* ai); // Move to CombatMovementStrategy
Unit* GetGroupTarget(BotAI* ai); // Move to CombatMovementStrategy
```
**Estimated Reduction**: 272 lines eliminated
---
#### ⚠️ BotAI::UpdateAI() periodic group check (27 lines → REMOVE)
**Why Remove**:
- Workaround for missing event system
- 1s polling lag
- Inefficient
**Replace With**:
```cpp
// BotAI constructor
void BotAI::BotAI(Player* bot)
{
_eventDispatcher->Subscribe(EventType::GROUP_JOINED, this);
_eventDispatcher->Subscribe(EventType::GROUP_LEFT, this);
}
// Event handler
void BotAI::OnEvent(BotEvent const& event)
{
switch (event.type)
{
case EventType::GROUP_JOINED:
OnGroupJoined(event.group);
break;
case EventType::GROUP_LEFT:
OnGroupLeft();
break;
}
}
```
**Estimated Reduction**: 27 lines eliminated
---
### 5.3 REMOVE (Dead/Duplicate Code)
#### ❌ Duplicate ClassAI Movement Code (~200 lines across multiple files)
**Files Affected**:
- HunterAI.cpp, MageAI.cpp, WarriorAI.cpp, PriestAI.cpp, etc.
**Issue**: Each ClassAI has its own movement logic instead of delegating
**Example - HunterAI.cpp**:
```cpp
// REMOVE THIS:
if (distance > 25.0f)
{
bot->GetMotionMaster()->MoveChase(target, 25.0f);
}
// ClassAI should ONLY provide this:
float GetOptimalRange(Unit* target) override
{
return 25.0f; // Let CombatMovementStrategy handle actual movement
}
```
**Estimated Reduction**: ~200 lines across all ClassAI files
---
#### ❌ BotSession Group State Tracking (~50 lines)
**Location**: BotSession.cpp
**Issue**: Tracks group state redundantly (BotAI also tracks it)
**Solution**: Remove BotSession group state, use events instead
---
#### ❌ Unused/Dead Event Types (~30 lines)
**Location**: BotEventTypes.h
**Issue**: Many event types defined but never dispatched
**Solution**: Audit and remove unused event types
---
### 5.4 Code Reduction Summary
| Component | Current Lines | After Refactor | Reduction | Status |
|-----------|---------------|----------------|-----------|--------|
| LeaderFollowBehavior | 1,497 | 800 | 697 (47%) | REFACTOR |
| CombatMovementStrategy | 734 | 400 | 334 (45%) | REFACTOR |
| GroupCombatStrategy | 272 | 0 | 272 (100%) | REMOVE - merge into Combat |
| BotMovementUtil | 172 | 250 | +78 (expansion) | EXPAND |
| BotAI periodic checks | 27 | 0 | 27 (100%) | REMOVE - use events |
| ClassAI movement duplication | ~200 | 0 | 200 (100%) | REMOVE |
| BotSession group tracking | ~50 | 0 | 50 (100%) | REMOVE |
| **TOTAL** | **~2,952** | **~1,450** | **~1,502 (51%)** | - |
**Result**: ~51% reduction in movement/group code while IMPROVING functionality
---
## 6. RECOMMENDED ARCHITECTURE
### 6.1 Movement System (SIMPLIFIED)
```
┌─────────────────────────────────────────────────────┐
│ BotAI::UpdateAI() │
│ (Single entry point, every frame) │
└─────────────────────┬───────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ BehaviorPriorityManager::SelectActive() │
│ (Selects ONE strategy based on priority/exclusion) │
└─────────────────────┬───────────────────────────────┘
│
┌─────────────┼─────────────┬─────────────────┐
▼ ▼ ▼ ▼
┌────────────┐ ┌──────────┐ ┌───────────┐ ┌────────────┐
│ Combat │ │ Follow │ │ Idle │ │ Casting │
│ Movement │ │ Behavior │ │ Strategy │ │ Strategy │
│ (P=100) │ │ (P=50) │ │ (P=10) │ │ (P=80) │
└──────┬─────┘ └────┬─────┘ └─────┬─────┘ └──────┬─────┘
│ │ │ │
│ All movement execution flows through: │
│ │ │ │
└────────────┴──────────────┴─────────────────┘
│
▼
┌────────────────────────────┐
│ BotMovementUtil │
│ (SINGLE movement entry │
│ point with deduplication)│
└─────────────┬──────────────┘
│
▼
┌────────────────┐
│ MotionMaster │
│ (TrinityCore) │
└────────────────┘
```
**Key Principles**:
1. **ONE** entry point: BotMovementUtil
2. **ONE** active strategy at a time (selected by priority)
3. **ZERO** direct MotionMaster calls from strategies
4. **Exclusion rules**: Combat excludes Follow
---
### 6.2 Group Management (EVENT-DRIVEN)
```
┌──────────────────────────────────────────────────────┐
│ TrinityCore Packet System │
│ CMSG_GROUP_INVITE │
└────────────────────┬─────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────┐
│ BotSession::HandleGroupInvitation() │
│ (Packet handler - receives invites) │
└────────────────────┬─────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────┐
│ GroupInvitationHandler::HandleInvitation() │
│ (Validates, queues, auto-accepts) │
└────────────────────┬─────────────────────────────────┘
│
│ (On accept success)
▼
┌──────────────────────────────────────────────────────┐
│ EventDispatcher::Dispatch(GROUP_JOINED) │
│ (Broadcasts event to all subscribers) │
└────────────────────┬─────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────┐
│ BotAI::OnEvent(GROUP_JOINED) │
│ - ActivateStrategy("follow") │
│ - ActivateStrategy("combat_movement") │
│ - DeactivateStrategy("idle") │
└──────────────────────────────────────────────────────┘
```
**Key Principles**:
1. **Event-driven**: No polling, instant reaction
2. **Decoupled**: GroupInvitationHandler doesn't know about BotAI
3. **Extensible**: Easy to add new subscribers (e.g., QuestManager reacts to group changes)
---
### 6.3 Strategy Priority Enforcement
```cpp
// BotAI::UpdateStrategies(uint32 diff)
void BotAI::UpdateStrategies(uint32 diff)
{
// Get all registered strategies
std::vector<Strategy*> allStrategies = GetAllStrategies();
// Let BehaviorPriorityManager select ONE active strategy
Strategy* activeStrategy = _priorityManager->SelectActiveBehavior(allStrategies);
if (activeStrategy)
{
// ONLY execute the selected strategy
activeStrategy->UpdateBehavior(this, diff);
}
// If strategy is marked as "allowsLowerPriority", run those too
if (activeStrategy && activeStrategy->AllowsLowerPriority())
{
std::vector<Strategy*> lowerPriority = _priorityManager->GetLowerPriorityStrategies(activeStrategy);
for (Strategy* strat : lowerPriority)
{
if (!_priorityManager->ConflictsWith(activeStrategy, strat))
strat->UpdateBehavior(this, diff);
}
}
}
```
---
## 7. IMPLEMENTATION ROADMAP
### Phase 1: Foundation (Week 1)
1. ✅ **Enforce BehaviorPriorityManager**
- Modify BotAI::UpdateStrategies() to ONLY run strategies selected by priority manager
- Add exclusion rules: Combat excludes Follow
- Test: Bot in combat should NOT execute follow logic
2. ✅ **Standardize Movement**
- Replace all direct `MotionMaster::MovePoint()` calls with `BotMovementUtil::MoveToPosition()`
- Replace all direct `MotionMaster::MoveChase()` calls with `BotMovementUtil::ChaseTarget()`
- Test: No more stuttering/blinking during movement
### Phase 2: Group Events (Week 2)
1. ✅ **Add Group Events**
- Add `GROUP_JOINED` and `GROUP_LEFT` to BotEventTypes.h
- GroupInvitationHandler dispatches `GROUP_JOINED` on successful accept
- TrinityCore integration dispatches `GROUP_LEFT` when removed from group
2. ✅ **Remove Polling Workaround**
- Remove 1s periodic group check from BotAI::UpdateAI()
- BotAI subscribes to group events instead
- Test: Instant strategy activation when group joined
### Phase 3: Strategy Refactoring (Week 3)
1. ✅ **Fix Strategy Priorities**
- LeaderFollowBehavior: Priority 200 → 50
- CombatMovementStrategy: Priority 80 → 100, mark exclusive
- Test: Combat movement has exclusive control
2. ✅ **Merge GroupCombatStrategy**
- Move group assist logic into CombatMovementStrategy
- Remove GroupCombatStrategy as separate file
- Test: Group assist still works
3. ✅ **Throttle LeaderFollowBehavior**
- Add 100ms update interval (10 Hz instead of 60 Hz)
- Test: Still smooth following, lower CPU usage
### Phase 4: ClassAI Standardization (Week 4)
1. ✅ **Remove ClassAI Movement**
- Each ClassAI only provides `GetOptimalRange()` and `GetOptimalAngle()`
- Remove direct MotionMaster calls from all ClassAI implementations
- Test: Combat positioning still correct for all classes
2. ✅ **Combat Movement Delegation**
- CombatMovementStrategy queries ClassAI for optimal range/angle
- CombatMovementStrategy executes movement via BotMovementUtil
- Test: Hunters at 25yd, Warriors at 5yd
### Phase 5: Testing & Validation (Week 5)
1. ✅ **Integration Tests**
- Bot joins group → Follow activates instantly
- Bot enters combat → Follow deactivates, combat positioning activates
- Bot exits combat → Follow resumes
- Bot leaves group → Idle activates
2. ✅ **Performance Tests**
- Measure CPU per bot (target: <0.1%)
- Measure movement smoothness (zero stuttering)
- Measure strategy switch latency (<50ms)
---
## 8. CRITICAL DEPENDENCIES
### Required TrinityCore APIs (DO NOT MODIFY)
- `MotionMaster::MovePoint()`
- `MotionMaster::MoveChase()`
- `MotionMaster::MoveFollow()`
- `MotionMaster::GetCurrentMovementGeneratorType()`
- `Player::GetGroup()`
- `Group::GetMembers()`
- `ObjectAccessor::FindPlayer()`
### Module-Only Changes (NO CORE MODIFICATIONS)
- All refactoring happens in `src/modules/Playerbot/`
- Zero changes to TrinityCore files
- Uses existing hook points only
---
## 9. SUCCESS CRITERIA
### Movement System
- ✅ ZERO stuttering or blinking during movement
- ✅ ONE and only ONE system controls bot movement at any time
- ✅ Combat positioning has exclusive control (no follow interference)
- ✅ <0.1% CPU per bot for movement updates
### Group System
- ✅ Instant strategy activation when group joined (<50ms)
- ✅ Zero polling (100% event-driven)
- ✅ Clean group leave handling (strategies deactivate)
### Strategy System
- ✅ BehaviorPriorityManager is the ONLY strategy selector
- ✅ Exclusion rules enforced (combat excludes follow)
- ✅ No conflicting strategies run simultaneously
### Code Quality
- ✅ 51% reduction in movement/group code (~1,500 lines removed)
- ✅ Zero duplicate logic
- ✅ All strategies use BotMovementUtil (no direct MotionMaster calls)
---
## 10. APPENDIX: FILE INVENTORY
### Movement Files (13 files, ~2,675 lines)
```
Movement/
├── LeaderFollowBehavior.cpp (1,497) - REFACTOR
├── LeaderFollowBehavior.h (350) - REFACTOR
├── BotMovementUtil.cpp (172) - EXPAND
├── BotMovementUtil.h (80) - EXPAND
├── Core/MovementTypes.h (100) - KEEP
├── Core/MovementValidator.cpp (150) - KEEP
├── Core/MovementValidator.h (80) - KEEP
├── Pathfinding/PathOptimizer.cpp (120) - KEEP
└── Pathfinding/NavMeshInterface.cpp (126) - KEEP
AI/Strategy/
├── CombatMovementStrategy.cpp (734) - REFACTOR
├── CombatMovementStrategy.h (150) - REFACTOR
├── GroupCombatStrategy.cpp (272) - REMOVE
└── GroupCombatStrategy.h (80) - REMOVE
```
### Group Files (6 files, ~800 lines)
```
Group/
├── GroupInvitationHandler.cpp (450) - KEEP + FIX
├── GroupInvitationHandler.h (150) - KEEP + FIX
└── GroupCoordinator.cpp (200) - KEEP
Session/
└── BotSession.cpp (1,193 total, ~100 group-related) - KEEP
AI/
└── BotAI.cpp (1,480 total, ~50 group-related) - FIX
```
### Strategy Files (12 files, ~1,500 lines)
```
AI/Strategy/
├── Strategy.h (185) - KEEP
├── Strategy.cpp (250) - KEEP
├── LeaderFollowBehavior.* (see Movement/) - REFACTOR
├── CombatMovementStrategy.* (see above) - REFACTOR
├── GroupCombatStrategy.* (see above) - REMOVE
├── IdleStrategy.cpp (136) - KEEP
├── IdleStrategy.h (60) - KEEP
AI/
├── BehaviorPriorityManager.h (264) - ENFORCE
└── BehaviorPriorityManager.cpp (350) - ENFORCE
```
### Event Files (5 files, ~600 lines)
```
Core/Events/
├── EventDispatcher.h (200) - EXPAND
├── EventDispatcher.cpp (300) - EXPAND
├── BotEventTypes.h (100) - ADD group events
└── BotEvent.h (80) - KEEP
```
---
**Total Analyzed**: ~5,000 lines of movement/group/strategy code
**Total to Remove/Refactor**: ~2,500 lines (50%)
**Total to Keep**: ~2,500 lines (50%)
---
## CONCLUSION
The Playerbot module has a solid foundation but suffers from:
1. **Multiple competing movement systems** causing conflicts
2. **Fragmented group management** without event-driven communication
3. **Inconsistent strategy priority enforcement**
The refactoring plan addresses all three issues while:
- **Reducing code by 51%** (~1,500 lines removed)
- **Improving performance** (throttling, caching, deduplication)
- **Maintaining functionality** (zero feature loss)
- **Following TrinityCore patterns** (module-only changes)
All changes are contained within `src/modules/Playerbot/` - **ZERO core modifications required**.