Skip to content

Commit

Permalink
added priority allow acitivty, modified scaling, and increased interval
Browse files Browse the repository at this point in the history
  • Loading branch information
hermensbas committed Oct 6, 2024
1 parent 2695b33 commit e077844
Show file tree
Hide file tree
Showing 3 changed files with 225 additions and 66 deletions.
261 changes: 197 additions & 64 deletions src/PlayerbotAI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4075,18 +4075,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)
Expand All @@ -4102,19 +4099,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)
Expand All @@ -4124,62 +4142,166 @@ bool PlayerbotAI::AllowActive(ActivityType activityType)
isLFG = true;
}
}

if (sLFGMgr->GetState(bot->GetGUID()) != lfg::LFG_STATE_NONE)
{
isLFG = true;
}

if (isLFG)
return true;

if (activityType != OUT_OF_PARTY_ACTIVITY && activityType != PACKET_ACTIVITY) // Is in combat. Defend yourself.
if (bot->IsInCombat())
return true;
return ActivePiorityType::IN_LFG;

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;
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, all bots in this bracket will be
// active above 20% activityMod and scale between those values.
std::pair<uint32, uint32> 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};
}

// Bots don't need to move using PathGenerator.

bool PlayerbotAI::AllowActive(ActivityType activityType)
{
//General exceptions
if (activityType == PACKET_ACTIVITY)
return true;

ActivePiorityType type = GetPriorityType(activityType);
if (activityType == DETAILED_MOVE_ACTIVITY)
return false;
{
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;
}
}

std::pair<uint8, uint8> priorityBracket = GetPriorityBracket(type);
float activityPercentage = sRandomPlayerbotMgr->getActivityPercentage(); // Activity between 0 and 100.
if (!priorityBracket.second) // No scaling
return true;

// 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)
if (priorityBracket.first >= activityPercentage)
return false;
if (priorityBracket.second <= activityPercentage && priorityBracket.second < 100)
return true;

uint32 mod = sPlayerbotAIConfig->botActiveAlone > 100 ? 100 : sPlayerbotAIConfig->botActiveAlone;
if (sPlayerbotAIConfig->botActiveAloneAutoScale)
float activePerc = (activityPercentage - priorityBracket.first) / (priorityBracket.second - priorityBracket.first);
activePerc *= (priorityBracket.second == 100) ? sPlayerbotAIConfig->botActiveAlone : 100;
if (sPlayerbotAIConfig->botActiveAloneAutoScale)
{
mod = AutoScaleActivity(mod);
activePerc *= AutoScaleActivity(activePerc);
}

uint32 ActivityNumber =
GetFixedBotNumer(BotTypeNumber::ACTIVITY_TYPE_NUMBER, 100,
sPlayerbotAIConfig->botActiveAlone * static_cast<float>(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);

return ActivityNumber <=
(sPlayerbotAIConfig->botActiveAlone * 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)
Expand All @@ -4196,27 +4318,38 @@ bool PlayerbotAI::AllowActivity(ActivityType activityType, bool checkNow)
return allowed;
}

// this mechanism helps preventing a backpressure of the mapUpdater workerThread,
// where the worker thread recieves more requests then i can process and more
// request are queued in the memory. As result the memory keeps footprint
// keeps growing and bot actions are out of sync with the world due late processing.
uint32 PlayerbotAI::AutoScaleActivity(uint32 mod)
{
uint32 maxDiff = sWorldUpdateTime.GetAverageUpdateTime();

uint32 maxDiff = sWorldUpdateTime.GetPercentile(95);
if (maxDiff > 500) return 0;
if (maxDiff > 250)

if (Map* map = bot->GetMap())
{
if (Map* map = bot->GetMap())
{
if (map->GetEntry()->IsWorldMap() &&
(!HasRealPlayers(map) ||
if (map->GetEntry()->IsWorldMap() &&
(!HasRealPlayers(map) ||
!map->IsGridLoaded(bot->GetPositionX(), bot->GetPositionY())))
return 0;
}
{
if (maxDiff > 90) return 0;
if (maxDiff > 60) return (mod * 1) / 10;
if (maxDiff > 30) return (mod * 2) / 10;

return (mod * 1) / 10;
return (mod * 3) / 10;
}
else
{
if (maxDiff > 180) return (mod * 1) / 10;
if (maxDiff > 160) return (mod * 2) / 10;
if (maxDiff > 120) return (mod * 3) / 10;
if (maxDiff > 90) return (mod * 4) / 10;
if (maxDiff > 60) return (mod * 5) / 10;
if (maxDiff > 30) return (mod * 6) / 10;
if (maxDiff > 20) return (mod * 9) / 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;
}
Expand Down
27 changes: 25 additions & 2 deletions src/PlayerbotAI.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
};

Expand Down Expand Up @@ -525,6 +546,8 @@ 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<uint32, uint32> GetPriorityBracket(ActivePiorityType type);
bool AllowActive(ActivityType activityType);
bool AllowActivity(ActivityType activityType = ALL_ACTIVITY, bool checkNow = false);
uint32 AutoScaleActivity(uint32 mod);
Expand Down
3 changes: 3 additions & 0 deletions src/RandomPlayerbotMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down

0 comments on commit e077844

Please sign in to comment.