From e8c8401b4ab75c6980df8c989b6ad85391d22b42 Mon Sep 17 00:00:00 2001 From: bash Date: Mon, 7 Oct 2024 20:57:19 +0000 Subject: [PATCH 01/22] Ported cmangos of allowAcitity and prority, removed autoscaled based on latency --- conf/playerbots.conf.dist | 4 - src/PlayerbotAI.cpp | 263 +++++++++++++++++++++++++------------ src/PlayerbotAI.h | 28 +++- src/PlayerbotAIConfig.cpp | 1 - src/PlayerbotAIConfig.h | 1 - src/RandomPlayerbotMgr.cpp | 3 + 6 files changed, 209 insertions(+), 91 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 6da1c7a3..a977beb9 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -1462,10 +1462,6 @@ AiPlayerbot.RandombotsWalkingRPG.InDoors = 0 # The default is 10. With 10% of all bots going active or inactive each minute. AiPlayerbot.BotActiveAlone = 100 -# Specify 1 for enabled, 0 for disabled. -# The default is 1. Automatically adjusts 'BotActiveAlone' percentage based on server latency. -AiPlayerbot.botActiveAloneAutoScale = 1 - # Premade spell to avoid (undetected spells) # spellid-radius, ... AiPlayerbot.PremadeAvoidAoe = 62234-4 diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 68512241..b597f646 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -3926,7 +3926,10 @@ Player* PlayerbotAI::GetGroupMaster() uint32 PlayerbotAI::GetFixedBotNumer(BotTypeNumber typeNumber, uint32 maxNum, float cyclePerMin) { - uint32 randseed = rand32(); // Seed random number + //deterministic seed + uint8 seedNumber = uint8(typeNumber); + std::mt19937 rng(seedNumber); + uint32 randseed = rng(); // Seed random number uint32 randnum = bot->GetGUID().GetCounter() + randseed; // Semi-random but fixed number for each bot. if (cyclePerMin > 0) @@ -3936,8 +3939,7 @@ uint32 PlayerbotAI::GetFixedBotNumer(BotTypeNumber typeNumber, uint32 maxNum, fl randnum += cycle; // Make the random number cylce. } - randnum = - (randnum % (maxNum + 1)); // Loops the randomnumber at maxNum. Bassically removes all the numbers above 99. + randnum = (randnum % (maxNum + 1)); // Loops the randomnumber at maxNum. Bassically removes all the numbers above 99. return randnum; // Now we have a number unique for each bot between 0 and maxNum that increases by cyclePerMin. } @@ -4075,18 +4077,15 @@ inline bool HasRealPlayers(Map* map) return false; } -bool PlayerbotAI::AllowActive(ActivityType activityType) +ActivePiorityType PlayerbotAI::GetPriorityType(ActivityType activityType) { - // General exceptions - if (activityType == PACKET_ACTIVITY) - return true; + // First priority - priorities disabled or has player master. Always active. + if (HasRealPlayerMaster()) + return ActivePiorityType::HAS_REAL_PLAYER_MASTER; - if (GetMaster()) // Has player master. Always active. - { - PlayerbotAI* masterBotAI = GET_PLAYERBOT_AI(GetMaster()); - if (!masterBotAI || masterBotAI->IsRealPlayer()) - return true; - } + // Self bot in a group with a bot master. + if (IsRealPlayer()) + return ActivePiorityType::IS_REAL_PLAYER; Group* group = bot->GetGroup(); if (group) @@ -4102,19 +4101,40 @@ bool PlayerbotAI::AllowActive(ActivityType activityType) PlayerbotAI* memberBotAI = GET_PLAYERBOT_AI(member); if (!memberBotAI || memberBotAI->HasRealPlayerMaster()) - return true; + return ActivePiorityType::IN_GROUP_WITH_REAL_PLAYER; if (group->IsLeader(member->GetGUID())) + { if (!memberBotAI->AllowActivity(PARTY_ACTIVITY)) - return false; + return ActivePiorityType::IN_GROUP_WITH_REAL_PLAYER; + } } } - if (!WorldPosition(bot).isOverworld()) // bg, raid, dungeon - return true; + if (bot->IsBeingTeleported()) // Allow activity while teleportation. + return ActivePiorityType::IN_INSTANCE; - if (bot->InBattlegroundQueue()) // In bg queue. Speed up bg queue/join. - return true; + if (!WorldPosition(bot).isOverworld()) + return ActivePiorityType::IN_INSTANCE; + + if (HasPlayerNearby()) + return ActivePiorityType::VISIBLE_FOR_PLAYER; + + if (activityType != OUT_OF_PARTY_ACTIVITY && activityType != PACKET_ACTIVITY) + { + // Is in combat.Defend yourself. + if (bot->IsInCombat()) + return ActivePiorityType::IN_COMBAT; + } + + if (HasPlayerNearby(300.f)) + return ActivePiorityType::NEARBY_PLAYER; + + //if (sPlayerbotAIConfig->IsFreeAltBot(bot) || HasStrategy("travel once", BotState::BOT_STATE_NON_COMBAT)) + // return ActivePiorityType::IS_ALWAYS_ACTIVE; + + if (bot->InBattlegroundQueue()) + return ActivePiorityType::IN_BG_QUEUE; bool isLFG = false; if (group) @@ -4124,62 +4144,166 @@ bool PlayerbotAI::AllowActive(ActivityType activityType) isLFG = true; } } - if (sLFGMgr->GetState(bot->GetGUID()) != lfg::LFG_STATE_NONE) { isLFG = true; } - if (isLFG) - return true; + return ActivePiorityType::IN_LFG; - if (activityType != OUT_OF_PARTY_ACTIVITY && activityType != PACKET_ACTIVITY) // Is in combat. Defend yourself. - if (bot->IsInCombat()) - return true; - - if (HasPlayerNearby(300.f)) // Player is near. Always active. - return true; + // If has real players - slow down continents without player + // This means we first disable bots in a different continent/area. + if (sRandomPlayerbotMgr->GetPlayers().empty()) + return ActivePiorityType::IN_EMPTY_SERVER; // friends always active - - // HasFriend sometimes cause crash, disable - // for (auto& player : sRandomPlayerbotMgr->GetPlayers()) - // { - // if (!player || !player->IsInWorld()) - // continue; + // for (auto& player : sRandomPlayerbotMgr->GetPlayers()) + // { + // if (!player || !player->IsInWorld()) + // continue; // if (player->GetSocial()->HasFriend(bot->GetGUID())) - // return true; + // return ActivePiorityType::PLAYER_FRIEND; // } - if (activityType == OUT_OF_PARTY_ACTIVITY || - activityType == GRIND_ACTIVITY) // Many bots nearby. Do not do heavy area checks. - if (HasManyPlayersNearby()) - return false; + // real guild always active if member+ + if (IsInRealGuild()) + return ActivePiorityType::PLAYER_GUILD; - // Bots don't need to move using PathGenerator. - if (activityType == DETAILED_MOVE_ACTIVITY) - return false; + if (bot->IsBeingTeleported() || !bot->IsInWorld() || !HasRealPlayers(bot->GetMap())) + return ActivePiorityType::IN_INACTIVE_MAP; - // All exceptions are now done. - // Below is code to have a specified % of bots active at all times. - // The default is 10%. With 0.1% of all bots going active or inactive each minute. - if (sPlayerbotAIConfig->botActiveAlone <= 0) - return false; - - uint32 mod = sPlayerbotAIConfig->botActiveAlone > 100 ? 100 : sPlayerbotAIConfig->botActiveAlone; - if (sPlayerbotAIConfig->botActiveAloneAutoScale) + // IN_ACTIVE_AREA + if (activityType == OUT_OF_PARTY_ACTIVITY || activityType == GRIND_ACTIVITY) { - mod = AutoScaleActivity(mod); + // Many bots nearby. Do not do heavy area checks. + if (HasManyPlayersNearby()) + return ActivePiorityType::IN_ACTIVE_AREA; } - uint32 ActivityNumber = - GetFixedBotNumer(BotTypeNumber::ACTIVITY_TYPE_NUMBER, 100, - sPlayerbotAIConfig->botActiveAlone * static_cast(mod) / 100 * 0.01f); + return ActivePiorityType::IN_ACTIVE_AREA; +} - return ActivityNumber <= - (sPlayerbotAIConfig->botActiveAlone * mod) / - 100; // The given percentage of bots should be active and rotate 1% of those active bots each minute. +// 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, all bots in this bracket 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 + if (activityType == PACKET_ACTIVITY) + return true; + + ActivePiorityType type = GetPriorityType(activityType); + if (activityType == DETAILED_MOVE_ACTIVITY) + { + 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: + case ActivePiorityType::IN_COMBAT: + case ActivePiorityType::NEARBY_PLAYER: + return true; + break; + case ActivePiorityType::IS_ALWAYS_ACTIVE: + case ActivePiorityType::IN_BG_QUEUE: + case ActivePiorityType::IN_LFG: + case ActivePiorityType::PLAYER_FRIEND: + case ActivePiorityType::PLAYER_GUILD: + case ActivePiorityType::IN_ACTIVE_AREA: + case ActivePiorityType::IN_EMPTY_SERVER: + case ActivePiorityType::IN_ACTIVE_MAP: + case ActivePiorityType::IN_INACTIVE_MAP: + default: + break; + } + } + else if (activityType == REACT_ACTIVITY) + { + 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: + case ActivePiorityType::IS_ALWAYS_ACTIVE: + case ActivePiorityType::IN_COMBAT: + return true; + break; + case ActivePiorityType::NEARBY_PLAYER: + case ActivePiorityType::IN_BG_QUEUE: + case ActivePiorityType::IN_LFG: + case ActivePiorityType::PLAYER_FRIEND: + case ActivePiorityType::PLAYER_GUILD: + case ActivePiorityType::IN_ACTIVE_AREA: + case ActivePiorityType::IN_EMPTY_SERVER: + case ActivePiorityType::IN_ACTIVE_MAP: + case ActivePiorityType::IN_INACTIVE_MAP: + default: + return false; + break; + } + } + + // GetPriorityBracket acitivity + std::pair priorityBracket = GetPriorityBracket(type); + if (!priorityBracket.second) + return true; // No scaling + + // Activity between 0 and 100. + float activityPercentage = sRandomPlayerbotMgr->getActivityPercentage(); + if (priorityBracket.first >= activityPercentage) + return false; + if (priorityBracket.second <= activityPercentage && priorityBracket.second < 100) + return true; + + float activePerc = (activityPercentage - priorityBracket.first) / (priorityBracket.second - priorityBracket.first); + activePerc *= (priorityBracket.second == 100) ? sPlayerbotAIConfig->botActiveAlone : 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, activePerc * 0.01f); + + // 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) @@ -4196,31 +4320,6 @@ bool PlayerbotAI::AllowActivity(ActivityType activityType, bool checkNow) return allowed; } -uint32 PlayerbotAI::AutoScaleActivity(uint32 mod) -{ - uint32 maxDiff = sWorldUpdateTime.GetAverageUpdateTime(); - - if (maxDiff > 500) return 0; - if (maxDiff > 250) - { - if (Map* map = bot->GetMap()) - { - if (map->GetEntry()->IsWorldMap() && - (!HasRealPlayers(map) || - !map->IsGridLoaded(bot->GetPositionX(), bot->GetPositionY()))) - return 0; - } - - return (mod * 1) / 10; - } - if (maxDiff > 200) return (mod * 3) / 10; - if (maxDiff > 150) return (mod * 5) / 10; - if (maxDiff > 100) return (mod * 6) / 10; - if (maxDiff > 80) return (mod * 9) / 10; - - return mod; -} - 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 6e82338b..3b83a5eb 100644 --- a/src/PlayerbotAI.h +++ b/src/PlayerbotAI.h @@ -241,6 +241,27 @@ enum class GuilderType : uint8 VERY_LARGE = 250 }; +enum class ActivePiorityType : uint8 +{ + IS_REAL_PLAYER = 0, + HAS_REAL_PLAYER_MASTER = 1, + IN_GROUP_WITH_REAL_PLAYER = 2, + IN_INSTANCE = 3, + VISIBLE_FOR_PLAYER = 4, + IS_ALWAYS_ACTIVE = 5, + IN_COMBAT = 6, + IN_BG_QUEUE = 7, + IN_LFG = 8, + NEARBY_PLAYER = 9, + PLAYER_FRIEND = 10, + PLAYER_GUILD = 11, + IN_ACTIVE_AREA = 12, + IN_ACTIVE_MAP = 13, + IN_INACTIVE_MAP = 14, + IN_EMPTY_SERVER = 15, + MAX_TYPE +}; + enum ActivityType { GRIND_ACTIVITY = 1, @@ -250,8 +271,8 @@ enum ActivityType PACKET_ACTIVITY = 5, DETAILED_MOVE_ACTIVITY = 6, PARTY_ACTIVITY = 7, - ALL_ACTIVITY = 8, - + REACT_ACTIVITY = 8, + ALL_ACTIVITY = 9, MAX_ACTIVITY_TYPE }; @@ -525,9 +546,10 @@ public: bool HasPlayerNearby(WorldPosition* pos, float range = sPlayerbotAIConfig->reactDistance); 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 AutoScaleActivity(uint32 mod); // Check if player is safe to use. bool IsSafe(Player* player); diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 10c680ae..1d60091b 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -465,7 +465,6 @@ bool PlayerbotAIConfig::Initialize() playerbotsXPrate = sConfigMgr->GetOption("AiPlayerbot.KillXPRate", 1); disableDeathKnightLogin = sConfigMgr->GetOption("AiPlayerbot.DisableDeathKnightLogin", 0); botActiveAlone = sConfigMgr->GetOption("AiPlayerbot.BotActiveAlone", 100); - botActiveAloneAutoScale = sConfigMgr->GetOption("AiPlayerbot.botActiveAloneAutoScale", true); enablePrototypePerformanceDiff = sConfigMgr->GetOption("AiPlayerbot.EnablePrototypePerformanceDiff", false); diffWithPlayer = sConfigMgr->GetOption("AiPlayerbot.DiffWithPlayer", 100); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index f8e3fd82..6caf1179 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -263,7 +263,6 @@ public: uint32 playerbotsXPrate; bool disableDeathKnightLogin; uint32 botActiveAlone; - bool botActiveAloneAutoScale; uint32 enablePrototypePerformanceDiff; uint32 diffWithPlayer; diff --git a/src/RandomPlayerbotMgr.cpp b/src/RandomPlayerbotMgr.cpp index 7d26a096..5d3b5edf 100644 --- a/src/RandomPlayerbotMgr.cpp +++ b/src/RandomPlayerbotMgr.cpp @@ -1108,6 +1108,9 @@ bool RandomPlayerbotMgr::ProcessBot(uint32 bot) bool RandomPlayerbotMgr::ProcessBot(Player* player) { + if (!player || !player->IsInWorld() || player->IsBeingTeleported() || player->GetSession()->isLogingOut()) + return false; + uint32 bot = player->GetGUID().GetCounter(); if (player->InBattleground()) From c7197f0911551d5c097c070bea3ecd2c05a47ed7 Mon Sep 17 00:00:00 2001 From: bash Date: Wed, 9 Oct 2024 22:34:37 +0000 Subject: [PATCH 02/22] [performance] BotActiveAlone SmartScale toggle --- conf/playerbots.conf.dist | 4 +++ src/PlayerbotAI.cpp | 54 ++++++++++++++++++++++++--------------- src/PlayerbotAI.h | 1 + src/PlayerbotAIConfig.cpp | 1 + src/PlayerbotAIConfig.h | 1 + 5 files changed, 41 insertions(+), 20 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index a977beb9..e0356cb7 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -1462,6 +1462,10 @@ AiPlayerbot.RandombotsWalkingRPG.InDoors = 0 # The default is 10. With 10% of all bots going active or inactive each minute. AiPlayerbot.BotActiveAlone = 100 +# Specify smart scaling is enabled or not. +# The default is 1. When enabled (smart) scales the 'BotActiveAlone' value. +AiPlayerbot.botActiveAloneSmartScale = 1 + # Premade spell to avoid (undetected spells) # spellid-radius, ... AiPlayerbot.PremadeAvoidAoe = 62234-4 diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index b597f646..0df602d8 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -239,6 +239,7 @@ void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal) { return; } + // if (!GetMaster() || !GetMaster()->IsInWorld() || !GetMaster()->GetSession() || // GetMaster()->GetSession()->isLogingOut()) { // return; @@ -301,6 +302,7 @@ void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal) // bot->GetMotionMaster()->Clear(); // bot->GetMotionMaster()->MoveIdle(); // } + // cheat options if (bot->IsAlive() && ((uint32)GetCheat() > 0 || (uint32)sPlayerbotAIConfig->botCheatMask > 0)) { @@ -4188,7 +4190,7 @@ ActivePiorityType PlayerbotAI::GetPriorityType(ActivityType activityType) // Ie. 10,20 means all bots in this bracket will be inactive below 10% activityMod, all bots in this bracket 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: @@ -4219,13 +4221,13 @@ std::pair PlayerbotAI::GetPriorityBracket(ActivePiorityType type default: return {90, 100}; } - + return {90, 100}; } bool PlayerbotAI::AllowActive(ActivityType activityType) { - //General exceptions + // General exceptions if (activityType == PACKET_ACTIVITY) return true; @@ -4285,19 +4287,17 @@ bool PlayerbotAI::AllowActive(ActivityType activityType) } // GetPriorityBracket acitivity - std::pair priorityBracket = GetPriorityBracket(type); - if (!priorityBracket.second) - return true; // No scaling - - // Activity between 0 and 100. - float activityPercentage = sRandomPlayerbotMgr->getActivityPercentage(); - if (priorityBracket.first >= activityPercentage) - return false; - if (priorityBracket.second <= activityPercentage && priorityBracket.second < 100) - return true; - - float activePerc = (activityPercentage - priorityBracket.first) / (priorityBracket.second - priorityBracket.first); - activePerc *= (priorityBracket.second == 100) ? sPlayerbotAIConfig->botActiveAlone : 100; + float activePerc = 100; + if (sPlayerbotAIConfig->botActiveAloneSmartScale) + { + 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) ? sPlayerbotAIConfig->botActiveAlone : 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, activePerc * 0.01f); @@ -5427,15 +5427,29 @@ bool PlayerbotAI::CanMove() if (IsInVehicle() && !IsInVehicle(true)) return false; - if (bot->isFrozen() || bot->IsPolymorphed() || (bot->isDead() && !bot->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) || - bot->IsBeingTeleported() || bot->isInRoots() || bot->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION) || - bot->HasAuraType(SPELL_AURA_MOD_CONFUSE) || bot->IsCharmed() || bot->HasAuraType(SPELL_AURA_MOD_STUN) || - bot->HasUnitState(UNIT_STATE_IN_FLIGHT) || bot->HasUnitState(UNIT_STATE_LOST_CONTROL)) + if (bot->isFrozen() || + bot->IsPolymorphed() || + (bot->isDead() && !bot->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) || + bot->IsBeingTeleported() || + bot->isInRoots() || + bot->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION) || + bot->HasAuraType(SPELL_AURA_MOD_CONFUSE) || + bot->IsCharmed() || + bot->HasAuraType(SPELL_AURA_MOD_STUN) || + bot->HasUnitState(UNIT_STATE_IN_FLIGHT) || + bot->HasUnitState(UNIT_STATE_LOST_CONTROL)) + return false; return bot->GetMotionMaster()->GetCurrentMovementGeneratorType() != FLIGHT_MOTION_TYPE; } +bool PlayerbotAI::IsTaxiFlying() +{ + return bot->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && + bot->HasUnitState(UNIT_STATE_IGNORE_PATHFINDING); +} + bool PlayerbotAI::IsInRealGuild() { if (!bot->GetGuildId()) diff --git a/src/PlayerbotAI.h b/src/PlayerbotAI.h index 3b83a5eb..d1a2f292 100644 --- a/src/PlayerbotAI.h +++ b/src/PlayerbotAI.h @@ -576,6 +576,7 @@ public: void ResetJumpDestination() { jumpDestination = Position(); } bool CanMove(); + bool IsTaxiFlying(); bool IsInRealGuild(); static std::vector dispel_whitelist; bool EqualLowercaseName(std::string s1, std::string s2); diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 1d60091b..d6c8e972 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -465,6 +465,7 @@ bool PlayerbotAIConfig::Initialize() playerbotsXPrate = sConfigMgr->GetOption("AiPlayerbot.KillXPRate", 1); disableDeathKnightLogin = sConfigMgr->GetOption("AiPlayerbot.DisableDeathKnightLogin", 0); botActiveAlone = sConfigMgr->GetOption("AiPlayerbot.BotActiveAlone", 100); + botActiveAloneSmartScale = sConfigMgr->GetOption("AiPlayerbot.botActiveAloneSmartScale", 1); enablePrototypePerformanceDiff = sConfigMgr->GetOption("AiPlayerbot.EnablePrototypePerformanceDiff", false); diffWithPlayer = sConfigMgr->GetOption("AiPlayerbot.DiffWithPlayer", 100); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index 6caf1179..24609eae 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -263,6 +263,7 @@ public: uint32 playerbotsXPrate; bool disableDeathKnightLogin; uint32 botActiveAlone; + bool botActiveAloneSmartScale; uint32 enablePrototypePerformanceDiff; uint32 diffWithPlayer; From 90464ae3edba024f12a66e52798da193c0b29b59 Mon Sep 17 00:00:00 2001 From: bash Date: Thu, 10 Oct 2024 18:01:54 +0000 Subject: [PATCH 03/22] Added min and max level for smartScale --- conf/playerbots.conf.dist | 4 ++++ src/PlayerbotAI.cpp | 4 +++- src/PlayerbotAIConfig.cpp | 2 ++ src/PlayerbotAIConfig.h | 2 ++ 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index e0356cb7..fe34fde4 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -1464,7 +1464,11 @@ 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 +AiPlayerbot.botActiveAloneSmartScaleWhenMinLevel = 1 +AiPlayerbot.botActiveAloneSmartScaleWhenMaxLevel = 80 + # Premade spell to avoid (undetected spells) # spellid-radius, ... diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 0df602d8..bba3753a 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -4288,7 +4288,9 @@ bool PlayerbotAI::AllowActive(ActivityType activityType) // GetPriorityBracket acitivity float activePerc = 100; - if (sPlayerbotAIConfig->botActiveAloneSmartScale) + if (sPlayerbotAIConfig->botActiveAloneSmartScale && + bot->GetLevel() >= sPlayerbotAIConfig->botActiveAloneSmartScaleWhenMinLevel && + bot->GetLevel() <= sPlayerbotAIConfig->botActiveAloneSmartScaleWhenMaxLevel) { std::pair priorityBracket = GetPriorityBracket(type); if (!priorityBracket.second) return true; diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index d6c8e972..270d3ae5 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -466,6 +466,8 @@ bool PlayerbotAIConfig::Initialize() disableDeathKnightLogin = sConfigMgr->GetOption("AiPlayerbot.DisableDeathKnightLogin", 0); botActiveAlone = sConfigMgr->GetOption("AiPlayerbot.BotActiveAlone", 100); botActiveAloneSmartScale = sConfigMgr->GetOption("AiPlayerbot.botActiveAloneSmartScale", 1); + botActiveAloneSmartScaleWhenMinLevel = sConfigMgr->GetOption("AiPlayerbot.botActiveAloneSmartScaleWhenMinLevel", 1); + botActiveAloneSmartScaleWhenMaxLevel = sConfigMgr->GetOption("AiPlayerbot.botActiveAloneSmartScaleWhenMaxLevel", 80); enablePrototypePerformanceDiff = sConfigMgr->GetOption("AiPlayerbot.EnablePrototypePerformanceDiff", false); diffWithPlayer = sConfigMgr->GetOption("AiPlayerbot.DiffWithPlayer", 100); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index 24609eae..4a2ec5b9 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -264,6 +264,8 @@ public: bool disableDeathKnightLogin; uint32 botActiveAlone; bool botActiveAloneSmartScale; + uint32 botActiveAloneSmartScaleWhenMinLevel; + uint32 botActiveAloneSmartScaleWhenMaxLevel; uint32 enablePrototypePerformanceDiff; uint32 diffWithPlayer; From c6f9f43a33d69395765ccd446d2ac570c8b2281d Mon Sep 17 00:00:00 2001 From: bash Date: Fri, 11 Oct 2024 18:48:00 +0000 Subject: [PATCH 04/22] [performance] Tweaked autoscale, too many rndbots were idle which defeats the purpose of having rndbots --- src/PlayerbotAI.cpp | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index bba3753a..c42ad985 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -4187,8 +4187,8 @@ ActivePiorityType PlayerbotAI::GetPriorityType(ActivityType activityType) } // 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, all bots in this bracket will be -// active above 20% activityMod and scale between those values. +// 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) @@ -4203,26 +4203,24 @@ std::pair PlayerbotAI::GetPriorityBracket(ActivePiorityType type case ActivePiorityType::IN_COMBAT: return {0, 10}; case ActivePiorityType::IN_BG_QUEUE: - return {0, 20}; case ActivePiorityType::IN_LFG: - return {0, 30}; + return {0, 20}; case ActivePiorityType::NEARBY_PLAYER: - return {0, 40}; + return {0, 30}; case ActivePiorityType::PLAYER_FRIEND: + return {0, 40}; + case ActivePiorityType::IN_ACTIVE_AREA: 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}; + return {20, 100}; case ActivePiorityType::IN_INACTIVE_MAP: - return {80, 100}; - default: + return {50, 100}; + case ActivePiorityType::IN_EMPTY_SERVER: return {90, 100}; + default: + return {50, 100}; } - - return {90, 100}; } bool PlayerbotAI::AllowActive(ActivityType activityType) From 158d923c15d1bb062c465261ff091e2f4976c8de Mon Sep 17 00:00:00 2001 From: bash Date: Fri, 11 Oct 2024 21:20:43 +0000 Subject: [PATCH 05/22] Autoscale latency modifier --- conf/playerbots.conf.dist | 12 +++++------- src/PlayerbotAIConfig.cpp | 14 ++++++++------ src/PlayerbotAIConfig.h | 6 ++---- src/RandomPlayerbotMgr.cpp | 11 ++++------- .../actions/BattleGroundJoinAction.cpp | 18 ++++++++---------- 5 files changed, 27 insertions(+), 34 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index fe34fde4..c7d23eed 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -1263,11 +1263,6 @@ Playerbots.Updates.EnableDatabases = 1 # Command server port, 0 - disabled AiPlayerbot.CommandServerPort = 8888 -# Diff with/without player in server. The server will tune bot activity to reach the desired server tick speed (in ms).# PLAYERBOT SYSTEM SETTINGS # -AiPlayerbot.EnablePrototypePerformanceDiff = 0 -AiPlayerbot.DiffWithPlayer = 100 -AiPlayerbot.DiffEmpty = 200 - # # # @@ -1464,11 +1459,14 @@ 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, ... diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 270d3ae5..816a345f 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -466,12 +466,14 @@ bool PlayerbotAIConfig::Initialize() disableDeathKnightLogin = sConfigMgr->GetOption("AiPlayerbot.DisableDeathKnightLogin", 0); botActiveAlone = sConfigMgr->GetOption("AiPlayerbot.BotActiveAlone", 100); botActiveAloneSmartScale = sConfigMgr->GetOption("AiPlayerbot.botActiveAloneSmartScale", 1); - botActiveAloneSmartScaleWhenMinLevel = sConfigMgr->GetOption("AiPlayerbot.botActiveAloneSmartScaleWhenMinLevel", 1); - botActiveAloneSmartScaleWhenMaxLevel = sConfigMgr->GetOption("AiPlayerbot.botActiveAloneSmartScaleWhenMaxLevel", 80); - - enablePrototypePerformanceDiff = sConfigMgr->GetOption("AiPlayerbot.EnablePrototypePerformanceDiff", false); - diffWithPlayer = sConfigMgr->GetOption("AiPlayerbot.DiffWithPlayer", 100); - diffEmpty = sConfigMgr->GetOption("AiPlayerbot.DiffEmpty", 200); + botActiveAloneSmartScaleWhenMinLevel = + 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 4a2ec5b9..5ac3fa4a 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -266,10 +266,8 @@ public: bool botActiveAloneSmartScale; uint32 botActiveAloneSmartScaleWhenMinLevel; uint32 botActiveAloneSmartScaleWhenMaxLevel; - - uint32 enablePrototypePerformanceDiff; - uint32 diffWithPlayer; - uint32 diffEmpty; + uint32 botActiveAloneSmartScaleDiffWithPlayer; + uint32 botActiveAloneSmartScaleDiffEmpty; bool freeMethodLoot; int32 lootRollLevel; diff --git a/src/RandomPlayerbotMgr.cpp b/src/RandomPlayerbotMgr.cpp index 5d3b5edf..9991144a 100644 --- a/src/RandomPlayerbotMgr.cpp +++ b/src/RandomPlayerbotMgr.cpp @@ -292,12 +292,8 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/) if (!sPlayerbotAIConfig->randomBotAutologin || !sPlayerbotAIConfig->enabled) return; - if (sPlayerbotAIConfig->enablePrototypePerformanceDiff) + if (sPlayerbotAIConfig->botActiveAloneSmartScale) { - LOG_INFO("playerbots", "---------------------------------------"); - LOG_INFO("playerbots", - "PROTOTYPE: Playerbot performance enhancements are active. Issues and instability may occur."); - LOG_INFO("playerbots", "---------------------------------------"); ScaleBotActivity(); } @@ -414,8 +410,9 @@ void RandomPlayerbotMgr::ScaleBotActivity() // max/min activity // % increase/decrease wanted diff , avg diff - float activityPercentageMod = pid.calculate( - sRandomPlayerbotMgr->GetPlayers().empty() ? sPlayerbotAIConfig->diffEmpty : sPlayerbotAIConfig->diffWithPlayer, + float activityPercentageMod = pid.calculate(sRandomPlayerbotMgr->GetPlayers().empty() ? + sPlayerbotAIConfig->botActiveAloneSmartScaleDiffEmpty : + sPlayerbotAIConfig->botActiveAloneSmartScaleDiffWithPlayer, sWorldUpdateTime.GetAverageUpdateTime()); activityPercentage = activityPercentageMod + 50; diff --git a/src/strategy/actions/BattleGroundJoinAction.cpp b/src/strategy/actions/BattleGroundJoinAction.cpp index e6842b23..349ae410 100644 --- a/src/strategy/actions/BattleGroundJoinAction.cpp +++ b/src/strategy/actions/BattleGroundJoinAction.cpp @@ -234,16 +234,15 @@ bool BGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battlegroun return false; TeamId teamId = bot->GetTeamId(); - bool noLag = sWorldUpdateTime.GetAverageUpdateTime() < (sRandomPlayerbotMgr->GetPlayers().empty() - ? sPlayerbotAIConfig->diffEmpty - : sPlayerbotAIConfig->diffWithPlayer) * - 1.1; + 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->enablePrototypePerformanceDiff && !noLag) + if (sPlayerbotAIConfig->botActiveAloneSmartScale && !noLag) return false; // If the bot is in a group, only the leader can queue @@ -578,16 +577,15 @@ bool FreeBGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battleg return false; TeamId teamId = bot->GetTeamId(); - bool noLag = sWorldUpdateTime.GetAverageUpdateTime() < (sRandomPlayerbotMgr->GetPlayers().empty() - ? sPlayerbotAIConfig->diffEmpty - : sPlayerbotAIConfig->diffWithPlayer) * - 1.1; + 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->enablePrototypePerformanceDiff && !noLag) + if (sPlayerbotAIConfig->botActiveAloneSmartScale && !noLag) return false; // If the bot is in a group, only the leader can queue From 98c084680c6220756f97a4df5b02e6f18d70bb83 Mon Sep 17 00:00:00 2001 From: avirar Date: Sat, 12 Oct 2024 17:50:42 +1100 Subject: [PATCH 06/22] Update DropQuestAction.cpp Bots were not dropping trivial quests. Initially let them keep quests in progress, but their logs were still very full. --- src/strategy/actions/DropQuestAction.cpp | 99 ++++++++++++++++-------- 1 file changed, 68 insertions(+), 31 deletions(-) diff --git a/src/strategy/actions/DropQuestAction.cpp b/src/strategy/actions/DropQuestAction.cpp index a1e2ffcb..910e5498 100644 --- a/src/strategy/actions/DropQuestAction.cpp +++ b/src/strategy/actions/DropQuestAction.cpp @@ -58,55 +58,92 @@ bool DropQuestAction::Execute(Event event) return true; } + bool CleanQuestLogAction::Execute(Event event) { Player* requester = event.getOwner() ? event.getOwner() : GetMaster(); - std::string link = event.getParam(); - if (botAI->HasActivePlayerMaster() || !sRandomPlayerbotMgr->IsRandomBot(bot)) + if (!requester) + { + botAI->TellMaster("No event owner detected"); return false; - - uint8 totalQuests = 0; - // Count the total quests - DropQuestType(totalQuests); - if (MAX_QUEST_LOG_SIZE - totalQuests > 6) - { - // Drop failed quests - DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE, true, true); - return true; } - // Only drop gray quests when able to fight proper lvl quests. - if (AI_VALUE(bool, "can fight equal")) + // Only output this message if "debug rpg" strategy is enabled + if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT)) { - // Drop gray/red quests. - DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 6); - // Drop gray/red quests with progress. - DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 6, false, true); - // Drop gray/red completed quests. - DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 6, false, true, true); + botAI->TellMaster("Clean Quest Log command received, removing grey/trivial quests..."); } - if (MAX_QUEST_LOG_SIZE - totalQuests > 4) - return true; + uint8 botLevel = bot->GetLevel(); // Get bot's level + uint8 numQuest = 0; + for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot) + { + if (bot->GetQuestSlotQuestId(slot)) + { + numQuest++; + } + } - DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 4, true); // Drop quests without progress. + for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot) + { + uint32 questId = bot->GetQuestSlotQuestId(slot); + if (!questId) + continue; - if (MAX_QUEST_LOG_SIZE - totalQuests > 2) - return true; + const Quest* quest = sObjectMgr->GetQuestTemplate(questId); + if (!quest) + continue; - DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 2, true, true); // Drop quests with progress. + // Determine if quest is trivial by comparing levels + int32 questLevel = quest->GetQuestLevel(); + if (questLevel == -1) // For scaling quests, default to bot level + { + questLevel = botLevel; + } - if (MAX_QUEST_LOG_SIZE - totalQuests > 0) - return true; + // Check if the quest is trivial (grey) for the bot + if ((botLevel - questLevel) >= 5) + { + // Output only if "debug rpg" strategy is enabled + if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT)) + { + botAI->TellMaster("Quest [ " + quest->GetTitle() + " ] will be removed because it is trivial (grey)."); + } - DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 1, true, true, true); // Drop completed quests. + // Remove quest + bot->SetQuestSlot(slot, 0); + bot->TakeQuestSourceItem(questId, false); + bot->SetQuestStatus(questId, QUEST_STATUS_NONE); + bot->RemoveRewardedQuest(questId); - if (MAX_QUEST_LOG_SIZE - totalQuests > 0) - return true; + numQuest--; - return false; + if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT)) + { + const std::string text_quest = ChatHelper::FormatQuest(quest); + LOG_INFO("playerbots", "{} => Quest [ {} ] removed", bot->GetName(), quest->GetTitle()); + bot->Say("Quest [ " + text_quest + " ] removed", LANG_UNIVERSAL); + } + + if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT)) + { + botAI->TellMaster("Quest [ " + quest->GetTitle() + " ] has been removed."); + } + } + else + { + // Only output if "debug rpg" strategy is enabled + if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT)) + { + botAI->TellMaster("Quest [ " + quest->GetTitle() + " ] is not trivial and will be kept."); + } + } + } + + return true; } + void CleanQuestLogAction::DropQuestType(uint8& numQuest, uint8 wantNum, bool isGreen, bool hasProgress, bool isComplete) { std::vector slots; From 8c86c6b6d79453f5a4568f3c646b5686df10f476 Mon Sep 17 00:00:00 2001 From: bash Date: Sat, 12 Oct 2024 10:34:45 +0000 Subject: [PATCH 07/22] [performance] SmartScale slighty more aggresive, after testing i found some bots to active --- src/PlayerbotAI.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index c42ad985..e3fe0c4c 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -4190,7 +4190,7 @@ ActivePiorityType PlayerbotAI::GetPriorityType(ActivityType activityType) // 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: @@ -4203,24 +4203,27 @@ std::pair PlayerbotAI::GetPriorityBracket(ActivePiorityType type case ActivePiorityType::IN_COMBAT: return {0, 10}; case ActivePiorityType::IN_BG_QUEUE: - case ActivePiorityType::IN_LFG: return {0, 20}; - case ActivePiorityType::NEARBY_PLAYER: + case ActivePiorityType::IN_LFG: return {0, 30}; - case ActivePiorityType::PLAYER_FRIEND: + case ActivePiorityType::NEARBY_PLAYER: return {0, 40}; - case ActivePiorityType::IN_ACTIVE_AREA: + case ActivePiorityType::PLAYER_FRIEND: case ActivePiorityType::PLAYER_GUILD: return {0, 50}; + case ActivePiorityType::IN_ACTIVE_AREA: + return {30, 100}; case ActivePiorityType::IN_ACTIVE_MAP: - return {20, 100}; + return {50, 100}; case ActivePiorityType::IN_INACTIVE_MAP: - return {50, 100}; + return {70, 100}; case ActivePiorityType::IN_EMPTY_SERVER: - return {90, 100}; + return {80, 100}; default: - return {50, 100}; + return {90, 100}; } + + return {90, 100}; } bool PlayerbotAI::AllowActive(ActivityType activityType) From 77ba59ed547a514b09a105cb97cd3d7dd25de990 Mon Sep 17 00:00:00 2001 From: bash Date: Sun, 13 Oct 2024 00:00:41 +0000 Subject: [PATCH 08/22] [performance] Smartscale added missing acitivity --- src/PlayerbotAI.cpp | 63 ++++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 24 deletions(-) diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index c42ad985..94bc7d2d 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -4101,10 +4101,12 @@ ActivePiorityType PlayerbotAI::GetPriorityType(ActivityType activityType) if (member == bot) continue; + //IN_GROUP_WITH_REAL_PLAYER PlayerbotAI* memberBotAI = GET_PLAYERBOT_AI(member); if (!memberBotAI || memberBotAI->HasRealPlayerMaster()) return ActivePiorityType::IN_GROUP_WITH_REAL_PLAYER; + //IN_GROUP_WITH_REAL_PLAYER if (group->IsLeader(member->GetGUID())) { if (!memberBotAI->AllowActivity(PARTY_ACTIVITY)) @@ -4113,22 +4115,27 @@ ActivePiorityType PlayerbotAI::GetPriorityType(ActivityType activityType) } } + //IN_INSTANCE if (bot->IsBeingTeleported()) // Allow activity while teleportation. return ActivePiorityType::IN_INSTANCE; + //IN_INSTANCE if (!WorldPosition(bot).isOverworld()) return ActivePiorityType::IN_INSTANCE; - if (HasPlayerNearby()) + //VISIBLE_FOR_PLAYER + if (HasPlayerNearby(sPlayerbotAIConfig->reactDistance)) return ActivePiorityType::VISIBLE_FOR_PLAYER; + //IN_COMBAT if (activityType != OUT_OF_PARTY_ACTIVITY && activityType != PACKET_ACTIVITY) { - // Is in combat.Defend yourself. + // Is in combat, defend yourself. if (bot->IsInCombat()) return ActivePiorityType::IN_COMBAT; } + //NEARBY_PLAYER if (HasPlayerNearby(300.f)) return ActivePiorityType::NEARBY_PLAYER; @@ -4153,33 +4160,38 @@ ActivePiorityType PlayerbotAI::GetPriorityType(ActivityType activityType) if (isLFG) return ActivePiorityType::IN_LFG; - // If has real players - slow down continents without player - // This means we first disable bots in a different continent/area. + //IN_EMPTY_SERVER if (sRandomPlayerbotMgr->GetPlayers().empty()) return ActivePiorityType::IN_EMPTY_SERVER; - // friends always active - // for (auto& player : sRandomPlayerbotMgr->GetPlayers()) - // { - // if (!player || !player->IsInWorld()) - // continue; + //PLAYER_FRIEND (on friendlist of real player) (needs to be tested for stability) + /*for (auto& player : sRandomPlayerbotMgr->GetPlayers()) + { + if (!player || !player->IsInWorld()) + continue; - // if (player->GetSocial()->HasFriend(bot->GetGUID())) - // return ActivePiorityType::PLAYER_FRIEND; - // } + if (player->GetSocial() && + bot->GetGUID() && + player->GetSocial()->HasFriend(bot->GetGUID())) + return ActivePiorityType::PLAYER_FRIEND; + }*/ - // real guild always active if member+ + //PLAYER_GUILD (contains real player) if (IsInRealGuild()) return ActivePiorityType::PLAYER_GUILD; + //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())) + return ActivePiorityType::IN_ACTIVE_MAP; + // IN_ACTIVE_AREA if (activityType == OUT_OF_PARTY_ACTIVITY || activityType == GRIND_ACTIVITY) { - // Many bots nearby. Do not do heavy area checks. - if (HasManyPlayersNearby()) + if (HasManyPlayersNearby(20, sPlayerbotAIConfig->sightDistance)) return ActivePiorityType::IN_ACTIVE_AREA; } @@ -4190,7 +4202,7 @@ ActivePiorityType PlayerbotAI::GetPriorityType(ActivityType activityType) // 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: @@ -4203,24 +4215,27 @@ std::pair PlayerbotAI::GetPriorityBracket(ActivePiorityType type case ActivePiorityType::IN_COMBAT: return {0, 10}; case ActivePiorityType::IN_BG_QUEUE: - case ActivePiorityType::IN_LFG: return {0, 20}; - case ActivePiorityType::NEARBY_PLAYER: + case ActivePiorityType::IN_LFG: return {0, 30}; - case ActivePiorityType::PLAYER_FRIEND: + case ActivePiorityType::NEARBY_PLAYER: return {0, 40}; - case ActivePiorityType::IN_ACTIVE_AREA: + case ActivePiorityType::PLAYER_FRIEND: case ActivePiorityType::PLAYER_GUILD: return {0, 50}; + case ActivePiorityType::IN_ACTIVE_AREA: + return {30, 100}; case ActivePiorityType::IN_ACTIVE_MAP: - return {20, 100}; + return {50, 100}; case ActivePiorityType::IN_INACTIVE_MAP: - return {50, 100}; + return {70, 100}; case ActivePiorityType::IN_EMPTY_SERVER: - return {90, 100}; + return {80, 100}; default: - return {50, 100}; + return {90, 100}; } + + return {90, 100}; } bool PlayerbotAI::AllowActive(ActivityType activityType) From 62aef235d16b14d8fa0dbb191c255fbcca7fce3d Mon Sep 17 00:00:00 2001 From: bash Date: Sun, 13 Oct 2024 22:05:39 +0000 Subject: [PATCH 09/22] Rewrote scaling, moving away from cmangos solutions --- conf/playerbots.conf.dist | 6 +- src/PlayerbotAI.cpp | 145 +++++++++++------- src/PlayerbotAI.h | 2 +- src/PlayerbotAIConfig.cpp | 4 - src/PlayerbotAIConfig.h | 2 - src/RandomPlayerbotMgr.cpp | 26 ---- src/RandomPlayerbotMgr.h | 3 +- .../actions/BattleGroundJoinAction.cpp | 15 -- 8 files changed, 90 insertions(+), 113 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index c7d23eed..0c220c81 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -1459,14 +1459,10 @@ AiPlayerbot.BotActiveAlone = 100 # Specify smart scaling is enabled or not. # The default is 1. When enabled (smart) scales the 'BotActiveAlone' value. -AiPlayerbot.botActiveAloneSmartScale = 1 # Only when botLevel is between WhenMinLevel and WhenMaxLevel. +AiPlayerbot.botActiveAloneSmartScale = 1 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, ... diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 94bc7d2d..4b037f7e 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,12 +4181,18 @@ ActivePiorityType PlayerbotAI::GetPriorityType(ActivityType activityType) return ActivePiorityType::PLAYER_GUILD; //IN_INACTIVE_MAP - if (bot->IsBeingTeleported() || !bot->IsInWorld() || !HasRealPlayers(bot->GetMap())) - return ActivePiorityType::IN_INACTIVE_MAP; + if (bot->IsBeingTeleported() || + !bot->IsInWorld() || + !HasRealPlayers(bot->GetMap()) || + !bot->GetMap()->IsGridLoaded(bot->GetPositionX(), bot->GetPositionY())) + return ActivePiorityType::IN_INACTIVE_MAP; //IN_ACTIVE_MAP - if (!bot->IsBeingTeleported() && bot->IsInWorld() && HasRealPlayers(bot->GetMap())) - return ActivePiorityType::IN_ACTIVE_MAP; + if (!bot->IsBeingTeleported() && + bot->IsInWorld() && + HasRealPlayers(bot->GetMap()) && + bot->GetMap()->IsGridLoaded(bot->GetPositionX(), bot->GetPositionY())) + return ActivePiorityType::IN_ACTIVE_MAP; // IN_ACTIVE_AREA if (activityType == OUT_OF_PARTY_ACTIVITY || activityType == GRIND_ACTIVITY) @@ -4198,46 +4204,6 @@ 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: - return {30, 100}; - case ActivePiorityType::IN_ACTIVE_MAP: - return {50, 100}; - case ActivePiorityType::IN_INACTIVE_MAP: - return {70, 100}; - case ActivePiorityType::IN_EMPTY_SERVER: - return {80, 100}; - default: - return {90, 100}; - } - - return {90, 100}; -} - bool PlayerbotAI::AllowActive(ActivityType activityType) { // General exceptions @@ -4299,26 +4265,25 @@ bool PlayerbotAI::AllowActive(ActivityType activityType) } } - // GetPriorityBracket acitivity - float activePerc = 100; + uint32 botActiveAlonePerc = sPlayerbotAIConfig->botActiveAlone > 100 ? 100 : sPlayerbotAIConfig->botActiveAlone; + uint32 mod = botActiveAlonePerc; + if (botActiveAlonePerc <= 0) return false; + if (botActiveAlonePerc >= 100) return true; + if (sPlayerbotAIConfig->botActiveAloneSmartScale && bot->GetLevel() >= sPlayerbotAIConfig->botActiveAloneSmartScaleWhenMinLevel && bot->GetLevel() <= sPlayerbotAIConfig->botActiveAloneSmartScaleWhenMaxLevel) { - 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) ? sPlayerbotAIConfig->botActiveAlone : 100; + // float activityPercentage = sRandomPlayerbotMgr->getActivityPercentage(); + mod = SmartScaleActivity(type, botActiveAlonePerc); } - // 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 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 given percentage of bots should be active and rotate 1% of those active bots each minute. - return ActivityNumber <= (activePerc); + //The given percentage of bots should be active and rotate 1% of those active bots each minute. + return ActivityNumber <= (botActiveAlonePerc * mod) / 100; } bool PlayerbotAI::AllowActivity(ActivityType activityType, bool checkNow) @@ -4335,6 +4300,70 @@ 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 d1a2f292..90024f2b 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 816a345f..53a7b720 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -470,10 +470,6 @@ 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 5ac3fa4a..0f34b41e 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -266,8 +266,6 @@ 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 9991144a..8ace6b8d 100644 --- a/src/RandomPlayerbotMgr.cpp +++ b/src/RandomPlayerbotMgr.cpp @@ -292,11 +292,6 @@ 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)) @@ -402,27 +397,6 @@ 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 5c35aefa..7d0670e2 100644 --- a/src/RandomPlayerbotMgr.h +++ b/src/RandomPlayerbotMgr.h @@ -103,8 +103,7 @@ public: void LogPlayerLocation(); void UpdateAIInternal(uint32 elapsed, bool minimal = false) override; -private: - void ScaleBotActivity(); +//private: public: uint32 activeBots = 0; diff --git a/src/strategy/actions/BattleGroundJoinAction.cpp b/src/strategy/actions/BattleGroundJoinAction.cpp index 349ae410..541ce2a4 100644 --- a/src/strategy/actions/BattleGroundJoinAction.cpp +++ b/src/strategy/actions/BattleGroundJoinAction.cpp @@ -234,17 +234,9 @@ 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; @@ -577,17 +569,10 @@ 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; From 6e4db7ee3be2fbc7ea919782a5df415a3795e00d Mon Sep 17 00:00:00 2001 From: bash Date: Sun, 13 Oct 2024 22:48:33 +0000 Subject: [PATCH 10/22] Replaced isTaxiFlying check with new function --- src/RandomPlayerbotMgr.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/RandomPlayerbotMgr.cpp b/src/RandomPlayerbotMgr.cpp index 8ace6b8d..c48b5b25 100644 --- a/src/RandomPlayerbotMgr.cpp +++ b/src/RandomPlayerbotMgr.cpp @@ -1236,9 +1236,7 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector& if (botAI) { // ignore when in when taxi with boat/zeppelin and has players nearby - if (bot->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && - bot->HasUnitState(UNIT_STATE_IGNORE_PATHFINDING) && - botAI->HasPlayerNearby()) + if (botAI->IsTaxiFlying() && botAI->HasPlayerNearby()) return; } From db395ae13c7f47780c3e5a2563661b30e0db1ab3 Mon Sep 17 00:00:00 2001 From: EricksOliveira Date: Sun, 13 Oct 2024 20:17:18 -0300 Subject: [PATCH 11/22] Fix LFG Join bug This PR adjusts the execution priority of bot actions in Dungeon Finder (DF), modifying the relevance logic to make responses faster. The relevance calculation formula was changed in RpgAction::SetNextRpgAction to reduce the delay between activating actions, especially to improve the acceptance time of bots in DF queues. With these changes, bots now accept vacancies in a more agile and efficient way, optimizing overall response time. --- src/strategy/actions/RpgAction.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strategy/actions/RpgAction.cpp b/src/strategy/actions/RpgAction.cpp index c300221c..f5ffa130 100644 --- a/src/strategy/actions/RpgAction.cpp +++ b/src/strategy/actions/RpgAction.cpp @@ -79,7 +79,7 @@ bool RpgAction::SetNextRpgAction() { NextAction* nextAction = nextActions[i]; - if (nextAction->getRelevance() > 2.0f) + if (nextAction->getRelevance() > 5.0f) continue; if (!isChecked && !trigger->IsActive()) @@ -92,7 +92,7 @@ bool RpgAction::SetNextRpgAction() continue; actions.push_back(action); - relevances.push_back((nextAction->getRelevance() - 1) * 1000); + relevances.push_back((nextAction->getRelevance() - 1) * 500); } NextAction::destroy(nextActions); } From 12be2c997128156bf5079bf43d402bded685f430 Mon Sep 17 00:00:00 2001 From: bash Date: Thu, 17 Oct 2024 17:52:05 +0000 Subject: [PATCH 12/22] Revert "Rewrote scaling, moving away from cmangos solutions" This reverts commit 62aef235d16b14d8fa0dbb191c255fbcca7fce3d. --- conf/playerbots.conf.dist | 6 +- src/PlayerbotAI.cpp | 145 +++++++----------- src/PlayerbotAI.h | 2 +- src/PlayerbotAIConfig.cpp | 4 + src/PlayerbotAIConfig.h | 2 + src/RandomPlayerbotMgr.cpp | 26 ++++ src/RandomPlayerbotMgr.h | 3 +- .../actions/BattleGroundJoinAction.cpp | 15 ++ 8 files changed, 113 insertions(+), 90 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 0c220c81..c7d23eed 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -1459,10 +1459,14 @@ 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, ... diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 4b037f7e..94bc7d2d 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,46 @@ 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: + return {30, 100}; + case ActivePiorityType::IN_ACTIVE_MAP: + return {50, 100}; + case ActivePiorityType::IN_INACTIVE_MAP: + return {70, 100}; + case ActivePiorityType::IN_EMPTY_SERVER: + return {80, 100}; + default: + return {90, 100}; + } + + return {90, 100}; +} + bool PlayerbotAI::AllowActive(ActivityType activityType) { // General exceptions @@ -4265,25 +4299,26 @@ 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 activePerc = 100; 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) ? sPlayerbotAIConfig->botActiveAlone : 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; From a3abc78c247683df83eb9e6d3b5edd629da63b0a Mon Sep 17 00:00:00 2001 From: Trus3683 <152137641+Trus3683@users.noreply.github.com> Date: Thu, 17 Oct 2024 12:53:43 -0700 Subject: [PATCH 13/22] Visual update playerbots.conf.dist Cleanup for readability on new scaling/bot tuning implements --- conf/playerbots.conf.dist | 2 ++ 1 file changed, 2 insertions(+) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index c7d23eed..b644c6c9 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -1460,9 +1460,11 @@ AiPlayerbot.BotActiveAlone = 100 # Specify smart scaling is enabled or not. # The default is 1. When enabled (smart) scales the 'BotActiveAlone' value. 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 From 4eb40c03952840c6c8ba7e79c5c0730702c1ae58 Mon Sep 17 00:00:00 2001 From: bash Date: Thu, 17 Oct 2024 20:28:56 +0000 Subject: [PATCH 14/22] minor bugfix and back to original cmangos values --- src/PlayerbotAI.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 94bc7d2d..023ec7b6 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -4224,19 +4224,18 @@ std::pair PlayerbotAI::GetPriorityBracket(ActivePiorityType type case ActivePiorityType::PLAYER_GUILD: return {0, 50}; case ActivePiorityType::IN_ACTIVE_AREA: - return {30, 100}; - case ActivePiorityType::IN_ACTIVE_MAP: - return {50, 100}; - case ActivePiorityType::IN_INACTIVE_MAP: - return {70, 100}; 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) { @@ -4300,7 +4299,8 @@ bool PlayerbotAI::AllowActive(ActivityType activityType) } // GetPriorityBracket acitivity - float activePerc = 100; + float normalizedBotActiveAlone = sPlayerbotAIConfig->botActiveAlone > 100 ? 100 : sPlayerbotAIConfig->botActiveAlone; + float activePerc = normalizedBotActiveAlone; if (sPlayerbotAIConfig->botActiveAloneSmartScale && bot->GetLevel() >= sPlayerbotAIConfig->botActiveAloneSmartScaleWhenMinLevel && bot->GetLevel() <= sPlayerbotAIConfig->botActiveAloneSmartScaleWhenMaxLevel) @@ -4311,7 +4311,7 @@ bool PlayerbotAI::AllowActive(ActivityType activityType) 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) ? sPlayerbotAIConfig->botActiveAlone : 100; + activePerc *= (priorityBracket.second == 100) ? normalizedBotActiveAlone : 100; } // The last number if the amount it cycles per min. Currently set to 1% of the active bots. From 037258fb1a0890054a77b79f7aaf0722bad430d9 Mon Sep 17 00:00:00 2001 From: EricksOliveira Date: Thu, 17 Oct 2024 21:19:00 -0300 Subject: [PATCH 15/22] Fix Bug Bot blocked in PT After leaving PT, the Bot was stuck in a Group, stopped and without receiving invites from other players. Ideally, use the LeaveGroupOnLogout.Enabled = 1 setting in Worldserver.conf so that after the player leaves the game, the Bots are not stuck in Raid. --- src/strategy/actions/LeaveGroupAction.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/strategy/actions/LeaveGroupAction.cpp b/src/strategy/actions/LeaveGroupAction.cpp index 39d0451d..b2594e0f 100644 --- a/src/strategy/actions/LeaveGroupAction.cpp +++ b/src/strategy/actions/LeaveGroupAction.cpp @@ -30,6 +30,8 @@ bool PartyCommandAction::Execute(Event event) Player* master = GetMaster(); if (master && member == master->GetName()) return Leave(bot); + + botAI->Reset(); return false; } @@ -62,6 +64,8 @@ bool UninviteAction::Execute(Event event) if (bot->GetGUID() == guid) return Leave(bot); } + + botAI->Reset(); return false; } @@ -160,6 +164,8 @@ bool LeaveFarAwayAction::isUseful() { return true; } + + botAI->Reset(); return false; } From 65b6e15ea1ff87db9e50463f93d74c4d6de340d3 Mon Sep 17 00:00:00 2001 From: EricksOliveira Date: Fri, 18 Oct 2024 09:27:46 -0300 Subject: [PATCH 16/22] Fix Crash - OnBotLogin 1. Improvements in error handling: Added detailed logs for cases where botAI or master are null, allowing better failure tracking. 2. Additional null pointer checks: Added checks to ensure that the botAI and master are valid before performing actions dependent on these objects, preventing potential crashes. 3. Optimization in bot login logic: Revised the bot input flow to ensure it is added to the group appropriately depending on its relationship to the master. Added logic for handling different types of groups (raid, LFG, etc.), including the possibility of automatic conversion to raid if necessary. --- src/PlayerbotMgr.cpp | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/src/PlayerbotMgr.cpp b/src/PlayerbotMgr.cpp index 34e107d1..3cae1645 100644 --- a/src/PlayerbotMgr.cpp +++ b/src/PlayerbotMgr.cpp @@ -100,6 +100,8 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con Player* bot = botSession->GetPlayer(); if (!bot) { + // Log para debug + LOG_ERROR("mod-playerbots", "Bot player could not be loaded for account ID: {}", botAccountId); botSession->LogoutPlayer(true); delete botSession; botLoading.erase(holder.GetGuid()); @@ -108,6 +110,14 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con uint32 masterAccount = holder.GetMasterAccountId(); WorldSession* masterSession = masterAccount ? sWorld->FindSession(masterAccount) : nullptr; + + // Check if masterSession->GetPlayer() is valid + Player* masterPlayer = masterSession ? masterSession->GetPlayer() : nullptr; + if (masterSession && !masterPlayer) + { + LOG_ERROR("mod-playerbots", "Master session found but no player is associated for master account ID: {}", masterAccount); + } + std::ostringstream out; bool allowed = false; if (botAccountId == masterAccount) @@ -115,7 +125,7 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con allowed = true; } else if (masterSession && sPlayerbotAIConfig->allowGuildBots && bot->GetGuildId() != 0 && - bot->GetGuildId() == masterSession->GetPlayer()->GetGuildId()) + bot->GetGuildId() == masterPlayer->GetGuildId()) { allowed = true; } @@ -129,10 +139,14 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con out << "Failure: You are not allowed to control bot " << bot->GetName().c_str(); } - if (allowed && masterSession) + if (allowed && masterSession && masterPlayer) { - Player* player = masterSession->GetPlayer(); - PlayerbotMgr* mgr = GET_PLAYERBOT_MGR(player); + PlayerbotMgr* mgr = GET_PLAYERBOT_MGR(masterPlayer); + if (!mgr) + { + LOG_ERROR("mod-playerbots", "PlayerbotMgr not found for master player with GUID: {}", masterPlayer->GetGUID().GetRawValue()); + } + uint32 count = mgr->GetPlayerbotsCount(); uint32 cls_count = mgr->GetPlayerbotsCountByClass(bot->getClass()); if (count >= sPlayerbotAIConfig->maxAddedBots) @@ -428,14 +442,17 @@ void PlayerbotHolder::OnBotLogin(Player* const bot) PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot); if (!botAI) { + // Log a warning here to indicate that the botAI is null + LOG_ERROR("mod-playerbots", "PlayerbotAI is null for bot with GUID: {}", bot->GetGUID().GetRawValue()); return; } + Player* master = botAI->GetMaster(); - if (master) + if (!master) { - ObjectGuid masterGuid = master->GetGUID(); - if (master->GetGroup() && !master->GetGroup()->IsLeader(masterGuid)) - master->GetGroup()->ChangeLeader(masterGuid); + // Log a warning to indicate that the master is null + LOG_ERROR("mod-playerbots", "Master is null for bot with GUID: {}", bot->GetGUID().GetRawValue()); + return; } Group* group = bot->GetGroup(); From 8f2455b7663c935fb33d3552bb1371390d1106f8 Mon Sep 17 00:00:00 2001 From: EricksOliveira Date: Fri, 18 Oct 2024 14:37:54 -0300 Subject: [PATCH 17/22] Update PlayerbotCommandServer.cpp Protection against race conditions: Added a global mutex (session_mutex) to synchronize access to the session() function when multiple threads are running. This avoids concurrency problems in environments with many simultaneous connections. Thread pool usage: Replaced manual thread creation with boost::thread with a thread pool using boost::asio::thread_pool. The thread pool improves resource management and limits the number of simultaneous threads, optimizing performance. Checking for socket errors: Added check to ensure the socket is not null or closed before trying to read it. Implemented detailed error handling for readings and writings, including detailed logs to facilitate debugging. Secure socket closure: Now sockets are correctly closed at the end of the session, even in the event of an error, preventing resource leaks. --- src/PlayerbotCommandServer.cpp | 52 ++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/src/PlayerbotCommandServer.cpp b/src/PlayerbotCommandServer.cpp index 482c2348..c08f1d05 100644 --- a/src/PlayerbotCommandServer.cpp +++ b/src/PlayerbotCommandServer.cpp @@ -9,8 +9,10 @@ #include #include #include +#include #include #include +#include #include "IoContext.h" #include "Playerbots.h" @@ -18,21 +20,39 @@ using boost::asio::ip::tcp; typedef boost::shared_ptr socket_ptr; +std::mutex session_mutex; // Global mutex to protect sessions +boost::asio::thread_pool pool(4); // 4-thread thread pool + bool ReadLine(socket_ptr sock, std::string* buffer, std::string* line) { - // Do the real reading from fd until buffer has '\n'. + // Check if the socket is valid before using it + if (!sock || !sock->is_open()) + { + LOG_ERROR("playerbots", "Invalid or closed socket."); + return false; + } + + // Does the actual reading until the buffer has a '\n' std::string::iterator pos; while ((pos = find(buffer->begin(), buffer->end(), '\n')) == buffer->end()) { char buf[1025]; boost::system::error_code error; - size_t n = sock->read_some(boost::asio::buffer(buf), error); - if (n == -1 || error == boost::asio::error::eof) - return false; - else if (error) - throw boost::system::system_error(error); // Some other error. - buf[n] = 0; + // Read socket data + size_t n = sock->read_some(boost::asio::buffer(buf), error); + if (n == 0 || error == boost::asio::error::eof) + { + LOG_INFO("playerbots", "Connection closed by peer."); + return false; + } + else if (error) + { + LOG_ERROR("playerbots", "Socket read error: {}", error.message()); + return false; // Returns false in case of error. + } + + buf[n] = 0; // Ensures the buffer ends with null *buffer += buf; } @@ -45,6 +65,8 @@ void session(socket_ptr sock) { try { + std::lock_guard guard(session_mutex); // Protect session with mutex + std::string buffer, request; while (ReadLine(sock, &buffer, &request)) { @@ -55,7 +77,19 @@ void session(socket_ptr sock) } catch (std::exception& e) { - LOG_ERROR("playerbots", "{}", e.what()); + LOG_ERROR("playerbots", "Session error: {}", e.what()); + } + + // Make sure to close the socket at the end of the session + if (sock && sock->is_open()) + { + boost::system::error_code ec; + sock->shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); + sock->close(ec); + if (ec) + { + LOG_ERROR("playerbots", "Error closing socket: {}", ec.message()); + } } } @@ -66,7 +100,7 @@ void server(Acore::Asio::IoContext& io_service, short port) { socket_ptr sock(new tcp::socket(io_service)); a.accept(*sock); - boost::thread t(boost::bind(session, sock)); + boost::asio::post(pool, boost::bind(session, sock)); // Use thread pool instead of creating new threads } } From eabad44d4bcc45a255fb7bdda409e6f7a1a47e64 Mon Sep 17 00:00:00 2001 From: EricksOliveira Date: Fri, 18 Oct 2024 14:40:25 -0300 Subject: [PATCH 18/22] Revert "Update PlayerbotCommandServer.cpp" This reverts commit 8f2455b7663c935fb33d3552bb1371390d1106f8. --- src/PlayerbotCommandServer.cpp | 46 +++++----------------------------- 1 file changed, 6 insertions(+), 40 deletions(-) diff --git a/src/PlayerbotCommandServer.cpp b/src/PlayerbotCommandServer.cpp index c08f1d05..482c2348 100644 --- a/src/PlayerbotCommandServer.cpp +++ b/src/PlayerbotCommandServer.cpp @@ -9,10 +9,8 @@ #include #include #include -#include #include #include -#include #include "IoContext.h" #include "Playerbots.h" @@ -20,39 +18,21 @@ using boost::asio::ip::tcp; typedef boost::shared_ptr socket_ptr; -std::mutex session_mutex; // Global mutex to protect sessions -boost::asio::thread_pool pool(4); // 4-thread thread pool - bool ReadLine(socket_ptr sock, std::string* buffer, std::string* line) { - // Check if the socket is valid before using it - if (!sock || !sock->is_open()) - { - LOG_ERROR("playerbots", "Invalid or closed socket."); - return false; - } - - // Does the actual reading until the buffer has a '\n' + // Do the real reading from fd until buffer has '\n'. std::string::iterator pos; while ((pos = find(buffer->begin(), buffer->end(), '\n')) == buffer->end()) { char buf[1025]; boost::system::error_code error; - - // Read socket data size_t n = sock->read_some(boost::asio::buffer(buf), error); - if (n == 0 || error == boost::asio::error::eof) - { - LOG_INFO("playerbots", "Connection closed by peer."); + if (n == -1 || error == boost::asio::error::eof) return false; - } else if (error) - { - LOG_ERROR("playerbots", "Socket read error: {}", error.message()); - return false; // Returns false in case of error. - } + throw boost::system::system_error(error); // Some other error. - buf[n] = 0; // Ensures the buffer ends with null + buf[n] = 0; *buffer += buf; } @@ -65,8 +45,6 @@ void session(socket_ptr sock) { try { - std::lock_guard guard(session_mutex); // Protect session with mutex - std::string buffer, request; while (ReadLine(sock, &buffer, &request)) { @@ -77,19 +55,7 @@ void session(socket_ptr sock) } catch (std::exception& e) { - LOG_ERROR("playerbots", "Session error: {}", e.what()); - } - - // Make sure to close the socket at the end of the session - if (sock && sock->is_open()) - { - boost::system::error_code ec; - sock->shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); - sock->close(ec); - if (ec) - { - LOG_ERROR("playerbots", "Error closing socket: {}", ec.message()); - } + LOG_ERROR("playerbots", "{}", e.what()); } } @@ -100,7 +66,7 @@ void server(Acore::Asio::IoContext& io_service, short port) { socket_ptr sock(new tcp::socket(io_service)); a.accept(*sock); - boost::asio::post(pool, boost::bind(session, sock)); // Use thread pool instead of creating new threads + boost::thread t(boost::bind(session, sock)); } } From c313cdfa8eb6f6150e6b2df8a557ab2d46cbf54e Mon Sep 17 00:00:00 2001 From: Revision Date: Sat, 19 Oct 2024 03:10:46 +0200 Subject: [PATCH 19/22] Move tables into their own files --- ...layerbots_text.sql => ai_playerbot_texts.sql} | 16 ---------------- .../base/ai_playerbot_texts_chance.sql | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 16 deletions(-) rename sql/playerbots/base/{playerbots_text.sql => ai_playerbot_texts.sql} (99%) create mode 100644 sql/playerbots/base/ai_playerbot_texts_chance.sql diff --git a/sql/playerbots/base/playerbots_text.sql b/sql/playerbots/base/ai_playerbot_texts.sql similarity index 99% rename from sql/playerbots/base/playerbots_text.sql rename to sql/playerbots/base/ai_playerbot_texts.sql index 881e4671..718db731 100644 --- a/sql/playerbots/base/playerbots_text.sql +++ b/sql/playerbots/base/ai_playerbot_texts.sql @@ -1457,19 +1457,3 @@ INSERT INTO `ai_playerbot_texts` (`name`, `text`, `say_type`, `reply_type`, `tex ('dummy_end', 'dummy', 0, 0, '', '', '', '', '', '', '', ''); - -DROP TABLE IF EXISTS `ai_playerbot_texts_chance`; - -CREATE TABLE IF NOT EXISTS `ai_playerbot_texts_chance` ( - `id` bigint(20) NOT NULL AUTO_INCREMENT, - `name` varchar(255) NOT NULL, - `probability` bigint(20) NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=UTF8; - -/*!40000 ALTER TABLE `ai_playerbot_texts_chance` DISABLE KEYS */; -INSERT INTO `ai_playerbot_texts_chance` (`id`, `name`, `probability`) VALUES - (1, 'taunt', 30), - (2, 'aoe', 75), - (3, 'loot', 20); -/*!40000 ALTER TABLE `ai_playerbot_texts_chance` ENABLE KEYS */; \ No newline at end of file diff --git a/sql/playerbots/base/ai_playerbot_texts_chance.sql b/sql/playerbots/base/ai_playerbot_texts_chance.sql new file mode 100644 index 00000000..81218dba --- /dev/null +++ b/sql/playerbots/base/ai_playerbot_texts_chance.sql @@ -0,0 +1,14 @@ +DROP TABLE IF EXISTS `ai_playerbot_texts_chance`; +CREATE TABLE IF NOT EXISTS `ai_playerbot_texts_chance` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `probability` bigint(20) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=UTF8; + +/*!40000 ALTER TABLE `ai_playerbot_texts_chance` DISABLE KEYS */; +INSERT INTO `ai_playerbot_texts_chance` (`id`, `name`, `probability`) VALUES + (1, 'taunt', 30), + (2, 'aoe', 75), + (3, 'loot', 20); +/*!40000 ALTER TABLE `ai_playerbot_texts_chance` ENABLE KEYS */; From 8d7a7aed2acf1c99409ecc4c5571ed0ebf2ca1cb Mon Sep 17 00:00:00 2001 From: Revision Date: Sat, 19 Oct 2024 03:11:40 +0200 Subject: [PATCH 20/22] Fix a typo --- sql/playerbots/base/ai_playerbot_texts.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/playerbots/base/ai_playerbot_texts.sql b/sql/playerbots/base/ai_playerbot_texts.sql index 718db731..e1c49907 100644 --- a/sql/playerbots/base/ai_playerbot_texts.sql +++ b/sql/playerbots/base/ai_playerbot_texts.sql @@ -464,7 +464,7 @@ INSERT INTO `ai_playerbot_texts` (`name`, `text`, `say_type`, `reply_type`, `tex -- %my_level ('suggest_something', 'Wanna party in %zone_name.', 0, 0, '', 'Je veux faire la fête dans %zone_name.', '', '', '', '¡Vamos a perrear a %zone_name!', '', 'Ищу группу в %zone_name.'), ('suggest_something', 'Anyone is looking for %my_role?', 0, 0, '', 'Quelqu\'un cherche un %my_role ?', '', '', '', '¿Alguien está buscando %my_role?', '', 'Кто-нибудь ищет %my_role?'), -('suggest_something', '%my_role is looking for quild.', 0, 0, '', '%my_role recherche une guilde.', '', '', '', '%my_role está buscando hermandad.', '', '%my_role ищу гильдию.'), +('suggest_something', '%my_role is looking for guild.', 0, 0, '', '%my_role recherche une guilde.', '', '', '', '%my_role está buscando hermandad.', '', '%my_role ищу гильдию.'), ('suggest_something', 'Looking for gold.', 0, 0, '', 'A la recherche de l\'or.', '', '', '', 'Buscando oro.', '', 'Дайте голды'), ('suggest_something', '%my_role wants to join a good guild.', 0, 0, '', '%my_role veut rejoindre une bonne guilde.', '', '', '', '%my_role quiere unirse a una buen hermandad.', '', '%my_role хочу в хорошую гильдию.'), ('suggest_something', 'Need a friend.', 0, 0, '', 'Besoin d\'un ami.', '', '', '', 'Necesito un amigo...', '', 'Ищу друга.'), From 72debb6e8365a8d47c4ac2ebd1a9b5a5b619f16e Mon Sep 17 00:00:00 2001 From: EricksOliveira Date: Sat, 19 Oct 2024 09:55:27 -0300 Subject: [PATCH 21/22] Fix Crash q [ link item ] This PR adds a null pointer check to the ChatHelper::FormatQuest function to avoid a crash that occurred when trying to format a null quest. The crash occurred when the quest pointer was nullptr and the code tried to access the GetQuestId(), GetQuestLevel() and GetTitle() methods. Changes: Added a nullptr check to the beginning of the ChatHelper::FormatQuest function. Return of a standard error message ("Invalid quest") if the quest is null. Impact: Prevents crashes when formatting null quests. Improves bot system stability when dealing with invalid quests. --- src/ChatHelper.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ChatHelper.cpp b/src/ChatHelper.cpp index 8f464d5d..7bd8e590 100644 --- a/src/ChatHelper.cpp +++ b/src/ChatHelper.cpp @@ -304,9 +304,13 @@ ItemIds ChatHelper::parseItems(std::string const text) std::string const ChatHelper::FormatQuest(Quest const* quest) { + if (!quest) + { + return "Invalid quest"; + } + std::ostringstream out; - out << "|cFFFFFF00|Hquest:" << quest->GetQuestId() << ':' << quest->GetQuestLevel() << "|h[" << quest->GetTitle() - << "]|h|r"; + out << "|cFFFFFF00|Hquest:" << quest->GetQuestId() << ':' << quest->GetQuestLevel() << "|h[" << quest->GetTitle() << "]|h|r"; return out.str(); } From 8ac7d5823068e25b411263b5a9697c0f8b00f080 Mon Sep 17 00:00:00 2001 From: EricksOliveira Date: Sat, 19 Oct 2024 14:29:44 -0300 Subject: [PATCH 22/22] Fix Crash The Nexux Log Crash: 00007FF7750C05ED 00000028A47FEA10 FirebombSpreadAction::Execute+1AD E:\Server\Heroes_Azeroth\modules\mod-playerbots\src\strategy\dungeons\wotlk\nexus\NexusActions.cpp line 58 This PR fixes a possible crash in the FirebombSpreadAction::Execute function, located in the NexusActions.cpp file, which occurred due to the lack of checking for null pointers when accessing group members. Main changes: Added a null pointer check to ensure botAI->GetUnit(member) returns a valid unit before calling functions like GetExactDist2d and MoveAway. If botAI->GetUnit(member) returns nullptr, execution ignores the specific member, avoiding access to an invalid pointer that could cause a server crash. --- src/strategy/dungeons/wotlk/nexus/NexusActions.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/strategy/dungeons/wotlk/nexus/NexusActions.cpp b/src/strategy/dungeons/wotlk/nexus/NexusActions.cpp index 1a918614..e494251e 100644 --- a/src/strategy/dungeons/wotlk/nexus/NexusActions.cpp +++ b/src/strategy/dungeons/wotlk/nexus/NexusActions.cpp @@ -54,9 +54,16 @@ bool FirebombSpreadAction::Execute(Event event) { continue; } - if (bot->GetExactDist2d(botAI->GetUnit(member)) < targetDist) + + Unit* unit = botAI->GetUnit(member); + if (!unit) { - return MoveAway(botAI->GetUnit(member), targetDist); + continue; + } + + if (bot->GetExactDist2d(unit) < targetDist) + { + return MoveAway(unit, targetDist); } } return false;