From 8529654f8fc4be92344bf079d65a215fea3b608c Mon Sep 17 00:00:00 2001 From: bashermens <31279994+hermensbas@users.noreply.github.com> Date: Sun, 1 Feb 2026 10:18:59 +0100 Subject: [PATCH] Correction after singleton PR (#2095) # Pull Request Some logic was changed but differs from the original code, certain edge cases so not result in same behavior. This returns the original code with only the singleton chances. @Wishmaster117 Reviewed the hotfix and noticed the different code paths. ps: reverted an removed placeholder since its ongoing issue/research. --- src/Script/Playerbots.cpp | 46 +++++++++++++++++++++++ src/Script/WorldThr/PlayerbotOperations.h | 32 +++++----------- 2 files changed, 56 insertions(+), 22 deletions(-) diff --git a/src/Script/Playerbots.cpp b/src/Script/Playerbots.cpp index 065ccb87..c4487f89 100644 --- a/src/Script/Playerbots.cpp +++ b/src/Script/Playerbots.cpp @@ -124,6 +124,52 @@ public: } } + bool OnPlayerBeforeTeleport(Player* /*player*/, uint32 /*mapid*/, float /*x*/, float /*y*/, float /*z*/, + float /*orientation*/, uint32 /*options*/, Unit* /*target*/) override + { + /* for now commmented out until proven its actually required + * havent seen any proof CleanVisibilityReferences() is needed + + // If the player is not safe to touch, do nothing + if (!player) + return true; + + // If same map or not in world do nothing + if (!player->IsInWorld() || player->GetMapId() == mapid) + return true; + + // If real player do nothing + PlayerbotAI* ai = GET_PLAYERBOT_AI(player); + if (!ai || ai->IsRealPlayer()) + return true; + + // Cross-map bot teleport: defer visibility reference cleanup. + // CleanVisibilityReferences() erases this bot's GUID from other objects' visibility containers. + // This is intentionally done via the event queue (instead of directly here) because erasing + // from other players' visibility maps inside the teleport call stack can hit unsafe re-entrancy + // or iterator invalidation while visibility updates are in progress + ObjectGuid guid = player->GetGUID(); + player->m_Events.AddEventAtOffset( + [guid, mapid]() + { + // do nothing, if the player is not safe to touch + Player* p = ObjectAccessor::FindPlayer(guid); + if (!p || !p->IsInWorld() || p->IsDuringRemoveFromWorld()) + return; + + // do nothing if we are already on the target map + if (p->GetMapId() == mapid) + return; + + p->GetObjectVisibilityContainer().CleanVisibilityReferences(); + }, + Milliseconds(0)); + + */ + + return true; + } + void OnPlayerAfterUpdate(Player* player, uint32 diff) override { PlayerbotAI* const botAI = PlayerbotsMgr::instance().GetPlayerbotAI(player); diff --git a/src/Script/WorldThr/PlayerbotOperations.h b/src/Script/WorldThr/PlayerbotOperations.h index 49020702..a80321d5 100644 --- a/src/Script/WorldThr/PlayerbotOperations.h +++ b/src/Script/WorldThr/PlayerbotOperations.h @@ -479,35 +479,23 @@ public: bool Execute() override { // find and verify bot still exists - Player* bot = ObjectAccessor::FindConnectedPlayer(this->m_botGuid); - + Player* bot = ObjectAccessor::FindConnectedPlayer(m_botGuid); if (!bot) - { return false; - } - if (this->m_masterAccountId) + PlayerbotHolder* holder = &RandomPlayerbotMgr::instance(); + if (m_masterAccountId) { - WorldSession* masterSession = sWorldSessionMgr->FindSession(this->m_masterAccountId); + WorldSession* masterSession = sWorldSessionMgr->FindSession(m_masterAccountId); Player* masterPlayer = masterSession ? masterSession->GetPlayer() : nullptr; - - if (masterPlayer != nullptr) - { - PlayerbotMgr* manager = PlayerbotsMgr::instance().GetPlayerbotMgr(masterPlayer); - - if (manager == nullptr) - { - return false; - } - - manager->OnBotLogin(bot); - } - } - else - { - sRandomPlayerbotMgr.OnBotLogin(bot); + if (masterPlayer) + holder = PlayerbotsMgr::instance().GetPlayerbotMgr(masterPlayer); } + if (!holder) + return false; + + holder->OnBotLogin(bot); return true; }