Commit Graph
15 Commits
Author SHA1 Message Date
luis b2a6d321f7 bot fixes 2026-05-01 07:18:39 -03:00
luis 911789e474 new bot system 2026-04-05 13:17:39 -03:00
luis e9876286b9 initial trading post it have mem leak and dragonriding base 2026-03-14 07:08:14 -03:00
luis e353d3078b all bot worldserver info move to debug 2026-02-21 04:37:13 -03:00
luis c706ac1789 Debug logs 2026-02-21 03:55:25 -03:00
agathoandClaude Opus 4.6 900ee56f03 fix(bg): Fix BG bot lifecycle - cleanup on end, end when human leaves, stop over-spawning
Three fixes for BG bot lifecycle issues:

1. End BG when last human leaves: MonitorActiveBattlegrounds() now checks
   for human presence in active BGs. After a 30s grace period with no
   humans, the BG ends as a draw via EndBattleground(TEAM_OTHER).

2. Release and logout BG bots on BG end: OnBattlegroundEnd() now releases
   pool bots via InstanceBotPool::ReleaseBot(), logs out all BG bots via
   BotWorldSessionMgr::RemovePlayerBot(), and notifies the orchestrator
   via OnInstanceEnded(). Previously only tracking maps were cleared.

3. Fix zone spawner over-spawning with no humans: CalculateTargetBotCount()
   now uses _lastRealPlayerCount (humans only) instead of the broken
   condition that always applied minimums in static mode or counted bot
   sessions as active players.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-07 07:40:55 -03:00
agathoandClaude Opus 4.5 d5d61361ba fix(lifecycle): Fix incomplete type error and deprecated APIs in clean build
- Add BotAI.h include to 9 files that use unique_ptr<BotAI> via BotSession.h
  Files fixed: BotCharacterCreator, BotResourcePool, BotSpawnOrchestrator,
  BotSpawner, GracefulExitHandler, DynamicQuestSystem, ObjectiveTracker,
  LootDistribution

- Fix CorpseCrashMitigation.cpp deprecated TrinityCore APIs:
  * Replace SetDeathState() with setDeathState() (correct casing)
  * Replace SetFlag/RemoveFlag/GetByteValue with internal tracking set
  * Replace deprecated PLAYER_FIELD_BYTES2 with _pendingPrevention set
  * Fix dynamic_cast<BotAI*> by using BotSession->GetAI() pattern
  * Fix OrderedSharedMutex usage (direct lock/unlock instead of std::lock)

- Add _pendingPrevention unordered_set to CorpseCrashMitigation.h

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-04 21:08:34 -03:00
agathoandClaude Opus 4.5 8ebff3aa3b fix(spawner): P1 - Fix ProcessingQueue flag race with atomic compare-exchange
**Problem:**
Classic check-then-set race condition in spawn queue processing:

Thread 1: Check _processingQueue=false ✓ (line 283)
Thread 2: Check _processingQueue=false ✓ (before T1 sets it!)
Thread 1: Set _processingQueue=true, enters processing (line 285)
Thread 2: Set _processingQueue=true, enters processing ❌ CONCURRENT PROCESSING!

Multiple threads could simultaneously enter the spawn queue processing critical
section because the check and set operations were not atomic:

```cpp
// OLD CODE - UNSAFE
if (!_processingQueue.load() && queueHasItems)  // CHECK (T1)
{
    _processingQueue.store(true);                // SET (T2) - RACE!
    ProcessSpawnQueue();                         // Both threads enter!
    _processingQueue.store(false);
}
```

This could cause:
- Duplicate spawn attempts for the same request
- Concurrent map modifications (TBB concurrent_hash_map isn't safe for this pattern)
- Throttler/orchestrator confusion from concurrent access
- Potential crashes from race conditions in spawn logic

**Root Cause:**
Non-atomic check-then-set pattern. Between line 283 (check) and line 285 (set),
another thread could pass the same check, resulting in both threads setting the
flag and entering the critical section.

**Solution:**
Atomic compare-exchange-strong operation:

```cpp
// NEW CODE - SAFE
bool expected = false;
if (queueHasItems && _processingQueue.compare_exchange_strong(
        expected, true, std::memory_order_acquire, std::memory_order_relaxed))
{
    try {
        ProcessSpawnQueue();  // Only ONE thread can enter
    } catch (...) {
        TC_LOG_ERROR("Exception in queue processing");
    }
    _processingQueue.store(false, std::memory_order_release);
}
```

**How compare_exchange_strong Works:**
1. Atomically checks if _processingQueue == expected (false)
2. If true, atomically sets _processingQueue = true
3. Returns true (only ONE thread succeeds)
4. Other threads see expected changed to true by the compare, fail check
5. Guarantees mutual exclusion without explicit mutex

**Thread Execution Example:**
- Thread 1: CAS(false→true) succeeds, expected=false, returns true ✓
- Thread 2: CAS(false→true) fails (already true), expected=true, returns false ✓
- Thread 1: Processes queue exclusively
- Thread 2: Skips processing, continues Update()

**Memory Ordering:**
- acquire: Ensures all subsequent reads see values written before the store(true)
- release: Ensures all prior writes are visible before store(false) becomes visible
- Proper synchronization without full sequential consistency overhead

**Additional Safety:**
- Wrapped processing in try-catch to ensure flag is always reset
- Used memory_order_release when resetting flag for proper visibility
- Exception-safe cleanup guarantees no stuck flag state

**Testing:**
- Compiled cleanly (RelWithDebInfo)
- No new warnings
- Pattern guarantees mutual exclusion

**Benefits:**
- Zero contention: Only atomic operations, no mutex overhead
- Correct: Guarantees exactly one thread processes queue per update cycle
- Fast: Lock-free atomic operations are ~10-100x faster than mutex
- Safe: Exception-safe cleanup ensures flag is always reset

**Location:** src/modules/Playerbot/Lifecycle/BotSpawner.cpp:267-420
**Priority:** P1 (Race condition in spawn queue processing)
**Task:** SESSION_LIFECYCLE_FIXES Task 4/7

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-04 21:05:07 -03:00
agathoandClaude Opus 4.5 226d6de60c fix(spawner): P1 - Fix TOCTOU race in ValidateSpawnRequest with atomic pre-increment
**Problem:**
Classic Time-Of-Check-Time-Of-Use (TOCTOU) race in spawn validation:

Thread 1: Check count=99 < 100 ✓ (line 737 ValidateSpawnRequest)
Thread 2: Check count=99 < 100 ✓ (before T1 increments)
Thread 1: Spawns, count becomes 100 (line 1131 ContinueSpawnWithCharacter)
Thread 2: Spawns, count becomes 101 ❌ POPULATION CAP OVERFLOW!

Multiple threads could pass population cap check simultaneously because:
1. Check happens in ValidateSpawnRequest (line 737-755)
2. Increment happens much later in ContinueSpawnWithCharacter (line 1131)
3. Time gap between check and increment allows race conditions

With 4 threads spawning 50 bots each (target: 100 max), actual count could
reach 120-150 due to concurrent validation passes.

**Root Cause:**
```cpp
// OLD FLOW - UNSAFE
SpawnBot() {
    if (!ValidateSpawnRequest()) return false;  // CHECK (T1)
    // TIME GAP - other threads can also pass check here
    return SpawnBotInternal();                   // USE (T2)
}

ContinueSpawnWithCharacter() {
    _activeBotCount.fetch_add(1);  // INCREMENT (T3) - too late!
}
```

**Solution:**
Atomic pre-increment with rollback pattern:

```cpp
// NEW FLOW - SAFE
SpawnBot() {
    // 1. Basic validation (non-population)
    if (!ValidateSpawnRequestBasic()) return false;

    // 2. ATOMIC PRE-INCREMENT - reserves slot, returns OLD value
    uint32 oldCount = _activeBotCount.fetch_add(1, acquire);

    // 3. Check cap using OLD value (before increment)
    if (oldCount >= maxBotsTotal) {
        _activeBotCount.fetch_sub(1, release);  // Rollback
        return false;
    }

    // 4. Spawn (counter already incremented, no double-count)
    if (!SpawnBotInternal()) {
        _activeBotCount.fetch_sub(1, release);  // Rollback on error
        return false;
    }
    return true;
}
```

**Why This Works:**
- fetch_add() is atomic - only ONE thread can get oldCount=99
- Thread that gets oldCount=99 passes (reserves slot 100)
- Next thread gets oldCount=100, fails check, rolls back
- Zero time gap between check and increment
- Exact cap enforcement guaranteed

**Changes:**
1. Created ValidateSpawnRequestBasic() - non-population validation
2. Updated SpawnBot() - atomic pre-increment with rollback
3. Removed increment from ContinueSpawnWithCharacter() - prevent double-count
4. Kept ValidateSpawnRequest() for backward compatibility (marked deprecated)

**Testing:**
- Compiled cleanly (RelWithDebInfo)
- No new warnings
- Pattern guarantees exact cap enforcement

**Limitations:**
- Zone/map caps still best-effort (no per-zone atomic counters yet)
- Global cap is the hard limit (perfectly enforced)
- TODO: Add per-zone atomic counters for perfect zone cap enforcement

**Location:**
- src/modules/Playerbot/Lifecycle/BotSpawner.cpp (lines 527-620, 698-795, 1130-1135)
- src/modules/Playerbot/Lifecycle/BotSpawner.h (line 205)

**Priority:** P1 (Race condition causing population cap overflow)
**Task:** SESSION_LIFECYCLE_FIXES Task 3/7

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-04 21:04:18 -03:00
agathoandClaude Opus 4.5 2bdad4f24e fix(spawner): P1 - Fix DespawnAllBots iterator race with atomic swap
**Problem:**
Range-based for loop over TBB concurrent_hash_map in DespawnAllBots() was NOT
atomic. Other threads could modify _activeBots during iteration, causing:
- Iterator invalidation
- Missing bots (removed during iteration)
- Seeing bots twice (if rehash happens)
- Potential crashes from concurrent modification

**Root Cause:**
```cpp
// UNSAFE - NOT atomic, race condition window
for (auto const& [guid, zoneId] : _activeBots) {
    botsToRemove.push_back(guid);
}
```

While iterating, other threads could call SpawnBot/DespawnBot, modifying the
underlying hash table structure.

**Solution:**
Implemented atomic swap pattern:
1. Create empty concurrent_hash_maps
2. Atomically swap with _activeBots and _botsByZone (TBB swap is atomic)
3. Process isolated snapshot with zero race condition risk
4. Directly cleanup sessions (bypass DespawnBot since entries already removed)

**Benefits:**
- Thread-safe: No race conditions possible
- Fast: Single pass, no repeated lookups
- Clean: All session cleanup handled properly
- Stats: Batch updates for performance

**Technical Details:**
- Used tbb::concurrent_hash_map::swap() atomic operation
- Isolated oldBots map guarantees no concurrent access
- Direct session cleanup via RemoveAllPlayerBots()
- Atomic counter updates with memory_order_release
- Batch stat updates (single fetch_add vs N individual calls)

**Testing:**
- Compiled cleanly (RelWithDebInfo)
- No new warnings

**Location:** src/modules/Playerbot/Lifecycle/BotSpawner.cpp:1256-1300
**Priority:** P1 (Race condition in mass despawn operation)
**Task:** SESSION_LIFECYCLE_FIXES Task 2/7

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-04 21:03:36 -03:00
agathoandClaude Opus 4.5 42aadb1aae chore(playerbot): Sync session state - documentation and hook updates
This commit syncs accumulated changes from previous development sessions:

Code Changes:
- Added BG invitation hook (OnBGInvitationReceived) to PlayerBotHooks
- Updated spell validations for WoW 12.0 compatibility
- Minor ClassAI adjustments across multiple specs
- Combat system refinements
- BattlegroundQueue core integration

Documentation Updates:
- Updated multiple phase completion documents
- Synchronized technical specifications
- Updated architecture and testing documentation
- Configuration guides and deployment docs

Project Maintenance:
- Serena project configuration updated
- Build system verified (successful compilation)
- All changes compile cleanly

This represents incremental development progress and is being committed
before proceeding with next priority tasks.

Build Status: SUCCESS (worldserver.exe 55MB)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-04 20:59:19 -03:00
agathoandClaude Opus 4.5 9f10b1a1ef fix(spawner): Allow warm pool bots to bypass MaxBots limit
Warm pool and JIT bots for BG/dungeon/arena are temporary special-purpose
bots that should not be blocked by the MaxBots configuration setting.

Changes:
- Add bypassMaxBotsLimit field to SpawnRequest struct
- Pass bypassMaxBotsLimit through BotSpawner chain to AddPlayerBot
- Set bypassMaxBotsLimit=true in InstanceBotPool::WarmUpBot

This fixes the issue where setting MaxBots=0 (to disable world population
bots) also blocked warm pool bots from spawning for battleground queues.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-04 20:34:08 -03:00
agathoandClaude Opus 4.5 7562fa663b fix(spawner): Add WoW 11.x character customization for JIT bot creation
JIT bots were failing to create (1/29 success rate) because
Player::Create() calls ValidateAppearance() which requires valid
ChrCustomizationChoice entries for WoW 11.x.

The fix generates default customizations using DB2Manager APIs:
- GetCustomiztionOptions() to get available options for race/gender
- GetCustomiztionChoices() to get valid choices for each option
- Uses first available choice for each customization option

Applied to both CreateBotCharacter() overloads to fix JIT/Instance bot
creation for BG queue population.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-04 20:24:12 -03:00
agathoandClaude Opus 4.5 2583f507bc fix(playerbot): Resolve build errors and implement spec-based role detection
Build fixes:
- Add Player forward declaration to JITBotFactory.h
- Add missing includes: BotWorldSessionMgr.h, BotSession.h, DB2Stores.h
- Fix LocalizedString usage with DEFAULT_LOCALE instead of integer index
- Fix SpellName pointer dereference: (*spellInfo->SpellName)[DEFAULT_LOCALE]
- Fix PlayerSpell member access: .active/.disabled instead of .IsActive()/.IsDisabled()
- Remove non-existent BotSessionMgr.cpp/.h from CMakeLists.txt

New features:
- Implement enterprise-grade role detection in JITBotFactory using DB2 spec data
- Add GetPlayerSpecRole() using ChrSpecializationEntry for accurate role detection
- Add GroupRoleToBotRole() conversion for pool system compatibility
- Add DetermineBotRole() as main entry point for spec-based role determination
- Distinguish melee/ranged DPS using ChrSpecializationFlag

Code cleanup:
- Remove obsolete BotSessionMgr files (replaced by BotWorldSessionMgr)
- Remove IBotSessionMgr interface (no longer needed)
- Remove MockSpatialGridManager test mock
- Remove invalid dynamic_cast<BotAI*>(UnitAI*) - types are unrelated

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-01-22 19:59:45 -03:00
luis 352fd58121 Modules init 2026-01-20 21:36:03 -03:00