Commit Graph
3372 Commits
Author SHA1 Message Date
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 c58145d6d2 fix(spawner): Allow runtime bot spawning after startup phase completes
The StartupSpawnOrchestrator was blocking ALL bot spawning once
startup phases completed (Phase 5 = COMPLETED). This prevented:
- Warm pool bots from logging in for BG queues
- JIT bots from spawning for on-demand content
- Any runtime spawn requests

The orchestrator now checks if the priority queue has items in
COMPLETED phase and allows spawning to proceed. This enables:
- Warm pool bot login: bots already queued for spawn via BotSpawner
- Runtime spawning: new bot requests after startup
- BG queue population: bots can now actually join queues

Evidence from logs showed:
- "BG shortage fully satisfied from warm pool" (bots selected)
- "Queued pool bot Player-1-XXXX for login via BotSpawner"
- But "Phase 2 throttling active - spawn deferred" (blocked!)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-04 20:33:02 -03:00
agathoandClaude Opus 4.5 cc9da83744 fix(botai): Use cached GUID in destructor to prevent dangling pointer crash
BotAI::~BotAI() was accessing _bot->GetGUID() for blackboard cleanup,
but during destruction _bot may be a dangling pointer to already-freed
memory. This caused ACCESS_VIOLATION crashes (C0000005) during bot
session destruction.

The fix uses _cachedBotGuid (captured in constructor) instead, following
the same safe pattern already used in UnsubscribeFromEventBuses().

Root cause: Race condition where Player object is destroyed before BotAI
destructor completes blackboard cleanup.

Evidence from crash logs:
- "Removed bot blackboard for Player-1-214CB312020" (hex pointer value)
- "AFKSimulator::OnShutdown - Bot  AFK simulator shutdown" (empty name)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-04 20:30:43 -03:00
agathoandClaude Opus 4.5 352e74d705 feat(playerbot): WoW 12.0 PvP spell utilities and documentation update
Implements SpellPvpModifier and SpellAttr16 support for WoW 12.0:

PvP Spell Utilities (new PvPSpellUtils.h):
- GetPvPMultiplier() accessing SpellEffectEntry::PvpMultiplier from DB2
- ApplyPvPModifier() for PvP damage/healing adjustments
- SpellAttr16 infrastructure (all 32 flags currently UNK)
- PvP combat detection and spell damage estimation
- SpellPvpModifier type classification

PvPCombatAI Enhancements:
- Enhanced EstimateDPS() with PvP-aware calculations
- Added HasBurstCooldownActive() for offensive cooldown detection
- Integrated PvPSpellUtils for accurate damage estimation

InterruptManager Updates:
- Added HasSpellAttr16() and HasAnySpellAttr16() methods
- Added GetPvPInterruptMultiplier() for priority calculation
- Added IsPvPHighPriorityInterrupt() for target selection

Documentation Updates (11.2 → 12.0):
- Updated 30+ files with version references
- C++ source comments, header documentation
- SQL schema version comments and defaults
- Configuration files and markdown docs
- Preserved statistical data values unchanged

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-04 20:29:58 -03:00
agathoandClaude Opus 4.5 f15786ab15 docs: Update WoW 12.0 migration checklist with completed status
Mark all Phase 1-3 migration tasks as complete:
- Difficulty type migration (uint8 → int16)
- Stats/Spirit support (MAX_STATS = 5)
- File renames (WoW112 → WoW120)
- Namespace updates (WoW112Spells → WoW120Spells)
- Comment updates (11.2 → 12.0)
- Item Squish verified (handled transparently by TrinityCore)

Remaining optional enhancements:
- SpellAttr16 checks
- Housing map exclusions

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-04 20:28:56 -03:00
agathoandClaude Opus 4.5 a2b3d67321 feat(playerbot): WoW 12.0 migration - Update version references and file names
BREAKING CHANGE: Renamed WoW112* files to WoW120* variants

Migration changes:
- Rename WoW112CharacterCreation.h to WoW120CharacterCreation.h
- Rename ResourceTypes_WoW112.h to ResourceTypes_WoW120.h
- Rename SpellValidation_WoW112.h to SpellValidation_WoW120.h
- Rename SpellValidation_WoW112_Part2.h to SpellValidation_WoW120_Part2.h
- Rename CombatSpecializationTemplate_WoW112.h to WoW120 variant
- Rename ResourceSystemWoW112.md to WoW120 variant
- Update WoW112Spells namespace to WoW120Spells in all files
- Update all include paths from WoW112 to WoW120
- Update comments referencing "11.2" to "12.0"
- Add Spirit stat to BaseStats (MAX_STATS = 5 in WoW 12.0)
- Update Difficulty enum types from uint8 to int16

Part of WoW 12.0 API migration (TrinityCore commit b0a596908d5c1b5b09f90e97b17a7fc785e5366f)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-04 20:28:17 -03:00
agathoandClaude Opus 4.5 ac473ee5dc feat(playerbot): Add Spirit stat support for WoW 12.0 migration
- Rename WoW112CharacterCreation.h to WoW120CharacterCreation.h
- Add Spirit stat to BaseStats struct (MAX_STATS = 5 in WoW 12.0)
- Set Spirit values: 18 for melee, 28 for casters, 25 for hybrids
- Update CMakeLists.txt to reference new header file
- Update BotCharacterCreator.cpp include path

Part of WoW 12.0 API migration (commit b0a596908d5c1b5b09f90e97b17a7fc785e5366f)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-04 20:26:50 -03:00
agathoandClaude Opus 4.5 318c198b66 refactor(12.0): Update Difficulty enum type from uint8 to int16
TrinityCore 12.0 changed the core Difficulty enum from uint8 to int16.
This commit updates all Playerbot module enums and function signatures
to match:

- InstanceFarmingManager.h: InstanceDifficulty enum
- RaidState.h: RaidDifficulty enum
- DungeonState.h: DungeonDifficulty enum
- GroupEvents.h/cpp: DifficultyChanged() parameter
- PlayerbotGroupScript.h: GroupStateSnapshot difficulty fields
- PlayerbotGroupScript.cpp: Difficulty casts
- PlayerBotHooks.cpp: GroupEvent difficulty cast

Also adds comprehensive WOW_12_0_MIGRATION_ANALYSIS.md documenting:
- Critical API changes (Stats, Difficulty, Items, Spells)
- Files requiring updates
- Migration task plan

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-04 20:25:58 -03:00
agathoandClaude Opus 4.5 38c85f0a05 fix(eventbus): Prevent dangling pointer crash during bot cleanup
During bot destruction, the Player object may be destroyed before
the BotAI destructor runs, causing _bot to become a dangling pointer.
When UnsubscribeFromEventBuses() tries to access _bot->GetGUID(),
it crashes with ACCESS_VIOLATION at GenericEventBus.h line 277.

Fix:
- Add _cachedBotGuid member to BotAI, initialized at construction
- Add UnsubscribeByGuid() method to GenericEventBus template
- Update UnsubscribeFromEventBuses() to use cached GUID directly
  via EventBus<T>::instance()->UnsubscribeByGuid(_cachedBotGuid)

This ensures safe cleanup even when Player is already destroyed.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-04 20:25:02 -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 b8baf73d19 fix(instance): Disable QuestStrategy for instance bots
Instance bots (JIT bots for BG/dungeon) should NEVER run quest behavior.
This was causing crashes when:
1. Bot worker thread calls QuestAcceptanceManager::AcceptQuest
2. SmartAI::OnQuestAccept is triggered
3. SmartScript (not thread-safe) crashes with memory corruption

Fix: Check IsInstanceBot() in both IsActive() and GetRelevance() to
completely disable quest strategy for instance bots.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-04 20:23:22 -03:00
agathoandClaude Opus 4.5 5d09867066 fix(map): Add safety checks to prevent null map crash in AddUpdateObject
Added null pointer validation to:
- WorldObject::AddToObjectUpdate() - validates GetMap() before calling
- WorldObject::RemoveFromObjectUpdate() - same validation
- Map::AddUpdateObject() - validates object pointer
- Map::RemoveUpdateObject() - same validation

These checks prevent potential crashes from memory corruption scenarios
where the Map pointer or object pointer could be invalid.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-04 20:22:44 -03:00
agathoandClaude Opus 4.5 5eeaa84d8c fix(eventbus): Fix use-after-free crash in DispatchEvent (line 759)
Previous implementation validated handlers with lock held, then released
the lock before dispatching. This created a race window where another
thread could delete the BotAI between validation and dispatch, causing
ACCESS_VIOLATION crash.

Windows SEH exceptions (like access violations) are NOT caught by C++
catch(...), so the server crashes immediately.

Fix: Hold the recursive mutex during dispatch. This is safe because:
1. _subscriptionMutex is recursive - handlers can call Unsubscribe()
2. Single lock acquisition for entire dispatch phase
3. No race window between validation and dispatch

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-04 20:20:51 -03:00
agathoandClaude Opus 4.5 ecec2fdf9e fix(instance): Add queue timeout to prevent instance bot accumulation
Problem: Instance bots sitting in BG queue were considered "active" and never
timed out. If the BG never popped (not enough players), bots accumulated
indefinitely, causing "HARD CAP REACHED" errors (563 bots when only 19 requested).

Root cause:
- IsInActiveInstanceState() returns true for bots in BG/LFG queue
- Active bots never trigger idle timeout
- If BG never starts, bots wait in queue forever

Solution: Add a 5-minute queue timeout separate from idle timeout:
- Track _queueAccumulatorMs - time spent waiting in queue
- Track _hasEnteredInstance - whether bot actually entered content
- If bot is in queue for >5 minutes without entering instance → logout

New member variables:
- _instanceBotStartTime: when bot was marked as instance bot
- _queueAccumulatorMs: accumulated queue wait time
- _hasEnteredInstance: true once bot enters dungeon/BG/arena

Constants:
- INSTANCE_BOT_IDLE_TIMEOUT_MS = 60s (existing)
- INSTANCE_BOT_QUEUE_TIMEOUT_MS = 5 minutes (new)

This prevents bot explosion when BGs don't pop due to population imbalance.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-04 20:20:00 -03:00
agathoandClaude Opus 4.5 61d7aec8f5 fix(warmpool): Handle already-online bots in WarmUpBot - queue directly for BG
Root cause: When warm pool bots were already logged in, BotSpawner::SpawnBot()
would return failure (bot already in _botSessions). WarmUpBot treated this as
a failure and moved bots to Maintenance, so they never queued for BG.

The fix: At the start of WarmUpBot, check if bot is already online via
ObjectAccessor::FindPlayer(). If so:
- Mark as instance bot
- Queue directly for BG using BGBotManager::QueueBotForBG()
- Set slot state to Assigned
- Call OnBotWarmupComplete(true)
- Return early (skip spawning)

This ensures warm pool bots that are already online get properly queued
for battlegrounds instead of being moved to Maintenance.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-04 20:19:02 -03:00
agathoandClaude Opus 4.5 6c812394cb fix(jit): Fix instance bot marking timing - defer until session exists
The issue: AddPlayerBot() only queues spawn to _pendingSpawns and returns
immediately. MarkAsInstanceBot() was called right after, but the session
doesn't exist yet, causing "session not found" errors and bots not being
properly tracked as instance bots.

The fix:
- Add markAsInstanceBot field to BotPendingConfiguration
- Set markAsInstanceBot=true in BotCloneEngine and InstanceBotPool
- Apply marking in BotPostLoginConfigurator::ApplyPendingConfiguration()
  AFTER the session is guaranteed to exist
- Remove premature MarkAsInstanceBot() call from JITBotFactory

This ensures JIT/warm pool bots get:
- Proper idle timeout (60 seconds)
- Restricted behavior (no questing, BattlePetManager, etc.)
- Correct instance bot tracking

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-04 20:18:24 -03:00
agathoandClaude Opus 4.5 8ea5a7ffd2 fix(bg): Fix BG queue count using wrong data source (selection pool vs queued groups)
ROOT CAUSE: QueueStatePoller was using BattlegroundQueue::GetPlayersInQueue()
which returns from m_SelectionPools (populated during matchmaking), not from
m_QueuedGroups (the actual queue). This caused the system to always see 0
players in queue even after bots were successfully queued.

SYMPTOMS:
- Bots logged "Successfully queued for BG" but next poll showed 0/10 in queue
- BG queue population kept trying to fill already-filled queues
- BGs took forever to start due to count mismatch

FIX:
- Added GetQueuedPlayersCount(teamId, bracketId) to BattlegroundQueue
- This function iterates m_QueuedGroups for the specific bracket and team
- Only counts players not already invited to a BG instance
- Updated QueueStatePoller to use the new function instead of GetPlayersInQueue()

TESTING: Verified bots are queued and count now reflects actual queued players

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-04 20:15:46 -03:00
agathoandClaude Opus 4.5 cd96407829 perf(managers): Skip non-essential systems for instance bots
Instance bots (warm pool, JIT) are single-purpose bots for BG/Arena/
Dungeon/Raid content. They don't need world-bot systems.

GameSystemsManager - skip for instance bots:
- HumanizationManager (AFK behavior, breaks)
- BattlePetManager (pet battles)
- BankingManager (personal banking)
- ProfessionManager (crafting)
- GatheringManager (mining, herbalism)
- All auction/profession bridges
- MountManager, RidingManager
- FarmingCoordinator

SoloStrategy - disabled for instance bots:
- Questing, grinding, gathering, exploration
- Instance bots focus on their instance content instead

Managers kept for instance bots:
- TradeManager (repairs)
- GroupCoordinator (group mechanics)
- ArenaAI, PvPCombatAI (PvP combat)
- EquipmentManager (they get leveled and geared)
- EventDispatcher, ManagerRegistry (core systems)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-04 20:13:48 -03:00
agathoandClaude Opus 4.5 26345fdb81 fix(pool): Fix warm pool bots not queuing for BG after login
Warm pool bots were being "assigned" to BG but never actually queued
because they weren't in the world when QueueStatePoller tried to call
ObjectAccessor::FindPlayer(). The bots were in "login in progress" state.

Fix: WarmUpBot now reads the contentId and instanceType from the slot
(set by AssignBot) and includes them in BotPendingConfiguration. After
the bot logs in, BotPostLoginConfigurator queues them for the BG/dungeon.

This applies the same pattern used for JIT bots - deferred queueing
after login instead of immediate queueing.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-03 21:32:14 -03:00
agathoandClaude Opus 4.5 681d2be68e fix(jit): Fix JIT bots not queuing for battlegrounds
JIT-created bots were never being queued for BG because the onComplete
callback tried to use ObjectAccessor::FindPlayer() before bots entered
the world. Replaced direct callback queueing with deferred post-login
queueing via BotPostLoginConfigurator (same pattern as LFG dungeons).

Changes:
- BotPostLoginConfigurator: Implement BG queueing after bot login
- QueueStatePoller: Use battlegroundIdToQueue field instead of callback

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-03 21:31:24 -03:00
agathoandClaude Opus 4.5 e136047f18 fix(maps): Prevent use-after-free crash in Map::SendObjectUpdates
Three-layer defense against dangling pointers in _updateObjects:

1. BotWorldSessionMgr: Call SetDestroyedObject(true) early in
   RemovePlayerBot() before clearing update mask

2. BaseEntity: Block re-adding to _updateObjects once marked destroyed
   by checking !m_isDestroyedObject in AddToObjectUpdateIfNeeded()

3. Map: Add IsDestroyedObject() check before BuildUpdate() as final
   safety net for partially corrupted objects

Also fix BG bot count calculation in QueueStatePoller to use
maxPlayersPerTeam instead of minPlayersPerTeam (15v15 for SotA
instead of 5v5)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-03 21:29:55 -03:00
agathoandClaude Opus 4.5 df8bea884e fix(bg): Allow BG tactics to interrupt follow mode in battlegrounds
ROOT CAUSE: Bots in groups were just following the master instead of
executing battleground tactics because MoveToPosition() refused to
interrupt FOLLOW_MOTION_TYPE movement.

When a grouped bot enters a battleground:
1. Bot has FOLLOW_MOTION_TYPE active (following group leader)
2. BG AI calls MoveToPosition() to send bot to flag/objective
3. MoveToPosition() sees FOLLOW_MOTION_TYPE and returns false
4. Bot keeps following master, ignoring all BG tactics

SOLUTION: Add battleground exception to FOLLOW_MOTION_TYPE check.
When bot is in an active battleground (STATUS_IN_PROGRESS), the
BG movement is allowed to clear follow motion and take over.

This allows BG tactics (flag capture, defense, etc.) to work
while preserving follow behavior for normal group play outside BGs.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-03 21:28:33 -03:00
StorM 50d9687457 fix compile linux 2026-02-02 17:52:31 +01:00
agathoandClaude Opus 4.5 b60bcc4c91 fix(eventbus): Fix use-after-free crash in DispatchEvent (line 741)
ROOT CAUSE: The crash occurred when dispatching events to handlers that
had been deleted between validation and dispatch. This was triggered when
Arathi Basin battleground ended - players are removed and their BotAI
objects deleted while events are still being dispatched.

The previous validation at line 730 only checked if the GUID existed in
_subscriberPointers, but did NOT validate that the pointer was still the
same. This allowed three failure modes:
1. Bot unsubscribed (GUID removed) - correctly skipped
2. Bot deleted and REPLACED with new bot at same GUID - dispatched to WRONG object!
3. Bot deleted but GUID not yet removed from map - dispatched to FREED memory! (CRASH)

SOLUTION: Store the original BotAI* pointer alongside the handler and validate
BOTH GUID existence AND pointer match during the second validation pass.
This catches cases 2 and 3 where the underlying object has changed.

Changes:
- handlersToDispatch now stores struct with {guid, botAI*, handler*}
- Validation now checks: it->second == info.botAI (pointer match)
- Added catch(...) block to catch any remaining edge cases

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-02 13:45:31 -03:00
agathoandClaude Opus 4.5 bc739e0c8d fix(threadpool): Fix counter mismatch root cause - memory ordering bug
ROOT CAUSE: The counter mismatch ("1 in-flight, 0 active workers") was
caused by incorrect memory ordering. totalSubmitted and totalCompleted
were using memory_order_relaxed for writes, but WaitForCompletion used
memory_order_acquire for reads. With relaxed writes and acquire reads,
there's no happens-before relationship - the acquire load doesn't
synchronize with relaxed stores.

SOLUTION: Changed all writes to totalSubmitted and totalCompleted to use
memory_order_release. Combined with the acquire reads in WaitForCompletion,
this creates proper synchronization via the release-acquire pattern.

Changes:
- ThreadPool.h Submit(): totalSubmitted now uses release ordering
- ThreadPool.h Submit() failure path: totalCompleted now uses release
- ThreadPool.cpp RecordTaskCompletion(): totalCompleted uses release
- ThreadPool.cpp outer catch: totalCompleted uses release
- ThreadPool.cpp WaitForCompletion auto-correction: uses release

This should eliminate the "ghost counter" issue that required the
auto-correction workaround added in the previous commit.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-02 13:44:34 -03:00
agathoandClaude Opus 4.5 cb683ef67a fix(threading): Add counter mismatch auto-correction in ThreadPool
Root cause identified: The "1 in-flight, 0 active workers" timeout
was caused by a counter mismatch where totalSubmitted > totalCompleted
even though all tasks had actually finished. This can happen if an
exception occurs during task submission that doesn't properly update
the completed counter.

Solution: In WaitForCompletion(), detect the mismatch condition:
- All queues are empty
- All workers are sleeping (0 active)
- But counters show in-flight tasks

When detected, log a warning and correct the counters to prevent
the permanent 10-second timeout on every update cycle.

This is a workaround - the real fix would be to ensure all code
paths properly maintain counter balance. But this prevents the
timeout from blocking bot updates indefinitely.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-02 13:36:49 -03:00
agathoandClaude Opus 4.5 3013dfd1cf diag(threading): Add debug logging to RegisterTaskStart
Added periodic logging (every 100 registrations) to verify that
RegisterTaskStart is actually being called. This helps diagnose why
"0 tasks tracked" is showing despite tasks being in-flight.

Also improved LogStuckTasks to always output a summary showing
total tracked and stuck count for better diagnostics.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-02 13:35:32 -03:00
agathoandClaude Opus 4.5 cd2f95ff2a fix(threading): Fix in-flight counter and improve stuck task detection
1. ThreadPool counter fix:
   - The outer catch block in WorkerThread::Run() was only updating
     the per-worker counter, not the pool's totalCompleted
   - This caused GetInFlightTasks() to return permanently inflated
     values when exceptions occurred (explaining "1 in-flight, 0 active
     workers" with all tasks done)
   - Now properly updates pool counter in outer catch

2. Improved stuck task detection:
   - LogStuckTasks now always outputs a summary showing how many tasks
     are tracked and how many are stuck
   - This helps diagnose whether tasks are being registered properly

Expected fix: The "1 in-flight, 0 active workers" issue should no longer
occur if the root cause was exception handling leaving the counter in
an inconsistent state.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-02 13:34:40 -03:00
agathoandClaude Opus 4.5 9b830878a9 diag(threading): Add stuck task detection for ThreadPool timeouts
When ThreadPool wait times out (>2s), we now log which specific bot(s)
are stuck. This helps identify:
- Deadlocks within bot update tasks
- Infinite loops in AI subsystems
- Slow operations (pathfinding, database, etc.)

Implementation:
- Added thread-safe registry tracking executing bot tasks
- RAII guard ensures tasks are always unregistered on exit
- LogStuckTasks() called at 2s warning and 10s timeout
- Logs bot name and GUID with execution time

Example output:
  STUCK TASK DETECTED: Bot Anderenz (GUID: Player-XXX) has been
  executing for 5432ms!

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-02 13:32:37 -03:00
StorM a667499035 fix compile linux 2026-02-02 17:32:30 +01:00
StorM 38cd4dfe71 fix compile linux 2026-02-02 17:32:28 +01:00
agathoandClaude Opus 4.5 c986da9c77 perf(mmap): Cache failed MMAP load attempts to prevent repeated retries
Similar to the VMAP fix, this caches failed MMAP load attempts using a
bitset per TerrainInfo instance. This prevents the server from repeatedly
attempting to load MMAP tiles that don't exist (e.g., unused dungeon maps,
boost experience maps, etc.), which was causing significant slowdowns.

Changes:
- Add _mmapLoadFailed bitset to TerrainInfo class
- Skip LoadMMapImpl early if grid already marked as failed
- Cache FileNotFound, VersionMismatch, ReadFromFileFailed, and
  LibraryError results
- Change expected "FileNotFound" log level from WARN to DEBUG
- Update analysis documentation with fix status

Impact: Near-instant returns for grids with missing MMAP data instead of
repeated file I/O attempts.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-02 13:31:23 -03:00
agathoandClaude Opus 4.5 cfe60008d5 perf(vmap): Cache failed VMAP load attempts to prevent repeated retries
Problem: VMAP loading for maps without data (Boost Experience, phased zones,
newer dungeons) was retried on EVERY access, causing:
- Thousands of file access attempts per session
- Log spam with "Could not load VMAP" errors
- Server slowdown from repeated disk I/O

Solution: Added _vmapLoadFailed bitset to TerrainInfo that caches failed
VMAP load attempts, similar to existing _gridFileExists pattern for maps.

Changes:
- TerrainMgr.h: Added _vmapLoadFailed bitset
- TerrainMgr.cpp: Check bitset before load, cache failures, reduce log level

Maps affected: 1949, 1950 (8.0 Boost), 1554, 1557 (7.0 Boost), 1465 (Tanaan),
2648, 2649, 2662, 2669 (TWW dungeons), and others without VMAP data.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-02 13:29:41 -03:00
agathoandClaude Opus 4.5 66ecfc7a2f perf(threading): Fix extreme lag with lock contention and throttling optimizations
Root cause analysis identified cumulative lock contention causing severe lag
after humanization implementation. Applied comprehensive fixes:

GenericEventBus (CRITICAL):
- Changed lock-per-handler pattern to single lock acquisition
- Reduced mutex acquisitions from 100+ per event to 2
- ~50x improvement in event dispatch performance

GameSystemsManager (HIGH):
- Added throttle timers to 11 managers updating every frame
- Mount (200ms), Riding (5s), BattlePet (500ms), ArenaAI (100ms)
- PvPCombat (100ms), Auction (5s), Banking (5s), bridges (2-5s)
- ~30x reduction in manager updates per second

SpatialGridManager (MEDIUM):
- Added double-checked locking to CreateGrid()
- Added optimized GetOrCreateGrid() method
- Eliminates thundering herd on 90+ call sites

CombatEventRouter (MEDIUM):
- Replaced mutex-protected stats map with lock-free atomic array
- Zero lock contention for per-type statistics

Map.cpp:
- Changed ASSERT to graceful skip for race condition in SendObjectUpdates

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-02 13:28:56 -03:00
agathoandClaude Opus 4.5 22e6d29ddc fix(spatial): Fix data race and performance issues in SpatialGridManager
PROBLEM: Extreme lag with 100+ bots caused by SpatialGridManager issues:

1. DATA RACE BUG in GetGrid():
   - Writing lastAccessTime under shared_lock using const_cast
   - Multiple threads writing same memory location concurrently = undefined behavior
   - Could cause crashes, memory corruption, or silent data corruption

2. PERFORMANCE ISSUE in GetGrid():
   - Called thousands of times per second (100+ bots × multiple calls per update)
   - Each call: acquire shared_lock + chrono::steady_clock::now()
   - Unnecessary overhead for a keep-alive timestamp that's rarely checked

3. Same issues in UpdateGrid() and TouchGrid()

SOLUTION:

1. GetGrid(): Remove lastAccessTime update entirely
   - This method is for READ-ONLY grid access
   - lastAccessTime is only used for cleanup of inactive grids
   - No need to update on every access

2. UpdateGrid(): Split into 3 phases
   - Phase 1: Get grid pointer under shared_lock (fast)
   - Phase 2: Update grid WITHOUT holding manager lock
   - Phase 3: Update lastAccessTime under exclusive lock

3. TouchGrid(): Use unique_lock (exclusive) for write operation
   - This method explicitly updates lastAccessTime
   - Must use exclusive lock for write operations

IMPACT:
- Eliminates ~1000+ chrono::now() calls per second
- Fixes potential memory corruption from data race
- Reduces lock contention on SpatialGridManager

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-02 13:27:52 -03:00
agathoandClaude Opus 4.5 5e9d455b5c fix(pool): Fix InstanceBotPool account_id persistence and login failures
PROBLEM 1: "Pool bot failed to login via BotSpawner"
- Bots in maintenance state after warmup failure

PROBLEM 2: "No account ID for bot (not in slot or CharacterCache)"
- Bots with account_id = 0 in playerbot_instance_pool table
- CharacterCache doesn't have the account association

ROOT CAUSE:
The ON DUPLICATE KEY UPDATE clause in SyncToDatabase() did NOT include
`account_id`, so:
1. Bot initially saved with account_id = 0 (bug in some code path)
2. WarmUpBot corrects it from CharacterCache and updates the slot
3. SyncToDatabase INSERTs the correct account_id, BUT
4. ON DUPLICATE KEY UPDATE doesn't update account_id column
5. On restart, LoadFromDatabase loads account_id = 0 again

SOLUTION:
1. Add `account_id = VALUES(account_id)` to ON DUPLICATE KEY UPDATE
   - Now account_id corrections are persisted properly

2. Add account_id repair in LoadFromDatabase()
   - If account_id = 0, try to get it from CharacterCache
   - Log warning if CharacterCache also has no account

This ensures bots with previously corrupted account_id values
will be repaired on next load and the fix will be persisted.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-02 13:26:40 -03:00
agathoandClaude Opus 4.5 323ff2021f perf(quest): Fix mutex contention in QuestCompletion with shared_mutex
PROBLEM: QuestCompletion used std::mutex for read-heavy data structures
which blocked ALL readers when ANY read was happening. With 100+ bots
calling quest-related functions from ThreadPool workers, this caused
severe lock contention and task delays.

AFFECTED MUTEXES (all read-heavy patterns):
- _pausedBotsMutex: Checked on EVERY quest event (HandleQuestEvent)
- _questOrderMutex: Read frequently during quest prioritization
- _objectiveOrderMutex: Read during objective sequencing

SOLUTION:
1. Changed _pausedBotsMutex from std::mutex to std::shared_mutex
   - Read operations (find) use std::shared_lock (concurrent readers OK)
   - Write operations (insert/erase) use std::unique_lock (exclusive)

2. Changed _questOrderMutex from std::mutex to std::shared_mutex
   - All operations use std::unique_lock (mostly writes in current code)
   - Future optimization: use shared_lock for read-only accesses

3. Changed _objectiveOrderMutex from std::mutex to std::shared_mutex
   - All operations use std::unique_lock (writes only currently)

This eliminates a major ThreadPool bottleneck where every bot's
quest event processing was blocking on mutex acquisition.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-02 13:26:00 -03:00
agathoandClaude Opus 4.5 018de94dc3 perf(humanization): Fix mutex contention in HumanizationConfig
PROBLEM: HumanizationConfig used std::mutex which blocked ALL readers
when ANY read was happening. With 100+ concurrent bots calling
GetActivityConfig() and GetHourlyActivityMultiplier() from ThreadPool
workers, this caused severe lock contention and task delays.

SOLUTION:
1. Changed std::mutex to std::shared_mutex for read-heavy access
2. Use std::unique_lock only during Load()/Reload() (rare operation)
3. Use std::shared_lock for GetActivityConfig() (multiple readers OK)
4. Made GetHourlyActivityMultiplier() lock-free since _hourlyMultipliers
   is set once during Load() and never modified at runtime
5. Changed C-array to std::array<float, 24> for better type safety

This eliminates a major ThreadPool bottleneck where every bot's
HumanizationManager::Update() was blocking on mutex acquisition.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-02 13:24:54 -03:00
agathoandClaude Opus 4.5 7c68c7b4d0 fix(threadpool): Prevent FreezeDetector crash with shorter timeouts
Root cause: ThreadPool::WaitForCompletion could block world thread for
35+ seconds (5s + 30s), leaving insufficient buffer before FreezeDetector
triggers at 60 seconds. Combined with other World::Update operations,
total time exceeded 60s causing forced crash.

Changes:
- BotWorldSessionMgr: Reduce wait timeouts from 5s+30s to 2s+8s (10s max)
- ThreadPool::WaitForCompletion: Add hard cap of 15 seconds regardless
  of caller-specified timeout
- ThreadPool.h: Change default timeout from milliseconds::max() to 10s

This ensures world thread never blocks more than 15 seconds in
WaitForCompletion, leaving 45+ seconds buffer for FreezeDetector.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-02 13:23:11 -03:00
luis 8ce4578e85 typo fix and add blizzlike fixes 2026-02-02 00:47:02 -03:00
luis 5504081897 blizzlike boss 2026-02-01 21:38:43 -03:00
luis 78c9561f7d init boss merge 2026-02-01 21:11:34 -03:00
Shauren bcf0f246bd Core/SAI: Remove unused field
Signed-off-by: luis <[email protected]>
2026-02-01 20:47:51 -03:00
luis 52b123a173 more logs to debug 2026-02-01 18:39:30 -03:00
luis 52251aac69 debug log 2026-02-01 18:19:31 -03:00
Aqua Deus d23e0a29ad Scripts/Spells: Implement dh talent "Shattered Restoration" (#31507)
Signed-off-by: luis <[email protected]>
2026-02-01 17:47:00 -03:00
Cristian Vintila 407bbb59a7 Scripts/Spells: Implement Rake stealth stun and multiplier (#31511)
Signed-off-by: luis <[email protected]>
2026-02-01 17:46:07 -03:00
Cristian Vintila dff034f0d1 Scripts/Spells: Use form-dependent bleed spells for druid spell Thrash (#31513)
Signed-off-by: luis <[email protected]>
2026-02-01 17:45:27 -03:00
Shauren 6c06fb77f4 Core/VMaps: Fixed loading vmap tiles that have destructible buildings on them
Closes #31649

Signed-off-by: luis <[email protected]>
2026-02-01 17:44:22 -03:00
Shauren 3636899681 Core/VMaps: Optimize vmap tile unload
Signed-off-by: luis <[email protected]>
2026-02-01 17:43:45 -03:00