From c90b155a70f02dc8d30b4347dd4ad23dc45e8b8f Mon Sep 17 00:00:00 2001 From: root Date: Mon, 6 Oct 2025 11:22:45 +1100 Subject: [PATCH] fix: Replace static m_botReleaseTimes with per-bot storage to prevent race condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes a thread safety issue where multiple bots dying in battlegrounds simultaneously would corrupt the shared static unordered_map, causing segmentation faults. Changes: - Remove: static m_botReleaseTimes map from AutoReleaseSpiritAction - Add: bgReleaseAttemptTime member to PlayerbotAI (per-bot storage) - Update: All references to use per-bot storage instead of static map Why this fixes the crash: - Each PlayerbotAI instance is accessed by only one map update thread - No cross-thread access to shared data structures - No mutex/locking required - thread-safe by design - Automatic cleanup when bot is destroyed Thread-safe solution: Per-bot state eliminates race conditions without performance overhead. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/PlayerbotAI.h | 1 + src/strategy/actions/ReleaseSpiritAction.cpp | 14 ++++++-------- src/strategy/actions/ReleaseSpiritAction.h | 1 - 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/PlayerbotAI.h b/src/PlayerbotAI.h index 04deae3a..180606e8 100644 --- a/src/PlayerbotAI.h +++ b/src/PlayerbotAI.h @@ -601,6 +601,7 @@ public: NewRpgInfo rpgInfo; NewRpgStatistic rpgStatistic; std::unordered_set lowPriorityQuest; + time_t bgReleaseAttemptTime = 0; // Schedules a callback to run once after milliseconds. void AddTimedEvent(std::function callback, uint32 delayMs); diff --git a/src/strategy/actions/ReleaseSpiritAction.cpp b/src/strategy/actions/ReleaseSpiritAction.cpp index 0d725f74..666e42ab 100644 --- a/src/strategy/actions/ReleaseSpiritAction.cpp +++ b/src/strategy/actions/ReleaseSpiritAction.cpp @@ -192,12 +192,11 @@ bool AutoReleaseSpiritAction::ShouldDelayBattlegroundRelease() const { // The below delays release to spirit with 6 seconds. // This prevents currently casted (ranged) spells to be re-directed to the died bot's ghost. - const int32_t botId = bot->GetGUID().GetRawValue(); - // If the bot already is a spirit, erase release time and return true + // If the bot already is a spirit, reset release time and return true if (bot->HasPlayerFlag(PLAYER_FLAGS_GHOST)) { - m_botReleaseTimes.erase(botId); + botAI->bgReleaseAttemptTime = 0; return true; } @@ -205,14 +204,13 @@ bool AutoReleaseSpiritAction::ShouldDelayBattlegroundRelease() const const time_t now = time(nullptr); constexpr time_t RELEASE_DELAY = 6; - auto& lastReleaseTime = m_botReleaseTimes[botId]; - if (lastReleaseTime == 0) - lastReleaseTime = now; + if (botAI->bgReleaseAttemptTime == 0) + botAI->bgReleaseAttemptTime = now; - if (now - lastReleaseTime < RELEASE_DELAY) + if (now - botAI->bgReleaseAttemptTime < RELEASE_DELAY) return false; - m_botReleaseTimes.erase(botId); + botAI->bgReleaseAttemptTime = 0; return true; } diff --git a/src/strategy/actions/ReleaseSpiritAction.h b/src/strategy/actions/ReleaseSpiritAction.h index debeab84..57851214 100644 --- a/src/strategy/actions/ReleaseSpiritAction.h +++ b/src/strategy/actions/ReleaseSpiritAction.h @@ -38,7 +38,6 @@ private: bool ShouldAutoRelease() const; bool ShouldDelayBattlegroundRelease() const; - inline static std::unordered_map m_botReleaseTimes; time_t m_bgGossipTime = 0; };