diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 0c220c81..b644c6c9 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -1459,11 +1459,17 @@ AiPlayerbot.BotActiveAlone = 100 # Specify smart scaling is enabled or not. # The default is 1. When enabled (smart) scales the 'BotActiveAlone' value. -# Only when botLevel is between WhenMinLevel and WhenMaxLevel. AiPlayerbot.botActiveAloneSmartScale = 1 + +# Only when botLevel is between WhenMinLevel and WhenMaxLevel. AiPlayerbot.botActiveAloneSmartScaleWhenMinLevel = 1 AiPlayerbot.botActiveAloneSmartScaleWhenMaxLevel = 80 +# The server will tune bot activity to reach the desired server tick speed (in ms) +# bots will only join battleground when there is no lag based on latency diffs below +AiPlayerbot.botActiveAloneSmartScaleDiffWithPlayer = 100 +AiPlayerbot.botActiveAloneSmartScaleDiffEmpty = 200 + # Premade spell to avoid (undetected spells) # spellid-radius, ... AiPlayerbot.PremadeAvoidAoe = 62234-4 diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 4b037f7e..023ec7b6 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -4095,7 +4095,7 @@ ActivePiorityType PlayerbotAI::GetPriorityType(ActivityType activityType) for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next()) { Player* member = gref->GetSource(); - if (!member || (!member->IsInWorld() && member->GetMapId() != bot->GetMapId())) + if (!member || !member->IsInWorld() && member->GetMapId() != bot->GetMapId()) continue; if (member == bot) @@ -4181,18 +4181,12 @@ ActivePiorityType PlayerbotAI::GetPriorityType(ActivityType activityType) return ActivePiorityType::PLAYER_GUILD; //IN_INACTIVE_MAP - if (bot->IsBeingTeleported() || - !bot->IsInWorld() || - !HasRealPlayers(bot->GetMap()) || - !bot->GetMap()->IsGridLoaded(bot->GetPositionX(), bot->GetPositionY())) - return ActivePiorityType::IN_INACTIVE_MAP; + if (bot->IsBeingTeleported() || !bot->IsInWorld() || !HasRealPlayers(bot->GetMap())) + return ActivePiorityType::IN_INACTIVE_MAP; //IN_ACTIVE_MAP - if (!bot->IsBeingTeleported() && - bot->IsInWorld() && - HasRealPlayers(bot->GetMap()) && - bot->GetMap()->IsGridLoaded(bot->GetPositionX(), bot->GetPositionY())) - return ActivePiorityType::IN_ACTIVE_MAP; + if (!bot->IsBeingTeleported() && bot->IsInWorld() && HasRealPlayers(bot->GetMap())) + return ActivePiorityType::IN_ACTIVE_MAP; // IN_ACTIVE_AREA if (activityType == OUT_OF_PARTY_ACTIVITY || activityType == GRIND_ACTIVITY) @@ -4204,6 +4198,45 @@ ActivePiorityType PlayerbotAI::GetPriorityType(ActivityType activityType) return ActivePiorityType::IN_ACTIVE_AREA; } +// Returns the lower and upper bracket for bots to be active. +// Ie. { 10, 20 } means all bots in this bracket will be inactive below 10% activityMod, +// and will be active above 20% activityMod and scale between those values. +std::pair PlayerbotAI::GetPriorityBracket(ActivePiorityType type) +{ + switch (type) + { + case ActivePiorityType::HAS_REAL_PLAYER_MASTER: + case ActivePiorityType::IS_REAL_PLAYER: + case ActivePiorityType::IN_GROUP_WITH_REAL_PLAYER: + case ActivePiorityType::IN_INSTANCE: + case ActivePiorityType::VISIBLE_FOR_PLAYER: + return {0, 0}; + case ActivePiorityType::IS_ALWAYS_ACTIVE: + case ActivePiorityType::IN_COMBAT: + return {0, 10}; + case ActivePiorityType::IN_BG_QUEUE: + return {0, 20}; + case ActivePiorityType::IN_LFG: + return {0, 30}; + case ActivePiorityType::NEARBY_PLAYER: + return {0, 40}; + case ActivePiorityType::PLAYER_FRIEND: + case ActivePiorityType::PLAYER_GUILD: + return {0, 50}; + case ActivePiorityType::IN_ACTIVE_AREA: + case ActivePiorityType::IN_EMPTY_SERVER: + return {50, 100}; + case ActivePiorityType::IN_ACTIVE_MAP: + return {70, 100}; + case ActivePiorityType::IN_INACTIVE_MAP: + return {80, 100}; + default: + return {90, 100}; + } + + return {90, 100}; +} + bool PlayerbotAI::AllowActive(ActivityType activityType) { // General exceptions @@ -4265,25 +4298,27 @@ bool PlayerbotAI::AllowActive(ActivityType activityType) } } - uint32 botActiveAlonePerc = sPlayerbotAIConfig->botActiveAlone > 100 ? 100 : sPlayerbotAIConfig->botActiveAlone; - uint32 mod = botActiveAlonePerc; - if (botActiveAlonePerc <= 0) return false; - if (botActiveAlonePerc >= 100) return true; - + // GetPriorityBracket acitivity + float normalizedBotActiveAlone = sPlayerbotAIConfig->botActiveAlone > 100 ? 100 : sPlayerbotAIConfig->botActiveAlone; + float activePerc = normalizedBotActiveAlone; if (sPlayerbotAIConfig->botActiveAloneSmartScale && bot->GetLevel() >= sPlayerbotAIConfig->botActiveAloneSmartScaleWhenMinLevel && bot->GetLevel() <= sPlayerbotAIConfig->botActiveAloneSmartScaleWhenMaxLevel) { - // float activityPercentage = sRandomPlayerbotMgr->getActivityPercentage(); - mod = SmartScaleActivity(type, botActiveAlonePerc); + std::pair priorityBracket = GetPriorityBracket(type); + if (!priorityBracket.second) return true; + float activityPercentage = sRandomPlayerbotMgr->getActivityPercentage(); + if (priorityBracket.first >= activityPercentage) return false; + if (priorityBracket.second <= activityPercentage && priorityBracket.second < 100) return true; + activePerc = (activityPercentage - priorityBracket.first) / (priorityBracket.second - priorityBracket.first); + activePerc *= (priorityBracket.second == 100) ? normalizedBotActiveAlone : 100; } - //The last number if the amount it cycles per min. Currently set to 1% of the active bots. - uint32 ActivityNumber = GetFixedBotNumer(BotTypeNumber::ACTIVITY_TYPE_NUMBER, 100, - botActiveAlonePerc * static_cast(mod) / 100 * 0.01f); + // The last number if the amount it cycles per min. Currently set to 1% of the active bots. + uint32 ActivityNumber = GetFixedBotNumer(BotTypeNumber::ACTIVITY_TYPE_NUMBER, 100, activePerc * 0.01f); - //The given percentage of bots should be active and rotate 1% of those active bots each minute. - return ActivityNumber <= (botActiveAlonePerc * mod) / 100; + // The given percentage of bots should be active and rotate 1% of those active bots each minute. + return ActivityNumber <= (activePerc); } bool PlayerbotAI::AllowActivity(ActivityType activityType, bool checkNow) @@ -4300,70 +4335,6 @@ bool PlayerbotAI::AllowActivity(ActivityType activityType, bool checkNow) return allowed; } -uint32 PlayerbotAI::SmartScaleActivity(ActivePiorityType type, uint32 botActiveAlonePerc) -{ - uint32 maxDiff = sWorldUpdateTime.GetPercentile(90); - //uint32 maxDiff = sWorldUpdateTime.GetMaxUpdateTimeOfCurrentTable(); - //uint32 maxDiff = sWorldUpdateTime.GetMaxUpdateTime(); - if (maxDiff > 500) - return 0; - - float ActivePiorityTypeMod = 1; - switch (type) - { - case ActivePiorityType::HAS_REAL_PLAYER_MASTER: - case ActivePiorityType::IS_REAL_PLAYER: - case ActivePiorityType::IN_GROUP_WITH_REAL_PLAYER: - case ActivePiorityType::IN_INSTANCE: - case ActivePiorityType::VISIBLE_FOR_PLAYER: - // we always enforce 100% with the above acitivities - // otherwise it will effect the pve gameplay. - return 100; - case ActivePiorityType::IS_ALWAYS_ACTIVE: - case ActivePiorityType::IN_COMBAT: - ActivePiorityTypeMod = 0.9; - break; - case ActivePiorityType::IN_BG_QUEUE: - case ActivePiorityType::IN_LFG: - ActivePiorityTypeMod = 0.7; - break; - case ActivePiorityType::NEARBY_PLAYER: - case ActivePiorityType::PLAYER_FRIEND: - case ActivePiorityType::PLAYER_GUILD: - case ActivePiorityType::IN_ACTIVE_AREA: - ActivePiorityTypeMod = 0.6; - break; - case ActivePiorityType::IN_ACTIVE_MAP: - case ActivePiorityType::IN_INACTIVE_MAP: - ActivePiorityTypeMod = 0.5; - break; - case ActivePiorityType::IN_EMPTY_SERVER: - ActivePiorityTypeMod = 0.4; - break; - default: - ActivePiorityTypeMod = 0.5; - break; - } - - if (maxDiff > 250) - return ActivePiorityTypeMod * (botActiveAlonePerc * 2) / 10; - if (maxDiff > 220) - return ActivePiorityTypeMod * (botActiveAlonePerc * 3) / 10; - if (maxDiff > 190) - return ActivePiorityTypeMod * (botActiveAlonePerc * 4) / 10; - if (maxDiff > 160) - return ActivePiorityTypeMod * (botActiveAlonePerc * 5) / 10; - if (maxDiff > 130) - return ActivePiorityTypeMod * (botActiveAlonePerc * 6) / 10; - if (maxDiff > 100) - return ActivePiorityTypeMod * (botActiveAlonePerc * 8) / 10; - if (maxDiff > 80) - return ActivePiorityTypeMod * (botActiveAlonePerc * 9) / 10; - - - return botActiveAlonePerc; -} - bool PlayerbotAI::IsOpposing(Player* player) { return IsOpposing(player->getRace(), bot->getRace()); } bool PlayerbotAI::IsOpposing(uint8 race1, uint8 race2) diff --git a/src/PlayerbotAI.h b/src/PlayerbotAI.h index 90024f2b..d1a2f292 100644 --- a/src/PlayerbotAI.h +++ b/src/PlayerbotAI.h @@ -547,9 +547,9 @@ public: bool HasPlayerNearby(float range = sPlayerbotAIConfig->reactDistance); bool HasManyPlayersNearby(uint32 trigerrValue = 20, float range = sPlayerbotAIConfig->sightDistance); ActivePiorityType GetPriorityType(ActivityType activityType); + std::pair GetPriorityBracket(ActivePiorityType type); bool AllowActive(ActivityType activityType); bool AllowActivity(ActivityType activityType = ALL_ACTIVITY, bool checkNow = false); - uint32 SmartScaleActivity(ActivePiorityType type, uint32 botActiveAlonePerc); // Check if player is safe to use. bool IsSafe(Player* player); diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 53a7b720..816a345f 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -470,6 +470,10 @@ bool PlayerbotAIConfig::Initialize() sConfigMgr->GetOption("AiPlayerbot.botActiveAloneSmartScaleWhenMinLevel", 1); botActiveAloneSmartScaleWhenMaxLevel = sConfigMgr->GetOption("AiPlayerbot.botActiveAloneSmartScaleWhenMaxLevel", 80); + botActiveAloneSmartScaleDiffWithPlayer = + sConfigMgr->GetOption("AiPlayerbot.botActiveAloneSmartScaleDiffWithPlayer", 100); + botActiveAloneSmartScaleDiffEmpty = + sConfigMgr->GetOption("AiPlayerbot.botActiveAloneSmartScaleDiffEmpty", 200); randombotsWalkingRPG = sConfigMgr->GetOption("AiPlayerbot.RandombotsWalkingRPG", false); randombotsWalkingRPGInDoors = sConfigMgr->GetOption("AiPlayerbot.RandombotsWalkingRPG.InDoors", false); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index 0f34b41e..5ac3fa4a 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -266,6 +266,8 @@ public: bool botActiveAloneSmartScale; uint32 botActiveAloneSmartScaleWhenMinLevel; uint32 botActiveAloneSmartScaleWhenMaxLevel; + uint32 botActiveAloneSmartScaleDiffWithPlayer; + uint32 botActiveAloneSmartScaleDiffEmpty; bool freeMethodLoot; int32 lootRollLevel; diff --git a/src/RandomPlayerbotMgr.cpp b/src/RandomPlayerbotMgr.cpp index c48b5b25..37acca8d 100644 --- a/src/RandomPlayerbotMgr.cpp +++ b/src/RandomPlayerbotMgr.cpp @@ -292,6 +292,11 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/) if (!sPlayerbotAIConfig->randomBotAutologin || !sPlayerbotAIConfig->enabled) return; + if (sPlayerbotAIConfig->botActiveAloneSmartScale) + { + ScaleBotActivity(); + } + uint32 maxAllowedBotCount = GetEventValue(0, "bot_count"); if (!maxAllowedBotCount || (maxAllowedBotCount < sPlayerbotAIConfig->minRandomBots || maxAllowedBotCount > sPlayerbotAIConfig->maxRandomBots)) @@ -397,6 +402,27 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/) } } +void RandomPlayerbotMgr::ScaleBotActivity() +{ + float activityPercentage = getActivityPercentage(); + + // if (activityPercentage >= 100.0f || activityPercentage <= 0.0f) pid.reset(); //Stop integer buildup during + // max/min activity + + // % increase/decrease wanted diff , avg diff + float activityPercentageMod = pid.calculate(sRandomPlayerbotMgr->GetPlayers().empty() ? + sPlayerbotAIConfig->botActiveAloneSmartScaleDiffEmpty : + sPlayerbotAIConfig->botActiveAloneSmartScaleDiffWithPlayer, + sWorldUpdateTime.GetAverageUpdateTime()); + + activityPercentage = activityPercentageMod + 50; + + // Cap the percentage between 0 and 100. + activityPercentage = std::max(0.0f, std::min(100.0f, activityPercentage)); + + setActivityPercentage(activityPercentage); +} + uint32 RandomPlayerbotMgr::AddRandomBots() { uint32 maxAllowedBotCount = GetEventValue(0, "bot_count"); diff --git a/src/RandomPlayerbotMgr.h b/src/RandomPlayerbotMgr.h index 7d0670e2..5c35aefa 100644 --- a/src/RandomPlayerbotMgr.h +++ b/src/RandomPlayerbotMgr.h @@ -103,7 +103,8 @@ public: void LogPlayerLocation(); void UpdateAIInternal(uint32 elapsed, bool minimal = false) override; -//private: +private: + void ScaleBotActivity(); public: uint32 activeBots = 0; diff --git a/src/strategy/actions/BattleGroundJoinAction.cpp b/src/strategy/actions/BattleGroundJoinAction.cpp index 541ce2a4..349ae410 100644 --- a/src/strategy/actions/BattleGroundJoinAction.cpp +++ b/src/strategy/actions/BattleGroundJoinAction.cpp @@ -234,9 +234,17 @@ bool BGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battlegroun return false; TeamId teamId = bot->GetTeamId(); + bool noLag = sWorldUpdateTime.GetAverageUpdateTime() < (sRandomPlayerbotMgr->GetPlayers().empty() ? + sPlayerbotAIConfig->botActiveAloneSmartScaleDiffEmpty : + sPlayerbotAIConfig->botActiveAloneSmartScaleDiffWithPlayer) * 1.1; + uint32 BracketSize = bg->GetMaxPlayersPerTeam() * 2; uint32 TeamSize = bg->GetMaxPlayersPerTeam(); + // If performance diff is enabled, only queue if there is no lag + if (sPlayerbotAIConfig->botActiveAloneSmartScale && !noLag) + return false; + // If the bot is in a group, only the leader can queue if (bot->GetGroup() && !bot->GetGroup()->IsLeader(bot->GetGUID())) return false; @@ -569,10 +577,17 @@ bool FreeBGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battleg return false; TeamId teamId = bot->GetTeamId(); + bool noLag = sWorldUpdateTime.GetAverageUpdateTime() < (sRandomPlayerbotMgr->GetPlayers().empty() ? + sPlayerbotAIConfig->botActiveAloneSmartScaleDiffEmpty : + sPlayerbotAIConfig->botActiveAloneSmartScaleDiffWithPlayer) * 1.1; uint32 BracketSize = bg->GetMaxPlayersPerTeam() * 2; uint32 TeamSize = bg->GetMaxPlayersPerTeam(); + // If performance diff is enabled, only queue if there is no lag + if (sPlayerbotAIConfig->botActiveAloneSmartScale && !noLag) + return false; + // If the bot is in a group, only the leader can queue if (bot->GetGroup() && !bot->GetGroup()->IsLeader(bot->GetGUID())) return false;