Module BG BotFill : remplissage dynamique des champs de bataille par PlayerBots

Nouvelle cle pbotbg : active le remplissage des BG par bots (WS/AB/EY/AV/IC)
sans reveiller les bots de monde/LFG/arene (pbotall reste a 0).
- OnRealPlayerJoinBattlegroundQueue reecrit : bracket du joueur +
  QueryNeedPlayerCount (besoin reel) au lieu de 5 bots fixes par faction
- pbotbg_maxperteam : plafond de taille d equipe vise par le remplissage
- pbotbg_idlelogout : deconnexion des bots inactifs apres N secondes
- broadcast chinois remplace par un log, printf de debug supprime

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
SylvaniaCore deploy
2026-08-11 22:45:31 +02:00
parent 94b6fd654a
commit 6cc9f3a17a
5 changed files with 161 additions and 46 deletions
@@ -1282,7 +1282,7 @@ bool BattlegroundQueue::ExistRealPlayer(const PVPDifficultyEntry* bracketEntry,
return false;
}
bool BattlegroundQueue::QueryNeedPlayerCount(BattlegroundTypeId bgTypeID, BattlegroundBracketId bracket_id, uint32 aaType, int32& needAlliance, int32& needHorde)
bool BattlegroundQueue::QueryNeedPlayerCount(BattlegroundTypeId bgTypeID, BattlegroundBracketId bracket_id, uint32 aaType, int32& needAlliance, int32& needHorde, int32 teamSizeCap)
{
if (bracket_id >= MAX_BATTLEGROUND_BRACKETS)
return false;
@@ -1298,6 +1298,14 @@ bool BattlegroundQueue::QueryNeedPlayerCount(BattlegroundTypeId bgTypeID, Battle
maxNumber = aaType * 2;
needAlliance = maxNumber / 2;
needHorde = maxNumber / 2;
// SylvaniaCore (module BG BotFill): plafond configurable de taille d'equipe visee
if (teamSizeCap > 0 && !bg_template->isArena())
{
if (needAlliance > teamSizeCap)
needAlliance = teamSizeCap;
if (needHorde > teamSizeCap)
needHorde = teamSizeCap;
}
GroupsQueueType& groupQueueAlliance = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE];
for (GroupsQueueType::iterator itGroup = groupQueueAlliance.begin(); itGroup != groupQueueAlliance.end(); itGroup++)
{
@@ -100,7 +100,7 @@ class TC_GAME_API BattlegroundQueue
bool TryGatherPlayerByEnemyRatedArena(BattlegroundBracketId bracket_id, GroupQueueInfo* gInfo, bool needBroadcast = false);
void RatedArenaAllPlayerBotEnter(BattlegroundBracketId bracket_id);
bool ExistRealPlayer(const PVPDifficultyEntry* bracketEntry, bool isRated = false);
bool QueryNeedPlayerCount(BattlegroundTypeId bgTypeID, BattlegroundBracketId bracket_id, uint32 aaType, int32& needAlliance, int32& needHorde);
bool QueryNeedPlayerCount(BattlegroundTypeId bgTypeID, BattlegroundBracketId bracket_id, uint32 aaType, int32& needAlliance, int32& needHorde, int32 teamSizeCap = 0);
void AllPlayerBotLeaveQueueFromRatedArena(BattlegroundBracketId bracket_id);
typedef std::map<ObjectGuid, PlayerQueueInfo> QueuedPlayersMap;
QueuedPlayersMap m_QueuedPlayers;
+116 -44
View File
@@ -36,6 +36,7 @@
#include "CharacterPackets.h"
#include "MotionMaster.h"
#include <boost/algorithm/string.hpp>
#include <algorithm>
//#include <boost/format.hpp>
PlayerBotCharBaseInfo PlayerBotBaseInfo::empty;
@@ -1577,40 +1578,48 @@ void PlayerBotMgr::SupplementOneRandomPlayerBotPerAccount()
void PlayerBotMgr::OnRealPlayerJoinBattlegroundQueue(uint32 bgTypeId, uint32 level)
{
// SylvaniaCore (module BG BotFill): remplissage dynamique de la file selon le besoin
// reel du bracket du joueur (remplace l'ancien ajout fixe de 5 bots par faction)
bool botAll = sConfigMgr->GetIntDefault("pbotall", 1) != 0;
bool botBG = sConfigMgr->GetIntDefault("pbotbg", 0) != 0;
if (!botAll && !botBG)
return;
BattlegroundTypeId _bgTypeId = BattlegroundTypeId(bgTypeId);
BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(BattlegroundTypeId(bgTypeId), 0);
if (std::find(m_BGTypes.begin(), m_BGTypes.end(), _bgTypeId) == m_BGTypes.end())
return; // pas d'IA d'objectifs (CommandBG) pour ce BG
BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(_bgTypeId, 0);
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
Battleground* bg = sBattlegroundMgr->GetBattlegroundTemplate(BattlegroundTypeId(bgTypeId));
Battleground* bg = sBattlegroundMgr->GetBattlegroundTemplate(_bgTypeId);
if (!bg)
return;
uint32 needAlliancePlayerCount = 5;
uint32 needHordePlayerCount = 5;
uint32 _time = 0;
for (uint32 j = BattlegroundBracketId::BG_BRACKET_ID_FIRST; j <= BattlegroundBracketId::BG_BRACKET_ID_LAST; j++)
{
BattlegroundBracketId bracket = BattlegroundBracketId(j);
PVPDifficultyEntry const* bracketEntry = DB2Manager::GetBattlegroundBracketById(bg->GetMapId(), bracket);
if (!bracketEntry)
continue;
if (!bgQueue.ExistRealPlayer(bracketEntry))
continue;
if (needAlliancePlayerCount > 0)
{
for (uint32 k = 0; k <= needAlliancePlayerCount; k++)
AddNewPlayerBotToBG(TeamId::TEAM_ALLIANCE, bracketEntry->MinLevel, bracketEntry->MaxLevel, _bgTypeId);
}
if (needHordePlayerCount > 0)
{
for (uint32 k = 0; k <= needHordePlayerCount; k++)
AddNewPlayerBotToBG(TeamId::TEAM_HORDE, bracketEntry->MinLevel, bracketEntry->MaxLevel, _bgTypeId);
}
printf("QueryNeedPlayerCount %d %d \n", needAlliancePlayerCount, needHordePlayerCount);
PVPDifficultyEntry const* bracketEntry = sDB2Manager.GetBattlegroundBracketByLevel(bg->GetMapId(), level);
if (!bracketEntry)
return;
if (!bgQueue.ExistRealPlayer(bracketEntry))
return;
int32 needAlliance = 0;
int32 needHorde = 0;
int32 teamSizeCap = sConfigMgr->GetIntDefault("pbotbg_maxperteam", 0);
if (!bgQueue.QueryNeedPlayerCount(_bgTypeId, bracketEntry->GetBracketId(), 0, needAlliance, needHorde, teamSizeCap))
return;
int32 maxOnline = sConfigMgr->GetIntDefault("pbotasl", 88);
for (int32 k = 0; k < needAlliance + needHorde; ++k)
{
if (maxOnline > 0 && int32(GetOnlineBotCount(TeamId::TEAM_ALLIANCE, true) + GetOnlineBotCount(TeamId::TEAM_HORDE, true)) >= maxOnline)
break;
if (k < needAlliance)
AddNewPlayerBotToBG(TeamId::TEAM_ALLIANCE, bracketEntry->MinLevel, bracketEntry->MaxLevel, _bgTypeId);
else
AddNewPlayerBotToBG(TeamId::TEAM_HORDE, bracketEntry->MinLevel, bracketEntry->MaxLevel, _bgTypeId);
}
TC_LOG_INFO("bg.battleground", "BG BotFill: file bg %u (niveau %u, bracket %u-%u) -> engage %d bots Alliance / %d bots Horde",
bgTypeId, level, bracketEntry->MinLevel, bracketEntry->MaxLevel, needAlliance, needHorde);
}
void PlayerBotMgr::OnRealPlayerLeaveBattlegroundQueue(uint32 bgTypeId, uint32 level)
@@ -2420,9 +2429,7 @@ void PlayerBotMgr::AddNewPlayerBotToBG(TeamId team, uint32 minLV, uint32 maxLV,
}
}
std::string allonlineText;
consoleToUtf8(std::string("|cffff8800所有机器人账号已经全部在线,无法加入新机器人到战场中。|r"), allonlineText);
sWorld->SendGlobalText(allonlineText.c_str(), NULL);
TC_LOG_INFO("bg.battleground", "BG BotFill: tous les comptes bots sont deja occupes ou en ligne, aucun bot disponible");
}
void PlayerBotMgr::AddNewPlayerBotToLFG(lfg::LFGBotRequirement* botRequirement)
@@ -3031,6 +3038,7 @@ bool PlayerBotMgr::CanReadyArenaByArenaTeamID(uint32 arenaTeamId)
void PlayerBotMgr::QueryBattlegroundRequirement()
{
int32 teamSizeCap = sConfigMgr->GetIntDefault("pbotbg_maxperteam", 0);
for (BattleGroundTypes::iterator itType = m_BGTypes.begin(); itType != m_BGTypes.end(); itType++)
{
BattlegroundTypeId bgTypeID = *itType;
@@ -3047,9 +3055,14 @@ void PlayerBotMgr::QueryBattlegroundRequirement()
uint32 maxLV = bg->GetMaxLevel();
if (!bg->isRated() && bg->GetStatus() > STATUS_WAIT_QUEUE && bg->GetStatus() < STATUS_WAIT_LEAVE)
{
if (bg->GetFreeSlotsForTeam(Team::ALLIANCE) > 0 && bg->GetFreeSlotsForTeam(Team::ALLIANCE) >= bg->GetFreeSlotsForTeam(Team::HORDE))
// SylvaniaCore (module BG BotFill): respect du plafond pbotbg_maxperteam
bool allianceNeed = bg->GetFreeSlotsForTeam(Team::ALLIANCE) > 0
&& (teamSizeCap <= 0 || bg->GetPlayersCountByTeam(ALLIANCE) < uint32(teamSizeCap));
bool hordeNeed = bg->GetFreeSlotsForTeam(Team::HORDE) > 0
&& (teamSizeCap <= 0 || bg->GetPlayersCountByTeam(HORDE) < uint32(teamSizeCap));
if (allianceNeed && bg->GetFreeSlotsForTeam(Team::ALLIANCE) >= bg->GetFreeSlotsForTeam(Team::HORDE))
AddNewPlayerBotToBG(TeamId::TEAM_ALLIANCE, minLV, maxLV, bgTypeID);
else if (bg->GetFreeSlotsForTeam(Team::HORDE) > 0)
else if (hordeNeed)
AddNewPlayerBotToBG(TeamId::TEAM_HORDE, minLV, maxLV, bgTypeID);
else
continue;
@@ -3069,7 +3082,7 @@ void PlayerBotMgr::QueryBattlegroundRequirement()
continue;
int32 needAlliancePlayerCount = 0;
int32 needHordePlayerCount = 0;
if (bgQueue.QueryNeedPlayerCount(bgTypeID, bracket, 0, needAlliancePlayerCount, needHordePlayerCount))
if (bgQueue.QueryNeedPlayerCount(bgTypeID, bracket, 0, needAlliancePlayerCount, needHordePlayerCount, teamSizeCap))
{
if (needAlliancePlayerCount > 0 && needAlliancePlayerCount >= needHordePlayerCount)
AddNewPlayerBotToBG(TeamId::TEAM_ALLIANCE, bracketEntry->MinLevel, bracketEntry->MaxLevel, bgTypeID);
@@ -3341,30 +3354,89 @@ uint32 PlayerBotMgr::GetOnlineBotCount2(TeamId team, bool hasReal)
return onlineCount;
}
// SylvaniaCore (module BG BotFill): en mode pbotbg seul, un bot n'a de raison d'etre en
// ligne que pour un BG ; on deconnecte ceux qui restent inactifs trop longtemps.
void PlayerBotMgr::UpdateIdleBotLogout()
{
int32 idleLogout = sConfigMgr->GetIntDefault("pbotbg_idlelogout", 300);
if (idleLogout <= 0)
return;
if (m_LastIdleScanTick && GetMSTimeDiffToNow(m_LastIdleScanTick) < 5000)
return;
uint32 now = getMSTime();
m_LastIdleScanTick = now;
const SessionMap& allSession = sWorld->GetAllSessions();
for (SessionMap::const_iterator itSession = allSession.begin(); itSession != allSession.end(); itSession++)
{
WorldSession* session = itSession->second;
if (!session || !session->IsBotSession())
continue;
PlayerBotSession* pSession = dynamic_cast<PlayerBotSession*>(session);
if (!pSession || pSession->PlayerLoading() || pSession->IsAccountBotSession())
continue;
Player* player = pSession->GetPlayer();
if (!player || !player->IsInWorld() || player->IsLoading())
continue;
uint32 accId = session->GetAccountId();
bool busy = pSession->HasSchedules() || player->InBattleground() || player->InArena()
|| player->InBattlegroundQueue() || player->GetMap()->IsDungeon() || player->isUsingLfg()
|| player->IsInCombat();
if (busy)
{
m_BotIdleSince.erase(accId);
continue;
}
std::map<uint32, uint32>::iterator itIdle = m_BotIdleSince.find(accId);
if (itIdle == m_BotIdleSince.end())
{
m_BotIdleSince[accId] = now;
continue;
}
if (GetMSTimeDiffToNow(itIdle->second) >= uint32(idleLogout) * IN_MILLISECONDS)
{
m_BotIdleSince.erase(itIdle);
TC_LOG_INFO("bg.battleground", "BG BotFill: deconnexion du bot inactif (compte %u)", accId);
PlayerBotLogout(accId);
return; // un logout par passage, par prudence
}
}
}
void PlayerBotMgr::Update()
{
if (!sConfigMgr->GetIntDefault("pbotall", 1)) // SylvaniaCore: serveur sans bots -> tick bot inerte (evite crash #56 sur file BG/arene)
// SylvaniaCore (module BG BotFill): pbotall = systeme bot complet (monde/LFG/arene/BG),
// pbotbg = remplissage des champs de bataille uniquement
bool botAll = sConfigMgr->GetIntDefault("pbotall", 1) != 0;
bool botBG = sConfigMgr->GetIntDefault("pbotbg", 0) != 0;
if (!botAll && !botBG)
return;
OnlinePlayerBotByGUIDQueue();
//if (!ExistUnBGPlayerBot())
QueryBattlegroundRequirement();
if (!botAll)
UpdateIdleBotLogout();
#ifndef INCOMPLETE_BOT
//sArenaTeamMgr->CheckPlayerBotArenaTeam();
QueryRatedArenaRequirement();
QueryNonRatedArenaRequirement();
if (m_LFGSearchTick > 1)
if (botAll)
{
m_LFGSearchTick = 0;
if (lfg::LFGBotRequirement* pbotReq = sLFGMgr->SearchLFGBotRequirement())
//sArenaTeamMgr->CheckPlayerBotArenaTeam();
QueryRatedArenaRequirement();
QueryNonRatedArenaRequirement();
if (m_LFGSearchTick > 1)
{
AddNewPlayerBotToLFG(pbotReq);
delete pbotReq;
m_LFGSearchTick = 0;
if (lfg::LFGBotRequirement* pbotReq = sLFGMgr->SearchLFGBotRequirement())
{
AddNewPlayerBotToLFG(pbotReq);
delete pbotReq;
}
}
else
++m_LFGSearchTick;
}
else
++m_LFGSearchTick;
#endif
std::list<std::map<uint32, std::list<UnitAI*> >::iterator > delITer;
+3
View File
@@ -357,6 +357,8 @@ public:
bool CanReadyArenaByArenaTeamID(uint32 arenaTeamId);
void SetMax(int max) { m_MaxOnlineBot = max; }
int32 m_MaxOnlineBot;
uint32 m_LastIdleScanTick = 0;
std::map<uint32, uint32> m_BotIdleSince;
int32 m_BotOnlineCount;
private:
@@ -388,6 +390,7 @@ private:
bool FillOnlineBotScheduleByLFGRequirement(lfg::LFGBotRequirement* botRequirement, BotGlobleSchedule* botSchedule);
uint32 GetScheduleTalentByLFGRequirement(lfg::LfgRoles roles, uint32 botCls);
void QueryBattlegroundRequirement();
void UpdateIdleBotLogout();
void QueryRatedArenaRequirement();
void QueryNonRatedArenaRequirement();
void OnlinePlayerBotByGUIDQueue();
@@ -4576,6 +4576,38 @@ LFGnumPlayer_Add = 0
pbotall = 1
###################################################################################################
# MODULE BG BOTFILL (SylvaniaCore)
#
# pbotbg
# Description: Remplissage des champs de bataille par PlayerBots quand des joueurs
# reels sont en file (WS / AB / EY / AV / IC), sans activer les bots
# de monde, LFG ni arene (independant de pbotall).
# Default: 0 - Desactive
# 1 - Active
#
pbotbg = 0
#
# pbotbg_maxperteam
# Description: Taille equipe visee par le remplissage (joueurs reels + bots).
# 0 = taille maximale du BG (10v10 WS, 15v15 AB, 40v40 AV...)
# Default: 0
#
pbotbg_maxperteam = 0
#
# pbotbg_idlelogout
# Description: Deconnexion d un bot reste inactif (hors BG, file, donjon, combat)
# pendant N secondes. 0 = jamais.
# Default: 300
#
pbotbg_idlelogout = 300
#
# PlayerBot Maximum Online Limit
#