1215 lines
43 KiB
Markdown
1215 lines
43 KiB
Markdown
# 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**.
|