7.2 KiB
7.2 KiB
Phase 2 Manager Execution Failure - ROOT CAUSE ANALYSIS
Issue Summary
Phase 2 BehaviorManager-based managers (QuestManager, TradeManager, GatheringManager, AuctionManager) are not executing despite being properly initialized and called from UpdateAI.
Evidence
What's Working ✅
- Managers ARE initialized in BotAI constructor (BotAI.cpp:67-70)
- UpdateManagers() IS called in UpdateAI (BotAI.cpp:242)
- UpdateManagers() implementation exists and calls Update() on all 4 managers
- Managers ARE enabled by default (BehaviorManager.h:245:
std::atomic<bool> m_enabled{true}) - UpdateAI is being called: 11,591 successful UpdateAI calls in logs
What's NOT Working ❌
ZERO traces in 153,850 log lines of:
- UpdateManagers being called
- Any manager Update() calls
- Any manager OnUpdate() calls
- Any BehaviorManager activity
ROOT CAUSE IDENTIFIED
The Problem: IsInWorld() Check
Location: BehaviorManager::ValidatePointers() (BehaviorManager.cpp:262-270)
// Check if bot is in world
if (!m_bot->IsInWorld())
{
TC_LOG_DEBUG("module.playerbot", "[{}] Bot {} is not in world", m_managerName, m_bot->GetName());
return false; // ← RETURNS FALSE
}
Consequence: When ValidatePointers() returns false, BehaviorManager::Update() permanently disables the manager (line 92):
if (!ValidatePointers())
{
m_enabled.store(false, std::memory_order_release); // ← MANAGER GETS DISABLED PERMANENTLY
TC_LOG_ERROR("module.playerbot", "[{}] Disabled due to invalid pointers", m_managerName);
return;
}
Why This Happens
The issue occurs because of a timing discrepancy:
- BotAI::UpdateAI() checks
IsInWorld()at line 110 and passes - UpdateManagers() checks
IsInWorld()at line 1228 and passes - BehaviorManager::Update() is called, which calls
ValidatePointers() - Inside ValidatePointers(),
IsInWorld()is checked AGAIN (line 262) - Between the check in UpdateAI and the check in ValidatePointers, the bot's world state may have changed, OR
- There's a bug in the IsInWorld() implementation that causes false negatives
The Critical Flaw
The real problem is PERMANENT DISABLING:
- If
IsInWorld()returnsfalseeven ONCE, the manager is permanently disabled - The manager will NEVER recover because
m_enabledis set tofalseand never reset - This is overly aggressive - a temporary state check shouldn't permanently disable a manager
Code Flow Analysis
UpdateAI (BotAI.cpp:98)
├─ Bot IsInWorld() check (line 110) ✅ PASS
│
├─ UpdateManagers (BotAI.cpp:1211)
│ ├─ Bot IsInWorld() check (line 1228) ✅ PASS
│ │
│ ├─ QuestManager->Update()
│ │ └─ BehaviorManager::Update (BehaviorManager.cpp:58)
│ │ ├─ enabled check (line 74) ✅ true (default)
│ │ ├─ busy check (line 82) ✅ false
│ │ ├─ ValidatePointers() (line 90)
│ │ │ ├─ m_bot check ✅ PASS
│ │ │ ├─ m_bot->IsInWorld() ❌ FAIL (WHY?)
│ │ │ └─ return false
│ │ └─ m_enabled.store(false) ← PERMANENTLY DISABLED
│ │
│ ├─ TradeManager->Update() [same failure]
│ ├─ GatheringManager->Update() [same failure]
│ └─ AuctionManager->Update() [same failure]
Possible Causes
1. Race Condition (MOST LIKELY)
- Bot's world state changes between UpdateAI check and ValidatePointers check
- This could happen if bot is being removed from world in another thread
- Extremely unlikely given single-threaded world update, but possible
2. IsInWorld() Implementation Bug
- Player::IsInWorld() may have a bug causing false negatives
- Worth investigating TrinityCore's implementation
3. Initialization Timing Issue
- Managers are created in BotAI constructor
- At that moment, bot might not be fully "in world" yet
- First Update() call happens before bot is fully initialized
4. Redundant Check Logic
- UpdateAI already checks IsInWorld() at line 110
- UpdateManagers checks it again at line 1228
- ValidatePointers checks it AGAIN at line 262
- This is defensive over-engineering that backfires
The Fix
Option 1: Remove Permanent Disabling (RECOMMENDED)
Don't permanently disable managers on transient failures:
// In BehaviorManager::Update()
if (!ValidatePointers())
{
// DON'T disable permanently - just skip this update
// m_enabled.store(false, std::memory_order_release); // ← REMOVE THIS
if (shouldLog)
TC_LOG_DEBUG("module.playerbot", "[{}] Skipping update - invalid pointers", m_managerName);
return;
}
Rationale:
- A temporary state issue shouldn't permanently break the manager
- If the bot is truly gone, the bot deletion will clean up managers anyway
- Allows managers to recover from transient failures
Option 2: Trust Parent Check (ALSO RECOMMENDED)
Remove the redundant IsInWorld() check from ValidatePointers():
bool BehaviorManager::ValidatePointers() const
{
// Check bot pointer validity
if (!m_bot)
{
TC_LOG_ERROR("module.playerbot", "[{}] Bot pointer is null", m_managerName);
return false;
}
// REMOVE THIS CHECK - parent UpdateManagers() already validated
// if (!m_bot->IsInWorld())
// {
// return false;
// }
// Check AI pointer validity
if (!m_ai)
{
TC_LOG_ERROR("module.playerbot", "[{}] AI pointer is null for bot {}", m_managerName, m_bot->GetName());
return false;
}
return true;
}
Rationale:
- UpdateAI already checked IsInWorld() at line 110
- UpdateManagers already checked IsInWorld() at line 1228
- Triple-checking is redundant and causes problems
- Trust the caller's validation
Option 3: Combine Both Fixes (BEST)
- Remove the IsInWorld() check from ValidatePointers()
- Remove permanent disabling on validation failure
- Let managers gracefully skip updates when needed
Next Steps
- Add strategic logging (DONE) to confirm diagnosis
- Run worldserver with logging enabled
- Examine logs to see which check is failing
- Apply the fix based on log evidence
- Verify managers are executing after fix
Strategic Logging Added
BotAI.cpp:UpdateManagers()
- Entry logging with IsInWorld() status
- Per-manager Update() call tracing
- Completion confirmation
BehaviorManager.cpp:Update()
- Entry logging with enabled/busy/botInWorld status
- Validation failure tracing
- Pass/fail indicators
BehaviorManager.cpp:ValidatePointers()
- Per-check validation logging
- Specific failure reason identification
- Success confirmation
Testing Instructions
- Compile with logging changes
- Run worldserver
- Add bot to group
- Observe logs for:
- "UpdateManagers ENTRY" messages
- "ValidatePointers FAILED" messages
- Which specific check is failing
- Apply appropriate fix based on evidence
Expected Outcome
Logs will reveal:
- Whether UpdateManagers() is being called ✅
- Whether manager Update() is being reached ✅
- Which ValidatePointers() check is failing (bot null vs IsInWorld vs AI null)
- Whether managers are being permanently disabled
This will confirm the root cause and guide the fix implementation.