From 681d2be68e3b701b84166fff6baf4667c40b094f Mon Sep 17 00:00:00 2001 From: agatho Date: Tue, 3 Feb 2026 06:34:51 +0100 Subject: [PATCH] fix(jit): Fix JIT bots not queuing for battlegrounds JIT-created bots were never being queued for BG because the onComplete callback tried to use ObjectAccessor::FindPlayer() before bots entered the world. Replaced direct callback queueing with deferred post-login queueing via BotPostLoginConfigurator (same pattern as LFG dungeons). Changes: - BotPostLoginConfigurator: Implement BG queueing after bot login - QueueStatePoller: Use battlegroundIdToQueue field instead of callback Co-Authored-By: Claude Opus 4.5 Signed-off-by: luis --- .../Instance/BotPostLoginConfigurator.cpp | 53 ++++++++++++++++++- .../Lifecycle/Instance/QueueStatePoller.cpp | 38 ++++++------- 2 files changed, 68 insertions(+), 23 deletions(-) diff --git a/src/modules/Playerbot/Lifecycle/Instance/BotPostLoginConfigurator.cpp b/src/modules/Playerbot/Lifecycle/Instance/BotPostLoginConfigurator.cpp index 455b75d43..76f3cabd5 100644 --- a/src/modules/Playerbot/Lifecycle/Instance/BotPostLoginConfigurator.cpp +++ b/src/modules/Playerbot/Lifecycle/Instance/BotPostLoginConfigurator.cpp @@ -11,6 +11,8 @@ #include "BotTemplateRepository.h" #include "Equipment/BotGearFactory.h" #include "LFG/LFGBotManager.h" +#include "PvP/BGBotManager.h" +#include "BattlegroundMgr.h" #include "Player.h" #include "Item.h" #include "Log.h" @@ -360,8 +362,55 @@ bool BotPostLoginConfigurator::ApplyPendingConfiguration(Player* player) } } - // TODO: Add battleground and arena queueing when needed - // if (config.battlegroundIdToQueue > 0) { ... } + // Step 8: Queue for battleground if this was a JIT-created bot + if (config.battlegroundIdToQueue > 0) + { + BattlegroundTypeId bgTypeId = static_cast(config.battlegroundIdToQueue); + TC_LOG_INFO("module.playerbot.configurator", + "Queueing JIT bot {} for battleground {} after configuration", + player->GetName(), config.battlegroundIdToQueue); + + // Get the BG template to find the map ID + BattlegroundTemplate const* bgTemplate = sBattlegroundMgr->GetBattlegroundTemplateByTypeId(bgTypeId); + if (bgTemplate && !bgTemplate->MapIDs.empty()) + { + // Determine bracket from bot's level + PVPDifficultyEntry const* bracketEntry = DB2Manager::GetBattlegroundBracketByLevel( + bgTemplate->MapIDs.front(), player->GetLevel()); + + if (bracketEntry) + { + BattlegroundBracketId bracketId = bracketEntry->GetBracketId(); + + if (sBGBotManager->QueueBotForBG(player, bgTypeId, bracketId)) + { + TC_LOG_INFO("module.playerbot.configurator", + "Successfully queued bot {} for BG {} bracket {}", + player->GetName(), config.battlegroundIdToQueue, static_cast(bracketId)); + } + else + { + TC_LOG_WARN("module.playerbot.configurator", + "Failed to queue bot {} for BG {}", + player->GetName(), config.battlegroundIdToQueue); + } + } + else + { + TC_LOG_WARN("module.playerbot.configurator", + "Could not determine BG bracket for bot {} (level {}) on map {}", + player->GetName(), player->GetLevel(), bgTemplate->MapIDs.front()); + } + } + else + { + TC_LOG_WARN("module.playerbot.configurator", + "Could not find BG template for type {}", + config.battlegroundIdToQueue); + } + } + + // TODO: Add arena queueing when needed // if (config.arenaTypeToQueue > 0) { ... } // Calculate timing diff --git a/src/modules/Playerbot/Lifecycle/Instance/QueueStatePoller.cpp b/src/modules/Playerbot/Lifecycle/Instance/QueueStatePoller.cpp index 245d17ca6..dda8bf774 100644 --- a/src/modules/Playerbot/Lifecycle/Instance/QueueStatePoller.cpp +++ b/src/modules/Playerbot/Lifecycle/Instance/QueueStatePoller.cpp @@ -660,17 +660,16 @@ void QueueStatePoller::ProcessBGShortage(BGQueueSnapshot const& snapshot) request.priority = priority; request.createdAt = std::chrono::system_clock::now(); - // Callback to queue the bot for BG after creation - request.onComplete = [bgTypeId = snapshot.bgTypeId, bracket = snapshot.bracketId](std::vector const& botGuids) { - for (ObjectGuid const& guid : botGuids) - { - if (Player* bot = ObjectAccessor::FindPlayer(guid)) - { - sBGBotManager->QueueBotForBG(bot, bgTypeId, bracket); - TC_LOG_DEBUG("playerbot.jit", "QueueStatePoller: JIT Alliance bot {} queued for BG type {}", - guid.ToString(), static_cast(bgTypeId)); - } - } + // Set BG ID for post-login queueing + // The BotPostLoginConfigurator will queue bots AFTER they're fully logged in + // This avoids the timing issue where ObjectAccessor::FindPlayer returns nullptr + // because the bots haven't entered the world yet when onComplete fires. + request.battlegroundIdToQueue = static_cast(snapshot.bgTypeId); + + // Callback for debugging (bots queue via BotPostLoginConfigurator, not here) + request.onComplete = [bgTypeId = snapshot.bgTypeId](std::vector const& botGuids) { + TC_LOG_INFO("playerbot.jit", "QueueStatePoller: {} JIT Alliance bots created for BG {} - they will auto-queue after login", + botGuids.size(), static_cast(bgTypeId)); }; uint32 requestId = sJITBotFactory->SubmitRequest(std::move(request)); @@ -693,16 +692,13 @@ void QueueStatePoller::ProcessBGShortage(BGQueueSnapshot const& snapshot) request.priority = priority; request.createdAt = std::chrono::system_clock::now(); - request.onComplete = [bgTypeId = snapshot.bgTypeId, bracket = snapshot.bracketId](std::vector const& botGuids) { - for (ObjectGuid const& guid : botGuids) - { - if (Player* bot = ObjectAccessor::FindPlayer(guid)) - { - sBGBotManager->QueueBotForBG(bot, bgTypeId, bracket); - TC_LOG_DEBUG("playerbot.jit", "QueueStatePoller: JIT Horde bot {} queued for BG type {}", - guid.ToString(), static_cast(bgTypeId)); - } - } + // Set BG ID for post-login queueing (same as Alliance - bracket determined by level) + request.battlegroundIdToQueue = static_cast(snapshot.bgTypeId); + + // Callback for debugging (bots queue via BotPostLoginConfigurator, not here) + request.onComplete = [bgTypeId = snapshot.bgTypeId](std::vector const& botGuids) { + TC_LOG_INFO("playerbot.jit", "QueueStatePoller: {} JIT Horde bots created for BG {} - they will auto-queue after login", + botGuids.size(), static_cast(bgTypeId)); }; uint32 requestId = sJITBotFactory->SubmitRequest(std::move(request));