fix: Replace static m_botReleaseTimes with per-bot storage to prevent race condition

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 <noreply@anthropic.com>
This commit is contained in:
root
2025-10-06 11:22:45 +11:00
parent d26c2a3549
commit c90b155a70
3 changed files with 7 additions and 9 deletions

View File

@@ -601,6 +601,7 @@ public:
NewRpgInfo rpgInfo;
NewRpgStatistic rpgStatistic;
std::unordered_set<uint32> lowPriorityQuest;
time_t bgReleaseAttemptTime = 0;
// Schedules a callback to run once after <delayMs> milliseconds.
void AddTimedEvent(std::function<void()> callback, uint32 delayMs);

View File

@@ -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;
}

View File

@@ -38,7 +38,6 @@ private:
bool ShouldAutoRelease() const;
bool ShouldDelayBattlegroundRelease() const;
inline static std::unordered_map<uint32_t, time_t> m_botReleaseTimes;
time_t m_bgGossipTime = 0;
};