Skip to content

Commit

Permalink
Alt login: Added login criteria based on battleground, arena, instanc…
Browse files Browse the repository at this point in the history
…e and online status
  • Loading branch information
mostlikely4r committed Dec 12, 2024
1 parent ab05467 commit 41be444
Show file tree
Hide file tree
Showing 7 changed files with 206 additions and 94 deletions.
9 changes: 6 additions & 3 deletions playerbot/PlayerbotAIConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ bool PlayerbotAIConfig::Initialize()

loginBotsNearPlayerRange = config.GetIntDefault("AiPlayerbot.LoginBotsNearPlayerRange", 1000);

LoadListString<std::vector<std::string> >(config.GetStringDefault("AiPlayerbot.DefaultLoginCriteria", "maxbots,spareroom,logoff,offline"), defaultLoginCriteria);
LoadListString<std::vector<std::string> >(config.GetStringDefault("AiPlayerbot.DefaultLoginCriteria", "maxbots,spareroom,offline"), defaultLoginCriteria);

std::vector<std::string> criteriaValues = configA->GetValues("AiPlayerbot.LoginCriteria");
for (auto& value : criteriaValues)
Expand All @@ -281,8 +281,11 @@ bool PlayerbotAIConfig::Initialize()

if (criteriaValues.empty())
{
loginCriteria.push_back({"guild"});
loginCriteria.push_back({"classrace,level"});
loginCriteria.push_back({ "group" });
loginCriteria.push_back({ "arena" });
loginCriteria.push_back({ "bg" });
loginCriteria.push_back({ "guild" });
loginCriteria.push_back({ "classrace,level,logoff" });
}


Expand Down
108 changes: 83 additions & 25 deletions playerbot/PlayerbotLoginMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,25 @@ bool PlayerLoginInfo::IsOnPlayerMap(const LoginSpace& space) const
return false;
}

bool PlayerLoginInfo::IsInPlayerGroup(const LoginSpace& space) const
{
if (space.realPlayerInfos.empty())
return true;

if (!groupId)
return false;

for (auto& player : space.realPlayerInfos)
{
if (player.groupId == groupId)
{
return true;
}
}

return false;
}

bool PlayerLoginInfo::IsInPlayerGuild(const LoginSpace& space) const
{
if (space.realPlayerInfos.empty())
Expand All @@ -102,6 +121,21 @@ bool PlayerLoginInfo::IsInPlayerGuild(const LoginSpace& space) const
return false;
}

bool PlayerLoginInfo::IsInBG() const
{
return position.isBg();
}

bool PlayerLoginInfo::IsInArena() const
{
return position.isArena();
}

bool PlayerLoginInfo::IsInInstance() const
{
return !position.isOverworld() && !position.isBg() && position.isArena();
}

bool PlayerLoginInfo::SendHolder()
{
if (holderState == HolderState::HOLDER_SENT)
Expand Down Expand Up @@ -245,6 +279,8 @@ void PlayerLoginInfo::Update(Player* player)
level = player->GetLevel();
position = WorldPosition(player);
isNew = ((level > 1) ? false : (player->GetTotalPlayedTime() == 0));
groupId = player->GetGroup() ? player->GetGroup()->GetId() : 0;
guildId = player->GetGuildId();
}

bool PlayerLoginInfo::LoginBot()
Expand Down Expand Up @@ -333,13 +369,15 @@ T GetFuture(Method&& method, std::future<T>& fut, bool restart, Args&&... args)

void PlayerBotLoginMgr::Update(RealPlayers& realPlayers)
{
UpdateOnlineBots();

if (botPool.empty())
{
botPool = GetFuture(LoadBotsFromDb, futurePool, false);
return;
}

LoginoutQueue queue = GetFuture(FillLoginLogoutQueue, futureQueue, true, &botPool, realPlayers);
BotInfos queue = GetFuture(FillLoginLogoutQueue, futureQueue, true, &botPool, realPlayers);

if (!queue.empty())
{
Expand Down Expand Up @@ -411,7 +449,7 @@ BotPool PlayerBotLoginMgr::LoadBotsFromDb()
return botPool;
}

void PlayerBotLoginMgr::SendHolders(const LoginoutQueue& queue)
void PlayerBotLoginMgr::SendHolders(const BotInfos& queue)
{
CharacterDatabase.AsyncPQuery(&RandomPlayerbotMgr::DatabasePing, sWorld.GetCurrentMSTime(), std::string("CharacterDatabase"), "select 1 from dual");

Expand All @@ -435,7 +473,18 @@ void PlayerBotLoginMgr::SendHolders(BotPool* pool)
}
}

void PlayerBotLoginMgr::UpdateOnlineBots()
{
for (auto& info : onlineBots)
{
Player* player = info->GetPlayer();
if(player)
info->Update(player);
}
}

#define ADD_CRITERIA(type, condition) criteria.push_back(std::make_pair(LoginCriterionFailType::type, []( const PlayerLoginInfo& info, const LoginSpace& space) {return condition;}))
#define ADD_KEEP_CRITERIA(type, condition) criteria.push_back(std::make_pair(LoginCriterionFailType::type, []( const PlayerLoginInfo& info, const LoginSpace& space) {return !(condition);}))

uint32 PlayerBotLoginMgr::GetLoginCriteriaSize()
{
Expand Down Expand Up @@ -475,39 +524,42 @@ std::vector<std::string> PlayerBotLoginMgr::GetVariableLoginCriteria(const uint8
return {};
}


LoginCriteria PlayerBotLoginMgr::GetLoginCriteria(const uint8 attempt)
{
LoginCriteria criteria;

std::vector<std::string> defaultCriteria = sPlayerbotAIConfig.defaultLoginCriteria;
std::vector<std::string> configCriteria = sPlayerbotAIConfig.defaultLoginCriteria;
std::vector<std::string> attemptCriteria = GetVariableLoginCriteria(attempt);
configCriteria.insert(configCriteria.end(), attemptCriteria.begin(), attemptCriteria.end());

for (uint8 i = 0; i < defaultCriteria.size(); i++)
for (auto& criterion : configCriteria)
{
if (defaultCriteria[i] == "maxbots")
if (criterion == "maxbots")
ADD_CRITERIA(MAX_BOTS, space.totalSpace <= int(0));
if (defaultCriteria[i] == "spareroom" && attempt > 0)
if (criterion == "spareroom" && attempt > 0)
ADD_CRITERIA(SPARE_ROOM, space.totalSpace <= (int32)sPlayerbotAIConfig.freeRoomForNonSpareBots);
if (defaultCriteria[i] == "logoff")
ADD_CRITERIA(RANDOM_TIMED_LOGOUT, info.GetLoginState() == LoginState::BOT_ONLINE && !sRandomPlayerbotMgr.GetValue(info.GetId(), "add"));
if (defaultCriteria[i] == "offline")
ADD_CRITERIA(RANDOM_TIMED_OFFLINE, info.GetLoginState() == LoginState::BOT_OFFLINE && sRandomPlayerbotMgr.GetValue(info.GetId(), "logout"));
}

std::vector<std::string> configCriteria = GetVariableLoginCriteria(attempt);

for (auto& criterion : configCriteria)
{
if (criterion == "online")
ADD_KEEP_CRITERIA(ONLINE, info.IsOnline());
if (criterion == "logoff" && sPlayerbotAIConfig.randomBotTimedLogout)
ADD_CRITERIA(RANDOM_TIMED_LOGOUT, info.IsOnline() && !sRandomPlayerbotMgr.GetValue(info.GetId(), "add"));
if (criterion == "offline" && sPlayerbotAIConfig.randomBotTimedOffline)
ADD_CRITERIA(RANDOM_TIMED_OFFLINE, !info.IsOnline() && sRandomPlayerbotMgr.GetValue(info.GetId(), "logout"));
if (criterion == "bg")
ADD_KEEP_CRITERIA(BG, info.IsOnline() && info.IsInBG());
if (criterion == "arena")
ADD_KEEP_CRITERIA(ARENA, info.IsOnline() && info.IsInArena());
if (criterion == "instance")
ADD_KEEP_CRITERIA(INSTANCE, info.IsOnline() && info.IsInInstance());
if (criterion == "classrace")
ADD_CRITERIA(CLASSRACE, space.classRaceBucket[info.GetClass()][info.GetRace()] <= 0);
if (criterion == "level")
ADD_CRITERIA(LEVEL, space.levelBucket[info.GetLevel()] <= 0);
if (criterion == "range")
ADD_CRITERIA(RANGE, !info.IsNearPlayer(space));
ADD_KEEP_CRITERIA(RANGE, info.IsNearPlayer(space));
if (criterion == "map")
ADD_CRITERIA(MAP, !info.IsOnPlayerMap(space));
ADD_KEEP_CRITERIA(MAP, info.IsOnPlayerMap(space));
if (criterion == "guild")
ADD_CRITERIA(GUILD, !info.IsInPlayerGuild(space));
ADD_KEEP_CRITERIA(GUILD, info.IsInPlayerGuild(space));
}

return criteria;
Expand Down Expand Up @@ -568,7 +620,7 @@ bool PlayerBotLoginMgr::CriteriaStillValid(const LoginCriterionFailType oldFailT
return false;
}

LoginoutQueue PlayerBotLoginMgr::FillLoginLogoutQueue(BotPool* pool, const RealPlayers& realPlayers)
BotInfos PlayerBotLoginMgr::FillLoginLogoutQueue(BotPool* pool, const RealPlayers& realPlayers)
{
LoginSpace loginSpace;
loginSpace.realPlayerInfos = GetPlayerInfos(realPlayers);
Expand Down Expand Up @@ -614,7 +666,7 @@ LoginoutQueue PlayerBotLoginMgr::FillLoginLogoutQueue(BotPool* pool, const RealP
break;
}

LoginoutQueue queue;
BotInfos queue;
uint32 logins = 0;

for (auto& info : potentialQueue)
Expand Down Expand Up @@ -656,12 +708,18 @@ LoginoutQueue PlayerBotLoginMgr::FillLoginLogoutQueue(BotPool* pool, const RealP
return queue;
}

void PlayerBotLoginMgr::LoginLogoutBots(const LoginoutQueue& queue) const
void PlayerBotLoginMgr::LoginLogoutBots(const BotInfos& queue)
{
for (auto& info : queue)
{
info->LoginBot();
info->LogoutBot();
if (info->LoginBot())
{
onlineBots.push_back(info);
}
if (info->LogoutBot())
{
onlineBots.erase(std::remove(onlineBots.begin(), onlineBots.end(), info), onlineBots.end());
}
}
}

Expand Down
46 changes: 31 additions & 15 deletions playerbot/PlayerbotLoginMgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class PlayerLoginInfo;

typedef std::map<uint32, PlayerLoginInfo> BotPool;
typedef std::vector<PlayerLoginInfo> RealPlayerInfos;
typedef std::vector<PlayerLoginInfo*> LoginoutQueue;
typedef std::vector<PlayerLoginInfo*> BotInfos;

struct LoginSpace
{
Expand Down Expand Up @@ -42,29 +42,37 @@ enum class FillStep : uint8
enum class LoginCriterionFailType : uint8
{
UNKNOWN = 0,
MAX_BOTS = 2,
SPARE_ROOM = 3,
RANDOM_TIMED_LOGOUT = 4,
RANDOM_TIMED_OFFLINE = 5,
CLASSRACE = 6,
LEVEL = 7,
RANGE = 8,
MAP = 9,
GUILD = 10,
LOGIN_OK = 11
MAX_BOTS = 1,
SPARE_ROOM,
ONLINE,
RANDOM_TIMED_LOGOUT,
RANDOM_TIMED_OFFLINE,
CLASSRACE,
LEVEL,
RANGE,
MAP,
GUILD,
BG,
ARENA,
INSTANCE,
LOGIN_OK
};

static const std::unordered_map<LoginCriterionFailType, std::string> failName = {
{LoginCriterionFailType::UNKNOWN, "UNKNOWN"}
,{LoginCriterionFailType::MAX_BOTS, "MAX_BOTS"}
,{LoginCriterionFailType::SPARE_ROOM, "SPARE_ROOM"}
,{LoginCriterionFailType::ONLINE, "ONLINE"}
,{LoginCriterionFailType::RANDOM_TIMED_LOGOUT, "RANDOM_TIMED_LOGOUT"}
,{LoginCriterionFailType::RANDOM_TIMED_OFFLINE , "RANDOM_TIMED_OFFLINE"}
,{LoginCriterionFailType::CLASSRACE, "CLASSRACE"}
,{LoginCriterionFailType::LEVEL, "LEVEL"}
,{LoginCriterionFailType::RANGE , "RANGE"}
,{LoginCriterionFailType::MAP , "MAP"}
,{LoginCriterionFailType::GUILD , "GUILD"}
,{LoginCriterionFailType::BG , "BG"}
,{LoginCriterionFailType::ARENA , "ARENA"}
,{LoginCriterionFailType::INSTANCE , "INSTANCE"}
,{LoginCriterionFailType::LOGIN_OK, "LOGIN_OK"} };

typedef std::vector <std::pair<LoginCriterionFailType, std::function<bool(const PlayerLoginInfo&, const LoginSpace&)>>> LoginCriteria;
Expand All @@ -84,7 +92,12 @@ class PlayerLoginInfo
Player* GetPlayer() const { return sObjectMgr.GetPlayer(ObjectGuid(HIGHGUID_PLAYER, guid), false); }
bool IsNearPlayer(const LoginSpace& space) const;
bool IsOnPlayerMap(const LoginSpace& space) const;
bool IsInPlayerGroup(const LoginSpace& space) const;
bool IsInPlayerGuild(const LoginSpace& space) const;
bool IsInBG() const;
bool IsInArena() const;
bool IsInInstance() const;
bool IsOnline() const { return loginState == LoginState::BOT_ONLINE || loginState == LoginState::BOT_ON_LOGOUTQUEUE; }
LoginState GetLoginState() const { return loginState; }

bool SendHolder();
Expand All @@ -111,6 +124,7 @@ class PlayerLoginInfo
uint32 level;
bool isNew = false;
WorldPosition position;
uint32 groupId;
uint32 guildId;

SqlQueryHolder* holder = nullptr;
Expand All @@ -125,8 +139,9 @@ class PlayerBotLoginMgr

private:
static BotPool LoadBotsFromDb();
static LoginoutQueue FillLoginLogoutQueue(BotPool* pool, const RealPlayers& realPlayers);
void LoginLogoutBots(const LoginoutQueue& queue) const;
void UpdateOnlineBots();
static BotInfos FillLoginLogoutQueue(BotPool* pool, const RealPlayers& realPlayers);
void LoginLogoutBots(const BotInfos& queue);

static RealPlayerInfos GetPlayerInfos(const RealPlayers& realPlayers);
static uint32 GetLoginCriteriaSize();
Expand All @@ -140,12 +155,13 @@ class PlayerBotLoginMgr
static uint32 GetLevelBucketSize(uint32 level);
static void FillLoginSpace(BotPool* pool, LoginSpace& space, FillStep step);

static void SendHolders(const LoginoutQueue& queue);
static void SendHolders(const BotInfos& queue);
static void SendHolders(BotPool* pool);

std::future<LoginoutQueue> futureQueue;
std::future<BotInfos> futureQueue;
std::future<BotPool> futurePool;

BotInfos onlineBots;
BotPool botPool;
};

Expand Down
2 changes: 2 additions & 0 deletions playerbot/WorldPosition.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ namespace ai
void printWKT(std::ostringstream& out) const { printWKT({ *this }, out); }

bool isOverworld() const { return mapid == 0 || mapid == 1 || mapid == 530 || mapid == 571; }
bool isBg() const { return mapid == 30 || mapid == 489 || mapid == 529 || mapid == 566 || mapid == 607 || mapid == 628; }
bool isArena() const { return mapid == 559 || mapid == 572 || mapid == 562 || mapid == 617 || mapid == 618; }
bool isInWater() const { return getTerrain() ? getTerrain()->IsInWater(coord_x, coord_y, coord_z) : false; };
bool isUnderWater() const { return getTerrain() ? getTerrain()->IsUnderWater(coord_x, coord_y, coord_z) : false; };

Expand Down
45 changes: 28 additions & 17 deletions playerbot/aiplayerbot.conf.dist.in
Original file line number Diff line number Diff line change
Expand Up @@ -990,24 +990,35 @@ AiPlayerbot.PerfMonEnabled = 0
# !!warning heavy db usage at start!!
# AiPlayerbot.PreloadHolders = 0

# The login criteria to apply when trying to log in bots. options:
# maxbots: Login bots trying to stay under the current maximum bot count.
# spareroom: Login bots trying to keep spare room for better bots.
# logoff: Login bots that are not slated to log off after being online for a configured amount of time.
# offline: Login bots that are not slated to stay offline for a configured amount of time.
# classrace: Login bots prefering to stick to class/race probabilities.
# level: Login bots prefering to stick to level probabilities.
# range: Login bots prefering to only log in bots inside the near player range.
# map: Login bots trying to find bots on the same map as players.
# guild: Login bots trying to find bots in the guild of online players.
# The login criteria to apply when trying to log in/keep online bots. options:
# maxbots: Keep the total number of bots below the maxium (between max/min).
# spareroom: Keep some spare room below the max to login better bots.
# bg: Bots online inside battlegrounds should not log off.
# arena: Bots online inside arenas should not log off.
# instance: Bots online inside instances should not log off.
# online: Bots currently online stay online.
# logoff: Bots slated to logoff should log off. (Needs RandomBotTimedLogout)
# offline: Bots slated to stay offline should stay offline. (Needs RandomBotTimedOffline)
# classrace: Match the online bots to the configured class/race probabilities.
# level: Match the online bots to the configured level probabilities.
# range: Prefer bots near an online player.
# map: Prefer bots on the same map of an online player.
# group: Prefer bots in the same group as an online player.
# guild: Prefer bots in the same guild as an online player.
#
# How it works: Default criteria are always applied only bots must match all to login.
# After this only bots matching 'all' criteria of the first line are logged in.
# If there is still room 1 criteria of line 1 is dropped broadening the range allowing more bots in.
# After only the last criteria of line 1 is tried it will move to all criteria of line 2. And so on.
# AiPlayerbot.DefaultLoginCriteria1 = maxbots,spareroom,logoff,offline
# AiPlayerbot.LoginCriteria.1 = guild
# AiPlayerbot.LoginCriteria.2 = classrace,level
# How it works: All bots are evaluated based on configurd criteria wether they should be online of offline.
# The default criteria must all be true or the bot will be logged off and can not log in.
# Each line works as an AND construction where the back criteria are dropped to find more bots to log in.
# Example classrace,level means it tries to find all bots to properly maintain the level and classrace probabilties and if it needs more bots it only looks at classrace.
# The multiple lines work as an OR construction where the top lines are used first and as more bots are needed it moves down.
# Example 1 = group, 2 = bg. First it tries to login all bots in player groups, then as more bots are needed it looks for bots that might be online inside battlegrounds.
#
# AiPlayerbot.DefaultLoginCriteria1 = maxbots,spareroom,offline
# AiPlayerbot.LoginCriteria.1 = group
# AiPlayerbot.LoginCriteria.2 = bg
# AiPlayerbot.LoginCriteria.3 = arena
# AiPlayerbot.LoginCriteria.4 = guild
# AiPlayerbot.LoginCriteria.5 = classrace,level,logoff

# When bots are logged in that do not fully match all criteria selected it will do so up to xxx spaces below the maximum. Bots that suddenly match all the criteria will then have room to use this to log in.
# AiPlayerbot.FreeRoomForNonSpareBots = 0
Expand Down
Loading

0 comments on commit 41be444

Please sign in to comment.