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

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 ✅

  1. Managers ARE initialized in BotAI constructor (BotAI.cpp:67-70)
  2. UpdateManagers() IS called in UpdateAI (BotAI.cpp:242)
  3. UpdateManagers() implementation exists and calls Update() on all 4 managers
  4. Managers ARE enabled by default (BehaviorManager.h:245: std::atomic<bool> m_enabled{true})
  5. 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:

  1. BotAI::UpdateAI() checks IsInWorld() at line 110 and passes
  2. UpdateManagers() checks IsInWorld() at line 1228 and passes
  3. BehaviorManager::Update() is called, which calls ValidatePointers()
  4. Inside ValidatePointers(), IsInWorld() is checked AGAIN (line 262)
  5. Between the check in UpdateAI and the check in ValidatePointers, the bot's world state may have changed, OR
  6. There's a bug in the IsInWorld() implementation that causes false negatives

The Critical Flaw

The real problem is PERMANENT DISABLING:

  • If IsInWorld() returns false even ONCE, the manager is permanently disabled
  • The manager will NEVER recover because m_enabled is set to false and 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

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

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)

  1. Remove the IsInWorld() check from ValidatePointers()
  2. Remove permanent disabling on validation failure
  3. Let managers gracefully skip updates when needed

Next Steps

  1. Add strategic logging (DONE) to confirm diagnosis
  2. Run worldserver with logging enabled
  3. Examine logs to see which check is failing
  4. Apply the fix based on log evidence
  5. 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

  1. Compile with logging changes
  2. Run worldserver
  3. Add bot to group
  4. Observe logs for:
    • "UpdateManagers ENTRY" messages
    • "ValidatePointers FAILED" messages
    • Which specific check is failing
  5. 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.