From 5a6c54eab45eeec1495456f967dc69d09514ee01 Mon Sep 17 00:00:00 2001 From: jimm0thy <25890053+jimm0thy@users.noreply.github.com> Date: Mon, 24 Feb 2025 12:13:39 -0500 Subject: [PATCH 1/4] Ignore Friend Listed Bots Added option to ignore bots that are on a real player's friend list --- conf/mod_player_bot_level_brackets.conf.dist | 7 +++++++ src/mod-player-bot-level-brackets.cpp | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/conf/mod_player_bot_level_brackets.conf.dist b/conf/mod_player_bot_level_brackets.conf.dist index 9f0c9e4..741b8b4 100644 --- a/conf/mod_player_bot_level_brackets.conf.dist +++ b/conf/mod_player_bot_level_brackets.conf.dist @@ -34,6 +34,13 @@ BotLevelBrackets.UseDynamicDistribution = 0 # Default: 1.0 BotLevelBrackets.RealPlayerWeight = 1.0 +# +# BotLevelBrackets.IgnoreFriendListed +# Description: Ignore bots that are on real players friend's lists from any brackets +# Default: 1 (enabled) +# Valid values: 0 (off) / 1 (on) +BotLevelBrackets.IgnoreFriendListed = 1 + # # Alliance Level Brackets Configuration # The percentages below must sum to 100. diff --git a/src/mod-player-bot-level-brackets.cpp b/src/mod-player-bot-level-brackets.cpp index b1a159a..815fa45 100644 --- a/src/mod-player-bot-level-brackets.cpp +++ b/src/mod-player-bot-level-brackets.cpp @@ -15,6 +15,9 @@ #include #include #include "PlayerbotFactory.h" +#include "DatabaseEnv.h" +#include "QueryResult.h" + static bool IsAlliancePlayerBot(Player* bot); static bool IsHordePlayerBot(Player* bot); @@ -47,6 +50,7 @@ static uint32 g_BotDistCheckFrequency = 300; // in seconds static uint32 g_BotDistFlaggedCheckFrequency = 15; // in seconds static bool g_BotDistDebugMode = false; static bool g_UseDynamicDistribution = false; +static bool g_IgnoreFriendListed = true; // Real player weight to boost bracket contributions. static float g_RealPlayerWeight = 1.0f; @@ -59,6 +63,7 @@ static void LoadBotLevelBracketsConfig() g_BotDistFlaggedCheckFrequency = sConfigMgr->GetOption("BotLevelBrackets.CheckFlaggedFrequency", 15); g_UseDynamicDistribution = sConfigMgr->GetOption("BotLevelBrackets.UseDynamicDistribution", false); g_RealPlayerWeight = sConfigMgr->GetOption("BotLevelBrackets.RealPlayerWeight", 1.0f); + g_IgnoreFriendListed = sConfigMgr->GetOption("BotLevelBrackets.IgnoreFriendListed", true); // Load the bot level restrictions. g_RandomBotMinLevel = static_cast(sConfigMgr->GetOption("AiPlayerbot.RandomBotMinLevel", 1)); @@ -350,6 +355,20 @@ static bool IsBotSafeForLevelReset(Player* bot) } } } + // Lets ignore bots that have human friends + if (g_IgnoreFriendListed) + { + QueryResult result = CharacterDatabase.Query("SELECT COUNT(friend) FROM character_social WHERE friend IN (SELECT guid FROM characters WHERE name ='{}') and flags = 1", bot->GetName()); + uint32 friendCount = 0; + friendCount = result->Fetch()->Get(); + + if (friendCount >= 1) + { + LOG_INFO("server.loading", "[BotLevelBrackets] Bot {} (Level {}) is on a Real Player's friends list", bot->GetName(), bot->GetLevel()); + return false; + } + } + return true; } From 69e346e357cf84fed6c144cc9e64cbd55f2da8db Mon Sep 17 00:00:00 2001 From: jimm0thy <25890053+jimm0thy@users.noreply.github.com> Date: Mon, 24 Feb 2025 18:07:59 -0500 Subject: [PATCH 2/4] Added Option to Enable/Disable Mod --- conf/mod_player_bot_level_brackets.conf.dist | 6 + src/mod-player-bot-level-brackets.cpp | 1129 +++++++++--------- 2 files changed, 576 insertions(+), 559 deletions(-) diff --git a/conf/mod_player_bot_level_brackets.conf.dist b/conf/mod_player_bot_level_brackets.conf.dist index 741b8b4..4d96cef 100644 --- a/conf/mod_player_bot_level_brackets.conf.dist +++ b/conf/mod_player_bot_level_brackets.conf.dist @@ -3,6 +3,12 @@ ############################################## # mod-player-bot-level-brackets configuration ############################################## +# BotLevelBrackets.ModEnabled +# Description: Turns module on/on +# Default: 1 (enabled) +# Valid Values: 0 (off) / 1 (on) +BotLevelBrackets.ModEnabled = 1 + # # BotLevelBrackets.DebugMode # Description: Enables debug logging for the Bot Level Brackets module. diff --git a/src/mod-player-bot-level-brackets.cpp b/src/mod-player-bot-level-brackets.cpp index 815fa45..ae35962 100644 --- a/src/mod-player-bot-level-brackets.cpp +++ b/src/mod-player-bot-level-brackets.cpp @@ -51,6 +51,7 @@ static uint32 g_BotDistFlaggedCheckFrequency = 15; // in seconds static bool g_BotDistDebugMode = false; static bool g_UseDynamicDistribution = false; static bool g_IgnoreFriendListed = true; +static bool g_EnableMod = true; // Real player weight to boost bracket contributions. static float g_RealPlayerWeight = 1.0f; @@ -64,6 +65,7 @@ static void LoadBotLevelBracketsConfig() g_UseDynamicDistribution = sConfigMgr->GetOption("BotLevelBrackets.UseDynamicDistribution", false); g_RealPlayerWeight = sConfigMgr->GetOption("BotLevelBrackets.RealPlayerWeight", 1.0f); g_IgnoreFriendListed = sConfigMgr->GetOption("BotLevelBrackets.IgnoreFriendListed", true); + g_EnableMod = sConfigMgr->GetOption("BotLevelBrackets.ModEnabled", true); // Load the bot level restrictions. g_RandomBotMinLevel = static_cast(sConfigMgr->GetOption("AiPlayerbot.RandomBotMinLevel", 1)); @@ -98,29 +100,32 @@ static void LoadBotLevelBracketsConfig() // If the bot is out of range, it returns -1 static int GetLevelRangeIndex(uint8 level, uint8 teamID) { - // If the bot's level is outside the allowed global bounds, signal an invalid bracket. - if (level < g_RandomBotMinLevel || level > g_RandomBotMaxLevel) + if (g_EnableMod) + { + // If the bot's level is outside the allowed global bounds, signal an invalid bracket. + if (level < g_RandomBotMinLevel || level > g_RandomBotMaxLevel) + return -1; + + if (teamID == TEAM_ALLIANCE) + { + for (int i = 0; i < NUM_RANGES; ++i) + { + if (level >= g_AllianceLevelRanges[i].lower && level <= g_AllianceLevelRanges[i].upper) + return i; + } + } + + if (teamID == TEAM_HORDE) + { + for (int i = 0; i < NUM_RANGES; ++i) + { + if (level >= g_HordeLevelRanges[i].lower && level <= g_HordeLevelRanges[i].upper) + return i; + } + } + return -1; - - if(teamID == TEAM_ALLIANCE) - { - for (int i = 0; i < NUM_RANGES; ++i) - { - if (level >= g_AllianceLevelRanges[i].lower && level <= g_AllianceLevelRanges[i].upper) - return i; - } } - - if(teamID == TEAM_HORDE) - { - for (int i = 0; i < NUM_RANGES; ++i) - { - if (level >= g_HordeLevelRanges[i].lower && level <= g_HordeLevelRanges[i].upper) - return i; - } - } - - return -1; } // Returns a random level within the provided range. @@ -238,70 +243,73 @@ static void LogAllBotLevels() static void ClampAndBalanceBrackets() { - // First, adjust Alliance brackets. - for (uint8 i = 0; i < NUM_RANGES; ++i) + if (g_EnableMod) { - if (g_AllianceLevelRanges[i].lower < g_RandomBotMinLevel) - g_AllianceLevelRanges[i].lower = g_RandomBotMinLevel; - if (g_AllianceLevelRanges[i].upper > g_RandomBotMaxLevel) - g_AllianceLevelRanges[i].upper = g_RandomBotMaxLevel; - // If the adjusted bracket is invalid, mark it to not be used. - if (g_AllianceLevelRanges[i].lower > g_AllianceLevelRanges[i].upper) - g_AllianceLevelRanges[i].desiredPercent = 0; - } - // Then, adjust Horde brackets similarly. - for (uint8 i = 0; i < NUM_RANGES; ++i) - { - if (g_HordeLevelRanges[i].lower < g_RandomBotMinLevel) - g_HordeLevelRanges[i].lower = g_RandomBotMinLevel; - if (g_HordeLevelRanges[i].upper > g_RandomBotMaxLevel) - g_HordeLevelRanges[i].upper = g_RandomBotMaxLevel; - if (g_HordeLevelRanges[i].lower > g_HordeLevelRanges[i].upper) - g_HordeLevelRanges[i].desiredPercent = 0; - } - // Balance desired percentages so the sum is 100. - uint32 totalAlliance = 0; - uint32 totalHorde = 0; - for (uint8 i = 0; i < NUM_RANGES; ++i) - { - totalAlliance += g_AllianceLevelRanges[i].desiredPercent; - totalHorde += g_HordeLevelRanges[i].desiredPercent; - } - // If totals are not 100, then distribute the missing percent among valid brackets. - if(totalAlliance != 100 && totalAlliance > 0) - { - - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance: Sum of percentages is {} (expected 100). Auto adjusting.", totalAlliance); - - int missing = 100 - totalAlliance; - while(missing > 0) + // First, adjust Alliance brackets. + for (uint8 i = 0; i < NUM_RANGES; ++i) { - for (uint8 i = 0; i < NUM_RANGES && missing > 0; ++i) + if (g_AllianceLevelRanges[i].lower < g_RandomBotMinLevel) + g_AllianceLevelRanges[i].lower = g_RandomBotMinLevel; + if (g_AllianceLevelRanges[i].upper > g_RandomBotMaxLevel) + g_AllianceLevelRanges[i].upper = g_RandomBotMaxLevel; + // If the adjusted bracket is invalid, mark it to not be used. + if (g_AllianceLevelRanges[i].lower > g_AllianceLevelRanges[i].upper) + g_AllianceLevelRanges[i].desiredPercent = 0; + } + // Then, adjust Horde brackets similarly. + for (uint8 i = 0; i < NUM_RANGES; ++i) + { + if (g_HordeLevelRanges[i].lower < g_RandomBotMinLevel) + g_HordeLevelRanges[i].lower = g_RandomBotMinLevel; + if (g_HordeLevelRanges[i].upper > g_RandomBotMaxLevel) + g_HordeLevelRanges[i].upper = g_RandomBotMaxLevel; + if (g_HordeLevelRanges[i].lower > g_HordeLevelRanges[i].upper) + g_HordeLevelRanges[i].desiredPercent = 0; + } + // Balance desired percentages so the sum is 100. + uint32 totalAlliance = 0; + uint32 totalHorde = 0; + for (uint8 i = 0; i < NUM_RANGES; ++i) + { + totalAlliance += g_AllianceLevelRanges[i].desiredPercent; + totalHorde += g_HordeLevelRanges[i].desiredPercent; + } + // If totals are not 100, then distribute the missing percent among valid brackets. + if (totalAlliance != 100 && totalAlliance > 0) + { + + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance: Sum of percentages is {} (expected 100). Auto adjusting.", totalAlliance); + + int missing = 100 - totalAlliance; + while (missing > 0) { - if(g_AllianceLevelRanges[i].lower <= g_AllianceLevelRanges[i].upper && - g_AllianceLevelRanges[i].desiredPercent > 0) + for (uint8 i = 0; i < NUM_RANGES && missing > 0; ++i) { - g_AllianceLevelRanges[i].desiredPercent++; - missing--; + if (g_AllianceLevelRanges[i].lower <= g_AllianceLevelRanges[i].upper && + g_AllianceLevelRanges[i].desiredPercent > 0) + { + g_AllianceLevelRanges[i].desiredPercent++; + missing--; + } } } } - } - if(totalHorde != 100 && totalHorde > 0) - { - - LOG_INFO("server.loading", "[BotLevelBrackets] Horde: Sum of percentages is {} (expected 100). Auto adjusting.", totalHorde); - - int missing = 100 - totalHorde; - while(missing > 0) + if (totalHorde != 100 && totalHorde > 0) { - for (uint8 i = 0; i < NUM_RANGES && missing > 0; ++i) + + LOG_INFO("server.loading", "[BotLevelBrackets] Horde: Sum of percentages is {} (expected 100). Auto adjusting.", totalHorde); + + int missing = 100 - totalHorde; + while (missing > 0) { - if(g_HordeLevelRanges[i].lower <= g_HordeLevelRanges[i].upper && - g_HordeLevelRanges[i].desiredPercent > 0) + for (uint8 i = 0; i < NUM_RANGES && missing > 0; ++i) { - g_HordeLevelRanges[i].desiredPercent++; - missing--; + if (g_HordeLevelRanges[i].lower <= g_HordeLevelRanges[i].upper && + g_HordeLevelRanges[i].desiredPercent > 0) + { + g_HordeLevelRanges[i].desiredPercent++; + missing--; + } } } } @@ -395,7 +403,7 @@ static void ProcessPendingLevelResets() Player* bot = it->bot; int targetRange = it->targetRange; - if (bot && bot->IsInWorld() && IsBotSafeForLevelReset(bot)) + if (bot && bot->IsInWorld() && IsBotSafeForLevelReset(bot) && g_EnableMod) { AdjustBotToRange(bot, targetRange, it->factionRanges); LOG_INFO("server.loading", "[BotLevelBrackets] Bot '{}' successfully reset to level range {}-{}.", @@ -497,552 +505,555 @@ public: void OnUpdate(uint32 diff) override { - m_timer += diff; - m_flaggedTimer += diff; - - // Process pending level resets. - if (m_flaggedTimer >= g_BotDistFlaggedCheckFrequency * 1000) + if (g_EnableMod) { - LOG_INFO("server.loading", "[BotLevelBrackets] Pending Level Resets Triggering."); - ProcessPendingLevelResets(); - m_flaggedTimer = 0; - } + m_timer += diff; + m_flaggedTimer += diff; - // Continue with distribution adjustments once the timer expires. - if (m_timer < g_BotDistCheckFrequency * 1000) - return; - m_timer = 0; - - // Dynamic distribution: recalc desired percentages based on non-bot players. - if (g_UseDynamicDistribution) - { - int allianceRealCounts[NUM_RANGES] = {0}; - int hordeRealCounts[NUM_RANGES] = {0}; - uint32 totalAllianceReal = 0; - uint32 totalHordeReal = 0; - // Iterate over all players and count non-bot players. - for (auto const& itr : ObjectAccessor::GetPlayers()) + // Process pending level resets. + if (m_flaggedTimer >= g_BotDistFlaggedCheckFrequency * 1000) { - Player* player = itr.second; - if (!player || !player->IsInWorld()) - continue; - if (IsPlayerBot(player)) - continue; // Skip bots. - int rangeIndex = GetOrFlagPlayerBracket(player); - if (rangeIndex < 0) - continue; - if (player->GetTeamId() == TEAM_ALLIANCE) - { - allianceRealCounts[rangeIndex]++; - totalAllianceReal++; - } - else if (player->GetTeamId() == TEAM_HORDE) - { - hordeRealCounts[rangeIndex]++; - totalHordeReal++; - } + LOG_INFO("server.loading", "[BotLevelBrackets] Pending Level Resets Triggering."); + ProcessPendingLevelResets(); + m_flaggedTimer = 0; } - // Use a baseline weight to ensure an equal share when no real players are present. - const float baseline = 1.0f; - float allianceTotalWeight = 0.0f; - float hordeTotalWeight = 0.0f; - float allianceWeights[NUM_RANGES] = {0}; - float hordeWeights[NUM_RANGES] = {0}; - for (int i = 0; i < NUM_RANGES; ++i) + + // Continue with distribution adjustments once the timer expires. + if (m_timer < g_BotDistCheckFrequency * 1000) + return; + m_timer = 0; + + // Dynamic distribution: recalc desired percentages based on non-bot players. + if (g_UseDynamicDistribution) { - // Only count valid brackets. - if (g_AllianceLevelRanges[i].lower > g_AllianceLevelRanges[i].upper) - allianceWeights[i] = 0.0f; - else - allianceWeights[i] = baseline + g_RealPlayerWeight * + int allianceRealCounts[NUM_RANGES] = { 0 }; + int hordeRealCounts[NUM_RANGES] = { 0 }; + uint32 totalAllianceReal = 0; + uint32 totalHordeReal = 0; + // Iterate over all players and count non-bot players. + for (auto const& itr : ObjectAccessor::GetPlayers()) + { + Player* player = itr.second; + if (!player || !player->IsInWorld()) + continue; + if (IsPlayerBot(player)) + continue; // Skip bots. + int rangeIndex = GetOrFlagPlayerBracket(player); + if (rangeIndex < 0) + continue; + if (player->GetTeamId() == TEAM_ALLIANCE) + { + allianceRealCounts[rangeIndex]++; + totalAllianceReal++; + } + else if (player->GetTeamId() == TEAM_HORDE) + { + hordeRealCounts[rangeIndex]++; + totalHordeReal++; + } + } + // Use a baseline weight to ensure an equal share when no real players are present. + const float baseline = 1.0f; + float allianceTotalWeight = 0.0f; + float hordeTotalWeight = 0.0f; + float allianceWeights[NUM_RANGES] = { 0 }; + float hordeWeights[NUM_RANGES] = { 0 }; + for (int i = 0; i < NUM_RANGES; ++i) + { + // Only count valid brackets. + if (g_AllianceLevelRanges[i].lower > g_AllianceLevelRanges[i].upper) + allianceWeights[i] = 0.0f; + else + allianceWeights[i] = baseline + g_RealPlayerWeight * (totalAllianceReal > 0 ? (1.0f / totalAllianceReal) : 1.0f) * log(1 + allianceRealCounts[i]); - if (g_HordeLevelRanges[i].lower > g_HordeLevelRanges[i].upper) - hordeWeights[i] = 0.0f; - else - hordeWeights[i] = baseline + g_RealPlayerWeight * + if (g_HordeLevelRanges[i].lower > g_HordeLevelRanges[i].upper) + hordeWeights[i] = 0.0f; + else + hordeWeights[i] = baseline + g_RealPlayerWeight * (totalHordeReal > 0 ? (1.0f / totalHordeReal) : 1.0f) * log(1 + hordeRealCounts[i]); - allianceTotalWeight += allianceWeights[i]; - hordeTotalWeight += hordeWeights[i]; - } - // Recalculate desired percentages for each range. - for (int i = 0; i < NUM_RANGES; ++i) - { - g_AllianceLevelRanges[i].desiredPercent = static_cast(round((allianceWeights[i] / allianceTotalWeight) * 100)); - if (g_BotDistDebugMode) - { - LOG_INFO("server.loading", "[BotLevelBrackets] Dynamic Distribution - Alliance Range {}: {}-{}, Real Players: {} (weight: {:.2f}), New Desired: {}%", - i + 1, g_AllianceLevelRanges[i].lower, g_AllianceLevelRanges[i].upper, allianceRealCounts[i], allianceWeights[i], g_AllianceLevelRanges[i].desiredPercent); + allianceTotalWeight += allianceWeights[i]; + hordeTotalWeight += hordeWeights[i]; } - } - - uint8 sumAlliance = 0; - for (int i = 0; i < NUM_RANGES; ++i) - sumAlliance += g_AllianceLevelRanges[i].desiredPercent; - if (sumAlliance < 100 && allianceTotalWeight > 0) - { - uint8 missing = 100 - sumAlliance; - if (g_BotDistDebugMode) + // Recalculate desired percentages for each range. + for (int i = 0; i < NUM_RANGES; ++i) { - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance normalization: current sum = {}, missing = {}", sumAlliance, missing); - } - while (missing > 0) - { - for (int i = 0; i < NUM_RANGES && missing > 0; ++i) - { - if (g_AllianceLevelRanges[i].lower <= g_AllianceLevelRanges[i].upper && - allianceWeights[i] > 0) - { - g_AllianceLevelRanges[i].desiredPercent++; - missing--; - } - } - } - if (g_BotDistDebugMode) - { - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance normalized percentages:"); - for (int i = 0; i < NUM_RANGES; ++i) - { - LOG_INFO("server.loading", " Range {}: {}% ({}-{})", i + 1, - g_AllianceLevelRanges[i].desiredPercent, - g_AllianceLevelRanges[i].lower, - g_AllianceLevelRanges[i].upper); - } - } - } - - - for (int i = 0; i < NUM_RANGES; ++i) - { - g_HordeLevelRanges[i].desiredPercent = static_cast(round((hordeWeights[i] / hordeTotalWeight) * 100)); - if (g_BotDistDebugMode) - { - LOG_INFO("server.loading", "[BotLevelBrackets] Dynamic Distribution - Horde Range {}: {}-{}, Real Players: {} (weight: {:.2f}), New Desired: {}%", - i + 1, g_HordeLevelRanges[i].lower, g_HordeLevelRanges[i].upper, hordeRealCounts[i], hordeWeights[i], g_HordeLevelRanges[i].desiredPercent); - } - } - - uint8 sumHorde = 0; - for (int i = 0; i < NUM_RANGES; ++i) - sumHorde += g_HordeLevelRanges[i].desiredPercent; - if (sumHorde < 100 && hordeTotalWeight > 0) - { - uint8 missing = 100 - sumHorde; - if (g_BotDistDebugMode) - { - LOG_INFO("server.loading", "[BotLevelBrackets] Horde normalization: current sum = {}, missing = {}", sumHorde, missing); - } - while (missing > 0) - { - for (int i = 0; i < NUM_RANGES && missing > 0; ++i) - { - if (g_HordeLevelRanges[i].lower <= g_HordeLevelRanges[i].upper && - hordeWeights[i] > 0) - { - g_HordeLevelRanges[i].desiredPercent++; - missing--; - } - } - } - if (g_BotDistDebugMode) - { - LOG_INFO("server.loading", "[BotLevelBrackets] Horde normalized percentages:"); - for (int i = 0; i < NUM_RANGES; ++i) - { - LOG_INFO("server.loading", " Range {}: {}% ({}-{})", i + 1, - g_HordeLevelRanges[i].desiredPercent, - g_HordeLevelRanges[i].lower, - g_HordeLevelRanges[i].upper); - } - } - } - - } - - // Containers for Alliance bots. - uint32 totalAllianceBots = 0; - int allianceActualCounts[NUM_RANGES] = {0}; - std::vector allianceBotsByRange[NUM_RANGES]; - - // Containers for Horde bots. - uint32 totalHordeBots = 0; - int hordeActualCounts[NUM_RANGES] = {0}; - std::vector hordeBotsByRange[NUM_RANGES]; - - // Iterate only over player bots. - auto const& allPlayers = ObjectAccessor::GetPlayers(); - if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] Starting processing of {} players.", allPlayers.size()); - - for (auto const& itr : allPlayers) - { - Player* player = itr.second; - if (!player) - { - if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] Skipping null player."); - continue; - } - if (!player->IsInWorld()) - { - if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] Skipping player '{}' as they are not in world.", player->GetName()); - continue; - } - if (!IsPlayerBot(player) || !IsPlayerRandomBot(player)) - { - if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] Skipping player '{}' as they are not a random bot.", player->GetName()); - continue; - } - - if (IsAlliancePlayerBot(player)) - { - totalAllianceBots++; - int rangeIndex = GetOrFlagPlayerBracket(player); - if (rangeIndex >= 0) - { - allianceActualCounts[rangeIndex]++; - allianceBotsByRange[rangeIndex].push_back(player); + g_AllianceLevelRanges[i].desiredPercent = static_cast(round((allianceWeights[i] / allianceTotalWeight) * 100)); if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' with level {} added to range {}.", - player->GetName(), player->GetLevel(), rangeIndex + 1); + { + LOG_INFO("server.loading", "[BotLevelBrackets] Dynamic Distribution - Alliance Range {}: {}-{}, Real Players: {} (weight: {:.2f}), New Desired: {}%", + i + 1, g_AllianceLevelRanges[i].lower, g_AllianceLevelRanges[i].upper, allianceRealCounts[i], allianceWeights[i], g_AllianceLevelRanges[i].desiredPercent); + } } - else if (g_BotDistDebugMode) + + uint8 sumAlliance = 0; + for (int i = 0; i < NUM_RANGES; ++i) + sumAlliance += g_AllianceLevelRanges[i].desiredPercent; + if (sumAlliance < 100 && allianceTotalWeight > 0) { - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' with level {} does not fall into any defined range.", - player->GetName(), player->GetLevel()); - } - } - else if (IsHordePlayerBot(player)) - { - totalHordeBots++; - int rangeIndex = GetOrFlagPlayerBracket(player); - if (rangeIndex >= 0) - { - hordeActualCounts[rangeIndex]++; - hordeBotsByRange[rangeIndex].push_back(player); + uint8 missing = 100 - sumAlliance; if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' with level {} added to range {}.", - player->GetName(), player->GetLevel(), rangeIndex + 1); + { + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance normalization: current sum = {}, missing = {}", sumAlliance, missing); + } + while (missing > 0) + { + for (int i = 0; i < NUM_RANGES && missing > 0; ++i) + { + if (g_AllianceLevelRanges[i].lower <= g_AllianceLevelRanges[i].upper && + allianceWeights[i] > 0) + { + g_AllianceLevelRanges[i].desiredPercent++; + missing--; + } + } + } + if (g_BotDistDebugMode) + { + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance normalized percentages:"); + for (int i = 0; i < NUM_RANGES; ++i) + { + LOG_INFO("server.loading", " Range {}: {}% ({}-{})", i + 1, + g_AllianceLevelRanges[i].desiredPercent, + g_AllianceLevelRanges[i].lower, + g_AllianceLevelRanges[i].upper); + } + } } - else if (g_BotDistDebugMode) + + + for (int i = 0; i < NUM_RANGES; ++i) { - LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' with level {} does not fall into any defined range.", - player->GetName(), player->GetLevel()); + g_HordeLevelRanges[i].desiredPercent = static_cast(round((hordeWeights[i] / hordeTotalWeight) * 100)); + if (g_BotDistDebugMode) + { + LOG_INFO("server.loading", "[BotLevelBrackets] Dynamic Distribution - Horde Range {}: {}-{}, Real Players: {} (weight: {:.2f}), New Desired: {}%", + i + 1, g_HordeLevelRanges[i].lower, g_HordeLevelRanges[i].upper, hordeRealCounts[i], hordeWeights[i], g_HordeLevelRanges[i].desiredPercent); + } + } + + uint8 sumHorde = 0; + for (int i = 0; i < NUM_RANGES; ++i) + sumHorde += g_HordeLevelRanges[i].desiredPercent; + if (sumHorde < 100 && hordeTotalWeight > 0) + { + uint8 missing = 100 - sumHorde; + if (g_BotDistDebugMode) + { + LOG_INFO("server.loading", "[BotLevelBrackets] Horde normalization: current sum = {}, missing = {}", sumHorde, missing); + } + while (missing > 0) + { + for (int i = 0; i < NUM_RANGES && missing > 0; ++i) + { + if (g_HordeLevelRanges[i].lower <= g_HordeLevelRanges[i].upper && + hordeWeights[i] > 0) + { + g_HordeLevelRanges[i].desiredPercent++; + missing--; + } + } + } + if (g_BotDistDebugMode) + { + LOG_INFO("server.loading", "[BotLevelBrackets] Horde normalized percentages:"); + for (int i = 0; i < NUM_RANGES; ++i) + { + LOG_INFO("server.loading", " Range {}: {}% ({}-{})", i + 1, + g_HordeLevelRanges[i].desiredPercent, + g_HordeLevelRanges[i].lower, + g_HordeLevelRanges[i].upper); + } + } + } + + } + + // Containers for Alliance bots. + uint32 totalAllianceBots = 0; + int allianceActualCounts[NUM_RANGES] = { 0 }; + std::vector allianceBotsByRange[NUM_RANGES]; + + // Containers for Horde bots. + uint32 totalHordeBots = 0; + int hordeActualCounts[NUM_RANGES] = { 0 }; + std::vector hordeBotsByRange[NUM_RANGES]; + + // Iterate only over player bots. + auto const& allPlayers = ObjectAccessor::GetPlayers(); + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] Starting processing of {} players.", allPlayers.size()); + + for (auto const& itr : allPlayers) + { + Player* player = itr.second; + if (!player) + { + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] Skipping null player."); + continue; + } + if (!player->IsInWorld()) + { + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] Skipping player '{}' as they are not in world.", player->GetName()); + continue; + } + if (!IsPlayerBot(player) || !IsPlayerRandomBot(player)) + { + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] Skipping player '{}' as they are not a random bot.", player->GetName()); + continue; + } + + if (IsAlliancePlayerBot(player)) + { + totalAllianceBots++; + int rangeIndex = GetOrFlagPlayerBracket(player); + if (rangeIndex >= 0) + { + allianceActualCounts[rangeIndex]++; + allianceBotsByRange[rangeIndex].push_back(player); + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' with level {} added to range {}.", + player->GetName(), player->GetLevel(), rangeIndex + 1); + } + else if (g_BotDistDebugMode) + { + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' with level {} does not fall into any defined range.", + player->GetName(), player->GetLevel()); + } + } + else if (IsHordePlayerBot(player)) + { + totalHordeBots++; + int rangeIndex = GetOrFlagPlayerBracket(player); + if (rangeIndex >= 0) + { + hordeActualCounts[rangeIndex]++; + hordeBotsByRange[rangeIndex].push_back(player); + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' with level {} added to range {}.", + player->GetName(), player->GetLevel(), rangeIndex + 1); + } + else if (g_BotDistDebugMode) + { + LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' with level {} does not fall into any defined range.", + player->GetName(), player->GetLevel()); + } } } - } - if (g_BotDistDebugMode) - { - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - LOG_INFO("server.loading", "[BotLevelBrackets] Total Alliance Bots: {}.", totalAllianceBots); - LOG_INFO("server.loading", "[BotLevelBrackets] Total Horde Bots: {}.", totalHordeBots); - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - } - - // Process Alliance bots. - if (totalAllianceBots > 0) - { - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - int allianceDesiredCounts[NUM_RANGES] = {0}; - for (int i = 0; i < NUM_RANGES; ++i) + if (g_BotDistDebugMode) { - allianceDesiredCounts[i] = static_cast(round((g_AllianceLevelRanges[i].desiredPercent / 100.0) * totalAllianceBots)); - if (g_BotDistDebugMode) - { - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance Range {} ({}-{}): Desired = {}, Actual = {}.", - i + 1, g_AllianceLevelRanges[i].lower, g_AllianceLevelRanges[i].upper, - allianceDesiredCounts[i], allianceActualCounts[i]); - } + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); + LOG_INFO("server.loading", "[BotLevelBrackets] Total Alliance Bots: {}.", totalAllianceBots); + LOG_INFO("server.loading", "[BotLevelBrackets] Total Horde Bots: {}.", totalHordeBots); + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); } - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - // Adjust overpopulated ranges. - for (int i = 0; i < NUM_RANGES; ++i) - { - if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] >>> Processing Alliance bots in range {}.", i + 1); - std::vector safeBots; - std::vector flaggedBots; - for (Player* bot : allianceBotsByRange[i]) + // Process Alliance bots. + if (totalAllianceBots > 0) + { + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); + int allianceDesiredCounts[NUM_RANGES] = { 0 }; + for (int i = 0; i < NUM_RANGES; ++i) { - if (IsBotSafeForLevelReset(bot)) + allianceDesiredCounts[i] = static_cast(round((g_AllianceLevelRanges[i].desiredPercent / 100.0) * totalAllianceBots)); + if (g_BotDistDebugMode) { - safeBots.push_back(bot); - if (g_BotDistDebugMode) - { - //LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' is safe for level reset in range {}.", bot->GetName(), i + 1); - } - } - else - { - flaggedBots.push_back(bot); - if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' is NOT safe for level reset in range {}.", - bot->GetName(), i + 1); + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance Range {} ({}-{}): Desired = {}, Actual = {}.", + i + 1, g_AllianceLevelRanges[i].lower, g_AllianceLevelRanges[i].upper, + allianceDesiredCounts[i], allianceActualCounts[i]); } } - while (allianceActualCounts[i] > allianceDesiredCounts[i] && !safeBots.empty()) + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); + // Adjust overpopulated ranges. + for (int i = 0; i < NUM_RANGES; ++i) { - Player* bot = safeBots.back(); - safeBots.pop_back(); - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance safe bot '{}' from range {} will be moved.", - bot->GetName(), i + 1); - int targetRange = -1; - if (bot->getClass() == CLASS_DEATH_KNIGHT) + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] >>> Processing Alliance bots in range {}.", i + 1); + + std::vector safeBots; + std::vector flaggedBots; + for (Player* bot : allianceBotsByRange[i]) { - for (int j = 0; j < NUM_RANGES; ++j) + if (IsBotSafeForLevelReset(bot)) { - if (allianceActualCounts[j] < allianceDesiredCounts[j] && g_AllianceLevelRanges[j].upper >= 55) + safeBots.push_back(bot); + if (g_BotDistDebugMode) { - targetRange = j; - break; + //LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' is safe for level reset in range {}.", bot->GetName(), i + 1); } } - } - else - { - for (int j = 0; j < NUM_RANGES; ++j) + else { - if (allianceActualCounts[j] < allianceDesiredCounts[j]) - { - targetRange = j; - break; - } + flaggedBots.push_back(bot); + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' is NOT safe for level reset in range {}.", + bot->GetName(), i + 1); } } - if (targetRange == -1) + while (allianceActualCounts[i] > allianceDesiredCounts[i] && !safeBots.empty()) { - LOG_INFO("server.loading", "[BotLevelBrackets] No valid target range found for alliance safe bot '{}'.", bot->GetName()); - break; - } - LOG_INFO("server.loading", "[BotLevelBrackets] !!!! Adjusting alliance bot '{}' from range {} to range {} ({}-{}).", - bot->GetName(), i + 1, targetRange + 1, g_AllianceLevelRanges[targetRange].lower, g_AllianceLevelRanges[targetRange].upper); - AdjustBotToRange(bot, targetRange, g_AllianceLevelRanges); - allianceActualCounts[i]--; - allianceActualCounts[targetRange]++; - } - while (allianceActualCounts[i] > allianceDesiredCounts[i] && !flaggedBots.empty()) - { - Player* bot = flaggedBots.back(); - flaggedBots.pop_back(); - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance flagged bot '{}' from range {} will be processed for pending reset.", - bot->GetName(), i + 1); - int targetRange = -1; - if (bot->getClass() == CLASS_DEATH_KNIGHT) - { - for (int j = 0; j < NUM_RANGES; ++j) + Player* bot = safeBots.back(); + safeBots.pop_back(); + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance safe bot '{}' from range {} will be moved.", + bot->GetName(), i + 1); + int targetRange = -1; + if (bot->getClass() == CLASS_DEATH_KNIGHT) { - if (allianceActualCounts[j] < allianceDesiredCounts[j] && g_AllianceLevelRanges[j].upper >= 55) + for (int j = 0; j < NUM_RANGES; ++j) { - targetRange = j; - break; + if (allianceActualCounts[j] < allianceDesiredCounts[j] && g_AllianceLevelRanges[j].upper >= 55) + { + targetRange = j; + break; + } } } - } - else - { - for (int j = 0; j < NUM_RANGES; ++j) + else { - if (allianceActualCounts[j] < allianceDesiredCounts[j]) + for (int j = 0; j < NUM_RANGES; ++j) { - targetRange = j; - break; + if (allianceActualCounts[j] < allianceDesiredCounts[j]) + { + targetRange = j; + break; + } } } - } - if (targetRange == -1) - { - LOG_INFO("server.loading", "[BotLevelBrackets] No valid target range found for flagged alliance bot '{}' for pending reset.", bot->GetName()); - break; - } - bool alreadyFlagged = false; - for (auto& entry : g_PendingLevelResets) - { - if (entry.bot == bot) + if (targetRange == -1) { - alreadyFlagged = true; + LOG_INFO("server.loading", "[BotLevelBrackets] No valid target range found for alliance safe bot '{}'.", bot->GetName()); break; } + LOG_INFO("server.loading", "[BotLevelBrackets] !!!! Adjusting alliance bot '{}' from range {} to range {} ({}-{}).", + bot->GetName(), i + 1, targetRange + 1, g_AllianceLevelRanges[targetRange].lower, g_AllianceLevelRanges[targetRange].upper); + AdjustBotToRange(bot, targetRange, g_AllianceLevelRanges); + allianceActualCounts[i]--; + allianceActualCounts[targetRange]++; } - if (!alreadyFlagged) + while (allianceActualCounts[i] > allianceDesiredCounts[i] && !flaggedBots.empty()) { - g_PendingLevelResets.push_back({bot, targetRange, g_AllianceLevelRanges}); - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' flagged for pending level reset to range {}-{}.", - bot->GetName(), g_AllianceLevelRanges[targetRange].lower, g_AllianceLevelRanges[targetRange].upper); + Player* bot = flaggedBots.back(); + flaggedBots.pop_back(); + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance flagged bot '{}' from range {} will be processed for pending reset.", + bot->GetName(), i + 1); + int targetRange = -1; + if (bot->getClass() == CLASS_DEATH_KNIGHT) + { + for (int j = 0; j < NUM_RANGES; ++j) + { + if (allianceActualCounts[j] < allianceDesiredCounts[j] && g_AllianceLevelRanges[j].upper >= 55) + { + targetRange = j; + break; + } + } + } + else + { + for (int j = 0; j < NUM_RANGES; ++j) + { + if (allianceActualCounts[j] < allianceDesiredCounts[j]) + { + targetRange = j; + break; + } + } + } + if (targetRange == -1) + { + LOG_INFO("server.loading", "[BotLevelBrackets] No valid target range found for flagged alliance bot '{}' for pending reset.", bot->GetName()); + break; + } + bool alreadyFlagged = false; + for (auto& entry : g_PendingLevelResets) + { + if (entry.bot == bot) + { + alreadyFlagged = true; + break; + } + } + if (!alreadyFlagged) + { + g_PendingLevelResets.push_back({ bot, targetRange, g_AllianceLevelRanges }); + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' flagged for pending level reset to range {}-{}.", + bot->GetName(), g_AllianceLevelRanges[targetRange].lower, g_AllianceLevelRanges[targetRange].upper); + } } } } - } - // Process Horde bots. - if (totalHordeBots > 0) - { - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - int hordeDesiredCounts[NUM_RANGES] = {0}; - for (int i = 0; i < NUM_RANGES; ++i) + // Process Horde bots. + if (totalHordeBots > 0) { - hordeDesiredCounts[i] = static_cast(round((g_HordeLevelRanges[i].desiredPercent / 100.0) * totalHordeBots)); - if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); + int hordeDesiredCounts[NUM_RANGES] = { 0 }; + for (int i = 0; i < NUM_RANGES; ++i) { + hordeDesiredCounts[i] = static_cast(round((g_HordeLevelRanges[i].desiredPercent / 100.0) * totalHordeBots)); + if (g_BotDistDebugMode) + { + LOG_INFO("server.loading", "[BotLevelBrackets] Horde Range {} ({}-{}): Desired = {}, Actual = {}.", + i + 1, g_HordeLevelRanges[i].lower, g_HordeLevelRanges[i].upper, + hordeDesiredCounts[i], hordeActualCounts[i]); + } + } + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); + for (int i = 0; i < NUM_RANGES; ++i) + { + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] Processing Horde bots in range {}.", i + 1); + + std::vector safeBots; + std::vector flaggedBots; + for (Player* bot : hordeBotsByRange[i]) + { + if (IsBotSafeForLevelReset(bot)) + { + safeBots.push_back(bot); + if (g_BotDistDebugMode) + { + //LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' is safe for level reset in range {}.", bot->GetName(), i + 1); + } + } + else + { + flaggedBots.push_back(bot); + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' is NOT safe for level reset in range {}.", + bot->GetName(), i + 1); + } + } + while (hordeActualCounts[i] > hordeDesiredCounts[i] && !safeBots.empty()) + { + Player* bot = safeBots.back(); + safeBots.pop_back(); + LOG_INFO("server.loading", "[BotLevelBrackets] Horde safe bot '{}' from range {} will be moved.", + bot->GetName(), i + 1); + int targetRange = -1; + if (bot->getClass() == CLASS_DEATH_KNIGHT) + { + for (int j = 0; j < NUM_RANGES; ++j) + { + if (hordeActualCounts[j] < hordeDesiredCounts[j] && g_HordeLevelRanges[j].upper >= 55) + { + targetRange = j; + break; + } + } + } + else + { + for (int j = 0; j < NUM_RANGES; ++j) + { + if (hordeActualCounts[j] < hordeDesiredCounts[j]) + { + targetRange = j; + break; + } + } + } + if (targetRange == -1) + { + LOG_INFO("server.loading", "[BotLevelBrackets] No valid target range found for safe horde bot '{}'.", bot->GetName()); + break; + } + LOG_INFO("server.loading", "[BotLevelBrackets] !!!! Adjusting horde bot '{}' from range {} to range {} ({}-{}).", + bot->GetName(), i + 1, targetRange + 1, g_HordeLevelRanges[targetRange].lower, g_HordeLevelRanges[targetRange].upper); + AdjustBotToRange(bot, targetRange, g_HordeLevelRanges); + hordeActualCounts[i]--; + hordeActualCounts[targetRange]++; + } + while (hordeActualCounts[i] > hordeDesiredCounts[i] && !flaggedBots.empty()) + { + Player* bot = flaggedBots.back(); + flaggedBots.pop_back(); + LOG_INFO("server.loading", "[BotLevelBrackets] Horde flagged bot '{}' from range {} will be processed for pending reset.", + bot->GetName(), i + 1); + int targetRange = -1; + if (bot->getClass() == CLASS_DEATH_KNIGHT) + { + for (int j = 0; j < NUM_RANGES; ++j) + { + if (hordeActualCounts[j] < hordeDesiredCounts[j] && g_HordeLevelRanges[j].upper >= 55) + { + targetRange = j; + break; + } + } + } + else + { + for (int j = 0; j < NUM_RANGES; ++j) + { + if (hordeActualCounts[j] < hordeDesiredCounts[j]) + { + targetRange = j; + break; + } + } + } + if (targetRange == -1) + { + LOG_INFO("server.loading", "[BotLevelBrackets] No valid target range found for flagged horde bot '{}' for pending reset.", bot->GetName()); + break; + } + bool alreadyFlagged = false; + for (auto& entry : g_PendingLevelResets) + { + if (entry.bot == bot) + { + alreadyFlagged = true; + break; + } + } + if (!alreadyFlagged) + { + g_PendingLevelResets.push_back({ bot, targetRange, g_HordeLevelRanges }); + LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' flagged for pending level reset to range {}-{}.", + bot->GetName(), g_HordeLevelRanges[targetRange].lower, g_HordeLevelRanges[targetRange].upper); + } + } + } + } + + + if (g_BotDistDebugMode) + { + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================= COMPLETE"); + LOG_INFO("server.loading", "[BotLevelBrackets] Distribution adjustment complete. Alliance bots: {}, Horde bots: {}.", + totalAllianceBots, totalHordeBots); + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); + LogAllBotLevels(); + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); + int allianceDesiredCounts[NUM_RANGES] = { 0 }; + for (int i = 0; i < NUM_RANGES; ++i) + { + allianceDesiredCounts[i] = static_cast(round((g_AllianceLevelRanges[i].desiredPercent / 100.0) * totalAllianceBots)); + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance Range {} ({}-{}): Desired = {}, Actual = {}.", + i + 1, g_AllianceLevelRanges[i].lower, g_AllianceLevelRanges[i].upper, + allianceDesiredCounts[i], allianceActualCounts[i]); + } + LOG_INFO("server.loading", "[BotLevelBrackets] ----------------------------------------"); + int hordeDesiredCounts[NUM_RANGES] = { 0 }; + for (int i = 0; i < NUM_RANGES; ++i) + { + hordeDesiredCounts[i] = static_cast(round((g_HordeLevelRanges[i].desiredPercent / 100.0) * totalHordeBots)); LOG_INFO("server.loading", "[BotLevelBrackets] Horde Range {} ({}-{}): Desired = {}, Actual = {}.", - i + 1, g_HordeLevelRanges[i].lower, g_HordeLevelRanges[i].upper, - hordeDesiredCounts[i], hordeActualCounts[i]); + i + 1, g_HordeLevelRanges[i].lower, g_HordeLevelRanges[i].upper, + hordeDesiredCounts[i], hordeActualCounts[i]); } - } - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - for (int i = 0; i < NUM_RANGES; ++i) - { - if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] Processing Horde bots in range {}.", i + 1); + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - std::vector safeBots; - std::vector flaggedBots; - for (Player* bot : hordeBotsByRange[i]) - { - if (IsBotSafeForLevelReset(bot)) - { - safeBots.push_back(bot); - if (g_BotDistDebugMode) - { - //LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' is safe for level reset in range {}.", bot->GetName(), i + 1); - } - } - else - { - flaggedBots.push_back(bot); - if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' is NOT safe for level reset in range {}.", - bot->GetName(), i + 1); - } - } - while (hordeActualCounts[i] > hordeDesiredCounts[i] && !safeBots.empty()) - { - Player* bot = safeBots.back(); - safeBots.pop_back(); - LOG_INFO("server.loading", "[BotLevelBrackets] Horde safe bot '{}' from range {} will be moved.", - bot->GetName(), i + 1); - int targetRange = -1; - if (bot->getClass() == CLASS_DEATH_KNIGHT) - { - for (int j = 0; j < NUM_RANGES; ++j) - { - if (hordeActualCounts[j] < hordeDesiredCounts[j] && g_HordeLevelRanges[j].upper >= 55) - { - targetRange = j; - break; - } - } - } - else - { - for (int j = 0; j < NUM_RANGES; ++j) - { - if (hordeActualCounts[j] < hordeDesiredCounts[j]) - { - targetRange = j; - break; - } - } - } - if (targetRange == -1) - { - LOG_INFO("server.loading", "[BotLevelBrackets] No valid target range found for safe horde bot '{}'.", bot->GetName()); - break; - } - LOG_INFO("server.loading", "[BotLevelBrackets] !!!! Adjusting horde bot '{}' from range {} to range {} ({}-{}).", - bot->GetName(), i + 1, targetRange + 1, g_HordeLevelRanges[targetRange].lower, g_HordeLevelRanges[targetRange].upper); - AdjustBotToRange(bot, targetRange, g_HordeLevelRanges); - hordeActualCounts[i]--; - hordeActualCounts[targetRange]++; - } - while (hordeActualCounts[i] > hordeDesiredCounts[i] && !flaggedBots.empty()) - { - Player* bot = flaggedBots.back(); - flaggedBots.pop_back(); - LOG_INFO("server.loading", "[BotLevelBrackets] Horde flagged bot '{}' from range {} will be processed for pending reset.", - bot->GetName(), i + 1); - int targetRange = -1; - if (bot->getClass() == CLASS_DEATH_KNIGHT) - { - for (int j = 0; j < NUM_RANGES; ++j) - { - if (hordeActualCounts[j] < hordeDesiredCounts[j] && g_HordeLevelRanges[j].upper >= 55) - { - targetRange = j; - break; - } - } - } - else - { - for (int j = 0; j < NUM_RANGES; ++j) - { - if (hordeActualCounts[j] < hordeDesiredCounts[j]) - { - targetRange = j; - break; - } - } - } - if (targetRange == -1) - { - LOG_INFO("server.loading", "[BotLevelBrackets] No valid target range found for flagged horde bot '{}' for pending reset.", bot->GetName()); - break; - } - bool alreadyFlagged = false; - for (auto& entry : g_PendingLevelResets) - { - if (entry.bot == bot) - { - alreadyFlagged = true; - break; - } - } - if (!alreadyFlagged) - { - g_PendingLevelResets.push_back({bot, targetRange, g_HordeLevelRanges}); - LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' flagged for pending level reset to range {}-{}.", - bot->GetName(), g_HordeLevelRanges[targetRange].lower, g_HordeLevelRanges[targetRange].upper); - } - } } } - - - if (g_BotDistDebugMode) - { - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================= COMPLETE"); - LOG_INFO("server.loading", "[BotLevelBrackets] Distribution adjustment complete. Alliance bots: {}, Horde bots: {}.", - totalAllianceBots, totalHordeBots); - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - LogAllBotLevels(); - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - int allianceDesiredCounts[NUM_RANGES] = {0}; - for (int i = 0; i < NUM_RANGES; ++i) - { - allianceDesiredCounts[i] = static_cast(round((g_AllianceLevelRanges[i].desiredPercent / 100.0) * totalAllianceBots)); - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance Range {} ({}-{}): Desired = {}, Actual = {}.", - i + 1, g_AllianceLevelRanges[i].lower, g_AllianceLevelRanges[i].upper, - allianceDesiredCounts[i], allianceActualCounts[i]); - } - LOG_INFO("server.loading", "[BotLevelBrackets] ----------------------------------------"); - int hordeDesiredCounts[NUM_RANGES] = {0}; - for (int i = 0; i < NUM_RANGES; ++i) - { - hordeDesiredCounts[i] = static_cast(round((g_HordeLevelRanges[i].desiredPercent / 100.0) * totalHordeBots)); - LOG_INFO("server.loading", "[BotLevelBrackets] Horde Range {} ({}-{}): Desired = {}, Actual = {}.", - i + 1, g_HordeLevelRanges[i].lower, g_HordeLevelRanges[i].upper, - hordeDesiredCounts[i], hordeActualCounts[i]); - } - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - - } } private: From 014dbd49ee2be93bfb1f4de8c5110915b12dc08c Mon Sep 17 00:00:00 2001 From: jimm0thy <25890053+jimm0thy@users.noreply.github.com> Date: Tue, 25 Feb 2025 14:15:24 -0500 Subject: [PATCH 3/4] Revert "Added Option to Enable/Disable Mod" This reverts commit 69e346e357cf84fed6c144cc9e64cbd55f2da8db. Setting up separate branch --- conf/mod_player_bot_level_brackets.conf.dist | 6 - src/mod-player-bot-level-brackets.cpp | 1149 +++++++++--------- 2 files changed, 569 insertions(+), 586 deletions(-) diff --git a/conf/mod_player_bot_level_brackets.conf.dist b/conf/mod_player_bot_level_brackets.conf.dist index 4d96cef..741b8b4 100644 --- a/conf/mod_player_bot_level_brackets.conf.dist +++ b/conf/mod_player_bot_level_brackets.conf.dist @@ -3,12 +3,6 @@ ############################################## # mod-player-bot-level-brackets configuration ############################################## -# BotLevelBrackets.ModEnabled -# Description: Turns module on/on -# Default: 1 (enabled) -# Valid Values: 0 (off) / 1 (on) -BotLevelBrackets.ModEnabled = 1 - # # BotLevelBrackets.DebugMode # Description: Enables debug logging for the Bot Level Brackets module. diff --git a/src/mod-player-bot-level-brackets.cpp b/src/mod-player-bot-level-brackets.cpp index ae35962..815fa45 100644 --- a/src/mod-player-bot-level-brackets.cpp +++ b/src/mod-player-bot-level-brackets.cpp @@ -51,7 +51,6 @@ static uint32 g_BotDistFlaggedCheckFrequency = 15; // in seconds static bool g_BotDistDebugMode = false; static bool g_UseDynamicDistribution = false; static bool g_IgnoreFriendListed = true; -static bool g_EnableMod = true; // Real player weight to boost bracket contributions. static float g_RealPlayerWeight = 1.0f; @@ -65,7 +64,6 @@ static void LoadBotLevelBracketsConfig() g_UseDynamicDistribution = sConfigMgr->GetOption("BotLevelBrackets.UseDynamicDistribution", false); g_RealPlayerWeight = sConfigMgr->GetOption("BotLevelBrackets.RealPlayerWeight", 1.0f); g_IgnoreFriendListed = sConfigMgr->GetOption("BotLevelBrackets.IgnoreFriendListed", true); - g_EnableMod = sConfigMgr->GetOption("BotLevelBrackets.ModEnabled", true); // Load the bot level restrictions. g_RandomBotMinLevel = static_cast(sConfigMgr->GetOption("AiPlayerbot.RandomBotMinLevel", 1)); @@ -100,32 +98,29 @@ static void LoadBotLevelBracketsConfig() // If the bot is out of range, it returns -1 static int GetLevelRangeIndex(uint8 level, uint8 teamID) { - if (g_EnableMod) - { - // If the bot's level is outside the allowed global bounds, signal an invalid bracket. - if (level < g_RandomBotMinLevel || level > g_RandomBotMaxLevel) - return -1; - - if (teamID == TEAM_ALLIANCE) - { - for (int i = 0; i < NUM_RANGES; ++i) - { - if (level >= g_AllianceLevelRanges[i].lower && level <= g_AllianceLevelRanges[i].upper) - return i; - } - } - - if (teamID == TEAM_HORDE) - { - for (int i = 0; i < NUM_RANGES; ++i) - { - if (level >= g_HordeLevelRanges[i].lower && level <= g_HordeLevelRanges[i].upper) - return i; - } - } - + // If the bot's level is outside the allowed global bounds, signal an invalid bracket. + if (level < g_RandomBotMinLevel || level > g_RandomBotMaxLevel) return -1; + + if(teamID == TEAM_ALLIANCE) + { + for (int i = 0; i < NUM_RANGES; ++i) + { + if (level >= g_AllianceLevelRanges[i].lower && level <= g_AllianceLevelRanges[i].upper) + return i; + } } + + if(teamID == TEAM_HORDE) + { + for (int i = 0; i < NUM_RANGES; ++i) + { + if (level >= g_HordeLevelRanges[i].lower && level <= g_HordeLevelRanges[i].upper) + return i; + } + } + + return -1; } // Returns a random level within the provided range. @@ -243,73 +238,70 @@ static void LogAllBotLevels() static void ClampAndBalanceBrackets() { - if (g_EnableMod) + // First, adjust Alliance brackets. + for (uint8 i = 0; i < NUM_RANGES; ++i) + { + if (g_AllianceLevelRanges[i].lower < g_RandomBotMinLevel) + g_AllianceLevelRanges[i].lower = g_RandomBotMinLevel; + if (g_AllianceLevelRanges[i].upper > g_RandomBotMaxLevel) + g_AllianceLevelRanges[i].upper = g_RandomBotMaxLevel; + // If the adjusted bracket is invalid, mark it to not be used. + if (g_AllianceLevelRanges[i].lower > g_AllianceLevelRanges[i].upper) + g_AllianceLevelRanges[i].desiredPercent = 0; + } + // Then, adjust Horde brackets similarly. + for (uint8 i = 0; i < NUM_RANGES; ++i) + { + if (g_HordeLevelRanges[i].lower < g_RandomBotMinLevel) + g_HordeLevelRanges[i].lower = g_RandomBotMinLevel; + if (g_HordeLevelRanges[i].upper > g_RandomBotMaxLevel) + g_HordeLevelRanges[i].upper = g_RandomBotMaxLevel; + if (g_HordeLevelRanges[i].lower > g_HordeLevelRanges[i].upper) + g_HordeLevelRanges[i].desiredPercent = 0; + } + // Balance desired percentages so the sum is 100. + uint32 totalAlliance = 0; + uint32 totalHorde = 0; + for (uint8 i = 0; i < NUM_RANGES; ++i) + { + totalAlliance += g_AllianceLevelRanges[i].desiredPercent; + totalHorde += g_HordeLevelRanges[i].desiredPercent; + } + // If totals are not 100, then distribute the missing percent among valid brackets. + if(totalAlliance != 100 && totalAlliance > 0) { - // First, adjust Alliance brackets. - for (uint8 i = 0; i < NUM_RANGES; ++i) - { - if (g_AllianceLevelRanges[i].lower < g_RandomBotMinLevel) - g_AllianceLevelRanges[i].lower = g_RandomBotMinLevel; - if (g_AllianceLevelRanges[i].upper > g_RandomBotMaxLevel) - g_AllianceLevelRanges[i].upper = g_RandomBotMaxLevel; - // If the adjusted bracket is invalid, mark it to not be used. - if (g_AllianceLevelRanges[i].lower > g_AllianceLevelRanges[i].upper) - g_AllianceLevelRanges[i].desiredPercent = 0; - } - // Then, adjust Horde brackets similarly. - for (uint8 i = 0; i < NUM_RANGES; ++i) - { - if (g_HordeLevelRanges[i].lower < g_RandomBotMinLevel) - g_HordeLevelRanges[i].lower = g_RandomBotMinLevel; - if (g_HordeLevelRanges[i].upper > g_RandomBotMaxLevel) - g_HordeLevelRanges[i].upper = g_RandomBotMaxLevel; - if (g_HordeLevelRanges[i].lower > g_HordeLevelRanges[i].upper) - g_HordeLevelRanges[i].desiredPercent = 0; - } - // Balance desired percentages so the sum is 100. - uint32 totalAlliance = 0; - uint32 totalHorde = 0; - for (uint8 i = 0; i < NUM_RANGES; ++i) - { - totalAlliance += g_AllianceLevelRanges[i].desiredPercent; - totalHorde += g_HordeLevelRanges[i].desiredPercent; - } - // If totals are not 100, then distribute the missing percent among valid brackets. - if (totalAlliance != 100 && totalAlliance > 0) - { - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance: Sum of percentages is {} (expected 100). Auto adjusting.", totalAlliance); - - int missing = 100 - totalAlliance; - while (missing > 0) + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance: Sum of percentages is {} (expected 100). Auto adjusting.", totalAlliance); + + int missing = 100 - totalAlliance; + while(missing > 0) + { + for (uint8 i = 0; i < NUM_RANGES && missing > 0; ++i) { - for (uint8 i = 0; i < NUM_RANGES && missing > 0; ++i) + if(g_AllianceLevelRanges[i].lower <= g_AllianceLevelRanges[i].upper && + g_AllianceLevelRanges[i].desiredPercent > 0) { - if (g_AllianceLevelRanges[i].lower <= g_AllianceLevelRanges[i].upper && - g_AllianceLevelRanges[i].desiredPercent > 0) - { - g_AllianceLevelRanges[i].desiredPercent++; - missing--; - } + g_AllianceLevelRanges[i].desiredPercent++; + missing--; } } } - if (totalHorde != 100 && totalHorde > 0) + } + if(totalHorde != 100 && totalHorde > 0) + { + + LOG_INFO("server.loading", "[BotLevelBrackets] Horde: Sum of percentages is {} (expected 100). Auto adjusting.", totalHorde); + + int missing = 100 - totalHorde; + while(missing > 0) { - - LOG_INFO("server.loading", "[BotLevelBrackets] Horde: Sum of percentages is {} (expected 100). Auto adjusting.", totalHorde); - - int missing = 100 - totalHorde; - while (missing > 0) + for (uint8 i = 0; i < NUM_RANGES && missing > 0; ++i) { - for (uint8 i = 0; i < NUM_RANGES && missing > 0; ++i) + if(g_HordeLevelRanges[i].lower <= g_HordeLevelRanges[i].upper && + g_HordeLevelRanges[i].desiredPercent > 0) { - if (g_HordeLevelRanges[i].lower <= g_HordeLevelRanges[i].upper && - g_HordeLevelRanges[i].desiredPercent > 0) - { - g_HordeLevelRanges[i].desiredPercent++; - missing--; - } + g_HordeLevelRanges[i].desiredPercent++; + missing--; } } } @@ -403,7 +395,7 @@ static void ProcessPendingLevelResets() Player* bot = it->bot; int targetRange = it->targetRange; - if (bot && bot->IsInWorld() && IsBotSafeForLevelReset(bot) && g_EnableMod) + if (bot && bot->IsInWorld() && IsBotSafeForLevelReset(bot)) { AdjustBotToRange(bot, targetRange, it->factionRanges); LOG_INFO("server.loading", "[BotLevelBrackets] Bot '{}' successfully reset to level range {}-{}.", @@ -505,554 +497,551 @@ public: void OnUpdate(uint32 diff) override { - if (g_EnableMod) + m_timer += diff; + m_flaggedTimer += diff; + + // Process pending level resets. + if (m_flaggedTimer >= g_BotDistFlaggedCheckFrequency * 1000) { - m_timer += diff; - m_flaggedTimer += diff; + LOG_INFO("server.loading", "[BotLevelBrackets] Pending Level Resets Triggering."); + ProcessPendingLevelResets(); + m_flaggedTimer = 0; + } - // Process pending level resets. - if (m_flaggedTimer >= g_BotDistFlaggedCheckFrequency * 1000) + // Continue with distribution adjustments once the timer expires. + if (m_timer < g_BotDistCheckFrequency * 1000) + return; + m_timer = 0; + + // Dynamic distribution: recalc desired percentages based on non-bot players. + if (g_UseDynamicDistribution) + { + int allianceRealCounts[NUM_RANGES] = {0}; + int hordeRealCounts[NUM_RANGES] = {0}; + uint32 totalAllianceReal = 0; + uint32 totalHordeReal = 0; + // Iterate over all players and count non-bot players. + for (auto const& itr : ObjectAccessor::GetPlayers()) { - LOG_INFO("server.loading", "[BotLevelBrackets] Pending Level Resets Triggering."); - ProcessPendingLevelResets(); - m_flaggedTimer = 0; - } - - // Continue with distribution adjustments once the timer expires. - if (m_timer < g_BotDistCheckFrequency * 1000) - return; - m_timer = 0; - - // Dynamic distribution: recalc desired percentages based on non-bot players. - if (g_UseDynamicDistribution) - { - int allianceRealCounts[NUM_RANGES] = { 0 }; - int hordeRealCounts[NUM_RANGES] = { 0 }; - uint32 totalAllianceReal = 0; - uint32 totalHordeReal = 0; - // Iterate over all players and count non-bot players. - for (auto const& itr : ObjectAccessor::GetPlayers()) + Player* player = itr.second; + if (!player || !player->IsInWorld()) + continue; + if (IsPlayerBot(player)) + continue; // Skip bots. + int rangeIndex = GetOrFlagPlayerBracket(player); + if (rangeIndex < 0) + continue; + if (player->GetTeamId() == TEAM_ALLIANCE) { - Player* player = itr.second; - if (!player || !player->IsInWorld()) - continue; - if (IsPlayerBot(player)) - continue; // Skip bots. - int rangeIndex = GetOrFlagPlayerBracket(player); - if (rangeIndex < 0) - continue; - if (player->GetTeamId() == TEAM_ALLIANCE) - { - allianceRealCounts[rangeIndex]++; - totalAllianceReal++; - } - else if (player->GetTeamId() == TEAM_HORDE) - { - hordeRealCounts[rangeIndex]++; - totalHordeReal++; - } + allianceRealCounts[rangeIndex]++; + totalAllianceReal++; } - // Use a baseline weight to ensure an equal share when no real players are present. - const float baseline = 1.0f; - float allianceTotalWeight = 0.0f; - float hordeTotalWeight = 0.0f; - float allianceWeights[NUM_RANGES] = { 0 }; - float hordeWeights[NUM_RANGES] = { 0 }; - for (int i = 0; i < NUM_RANGES; ++i) + else if (player->GetTeamId() == TEAM_HORDE) { - // Only count valid brackets. - if (g_AllianceLevelRanges[i].lower > g_AllianceLevelRanges[i].upper) - allianceWeights[i] = 0.0f; - else - allianceWeights[i] = baseline + g_RealPlayerWeight * + hordeRealCounts[rangeIndex]++; + totalHordeReal++; + } + } + // Use a baseline weight to ensure an equal share when no real players are present. + const float baseline = 1.0f; + float allianceTotalWeight = 0.0f; + float hordeTotalWeight = 0.0f; + float allianceWeights[NUM_RANGES] = {0}; + float hordeWeights[NUM_RANGES] = {0}; + for (int i = 0; i < NUM_RANGES; ++i) + { + // Only count valid brackets. + if (g_AllianceLevelRanges[i].lower > g_AllianceLevelRanges[i].upper) + allianceWeights[i] = 0.0f; + else + allianceWeights[i] = baseline + g_RealPlayerWeight * (totalAllianceReal > 0 ? (1.0f / totalAllianceReal) : 1.0f) * log(1 + allianceRealCounts[i]); - if (g_HordeLevelRanges[i].lower > g_HordeLevelRanges[i].upper) - hordeWeights[i] = 0.0f; - else - hordeWeights[i] = baseline + g_RealPlayerWeight * + if (g_HordeLevelRanges[i].lower > g_HordeLevelRanges[i].upper) + hordeWeights[i] = 0.0f; + else + hordeWeights[i] = baseline + g_RealPlayerWeight * (totalHordeReal > 0 ? (1.0f / totalHordeReal) : 1.0f) * log(1 + hordeRealCounts[i]); - allianceTotalWeight += allianceWeights[i]; - hordeTotalWeight += hordeWeights[i]; - } - // Recalculate desired percentages for each range. - for (int i = 0; i < NUM_RANGES; ++i) + allianceTotalWeight += allianceWeights[i]; + hordeTotalWeight += hordeWeights[i]; + } + // Recalculate desired percentages for each range. + for (int i = 0; i < NUM_RANGES; ++i) + { + g_AllianceLevelRanges[i].desiredPercent = static_cast(round((allianceWeights[i] / allianceTotalWeight) * 100)); + if (g_BotDistDebugMode) { - g_AllianceLevelRanges[i].desiredPercent = static_cast(round((allianceWeights[i] / allianceTotalWeight) * 100)); - if (g_BotDistDebugMode) - { - LOG_INFO("server.loading", "[BotLevelBrackets] Dynamic Distribution - Alliance Range {}: {}-{}, Real Players: {} (weight: {:.2f}), New Desired: {}%", - i + 1, g_AllianceLevelRanges[i].lower, g_AllianceLevelRanges[i].upper, allianceRealCounts[i], allianceWeights[i], g_AllianceLevelRanges[i].desiredPercent); - } + LOG_INFO("server.loading", "[BotLevelBrackets] Dynamic Distribution - Alliance Range {}: {}-{}, Real Players: {} (weight: {:.2f}), New Desired: {}%", + i + 1, g_AllianceLevelRanges[i].lower, g_AllianceLevelRanges[i].upper, allianceRealCounts[i], allianceWeights[i], g_AllianceLevelRanges[i].desiredPercent); } - - uint8 sumAlliance = 0; - for (int i = 0; i < NUM_RANGES; ++i) - sumAlliance += g_AllianceLevelRanges[i].desiredPercent; - if (sumAlliance < 100 && allianceTotalWeight > 0) - { - uint8 missing = 100 - sumAlliance; - if (g_BotDistDebugMode) - { - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance normalization: current sum = {}, missing = {}", sumAlliance, missing); - } - while (missing > 0) - { - for (int i = 0; i < NUM_RANGES && missing > 0; ++i) - { - if (g_AllianceLevelRanges[i].lower <= g_AllianceLevelRanges[i].upper && - allianceWeights[i] > 0) - { - g_AllianceLevelRanges[i].desiredPercent++; - missing--; - } - } - } - if (g_BotDistDebugMode) - { - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance normalized percentages:"); - for (int i = 0; i < NUM_RANGES; ++i) - { - LOG_INFO("server.loading", " Range {}: {}% ({}-{})", i + 1, - g_AllianceLevelRanges[i].desiredPercent, - g_AllianceLevelRanges[i].lower, - g_AllianceLevelRanges[i].upper); - } - } - } - - - for (int i = 0; i < NUM_RANGES; ++i) - { - g_HordeLevelRanges[i].desiredPercent = static_cast(round((hordeWeights[i] / hordeTotalWeight) * 100)); - if (g_BotDistDebugMode) - { - LOG_INFO("server.loading", "[BotLevelBrackets] Dynamic Distribution - Horde Range {}: {}-{}, Real Players: {} (weight: {:.2f}), New Desired: {}%", - i + 1, g_HordeLevelRanges[i].lower, g_HordeLevelRanges[i].upper, hordeRealCounts[i], hordeWeights[i], g_HordeLevelRanges[i].desiredPercent); - } - } - - uint8 sumHorde = 0; - for (int i = 0; i < NUM_RANGES; ++i) - sumHorde += g_HordeLevelRanges[i].desiredPercent; - if (sumHorde < 100 && hordeTotalWeight > 0) - { - uint8 missing = 100 - sumHorde; - if (g_BotDistDebugMode) - { - LOG_INFO("server.loading", "[BotLevelBrackets] Horde normalization: current sum = {}, missing = {}", sumHorde, missing); - } - while (missing > 0) - { - for (int i = 0; i < NUM_RANGES && missing > 0; ++i) - { - if (g_HordeLevelRanges[i].lower <= g_HordeLevelRanges[i].upper && - hordeWeights[i] > 0) - { - g_HordeLevelRanges[i].desiredPercent++; - missing--; - } - } - } - if (g_BotDistDebugMode) - { - LOG_INFO("server.loading", "[BotLevelBrackets] Horde normalized percentages:"); - for (int i = 0; i < NUM_RANGES; ++i) - { - LOG_INFO("server.loading", " Range {}: {}% ({}-{})", i + 1, - g_HordeLevelRanges[i].desiredPercent, - g_HordeLevelRanges[i].lower, - g_HordeLevelRanges[i].upper); - } - } - } - } - // Containers for Alliance bots. - uint32 totalAllianceBots = 0; - int allianceActualCounts[NUM_RANGES] = { 0 }; - std::vector allianceBotsByRange[NUM_RANGES]; - - // Containers for Horde bots. - uint32 totalHordeBots = 0; - int hordeActualCounts[NUM_RANGES] = { 0 }; - std::vector hordeBotsByRange[NUM_RANGES]; - - // Iterate only over player bots. - auto const& allPlayers = ObjectAccessor::GetPlayers(); - if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] Starting processing of {} players.", allPlayers.size()); - - for (auto const& itr : allPlayers) + uint8 sumAlliance = 0; + for (int i = 0; i < NUM_RANGES; ++i) + sumAlliance += g_AllianceLevelRanges[i].desiredPercent; + if (sumAlliance < 100 && allianceTotalWeight > 0) { - Player* player = itr.second; - if (!player) + uint8 missing = 100 - sumAlliance; + if (g_BotDistDebugMode) { - if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] Skipping null player."); - continue; + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance normalization: current sum = {}, missing = {}", sumAlliance, missing); } - if (!player->IsInWorld()) + while (missing > 0) { - if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] Skipping player '{}' as they are not in world.", player->GetName()); - continue; - } - if (!IsPlayerBot(player) || !IsPlayerRandomBot(player)) - { - if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] Skipping player '{}' as they are not a random bot.", player->GetName()); - continue; - } - - if (IsAlliancePlayerBot(player)) - { - totalAllianceBots++; - int rangeIndex = GetOrFlagPlayerBracket(player); - if (rangeIndex >= 0) + for (int i = 0; i < NUM_RANGES && missing > 0; ++i) { - allianceActualCounts[rangeIndex]++; - allianceBotsByRange[rangeIndex].push_back(player); + if (g_AllianceLevelRanges[i].lower <= g_AllianceLevelRanges[i].upper && + allianceWeights[i] > 0) + { + g_AllianceLevelRanges[i].desiredPercent++; + missing--; + } + } + } + if (g_BotDistDebugMode) + { + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance normalized percentages:"); + for (int i = 0; i < NUM_RANGES; ++i) + { + LOG_INFO("server.loading", " Range {}: {}% ({}-{})", i + 1, + g_AllianceLevelRanges[i].desiredPercent, + g_AllianceLevelRanges[i].lower, + g_AllianceLevelRanges[i].upper); + } + } + } + + + for (int i = 0; i < NUM_RANGES; ++i) + { + g_HordeLevelRanges[i].desiredPercent = static_cast(round((hordeWeights[i] / hordeTotalWeight) * 100)); + if (g_BotDistDebugMode) + { + LOG_INFO("server.loading", "[BotLevelBrackets] Dynamic Distribution - Horde Range {}: {}-{}, Real Players: {} (weight: {:.2f}), New Desired: {}%", + i + 1, g_HordeLevelRanges[i].lower, g_HordeLevelRanges[i].upper, hordeRealCounts[i], hordeWeights[i], g_HordeLevelRanges[i].desiredPercent); + } + } + + uint8 sumHorde = 0; + for (int i = 0; i < NUM_RANGES; ++i) + sumHorde += g_HordeLevelRanges[i].desiredPercent; + if (sumHorde < 100 && hordeTotalWeight > 0) + { + uint8 missing = 100 - sumHorde; + if (g_BotDistDebugMode) + { + LOG_INFO("server.loading", "[BotLevelBrackets] Horde normalization: current sum = {}, missing = {}", sumHorde, missing); + } + while (missing > 0) + { + for (int i = 0; i < NUM_RANGES && missing > 0; ++i) + { + if (g_HordeLevelRanges[i].lower <= g_HordeLevelRanges[i].upper && + hordeWeights[i] > 0) + { + g_HordeLevelRanges[i].desiredPercent++; + missing--; + } + } + } + if (g_BotDistDebugMode) + { + LOG_INFO("server.loading", "[BotLevelBrackets] Horde normalized percentages:"); + for (int i = 0; i < NUM_RANGES; ++i) + { + LOG_INFO("server.loading", " Range {}: {}% ({}-{})", i + 1, + g_HordeLevelRanges[i].desiredPercent, + g_HordeLevelRanges[i].lower, + g_HordeLevelRanges[i].upper); + } + } + } + + } + + // Containers for Alliance bots. + uint32 totalAllianceBots = 0; + int allianceActualCounts[NUM_RANGES] = {0}; + std::vector allianceBotsByRange[NUM_RANGES]; + + // Containers for Horde bots. + uint32 totalHordeBots = 0; + int hordeActualCounts[NUM_RANGES] = {0}; + std::vector hordeBotsByRange[NUM_RANGES]; + + // Iterate only over player bots. + auto const& allPlayers = ObjectAccessor::GetPlayers(); + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] Starting processing of {} players.", allPlayers.size()); + + for (auto const& itr : allPlayers) + { + Player* player = itr.second; + if (!player) + { + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] Skipping null player."); + continue; + } + if (!player->IsInWorld()) + { + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] Skipping player '{}' as they are not in world.", player->GetName()); + continue; + } + if (!IsPlayerBot(player) || !IsPlayerRandomBot(player)) + { + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] Skipping player '{}' as they are not a random bot.", player->GetName()); + continue; + } + + if (IsAlliancePlayerBot(player)) + { + totalAllianceBots++; + int rangeIndex = GetOrFlagPlayerBracket(player); + if (rangeIndex >= 0) + { + allianceActualCounts[rangeIndex]++; + allianceBotsByRange[rangeIndex].push_back(player); + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' with level {} added to range {}.", + player->GetName(), player->GetLevel(), rangeIndex + 1); + } + else if (g_BotDistDebugMode) + { + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' with level {} does not fall into any defined range.", + player->GetName(), player->GetLevel()); + } + } + else if (IsHordePlayerBot(player)) + { + totalHordeBots++; + int rangeIndex = GetOrFlagPlayerBracket(player); + if (rangeIndex >= 0) + { + hordeActualCounts[rangeIndex]++; + hordeBotsByRange[rangeIndex].push_back(player); + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' with level {} added to range {}.", + player->GetName(), player->GetLevel(), rangeIndex + 1); + } + else if (g_BotDistDebugMode) + { + LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' with level {} does not fall into any defined range.", + player->GetName(), player->GetLevel()); + } + } + } + + if (g_BotDistDebugMode) + { + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); + LOG_INFO("server.loading", "[BotLevelBrackets] Total Alliance Bots: {}.", totalAllianceBots); + LOG_INFO("server.loading", "[BotLevelBrackets] Total Horde Bots: {}.", totalHordeBots); + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); + } + + // Process Alliance bots. + if (totalAllianceBots > 0) + { + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); + int allianceDesiredCounts[NUM_RANGES] = {0}; + for (int i = 0; i < NUM_RANGES; ++i) + { + allianceDesiredCounts[i] = static_cast(round((g_AllianceLevelRanges[i].desiredPercent / 100.0) * totalAllianceBots)); + if (g_BotDistDebugMode) + { + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance Range {} ({}-{}): Desired = {}, Actual = {}.", + i + 1, g_AllianceLevelRanges[i].lower, g_AllianceLevelRanges[i].upper, + allianceDesiredCounts[i], allianceActualCounts[i]); + } + } + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); + // Adjust overpopulated ranges. + for (int i = 0; i < NUM_RANGES; ++i) + { + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] >>> Processing Alliance bots in range {}.", i + 1); + + std::vector safeBots; + std::vector flaggedBots; + for (Player* bot : allianceBotsByRange[i]) + { + if (IsBotSafeForLevelReset(bot)) + { + safeBots.push_back(bot); if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' with level {} added to range {}.", - player->GetName(), player->GetLevel(), rangeIndex + 1); + { + //LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' is safe for level reset in range {}.", bot->GetName(), i + 1); + } } - else if (g_BotDistDebugMode) + else { - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' with level {} does not fall into any defined range.", - player->GetName(), player->GetLevel()); - } - } - else if (IsHordePlayerBot(player)) - { - totalHordeBots++; - int rangeIndex = GetOrFlagPlayerBracket(player); - if (rangeIndex >= 0) - { - hordeActualCounts[rangeIndex]++; - hordeBotsByRange[rangeIndex].push_back(player); + flaggedBots.push_back(bot); if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' with level {} added to range {}.", - player->GetName(), player->GetLevel(), rangeIndex + 1); - } - else if (g_BotDistDebugMode) - { - LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' with level {} does not fall into any defined range.", - player->GetName(), player->GetLevel()); + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' is NOT safe for level reset in range {}.", + bot->GetName(), i + 1); } } - } - - if (g_BotDistDebugMode) - { - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - LOG_INFO("server.loading", "[BotLevelBrackets] Total Alliance Bots: {}.", totalAllianceBots); - LOG_INFO("server.loading", "[BotLevelBrackets] Total Horde Bots: {}.", totalHordeBots); - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - } - - // Process Alliance bots. - if (totalAllianceBots > 0) - { - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - int allianceDesiredCounts[NUM_RANGES] = { 0 }; - for (int i = 0; i < NUM_RANGES; ++i) + while (allianceActualCounts[i] > allianceDesiredCounts[i] && !safeBots.empty()) { - allianceDesiredCounts[i] = static_cast(round((g_AllianceLevelRanges[i].desiredPercent / 100.0) * totalAllianceBots)); - if (g_BotDistDebugMode) + Player* bot = safeBots.back(); + safeBots.pop_back(); + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance safe bot '{}' from range {} will be moved.", + bot->GetName(), i + 1); + int targetRange = -1; + if (bot->getClass() == CLASS_DEATH_KNIGHT) { - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance Range {} ({}-{}): Desired = {}, Actual = {}.", - i + 1, g_AllianceLevelRanges[i].lower, g_AllianceLevelRanges[i].upper, - allianceDesiredCounts[i], allianceActualCounts[i]); - } - } - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - // Adjust overpopulated ranges. - for (int i = 0; i < NUM_RANGES; ++i) - { - if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] >>> Processing Alliance bots in range {}.", i + 1); - - std::vector safeBots; - std::vector flaggedBots; - for (Player* bot : allianceBotsByRange[i]) - { - if (IsBotSafeForLevelReset(bot)) + for (int j = 0; j < NUM_RANGES; ++j) { - safeBots.push_back(bot); - if (g_BotDistDebugMode) + if (allianceActualCounts[j] < allianceDesiredCounts[j] && g_AllianceLevelRanges[j].upper >= 55) { - //LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' is safe for level reset in range {}.", bot->GetName(), i + 1); - } - } - else - { - flaggedBots.push_back(bot); - if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' is NOT safe for level reset in range {}.", - bot->GetName(), i + 1); - } - } - while (allianceActualCounts[i] > allianceDesiredCounts[i] && !safeBots.empty()) - { - Player* bot = safeBots.back(); - safeBots.pop_back(); - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance safe bot '{}' from range {} will be moved.", - bot->GetName(), i + 1); - int targetRange = -1; - if (bot->getClass() == CLASS_DEATH_KNIGHT) - { - for (int j = 0; j < NUM_RANGES; ++j) - { - if (allianceActualCounts[j] < allianceDesiredCounts[j] && g_AllianceLevelRanges[j].upper >= 55) - { - targetRange = j; - break; - } - } - } - else - { - for (int j = 0; j < NUM_RANGES; ++j) - { - if (allianceActualCounts[j] < allianceDesiredCounts[j]) - { - targetRange = j; - break; - } - } - } - if (targetRange == -1) - { - LOG_INFO("server.loading", "[BotLevelBrackets] No valid target range found for alliance safe bot '{}'.", bot->GetName()); - break; - } - LOG_INFO("server.loading", "[BotLevelBrackets] !!!! Adjusting alliance bot '{}' from range {} to range {} ({}-{}).", - bot->GetName(), i + 1, targetRange + 1, g_AllianceLevelRanges[targetRange].lower, g_AllianceLevelRanges[targetRange].upper); - AdjustBotToRange(bot, targetRange, g_AllianceLevelRanges); - allianceActualCounts[i]--; - allianceActualCounts[targetRange]++; - } - while (allianceActualCounts[i] > allianceDesiredCounts[i] && !flaggedBots.empty()) - { - Player* bot = flaggedBots.back(); - flaggedBots.pop_back(); - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance flagged bot '{}' from range {} will be processed for pending reset.", - bot->GetName(), i + 1); - int targetRange = -1; - if (bot->getClass() == CLASS_DEATH_KNIGHT) - { - for (int j = 0; j < NUM_RANGES; ++j) - { - if (allianceActualCounts[j] < allianceDesiredCounts[j] && g_AllianceLevelRanges[j].upper >= 55) - { - targetRange = j; - break; - } - } - } - else - { - for (int j = 0; j < NUM_RANGES; ++j) - { - if (allianceActualCounts[j] < allianceDesiredCounts[j]) - { - targetRange = j; - break; - } - } - } - if (targetRange == -1) - { - LOG_INFO("server.loading", "[BotLevelBrackets] No valid target range found for flagged alliance bot '{}' for pending reset.", bot->GetName()); - break; - } - bool alreadyFlagged = false; - for (auto& entry : g_PendingLevelResets) - { - if (entry.bot == bot) - { - alreadyFlagged = true; + targetRange = j; break; } } - if (!alreadyFlagged) - { - g_PendingLevelResets.push_back({ bot, targetRange, g_AllianceLevelRanges }); - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' flagged for pending level reset to range {}-{}.", - bot->GetName(), g_AllianceLevelRanges[targetRange].lower, g_AllianceLevelRanges[targetRange].upper); - } } - } - } - - // Process Horde bots. - if (totalHordeBots > 0) - { - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - int hordeDesiredCounts[NUM_RANGES] = { 0 }; - for (int i = 0; i < NUM_RANGES; ++i) - { - hordeDesiredCounts[i] = static_cast(round((g_HordeLevelRanges[i].desiredPercent / 100.0) * totalHordeBots)); - if (g_BotDistDebugMode) + else { - LOG_INFO("server.loading", "[BotLevelBrackets] Horde Range {} ({}-{}): Desired = {}, Actual = {}.", - i + 1, g_HordeLevelRanges[i].lower, g_HordeLevelRanges[i].upper, - hordeDesiredCounts[i], hordeActualCounts[i]); - } - } - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - for (int i = 0; i < NUM_RANGES; ++i) - { - if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] Processing Horde bots in range {}.", i + 1); - - std::vector safeBots; - std::vector flaggedBots; - for (Player* bot : hordeBotsByRange[i]) - { - if (IsBotSafeForLevelReset(bot)) + for (int j = 0; j < NUM_RANGES; ++j) { - safeBots.push_back(bot); - if (g_BotDistDebugMode) + if (allianceActualCounts[j] < allianceDesiredCounts[j]) { - //LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' is safe for level reset in range {}.", bot->GetName(), i + 1); - } - } - else - { - flaggedBots.push_back(bot); - if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' is NOT safe for level reset in range {}.", - bot->GetName(), i + 1); - } - } - while (hordeActualCounts[i] > hordeDesiredCounts[i] && !safeBots.empty()) - { - Player* bot = safeBots.back(); - safeBots.pop_back(); - LOG_INFO("server.loading", "[BotLevelBrackets] Horde safe bot '{}' from range {} will be moved.", - bot->GetName(), i + 1); - int targetRange = -1; - if (bot->getClass() == CLASS_DEATH_KNIGHT) - { - for (int j = 0; j < NUM_RANGES; ++j) - { - if (hordeActualCounts[j] < hordeDesiredCounts[j] && g_HordeLevelRanges[j].upper >= 55) - { - targetRange = j; - break; - } - } - } - else - { - for (int j = 0; j < NUM_RANGES; ++j) - { - if (hordeActualCounts[j] < hordeDesiredCounts[j]) - { - targetRange = j; - break; - } - } - } - if (targetRange == -1) - { - LOG_INFO("server.loading", "[BotLevelBrackets] No valid target range found for safe horde bot '{}'.", bot->GetName()); - break; - } - LOG_INFO("server.loading", "[BotLevelBrackets] !!!! Adjusting horde bot '{}' from range {} to range {} ({}-{}).", - bot->GetName(), i + 1, targetRange + 1, g_HordeLevelRanges[targetRange].lower, g_HordeLevelRanges[targetRange].upper); - AdjustBotToRange(bot, targetRange, g_HordeLevelRanges); - hordeActualCounts[i]--; - hordeActualCounts[targetRange]++; - } - while (hordeActualCounts[i] > hordeDesiredCounts[i] && !flaggedBots.empty()) - { - Player* bot = flaggedBots.back(); - flaggedBots.pop_back(); - LOG_INFO("server.loading", "[BotLevelBrackets] Horde flagged bot '{}' from range {} will be processed for pending reset.", - bot->GetName(), i + 1); - int targetRange = -1; - if (bot->getClass() == CLASS_DEATH_KNIGHT) - { - for (int j = 0; j < NUM_RANGES; ++j) - { - if (hordeActualCounts[j] < hordeDesiredCounts[j] && g_HordeLevelRanges[j].upper >= 55) - { - targetRange = j; - break; - } - } - } - else - { - for (int j = 0; j < NUM_RANGES; ++j) - { - if (hordeActualCounts[j] < hordeDesiredCounts[j]) - { - targetRange = j; - break; - } - } - } - if (targetRange == -1) - { - LOG_INFO("server.loading", "[BotLevelBrackets] No valid target range found for flagged horde bot '{}' for pending reset.", bot->GetName()); - break; - } - bool alreadyFlagged = false; - for (auto& entry : g_PendingLevelResets) - { - if (entry.bot == bot) - { - alreadyFlagged = true; + targetRange = j; break; } } - if (!alreadyFlagged) + } + if (targetRange == -1) + { + LOG_INFO("server.loading", "[BotLevelBrackets] No valid target range found for alliance safe bot '{}'.", bot->GetName()); + break; + } + LOG_INFO("server.loading", "[BotLevelBrackets] !!!! Adjusting alliance bot '{}' from range {} to range {} ({}-{}).", + bot->GetName(), i + 1, targetRange + 1, g_AllianceLevelRanges[targetRange].lower, g_AllianceLevelRanges[targetRange].upper); + AdjustBotToRange(bot, targetRange, g_AllianceLevelRanges); + allianceActualCounts[i]--; + allianceActualCounts[targetRange]++; + } + while (allianceActualCounts[i] > allianceDesiredCounts[i] && !flaggedBots.empty()) + { + Player* bot = flaggedBots.back(); + flaggedBots.pop_back(); + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance flagged bot '{}' from range {} will be processed for pending reset.", + bot->GetName(), i + 1); + int targetRange = -1; + if (bot->getClass() == CLASS_DEATH_KNIGHT) + { + for (int j = 0; j < NUM_RANGES; ++j) { - g_PendingLevelResets.push_back({ bot, targetRange, g_HordeLevelRanges }); - LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' flagged for pending level reset to range {}-{}.", - bot->GetName(), g_HordeLevelRanges[targetRange].lower, g_HordeLevelRanges[targetRange].upper); + if (allianceActualCounts[j] < allianceDesiredCounts[j] && g_AllianceLevelRanges[j].upper >= 55) + { + targetRange = j; + break; + } } } + else + { + for (int j = 0; j < NUM_RANGES; ++j) + { + if (allianceActualCounts[j] < allianceDesiredCounts[j]) + { + targetRange = j; + break; + } + } + } + if (targetRange == -1) + { + LOG_INFO("server.loading", "[BotLevelBrackets] No valid target range found for flagged alliance bot '{}' for pending reset.", bot->GetName()); + break; + } + bool alreadyFlagged = false; + for (auto& entry : g_PendingLevelResets) + { + if (entry.bot == bot) + { + alreadyFlagged = true; + break; + } + } + if (!alreadyFlagged) + { + g_PendingLevelResets.push_back({bot, targetRange, g_AllianceLevelRanges}); + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' flagged for pending level reset to range {}-{}.", + bot->GetName(), g_AllianceLevelRanges[targetRange].lower, g_AllianceLevelRanges[targetRange].upper); + } } } + } - - if (g_BotDistDebugMode) + // Process Horde bots. + if (totalHordeBots > 0) + { + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); + int hordeDesiredCounts[NUM_RANGES] = {0}; + for (int i = 0; i < NUM_RANGES; ++i) { - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================= COMPLETE"); - LOG_INFO("server.loading", "[BotLevelBrackets] Distribution adjustment complete. Alliance bots: {}, Horde bots: {}.", - totalAllianceBots, totalHordeBots); - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - LogAllBotLevels(); - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - int allianceDesiredCounts[NUM_RANGES] = { 0 }; - for (int i = 0; i < NUM_RANGES; ++i) + hordeDesiredCounts[i] = static_cast(round((g_HordeLevelRanges[i].desiredPercent / 100.0) * totalHordeBots)); + if (g_BotDistDebugMode) { - allianceDesiredCounts[i] = static_cast(round((g_AllianceLevelRanges[i].desiredPercent / 100.0) * totalAllianceBots)); - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance Range {} ({}-{}): Desired = {}, Actual = {}.", - i + 1, g_AllianceLevelRanges[i].lower, g_AllianceLevelRanges[i].upper, - allianceDesiredCounts[i], allianceActualCounts[i]); - } - LOG_INFO("server.loading", "[BotLevelBrackets] ----------------------------------------"); - int hordeDesiredCounts[NUM_RANGES] = { 0 }; - for (int i = 0; i < NUM_RANGES; ++i) - { - hordeDesiredCounts[i] = static_cast(round((g_HordeLevelRanges[i].desiredPercent / 100.0) * totalHordeBots)); LOG_INFO("server.loading", "[BotLevelBrackets] Horde Range {} ({}-{}): Desired = {}, Actual = {}.", - i + 1, g_HordeLevelRanges[i].lower, g_HordeLevelRanges[i].upper, - hordeDesiredCounts[i], hordeActualCounts[i]); + i + 1, g_HordeLevelRanges[i].lower, g_HordeLevelRanges[i].upper, + hordeDesiredCounts[i], hordeActualCounts[i]); } - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - } + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); + for (int i = 0; i < NUM_RANGES; ++i) + { + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] Processing Horde bots in range {}.", i + 1); + + std::vector safeBots; + std::vector flaggedBots; + for (Player* bot : hordeBotsByRange[i]) + { + if (IsBotSafeForLevelReset(bot)) + { + safeBots.push_back(bot); + if (g_BotDistDebugMode) + { + //LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' is safe for level reset in range {}.", bot->GetName(), i + 1); + } + } + else + { + flaggedBots.push_back(bot); + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' is NOT safe for level reset in range {}.", + bot->GetName(), i + 1); + } + } + while (hordeActualCounts[i] > hordeDesiredCounts[i] && !safeBots.empty()) + { + Player* bot = safeBots.back(); + safeBots.pop_back(); + LOG_INFO("server.loading", "[BotLevelBrackets] Horde safe bot '{}' from range {} will be moved.", + bot->GetName(), i + 1); + int targetRange = -1; + if (bot->getClass() == CLASS_DEATH_KNIGHT) + { + for (int j = 0; j < NUM_RANGES; ++j) + { + if (hordeActualCounts[j] < hordeDesiredCounts[j] && g_HordeLevelRanges[j].upper >= 55) + { + targetRange = j; + break; + } + } + } + else + { + for (int j = 0; j < NUM_RANGES; ++j) + { + if (hordeActualCounts[j] < hordeDesiredCounts[j]) + { + targetRange = j; + break; + } + } + } + if (targetRange == -1) + { + LOG_INFO("server.loading", "[BotLevelBrackets] No valid target range found for safe horde bot '{}'.", bot->GetName()); + break; + } + LOG_INFO("server.loading", "[BotLevelBrackets] !!!! Adjusting horde bot '{}' from range {} to range {} ({}-{}).", + bot->GetName(), i + 1, targetRange + 1, g_HordeLevelRanges[targetRange].lower, g_HordeLevelRanges[targetRange].upper); + AdjustBotToRange(bot, targetRange, g_HordeLevelRanges); + hordeActualCounts[i]--; + hordeActualCounts[targetRange]++; + } + while (hordeActualCounts[i] > hordeDesiredCounts[i] && !flaggedBots.empty()) + { + Player* bot = flaggedBots.back(); + flaggedBots.pop_back(); + LOG_INFO("server.loading", "[BotLevelBrackets] Horde flagged bot '{}' from range {} will be processed for pending reset.", + bot->GetName(), i + 1); + int targetRange = -1; + if (bot->getClass() == CLASS_DEATH_KNIGHT) + { + for (int j = 0; j < NUM_RANGES; ++j) + { + if (hordeActualCounts[j] < hordeDesiredCounts[j] && g_HordeLevelRanges[j].upper >= 55) + { + targetRange = j; + break; + } + } + } + else + { + for (int j = 0; j < NUM_RANGES; ++j) + { + if (hordeActualCounts[j] < hordeDesiredCounts[j]) + { + targetRange = j; + break; + } + } + } + if (targetRange == -1) + { + LOG_INFO("server.loading", "[BotLevelBrackets] No valid target range found for flagged horde bot '{}' for pending reset.", bot->GetName()); + break; + } + bool alreadyFlagged = false; + for (auto& entry : g_PendingLevelResets) + { + if (entry.bot == bot) + { + alreadyFlagged = true; + break; + } + } + if (!alreadyFlagged) + { + g_PendingLevelResets.push_back({bot, targetRange, g_HordeLevelRanges}); + LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' flagged for pending level reset to range {}-{}.", + bot->GetName(), g_HordeLevelRanges[targetRange].lower, g_HordeLevelRanges[targetRange].upper); + } + } + } + } + + + if (g_BotDistDebugMode) + { + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================= COMPLETE"); + LOG_INFO("server.loading", "[BotLevelBrackets] Distribution adjustment complete. Alliance bots: {}, Horde bots: {}.", + totalAllianceBots, totalHordeBots); + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); + LogAllBotLevels(); + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); + int allianceDesiredCounts[NUM_RANGES] = {0}; + for (int i = 0; i < NUM_RANGES; ++i) + { + allianceDesiredCounts[i] = static_cast(round((g_AllianceLevelRanges[i].desiredPercent / 100.0) * totalAllianceBots)); + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance Range {} ({}-{}): Desired = {}, Actual = {}.", + i + 1, g_AllianceLevelRanges[i].lower, g_AllianceLevelRanges[i].upper, + allianceDesiredCounts[i], allianceActualCounts[i]); + } + LOG_INFO("server.loading", "[BotLevelBrackets] ----------------------------------------"); + int hordeDesiredCounts[NUM_RANGES] = {0}; + for (int i = 0; i < NUM_RANGES; ++i) + { + hordeDesiredCounts[i] = static_cast(round((g_HordeLevelRanges[i].desiredPercent / 100.0) * totalHordeBots)); + LOG_INFO("server.loading", "[BotLevelBrackets] Horde Range {} ({}-{}): Desired = {}, Actual = {}.", + i + 1, g_HordeLevelRanges[i].lower, g_HordeLevelRanges[i].upper, + hordeDesiredCounts[i], hordeActualCounts[i]); + } + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); + } } From ca380ade3e1c0e7681efcac583680d494c14f1ed Mon Sep 17 00:00:00 2001 From: jimm0thy <25890053+jimm0thy@users.noreply.github.com> Date: Tue, 25 Feb 2025 14:15:24 -0500 Subject: [PATCH 4/4] Setting up separate branch for IgnoreFriends option by itself --- conf/mod_player_bot_level_brackets.conf.dist | 6 - src/mod-player-bot-level-brackets.cpp | 1149 +++++++++--------- 2 files changed, 569 insertions(+), 586 deletions(-) diff --git a/conf/mod_player_bot_level_brackets.conf.dist b/conf/mod_player_bot_level_brackets.conf.dist index 4d96cef..741b8b4 100644 --- a/conf/mod_player_bot_level_brackets.conf.dist +++ b/conf/mod_player_bot_level_brackets.conf.dist @@ -3,12 +3,6 @@ ############################################## # mod-player-bot-level-brackets configuration ############################################## -# BotLevelBrackets.ModEnabled -# Description: Turns module on/on -# Default: 1 (enabled) -# Valid Values: 0 (off) / 1 (on) -BotLevelBrackets.ModEnabled = 1 - # # BotLevelBrackets.DebugMode # Description: Enables debug logging for the Bot Level Brackets module. diff --git a/src/mod-player-bot-level-brackets.cpp b/src/mod-player-bot-level-brackets.cpp index ae35962..815fa45 100644 --- a/src/mod-player-bot-level-brackets.cpp +++ b/src/mod-player-bot-level-brackets.cpp @@ -51,7 +51,6 @@ static uint32 g_BotDistFlaggedCheckFrequency = 15; // in seconds static bool g_BotDistDebugMode = false; static bool g_UseDynamicDistribution = false; static bool g_IgnoreFriendListed = true; -static bool g_EnableMod = true; // Real player weight to boost bracket contributions. static float g_RealPlayerWeight = 1.0f; @@ -65,7 +64,6 @@ static void LoadBotLevelBracketsConfig() g_UseDynamicDistribution = sConfigMgr->GetOption("BotLevelBrackets.UseDynamicDistribution", false); g_RealPlayerWeight = sConfigMgr->GetOption("BotLevelBrackets.RealPlayerWeight", 1.0f); g_IgnoreFriendListed = sConfigMgr->GetOption("BotLevelBrackets.IgnoreFriendListed", true); - g_EnableMod = sConfigMgr->GetOption("BotLevelBrackets.ModEnabled", true); // Load the bot level restrictions. g_RandomBotMinLevel = static_cast(sConfigMgr->GetOption("AiPlayerbot.RandomBotMinLevel", 1)); @@ -100,32 +98,29 @@ static void LoadBotLevelBracketsConfig() // If the bot is out of range, it returns -1 static int GetLevelRangeIndex(uint8 level, uint8 teamID) { - if (g_EnableMod) - { - // If the bot's level is outside the allowed global bounds, signal an invalid bracket. - if (level < g_RandomBotMinLevel || level > g_RandomBotMaxLevel) - return -1; - - if (teamID == TEAM_ALLIANCE) - { - for (int i = 0; i < NUM_RANGES; ++i) - { - if (level >= g_AllianceLevelRanges[i].lower && level <= g_AllianceLevelRanges[i].upper) - return i; - } - } - - if (teamID == TEAM_HORDE) - { - for (int i = 0; i < NUM_RANGES; ++i) - { - if (level >= g_HordeLevelRanges[i].lower && level <= g_HordeLevelRanges[i].upper) - return i; - } - } - + // If the bot's level is outside the allowed global bounds, signal an invalid bracket. + if (level < g_RandomBotMinLevel || level > g_RandomBotMaxLevel) return -1; + + if(teamID == TEAM_ALLIANCE) + { + for (int i = 0; i < NUM_RANGES; ++i) + { + if (level >= g_AllianceLevelRanges[i].lower && level <= g_AllianceLevelRanges[i].upper) + return i; + } } + + if(teamID == TEAM_HORDE) + { + for (int i = 0; i < NUM_RANGES; ++i) + { + if (level >= g_HordeLevelRanges[i].lower && level <= g_HordeLevelRanges[i].upper) + return i; + } + } + + return -1; } // Returns a random level within the provided range. @@ -243,73 +238,70 @@ static void LogAllBotLevels() static void ClampAndBalanceBrackets() { - if (g_EnableMod) + // First, adjust Alliance brackets. + for (uint8 i = 0; i < NUM_RANGES; ++i) + { + if (g_AllianceLevelRanges[i].lower < g_RandomBotMinLevel) + g_AllianceLevelRanges[i].lower = g_RandomBotMinLevel; + if (g_AllianceLevelRanges[i].upper > g_RandomBotMaxLevel) + g_AllianceLevelRanges[i].upper = g_RandomBotMaxLevel; + // If the adjusted bracket is invalid, mark it to not be used. + if (g_AllianceLevelRanges[i].lower > g_AllianceLevelRanges[i].upper) + g_AllianceLevelRanges[i].desiredPercent = 0; + } + // Then, adjust Horde brackets similarly. + for (uint8 i = 0; i < NUM_RANGES; ++i) + { + if (g_HordeLevelRanges[i].lower < g_RandomBotMinLevel) + g_HordeLevelRanges[i].lower = g_RandomBotMinLevel; + if (g_HordeLevelRanges[i].upper > g_RandomBotMaxLevel) + g_HordeLevelRanges[i].upper = g_RandomBotMaxLevel; + if (g_HordeLevelRanges[i].lower > g_HordeLevelRanges[i].upper) + g_HordeLevelRanges[i].desiredPercent = 0; + } + // Balance desired percentages so the sum is 100. + uint32 totalAlliance = 0; + uint32 totalHorde = 0; + for (uint8 i = 0; i < NUM_RANGES; ++i) + { + totalAlliance += g_AllianceLevelRanges[i].desiredPercent; + totalHorde += g_HordeLevelRanges[i].desiredPercent; + } + // If totals are not 100, then distribute the missing percent among valid brackets. + if(totalAlliance != 100 && totalAlliance > 0) { - // First, adjust Alliance brackets. - for (uint8 i = 0; i < NUM_RANGES; ++i) - { - if (g_AllianceLevelRanges[i].lower < g_RandomBotMinLevel) - g_AllianceLevelRanges[i].lower = g_RandomBotMinLevel; - if (g_AllianceLevelRanges[i].upper > g_RandomBotMaxLevel) - g_AllianceLevelRanges[i].upper = g_RandomBotMaxLevel; - // If the adjusted bracket is invalid, mark it to not be used. - if (g_AllianceLevelRanges[i].lower > g_AllianceLevelRanges[i].upper) - g_AllianceLevelRanges[i].desiredPercent = 0; - } - // Then, adjust Horde brackets similarly. - for (uint8 i = 0; i < NUM_RANGES; ++i) - { - if (g_HordeLevelRanges[i].lower < g_RandomBotMinLevel) - g_HordeLevelRanges[i].lower = g_RandomBotMinLevel; - if (g_HordeLevelRanges[i].upper > g_RandomBotMaxLevel) - g_HordeLevelRanges[i].upper = g_RandomBotMaxLevel; - if (g_HordeLevelRanges[i].lower > g_HordeLevelRanges[i].upper) - g_HordeLevelRanges[i].desiredPercent = 0; - } - // Balance desired percentages so the sum is 100. - uint32 totalAlliance = 0; - uint32 totalHorde = 0; - for (uint8 i = 0; i < NUM_RANGES; ++i) - { - totalAlliance += g_AllianceLevelRanges[i].desiredPercent; - totalHorde += g_HordeLevelRanges[i].desiredPercent; - } - // If totals are not 100, then distribute the missing percent among valid brackets. - if (totalAlliance != 100 && totalAlliance > 0) - { - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance: Sum of percentages is {} (expected 100). Auto adjusting.", totalAlliance); - - int missing = 100 - totalAlliance; - while (missing > 0) + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance: Sum of percentages is {} (expected 100). Auto adjusting.", totalAlliance); + + int missing = 100 - totalAlliance; + while(missing > 0) + { + for (uint8 i = 0; i < NUM_RANGES && missing > 0; ++i) { - for (uint8 i = 0; i < NUM_RANGES && missing > 0; ++i) + if(g_AllianceLevelRanges[i].lower <= g_AllianceLevelRanges[i].upper && + g_AllianceLevelRanges[i].desiredPercent > 0) { - if (g_AllianceLevelRanges[i].lower <= g_AllianceLevelRanges[i].upper && - g_AllianceLevelRanges[i].desiredPercent > 0) - { - g_AllianceLevelRanges[i].desiredPercent++; - missing--; - } + g_AllianceLevelRanges[i].desiredPercent++; + missing--; } } } - if (totalHorde != 100 && totalHorde > 0) + } + if(totalHorde != 100 && totalHorde > 0) + { + + LOG_INFO("server.loading", "[BotLevelBrackets] Horde: Sum of percentages is {} (expected 100). Auto adjusting.", totalHorde); + + int missing = 100 - totalHorde; + while(missing > 0) { - - LOG_INFO("server.loading", "[BotLevelBrackets] Horde: Sum of percentages is {} (expected 100). Auto adjusting.", totalHorde); - - int missing = 100 - totalHorde; - while (missing > 0) + for (uint8 i = 0; i < NUM_RANGES && missing > 0; ++i) { - for (uint8 i = 0; i < NUM_RANGES && missing > 0; ++i) + if(g_HordeLevelRanges[i].lower <= g_HordeLevelRanges[i].upper && + g_HordeLevelRanges[i].desiredPercent > 0) { - if (g_HordeLevelRanges[i].lower <= g_HordeLevelRanges[i].upper && - g_HordeLevelRanges[i].desiredPercent > 0) - { - g_HordeLevelRanges[i].desiredPercent++; - missing--; - } + g_HordeLevelRanges[i].desiredPercent++; + missing--; } } } @@ -403,7 +395,7 @@ static void ProcessPendingLevelResets() Player* bot = it->bot; int targetRange = it->targetRange; - if (bot && bot->IsInWorld() && IsBotSafeForLevelReset(bot) && g_EnableMod) + if (bot && bot->IsInWorld() && IsBotSafeForLevelReset(bot)) { AdjustBotToRange(bot, targetRange, it->factionRanges); LOG_INFO("server.loading", "[BotLevelBrackets] Bot '{}' successfully reset to level range {}-{}.", @@ -505,554 +497,551 @@ public: void OnUpdate(uint32 diff) override { - if (g_EnableMod) + m_timer += diff; + m_flaggedTimer += diff; + + // Process pending level resets. + if (m_flaggedTimer >= g_BotDistFlaggedCheckFrequency * 1000) { - m_timer += diff; - m_flaggedTimer += diff; + LOG_INFO("server.loading", "[BotLevelBrackets] Pending Level Resets Triggering."); + ProcessPendingLevelResets(); + m_flaggedTimer = 0; + } - // Process pending level resets. - if (m_flaggedTimer >= g_BotDistFlaggedCheckFrequency * 1000) + // Continue with distribution adjustments once the timer expires. + if (m_timer < g_BotDistCheckFrequency * 1000) + return; + m_timer = 0; + + // Dynamic distribution: recalc desired percentages based on non-bot players. + if (g_UseDynamicDistribution) + { + int allianceRealCounts[NUM_RANGES] = {0}; + int hordeRealCounts[NUM_RANGES] = {0}; + uint32 totalAllianceReal = 0; + uint32 totalHordeReal = 0; + // Iterate over all players and count non-bot players. + for (auto const& itr : ObjectAccessor::GetPlayers()) { - LOG_INFO("server.loading", "[BotLevelBrackets] Pending Level Resets Triggering."); - ProcessPendingLevelResets(); - m_flaggedTimer = 0; - } - - // Continue with distribution adjustments once the timer expires. - if (m_timer < g_BotDistCheckFrequency * 1000) - return; - m_timer = 0; - - // Dynamic distribution: recalc desired percentages based on non-bot players. - if (g_UseDynamicDistribution) - { - int allianceRealCounts[NUM_RANGES] = { 0 }; - int hordeRealCounts[NUM_RANGES] = { 0 }; - uint32 totalAllianceReal = 0; - uint32 totalHordeReal = 0; - // Iterate over all players and count non-bot players. - for (auto const& itr : ObjectAccessor::GetPlayers()) + Player* player = itr.second; + if (!player || !player->IsInWorld()) + continue; + if (IsPlayerBot(player)) + continue; // Skip bots. + int rangeIndex = GetOrFlagPlayerBracket(player); + if (rangeIndex < 0) + continue; + if (player->GetTeamId() == TEAM_ALLIANCE) { - Player* player = itr.second; - if (!player || !player->IsInWorld()) - continue; - if (IsPlayerBot(player)) - continue; // Skip bots. - int rangeIndex = GetOrFlagPlayerBracket(player); - if (rangeIndex < 0) - continue; - if (player->GetTeamId() == TEAM_ALLIANCE) - { - allianceRealCounts[rangeIndex]++; - totalAllianceReal++; - } - else if (player->GetTeamId() == TEAM_HORDE) - { - hordeRealCounts[rangeIndex]++; - totalHordeReal++; - } + allianceRealCounts[rangeIndex]++; + totalAllianceReal++; } - // Use a baseline weight to ensure an equal share when no real players are present. - const float baseline = 1.0f; - float allianceTotalWeight = 0.0f; - float hordeTotalWeight = 0.0f; - float allianceWeights[NUM_RANGES] = { 0 }; - float hordeWeights[NUM_RANGES] = { 0 }; - for (int i = 0; i < NUM_RANGES; ++i) + else if (player->GetTeamId() == TEAM_HORDE) { - // Only count valid brackets. - if (g_AllianceLevelRanges[i].lower > g_AllianceLevelRanges[i].upper) - allianceWeights[i] = 0.0f; - else - allianceWeights[i] = baseline + g_RealPlayerWeight * + hordeRealCounts[rangeIndex]++; + totalHordeReal++; + } + } + // Use a baseline weight to ensure an equal share when no real players are present. + const float baseline = 1.0f; + float allianceTotalWeight = 0.0f; + float hordeTotalWeight = 0.0f; + float allianceWeights[NUM_RANGES] = {0}; + float hordeWeights[NUM_RANGES] = {0}; + for (int i = 0; i < NUM_RANGES; ++i) + { + // Only count valid brackets. + if (g_AllianceLevelRanges[i].lower > g_AllianceLevelRanges[i].upper) + allianceWeights[i] = 0.0f; + else + allianceWeights[i] = baseline + g_RealPlayerWeight * (totalAllianceReal > 0 ? (1.0f / totalAllianceReal) : 1.0f) * log(1 + allianceRealCounts[i]); - if (g_HordeLevelRanges[i].lower > g_HordeLevelRanges[i].upper) - hordeWeights[i] = 0.0f; - else - hordeWeights[i] = baseline + g_RealPlayerWeight * + if (g_HordeLevelRanges[i].lower > g_HordeLevelRanges[i].upper) + hordeWeights[i] = 0.0f; + else + hordeWeights[i] = baseline + g_RealPlayerWeight * (totalHordeReal > 0 ? (1.0f / totalHordeReal) : 1.0f) * log(1 + hordeRealCounts[i]); - allianceTotalWeight += allianceWeights[i]; - hordeTotalWeight += hordeWeights[i]; - } - // Recalculate desired percentages for each range. - for (int i = 0; i < NUM_RANGES; ++i) + allianceTotalWeight += allianceWeights[i]; + hordeTotalWeight += hordeWeights[i]; + } + // Recalculate desired percentages for each range. + for (int i = 0; i < NUM_RANGES; ++i) + { + g_AllianceLevelRanges[i].desiredPercent = static_cast(round((allianceWeights[i] / allianceTotalWeight) * 100)); + if (g_BotDistDebugMode) { - g_AllianceLevelRanges[i].desiredPercent = static_cast(round((allianceWeights[i] / allianceTotalWeight) * 100)); - if (g_BotDistDebugMode) - { - LOG_INFO("server.loading", "[BotLevelBrackets] Dynamic Distribution - Alliance Range {}: {}-{}, Real Players: {} (weight: {:.2f}), New Desired: {}%", - i + 1, g_AllianceLevelRanges[i].lower, g_AllianceLevelRanges[i].upper, allianceRealCounts[i], allianceWeights[i], g_AllianceLevelRanges[i].desiredPercent); - } + LOG_INFO("server.loading", "[BotLevelBrackets] Dynamic Distribution - Alliance Range {}: {}-{}, Real Players: {} (weight: {:.2f}), New Desired: {}%", + i + 1, g_AllianceLevelRanges[i].lower, g_AllianceLevelRanges[i].upper, allianceRealCounts[i], allianceWeights[i], g_AllianceLevelRanges[i].desiredPercent); } - - uint8 sumAlliance = 0; - for (int i = 0; i < NUM_RANGES; ++i) - sumAlliance += g_AllianceLevelRanges[i].desiredPercent; - if (sumAlliance < 100 && allianceTotalWeight > 0) - { - uint8 missing = 100 - sumAlliance; - if (g_BotDistDebugMode) - { - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance normalization: current sum = {}, missing = {}", sumAlliance, missing); - } - while (missing > 0) - { - for (int i = 0; i < NUM_RANGES && missing > 0; ++i) - { - if (g_AllianceLevelRanges[i].lower <= g_AllianceLevelRanges[i].upper && - allianceWeights[i] > 0) - { - g_AllianceLevelRanges[i].desiredPercent++; - missing--; - } - } - } - if (g_BotDistDebugMode) - { - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance normalized percentages:"); - for (int i = 0; i < NUM_RANGES; ++i) - { - LOG_INFO("server.loading", " Range {}: {}% ({}-{})", i + 1, - g_AllianceLevelRanges[i].desiredPercent, - g_AllianceLevelRanges[i].lower, - g_AllianceLevelRanges[i].upper); - } - } - } - - - for (int i = 0; i < NUM_RANGES; ++i) - { - g_HordeLevelRanges[i].desiredPercent = static_cast(round((hordeWeights[i] / hordeTotalWeight) * 100)); - if (g_BotDistDebugMode) - { - LOG_INFO("server.loading", "[BotLevelBrackets] Dynamic Distribution - Horde Range {}: {}-{}, Real Players: {} (weight: {:.2f}), New Desired: {}%", - i + 1, g_HordeLevelRanges[i].lower, g_HordeLevelRanges[i].upper, hordeRealCounts[i], hordeWeights[i], g_HordeLevelRanges[i].desiredPercent); - } - } - - uint8 sumHorde = 0; - for (int i = 0; i < NUM_RANGES; ++i) - sumHorde += g_HordeLevelRanges[i].desiredPercent; - if (sumHorde < 100 && hordeTotalWeight > 0) - { - uint8 missing = 100 - sumHorde; - if (g_BotDistDebugMode) - { - LOG_INFO("server.loading", "[BotLevelBrackets] Horde normalization: current sum = {}, missing = {}", sumHorde, missing); - } - while (missing > 0) - { - for (int i = 0; i < NUM_RANGES && missing > 0; ++i) - { - if (g_HordeLevelRanges[i].lower <= g_HordeLevelRanges[i].upper && - hordeWeights[i] > 0) - { - g_HordeLevelRanges[i].desiredPercent++; - missing--; - } - } - } - if (g_BotDistDebugMode) - { - LOG_INFO("server.loading", "[BotLevelBrackets] Horde normalized percentages:"); - for (int i = 0; i < NUM_RANGES; ++i) - { - LOG_INFO("server.loading", " Range {}: {}% ({}-{})", i + 1, - g_HordeLevelRanges[i].desiredPercent, - g_HordeLevelRanges[i].lower, - g_HordeLevelRanges[i].upper); - } - } - } - } - // Containers for Alliance bots. - uint32 totalAllianceBots = 0; - int allianceActualCounts[NUM_RANGES] = { 0 }; - std::vector allianceBotsByRange[NUM_RANGES]; - - // Containers for Horde bots. - uint32 totalHordeBots = 0; - int hordeActualCounts[NUM_RANGES] = { 0 }; - std::vector hordeBotsByRange[NUM_RANGES]; - - // Iterate only over player bots. - auto const& allPlayers = ObjectAccessor::GetPlayers(); - if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] Starting processing of {} players.", allPlayers.size()); - - for (auto const& itr : allPlayers) + uint8 sumAlliance = 0; + for (int i = 0; i < NUM_RANGES; ++i) + sumAlliance += g_AllianceLevelRanges[i].desiredPercent; + if (sumAlliance < 100 && allianceTotalWeight > 0) { - Player* player = itr.second; - if (!player) + uint8 missing = 100 - sumAlliance; + if (g_BotDistDebugMode) { - if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] Skipping null player."); - continue; + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance normalization: current sum = {}, missing = {}", sumAlliance, missing); } - if (!player->IsInWorld()) + while (missing > 0) { - if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] Skipping player '{}' as they are not in world.", player->GetName()); - continue; - } - if (!IsPlayerBot(player) || !IsPlayerRandomBot(player)) - { - if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] Skipping player '{}' as they are not a random bot.", player->GetName()); - continue; - } - - if (IsAlliancePlayerBot(player)) - { - totalAllianceBots++; - int rangeIndex = GetOrFlagPlayerBracket(player); - if (rangeIndex >= 0) + for (int i = 0; i < NUM_RANGES && missing > 0; ++i) { - allianceActualCounts[rangeIndex]++; - allianceBotsByRange[rangeIndex].push_back(player); + if (g_AllianceLevelRanges[i].lower <= g_AllianceLevelRanges[i].upper && + allianceWeights[i] > 0) + { + g_AllianceLevelRanges[i].desiredPercent++; + missing--; + } + } + } + if (g_BotDistDebugMode) + { + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance normalized percentages:"); + for (int i = 0; i < NUM_RANGES; ++i) + { + LOG_INFO("server.loading", " Range {}: {}% ({}-{})", i + 1, + g_AllianceLevelRanges[i].desiredPercent, + g_AllianceLevelRanges[i].lower, + g_AllianceLevelRanges[i].upper); + } + } + } + + + for (int i = 0; i < NUM_RANGES; ++i) + { + g_HordeLevelRanges[i].desiredPercent = static_cast(round((hordeWeights[i] / hordeTotalWeight) * 100)); + if (g_BotDistDebugMode) + { + LOG_INFO("server.loading", "[BotLevelBrackets] Dynamic Distribution - Horde Range {}: {}-{}, Real Players: {} (weight: {:.2f}), New Desired: {}%", + i + 1, g_HordeLevelRanges[i].lower, g_HordeLevelRanges[i].upper, hordeRealCounts[i], hordeWeights[i], g_HordeLevelRanges[i].desiredPercent); + } + } + + uint8 sumHorde = 0; + for (int i = 0; i < NUM_RANGES; ++i) + sumHorde += g_HordeLevelRanges[i].desiredPercent; + if (sumHorde < 100 && hordeTotalWeight > 0) + { + uint8 missing = 100 - sumHorde; + if (g_BotDistDebugMode) + { + LOG_INFO("server.loading", "[BotLevelBrackets] Horde normalization: current sum = {}, missing = {}", sumHorde, missing); + } + while (missing > 0) + { + for (int i = 0; i < NUM_RANGES && missing > 0; ++i) + { + if (g_HordeLevelRanges[i].lower <= g_HordeLevelRanges[i].upper && + hordeWeights[i] > 0) + { + g_HordeLevelRanges[i].desiredPercent++; + missing--; + } + } + } + if (g_BotDistDebugMode) + { + LOG_INFO("server.loading", "[BotLevelBrackets] Horde normalized percentages:"); + for (int i = 0; i < NUM_RANGES; ++i) + { + LOG_INFO("server.loading", " Range {}: {}% ({}-{})", i + 1, + g_HordeLevelRanges[i].desiredPercent, + g_HordeLevelRanges[i].lower, + g_HordeLevelRanges[i].upper); + } + } + } + + } + + // Containers for Alliance bots. + uint32 totalAllianceBots = 0; + int allianceActualCounts[NUM_RANGES] = {0}; + std::vector allianceBotsByRange[NUM_RANGES]; + + // Containers for Horde bots. + uint32 totalHordeBots = 0; + int hordeActualCounts[NUM_RANGES] = {0}; + std::vector hordeBotsByRange[NUM_RANGES]; + + // Iterate only over player bots. + auto const& allPlayers = ObjectAccessor::GetPlayers(); + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] Starting processing of {} players.", allPlayers.size()); + + for (auto const& itr : allPlayers) + { + Player* player = itr.second; + if (!player) + { + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] Skipping null player."); + continue; + } + if (!player->IsInWorld()) + { + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] Skipping player '{}' as they are not in world.", player->GetName()); + continue; + } + if (!IsPlayerBot(player) || !IsPlayerRandomBot(player)) + { + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] Skipping player '{}' as they are not a random bot.", player->GetName()); + continue; + } + + if (IsAlliancePlayerBot(player)) + { + totalAllianceBots++; + int rangeIndex = GetOrFlagPlayerBracket(player); + if (rangeIndex >= 0) + { + allianceActualCounts[rangeIndex]++; + allianceBotsByRange[rangeIndex].push_back(player); + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' with level {} added to range {}.", + player->GetName(), player->GetLevel(), rangeIndex + 1); + } + else if (g_BotDistDebugMode) + { + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' with level {} does not fall into any defined range.", + player->GetName(), player->GetLevel()); + } + } + else if (IsHordePlayerBot(player)) + { + totalHordeBots++; + int rangeIndex = GetOrFlagPlayerBracket(player); + if (rangeIndex >= 0) + { + hordeActualCounts[rangeIndex]++; + hordeBotsByRange[rangeIndex].push_back(player); + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' with level {} added to range {}.", + player->GetName(), player->GetLevel(), rangeIndex + 1); + } + else if (g_BotDistDebugMode) + { + LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' with level {} does not fall into any defined range.", + player->GetName(), player->GetLevel()); + } + } + } + + if (g_BotDistDebugMode) + { + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); + LOG_INFO("server.loading", "[BotLevelBrackets] Total Alliance Bots: {}.", totalAllianceBots); + LOG_INFO("server.loading", "[BotLevelBrackets] Total Horde Bots: {}.", totalHordeBots); + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); + } + + // Process Alliance bots. + if (totalAllianceBots > 0) + { + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); + int allianceDesiredCounts[NUM_RANGES] = {0}; + for (int i = 0; i < NUM_RANGES; ++i) + { + allianceDesiredCounts[i] = static_cast(round((g_AllianceLevelRanges[i].desiredPercent / 100.0) * totalAllianceBots)); + if (g_BotDistDebugMode) + { + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance Range {} ({}-{}): Desired = {}, Actual = {}.", + i + 1, g_AllianceLevelRanges[i].lower, g_AllianceLevelRanges[i].upper, + allianceDesiredCounts[i], allianceActualCounts[i]); + } + } + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); + // Adjust overpopulated ranges. + for (int i = 0; i < NUM_RANGES; ++i) + { + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] >>> Processing Alliance bots in range {}.", i + 1); + + std::vector safeBots; + std::vector flaggedBots; + for (Player* bot : allianceBotsByRange[i]) + { + if (IsBotSafeForLevelReset(bot)) + { + safeBots.push_back(bot); if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' with level {} added to range {}.", - player->GetName(), player->GetLevel(), rangeIndex + 1); + { + //LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' is safe for level reset in range {}.", bot->GetName(), i + 1); + } } - else if (g_BotDistDebugMode) + else { - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' with level {} does not fall into any defined range.", - player->GetName(), player->GetLevel()); - } - } - else if (IsHordePlayerBot(player)) - { - totalHordeBots++; - int rangeIndex = GetOrFlagPlayerBracket(player); - if (rangeIndex >= 0) - { - hordeActualCounts[rangeIndex]++; - hordeBotsByRange[rangeIndex].push_back(player); + flaggedBots.push_back(bot); if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' with level {} added to range {}.", - player->GetName(), player->GetLevel(), rangeIndex + 1); - } - else if (g_BotDistDebugMode) - { - LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' with level {} does not fall into any defined range.", - player->GetName(), player->GetLevel()); + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' is NOT safe for level reset in range {}.", + bot->GetName(), i + 1); } } - } - - if (g_BotDistDebugMode) - { - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - LOG_INFO("server.loading", "[BotLevelBrackets] Total Alliance Bots: {}.", totalAllianceBots); - LOG_INFO("server.loading", "[BotLevelBrackets] Total Horde Bots: {}.", totalHordeBots); - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - } - - // Process Alliance bots. - if (totalAllianceBots > 0) - { - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - int allianceDesiredCounts[NUM_RANGES] = { 0 }; - for (int i = 0; i < NUM_RANGES; ++i) + while (allianceActualCounts[i] > allianceDesiredCounts[i] && !safeBots.empty()) { - allianceDesiredCounts[i] = static_cast(round((g_AllianceLevelRanges[i].desiredPercent / 100.0) * totalAllianceBots)); - if (g_BotDistDebugMode) + Player* bot = safeBots.back(); + safeBots.pop_back(); + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance safe bot '{}' from range {} will be moved.", + bot->GetName(), i + 1); + int targetRange = -1; + if (bot->getClass() == CLASS_DEATH_KNIGHT) { - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance Range {} ({}-{}): Desired = {}, Actual = {}.", - i + 1, g_AllianceLevelRanges[i].lower, g_AllianceLevelRanges[i].upper, - allianceDesiredCounts[i], allianceActualCounts[i]); - } - } - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - // Adjust overpopulated ranges. - for (int i = 0; i < NUM_RANGES; ++i) - { - if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] >>> Processing Alliance bots in range {}.", i + 1); - - std::vector safeBots; - std::vector flaggedBots; - for (Player* bot : allianceBotsByRange[i]) - { - if (IsBotSafeForLevelReset(bot)) + for (int j = 0; j < NUM_RANGES; ++j) { - safeBots.push_back(bot); - if (g_BotDistDebugMode) + if (allianceActualCounts[j] < allianceDesiredCounts[j] && g_AllianceLevelRanges[j].upper >= 55) { - //LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' is safe for level reset in range {}.", bot->GetName(), i + 1); - } - } - else - { - flaggedBots.push_back(bot); - if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' is NOT safe for level reset in range {}.", - bot->GetName(), i + 1); - } - } - while (allianceActualCounts[i] > allianceDesiredCounts[i] && !safeBots.empty()) - { - Player* bot = safeBots.back(); - safeBots.pop_back(); - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance safe bot '{}' from range {} will be moved.", - bot->GetName(), i + 1); - int targetRange = -1; - if (bot->getClass() == CLASS_DEATH_KNIGHT) - { - for (int j = 0; j < NUM_RANGES; ++j) - { - if (allianceActualCounts[j] < allianceDesiredCounts[j] && g_AllianceLevelRanges[j].upper >= 55) - { - targetRange = j; - break; - } - } - } - else - { - for (int j = 0; j < NUM_RANGES; ++j) - { - if (allianceActualCounts[j] < allianceDesiredCounts[j]) - { - targetRange = j; - break; - } - } - } - if (targetRange == -1) - { - LOG_INFO("server.loading", "[BotLevelBrackets] No valid target range found for alliance safe bot '{}'.", bot->GetName()); - break; - } - LOG_INFO("server.loading", "[BotLevelBrackets] !!!! Adjusting alliance bot '{}' from range {} to range {} ({}-{}).", - bot->GetName(), i + 1, targetRange + 1, g_AllianceLevelRanges[targetRange].lower, g_AllianceLevelRanges[targetRange].upper); - AdjustBotToRange(bot, targetRange, g_AllianceLevelRanges); - allianceActualCounts[i]--; - allianceActualCounts[targetRange]++; - } - while (allianceActualCounts[i] > allianceDesiredCounts[i] && !flaggedBots.empty()) - { - Player* bot = flaggedBots.back(); - flaggedBots.pop_back(); - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance flagged bot '{}' from range {} will be processed for pending reset.", - bot->GetName(), i + 1); - int targetRange = -1; - if (bot->getClass() == CLASS_DEATH_KNIGHT) - { - for (int j = 0; j < NUM_RANGES; ++j) - { - if (allianceActualCounts[j] < allianceDesiredCounts[j] && g_AllianceLevelRanges[j].upper >= 55) - { - targetRange = j; - break; - } - } - } - else - { - for (int j = 0; j < NUM_RANGES; ++j) - { - if (allianceActualCounts[j] < allianceDesiredCounts[j]) - { - targetRange = j; - break; - } - } - } - if (targetRange == -1) - { - LOG_INFO("server.loading", "[BotLevelBrackets] No valid target range found for flagged alliance bot '{}' for pending reset.", bot->GetName()); - break; - } - bool alreadyFlagged = false; - for (auto& entry : g_PendingLevelResets) - { - if (entry.bot == bot) - { - alreadyFlagged = true; + targetRange = j; break; } } - if (!alreadyFlagged) - { - g_PendingLevelResets.push_back({ bot, targetRange, g_AllianceLevelRanges }); - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' flagged for pending level reset to range {}-{}.", - bot->GetName(), g_AllianceLevelRanges[targetRange].lower, g_AllianceLevelRanges[targetRange].upper); - } } - } - } - - // Process Horde bots. - if (totalHordeBots > 0) - { - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - int hordeDesiredCounts[NUM_RANGES] = { 0 }; - for (int i = 0; i < NUM_RANGES; ++i) - { - hordeDesiredCounts[i] = static_cast(round((g_HordeLevelRanges[i].desiredPercent / 100.0) * totalHordeBots)); - if (g_BotDistDebugMode) + else { - LOG_INFO("server.loading", "[BotLevelBrackets] Horde Range {} ({}-{}): Desired = {}, Actual = {}.", - i + 1, g_HordeLevelRanges[i].lower, g_HordeLevelRanges[i].upper, - hordeDesiredCounts[i], hordeActualCounts[i]); - } - } - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - for (int i = 0; i < NUM_RANGES; ++i) - { - if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] Processing Horde bots in range {}.", i + 1); - - std::vector safeBots; - std::vector flaggedBots; - for (Player* bot : hordeBotsByRange[i]) - { - if (IsBotSafeForLevelReset(bot)) + for (int j = 0; j < NUM_RANGES; ++j) { - safeBots.push_back(bot); - if (g_BotDistDebugMode) + if (allianceActualCounts[j] < allianceDesiredCounts[j]) { - //LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' is safe for level reset in range {}.", bot->GetName(), i + 1); - } - } - else - { - flaggedBots.push_back(bot); - if (g_BotDistDebugMode) - LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' is NOT safe for level reset in range {}.", - bot->GetName(), i + 1); - } - } - while (hordeActualCounts[i] > hordeDesiredCounts[i] && !safeBots.empty()) - { - Player* bot = safeBots.back(); - safeBots.pop_back(); - LOG_INFO("server.loading", "[BotLevelBrackets] Horde safe bot '{}' from range {} will be moved.", - bot->GetName(), i + 1); - int targetRange = -1; - if (bot->getClass() == CLASS_DEATH_KNIGHT) - { - for (int j = 0; j < NUM_RANGES; ++j) - { - if (hordeActualCounts[j] < hordeDesiredCounts[j] && g_HordeLevelRanges[j].upper >= 55) - { - targetRange = j; - break; - } - } - } - else - { - for (int j = 0; j < NUM_RANGES; ++j) - { - if (hordeActualCounts[j] < hordeDesiredCounts[j]) - { - targetRange = j; - break; - } - } - } - if (targetRange == -1) - { - LOG_INFO("server.loading", "[BotLevelBrackets] No valid target range found for safe horde bot '{}'.", bot->GetName()); - break; - } - LOG_INFO("server.loading", "[BotLevelBrackets] !!!! Adjusting horde bot '{}' from range {} to range {} ({}-{}).", - bot->GetName(), i + 1, targetRange + 1, g_HordeLevelRanges[targetRange].lower, g_HordeLevelRanges[targetRange].upper); - AdjustBotToRange(bot, targetRange, g_HordeLevelRanges); - hordeActualCounts[i]--; - hordeActualCounts[targetRange]++; - } - while (hordeActualCounts[i] > hordeDesiredCounts[i] && !flaggedBots.empty()) - { - Player* bot = flaggedBots.back(); - flaggedBots.pop_back(); - LOG_INFO("server.loading", "[BotLevelBrackets] Horde flagged bot '{}' from range {} will be processed for pending reset.", - bot->GetName(), i + 1); - int targetRange = -1; - if (bot->getClass() == CLASS_DEATH_KNIGHT) - { - for (int j = 0; j < NUM_RANGES; ++j) - { - if (hordeActualCounts[j] < hordeDesiredCounts[j] && g_HordeLevelRanges[j].upper >= 55) - { - targetRange = j; - break; - } - } - } - else - { - for (int j = 0; j < NUM_RANGES; ++j) - { - if (hordeActualCounts[j] < hordeDesiredCounts[j]) - { - targetRange = j; - break; - } - } - } - if (targetRange == -1) - { - LOG_INFO("server.loading", "[BotLevelBrackets] No valid target range found for flagged horde bot '{}' for pending reset.", bot->GetName()); - break; - } - bool alreadyFlagged = false; - for (auto& entry : g_PendingLevelResets) - { - if (entry.bot == bot) - { - alreadyFlagged = true; + targetRange = j; break; } } - if (!alreadyFlagged) + } + if (targetRange == -1) + { + LOG_INFO("server.loading", "[BotLevelBrackets] No valid target range found for alliance safe bot '{}'.", bot->GetName()); + break; + } + LOG_INFO("server.loading", "[BotLevelBrackets] !!!! Adjusting alliance bot '{}' from range {} to range {} ({}-{}).", + bot->GetName(), i + 1, targetRange + 1, g_AllianceLevelRanges[targetRange].lower, g_AllianceLevelRanges[targetRange].upper); + AdjustBotToRange(bot, targetRange, g_AllianceLevelRanges); + allianceActualCounts[i]--; + allianceActualCounts[targetRange]++; + } + while (allianceActualCounts[i] > allianceDesiredCounts[i] && !flaggedBots.empty()) + { + Player* bot = flaggedBots.back(); + flaggedBots.pop_back(); + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance flagged bot '{}' from range {} will be processed for pending reset.", + bot->GetName(), i + 1); + int targetRange = -1; + if (bot->getClass() == CLASS_DEATH_KNIGHT) + { + for (int j = 0; j < NUM_RANGES; ++j) { - g_PendingLevelResets.push_back({ bot, targetRange, g_HordeLevelRanges }); - LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' flagged for pending level reset to range {}-{}.", - bot->GetName(), g_HordeLevelRanges[targetRange].lower, g_HordeLevelRanges[targetRange].upper); + if (allianceActualCounts[j] < allianceDesiredCounts[j] && g_AllianceLevelRanges[j].upper >= 55) + { + targetRange = j; + break; + } } } + else + { + for (int j = 0; j < NUM_RANGES; ++j) + { + if (allianceActualCounts[j] < allianceDesiredCounts[j]) + { + targetRange = j; + break; + } + } + } + if (targetRange == -1) + { + LOG_INFO("server.loading", "[BotLevelBrackets] No valid target range found for flagged alliance bot '{}' for pending reset.", bot->GetName()); + break; + } + bool alreadyFlagged = false; + for (auto& entry : g_PendingLevelResets) + { + if (entry.bot == bot) + { + alreadyFlagged = true; + break; + } + } + if (!alreadyFlagged) + { + g_PendingLevelResets.push_back({bot, targetRange, g_AllianceLevelRanges}); + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance bot '{}' flagged for pending level reset to range {}-{}.", + bot->GetName(), g_AllianceLevelRanges[targetRange].lower, g_AllianceLevelRanges[targetRange].upper); + } } } + } - - if (g_BotDistDebugMode) + // Process Horde bots. + if (totalHordeBots > 0) + { + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); + int hordeDesiredCounts[NUM_RANGES] = {0}; + for (int i = 0; i < NUM_RANGES; ++i) { - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================= COMPLETE"); - LOG_INFO("server.loading", "[BotLevelBrackets] Distribution adjustment complete. Alliance bots: {}, Horde bots: {}.", - totalAllianceBots, totalHordeBots); - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - LogAllBotLevels(); - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - int allianceDesiredCounts[NUM_RANGES] = { 0 }; - for (int i = 0; i < NUM_RANGES; ++i) + hordeDesiredCounts[i] = static_cast(round((g_HordeLevelRanges[i].desiredPercent / 100.0) * totalHordeBots)); + if (g_BotDistDebugMode) { - allianceDesiredCounts[i] = static_cast(round((g_AllianceLevelRanges[i].desiredPercent / 100.0) * totalAllianceBots)); - LOG_INFO("server.loading", "[BotLevelBrackets] Alliance Range {} ({}-{}): Desired = {}, Actual = {}.", - i + 1, g_AllianceLevelRanges[i].lower, g_AllianceLevelRanges[i].upper, - allianceDesiredCounts[i], allianceActualCounts[i]); - } - LOG_INFO("server.loading", "[BotLevelBrackets] ----------------------------------------"); - int hordeDesiredCounts[NUM_RANGES] = { 0 }; - for (int i = 0; i < NUM_RANGES; ++i) - { - hordeDesiredCounts[i] = static_cast(round((g_HordeLevelRanges[i].desiredPercent / 100.0) * totalHordeBots)); LOG_INFO("server.loading", "[BotLevelBrackets] Horde Range {} ({}-{}): Desired = {}, Actual = {}.", - i + 1, g_HordeLevelRanges[i].lower, g_HordeLevelRanges[i].upper, - hordeDesiredCounts[i], hordeActualCounts[i]); + i + 1, g_HordeLevelRanges[i].lower, g_HordeLevelRanges[i].upper, + hordeDesiredCounts[i], hordeActualCounts[i]); } - LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); - } + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); + for (int i = 0; i < NUM_RANGES; ++i) + { + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] Processing Horde bots in range {}.", i + 1); + + std::vector safeBots; + std::vector flaggedBots; + for (Player* bot : hordeBotsByRange[i]) + { + if (IsBotSafeForLevelReset(bot)) + { + safeBots.push_back(bot); + if (g_BotDistDebugMode) + { + //LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' is safe for level reset in range {}.", bot->GetName(), i + 1); + } + } + else + { + flaggedBots.push_back(bot); + if (g_BotDistDebugMode) + LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' is NOT safe for level reset in range {}.", + bot->GetName(), i + 1); + } + } + while (hordeActualCounts[i] > hordeDesiredCounts[i] && !safeBots.empty()) + { + Player* bot = safeBots.back(); + safeBots.pop_back(); + LOG_INFO("server.loading", "[BotLevelBrackets] Horde safe bot '{}' from range {} will be moved.", + bot->GetName(), i + 1); + int targetRange = -1; + if (bot->getClass() == CLASS_DEATH_KNIGHT) + { + for (int j = 0; j < NUM_RANGES; ++j) + { + if (hordeActualCounts[j] < hordeDesiredCounts[j] && g_HordeLevelRanges[j].upper >= 55) + { + targetRange = j; + break; + } + } + } + else + { + for (int j = 0; j < NUM_RANGES; ++j) + { + if (hordeActualCounts[j] < hordeDesiredCounts[j]) + { + targetRange = j; + break; + } + } + } + if (targetRange == -1) + { + LOG_INFO("server.loading", "[BotLevelBrackets] No valid target range found for safe horde bot '{}'.", bot->GetName()); + break; + } + LOG_INFO("server.loading", "[BotLevelBrackets] !!!! Adjusting horde bot '{}' from range {} to range {} ({}-{}).", + bot->GetName(), i + 1, targetRange + 1, g_HordeLevelRanges[targetRange].lower, g_HordeLevelRanges[targetRange].upper); + AdjustBotToRange(bot, targetRange, g_HordeLevelRanges); + hordeActualCounts[i]--; + hordeActualCounts[targetRange]++; + } + while (hordeActualCounts[i] > hordeDesiredCounts[i] && !flaggedBots.empty()) + { + Player* bot = flaggedBots.back(); + flaggedBots.pop_back(); + LOG_INFO("server.loading", "[BotLevelBrackets] Horde flagged bot '{}' from range {} will be processed for pending reset.", + bot->GetName(), i + 1); + int targetRange = -1; + if (bot->getClass() == CLASS_DEATH_KNIGHT) + { + for (int j = 0; j < NUM_RANGES; ++j) + { + if (hordeActualCounts[j] < hordeDesiredCounts[j] && g_HordeLevelRanges[j].upper >= 55) + { + targetRange = j; + break; + } + } + } + else + { + for (int j = 0; j < NUM_RANGES; ++j) + { + if (hordeActualCounts[j] < hordeDesiredCounts[j]) + { + targetRange = j; + break; + } + } + } + if (targetRange == -1) + { + LOG_INFO("server.loading", "[BotLevelBrackets] No valid target range found for flagged horde bot '{}' for pending reset.", bot->GetName()); + break; + } + bool alreadyFlagged = false; + for (auto& entry : g_PendingLevelResets) + { + if (entry.bot == bot) + { + alreadyFlagged = true; + break; + } + } + if (!alreadyFlagged) + { + g_PendingLevelResets.push_back({bot, targetRange, g_HordeLevelRanges}); + LOG_INFO("server.loading", "[BotLevelBrackets] Horde bot '{}' flagged for pending level reset to range {}-{}.", + bot->GetName(), g_HordeLevelRanges[targetRange].lower, g_HordeLevelRanges[targetRange].upper); + } + } + } + } + + + if (g_BotDistDebugMode) + { + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================= COMPLETE"); + LOG_INFO("server.loading", "[BotLevelBrackets] Distribution adjustment complete. Alliance bots: {}, Horde bots: {}.", + totalAllianceBots, totalHordeBots); + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); + LogAllBotLevels(); + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); + int allianceDesiredCounts[NUM_RANGES] = {0}; + for (int i = 0; i < NUM_RANGES; ++i) + { + allianceDesiredCounts[i] = static_cast(round((g_AllianceLevelRanges[i].desiredPercent / 100.0) * totalAllianceBots)); + LOG_INFO("server.loading", "[BotLevelBrackets] Alliance Range {} ({}-{}): Desired = {}, Actual = {}.", + i + 1, g_AllianceLevelRanges[i].lower, g_AllianceLevelRanges[i].upper, + allianceDesiredCounts[i], allianceActualCounts[i]); + } + LOG_INFO("server.loading", "[BotLevelBrackets] ----------------------------------------"); + int hordeDesiredCounts[NUM_RANGES] = {0}; + for (int i = 0; i < NUM_RANGES; ++i) + { + hordeDesiredCounts[i] = static_cast(round((g_HordeLevelRanges[i].desiredPercent / 100.0) * totalHordeBots)); + LOG_INFO("server.loading", "[BotLevelBrackets] Horde Range {} ({}-{}): Desired = {}, Actual = {}.", + i + 1, g_HordeLevelRanges[i].lower, g_HordeLevelRanges[i].upper, + hordeDesiredCounts[i], hordeActualCounts[i]); + } + LOG_INFO("server.loading", "[BotLevelBrackets] ========================================="); + } }