From a1f9ff4542b0ff0bb4ff74ef088a718b8efc19dd Mon Sep 17 00:00:00 2001 From: Mat Date: Sat, 30 May 2026 15:48:29 +0200 Subject: [PATCH] fix bot leader handling (#2426) ## Pull Request Description This pr fixes bots "freaking out" after leader change and bots will promote player to party leader after give leader command closes #2420 #2424 ## Feature Evaluation - Describe the **minimum logic** required to achieve the intended behavior. - Describe the **processing cost** when this logic executes across many bots. ## How to Test the Changes 1. Join rdf or make group 2. Promote bot to leader (rnd or alt), if bot was not leader 3. Type /p give leader 4. Bot will promote you to leader and it will follow you instead of freaking out ## Impact Assessment - Does this change increase per-bot/per-tick processing or risk scaling poorly with thousands of bots? - - [x] No, not at all - - [ ] Minimal impact (**explain below**) - - [ ] Moderate impact (**explain below**) - Does this change modify default bot behavior? - - [ ] No - - [x] Yes (**explain why**) 1. Bots now reset their AI on every SMSG_GROUP_SET_LEADER packet, so old leader strategies get cleared after a leader change. 2. Random bots auto-bind their master to a real-player group member during reset botAI, so commands like give leader and follow logic that depend on HasActivePlayerMaster() start working for them. 3. On OnBotLogin, bots no longer steal leadership from a real player, they only force the leader change if the current leader is a bot or offline. - Does this change add new decision branches or increase maintenance complexity? - - [ ] No - - [x] Yes (**explain below**) Adds two small guards: an "is current leader a real player" check on login, and a "find first real-player member" loop inside ResetAiAction. Both reuse existing patterns (IsRealPlayer(), the OnPlayerLogin master-assign loop). ## AI Assistance Was AI assistance used while working on this change? - - [x] No - - [ ] Yes (**explain below**) ## Final Checklist - - [x] Stability is not compromised. - - [x] Performance impact is understood, tested, and acceptable. - - [x] Added logic complexity is justified and explained. - - [x] Any new bot dialogue lines are translated. - - [x] Documentation updated if needed (Conf comments, WiKi commands). ## Notes for Reviewers --- src/Ai/Base/Actions/ResetAiAction.cpp | 15 +++++++++++++++ .../Base/Strategy/WorldPacketHandlerStrategy.cpp | 2 +- src/Bot/PlayerbotMgr.cpp | 6 ------ src/Script/WorldThr/PlayerbotOperations.h | 1 + 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/Ai/Base/Actions/ResetAiAction.cpp b/src/Ai/Base/Actions/ResetAiAction.cpp index 19017c916..290d0ae11 100644 --- a/src/Ai/Base/Actions/ResetAiAction.cpp +++ b/src/Ai/Base/Actions/ResetAiAction.cpp @@ -44,6 +44,21 @@ bool ResetAiAction::Execute(Event event) } } } + if (Player* master = botAI->GetMaster()) + { + Group* botGroup = bot->GetGroup(); + Group* masterGroup = master->GetGroup(); + if (botGroup && (!masterGroup || masterGroup != botGroup)) + botAI->SetMaster(nullptr); + } + if (sRandomPlayerbotMgr.IsRandomBot(bot) && !bot->InBattleground()) + { + if (bot->GetGroup() && (!botAI->GetMaster() || GET_PLAYERBOT_AI(botAI->GetMaster()))) + { + if (Player* newMaster = botAI->FindNewMaster()) + botAI->SetMaster(newMaster); + } + } PlayerbotRepository::instance().Reset(botAI); botAI->ResetStrategies(false); botAI->TellMaster("AI was reset to defaults"); diff --git a/src/Ai/Base/Strategy/WorldPacketHandlerStrategy.cpp b/src/Ai/Base/Strategy/WorldPacketHandlerStrategy.cpp index ad31c2c39..5f2d2532d 100644 --- a/src/Ai/Base/Strategy/WorldPacketHandlerStrategy.cpp +++ b/src/Ai/Base/Strategy/WorldPacketHandlerStrategy.cpp @@ -16,7 +16,7 @@ void WorldPacketHandlerStrategy::InitTriggers(std::vector& trigger triggers.push_back( new TriggerNode("uninvite guid", { NextAction("uninvite", relevance) })); triggers.push_back( - new TriggerNode("group set leader", { /*NextAction("leader", relevance),*/ })); + new TriggerNode("group set leader", { NextAction("reset botAI", relevance) })); triggers.push_back(new TriggerNode( "not enough money", { NextAction("tell not enough money", relevance) })); triggers.push_back( diff --git a/src/Bot/PlayerbotMgr.cpp b/src/Bot/PlayerbotMgr.cpp index 0634bbf78..a6d4a3b79 100644 --- a/src/Bot/PlayerbotMgr.cpp +++ b/src/Bot/PlayerbotMgr.cpp @@ -481,12 +481,6 @@ void PlayerbotHolder::OnBotLogin(Player* const bot) } Player* master = botAI->GetMaster(); - if (master) - { - ObjectGuid masterGuid = master->GetGUID(); - if (master->GetGroup() && !master->GetGroup()->IsLeader(masterGuid)) - master->GetGroup()->ChangeLeader(masterGuid); - } Group* group = bot->GetGroup(); if (group) diff --git a/src/Script/WorldThr/PlayerbotOperations.h b/src/Script/WorldThr/PlayerbotOperations.h index ee6443cd8..cc62e7127 100644 --- a/src/Script/WorldThr/PlayerbotOperations.h +++ b/src/Script/WorldThr/PlayerbotOperations.h @@ -242,6 +242,7 @@ public: } group->ChangeLeader(newLeader->GetGUID()); + group->SendUpdate(); LOG_DEBUG("playerbots", "GroupSetLeaderOperation: Changed leader to {}", newLeader->GetName()); return true; }