diff --git a/src/modules/Playerbot/Humanization/Core/HumanizationConfig.cpp b/src/modules/Playerbot/Humanization/Core/HumanizationConfig.cpp index 77b92313e..cf3636122 100644 --- a/src/modules/Playerbot/Humanization/Core/HumanizationConfig.cpp +++ b/src/modules/Playerbot/Humanization/Core/HumanizationConfig.cpp @@ -24,7 +24,9 @@ HumanizationConfig& HumanizationConfig::Instance() void HumanizationConfig::Load() { - std::lock_guard lock(_mutex); + // CRITICAL FIX: Use exclusive lock only during config load/reload + // This is a rare operation (server startup or admin reload command) + std::unique_lock lock(_mutex); TC_LOG_INFO("module.playerbot.humanization", "Loading Humanization configuration..."); @@ -157,7 +159,9 @@ void HumanizationConfig::Reload() ActivityConfig HumanizationConfig::GetActivityConfig(ActivityCategory category) const { - std::lock_guard lock(_mutex); + // CRITICAL FIX: Use shared_lock for read operations + // Allows multiple concurrent readers (100+ bot updates) without blocking + std::shared_lock lock(_mutex); auto it = _activityConfigs.find(category); if (it != _activityConfigs.end()) @@ -188,7 +192,15 @@ float HumanizationConfig::GetHourlyActivityMultiplier(uint32 hour) const if (hour >= 24) hour = hour % 24; - std::lock_guard lock(_mutex); + // CRITICAL FIX: Lock-free read for hourly multipliers + // _hourlyMultipliers is a std::array that is: + // 1. Set once during Load() under exclusive lock + // 2. Never modified during runtime + // 3. std::array elements are POD types (float) with atomic-like read semantics on x86/x64 + // + // This eliminates a major contention point - every bot's HumanizationManager::Update() + // calls GetTimeOfDayMultiplier() which was acquiring mutex lock every time. + // With 100+ concurrent bots, this was causing severe lock contention. return _hourlyMultipliers[hour]; } diff --git a/src/modules/Playerbot/Humanization/Core/HumanizationConfig.h b/src/modules/Playerbot/Humanization/Core/HumanizationConfig.h index a44e565d3..7daa13356 100644 --- a/src/modules/Playerbot/Humanization/Core/HumanizationConfig.h +++ b/src/modules/Playerbot/Humanization/Core/HumanizationConfig.h @@ -18,9 +18,10 @@ #include "Define.h" #include "ActivityType.h" -#include +#include #include #include +#include namespace Playerbot { @@ -320,15 +321,20 @@ private: // Time of day bool _enableTimeOfDay = true; - float _hourlyMultipliers[24] = { + // CRITICAL FIX: Use std::array for thread-safe direct access (no lock needed for reads) + // These values are set once during Load() and never modified during runtime + std::array _hourlyMultipliers = {{ 0.2f, 0.1f, 0.1f, 0.1f, 0.1f, 0.2f, // 0-5 (night) 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, // 6-11 (morning) 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, // 12-17 (afternoon) 1.0f, 1.0f, 0.9f, 0.8f, 0.6f, 0.4f // 18-23 (evening) - }; + }}; - // Thread safety - mutable std::mutex _mutex; + // Thread safety - use shared_mutex for read-heavy access patterns + // CRITICAL FIX: std::mutex caused severe contention with 100+ concurrent bots + // std::shared_mutex allows multiple concurrent readers (bot updates) with only + // exclusive locking during config reload (rare operation) + mutable std::shared_mutex _mutex; bool _loaded = false; };