Improve login and init permission for rndbots and addclass bots (#930)

* Improve login and init permission for rndbots and addclass-bots

* Add AllowAcountBots config

* Update config description
This commit is contained in:
Yunfan Li
2025-02-03 19:46:49 +08:00
committed by GitHub
parent f5a8b3017e
commit fef67081ec
5 changed files with 95 additions and 103 deletions

View File

@@ -107,12 +107,9 @@ AiPlayerbot.DeleteRandomBotAccounts = 0
#
#
# Maximum number of bots added by one account
# The maximum number of bots that a player can control simultaneously
AiPlayerbot.MaxAddedBots = 40
# Maximum number of bots per class added by one account
AiPlayerbot.MaxAddedBotsPerClass = 40
# Enable/Disable create bot by addclass command (0 = GM only, 1 = enable)
# default: 1 (enable)
AiPlayerbot.AddClassCommand = 1
@@ -128,11 +125,10 @@ AiPlayerbot.GroupInvitationPermission = 1
# auto-login all player alts as bots on player login
AiPlayerbot.BotAutologin = 0
# Allow login other players' characters as bots
# Default: 0 (disabled)
AiPlayerbot.AllowPlayerBots = 0
# Allow/deny bots from the player's account
AiPlayerbot.AllowAccountBots = 1
# Allow/deny bots from your guild
# Allow/deny bots in the player's guild
AiPlayerbot.AllowGuildBots = 1
# Randombots will invite nearby bots to guilds
@@ -860,8 +856,8 @@ AiPlayerbot.FastReactInBG = 1
AiPlayerbot.RandomBotUpdateInterval = 20
AiPlayerbot.RandomBotCountChangeMinInterval = 1800
AiPlayerbot.RandomBotCountChangeMaxInterval = 7200
AiPlayerbot.MinRandomBotInWorldTime = 3600
AiPlayerbot.MaxRandomBotInWorldTime = 1209600
AiPlayerbot.MinRandomBotInWorldTime = 600
AiPlayerbot.MaxRandomBotInWorldTime = 28800
AiPlayerbot.MinRandomBotRandomizeTime = 7200
AiPlayerbot.MaxRandomBotRandomizeTime = 1209600
AiPlayerbot.RandomBotsPerInterval = 60

View File

@@ -125,11 +125,11 @@ bool PlayerbotAIConfig::Initialize()
iterationsPerTick = sConfigMgr->GetOption<int32>("AiPlayerbot.IterationsPerTick", 100);
allowAccountBots = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowAccountBots", true);
allowGuildBots = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowGuildBots", true);
randomBotGuildNearby = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotGuildNearby", false);
randomBotInvitePlayer = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotInvitePlayer", false);
inviteChat = sConfigMgr->GetOption<bool>("AiPlayerbot.InviteChat", false);
allowPlayerBots = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowPlayerBots", false);
randomBotMapsAsString = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotMaps", "0,1,530,571");
LoadList<std::vector<uint32>>(randomBotMapsAsString, randomBotMaps);
@@ -329,9 +329,7 @@ bool PlayerbotAIConfig::Initialize()
useFlyMountAtMinLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.UseFlyMountAtMinLevel", 60);
useFastFlyMountAtMinLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.UseFastFlyMountAtMinLevel", 70);
LOG_INFO("server.loading", "---------------------------------------");
LOG_INFO("server.loading", " Loading TalentSpecs ");
LOG_INFO("server.loading", "---------------------------------------");
LOG_INFO("server.loading", "Loading TalentSpecs...");
for (uint32 cls = 1; cls < MAX_CLASSES; ++cls)
{
@@ -474,7 +472,6 @@ bool PlayerbotAIConfig::Initialize()
autoInitEquipLevelLimitRatio = sConfigMgr->GetOption<float>("AiPlayerbot.AutoInitEquipLevelLimitRatio", 1.0);
maxAddedBots = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxAddedBots", 40);
maxAddedBotsPerClass = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxAddedBotsPerClass", 10);
addClassCommand = sConfigMgr->GetOption<int32>("AiPlayerbot.AddClassCommand", 1);
addClassAccountPoolSize = sConfigMgr->GetOption<int32>("AiPlayerbot.AddClassAccountPoolSize", 50);
maintenanceCommand = sConfigMgr->GetOption<int32>("AiPlayerbot.MaintenanceCommand", 1);

View File

@@ -54,7 +54,7 @@ public:
bool IsInPvpProhibitedArea(uint32 id);
bool enabled;
bool allowGuildBots, allowPlayerBots;
bool allowAccountBots, allowGuildBots;
bool randomBotGuildNearby, randomBotInvitePlayer, inviteChat;
uint32 globalCoolDown, reactDelay, maxWaitForMove, disableMoveSplinePath, maxMovementSearchTime, expireActionTime,
dispelAuraDuration, passiveDelay, repeatDelay, errorDelay, rpgDelay, sitDelay, returnDelay, lootDelay;
@@ -334,7 +334,7 @@ public:
bool botRepairWhenSummon;
bool autoInitOnly;
float autoInitEquipLevelLimitRatio;
int32 maxAddedBots, maxAddedBotsPerClass;
int32 maxAddedBots;
int32 addClassCommand;
int32 addClassAccountPoolSize;
int32 maintenanceCommand;

View File

@@ -17,6 +17,7 @@
#include "Define.h"
#include "Group.h"
#include "GroupMgr.h"
#include "GuildMgr.h"
#include "ObjectAccessor.h"
#include "ObjectGuid.h"
#include "ObjectMgr.h"
@@ -37,18 +38,18 @@ class PlayerbotLoginQueryHolder : public LoginQueryHolder
private:
uint32 masterAccountId;
PlayerbotHolder* playerbotHolder;
public:
PlayerbotLoginQueryHolder(PlayerbotHolder* playerbotHolder, uint32 masterAccount, uint32 accountId, ObjectGuid guid)
: LoginQueryHolder(accountId, guid), masterAccountId(masterAccount), playerbotHolder(playerbotHolder)
PlayerbotLoginQueryHolder(PlayerbotHolder* playerbotHolder, uint32 masterAccount, uint32 accountId, ObjectGuid guid, bool byAddClass)
: LoginQueryHolder(accountId, guid), masterAccountId(masterAccount), playerbotHolder(playerbotHolder), byAddClass(byAddClass)
{
}
uint32 GetMasterAccountId() const { return masterAccountId; }
PlayerbotHolder* GetPlayerbotHolder() { return playerbotHolder; }
bool byAddClass;
};
void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId)
void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId, bool byAddClass)
{
// bot is loading
if (botLoading.find(playerGuid) != botLoading.end())
@@ -62,9 +63,50 @@ void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId
uint32 accountId = sCharacterCache->GetCharacterAccountIdByGuid(playerGuid);
if (!accountId)
return;
WorldSession* masterSession = masterAccountId ? sWorld->FindSession(masterAccountId) : nullptr;
Player* masterPlayer = masterSession ? masterSession->GetPlayer() : nullptr;
bool isRndbot = !masterAccountId;
bool sameAccount = sPlayerbotAIConfig->allowAccountBots && accountId == masterAccountId;
Guild* guild = masterPlayer ? sGuildMgr->GetGuildById(masterPlayer->GetGuildId()) : nullptr;
bool sameGuild = sPlayerbotAIConfig->allowGuildBots && guild && guild->GetMember(playerGuid);
bool allowed = true;
std::ostringstream out;
std::string botName;
sCharacterCache->GetCharacterNameByGuid(playerGuid, botName);
if (!isRndbot && !sameAccount && !sameGuild && !byAddClass)
{
allowed = false;
out << "Failure: You are not allowed to control bot " << botName.c_str();
}
if (masterAccountId && masterPlayer)
{
PlayerbotMgr* mgr = GET_PLAYERBOT_MGR(masterPlayer);
if (!mgr)
{
LOG_DEBUG("playerbots", "PlayerbotMgr not found for master player with GUID: {}", masterPlayer->GetGUID().GetRawValue());
return;
}
uint32 count = mgr->GetPlayerbotsCount();
if (count >= sPlayerbotAIConfig->maxAddedBots)
{
allowed = false;
out << "Failure: You have added too many bots (more than " << sPlayerbotAIConfig->maxAddedBots << ")";
}
}
if (!allowed)
{
if (masterSession)
{
ChatHandler ch(masterSession);
ch.SendSysMessage(out.str());
}
return;
}
std::shared_ptr<PlayerbotLoginQueryHolder> holder =
std::make_shared<PlayerbotLoginQueryHolder>(this, masterAccountId, accountId, playerGuid);
std::make_shared<PlayerbotLoginQueryHolder>(this, masterAccountId, accountId, playerGuid, byAddClass);
if (!holder->Initialize())
{
return;
@@ -89,7 +131,7 @@ void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId
void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder const& holder)
{
uint32 botAccountId = holder.GetAccountId();
bool byAddClass = holder.byAddClass;
// At login DBC locale should be what the server is set to use by default (as spells etc are hardcoded to ENUS this
// allows channels to work as intended)
WorldSession* botSession = new WorldSession(botAccountId, "", nullptr, SEC_PLAYER, EXPANSION_WRATH_OF_THE_LICH_KING,
@@ -117,65 +159,10 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con
{
LOG_DEBUG("mod-playerbots", "Master session found but no player is associated for master account ID: {}", masterAccount);
}
std::ostringstream out;
bool allowed = false;
if (botAccountId == masterAccount)
{
allowed = true;
}
else if (masterSession && sPlayerbotAIConfig->allowGuildBots && bot->GetGuildId() != 0 &&
bot->GetGuildId() == masterPlayer->GetGuildId())
{
allowed = true;
}
else if (sPlayerbotAIConfig->IsInRandomAccountList(botAccountId))
{
allowed = true;
}
else
{
allowed = false;
out << "Failure: You are not allowed to control bot " << bot->GetName().c_str();
}
if (allowed && masterSession && masterPlayer)
{
PlayerbotMgr* mgr = GET_PLAYERBOT_MGR(masterPlayer);
if (!mgr)
{
LOG_DEBUG("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)
{
allowed = false;
out << "Failure: You have added too many bots";
}
else if (cls_count >= sPlayerbotAIConfig->maxAddedBotsPerClass)
{
allowed = false;
out << "Failure: You have added too many bots for this class";
}
}
if (allowed)
{
sRandomPlayerbotMgr->OnPlayerLogin(bot);
OnBotLogin(bot);
}
else
{
if (masterSession)
{
ChatHandler ch(masterSession);
ch.SendSysMessage(out.str());
}
botSession->LogoutPlayer(true);
delete botSession;
}
sRandomPlayerbotMgr->OnPlayerLogin(bot);
OnBotLogin(bot, byAddClass);
botLoading.erase(holder.GetGuid());
}
@@ -352,7 +339,7 @@ void PlayerbotHolder::LogoutPlayerBot(ObjectGuid guid)
botWorldSessionPtr->HandleLogoutRequestOpcode(data);
if (!bot)
{
playerBots.erase(guid);
RemoveFromPlayerbotsMap(guid);
delete botWorldSessionPtr;
if (target)
delete target;
@@ -361,7 +348,7 @@ void PlayerbotHolder::LogoutPlayerBot(ObjectGuid guid)
}
else
{
playerBots.erase(guid); // deletes bot player ptr inside this WorldSession PlayerBotMap
RemoveFromPlayerbotsMap(guid); // deletes bot player ptr inside this WorldSession PlayerBotMap
delete botWorldSessionPtr; // finally delete the bot's WorldSession
if (target)
delete target;
@@ -371,7 +358,7 @@ void PlayerbotHolder::LogoutPlayerBot(ObjectGuid guid)
else if (bot && (logout || !botWorldSessionPtr->isLogingOut()))
{
botAI->TellMaster("Goodbye!");
playerBots.erase(guid); // deletes bot player ptr inside this WorldSession PlayerBotMap
RemoveFromPlayerbotsMap(guid); // deletes bot player ptr inside this WorldSession PlayerBotMap
botWorldSessionPtr->LogoutPlayer(true); // this will delete the bot Player object and PlayerbotAI object
delete botWorldSessionPtr; // finally delete the bot's WorldSession
}
@@ -408,12 +395,19 @@ void PlayerbotHolder::DisablePlayerBot(ObjectGuid guid)
delete target;
}
playerBots.erase(guid); // deletes bot player ptr inside this WorldSession PlayerBotMap
RemoveFromPlayerbotsMap(guid); // deletes bot player ptr inside this WorldSession PlayerBotMap
delete botAI;
}
}
void PlayerbotHolder::RemoveFromPlayerbotsMap(ObjectGuid guid)
{
playerBots.erase(guid);
if (addClassBots.find(guid) != addClassBots.end())
addClassBots.erase(guid);
}
Player* PlayerbotHolder::GetPlayerBot(ObjectGuid playerGuid) const
{
PlayerBotMap::const_iterator it = playerBots.find(playerGuid);
@@ -427,7 +421,7 @@ Player* PlayerbotHolder::GetPlayerBot(ObjectGuid::LowType lowGuid) const
return (it == playerBots.end()) ? 0 : it->second;
}
void PlayerbotHolder::OnBotLogin(Player* const bot)
void PlayerbotHolder::OnBotLogin(Player* const bot, bool byAddClass)
{
// Prevent duplicate login
if (playerBots.find(bot->GetGUID()) != playerBots.end())
@@ -437,6 +431,9 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
sPlayerbotsMgr->AddPlayerbotData(bot, true);
playerBots[bot->GetGUID()] = bot;
if (byAddClass)
addClassBots.insert(bot->GetGUID());
OnBotLoginInternal(bot);
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
@@ -560,7 +557,7 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
}
bot->SaveToDB(false, false);
if (master && isRandomAccount && master->GetLevel() < bot->GetLevel())
if (byAddClass && master && isRandomAccount && master->GetLevel() < bot->GetLevel())
{
// PlayerbotFactory factory(bot, master->GetLevel());
// factory.Randomize(false);
@@ -647,22 +644,11 @@ std::string const PlayerbotHolder::ProcessBotCommand(std::string const cmd, Obje
bool isRandomAccount = sPlayerbotAIConfig->IsInRandomAccountList(botAccount);
bool isMasterAccount = (masterAccountId == botAccount);
if (!isRandomAccount && !isMasterAccount && !admin && masterguid)
{
Player* master = ObjectAccessor::FindConnectedPlayer(masterguid);
if (master && (!sPlayerbotAIConfig->allowGuildBots || !masterGuildId ||
(masterGuildId && sCharacterCache->GetCharacterGuildIdByGuid(guid) != masterGuildId)))
return "not in your guild or account";
}
if (cmd == "add" || cmd == "login")
{
if (ObjectAccessor::FindPlayer(guid))
return "player already logged in";
if (!sPlayerbotAIConfig->allowPlayerBots && !isRandomAccount && !isMasterAccount)
return "You cannot login another player's character as bot.";
AddPlayerBot(guid, masterAccountId);
return "ok";
}
@@ -686,12 +672,23 @@ std::string const PlayerbotHolder::ProcessBotCommand(std::string const cmd, Obje
if (!bot)
return "bot not found";
bool addClassBot = true;
if (!isRandomAccount || isRandomBot)
{
return "ERROR: You can not use this command on non-summoned random bot.";
addClassBot = false;
}
if (Player* master = GET_PLAYERBOT_AI(bot)->GetMaster())
{
PlayerbotMgr* masterMgr = GET_PLAYERBOT_MGR(master);
if (masterMgr && masterMgr->addClassBots.find(guid) == masterMgr->addClassBots.end())
addClassBot = false;
}
if (!addClassBot)
return "ERROR: You can not use this command on non-addclass random bot.";
if (!admin)
{
Player* master = ObjectAccessor::FindConnectedPlayer(masterguid);
@@ -1077,7 +1074,7 @@ std::vector<std::string> PlayerbotHolder::HandlePlayerbotCommand(char const* arg
continue;
if (ObjectAccessor::FindConnectedPlayer(guid))
continue;
AddPlayerBot(guid, master->GetSession()->GetAccountId());
AddPlayerBot(guid, master->GetSession()->GetAccountId(), true);
messages.push_back("Add class " + std::string(charname));
return messages;
}

View File

@@ -27,11 +27,12 @@ public:
PlayerbotHolder();
virtual ~PlayerbotHolder(){};
void AddPlayerBot(ObjectGuid guid, uint32 masterAccountId);
void AddPlayerBot(ObjectGuid guid, uint32 masterAccountId, bool byAddClass = false);
void HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder const& holder);
void LogoutPlayerBot(ObjectGuid guid);
void DisablePlayerBot(ObjectGuid guid);
void RemoveFromPlayerbotsMap(ObjectGuid guid);
Player* GetPlayerBot(ObjectGuid guid) const;
Player* GetPlayerBot(ObjectGuid::LowType lowGuid) const;
PlayerBotMap::const_iterator GetPlayerBotsBegin() const { return playerBots.begin(); }
@@ -42,7 +43,7 @@ public:
void HandleBotPackets(WorldSession* session);
void LogoutAllBots();
void OnBotLogin(Player* const bot);
void OnBotLogin(Player* const bot, bool byAddClass = false);
std::vector<std::string> HandlePlayerbotCommand(char const* args, Player* master = nullptr);
std::string const ProcessBotCommand(std::string const cmd, ObjectGuid guid, ObjectGuid masterguid, bool admin,
@@ -58,6 +59,7 @@ protected:
virtual void OnBotLoginInternal(Player* const bot) = 0;
PlayerBotMap playerBots;
std::unordered_set<ObjectGuid> addClassBots;
std::unordered_set<ObjectGuid> botLoading;
};