mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
[Large server fix] #1537 Serialize playerBots/botLoading with a mutex and use snapshot-based loops to fix concurrency crashes (#1540)
* MoveSplineInitArgs::Validate: expression 'velocity > 0.01f' failed for GUID Full * Update BotMovementUtils.h * Playerbots: guard against invalid-Z teleports * Update PlayerbotMgr.cpp
This commit is contained in:
@@ -41,6 +41,10 @@
|
|||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include <shared_mutex> // removes a long-standing crash (0xC0000005 ACCESS_VIOLATION)
|
#include <shared_mutex> // removes a long-standing crash (0xC0000005 ACCESS_VIOLATION)
|
||||||
#include "TravelMgr.h"
|
#include "TravelMgr.h"
|
||||||
|
#include <mutex>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
static std::mutex g_botMapsMx; // protect playerBots and botLoading
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// [Crash fix] Centralize clearing of pointer values in the AI context
|
// [Crash fix] Centralize clearing of pointer values in the AI context
|
||||||
@@ -105,9 +109,16 @@ public:
|
|||||||
|
|
||||||
void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId)
|
void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId)
|
||||||
{
|
{
|
||||||
// bot is loading
|
/*// bot is loading
|
||||||
if (botLoading.find(playerGuid) != botLoading.end())
|
if (botLoading.find(playerGuid) != botLoading.end())
|
||||||
return;
|
return;*/
|
||||||
|
|
||||||
|
// bot is loading (protégé)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(g_botMapsMx);
|
||||||
|
if (botLoading.find(playerGuid) != botLoading.end())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// has bot already been added?
|
// has bot already been added?
|
||||||
Player* bot = ObjectAccessor::FindConnectedPlayer(playerGuid);
|
Player* bot = ObjectAccessor::FindConnectedPlayer(playerGuid);
|
||||||
@@ -145,7 +156,16 @@ void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId
|
|||||||
LOG_DEBUG("mod-playerbots", "PlayerbotMgr not found for master player with GUID: {}", masterPlayer->GetGUID().GetRawValue());
|
LOG_DEBUG("mod-playerbots", "PlayerbotMgr not found for master player with GUID: {}", masterPlayer->GetGUID().GetRawValue());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint32 count = mgr->GetPlayerbotsCount() + botLoading.size();
|
|
||||||
|
// read botLoading.size() locked
|
||||||
|
size_t loadingCount = 0;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(g_botMapsMx);
|
||||||
|
loadingCount = botLoading.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// uint32 count = mgr->GetPlayerbotsCount() + botLoading.size();
|
||||||
|
uint32 count = mgr->GetPlayerbotsCount() + static_cast<uint32>(loadingCount);
|
||||||
if (count >= sPlayerbotAIConfig->maxAddedBots)
|
if (count >= sPlayerbotAIConfig->maxAddedBots)
|
||||||
{
|
{
|
||||||
allowed = false;
|
allowed = false;
|
||||||
@@ -161,14 +181,22 @@ void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::shared_ptr<PlayerbotLoginQueryHolder> holder =
|
// std::shared_ptr<PlayerbotLoginQueryHolder> holder =
|
||||||
std::make_shared<PlayerbotLoginQueryHolder>(this, masterAccountId, accountId, playerGuid);
|
// std::make_shared<PlayerbotLoginQueryHolder>(this, masterAccountId, accountId, playerGuid);
|
||||||
|
auto holder = std::make_shared<PlayerbotLoginQueryHolder>(this, masterAccountId, accountId, playerGuid);
|
||||||
if (!holder->Initialize())
|
if (!holder->Initialize())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
botLoading.insert(playerGuid);
|
// botLoading.insert(playerGuid);
|
||||||
|
// Protected insert
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(g_botMapsMx);
|
||||||
|
if (botLoading.find(playerGuid) != botLoading.end())
|
||||||
|
return; // already loging
|
||||||
|
botLoading.insert(playerGuid); // we reserve the GUID
|
||||||
|
}
|
||||||
|
|
||||||
// Always login in with world session to avoid race condition
|
// Always login in with world session to avoid race condition
|
||||||
sWorld->AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(holder))
|
sWorld->AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(holder))
|
||||||
@@ -185,7 +213,11 @@ bool PlayerbotHolder::IsAccountLinked(uint32 accountId, uint32 linkedAccountId)
|
|||||||
|
|
||||||
void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder const& holder)
|
void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder const& holder)
|
||||||
{
|
{
|
||||||
|
// Copy immediatly holder value
|
||||||
|
const ObjectGuid guid = holder.GetGuid();
|
||||||
|
const uint32 masterAccountId = holder.GetMasterAccountId();
|
||||||
uint32 botAccountId = holder.GetAccountId();
|
uint32 botAccountId = holder.GetAccountId();
|
||||||
|
|
||||||
// At login DBC locale should be what the server is set to use by default (as spells etc are hardcoded to ENUS this
|
// 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)
|
// allows channels to work as intended)
|
||||||
WorldSession* botSession = new WorldSession(botAccountId, "", 0x0, nullptr, SEC_PLAYER, EXPANSION_WRATH_OF_THE_LICH_KING,
|
WorldSession* botSession = new WorldSession(botAccountId, "", 0x0, nullptr, SEC_PLAYER, EXPANSION_WRATH_OF_THE_LICH_KING,
|
||||||
@@ -200,11 +232,16 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con
|
|||||||
LOG_DEBUG("mod-playerbots", "Bot player could not be loaded for account ID: {}", botAccountId);
|
LOG_DEBUG("mod-playerbots", "Bot player could not be loaded for account ID: {}", botAccountId);
|
||||||
botSession->LogoutPlayer(true);
|
botSession->LogoutPlayer(true);
|
||||||
delete botSession;
|
delete botSession;
|
||||||
botLoading.erase(holder.GetGuid());
|
// botLoading.erase(holder.GetGuid());
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(g_botMapsMx);
|
||||||
|
botLoading.erase(guid);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 masterAccount = holder.GetMasterAccountId();
|
// uint32 masterAccount = holder.GetMasterAccountId();
|
||||||
|
uint32 masterAccount = masterAccountId; // Avoid read in 'holder' after login
|
||||||
WorldSession* masterSession = masterAccount ? sWorldSessionMgr->FindSession(masterAccount) : nullptr;
|
WorldSession* masterSession = masterAccount ? sWorldSessionMgr->FindSession(masterAccount) : nullptr;
|
||||||
|
|
||||||
// Check if masterSession->GetPlayer() is valid
|
// Check if masterSession->GetPlayer() is valid
|
||||||
@@ -217,10 +254,14 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con
|
|||||||
sRandomPlayerbotMgr->OnPlayerLogin(bot);
|
sRandomPlayerbotMgr->OnPlayerLogin(bot);
|
||||||
OnBotLogin(bot);
|
OnBotLogin(bot);
|
||||||
|
|
||||||
botLoading.erase(holder.GetGuid());
|
// botLoading.erase(holder.GetGuid());
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(g_botMapsMx);
|
||||||
|
botLoading.erase(guid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerbotHolder::UpdateSessions()
|
/*void PlayerbotHolder::UpdateSessions()
|
||||||
{
|
{
|
||||||
for (PlayerBotMap::const_iterator itr = GetPlayerBotsBegin(); itr != GetPlayerBotsEnd(); ++itr)
|
for (PlayerBotMap::const_iterator itr = GetPlayerBotsBegin(); itr != GetPlayerBotsEnd(); ++itr)
|
||||||
{
|
{
|
||||||
@@ -238,6 +279,29 @@ void PlayerbotHolder::UpdateSessions()
|
|||||||
HandleBotPackets(bot->GetSession());
|
HandleBotPackets(bot->GetSession());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
void PlayerbotHolder::UpdateSessions()
|
||||||
|
{
|
||||||
|
PlayerBotMap botsCopy;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(g_botMapsMx);
|
||||||
|
botsCopy = playerBots;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& kv : botsCopy)
|
||||||
|
{
|
||||||
|
Player* const bot = kv.second;
|
||||||
|
if (bot->IsBeingTeleported())
|
||||||
|
{
|
||||||
|
if (PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot))
|
||||||
|
botAI->HandleTeleportAck();
|
||||||
|
}
|
||||||
|
else if (bot->IsInWorld())
|
||||||
|
{
|
||||||
|
HandleBotPackets(bot->GetSession());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*void PlayerbotHolder::HandleBotPackets(WorldSession* session)
|
/*void PlayerbotHolder::HandleBotPackets(WorldSession* session)
|
||||||
@@ -287,8 +351,27 @@ void PlayerbotHolder::LogoutAllBots()
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
PlayerBotMap bots = playerBots;
|
/*PlayerBotMap bots = playerBots;
|
||||||
for (auto& itr : bots)
|
for (auto& itr : bots)
|
||||||
|
{
|
||||||
|
Player* bot = itr.second;
|
||||||
|
if (!bot)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||||
|
if (!botAI || botAI->IsRealPlayer())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
LogoutPlayerBot(bot->GetGUID());
|
||||||
|
}*/
|
||||||
|
// Snapshot under lock for safe iteration
|
||||||
|
PlayerBotMap botsCopy;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(g_botMapsMx);
|
||||||
|
botsCopy = playerBots;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& itr : botsCopy)
|
||||||
{
|
{
|
||||||
Player* bot = itr.second;
|
Player* bot = itr.second;
|
||||||
if (!bot)
|
if (!bot)
|
||||||
@@ -302,7 +385,7 @@ void PlayerbotHolder::LogoutAllBots()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerbotMgr::CancelLogout()
|
/*void PlayerbotMgr::CancelLogout()
|
||||||
{
|
{
|
||||||
Player* master = GetMaster();
|
Player* master = GetMaster();
|
||||||
if (!master)
|
if (!master)
|
||||||
@@ -323,6 +406,53 @@ void PlayerbotMgr::CancelLogout()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (PlayerBotMap::const_iterator it = sRandomPlayerbotMgr->GetPlayerBotsBegin();
|
||||||
|
it != sRandomPlayerbotMgr->GetPlayerBotsEnd(); ++it)
|
||||||
|
{
|
||||||
|
Player* const bot = it->second;
|
||||||
|
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||||
|
if (!botAI || botAI->IsRealPlayer())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (botAI->GetMaster() != master)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (bot->GetSession()->isLogingOut())
|
||||||
|
{
|
||||||
|
WorldPackets::Character::LogoutCancel data = WorldPacket(CMSG_LOGOUT_CANCEL);
|
||||||
|
bot->GetSession()->HandleLogoutCancelOpcode(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
void PlayerbotMgr::CancelLogout()
|
||||||
|
{
|
||||||
|
Player* master = GetMaster();
|
||||||
|
if (!master)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Snapshot of "master" bots under lock
|
||||||
|
std::vector<Player*> botsCopy;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(g_botMapsMx);
|
||||||
|
for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it)
|
||||||
|
botsCopy.push_back(it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Player* const bot : botsCopy)
|
||||||
|
{
|
||||||
|
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||||
|
if (!botAI || botAI->IsRealPlayer())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (bot->GetSession()->isLogingOut())
|
||||||
|
{
|
||||||
|
WorldPackets::Character::LogoutCancel data = WorldPacket(CMSG_LOGOUT_CANCEL);
|
||||||
|
bot->GetSession()->HandleLogoutCancelOpcode(data);
|
||||||
|
botAI->TellMaster("Logout cancelled!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (PlayerBotMap::const_iterator it = sRandomPlayerbotMgr->GetPlayerBotsBegin();
|
for (PlayerBotMap::const_iterator it = sRandomPlayerbotMgr->GetPlayerBotsBegin();
|
||||||
it != sRandomPlayerbotMgr->GetPlayerBotsEnd(); ++it)
|
it != sRandomPlayerbotMgr->GetPlayerBotsEnd(); ++it)
|
||||||
{
|
{
|
||||||
@@ -489,33 +619,47 @@ void PlayerbotHolder::DisablePlayerBot(ObjectGuid guid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PlayerbotHolder::RemoveFromPlayerbotsMap(ObjectGuid guid)
|
void PlayerbotHolder::RemoveFromPlayerbotsMap(ObjectGuid guid)
|
||||||
|
// {
|
||||||
|
// playerBots.erase(guid);
|
||||||
|
// }
|
||||||
|
// Protected erase
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(g_botMapsMx);
|
||||||
playerBots.erase(guid);
|
playerBots.erase(guid);
|
||||||
}
|
}
|
||||||
|
|
||||||
Player* PlayerbotHolder::GetPlayerBot(ObjectGuid playerGuid) const
|
Player* PlayerbotHolder::GetPlayerBot(ObjectGuid playerGuid) const
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(g_botMapsMx); // We protect
|
||||||
PlayerBotMap::const_iterator it = playerBots.find(playerGuid);
|
PlayerBotMap::const_iterator it = playerBots.find(playerGuid);
|
||||||
return (it == playerBots.end()) ? 0 : it->second;
|
return (it == playerBots.end()) ? nullptr : it->second;// (nullptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
Player* PlayerbotHolder::GetPlayerBot(ObjectGuid::LowType lowGuid) const
|
Player* PlayerbotHolder::GetPlayerBot(ObjectGuid::LowType lowGuid) const
|
||||||
{
|
{
|
||||||
ObjectGuid playerGuid = ObjectGuid::Create<HighGuid::Player>(lowGuid);
|
ObjectGuid playerGuid = ObjectGuid::Create<HighGuid::Player>(lowGuid);
|
||||||
|
std::lock_guard<std::mutex> lk(g_botMapsMx); // We protect
|
||||||
PlayerBotMap::const_iterator it = playerBots.find(playerGuid);
|
PlayerBotMap::const_iterator it = playerBots.find(playerGuid);
|
||||||
return (it == playerBots.end()) ? 0 : it->second;
|
return (it == playerBots.end()) ? nullptr : it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerbotHolder::OnBotLogin(Player* const bot)
|
void PlayerbotHolder::OnBotLogin(Player* const bot)
|
||||||
{
|
{
|
||||||
// Prevent duplicate login
|
// Prevent duplicate login
|
||||||
if (playerBots.find(bot->GetGUID()) != playerBots.end())
|
/*if (playerBots.find(bot->GetGUID()) != playerBots.end())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
}*/
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(g_botMapsMx);
|
||||||
|
if (playerBots.find(bot->GetGUID()) != playerBots.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
playerBots[bot->GetGUID()] = bot;
|
||||||
}
|
}
|
||||||
|
|
||||||
sPlayerbotsMgr->AddPlayerbotData(bot, true);
|
sPlayerbotsMgr->AddPlayerbotData(bot, true);
|
||||||
playerBots[bot->GetGUID()] = bot;
|
// playerBots[bot->GetGUID()] = bot;
|
||||||
|
|
||||||
OnBotLoginInternal(bot);
|
OnBotLoginInternal(bot);
|
||||||
|
|
||||||
@@ -1230,8 +1374,13 @@ std::vector<std::string> PlayerbotHolder::HandlePlayerbotCommand(char const* arg
|
|||||||
// If the user requested a specific gender, skip any character that doesn't match.
|
// If the user requested a specific gender, skip any character that doesn't match.
|
||||||
if (gender != -1 && GetOfflinePlayerGender(guid) != gender)
|
if (gender != -1 && GetOfflinePlayerGender(guid) != gender)
|
||||||
continue;
|
continue;
|
||||||
if (botLoading.find(guid) != botLoading.end())
|
/*if (botLoading.find(guid) != botLoading.end())
|
||||||
continue;
|
continue;*/
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(g_botMapsMx);
|
||||||
|
if (botLoading.find(guid) != botLoading.end())
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (ObjectAccessor::FindConnectedPlayer(guid))
|
if (ObjectAccessor::FindConnectedPlayer(guid))
|
||||||
continue;
|
continue;
|
||||||
uint32 guildId = sCharacterCache->GetCharacterGuildIdByGuid(guid);
|
uint32 guildId = sCharacterCache->GetCharacterGuildIdByGuid(guid);
|
||||||
@@ -1295,12 +1444,25 @@ std::vector<std::string> PlayerbotHolder::HandlePlayerbotCommand(char const* arg
|
|||||||
|
|
||||||
if (charnameStr == "!" && master && master->GetSession()->GetSecurity() > SEC_GAMEMASTER)
|
if (charnameStr == "!" && master && master->GetSession()->GetSecurity() > SEC_GAMEMASTER)
|
||||||
{
|
{
|
||||||
for (PlayerBotMap::const_iterator i = GetPlayerBotsBegin(); i != GetPlayerBotsEnd(); ++i)
|
/*for (PlayerBotMap::const_iterator i = GetPlayerBotsBegin(); i != GetPlayerBotsEnd(); ++i)
|
||||||
{
|
{
|
||||||
if (Player* bot = i->second)
|
if (Player* bot = i->second)
|
||||||
if (bot->IsInWorld())
|
if (bot->IsInWorld())
|
||||||
bots.insert(bot->GetName());
|
bots.insert(bot->GetName());
|
||||||
}
|
}*/
|
||||||
|
// Snapshot under lock
|
||||||
|
std::vector<Player*> botsCopy;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(g_botMapsMx);
|
||||||
|
for (PlayerBotMap::const_iterator i = GetPlayerBotsBegin(); i != GetPlayerBotsEnd(); ++i)
|
||||||
|
botsCopy.push_back(i->second);
|
||||||
|
}
|
||||||
|
for (Player* const bot : botsCopy)
|
||||||
|
{
|
||||||
|
if (bot && bot->IsInWorld())
|
||||||
|
bots.insert(bot->GetName());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> chars = split(charnameStr, ',');
|
std::vector<std::string> chars = split(charnameStr, ',');
|
||||||
@@ -1404,7 +1566,7 @@ uint32 PlayerbotHolder::GetAccountId(ObjectGuid guid)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string const PlayerbotHolder::ListBots(Player* master)
|
/*std::string const PlayerbotHolder::ListBots(Player* master)
|
||||||
{
|
{
|
||||||
std::set<std::string> bots;
|
std::set<std::string> bots;
|
||||||
std::map<uint8, std::string> classNames;
|
std::map<uint8, std::string> classNames;
|
||||||
@@ -1490,6 +1652,103 @@ std::string const PlayerbotHolder::ListBots(Player* master)
|
|||||||
out << online[name] << name << " " << classes[name];
|
out << online[name] << name << " " << classes[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return out.str();
|
||||||
|
}*/
|
||||||
|
|
||||||
|
std::string const PlayerbotHolder::ListBots(Player* master)
|
||||||
|
{
|
||||||
|
std::set<std::string> bots;
|
||||||
|
std::map<uint8, std::string> classNames;
|
||||||
|
|
||||||
|
classNames[CLASS_DEATH_KNIGHT] = "Death Knight";
|
||||||
|
classNames[CLASS_DRUID] = "Druid";
|
||||||
|
classNames[CLASS_HUNTER] = "Hunter";
|
||||||
|
classNames[CLASS_MAGE] = "Mage";
|
||||||
|
classNames[CLASS_PALADIN] = "Paladin";
|
||||||
|
classNames[CLASS_PRIEST] = "Priest";
|
||||||
|
classNames[CLASS_ROGUE] = "Rogue";
|
||||||
|
classNames[CLASS_SHAMAN] = "Shaman";
|
||||||
|
classNames[CLASS_WARLOCK] = "Warlock";
|
||||||
|
classNames[CLASS_WARRIOR] = "Warrior";
|
||||||
|
classNames[CLASS_DEATH_KNIGHT] = "DeathKnight";
|
||||||
|
|
||||||
|
std::map<std::string, std::string> online;
|
||||||
|
std::vector<std::string> names;
|
||||||
|
std::map<std::string, std::string> classes;
|
||||||
|
|
||||||
|
// Snapshot under lock
|
||||||
|
std::vector<Player*> botsCopy;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(g_botMapsMx);
|
||||||
|
for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it)
|
||||||
|
botsCopy.push_back(it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Player* const bot : botsCopy)
|
||||||
|
{
|
||||||
|
std::string const name = bot->GetName();
|
||||||
|
bots.insert(name);
|
||||||
|
|
||||||
|
names.push_back(name);
|
||||||
|
online[name] = "+";
|
||||||
|
classes[name] = classNames[bot->getClass()];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (master)
|
||||||
|
{
|
||||||
|
QueryResult results = CharacterDatabase.Query(
|
||||||
|
"SELECT class, name FROM characters WHERE account = {}",
|
||||||
|
master->GetSession()->GetAccountId());
|
||||||
|
|
||||||
|
if (results)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Field* fields = results->Fetch();
|
||||||
|
uint8 cls = fields[0].Get<uint8>();
|
||||||
|
std::string const name = fields[1].Get<std::string>();
|
||||||
|
if (bots.find(name) == bots.end() && name != master->GetSession()->GetPlayerName())
|
||||||
|
{
|
||||||
|
names.push_back(name);
|
||||||
|
online[name] = "-";
|
||||||
|
classes[name] = classNames[cls];
|
||||||
|
}
|
||||||
|
} while (results->NextRow());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(names.begin(), names.end());
|
||||||
|
|
||||||
|
if (master)
|
||||||
|
{
|
||||||
|
if (Group* group = master->GetGroup())
|
||||||
|
{
|
||||||
|
Group::MemberSlotList const& groupSlot = group->GetMemberSlots();
|
||||||
|
for (Group::member_citerator itr = groupSlot.begin(); itr != groupSlot.end(); itr++)
|
||||||
|
{
|
||||||
|
Player* member = ObjectAccessor::FindPlayer(itr->guid);
|
||||||
|
if (member && sRandomPlayerbotMgr->IsRandomBot(member))
|
||||||
|
{
|
||||||
|
std::string const name = member->GetName();
|
||||||
|
|
||||||
|
names.push_back(name);
|
||||||
|
online[name] = "+";
|
||||||
|
classes[name] = classNames[member->getClass()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostringstream out;
|
||||||
|
bool first = true;
|
||||||
|
out << "Bot roster: ";
|
||||||
|
for (std::vector<std::string>::iterator i = names.begin(); i != names.end(); ++i)
|
||||||
|
{
|
||||||
|
if (first) first = false; else out << ", ";
|
||||||
|
std::string const name = *i;
|
||||||
|
out << online[name] << name << " " << classes[name];
|
||||||
|
}
|
||||||
|
|
||||||
return out.str();
|
return out.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1516,7 +1775,7 @@ std::string const PlayerbotHolder::LookupBots(Player* master)
|
|||||||
return ret_msg;
|
return ret_msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 PlayerbotHolder::GetPlayerbotsCountByClass(uint32 cls)
|
/*uint32 PlayerbotHolder::GetPlayerbotsCountByClass(uint32 cls)
|
||||||
{
|
{
|
||||||
uint32 count = 0;
|
uint32 count = 0;
|
||||||
for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it)
|
for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it)
|
||||||
@@ -1528,6 +1787,25 @@ uint32 PlayerbotHolder::GetPlayerbotsCountByClass(uint32 cls)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
uint32 PlayerbotHolder::GetPlayerbotsCountByClass(uint32 cls)
|
||||||
|
{
|
||||||
|
uint32 count = 0;
|
||||||
|
|
||||||
|
// Snapshot under lock
|
||||||
|
std::vector<Player*> botsCopy;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(g_botMapsMx);
|
||||||
|
for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it)
|
||||||
|
botsCopy.push_back(it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Player* const bot : botsCopy)
|
||||||
|
if (bot && bot->IsInWorld() && bot->getClass() == cls)
|
||||||
|
++count;
|
||||||
|
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerbotMgr::PlayerbotMgr(Player* const master) : PlayerbotHolder(), master(master), lastErrorTell(0) {}
|
PlayerbotMgr::PlayerbotMgr(Player* const master) : PlayerbotHolder(), master(master), lastErrorTell(0) {}
|
||||||
@@ -1544,7 +1822,7 @@ void PlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/)
|
|||||||
CheckTellErrors(elapsed);
|
CheckTellErrors(elapsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerbotMgr::HandleCommand(uint32 type, std::string const text)
|
/*void PlayerbotMgr::HandleCommand(uint32 type, std::string const text)
|
||||||
{
|
{
|
||||||
Player* master = GetMaster();
|
Player* master = GetMaster();
|
||||||
if (!master)
|
if (!master)
|
||||||
@@ -1570,6 +1848,47 @@ void PlayerbotMgr::HandleCommand(uint32 type, std::string const text)
|
|||||||
botAI->HandleCommand(type, text, master);
|
botAI->HandleCommand(type, text, master);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (PlayerBotMap::const_iterator it = sRandomPlayerbotMgr->GetPlayerBotsBegin();
|
||||||
|
it != sRandomPlayerbotMgr->GetPlayerBotsEnd(); ++it)
|
||||||
|
{
|
||||||
|
Player* const bot = it->second;
|
||||||
|
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||||
|
if (botAI && botAI->GetMaster() == master)
|
||||||
|
botAI->HandleCommand(type, text, master);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
void PlayerbotMgr::HandleCommand(uint32 type, std::string const text)
|
||||||
|
{
|
||||||
|
Player* master = GetMaster();
|
||||||
|
if (!master)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (text.find(sPlayerbotAIConfig->commandSeparator) != std::string::npos)
|
||||||
|
{
|
||||||
|
std::vector<std::string> commands;
|
||||||
|
split(commands, text, sPlayerbotAIConfig->commandSeparator.c_str());
|
||||||
|
for (std::vector<std::string>::iterator i = commands.begin(); i != commands.end(); ++i)
|
||||||
|
HandleCommand(type, *i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Snapshot of "master" bots under lock to avoid race conditions
|
||||||
|
std::vector<Player*> botsCopy;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(g_botMapsMx);
|
||||||
|
for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it)
|
||||||
|
botsCopy.push_back(it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Player* const bot : botsCopy)
|
||||||
|
{
|
||||||
|
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||||
|
if (botAI)
|
||||||
|
botAI->HandleCommand(type, text, master);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Random bots : unchanges
|
||||||
for (PlayerBotMap::const_iterator it = sRandomPlayerbotMgr->GetPlayerBotsBegin();
|
for (PlayerBotMap::const_iterator it = sRandomPlayerbotMgr->GetPlayerBotsBegin();
|
||||||
it != sRandomPlayerbotMgr->GetPlayerBotsEnd(); ++it)
|
it != sRandomPlayerbotMgr->GetPlayerBotsEnd(); ++it)
|
||||||
{
|
{
|
||||||
@@ -1580,7 +1899,7 @@ void PlayerbotMgr::HandleCommand(uint32 type, std::string const text)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerbotMgr::HandleMasterIncomingPacket(WorldPacket const& packet)
|
/*void PlayerbotMgr::HandleMasterIncomingPacket(WorldPacket const& packet)
|
||||||
{
|
{
|
||||||
for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it)
|
for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it)
|
||||||
{
|
{
|
||||||
@@ -1601,6 +1920,53 @@ void PlayerbotMgr::HandleMasterIncomingPacket(WorldPacket const& packet)
|
|||||||
botAI->HandleMasterIncomingPacket(packet);
|
botAI->HandleMasterIncomingPacket(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (packet.GetOpcode())
|
||||||
|
{
|
||||||
|
// if master is logging out, log out all bots
|
||||||
|
case CMSG_LOGOUT_REQUEST:
|
||||||
|
{
|
||||||
|
LogoutAllBots();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// if master cancelled logout, cancel too
|
||||||
|
case CMSG_LOGOUT_CANCEL:
|
||||||
|
{
|
||||||
|
CancelLogout();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
void PlayerbotMgr::HandleMasterIncomingPacket(WorldPacket const& packet)
|
||||||
|
{
|
||||||
|
// Snapshot of "master" bots under lock
|
||||||
|
std::vector<Player*> botsCopy;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(g_botMapsMx);
|
||||||
|
for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it)
|
||||||
|
botsCopy.push_back(it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Player* const bot : botsCopy)
|
||||||
|
{
|
||||||
|
if (!bot)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||||
|
if (botAI)
|
||||||
|
botAI->HandleMasterIncomingPacket(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Boucle random bots (inchangée)
|
||||||
|
for (PlayerBotMap::const_iterator it = sRandomPlayerbotMgr->GetPlayerBotsBegin();
|
||||||
|
it != sRandomPlayerbotMgr->GetPlayerBotsEnd(); ++it)
|
||||||
|
{
|
||||||
|
Player* const bot = it->second;
|
||||||
|
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||||
|
if (botAI && botAI->GetMaster() == GetMaster())
|
||||||
|
botAI->HandleMasterIncomingPacket(packet);
|
||||||
|
}
|
||||||
|
|
||||||
switch (packet.GetOpcode())
|
switch (packet.GetOpcode())
|
||||||
{
|
{
|
||||||
// if master is logging out, log out all bots
|
// if master is logging out, log out all bots
|
||||||
@@ -1618,7 +1984,8 @@ void PlayerbotMgr::HandleMasterIncomingPacket(WorldPacket const& packet)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerbotMgr::HandleMasterOutgoingPacket(WorldPacket const& packet)
|
|
||||||
|
/*void PlayerbotMgr::HandleMasterOutgoingPacket(WorldPacket const& packet)
|
||||||
{
|
{
|
||||||
for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it)
|
for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it)
|
||||||
{
|
{
|
||||||
@@ -1628,6 +1995,33 @@ void PlayerbotMgr::HandleMasterOutgoingPacket(WorldPacket const& packet)
|
|||||||
botAI->HandleMasterOutgoingPacket(packet);
|
botAI->HandleMasterOutgoingPacket(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (PlayerBotMap::const_iterator it = sRandomPlayerbotMgr->GetPlayerBotsBegin();
|
||||||
|
it != sRandomPlayerbotMgr->GetPlayerBotsEnd(); ++it)
|
||||||
|
{
|
||||||
|
Player* const bot = it->second;
|
||||||
|
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||||
|
if (botAI && botAI->GetMaster() == GetMaster())
|
||||||
|
botAI->HandleMasterOutgoingPacket(packet);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
void PlayerbotMgr::HandleMasterOutgoingPacket(WorldPacket const& packet)
|
||||||
|
{
|
||||||
|
// Snapshot of "master" bots under lock
|
||||||
|
std::vector<Player*> botsCopy;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(g_botMapsMx);
|
||||||
|
for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it)
|
||||||
|
botsCopy.push_back(it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Player* const bot : botsCopy)
|
||||||
|
{
|
||||||
|
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||||
|
if (botAI)
|
||||||
|
botAI->HandleMasterOutgoingPacket(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Random bots loop unchanged
|
||||||
for (PlayerBotMap::const_iterator it = sRandomPlayerbotMgr->GetPlayerBotsBegin();
|
for (PlayerBotMap::const_iterator it = sRandomPlayerbotMgr->GetPlayerBotsBegin();
|
||||||
it != sRandomPlayerbotMgr->GetPlayerBotsEnd(); ++it)
|
it != sRandomPlayerbotMgr->GetPlayerBotsEnd(); ++it)
|
||||||
{
|
{
|
||||||
@@ -1638,7 +2032,7 @@ void PlayerbotMgr::HandleMasterOutgoingPacket(WorldPacket const& packet)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerbotMgr::SaveToDB()
|
/*void PlayerbotMgr::SaveToDB()
|
||||||
{
|
{
|
||||||
for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it)
|
for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it)
|
||||||
{
|
{
|
||||||
@@ -1653,6 +2047,32 @@ void PlayerbotMgr::SaveToDB()
|
|||||||
if (GET_PLAYERBOT_AI(bot) && GET_PLAYERBOT_AI(bot)->GetMaster() == GetMaster())
|
if (GET_PLAYERBOT_AI(bot) && GET_PLAYERBOT_AI(bot)->GetMaster() == GetMaster())
|
||||||
bot->SaveToDB(false, false);
|
bot->SaveToDB(false, false);
|
||||||
}
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
void PlayerbotMgr::SaveToDB()
|
||||||
|
{
|
||||||
|
// Snapshot of "master" bots under lock
|
||||||
|
std::vector<Player*> botsCopy;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(g_botMapsMx);
|
||||||
|
for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it)
|
||||||
|
botsCopy.push_back(it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Player* const bot : botsCopy)
|
||||||
|
{
|
||||||
|
if (bot)
|
||||||
|
bot->SaveToDB(false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (PlayerBotMap::const_iterator it = sRandomPlayerbotMgr->GetPlayerBotsBegin();
|
||||||
|
it != sRandomPlayerbotMgr->GetPlayerBotsEnd(); ++it)
|
||||||
|
{
|
||||||
|
Player* const bot = it->second;
|
||||||
|
PlayerbotAI* ai = GET_PLAYERBOT_AI(bot);
|
||||||
|
if (ai && ai->GetMaster() == GetMaster())
|
||||||
|
bot->SaveToDB(false, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerbotMgr::OnBotLoginInternal(Player* const bot)
|
void PlayerbotMgr::OnBotLoginInternal(Player* const bot)
|
||||||
|
|||||||
Reference in New Issue
Block a user