From 83c6977de5dc4ab13e0401d36bd6cd4b0757ef03 Mon Sep 17 00:00:00 2001 From: Keleborn <22352763+Celandriel@users.noreply.github.com> Date: Sat, 3 Jan 2026 06:15:28 -0800 Subject: [PATCH] Refactor guild managment into a singleton (#1913) The idea is to centralize the creation, assignment, and management of bot guilds into a single class that can be referenced. The way this is intended to work. when the manager is created, if the config option to delete guilds is set, then it deletes all bot guilds. On startup 1. Load all guild names from database. Shuffle keys for some randomization. 2. Load Guilds from database 3. For existing guilds, identify the guild faction, number of members, and assess if the guild is 'full' based on the number of bots set in config. 4. Determine if the leader of the guild is a real player based on the leader account. 5. Mark any playerbot guild names as not available (false). The validation process (2-5) is set to run once an hour. Guild Creation. Now guild creation occurs on an as needed bases during the initialization process. Previously, all of the guilds would be created at once, and then randomly assigned. When a bot is not in a guild during initialization, it will check if there are any partially filled guilds of that bots faction where the bot can be assigned to. If not, and the cache of bot guilds is less than the set number in config, it will randomly return the available name. This then goes to the CreateGuild function where the core guild manager creates a guild, the guild emblem is set, and the cache updated. If a bot is assigned to guild, but fails to join then it throws an error. Checking for real player guilds function now lives in the guild manager. --------- Co-authored-by: bashermens <31279994+hermensbas@users.noreply.github.com> --- src/PlayerbotAI.cpp | 17 +- src/PlayerbotAI.h | 1 - src/PlayerbotAIConfig.cpp | 2 + src/PlayerbotAIConfig.h | 1 - src/PlayerbotGuildMgr.cpp | 322 +++++++++++++++++++++++++++++++ src/PlayerbotGuildMgr.h | 52 +++++ src/PlayerbotMgr.cpp | 3 +- src/Playerbots.cpp | 3 +- src/RandomPlayerbotFactory.cpp | 182 +---------------- src/RandomPlayerbotFactory.h | 1 - src/factory/PlayerbotFactory.cpp | 45 ++--- 11 files changed, 400 insertions(+), 229 deletions(-) create mode 100644 src/PlayerbotGuildMgr.cpp create mode 100644 src/PlayerbotGuildMgr.h diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 40271940..d10f950c 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -43,6 +43,7 @@ #include "PlayerbotAIConfig.h" #include "PlayerbotDbStore.h" #include "PlayerbotMgr.h" +#include "PlayerbotGuildMgr.h" #include "Playerbots.h" #include "PointMovementGenerator.h" #include "PositionValue.h" @@ -5862,26 +5863,12 @@ bool PlayerbotAI::CanMove() return bot->GetMotionMaster()->GetCurrentMovementGeneratorType() != FLIGHT_MOTION_TYPE; } -bool PlayerbotAI::IsRealGuild(uint32 guildId) -{ - Guild* guild = sGuildMgr->GetGuildById(guildId); - if (!guild) - { - return false; - } - uint32 leaderAccount = sCharacterCache->GetCharacterAccountIdByGuid(guild->GetLeaderGUID()); - if (!leaderAccount) - return false; - - return !(sPlayerbotAIConfig->IsInRandomAccountList(leaderAccount)); -} - bool PlayerbotAI::IsInRealGuild() { if (!bot->GetGuildId()) return false; - return IsRealGuild(bot->GetGuildId()); + return sPlayerbotGuildMgr->IsRealGuild(bot->GetGuildId()); } void PlayerbotAI::QueueChatResponse(const ChatQueuedReply chatReply) { chatReplies.push_back(std::move(chatReply)); } diff --git a/src/PlayerbotAI.h b/src/PlayerbotAI.h index 602b18d2..c8f5f230 100644 --- a/src/PlayerbotAI.h +++ b/src/PlayerbotAI.h @@ -579,7 +579,6 @@ public: void ResetJumpDestination() { jumpDestination = Position(); } bool CanMove(); - static bool IsRealGuild(uint32 guildId); bool IsInRealGuild(); static std::vector dispel_whitelist; bool EqualLowercaseName(std::string s1, std::string s2); diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 1b47c196..d8a8b0b4 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -10,6 +10,7 @@ #include "PlayerbotDungeonSuggestionMgr.h" #include "PlayerbotFactory.h" #include "Playerbots.h" +#include "PlayerbotGuildMgr.h" #include "RandomItemMgr.h" #include "RandomPlayerbotFactory.h" #include "RandomPlayerbotMgr.h" @@ -666,6 +667,7 @@ bool PlayerbotAIConfig::Initialize() sRandomPlayerbotMgr->Init(); } + sPlayerbotGuildMgr->Init(); sRandomItemMgr->Init(); sRandomItemMgr->InitAfterAhBot(); sPlayerbotTextMgr->LoadBotTexts(); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index 5013e412..fb112fc9 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -273,7 +273,6 @@ public: bool deleteRandomBotAccounts; uint32 randomBotGuildCount, randomBotGuildSizeMax; bool deleteRandomBotGuilds; - std::vector randomBotGuilds; std::vector pvpProhibitedZoneIds; std::vector pvpProhibitedAreaIds; bool fastReactInBG; diff --git a/src/PlayerbotGuildMgr.cpp b/src/PlayerbotGuildMgr.cpp new file mode 100644 index 00000000..98d71dab --- /dev/null +++ b/src/PlayerbotGuildMgr.cpp @@ -0,0 +1,322 @@ +#include "PlayerbotGuildMgr.h" +#include "Player.h" +#include "PlayerbotAIConfig.h" +#include "DatabaseEnv.h" +#include "Guild.h" +#include "GuildMgr.h" +#include "RandomPlayerbotMgr.h" +#include "ScriptMgr.h" + +PlayerbotGuildMgr::PlayerbotGuildMgr(){} + +void PlayerbotGuildMgr::Init() +{ + _guildCache.clear(); + if (sPlayerbotAIConfig->deleteRandomBotGuilds) + DeleteBotGuilds(); + + LoadGuildNames(); + ValidateGuildCache(); +} + +bool PlayerbotGuildMgr::CreateGuild(Player* player, std::string guildName) +{ + Guild* guild = new Guild(); + if (!guild->Create(player, guildName)) + { + LOG_ERROR("playerbots", "Error creating guild [ {} ] with leader [ {} ]", guildName, + player->GetName()); + delete guild; + return false; + } + sGuildMgr->AddGuild(guild); + + LOG_DEBUG("playerbots", "Guild created: id={} name='{}'", guild->GetId(), guildName); + SetGuildEmblem(guild->GetId()); + + GuildCache entry; + entry.name = guildName; + entry.memberCount = 1; + entry.status = 1; + entry.maxMembers = sPlayerbotAIConfig->randomBotGuildSizeMax; + entry.faction = player->GetTeamId(); + + _guildCache[guild->GetId()] = entry; + return true; +} + +bool PlayerbotGuildMgr::SetGuildEmblem(uint32 guildId) +{ + Guild* guild = sGuildMgr->GetGuildById(guildId); + if (!guild) + return false; + + // create random emblem + uint32 st, cl, br, bc, bg; + bg = urand(0, 51); + bc = urand(0, 17); + cl = urand(0, 17); + br = urand(0, 7); + st = urand(0, 180); + + LOG_DEBUG("playerbots", + "[TABARD] new guild id={} random -> style={}, color={}, borderStyle={}, borderColor={}, bgColor={}", + guild->GetId(), st, cl, br, bc, bg); + + // populate guild table with a random tabard design + CharacterDatabase.Execute( + "UPDATE guild SET EmblemStyle={}, EmblemColor={}, BorderStyle={}, BorderColor={}, BackgroundColor={} " + "WHERE guildid={}", + st, cl, br, bc, bg, guild->GetId()); + LOG_DEBUG("playerbots", "[TABARD] UPDATE done for guild id={}", guild->GetId()); + + // Immediate reading for log + if (QueryResult qr = CharacterDatabase.Query( + "SELECT EmblemStyle,EmblemColor,BorderStyle,BorderColor,BackgroundColor FROM guild WHERE guildid={}", + guild->GetId())) + { + Field* f = qr->Fetch(); + LOG_DEBUG("playerbots", + "[TABARD] DB check guild id={} => style={}, color={}, borderStyle={}, borderColor={}, bgColor={}", + guild->GetId(), f[0].Get(), f[1].Get(), f[2].Get(), f[3].Get(), f[4].Get()); + } + return true; +} + +std::string PlayerbotGuildMgr::AssignToGuild(Player* player) +{ + if (!player) + return ""; + + uint8_t playerFaction = player->GetTeamId(); + std::vector partiallyfilledguilds; + partiallyfilledguilds.reserve(_guildCache.size()); + + for (auto& keyValue : _guildCache) + { + GuildCache& cached = keyValue.second; + if (cached.status == 1 && cached.faction == playerFaction) + partiallyfilledguilds.push_back(&cached); + } + + if (!partiallyfilledguilds.empty()) + { + size_t idx = static_cast(urand(0, static_cast(partiallyfilledguilds.size()) - 1)); + return (partiallyfilledguilds[idx]->name); + } + + size_t count = std::count_if( + _guildCache.begin(), _guildCache.end(), + [](const std::pair& pair) + { + return !pair.second.hasRealPlayer; + } + ); + + if (count < sPlayerbotAIConfig->randomBotGuildCount) + { + for (auto& key : _shuffled_guild_keys) + { + if (_guildNames[key]) + { + LOG_INFO("playerbots","Assigning player [{}] to guild [{}]", player->GetName(), key); + return key; + } + } + LOG_ERROR("playerbots","No available guild names left."); + } + return ""; +} + +void PlayerbotGuildMgr::OnGuildUpdate(Guild* guild) +{ + auto it = _guildCache.find(guild->GetId()); + if (it == _guildCache.end()) + return; + + GuildCache& entry = it->second; + entry.memberCount = guild->GetMemberCount(); + if (entry.memberCount < entry.maxMembers) + entry.status = 1; + else if (entry.memberCount >= entry.maxMembers) + entry.status = 2; // Full + std::string guildName = guild->GetName(); + for (auto& it : _guildNames) + { + if (it.first == guildName) + { + it.second = false; + break; + } + } +} + +void PlayerbotGuildMgr::ResetGuildCache() +{ + for (auto it = _guildCache.begin(); it != _guildCache.end();) + { + GuildCache& cached = it->second; + cached.memberCount = 0; + cached.faction = 2; + cached.status = 0; + } +} + +void PlayerbotGuildMgr::LoadGuildNames() +{ + LOG_INFO("playerbots", "Loading guild names from playerbots_guild_names..."); + + QueryResult result = CharacterDatabase.Query("SELECT name_id, name FROM playerbots_guild_names"); + + if (!result) + { + LOG_ERROR("playerbots", "No entries found in playerbots_guild_names. List is empty."); + return; + } + + do + { + Field* fields = result->Fetch(); + _guildNames[fields[1].Get()] = true; + } while (result->NextRow()); + + for (auto& pair : _guildNames) + _shuffled_guild_keys.push_back(pair.first); + + std::random_device rd; + std::mt19937 g(rd()); + + std::shuffle(_shuffled_guild_keys.begin(), _shuffled_guild_keys.end(), g); + LOG_INFO("playerbots", "Loaded {} guild entries from playerbots_guild_names table.", _guildNames.size()); +} + +void PlayerbotGuildMgr::ValidateGuildCache() +{ + QueryResult result = CharacterDatabase.Query("SELECT guildid, name FROM guild"); + if (!result) + { + LOG_ERROR("playerbots", "No guilds found in database, resetting guild cache"); + ResetGuildCache(); + return; + } + + std::unordered_map dbGuilds; + do + { + Field* fields = result->Fetch(); + uint32 guildId = fields[0].Get(); + std::string guildName = fields[1].Get(); + dbGuilds[guildId] = guildName; + } while (result->NextRow()); + + for (auto it = dbGuilds.begin(); it != dbGuilds.end(); it++) + { + uint32 guildId = it->first; + GuildCache cache; + cache.name = it->second; + cache.maxMembers = sPlayerbotAIConfig->randomBotGuildSizeMax; + + Guild* guild = sGuildMgr ->GetGuildById(guildId); + if (!guild) + continue; + + cache.memberCount = guild->GetMemberCount(); + ObjectGuid leaderGuid = guild->GetLeaderGUID(); + CharacterCacheEntry const* leaderEntry = sCharacterCache->GetCharacterCacheByGuid(leaderGuid); + uint32 leaderAccount = leaderEntry->AccountId; + cache.hasRealPlayer = !(sPlayerbotAIConfig->IsInRandomAccountList(leaderAccount)); + cache.faction = Player::TeamIdForRace(leaderEntry->Race); + if (cache.memberCount == 0) + cache.status = 0; // empty + else if (cache.memberCount < cache.maxMembers) + cache.status = 1; // partially filled + else + cache.status = 2; // full + + _guildCache.insert_or_assign(guildId, cache); + for (auto& it : _guildNames) + { + if (it.first == cache.name) + { + it.second = false; + break; + } + } + } +} + +void PlayerbotGuildMgr::DeleteBotGuilds() +{ + LOG_INFO("playerbots", "Deleting random bot guilds..."); + std::vector randomBots; + + PlayerbotsDatabasePreparedStatement* stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_SEL_RANDOM_BOTS_BOT); + stmt->SetData(0, "add"); + if (PreparedQueryResult result = PlayerbotsDatabase.Query(stmt)) + { + do + { + Field* fields = result->Fetch(); + uint32 bot = fields[0].Get(); + randomBots.push_back(bot); + } while (result->NextRow()); + } + + for (std::vector::iterator i = randomBots.begin(); i != randomBots.end(); ++i) + { + if (Guild* guild = sGuildMgr->GetGuildByLeader(ObjectGuid::Create(*i))) + guild->Disband(); + } + LOG_INFO("playerbots", "Random bot guilds deleted"); +} + +bool PlayerbotGuildMgr::IsRealGuild(Player* bot) +{ + if (!bot) + return false; + uint32 guildId = bot->GetGuildId(); + if (!guildId) + return false; + + return IsRealGuild(guildId); +} + +bool PlayerbotGuildMgr::IsRealGuild(uint32 guildId) +{ + if (!guildId) + return false; + + auto it = _guildCache.find(guildId); + if (it == _guildCache.end()) + return false; + + return it->second.hasRealPlayer; +} + +class BotGuildCacheWorldScript : public WorldScript +{ + public: + + BotGuildCacheWorldScript() : WorldScript("BotGuildCacheWorldScript"), _validateTimer(0){} + + void OnUpdate(uint32 diff) override + { + _validateTimer += diff; + + if (_validateTimer >= _validateInterval) // Validate every hour + { + _validateTimer = 0; + sPlayerbotGuildMgr->ValidateGuildCache(); + LOG_INFO("playerbots", "Scheduled guild cache validation"); + } + } + + private: + uint32 _validateInterval = HOUR*IN_MILLISECONDS; + uint32 _validateTimer; +}; + +void PlayerBotsGuildValidationScript() +{ + new BotGuildCacheWorldScript(); +} \ No newline at end of file diff --git a/src/PlayerbotGuildMgr.h b/src/PlayerbotGuildMgr.h new file mode 100644 index 00000000..0df0df73 --- /dev/null +++ b/src/PlayerbotGuildMgr.h @@ -0,0 +1,52 @@ +#ifndef _PLAYERBOT_PLAYERBOTGUILDMGR_H +#define _PLAYERBOT_PLAYERBOTGUILDMGR_H + +#include "Guild.h" +#include "Player.h" +#include "PlayerbotAI.h" + +class PlayerbotAI; + +class PlayerbotGuildMgr +{ +public: + static PlayerbotGuildMgr* instance() + { + static PlayerbotGuildMgr instance; + return &instance; + } + + void Init(); + std::string AssignToGuild(Player* player); + void LoadGuildNames(); + void ValidateGuildCache(); + void ResetGuildCache(); + bool CreateGuild(Player* player, std::string guildName); + void OnGuildUpdate (Guild* guild); + bool SetGuildEmblem(uint32 guildId); + void DeleteBotGuilds(); + bool IsRealGuild(uint32 guildId); + bool IsRealGuild(Player* bot); + +private: + PlayerbotGuildMgr(); + std::unordered_map _guildNames; + + struct GuildCache + { + std::string name; + uint8 status; + uint32 maxMembers = 0; + uint32 memberCount = 0; + uint8 faction = 0; + bool hasRealPlayer = false; + }; + std::unordered_map _guildCache; + std::vector _shuffled_guild_keys; +}; + +void PlayerBotsGuildValidationScript(); + +#define sPlayerbotGuildMgr PlayerbotGuildMgr::instance() + +#endif \ No newline at end of file diff --git a/src/PlayerbotMgr.cpp b/src/PlayerbotMgr.cpp index 13a6acff..ae3d4e1b 100644 --- a/src/PlayerbotMgr.cpp +++ b/src/PlayerbotMgr.cpp @@ -32,6 +32,7 @@ #include "PlayerbotSecurity.h" #include "PlayerbotWorldThreadProcessor.h" #include "Playerbots.h" +#include "PlayerbotGuildMgr.h" #include "RandomPlayerbotMgr.h" #include "SharedDefines.h" #include "WorldSession.h" @@ -1193,7 +1194,7 @@ std::vector PlayerbotHolder::HandlePlayerbotCommand(char const* arg if (ObjectAccessor::FindConnectedPlayer(guid)) continue; uint32 guildId = sCharacterCache->GetCharacterGuildIdByGuid(guid); - if (guildId && PlayerbotAI::IsRealGuild(guildId)) + if (guildId && sPlayerbotGuildMgr->IsRealGuild(guildId)) continue; AddPlayerBot(guid, master->GetSession()->GetAccountId()); messages.push_back("Add class " + std::string(charname)); diff --git a/src/Playerbots.cpp b/src/Playerbots.cpp index e69c46bd..97e72e42 100644 --- a/src/Playerbots.cpp +++ b/src/Playerbots.cpp @@ -25,6 +25,7 @@ #include "Metric.h" #include "PlayerScript.h" #include "PlayerbotAIConfig.h" +#include "PlayerbotGuildMgr.h" #include "PlayerbotSpellCache.h" #include "PlayerbotWorldThreadProcessor.h" #include "RandomPlayerbotMgr.h" @@ -514,6 +515,6 @@ void AddPlayerbotsScripts() new PlayerbotsScript(); new PlayerBotsBGScript(); AddPlayerbotsSecureLoginScripts(); - AddSC_playerbots_commandscript(); + PlayerBotsGuildValidationScript(); } diff --git a/src/RandomPlayerbotFactory.cpp b/src/RandomPlayerbotFactory.cpp index 4be2d0ed..5a4672f5 100644 --- a/src/RandomPlayerbotFactory.cpp +++ b/src/RandomPlayerbotFactory.cpp @@ -11,6 +11,7 @@ #include "GuildMgr.h" #include "PlayerbotFactory.h" #include "Playerbots.h" +#include "PlayerbotGuildMgr.h" #include "ScriptMgr.h" #include "SharedDefines.h" #include "SocialMgr.h" @@ -754,187 +755,6 @@ void RandomPlayerbotFactory::CreateRandomBots() sPlayerbotAIConfig->randomBotAccounts.size(), totalRandomBotChars); } -void RandomPlayerbotFactory::CreateRandomGuilds() -{ - std::vector randomBots; - - PlayerbotsDatabasePreparedStatement* stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_SEL_RANDOM_BOTS_BOT); - stmt->SetData(0, "add"); - if (PreparedQueryResult result = PlayerbotsDatabase.Query(stmt)) - { - do - { - Field* fields = result->Fetch(); - uint32 bot = fields[0].Get(); - randomBots.push_back(bot); - } while (result->NextRow()); - } - - if (sPlayerbotAIConfig->deleteRandomBotGuilds) - { - LOG_INFO("playerbots", "Deleting random bot guilds..."); - for (std::vector::iterator i = randomBots.begin(); i != randomBots.end(); ++i) - { - if (Guild* guild = sGuildMgr->GetGuildByLeader(ObjectGuid::Create(*i))) - guild->Disband(); - } - - LOG_INFO("playerbots", "Random bot guilds deleted"); - } - - std::unordered_set botAccounts; - botAccounts.reserve(sPlayerbotAIConfig->randomBotAccounts.size()); - for (uint32 acc : sPlayerbotAIConfig->randomBotAccounts) - botAccounts.insert(acc); - - // Recount bot guilds directly from the database (does not depend on connected bots) - uint32 guildNumber = 0; - sPlayerbotAIConfig->randomBotGuilds.clear(); - sPlayerbotAIConfig->randomBotGuilds.shrink_to_fit(); // avoids accumulating old capacity - - if (!botAccounts.empty()) - { - if (QueryResult res = CharacterDatabase.Query( - // We only retrieve what is necessary (guildid, leader account) - "SELECT g.guildid, c.account " - "FROM guild g JOIN characters c ON g.leaderguid = c.guid")) - { - do - { - Field* f = res->Fetch(); - const uint32 guildId = f[0].Get(); - const uint32 accountId = f[1].Get(); - - // Determine if guild leader's account is a bot account. - if (botAccounts.find(accountId) != botAccounts.end()) - { - ++guildNumber; - sPlayerbotAIConfig->randomBotGuilds.push_back(guildId); - } - } while (res->NextRow()); - } - } - - LOG_INFO("playerbots", "{}/{} random bot guilds exist in guild table",guildNumber, sPlayerbotAIConfig->randomBotGuildCount); - if (guildNumber >= sPlayerbotAIConfig->randomBotGuildCount) - { - LOG_DEBUG("playerbots", "No new random guilds required"); - return; - } - - // We list the available leaders (online bots, not in guilds) - GuidVector availableLeaders; - availableLeaders.reserve(randomBots.size()); // limit reallocs - for (const uint32 botLowGuid : randomBots) - { - ObjectGuid leader = ObjectGuid::Create(botLowGuid); - if (sGuildMgr->GetGuildByLeader(leader)) - { - // already GuildLeader -> ignored - continue; - } - else - { - if (Player* player = ObjectAccessor::FindPlayer(leader)) - { - if (!player->GetGuildId()) - availableLeaders.push_back(leader); - } - } - } - LOG_DEBUG("playerbots", "{} available leaders for new guilds found", availableLeaders.size()); - - // Create up to randomBotGuildCount by counting only EFFECTIVE creations - uint32 createdThisRun = 0; - for (; guildNumber < sPlayerbotAIConfig->randomBotGuildCount; /* ++guildNumber -> done only if creation */) - { - std::string const guildName = CreateRandomGuildName(); - if (guildName.empty()) - break; // no more names available in playerbots_guild_names - - if (sGuildMgr->GetGuildByName(guildName)) - continue; // name already taken, skip - - if (availableLeaders.empty()) - { - LOG_ERROR("playerbots", "No leaders for random guilds available"); - break; // no more leaders: we can no longer progress without distorting the counter - } - - uint32 index = urand(0, availableLeaders.size() - 1); - ObjectGuid leader = availableLeaders[index]; - availableLeaders.erase(availableLeaders.begin() + index); // Removes the chosen leader to avoid re-selecting it repeatedly - - Player* player = ObjectAccessor::FindPlayer(leader); - if (!player) - { - LOG_ERROR("playerbots", "ObjectAccessor Cannot find player to set leader for guild {} . Skipped...", - guildName.c_str()); - // we will try with other leaders in the next round (guildNumber is not incremented) - continue; - } - - if (player->GetGuildId()) - { - // leader already in guild -> we don't advance the counter, we move on to the next one - continue; - } - - LOG_DEBUG("playerbots", "Creating guild name='{}' leader='{}'...", guildName.c_str(), player->GetName().c_str()); - - Guild* guild = new Guild(); - if (!guild->Create(player, guildName)) - { - LOG_ERROR("playerbots", "Error creating guild [ {} ] with leader [ {} ]", guildName.c_str(), - player->GetName().c_str()); - delete guild; - continue; - } - - sGuildMgr->AddGuild(guild); - - LOG_DEBUG("playerbots", "Guild created: id={} name='{}'", guild->GetId(), guildName.c_str()); - - // create random emblem - uint32 st, cl, br, bc, bg; - bg = urand(0, 51); - bc = urand(0, 17); - cl = urand(0, 17); - br = urand(0, 7); - st = urand(0, 180); - - LOG_DEBUG("playerbots", - "[TABARD] new guild id={} random -> style={}, color={}, borderStyle={}, borderColor={}, bgColor={}", - guild->GetId(), st, cl, br, bc, bg); - - // populate guild table with a random tabard design - CharacterDatabase.Execute( - "UPDATE guild SET EmblemStyle={}, EmblemColor={}, BorderStyle={}, BorderColor={}, BackgroundColor={} " - "WHERE guildid={}", - st, cl, br, bc, bg, guild->GetId()); - LOG_DEBUG("playerbots", "[TABARD] UPDATE done for guild id={}", guild->GetId()); - - // Immediate reading for log - if (QueryResult qr = CharacterDatabase.Query( - "SELECT EmblemStyle,EmblemColor,BorderStyle,BorderColor,BackgroundColor FROM guild WHERE guildid={}", - guild->GetId())) - { - Field* f = qr->Fetch(); - LOG_DEBUG("playerbots", - "[TABARD] DB check guild id={} => style={}, color={}, borderStyle={}, borderColor={}, bgColor={}", - guild->GetId(), f[0].Get(), f[1].Get(), f[2].Get(), f[3].Get(), f[4].Get()); - } - - sPlayerbotAIConfig->randomBotGuilds.push_back(guild->GetId()); - // The guild is only counted if it is actually created - ++guildNumber; - ++createdThisRun; - } - - // Shows the true total and how many were created during this run - LOG_INFO("playerbots", "{} random bot guilds created this run)", createdThisRun); -} - std::string const RandomPlayerbotFactory::CreateRandomGuildName() { std::string guildName = ""; diff --git a/src/RandomPlayerbotFactory.h b/src/RandomPlayerbotFactory.h index d6c19e45..92f2c9f3 100644 --- a/src/RandomPlayerbotFactory.h +++ b/src/RandomPlayerbotFactory.h @@ -51,7 +51,6 @@ public: Player* CreateRandomBot(WorldSession* session, uint8 cls, std::unordered_map>& names); static void CreateRandomBots(); - static void CreateRandomGuilds(); static void CreateRandomArenaTeams(ArenaType slot, uint32 count); static std::string const CreateRandomGuildName(); static uint32 CalculateTotalAccountCount(); diff --git a/src/factory/PlayerbotFactory.cpp b/src/factory/PlayerbotFactory.cpp index 50a216c9..ef320eba 100644 --- a/src/factory/PlayerbotFactory.cpp +++ b/src/factory/PlayerbotFactory.cpp @@ -30,6 +30,7 @@ #include "PlayerbotAI.h" #include "PlayerbotAIConfig.h" #include "PlayerbotDbStore.h" +#include "PlayerbotGuildMgr.h" #include "Playerbots.h" #include "QuestDef.h" #include "RandomItemMgr.h" @@ -3965,45 +3966,33 @@ void PlayerbotFactory::InitInventoryEquip() void PlayerbotFactory::InitGuild() { if (bot->GetGuildId()) - return; - - // bot->SaveToDB(false, false); - - // add guild tabard - if (bot->GetGuildId() && !bot->HasItemCount(5976, 1)) - StoreItem(5976, 1); - - if (sPlayerbotAIConfig->randomBotGuilds.empty()) - RandomPlayerbotFactory::CreateRandomGuilds(); - - std::vector guilds; - for (std::vector::iterator i = sPlayerbotAIConfig->randomBotGuilds.begin(); - i != sPlayerbotAIConfig->randomBotGuilds.end(); ++i) - guilds.push_back(*i); - - if (guilds.empty()) { - LOG_ERROR("playerbots", "No random guilds available"); + if (!bot->HasItemCount(5976, 1) && bot->GetLevel() > 9) + StoreItem(5976, 1); return; } - int index = urand(0, guilds.size() - 1); - uint32 guildId = guilds[index]; - Guild* guild = sGuildMgr->GetGuildById(guildId); + std::string guildName = sPlayerbotGuildMgr->AssignToGuild(bot); + if (guildName.empty()) + return; + + Guild* guild = sGuildMgr->GetGuildByName(guildName); if (!guild) { - LOG_ERROR("playerbots", "Invalid guild {}", guildId); + if (!sPlayerbotGuildMgr->CreateGuild(bot, guildName)) + LOG_ERROR("playerbots","Failed to create guild {} for bot {}", guildName, bot->GetName()); return; } - - if (guild->GetMemberSize() < urand(10, sPlayerbotAIConfig->randomBotGuildSizeMax)) - guild->AddMember(bot->GetGUID(), urand(GR_OFFICER, GR_INITIATE)); - + else + { + if (guild->AddMember(bot->GetGUID(),urand(GR_OFFICER, GR_INITIATE))) + sPlayerbotGuildMgr->OnGuildUpdate(guild); + else + LOG_ERROR("playerbots","Bot {} failed to join guild {}.", bot->GetName(), guildName); + } // add guild tabard if (bot->GetGuildId() && bot->GetLevel() > 9 && urand(0, 4) && !bot->HasItemCount(5976, 1)) StoreItem(5976, 1); - - // bot->SaveToDB(false, false); } void PlayerbotFactory::InitImmersive()