From d7542e2ef642ba3c481e82ddcf59fd42495410da Mon Sep 17 00:00:00 2001 From: bash Date: Mon, 7 Oct 2024 20:34:46 +0000 Subject: [PATCH] Ported cmangos of allowAcitity and prority, removed autoscaled based on latency --- conf/playerbots.conf.dist | 4 - src/PlayerbotAI.cpp | 259 +++++++++++++++++++++++++------------ src/PlayerbotAI.h | 28 +++- src/RandomPlayerbotMgr.cpp | 3 + 4 files changed, 207 insertions(+), 87 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 6da1c7a33..a977beb94 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 68512241e..b597f646b 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. + // real guild always active if member+ + if (IsInRealGuild()) + return ActivePiorityType::PLAYER_GUILD; + + if (bot->IsBeingTeleported() || !bot->IsInWorld() || !HasRealPlayers(bot->GetMap())) + return ActivePiorityType::IN_INACTIVE_MAP; + + // IN_ACTIVE_AREA + if (activityType == OUT_OF_PARTY_ACTIVITY || activityType == GRIND_ACTIVITY) + { + // Many bots nearby. Do not do heavy area checks. if (HasManyPlayersNearby()) - return false; + return ActivePiorityType::IN_ACTIVE_AREA; + } - // Bots don't need to move using PathGenerator. - if (activityType == DETAILED_MOVE_ACTIVITY) - return false; + return ActivePiorityType::IN_ACTIVE_AREA; +} - // 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; +// 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}; +} - uint32 mod = sPlayerbotAIConfig->botActiveAlone > 100 ? 100 : sPlayerbotAIConfig->botActiveAlone; - if (sPlayerbotAIConfig->botActiveAloneAutoScale) +bool PlayerbotAI::AllowActive(ActivityType activityType) +{ + //General exceptions + if (activityType == PACKET_ACTIVITY) + return true; + + ActivePiorityType type = GetPriorityType(activityType); + if (activityType == DETAILED_MOVE_ACTIVITY) { - mod = AutoScaleActivity(mod); + 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; + } } - uint32 ActivityNumber = - GetFixedBotNumer(BotTypeNumber::ACTIVITY_TYPE_NUMBER, 100, - sPlayerbotAIConfig->botActiveAlone * static_cast(mod) / 100 * 0.01f); + // 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); - return ActivityNumber <= - (sPlayerbotAIConfig->botActiveAlone * mod) / - 100; // The given percentage of bots should be active and rotate 1% of those active bots each minute. + // 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 6e82338bd..3b83a5eb8 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 @@ class PlayerbotAI : public PlayerbotAIBase 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/RandomPlayerbotMgr.cpp b/src/RandomPlayerbotMgr.cpp index 7d26a0963..5d3b5edf3 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())