16 KiB
Phase 2.4: Refactor Managers - Remove Automation Singletons
Duration: 2 weeks (2025-02-03 to 2025-02-17) Status: ⏳ PENDING Owner: Development Team
Objectives
Replace all singleton Automation classes with per-bot Manager instances:
- Delete QuestAutomation, TradeAutomation, AuctionAutomation, GatheringAutomation
- Create/refactor managers to inherit from BehaviorManager base class
- Integrate managers into BotAI lifecycle
- Eliminate 50-100ms blocking updates
- Achieve <1ms amortized cost per manager
Background
Current Problem: Singleton Automation Classes
QuestAutomation.h (324 lines):
class QuestAutomation
{
public:
static QuestAutomation* instance(); // ❌ Singleton pattern
void UpdateBotAutomation(Player* bot, uint32 diff); // 50-100ms blocking
private:
QuestAutomation() = default;
static QuestAutomation* _instance;
};
Problems:
- Performance: Each Update() call takes 50-100ms
- Scalability: Singleton shared state doesn't scale to 5000 bots
- Duplication: QuestAutomation duplicates QuestManager functionality
- Blocking: IdleStrategy calls these every frame, causing lag
- Architecture: Violates per-bot instance pattern
Current Files to Delete (~2000 lines):
Quest/QuestAutomation.h(324 lines)Quest/QuestAutomation.cpp(estimated 500 lines)Social/TradeAutomation.h(estimated 200 lines)Social/TradeAutomation.cpp(estimated 400 lines)Social/AuctionAutomation.h(estimated 200 lines)Social/AuctionAutomation.cpp(estimated 400 lines)Professions/GatheringAutomation.h(estimated 150 lines)Professions/GatheringAutomation.cpp(estimated 300 lines)
Solution: Per-Bot Manager Instances
New Pattern (all inherit from BehaviorManager):
// Base class from Phase 2.1
class BehaviorManager
{
public:
BehaviorManager(Player* bot, BotAI* ai, uint32 updateInterval);
virtual ~BehaviorManager() = default;
// Throttled update (called by BotAI::UpdateManagers)
void Update(uint32 diff);
// Fast state queries (atomic, no locks)
bool IsActive() const { return _active.load(); }
protected:
virtual void OnUpdate(uint32 diff) = 0; // Subclass implements
Player* _bot;
BotAI* _ai;
std::atomic<bool> _active{false};
uint32 _updateInterval;
uint32 _lastUpdate = 0;
};
// Example manager
class QuestManager : public BehaviorManager
{
public:
QuestManager(Player* bot, BotAI* ai)
: BehaviorManager(bot, ai, 2000) // Update every 2 seconds
{}
bool IsQuestingActive() const { return _hasActiveQuests.load(); }
protected:
void OnUpdate(uint32 diff) override
{
// Do heavyweight quest logic here (runs every 2 seconds)
_hasActiveQuests.store(bot->GetQuestCount() > 0);
}
private:
std::atomic<bool> _hasActiveQuests{false};
};
Benefits:
- ✅ Per-bot instance (no shared state)
- ✅ Throttled updates (2s interval = 0.05ms amortized)
- ✅ Fast state queries (atomic, <0.001ms)
- ✅ Unified pattern (all managers work the same way)
- ✅ Scalable to 5000+ bots
Technical Requirements
Manager Specifications
QuestManager:
- Update interval: 2000ms (2 seconds)
- Responsibilities: Quest pickup, turn-in, objective tracking
- State queries: IsQuestingActive(), HasActiveQuest(questId)
- Already exists at
Game/QuestManager.h- needs refactoring
TradeManager (NEW):
- Update interval: 5000ms (5 seconds)
- Responsibilities: Item trading, vendor interactions, repair
- State queries: IsTradingActive(), NeedsRepair()
- Replaces: TradeAutomation
AuctionManager:
- Update interval: 10000ms (10 seconds)
- Responsibilities: Auction house interactions, buying/selling
- State queries: HasActiveAuctions(), IsAtAuctionHouse()
- Already exists at
Economy/AuctionManager.h- needs refactoring
GatheringManager (NEW):
- Update interval: 1000ms (1 second)
- Responsibilities: Herb/ore detection, gathering execution
- State queries: IsGathering(), HasNearbyResources()
- Replaces: GatheringAutomation
Performance Requirements
- Manager::Update() amortized cost: <0.2ms per manager
- Manager state query: <0.001ms (atomic read)
- Total manager overhead: <0.8ms per bot per frame (4 managers × 0.2ms)
- Memory overhead: <4KB per bot (all managers combined)
Integration with BotAI
New UpdateManagers() Method:
void BotAI::UpdateManagers(uint32 diff)
{
if (!_bot || !_bot->IsInWorld())
return;
// Each manager throttles itself internally
if (_questManager)
_questManager->Update(diff);
if (_tradeManager)
_tradeManager->Update(diff);
if (_auctionManager)
_auctionManager->Update(diff);
if (_gatheringManager)
_gatheringManager->Update(diff);
}
Deliverables
1. Refactor QuestManager
Location: src/modules/Playerbot/Game/QuestManager.h
Changes Required:
// BEFORE: Custom implementation
class QuestManager
{
public:
QuestManager(Player* bot, BotAI* ai);
void Update(uint32 diff); // No throttling
// ... methods ...
};
// AFTER: Inherits from BehaviorManager
class QuestManager : public BehaviorManager
{
public:
QuestManager(Player* bot, BotAI* ai);
// Fast state queries
bool IsQuestingActive() const { return _hasActiveQuests.load(); }
bool HasActiveQuest(uint32 questId) const;
uint32 GetActiveQuestCount() const { return _activeQuestCount.load(); }
protected:
void OnUpdate(uint32 diff) override;
private:
std::atomic<bool> _hasActiveQuests{false};
std::atomic<uint32> _activeQuestCount{0};
// ... existing quest tracking data ...
};
2. Create TradeManager
Location: src/modules/Playerbot/Social/TradeManager.h (NEW)
Full Implementation:
#pragma once
#include "AI/BehaviorManager.h"
namespace Playerbot
{
class TradeManager : public BehaviorManager
{
public:
TradeManager(Player* bot, BotAI* ai);
~TradeManager() override = default;
// State queries
bool IsTradingActive() const { return _isTrading.load(); }
bool NeedsRepair() const { return _needsRepair.load(); }
bool NeedsSupplies() const { return _needsSupplies.load(); }
protected:
void OnUpdate(uint32 diff) override;
private:
// Trade logic
void CheckRepairStatus();
void CheckSupplyStatus();
void FindNearbyVendors();
void ExecuteTrade();
// State
std::atomic<bool> _isTrading{false};
std::atomic<bool> _needsRepair{false};
std::atomic<bool> _needsSupplies{false};
ObjectGuid _currentVendor;
};
} // namespace Playerbot
3. Refactor AuctionManager
Location: src/modules/Playerbot/Economy/AuctionManager.h
Changes Required: Similar to QuestManager refactor
- Inherit from BehaviorManager
- Add atomic state flags
- Implement OnUpdate() with 10-second throttling
- Add fast state query methods
4. Create GatheringManager
Location: src/modules/Playerbot/Professions/GatheringManager.h (NEW)
Full Implementation:
#pragma once
#include "AI/BehaviorManager.h"
namespace Playerbot
{
class GatheringManager : public BehaviorManager
{
public:
GatheringManager(Player* bot, BotAI* ai);
~GatheringManager() override = default;
// State queries
bool IsGathering() const { return _isGathering.load(); }
bool HasNearbyResources() const { return _hasNearbyResources.load(); }
protected:
void OnUpdate(uint32 diff) override;
private:
// Gathering logic
void ScanForResources();
void SelectBestResource();
void MoveToResource();
void GatherResource();
// State
std::atomic<bool> _isGathering{false};
std::atomic<bool> _hasNearbyResources{false};
ObjectGuid _currentResource;
std::vector<ObjectGuid> _nearbyHerbs;
std::vector<ObjectGuid> _nearbyOres;
};
} // namespace Playerbot
5. Integrate Managers into BotAI
Location: src/modules/Playerbot/AI/BotAI.h
Add Manager Members:
class BotAI
{
public:
// ... existing methods ...
// Manager access
QuestManager* GetQuestManager() const { return _questManager.get(); }
TradeManager* GetTradeManager() const { return _tradeManager.get(); }
AuctionManager* GetAuctionManager() const { return _auctionManager.get(); }
GatheringManager* GetGatheringManager() const { return _gatheringManager.get(); }
private:
// NEW: Manager update method
void UpdateManagers(uint32 diff);
// Manager instances
std::unique_ptr<QuestManager> _questManager;
std::unique_ptr<TradeManager> _tradeManager;
std::unique_ptr<AuctionManager> _auctionManager;
std::unique_ptr<GatheringManager> _gatheringManager;
};
Modify BotAI::UpdateAI():
void BotAI::UpdateAI(uint32 diff)
{
if (!_bot || !_bot->IsInWorld())
return;
// PHASE 1: Manager updates (heavyweight, throttled) ✅ NEW
UpdateManagers(diff);
// PHASE 2: Strategy updates (lightweight, every frame)
UpdateStrategies(diff);
// PHASE 3: Movement execution
UpdateMovement(diff);
// PHASE 4: Combat specialization
if (IsInCombat())
OnCombatUpdate(diff);
}
6. Delete Automation Files
Remove from filesystem:
cd src/modules/Playerbot
rm Quest/QuestAutomation.h
rm Quest/QuestAutomation.cpp
rm Social/TradeAutomation.h
rm Social/TradeAutomation.cpp
rm Social/AuctionAutomation.h
rm Social/AuctionAutomation.cpp
rm Professions/GatheringAutomation.h
rm Professions/GatheringAutomation.cpp
Remove from CMakeLists.txt:
# Remove these lines:
src/modules/Playerbot/Quest/QuestAutomation.cpp
src/modules/Playerbot/Social/TradeAutomation.cpp
src/modules/Playerbot/Social/AuctionAutomation.cpp
src/modules/Playerbot/Professions/GatheringAutomation.cpp
Find and remove all includes:
grep -r "QuestAutomation.h" --include="*.cpp" --include="*.h" src/modules/Playerbot/
grep -r "TradeAutomation.h" --include="*.cpp" --include="*.h" src/modules/Playerbot/
grep -r "AuctionAutomation.h" --include="*.cpp" --include="*.h" src/modules/Playerbot/
grep -r "GatheringAutomation.h" --include="*.cpp" --include="*.h" src/modules/Playerbot/
Files to update:
AI/Strategy/IdleStrategy.cpp(remove all Automation includes)- Any other files that reference Automation classes
7. Unit Tests
Location: tests/unit/Managers/
Test Files:
QuestManagerTest.cpp- Throttling, state queriesTradeManagerTest.cpp- Repair detection, vendor findingAuctionManagerTest.cpp- Auction tracking, bid logicGatheringManagerTest.cpp- Resource detection, gathering flow
8. Integration Tests
Location: tests/integration/ManagerIntegrationTest.cpp
Test Scenarios:
- All 4 managers update correctly with 100 bots
- Manager state queries are fast (<0.001ms)
- Managers don't interfere with each other
- Performance is <0.8ms total per bot
- No memory leaks after 10000 updates
9. Documentation
Location: docs/MANAGER_SYSTEM_GUIDE.md
Content:
- Manager pattern explanation
- How to create a new manager
- Throttling mechanism details
- State query best practices
- Migration guide from Automation classes
- Performance tuning guide
Implementation Steps
Week 1: Create New Managers (Days 1-7)
Day 1-2: Refactor QuestManager
- Add BehaviorManager inheritance
- Implement OnUpdate() with throttling
- Add atomic state flags
- Test with 100 bots
Day 3-4: Create TradeManager
- Write TradeManager.h header
- Implement TradeManager.cpp
- Add repair detection logic
- Add vendor finding logic
- Test basic functionality
Day 5-6: Create GatheringManager
- Write GatheringManager.h header
- Implement GatheringManager.cpp
- Add resource scanning logic
- Add gathering execution logic
- Test herb/ore gathering
Day 7: Refactor AuctionManager
- Add BehaviorManager inheritance
- Implement OnUpdate() with throttling
- Add atomic state flags
- Test auction tracking
Week 2: Integration and Cleanup (Days 8-14)
Day 8-9: Integrate into BotAI
- Add manager members to BotAI.h
- Implement UpdateManagers() method
- Initialize managers in BotAI constructor
- Modify UpdateAI() to call UpdateManagers()
- Compile and test basic integration
Day 10: Delete Automation Files
- Find all Automation includes
- Remove includes from all files
- Delete Automation source files
- Update CMakeLists.txt
- Verify compilation
Day 11: Write Tests
- Unit tests for all 4 managers
- Integration test for manager system
- Performance benchmark tests
- All tests must pass
Day 12-13: Performance Testing
- Benchmark with 100 bots
- Benchmark with 500 bots
- Benchmark with 1000 bots
- Profile manager updates
- Optimize if needed
Day 14: Documentation
- Write manager system guide
- Create migration guide
- Update architecture documentation
- Final code review
Success Criteria
Functional Requirements
- ✅ All 4 managers inherit from BehaviorManager
- ✅ No Automation singleton classes remain
- ✅ QuestManager refactored successfully
- ✅ TradeManager created and working
- ✅ GatheringManager created and working
- ✅ AuctionManager refactored successfully
- ✅ All managers integrated into BotAI
- ✅ UpdateManagers() called every frame
Performance Requirements
- ✅ QuestManager amortized cost <0.2ms
- ✅ TradeManager amortized cost <0.2ms
- ✅ AuctionManager amortized cost <0.2ms
- ✅ GatheringManager amortized cost <0.2ms
- ✅ Total manager overhead <0.8ms per bot
- ✅ State queries <0.001ms (atomic)
- ✅ 100 bots run without lag
- ✅ 500 bots run with <5% CPU increase
Code Quality
- ✅ All managers follow same pattern
- ✅ Full documentation for all managers
- ✅ Comprehensive test coverage
- ✅ No compiler warnings
- ✅ No memory leaks
- ✅ Clean separation of concerns
Cleanup
- ✅ 8 Automation files deleted (~2000 lines)
- ✅ All Automation includes removed
- ✅ CMakeLists.txt updated
- ✅ No dead code remaining
- ✅ Clean compilation
Dependencies
Requires
- Phase 2.1 complete (BehaviorManager base class)
- Phase 2.2 complete (CombatMovementStrategy - for context)
- Phase 2.3 complete (Universal ClassAI - for context)
Blocks
- Phase 2.5 (IdleStrategy needs manager state queries)
- Phase 2.6 (Integration testing needs all managers working)
- Phase 2.7 (Cleanup needs managers refactored first)
Risk Mitigation
Risk: Breaking existing functionality
Mitigation:
- Refactor one manager at a time
- Test after each refactor
- Keep parallel implementations temporarily if needed
Risk: Performance regression
Mitigation:
- Benchmark before/after each manager
- Profile with 500+ bots
- Adjust throttling intervals if needed
Risk: Missing Automation functionality
Mitigation:
- Compare Automation vs Manager methods line-by-line
- Port all important logic
- Create migration checklist
Risk: Difficult debugging
Mitigation:
- Add comprehensive logging during development
- Use performance monitoring
- Create debug commands for manager state
Migration Checklist
For Each Manager:
- List all methods from Automation class
- Implement equivalent methods in Manager class
- Add throttling to heavy operations
- Add atomic state flags for queries
- Write unit tests
- Test with 100 bots
- Document new API
- Remove Automation class
- Update all references
QuestManager Migration:
- QuestAutomation::UpdateBotAutomation → QuestManager::OnUpdate
- Quest pickup logic ported
- Quest turn-in logic ported
- Objective tracking ported
- State queries added (IsQuestingActive, etc.)
TradeManager Migration:
- TradeAutomation::UpdatePlayerAutomation → TradeManager::OnUpdate
- Repair logic ported
- Vendor finding ported
- Item selling logic ported
- State queries added (NeedsRepair, etc.)
GatheringManager Migration:
- GatheringAutomation::Update → GatheringManager::OnUpdate
- Resource scanning ported
- Gathering execution ported
- Profession checks ported
- State queries added (IsGathering, etc.)
AuctionManager Migration:
- AuctionAutomation::UpdatePlayerAutomation → AuctionManager::OnUpdate
- Auction tracking ported
- Bid logic ported
- Sale logic ported
- State queries added (HasActiveAuctions, etc.)
Next Phase
After completion, proceed to Phase 2.5: Update IdleStrategy (Observer Pattern)
Last Updated: 2025-01-13 Next Review: 2025-02-17