16 KiB
Phase 5: Management System Refactoring - Per-Bot Instance Pattern
Status: 📋 PLANNED
Date: 2025-11-18
Branch: claude/playerbot-cleanup-analysis-01CcHSnAWQM7W9zVeUuJMF4h
Executive Summary
Phase 5 continues the architectural transformation from Phase 4, converting additional singleton manager systems to per-bot instances integrated into GameSystemsManager. This phase targets management systems with clear per-bot state that manage bot behaviors and resources.
Scope
- Managers to Convert: 2 (BankingManager, FarmingCoordinator)
- Estimated Lines: ~2,000 across 14 files
- New Managers in GameSystemsManager: 21 → 23
- Pattern: Singleton → Per-Bot Instance (established in Phase 4)
Architecture Analysis
Current Singleton Landscape
After Phase 4 completion, I identified 90 files with static.*instance() patterns in the PlayerBot module. These fall into three categories:
1. Already Per-Bot (21 managers in GameSystemsManager)
✅ QuestManager, TradeManager, GatheringManager, ProfessionManager, 3 Bridges, AuctionManager, GroupCoordinator, DeathRecoveryManager, UnifiedMovementCoordinator, CombatStateManager, TargetScanner, GroupInvitationHandler, EventDispatcher, ManagerRegistry, 5 Decision Systems
2. Should Stay Global (Infrastructure)
🔒 BotTalentManager - Immutable talent loadout cache shared by all bots 🔒 ConfigManager - Global configuration system 🔒 PlayerbotDatabase - Database connection pool 🔒 BotLifecycleManager - Global bot creation/spawning orchestration 🔒 PlayerbotGroupManager - Global group management 🔒 LFGBotManager - LFG queue management (global) 🔒 SpatialGridManager - Spatial indexing (global) 🔒 BotPriorityManager - Global bot priority scheduling 🔒 Event Buses - Global pub-sub systems (ProfessionEventBus, etc.)
3. Should Be Per-Bot (Phase 5 Candidates)
🎯 BankingManager - Personal banking automation (★★★★★ High Priority) 🎯 FarmingCoordinator - Profession farming coordination (★★★★★ High Priority) 🎯 EquipmentManager - Equipment evaluation and auto-equip (★★★★ Medium Priority) 🎯 MountManager - Mount selection and usage (★★★ Lower Priority) 🎯 BattlePetManager - Battle pet management (★★★ Lower Priority) 🎯 UnifiedQuestManager - Quest management (complex, future phase) 🎯 UnifiedLootManager - Loot management (complex, group-based, future phase)
Phase 5 Execution Plan
Phase 5.1: BankingManager (22nd Manager)
Priority: ★★★★★ (Highest) Complexity: Medium Estimated Time: 2-3 hours
Why BankingManager First?
-
Clear Per-Bot State:
std::unordered_map<uint32, BotBankingProfile> _bankingProfiles; std::unordered_map<uint32, std::vector<BankingTransaction>> _transactionHistory; std::unordered_map<uint32, BankingStatistics> _playerStatistics; std::unordered_map<uint32, uint32> _lastBankAccessTimes; std::set<uint32> _currentlyBanking; -
All Methods Take Player Parameter*: 25+ methods all operate on
Player* -
Inherits from BehaviorManager: Already follows manager lifecycle pattern
-
Coordinates with Profession Systems: Integrates with ProfessionManager, GatheringMaterialsBridge, ProfessionAuctionBridge
-
Thread-Safe via Mutex: Uses
OrderedRecursiveMutex<TRADE_MANAGER>for synchronization
BankingManager Statistics
- File:
src/modules/Playerbot/Banking/BankingManager.h(494 lines) - File:
src/modules/Playerbot/Banking/BankingManager.cpp(~800 lines estimated) - Public Methods: 25 methods
- Key Features:
- Gold management (auto-deposit/withdraw)
- Item management (deposit excess, withdraw for crafting)
- Banking rules and priorities
- Transaction history tracking
- Bank space analysis
- Banker access and travel
Conversion Steps
-
Header Refactoring (
BankingManager.h):- Remove
static instance()method - Add
explicit BankingManager(Player* bot); - Add
~BankingManager();destructor - Remove
Player*parameters from all 25 methods - Convert data structures:
// BEFORE std::unordered_map<uint32, BotBankingProfile> _bankingProfiles; std::unordered_map<uint32, BankingStatistics> _playerStatistics; // AFTER BotBankingProfile _profile; BankingStatistics _statistics; uint32 _lastBankAccessTime{0}; bool _currentlyBanking{false}; - Keep shared data static (default banking rules, etc.)
- Remove
-
Implementation Refactoring (
BankingManager.cpp):- Implement static member initialization
- Implement per-bot constructor/destructor
- Refactor all 25 methods to use
_botmember - Remove mutex locking (per-bot isolation)
- Update ProfessionManager access via GameSystemsManager facade:
ProfessionManager* BankingManager::GetProfessionManager() { if (!_bot) return nullptr; BotSession* session = static_cast<BotSession*>(_bot->GetSession()); if (!session || !session->GetBotAI()) return nullptr; return session->GetBotAI()->GetGameSystems()->GetProfessionManager(); }
-
GameSystemsManager Integration:
- Update
GameSystemsManager.h:- Add include:
#include "Banking/BankingManager.h" - Add getter:
BankingManager* GetBankingManager() const { return _bankingManager.get(); } - Add member:
std::unique_ptr<BankingManager> _bankingManager;
- Add include:
- Update
GameSystemsManager.cpp:- Constructor:
_bankingManager = std::make_unique<BankingManager>(_bot); - Initialize: Call
_bankingManager->OnInitialize(); - Update: Call
_bankingManager->OnUpdate(diff); - Destructor:
_bankingManager.reset();
- Constructor:
- Update
-
Legacy Cleanup:
- Remove singleton registration from
PlayerbotModule.cpp - Remove DI registration from
ServiceRegistration.h - Update any direct
BankingManager::instance()calls
- Remove singleton registration from
-
Testing:
- Verify bot banking automation works
- Test gold deposit/withdrawal triggers
- Test item banking rules
- Test profession material coordination
Phase 5.2: FarmingCoordinator (23rd Manager)
Priority: ★★★★★ (Highest) Complexity: Medium-High Estimated Time: 2-3 hours
Why FarmingCoordinator Second?
-
Clear Per-Bot State:
std::unordered_map<uint32, FarmingSession> _activeSessions; std::unordered_map<uint32, FarmingCoordinatorProfile> _profiles; std::unordered_map<uint32, uint32> _lastFarmingTimes; std::unordered_map<uint32, FarmingStatistics> _playerStatistics; -
All Methods Take Player Parameter*: 19+ methods all operate on
Player* -
Complex Profession Coordination: Works with ProfessionManager, GatheringManager, auction systems
-
Session Management: Manages farming sessions per bot with state tracking
-
Zone Selection Logic: Per-bot zone scoring and travel logic
FarmingCoordinator Statistics
- File:
src/modules/Playerbot/Professions/FarmingCoordinator.h(383 lines) - File:
src/modules/Playerbot/Professions/FarmingCoordinator.cpp(~1,200 lines estimated) - Public Methods: 19 methods
- Key Features:
- Skill gap analysis (character level vs profession skill)
- Farming session management (start/stop/update)
- Zone selection and optimization
- Material stockpile management
- Travel and positioning
- Statistics tracking
Conversion Steps
-
Header Refactoring (
FarmingCoordinator.h):- Remove
static instance()method - Add
explicit FarmingCoordinator(Player* bot); - Add
~FarmingCoordinator();destructor - Remove
Player*parameters from all 19 methods - Convert data structures:
// BEFORE std::unordered_map<uint32, FarmingSession> _activeSessions; std::unordered_map<uint32, FarmingCoordinatorProfile> _profiles; // AFTER FarmingSession _activeSession; // Only one session per bot FarmingCoordinatorProfile _profile; uint32 _lastFarmingTime{0}; FarmingStatistics _statistics; - Keep shared data static (farming zones, node database, etc.):
static std::unordered_map<ProfessionType, std::vector<FarmingZoneInfo>> _farmingZones; static bool _farmingZonesInitialized;
- Remove
-
Implementation Refactoring (
FarmingCoordinator.cpp):- Implement static member initialization (farming zones)
- Implement per-bot constructor/destructor
- Refactor all 19 methods to use
_botmember - Remove mutex locking (per-bot isolation)
- Update ProfessionManager/GatheringManager access via facade
-
GameSystemsManager Integration:
- Update
GameSystemsManager.h:- Add include:
#include "Professions/FarmingCoordinator.h" - Add getter:
FarmingCoordinator* GetFarmingCoordinator() const { return _farmingCoordinator.get(); } - Add member:
std::unique_ptr<FarmingCoordinator> _farmingCoordinator;
- Add include:
- Update
GameSystemsManager.cpp:- Constructor:
_farmingCoordinator = std::make_unique<FarmingCoordinator>(_bot); - Initialize: Call
_farmingCoordinator->Initialize(_bot); - Update: Call
_farmingCoordinator->Update(diff); - Destructor:
_farmingCoordinator.reset();
- Constructor:
- Update
-
Legacy Cleanup:
- Remove singleton registration from
PlayerbotModule.cpp - Update any direct
FarmingCoordinator::instance()calls
- Remove singleton registration from
-
Testing:
- Verify farming session triggers when skill gap detected
- Test zone selection and travel
- Test farming session completion
- Test material stockpile coordination
Established Patterns (From Phase 4)
1. Singleton → Per-Bot Transformation Pattern
// STEP 1: Remove singleton
- static Bridge* instance();
+ explicit Bridge(Player* bot);
+ ~Bridge();
// STEP 2: Convert data structures
- std::unordered_map<playerGuid, T> _playerData;
+ T _data; // Direct member
// STEP 3: Update method signatures
- void Method(Player* player, ...);
+ void Method(...); // Use _bot instead
// STEP 4: Add static shared data
+ static SharedData _sharedData;
+ static bool _sharedDataInitialized;
// STEP 5: Remove mutex (per-bot isolation)
- std::mutex _mutex;
- std::lock_guard<std::mutex> lock(_mutex);
2. Facade Access Pattern
ProfessionManager* Manager::GetProfessionManager()
{
if (!_bot) return nullptr;
BotSession* session = static_cast<BotSession*>(_bot->GetSession());
if (!session || !session->GetBotAI()) return nullptr;
return session->GetBotAI()->GetGameSystems()->GetProfessionManager();
}
3. GameSystemsManager Integration Pattern
// Header
#include "Path/ManagerName.h"
ManagerName* GetManagerName() const { return _managerName.get(); }
std::unique_ptr<ManagerName> _managerName;
// Constructor
_managerName = std::make_unique<ManagerName>(_bot);
// Initialize
if (_managerName)
{
_managerName->Initialize(_bot); // or OnInitialize() for BehaviorManager
TC_LOG_DEBUG("playerbot", "GameSystemsManager: ManagerName initialized");
}
// Update
if (_managerName)
_managerName->Update(diff); // or OnUpdate() for BehaviorManager
// Destructor (explicit ordering)
_managerName.reset();
Performance Improvements Expected
Memory Optimization
| Aspect | Before | After | Improvement |
|---|---|---|---|
| Map Overhead | ~48 bytes/entry | 0 bytes | 100% reduction |
| Cache Locality | Poor (scattered) | Excellent (contiguous) | 40% estimated |
| Memory per Bot | Variable | Fixed | 30-50% reduction |
Concurrency Improvements
| Aspect | Before | After | Improvement |
|---|---|---|---|
| Mutex Locks | Required | Zero | 100% elimination |
| Lock Contention | High (100+ bots) | None | ∞% improvement |
| Thread Safety | Explicit locking | Implicit isolation | Simplified |
Testing Strategy
Per-Phase Testing
- Compilation: Ensure all files compile without errors
- Linkage: Verify no undefined references
- Runtime: Test bot creation, initialization, update loop
- Integration: Verify manager interactions work correctly
- Performance: Monitor memory usage and CPU contention
Integration Testing
-
Banking Automation:
- Bot deposits gold when exceeds threshold
- Bot withdraws materials for crafting
- Bank space optimization works
-
Farming Coordination:
- Bot detects skill gap and starts farming session
- Bot travels to optimal farming zone
- Bot gathers nodes and gains skill points
- Session completes when target skill reached
-
Cross-Manager Coordination:
- BankingManager ↔ ProfessionManager (material needs)
- FarmingCoordinator ↔ GatheringManager (node harvesting)
- FarmingCoordinator ↔ ProfessionManager (skill tracking)
Migration Guide for Developers
Old Code (Singleton)
BankingManager::instance()->DepositGold(player, 50000);
FarmingCoordinator::instance()->StartFarmingSession(player, ProfessionType::MINING);
New Code (Per-Bot)
auto* gameSystems = botAI->GetGameSystems();
gameSystems->GetBankingManager()->DepositGold(50000);
gameSystems->GetFarmingCoordinator()->StartFarmingSession(ProfessionType::MINING);
Key Differences:
- No more
::instance()calls - No more
Player* playerparameters - Access via
GameSystemsManagerfacade - Each bot has its own manager instances
Future Phases (Phase 6+)
Phase 6 Candidates (Medium Priority)
- EquipmentManager - Equipment evaluation and auto-equip (per-bot profiles, metrics)
- MountManager - Mount selection and usage (per-bot preferences)
- BattlePetManager - Battle pet management (per-bot collection)
Complex Refactoring (Future)
- UnifiedQuestManager - Large manager with 100+ methods (requires careful analysis)
- UnifiedLootManager - Group-based loot coordination (complex interactions)
- GuildBankManager - Guild-level vs per-bot considerations
Success Criteria
Phase 5 is considered complete when:
- ✅ BankingManager converted to per-bot instance (22nd manager)
- ✅ FarmingCoordinator converted to per-bot instance (23rd manager)
- ✅ Both managers integrated into GameSystemsManager
- ✅ All legacy singleton calls removed
- ✅ Code compiles without errors
- ✅ Integration tests pass
- ✅ Documentation updated (PHASE_5_COMPLETE.md)
- ✅ DEVELOPER_GUIDE.md updated with new managers
Risks and Mitigations
Risk 1: Breaking Existing Functionality
Mitigation: Systematic testing after each conversion, maintain backward compatibility during transition
Risk 2: Performance Regression
Mitigation: Profile before/after, measure memory usage and lock contention
Risk 3: Complex Dependencies
Mitigation: Use facade access pattern, document all cross-manager interactions
Risk 4: Initialization Ordering
Mitigation: Follow established GameSystemsManager initialization order, document dependencies
Conclusion
Phase 5 continues the architectural evolution from Phase 4, converting 2 high-priority management systems from singleton to per-bot instances. This phase targets systems with clear per-bot state and strong integration with the profession ecosystem.
Expected Benefits:
- Zero lock contention (100% mutex elimination for these 2 managers)
- Better cache locality (direct members vs maps)
- Cleaner API (no Player* parameters)
- Clear ownership (facade pattern)
- Improved scalability (per-bot isolation)
GameSystemsManager Evolution: 21 → 23 managers
Document Version: 1.0 Last Updated: 2025-11-18 Author: Claude (Anthropic)