fix(spawner): Allow warm pool bots to bypass MaxBots limit

Warm pool and JIT bots for BG/dungeon/arena are temporary special-purpose
bots that should not be blocked by the MaxBots configuration setting.

Changes:
- Add bypassMaxBotsLimit field to SpawnRequest struct
- Pass bypassMaxBotsLimit through BotSpawner chain to AddPlayerBot
- Set bypassMaxBotsLimit=true in InstanceBotPool::WarmUpBot

This fixes the issue where setting MaxBots=0 (to disable world population
bots) also blocked warm pool bots from spawning for battleground queues.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
This commit is contained in:
agatho
2026-02-04 20:34:08 -03:00
committed by luis
co-authored by Claude Opus 4.5
parent c58145d6d2
commit 9f10b1a1ef
4 changed files with 34 additions and 7 deletions
+31 -6
View File
@@ -62,6 +62,7 @@
#include "MotionMaster.h"
#include "RealmList.h"
#include "DB2Stores.h"
#include "DBCEnums.h" // WoW 12.0: MAP_WOWLABS, MAP_HOUSE_INTERIOR, MAP_HOUSE_NEIGHBORHOOD
#include "WorldSession.h"
#include "Movement/BotWorldPositioner.h"
#include <algorithm>
@@ -657,9 +658,10 @@ bool BotSpawner::SpawnBotInternal(SpawnRequest const& request)
}
}
bool BotSpawner::CreateBotSession(uint32 accountId, ObjectGuid characterGuid)
bool BotSpawner::CreateBotSession(uint32 accountId, ObjectGuid characterGuid, bool bypassMaxBotsLimit)
{
TC_LOG_INFO("module.playerbot.spawner", " Creating bot session for account {}, character {}", accountId, characterGuid.ToString());
TC_LOG_INFO("module.playerbot.spawner", " Creating bot session for account {}, character {}, bypassLimit={}",
accountId, characterGuid.ToString(), bypassMaxBotsLimit);
// DISABLED: Legacy BotSessionMgr creates invalid account IDs
// Use the BotSessionMgr to create a new bot session with ASYNC character login (legacy approach)
@@ -672,7 +674,8 @@ bool BotSpawner::CreateBotSession(uint32 accountId, ObjectGuid characterGuid)
// }
// PRIMARY: Use the fixed native TrinityCore login approach with proper account IDs
if (!Playerbot::sBotWorldSessionMgr->AddPlayerBot(characterGuid, accountId))
// Pass bypassMaxBotsLimit for pool/JIT bots that should bypass MaxBots config
if (!Playerbot::sBotWorldSessionMgr->AddPlayerBot(characterGuid, accountId, bypassMaxBotsLimit))
{
TC_LOG_ERROR("module.playerbot.spawner",
" Failed to create native WorldSession for character {}", characterGuid.ToString());
@@ -1085,10 +1088,11 @@ void BotSpawner::ContinueSpawnWithCharacter(ObjectGuid characterGuid, SpawnReque
return;
}
TC_LOG_INFO("module.playerbot.spawner", " Continuing spawn with character {} for account {}", characterGuid.ToString(), actualAccountId);
TC_LOG_INFO("module.playerbot.spawner", " Continuing spawn with character {} for account {} (bypassLimit={})",
characterGuid.ToString(), actualAccountId, request.bypassMaxBotsLimit);
// Create bot session
if (!CreateBotSession(actualAccountId, characterGuid))
// Create bot session - pass bypassMaxBotsLimit for pool/JIT bots
if (!CreateBotSession(actualAccountId, characterGuid, request.bypassMaxBotsLimit))
{
TC_LOG_ERROR("module.playerbot.spawner",
"Failed to create bot session for character {}", characterGuid.ToString());
@@ -1401,6 +1405,27 @@ bool BotSpawner::CanSpawnInZone(uint32 zoneId) const
bool BotSpawner::CanSpawnOnMap(uint32 mapId) const
{
// WoW 12.0: Check map type exclusions for housing and WowLabs maps
MapEntry const* mapEntry = sMapStore.LookupEntry(mapId);
if (mapEntry)
{
// Exclude housing maps (player housing interiors and neighborhoods)
// Exclude WowLabs maps (Plunderstorm and experimental game modes)
switch (mapEntry->InstanceType)
{
case MAP_WOWLABS: // Plunderstorm/experimental
case MAP_HOUSE_INTERIOR: // Player housing interior
case MAP_HOUSE_NEIGHBORHOOD: // Player housing neighborhood
TC_LOG_DEBUG("module.playerbot.spawner",
"CanSpawnOnMap: Rejecting map {} - map type {} is excluded (housing/WowLabs)",
mapId, static_cast<uint32>(mapEntry->InstanceType));
return false;
default:
break;
}
}
// Check population cap
uint32 mapBotCount = 0;
for (auto const& [zoneId, population] : _zonePopulations)
{
+1 -1
View File
@@ -200,7 +200,7 @@ private:
// Internal spawning
bool SpawnBotInternal(SpawnRequest const& request);
bool CreateBotSession(uint32 accountId, ObjectGuid characterGuid);
bool CreateBotSession(uint32 accountId, ObjectGuid characterGuid, bool bypassMaxBotsLimit = false);
bool ValidateSpawnRequest(SpawnRequest const& request) const;
// Phase 2: Priority assignment for spawn requests
@@ -1773,6 +1773,7 @@ bool InstanceBotPool::WarmUpBot(ObjectGuid botGuid)
request.type = SpawnRequest::SPECIFIC_CHARACTER;
request.accountId = accountId;
request.characterGuid = botGuid;
request.bypassMaxBotsLimit = true; // Pool bots bypass MaxBots limit - they're temporary for BG/dungeon/arena
request.callback = [this, botGuid](bool success, ObjectGuid guid) {
if (success)
{
@@ -31,6 +31,7 @@ struct SpawnRequest
uint8 classFilter = 0;
uint8 raceFilter = 0;
uint32 maxBotsPerZone = 50;
bool bypassMaxBotsLimit = false; // For pool/JIT bots that should bypass MaxBots config
// Callback on spawn completion
::std::function<void(bool success, ObjectGuid guid)> callback;