From 872e4176137b66c83ebcb03932fa8ff1e39fd791 Mon Sep 17 00:00:00 2001 From: Alex Dcnh <140754794+Wishmaster117@users.noreply.github.com> Date: Sun, 10 Aug 2025 21:23:02 +0200 Subject: [PATCH] Playerbots/LFG: fix false not eligible & dungeon 0/type 0, add clear diagnostics (#1521) Tested --- src/PlayerbotMgr.cpp | 18 ++++-- src/Playerbots.cpp | 133 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 145 insertions(+), 6 deletions(-) diff --git a/src/PlayerbotMgr.cpp b/src/PlayerbotMgr.cpp index 0b6d3967..182177c2 100644 --- a/src/PlayerbotMgr.cpp +++ b/src/PlayerbotMgr.cpp @@ -529,6 +529,9 @@ void PlayerbotHolder::OnBotLogin(Player* const bot) { botAI->ResetStrategies(!sRandomPlayerbotMgr->IsRandomBot(bot)); } + + botAI->Reset(true); // Reset transient states (incl. LFG "proposal") to avoid the "one or more players are not eligible" error after reconnect. + sPlayerbotDbStore->Load(botAI); if (master && !master->HasUnitState(UNIT_STATE_IN_FLIGHT)) @@ -548,16 +551,21 @@ void PlayerbotHolder::OnBotLogin(Player* const bot) if (master && master->GetGroup() && !group) { Group* mgroup = master->GetGroup(); - if (mgroup->GetMembersCount() >= 5) + // if (mgroup->GetMembersCount() >= 5) + if (mgroup->GetMembersCount() + 1 > 5) // only convert in raid if the add of THIS bot make group > 5 { if (!mgroup->isRaidGroup() && !mgroup->isLFGGroup() && !mgroup->isBGGroup() && !mgroup->isBFGroup()) { mgroup->ConvertToRaid(); } - if (mgroup->isRaidGroup()) - { - mgroup->AddMember(bot); - } + //if (mgroup->isRaidGroup()) + //{ + //mgroup->AddMember(bot); + //} + mgroup->AddMember(bot); + + LOG_DEBUG("playerbots", "[GROUP] after add: members={}, isRaid={}, isLFG={}", + (int)mgroup->GetMembersCount(), mgroup->isRaidGroup() ? 1 : 0, mgroup->isLFGGroup() ? 1 : 0); } else { diff --git a/src/Playerbots.cpp b/src/Playerbots.cpp index 13b04e0e..e39171b1 100644 --- a/src/Playerbots.cpp +++ b/src/Playerbots.cpp @@ -30,6 +30,7 @@ #include "cs_playerbots.h" #include "cmath" #include "BattleGroundTactics.h" +#include "ObjectAccessor.h" class PlayerbotsDatabaseScript : public DatabaseScript { @@ -311,7 +312,7 @@ class PlayerbotsScript : public PlayerbotScript public: PlayerbotsScript() : PlayerbotScript("PlayerbotsScript") {} - bool OnPlayerbotCheckLFGQueue(lfg::Lfg5Guids const& guidsList) override + /*bool OnPlayerbotCheckLFGQueue(lfg::Lfg5Guids const& guidsList) override { bool nonBotFound = false; for (ObjectGuid const& guid : guidsList.guids) @@ -325,7 +326,137 @@ public: } return nonBotFound; + }*/ + + // New LFG Function + bool OnPlayerbotCheckLFGQueue(lfg::Lfg5Guids const& guidsList) + { + const size_t totalSlots = guidsList.guids.size(); + size_t ignoredEmpty = 0, ignoredNonPlayer = 0; + size_t offlinePlayers = 0, botPlayers = 0, realPlayers = 0; + bool groupGuidSeen = false; + + LOG_DEBUG("playerbots", "[LFG] check start: slots={}", totalSlots); + + for (size_t i = 0; i < totalSlots; ++i) + { + ObjectGuid const& guid = guidsList.guids[i]; + + // 1) Placeholders to ignore + if (guid.IsEmpty()) + { + ++ignoredEmpty; + LOG_DEBUG("playerbots", "[LFG] slot {}: -> ignored", i); + continue; + } + + // Group GUID: in the original implementation this counted as "non-bot found" + if (guid.IsGroup()) + { + groupGuidSeen = true; + LOG_DEBUG("playerbots", "[LFG] slot {}: -> counts as having a real player (compat)", i); + continue; + } + + // Other non-Player GUIDs: various placeholders, ignore them + if (!guid.IsPlayer()) + { + ++ignoredNonPlayer; + LOG_DEBUG("playerbots", "[LFG] slot {}: guid={} (non-player/high={}) -> ignored", i, + static_cast(guid.GetRawValue()), (unsigned)guid.GetHigh()); + continue; + } + + // 2) Player present? + Player* player = ObjectAccessor::FindPlayer(guid); + if (!player) + { + ++offlinePlayers; + LOG_DEBUG("playerbots", "[LFG] slot {}: player guid={} is offline/not in world", i, + static_cast(guid.GetRawValue())); + continue; + } + + // 3) Bot or real player? + if (GET_PLAYERBOT_AI(player) != nullptr) + { + ++botPlayers; + LOG_DEBUG("playerbots", "[LFG] slot {}: BOT {} (lvl {}, class {})", i, player->GetName().c_str(), + player->GetLevel(), player->getClass()); + } + else + { + ++realPlayers; + LOG_DEBUG("playerbots", "[LFG] slot {}: REAL {} (lvl {}, class {})", i, player->GetName().c_str(), + player->GetLevel(), player->getClass()); + } + } + + // "Ultra-early phase" detection: only placeholders => DO NOT VETO + const bool onlyPlaceholders = (realPlayers + botPlayers + (groupGuidSeen ? 1 : 0)) == 0 && + (ignoredEmpty + ignoredNonPlayer) == totalSlots; + + // "Soft" LFG preflight if we actually see players AND at least one offline + if (!onlyPlaceholders && offlinePlayers > 0) + { + // Find a plausible leader: prefer a real online player, otherwise any online player + Player* leader = nullptr; + + for (ObjectGuid const& guid : guidsList.guids) + if (guid.IsPlayer()) + if (Player* p = ObjectAccessor::FindPlayer(guid)) + if (GET_PLAYERBOT_AI(p) == nullptr) + { + leader = p; + break; + } + + if (!leader) + for (ObjectGuid const& guid : guidsList.guids) + if (guid.IsPlayer()) + if (Player* p = ObjectAccessor::FindPlayer(guid)) + { + leader = p; + break; + } + + if (leader) + { + Group* g = leader->GetGroup(); + if (g) + { + LOG_DEBUG("playerbots", "[LFG-RESET] group members={}, isRaid={}, isLFGGroup={}", + (int)g->GetMembersCount(), g->isRaidGroup() ? 1 : 0, g->isLFGGroup() ? 1 : 0); + + // "Soft" reset of LFG states on the bots' AI side (proposal/role-check, etc.) + for (GroupReference* ref = g->GetFirstMember(); ref; ref = ref->next()) + { + Player* member = ref->GetSource(); + if (!member) + continue; + + if (PlayerbotAI* ai = GET_PLAYERBOT_AI(member)) + ai->Reset(true); + } + } + } + + LOG_DEBUG("playerbots", "[LFG] preflight soft-reset triggered (offline detected) -> allowQueue=no (retry)"); + return false; // ask the client to retry right after the reset + } + + // "Hybrid" policy: permissive if only placeholders; otherwise original logic + bool allowQueue = onlyPlaceholders ? true : ((offlinePlayers == 0) && (realPlayers >= 1 || groupGuidSeen)); + + LOG_DEBUG("playerbots", + "[LFG] summary: slots={}, real={}, bots={}, offline={}, ignored(empty+nonPlayer)={}, " + "groupGuidSeen={} -> allowQueue={}", + totalSlots, realPlayers, botPlayers, offlinePlayers, (ignoredEmpty + ignoredNonPlayer), + (groupGuidSeen ? "yes" : "no"), (allowQueue ? "yes" : "no")); + + return allowQueue; } + // End LFG void OnPlayerbotCheckKillTask(Player* player, Unit* victim) override {