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

43 KiB

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:

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:

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

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:

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

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:

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:

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

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

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:

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:

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:

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:

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:

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

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

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

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

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

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