From 86e8cc60c108f65544ccceedefa9ce5a56e22bd1 Mon Sep 17 00:00:00 2001 From: bo Date: Sat, 14 Mar 2026 21:07:00 -0500 Subject: [PATCH] Bot option: preserve bot groups --- .../Bots/playerbot/PlayerbotAIConfig.cpp | 2 + .../Bots/playerbot/PlayerbotAIConfig.h | 1 + .../Bots/playerbot/RandomPlayerbotMgr.cpp | 78 ++++++++++++++++++- .../Bots/playerbot/RandomPlayerbotMgr.h | 5 ++ .../Bots/playerbot/aiplayerbot.conf.dist.in | 3 + 5 files changed, 87 insertions(+), 2 deletions(-) diff --git a/src/modules/Bots/playerbot/PlayerbotAIConfig.cpp b/src/modules/Bots/playerbot/PlayerbotAIConfig.cpp index 59d8aad6f..c5dd9bef2 100644 --- a/src/modules/Bots/playerbot/PlayerbotAIConfig.cpp +++ b/src/modules/Bots/playerbot/PlayerbotAIConfig.cpp @@ -63,6 +63,7 @@ PlayerbotAIConfig::PlayerbotAIConfig() maxRandomBotsPriceChangeInterval(0), randomBotJoinLfg(false), randomBotLoginAtStartup(false), + randomBotKeepGroups(false), randomBotTeleLevel(0), logInGroupOnly(false), logValuesPerTick(false), @@ -188,6 +189,7 @@ bool PlayerbotAIConfig::Initialize() randomBotMinLevel = config.GetIntDefault("AiPlayerbot.RandomBotMinLevel", 1); randomBotMaxLevel = config.GetIntDefault("AiPlayerbot.RandomBotMaxLevel", 255); randomBotLoginAtStartup = config.GetBoolDefault("AiPlayerbot.RandomBotLoginAtStartup", true); + randomBotKeepGroups = config.GetBoolDefault("AiPlayerbot.RandomBotKeepGroups", false); randomBotTeleLevel = config.GetIntDefault("AiPlayerbot.RandomBotTeleLevel", 3); randomChangeMultiplier = config.GetFloatDefault("AiPlayerbot.RandomChangeMultiplier", 1.0); diff --git a/src/modules/Bots/playerbot/PlayerbotAIConfig.h b/src/modules/Bots/playerbot/PlayerbotAIConfig.h index 8f0cae669..a96b632e1 100644 --- a/src/modules/Bots/playerbot/PlayerbotAIConfig.h +++ b/src/modules/Bots/playerbot/PlayerbotAIConfig.h @@ -68,6 +68,7 @@ class PlayerbotAIConfig uint32 minRandomBotsPriceChangeInterval, maxRandomBotsPriceChangeInterval; bool randomBotJoinLfg; ///< Indicates if random bots should join Looking For Group. bool randomBotLoginAtStartup; ///< Indicates if random bots should login at startup. + bool randomBotKeepGroups; ///< Indicates if random bots should preserve groups across restarts. uint32 randomBotTeleLevel; ///< The teleport level for random bots. bool logInGroupOnly, logValuesPerTick; bool fleeingEnabled; ///< Indicates if fleeing is enabled for bots. diff --git a/src/modules/Bots/playerbot/RandomPlayerbotMgr.cpp b/src/modules/Bots/playerbot/RandomPlayerbotMgr.cpp index c1e7bca8a..2daac4064 100755 --- a/src/modules/Bots/playerbot/RandomPlayerbotMgr.cpp +++ b/src/modules/Bots/playerbot/RandomPlayerbotMgr.cpp @@ -37,6 +37,13 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed) return; } + if (sPlayerbotAIConfig.randomBotKeepGroups) + { + if (!processTicks) + EnsureGroupedBotsOnline(); + LoadGroupedBots(); + } + sLog.outBasic("Processing random bots..."); uint32 cachedMin = GetEventValue(0, "config_min"); @@ -157,8 +164,15 @@ bool RandomPlayerbotMgr::ProcessBot(uint32 bot) Player* player = GetPlayerBot(bot); if (!player || !player->GetGroup()) { - sLog.outDetail("Bot %d expired", bot); - SetEventValue(bot, "add", 0, 0); + if (sPlayerbotAIConfig.randomBotKeepGroups && m_groupedBots.count(bot)) + { + SetEventValue(bot, "add", 1, sPlayerbotAIConfig.maxRandomBotInWorldTime); + } + else + { + sLog.outDetail("Bot %d expired", bot); + SetEventValue(bot, "add", 0, 0); + } } return true; } @@ -690,6 +704,66 @@ bool RandomPlayerbotMgr::IsZoneSafeForBot(Player* bot, uint32 mapId, float x, fl return false; } +QueryResult* RandomPlayerbotMgr::QueryGroupedBots() +{ + if (sPlayerbotAIConfig.randomBotAccounts.empty()) + return nullptr; + + ostringstream os; + bool first = true; + for (list::iterator i = sPlayerbotAIConfig.randomBotAccounts.begin(); i != sPlayerbotAIConfig.randomBotAccounts.end(); ++i) + { + if (!first) os << ","; + os << *i; + first = false; + } + + return CharacterDatabase.PQuery( + "SELECT gm.`memberGuid` FROM `group_member` gm " + "INNER JOIN `characters` c ON gm.`memberGuid` = c.`guid` " + "INNER JOIN `groups` g ON gm.`groupId` = g.`groupId` " + "WHERE c.`account` IN (%s)", + os.str().c_str()); +} + +void RandomPlayerbotMgr::LoadGroupedBots() +{ + m_groupedBots.clear(); + QueryResult* result = QueryGroupedBots(); + if (!result) + return; + + do + { + Field* fields = result->Fetch(); + m_groupedBots.insert(fields[0].GetUInt32()); + } while (result->NextRow()); + delete result; +} + +void RandomPlayerbotMgr::EnsureGroupedBotsOnline() +{ + QueryResult* result = QueryGroupedBots(); + if (!result) + return; + + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + uint32 botGuid = fields[0].GetUInt32(); + if (!GetEventValue(botGuid, "add")) + { + SetEventValue(botGuid, "add", 1, sPlayerbotAIConfig.maxRandomBotInWorldTime); + count++; + } + } while (result->NextRow()); + delete result; + + if (count > 0) + sLog.outString("Queued %u grouped bot(s) for login at startup", count); +} + uint32 RandomPlayerbotMgr::GetEventValue(uint32 bot, string event) { uint32 value = 0; diff --git a/src/modules/Bots/playerbot/RandomPlayerbotMgr.h b/src/modules/Bots/playerbot/RandomPlayerbotMgr.h index 16c13cd3f..875ebf818 100644 --- a/src/modules/Bots/playerbot/RandomPlayerbotMgr.h +++ b/src/modules/Bots/playerbot/RandomPlayerbotMgr.h @@ -4,6 +4,7 @@ #include "Common.h" #include "PlayerbotAIBase.h" #include "PlayerbotMgr.h" +#include class WorldPacket; class Player; @@ -205,6 +206,9 @@ class RandomPlayerbotMgr : public PlayerbotHolder void ScheduleRandomize(uint32 bot, uint32 time); void RandomTeleport(Player* bot, uint32 mapId, float teleX, float teleY, float teleZ); void RandomTeleportForLevel(Player* bot); + void EnsureGroupedBotsOnline(); + void LoadGroupedBots(); + QueryResult* QueryGroupedBots(); /** * @brief Teleports the given player bot to a random location. @@ -228,6 +232,7 @@ class RandomPlayerbotMgr : public PlayerbotHolder private: vector players; ///< List of players. int processTicks; ///< Number of process ticks. + set m_groupedBots; ///< Cached set of bot GUIDs currently in a group, refreshed each update cycle. std::map m_areaCreatureStatsMap; std::map, uint32> m_cellToAreaCache; }; diff --git a/src/modules/Bots/playerbot/aiplayerbot.conf.dist.in b/src/modules/Bots/playerbot/aiplayerbot.conf.dist.in index c4c291066..63c4bfb4d 100644 --- a/src/modules/Bots/playerbot/aiplayerbot.conf.dist.in +++ b/src/modules/Bots/playerbot/aiplayerbot.conf.dist.in @@ -161,6 +161,9 @@ AiPlayerbot.RandomBotTeleLevel = 3 # Log on all random bots on start #AiPlayerbot.RandomBotLoginAtStartup = 1 +# Preserve bot group assignments across server restarts +#AiPlayerbot.RandomBotKeepGroups = 0 + # How far random bots are teleported after death #AiPlayerbot.RandomBotTeleportDistance = 1000