diff --git a/src/server/game/Battlegrounds/BattlegroundQueue.cpp b/src/server/game/Battlegrounds/BattlegroundQueue.cpp index 2833402..55769e9 100644 --- a/src/server/game/Battlegrounds/BattlegroundQueue.cpp +++ b/src/server/game/Battlegrounds/BattlegroundQueue.cpp @@ -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++) { diff --git a/src/server/game/Battlegrounds/BattlegroundQueue.h b/src/server/game/Battlegrounds/BattlegroundQueue.h index 5d91de8..9523c51 100644 --- a/src/server/game/Battlegrounds/BattlegroundQueue.h +++ b/src/server/game/Battlegrounds/BattlegroundQueue.h @@ -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 QueuedPlayersMap; QueuedPlayersMap m_QueuedPlayers; diff --git a/src/server/game/PlayerBot/PlayerBotMgr.cpp b/src/server/game/PlayerBot/PlayerBotMgr.cpp index 9736893..6b35043 100644 --- a/src/server/game/PlayerBot/PlayerBotMgr.cpp +++ b/src/server/game/PlayerBot/PlayerBotMgr.cpp @@ -36,6 +36,7 @@ #include "CharacterPackets.h" #include "MotionMaster.h" #include +#include //#include 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(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::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 >::iterator > delITer; diff --git a/src/server/game/PlayerBot/PlayerBotMgr.h b/src/server/game/PlayerBot/PlayerBotMgr.h index 79c36d9..2409fb3 100644 --- a/src/server/game/PlayerBot/PlayerBotMgr.h +++ b/src/server/game/PlayerBot/PlayerBotMgr.h @@ -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 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(); diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index ba0c7ff..c3e89c2 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -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 #