Skip to content

Commit 88144ef

Browse files
authored
Refactor code for updating battleground queues (#3057)
1 parent 38bfb83 commit 88144ef

2 files changed

Lines changed: 185 additions & 131 deletions

File tree

src/game/Battlegrounds/BattleGroundMgr.cpp

Lines changed: 180 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -630,67 +630,68 @@ bool BattleGroundQueue::CheckNormalMatch(BattleGroundBracketId bracketId, uint32
630630
return m_selectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() >= minPlayers && m_selectionPools[BG_TEAM_HORDE].GetPlayerCount() >= minPlayers;
631631
}
632632

633-
/*
634-
this method is called when group is inserted, or player / group is removed from BG Queue - there is only one player's status changed, so we don't use while(true) cycles to invite whole queue
635-
it must be called after fully adding the members of a group to ensure group joining
636-
should be called from BattleGround::RemovePlayer function in some cases
637-
*/
638-
void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BattleGroundBracketId bracketId)
633+
void BattleGroundQueue::RemoveOfflinePlayer()
639634
{
640-
//ACE_Guard<ACE_Recursive_Thread_Mutex> guard(m_lock);
641-
642-
// First, remove players who shouldn't be in queue anymore
643-
QueuedPlayersMap::iterator itrOffline = m_queuedPlayers.begin();
644-
while (itrOffline != m_queuedPlayers.end())
635+
for (auto itr = m_queuedPlayers.begin(); itr != m_queuedPlayers.end();)
645636
{
646-
// remove offline players
647-
if (!itrOffline->second.online && WorldTimer::getMSTimeDiffToNow(itrOffline->second.lastOnlineTime) > OFFLINE_BG_QUEUE_TIME)
637+
bool remove = false;
638+
639+
if (!itr->second.online && WorldTimer::getMSTimeDiffToNow(itr->second.lastOnlineTime) > OFFLINE_BG_QUEUE_TIME)
648640
{
649-
RemovePlayer(itrOffline->first, true);
650-
itrOffline = m_queuedPlayers.begin();
651-
continue;
641+
remove = true;
652642
}
653-
654-
// remove players who are in queue for bg that has ended
655-
GroupQueueInfo* group = itrOffline->second.groupInfo;
656-
if (group->isInvitedToBgInstanceGuid)
643+
else if (GroupQueueInfo* group = itr->second.groupInfo)
657644
{
658-
BattleGround* bg;
659-
if ((bg = sBattleGroundMgr.GetBattleGround(group->isInvitedToBgInstanceGuid, group->bgTypeId)) && bg->GetStatus() == STATUS_WAIT_LEAVE)
645+
if (group->isInvitedToBgInstanceGuid)
660646
{
661-
if (itrOffline->second.online)
647+
if (BattleGround* bg = sBattleGroundMgr.GetBattleGround(group->isInvitedToBgInstanceGuid, group->bgTypeId))
662648
{
663-
if (Player* player = ObjectAccessor::FindPlayerNotInWorld(itrOffline->first))
649+
if (bg->GetStatus() == STATUS_WAIT_LEAVE)
664650
{
665-
BattleGroundQueueTypeId queueTypeId = BattleGroundMgr::BgQueueTypeId(group->bgTypeId);
666-
uint32 queueSlot = player->GetBattleGroundQueueIndex(queueTypeId);
667-
if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES)
651+
if (itr->second.online)
668652
{
669-
player->RemoveBattleGroundQueueId(queueTypeId);
670-
671-
WorldPacket data;
672-
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0);
673-
player->GetSession()->SendPacket(&data);
653+
if (Player* player = ObjectAccessor::FindPlayerNotInWorld(itr->first))
654+
{
655+
BattleGroundQueueTypeId queueTypeId = BattleGroundMgr::BgQueueTypeId(group->bgTypeId);
656+
uint32 queueSlot = player->GetBattleGroundQueueIndex(queueTypeId);
657+
if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES)
658+
{
659+
player->RemoveBattleGroundQueueId(queueTypeId);
660+
661+
WorldPacket data;
662+
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0);
663+
player->GetSession()->SendPacket(&data);
664+
}
665+
}
674666
}
667+
668+
remove = true;
675669
}
676670
}
677-
678-
RemovePlayer(itrOffline->first, true);
679-
itrOffline = m_queuedPlayers.begin();
680-
continue;
681671
}
682672
}
683673

684-
++itrOffline;
674+
if (remove)
675+
{
676+
itr = m_queuedPlayers.erase(itr);
677+
}
678+
else
679+
{
680+
++itr;
681+
}
685682
}
683+
}
686684

687-
// if no players in queue - do nothing
688-
if (m_queuedGroups[bracketId][BG_QUEUE_PREMADE_ALLIANCE].empty() &&
689-
m_queuedGroups[bracketId][BG_QUEUE_PREMADE_HORDE].empty() &&
690-
m_queuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE].empty() &&
691-
m_queuedGroups[bracketId][BG_QUEUE_NORMAL_HORDE].empty())
692-
return;
685+
bool BattleGroundQueue::HasPlayersInQueue(BattleGroundBracketId bracketId)
686+
{
687+
return !(m_queuedGroups[bracketId][BG_QUEUE_PREMADE_ALLIANCE].empty() &&
688+
m_queuedGroups[bracketId][BG_QUEUE_PREMADE_HORDE].empty() &&
689+
m_queuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE].empty() &&
690+
m_queuedGroups[bracketId][BG_QUEUE_NORMAL_HORDE].empty());
691+
}
693692

693+
void BattleGroundQueue::CheckFreeSlots(BattleGroundTypeId bgTypeId, BattleGroundBracketId bracketId)
694+
{
694695
if (sWorld.getConfig(CONFIG_BOOL_BATTLEGROUND_RANDOMIZE))
695696
{
696697
auto seed = std::chrono::system_clock::now().time_since_epoch().count();
@@ -702,145 +703,193 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BattleGroundBracketI
702703
std::default_random_engine(seed));
703704
}
704705

705-
// battleground with free slot for player should be always in the beginning of the queue
706-
// maybe it would be better to create bgfreeslotqueue for each bracketId
707-
BgFreeSlotQueueType::iterator itr, next;
708-
for (itr = sBattleGroundMgr.m_bgFreeSlotQueue[bgTypeId].begin(); itr != sBattleGroundMgr.m_bgFreeSlotQueue[bgTypeId].end(); itr = next)
706+
std::vector<BattleGround*> fullBattlegrounds;
707+
708+
for (const auto pBattleGround : sBattleGroundMgr.m_bgFreeSlotQueue[bgTypeId])
709709
{
710-
next = itr;
711-
++next;
712-
// battleground is running, so if:
713-
if ((*itr)->GetTypeID() == bgTypeId && (*itr)->GetBracketId() == bracketId &&
714-
(*itr)->GetStatus() > STATUS_WAIT_QUEUE && (*itr)->GetStatus() < STATUS_WAIT_LEAVE)
710+
if (pBattleGround->GetTypeID() != bgTypeId || pBattleGround->GetBracketId() != bracketId)
711+
continue;
712+
713+
if (pBattleGround->GetStatus() <= STATUS_WAIT_QUEUE || pBattleGround->GetStatus() >= STATUS_WAIT_LEAVE)
714+
continue;
715+
716+
if (!pBattleGround->HasFreeSlots())
715717
{
716-
BattleGround* bg = *itr; //we have to store battleground pointer here, because when battleground is full, it is removed from free queue (not yet implemented!!)
717-
// and iterator is invalid
718+
fullBattlegrounds.push_back(pBattleGround);
719+
continue;
720+
}
718721

719-
// clear selection pools
720-
m_selectionPools[BG_TEAM_ALLIANCE].Init();
721-
m_selectionPools[BG_TEAM_HORDE].Init();
722+
m_selectionPools[BG_TEAM_ALLIANCE].Init();
723+
m_selectionPools[BG_TEAM_HORDE].Init();
722724

723-
// call a function that does the job for us
724-
FillPlayersToBg(bg, bracketId);
725+
FillPlayersToBg(pBattleGround, bracketId);
725726

726-
// now everything is set, invite players
727-
for (const auto itr : m_selectionPools[BG_TEAM_ALLIANCE].selectedGroups)
728-
InviteGroupToBG(itr, bg, itr->groupTeam);
729-
for (const auto itr : m_selectionPools[BG_TEAM_HORDE].selectedGroups)
730-
InviteGroupToBG(itr, bg, itr->groupTeam);
727+
for (const auto& group : m_selectionPools[BG_TEAM_ALLIANCE].selectedGroups)
728+
InviteGroupToBG(group, pBattleGround, group->groupTeam);
729+
for (const auto& group : m_selectionPools[BG_TEAM_HORDE].selectedGroups)
730+
InviteGroupToBG(group, pBattleGround, group->groupTeam);
731731

732-
if (!bg->HasFreeSlots())
733-
{
734-
// remove BG from m_bgFreeSlotQueue
735-
bg->RemoveFromBGFreeSlotQueue();
736-
}
732+
if (!pBattleGround->HasFreeSlots())
733+
{
734+
fullBattlegrounds.push_back(pBattleGround);
737735
}
738736
}
739737

740-
// finished iterating through the bgs with free slots, maybe we need to create a new bg
738+
for (const auto& pBattleGround : fullBattlegrounds)
739+
{
740+
sLog.Out(LOG_BASIC, LOG_LVL_MINIMAL, "[BattleGroundQueue::Update] removing full bg from m_bgFreeSlotQueue");
741+
pBattleGround->RemoveFromBGFreeSlotQueue();
742+
}
743+
}
744+
745+
bool BattleGroundQueue::CheckCreateNewBg(BattleGroundTypeId bgTypeId, BattleGroundBracketId bracketId)
746+
{
747+
bool createdPremadeBg = false;
748+
bool createdNormalBg = false;
741749

742-
BattleGround* bgTemplate = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
750+
BattleGround* bgTemplate = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
743751
if (!bgTemplate)
744752
{
745-
sLog.Out(LOG_BASIC, LOG_LVL_ERROR, "Battleground: Update: bg template not found for %u", bgTypeId);
746-
return;
753+
sLog.Out(LOG_BASIC, LOG_LVL_ERROR, "[BattleGroundQueue::CheckCreateNewBg] template not found for %u", bgTypeId);
754+
return false;
747755
}
748-
// get the min. players per team, properly for larger arenas as well.
756+
757+
// Get the min/max players per team
749758
uint32 minPlayersPerTeam = bgTemplate->GetMinPlayersPerTeam();
750759
uint32 maxPlayersPerTeam = bgTemplate->GetMaxPlayersPerTeam();
751760

752-
int normalMatchesCreationAttempts = 1;
753-
// now check if there are in queues enough players to start new game of (normal battleground)
754-
if (bgTypeId == BATTLEGROUND_AV && sWorld.getConfig(CONFIG_UINT32_AV_MIN_PLAYERS_IN_QUEUE) && !sBattleGroundMgr.isTesting())
761+
if (sBattleGroundMgr.isTesting())
762+
{
763+
minPlayersPerTeam = 1;
764+
}
765+
766+
// Alterac Valley specific handling
767+
if (bgTypeId == BATTLEGROUND_AV &&
768+
sWorld.getConfig(CONFIG_UINT32_AV_MIN_PLAYERS_IN_QUEUE) &&
769+
!sBattleGroundMgr.isTesting())
755770
{
756771
int minPlayersInQueue = sWorld.getConfig(CONFIG_UINT32_AV_MIN_PLAYERS_IN_QUEUE);
757772
int playersInQueuePerTeam[BG_TEAMS_COUNT] = {0};
758-
for (uint32 i = 0; i < BG_TEAMS_COUNT; i++)
773+
774+
for (uint32 i = 0; i < BG_TEAMS_COUNT; ++i)
759775
{
760-
GroupsQueueType::const_iterator itr = m_queuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE + i].begin();
761-
for (; itr != m_queuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++itr)
776+
for (GroupsQueueType::const_iterator itr = m_queuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE + i].begin();
777+
itr != m_queuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++itr)
778+
{
762779
if (!(*itr)->isInvitedToBgInstanceGuid)
763780
playersInQueuePerTeam[i]++; // Only one player, because premades are not allowed in AV.
781+
}
764782
}
783+
765784
if (playersInQueuePerTeam[BG_TEAM_ALLIANCE] < minPlayersInQueue ||
766-
playersInQueuePerTeam[BG_TEAM_HORDE] < minPlayersInQueue)
767-
normalMatchesCreationAttempts = 0;
768-
else
785+
playersInQueuePerTeam[BG_TEAM_HORDE] < minPlayersInQueue)
769786
{
770-
// Now randomize
771-
auto seed = std::chrono::system_clock::now().time_since_epoch().count();
772-
std::shuffle(m_queuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE].begin(),
773-
m_queuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE].begin() + minPlayersInQueue,
774-
std::default_random_engine(seed));
775-
std::shuffle(m_queuedGroups[bracketId][BG_QUEUE_NORMAL_HORDE].begin(),
776-
m_queuedGroups[bracketId][BG_QUEUE_NORMAL_HORDE].begin() + minPlayersInQueue,
777-
std::default_random_engine(seed));
778-
sLog.Out(LOG_BG, LOG_LVL_DETAIL, "Alterac queue randomized (%u alliance vs %u horde)",
779-
m_queuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE].size(),
780-
m_queuedGroups[bracketId][BG_QUEUE_NORMAL_HORDE].size());
787+
return false;
781788
}
789+
790+
// TODO:
791+
// missing check for sWorld.getConfig(CONFIG_BOOL_BATTLEGROUND_RANDOMIZE) like at CheckFreeSlots()?
792+
auto seed = std::chrono::system_clock::now().time_since_epoch().count();
793+
std::shuffle(m_queuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE].begin(),
794+
m_queuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE].end(),
795+
std::default_random_engine(seed));
796+
std::shuffle(m_queuedGroups[bracketId][BG_QUEUE_NORMAL_HORDE].begin(),
797+
m_queuedGroups[bracketId][BG_QUEUE_NORMAL_HORDE].end(),
798+
std::default_random_engine(seed));
799+
sLog.Out(LOG_BG, LOG_LVL_DETAIL, "Alterac queue randomized (%u alliance vs %u horde)",
800+
m_queuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE].size(),
801+
m_queuedGroups[bracketId][BG_QUEUE_NORMAL_HORDE].size());
782802
}
783-
if (bgTypeId == BATTLEGROUND_AV && sWorld.getConfig(CONFIG_UINT32_AV_INITIAL_MAX_PLAYERS) && !sBattleGroundMgr.isTesting() && normalMatchesCreationAttempts)
803+
804+
if (bgTypeId == BATTLEGROUND_AV && sWorld.getConfig(CONFIG_UINT32_AV_INITIAL_MAX_PLAYERS) && !sBattleGroundMgr.isTesting())
784805
{
785-
maxPlayersPerTeam = sWorld.getConfig(CONFIG_UINT32_AV_INITIAL_MAX_PLAYERS);
786-
if (maxPlayersPerTeam <= minPlayersPerTeam)
787-
maxPlayersPerTeam = minPlayersPerTeam;
788-
normalMatchesCreationAttempts = 2;
806+
uint32 configuredMax = sWorld.getConfig(CONFIG_UINT32_AV_INITIAL_MAX_PLAYERS);
807+
if (configuredMax > minPlayersPerTeam && configuredMax < maxPlayersPerTeam)
808+
maxPlayersPerTeam = configuredMax;
789809
}
790-
if (sBattleGroundMgr.isTesting())
791-
minPlayersPerTeam = 1;
792810

811+
uint32 qMinLevel = Player::GetMinLevelForBattleGroundBracketId(bracketId, bgTypeId);
812+
uint32 qMaxLevel = Player::GetMaxLevelForBattleGroundBracketId(bracketId, bgTypeId) - 1;
813+
814+
// Check for premade match
793815
m_selectionPools[BG_TEAM_ALLIANCE].Init();
794816
m_selectionPools[BG_TEAM_HORDE].Init();
795817

796-
uint32 qMinLevel = Player::GetMinLevelForBattleGroundBracketId(bracketId, bgTypeId);
797-
uint32 qMaxLevel = Player::GetMaxLevelForBattleGroundBracketId(bracketId, bgTypeId);
818+
if (CheckPremadeMatch(bracketId, minPlayersPerTeam, maxPlayersPerTeam))
798819
{
799-
//check if there is premade against premade match
800-
if (CheckPremadeMatch(bracketId, minPlayersPerTeam, maxPlayersPerTeam))
820+
BattleGround* newBg = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, bracketId);
821+
if (!newBg)
801822
{
802-
//create new battleground
803-
BattleGround* bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, bracketId);
804-
if (!bg2)
823+
sLog.Out(LOG_BASIC, LOG_LVL_ERROR, "[BattleGroundQueue::CheckCreateNewBg] failed to create premade battleground: %u", bgTypeId);
824+
return false;
825+
}
826+
827+
for (uint32 i = 0; i < BG_TEAMS_COUNT; ++i)
828+
{
829+
for (const auto group : m_selectionPools[BG_TEAM_ALLIANCE + i].selectedGroups)
805830
{
806-
sLog.Out(LOG_BASIC, LOG_LVL_ERROR, "BattleGroundQueue::Update - Cannot create battleground: %u", bgTypeId);
807-
return;
831+
InviteGroupToBG(group, newBg, group->groupTeam);
808832
}
809-
//invite those selection pools
810-
for (uint32 i = 0; i < BG_TEAMS_COUNT; i++)
811-
for (const auto itr : m_selectionPools[BG_TEAM_ALLIANCE + i].selectedGroups)
812-
InviteGroupToBG(itr, bg2, itr->groupTeam);
813-
//start bg
814-
bg2->SetLevelRange(qMinLevel, qMaxLevel - 1);
815-
bg2->StartBattleGround();
816833
}
834+
835+
newBg->SetLevelRange(qMinLevel, qMaxLevel);
836+
newBg->StartBattleGround();
837+
createdPremadeBg = true;
817838
}
818839

819-
for (int attempt = 0; attempt < normalMatchesCreationAttempts; ++attempt)
840+
// Only try to create normal match if no premade was created
841+
if (!createdPremadeBg)
820842
{
821843
m_selectionPools[BG_TEAM_ALLIANCE].Init();
822844
m_selectionPools[BG_TEAM_HORDE].Init();
823-
// if there are enough players in pools, start new battleground or non rated arena
845+
824846
if (CheckNormalMatch(bracketId, minPlayersPerTeam, maxPlayersPerTeam))
825847
{
826-
// we successfully created a pool
827-
BattleGround* bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, bracketId);
828-
if (!bg2)
848+
BattleGround* newBg = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, bracketId);
849+
if (!newBg)
829850
{
830-
sLog.Out(LOG_BASIC, LOG_LVL_ERROR, "BattleGroundQueue::Update - Cannot create battleground: %u", bgTypeId);
831-
return;
851+
sLog.Out(LOG_BASIC, LOG_LVL_ERROR, "[BattleGroundQueue::CheckCreateNewBg] Cannot create battleground: %u", bgTypeId);
852+
return false;
832853
}
833854

834-
// invite those selection pools
835-
for (uint32 i = 0; i < BG_TEAMS_COUNT; i++)
836-
for (const auto itr : m_selectionPools[BG_TEAM_ALLIANCE + i].selectedGroups)
837-
InviteGroupToBG(itr, bg2, itr->groupTeam);
855+
for (uint32 i = 0; i < BG_TEAMS_COUNT; ++i)
856+
{
857+
for (const auto group : m_selectionPools[BG_TEAM_ALLIANCE + i].selectedGroups)
858+
{
859+
InviteGroupToBG(group, newBg, group->groupTeam);
860+
}
861+
}
838862

839-
// start bg
840-
bg2->SetLevelRange(qMinLevel, qMaxLevel - 1);
841-
bg2->StartBattleGround();
863+
newBg->SetLevelRange(qMinLevel, qMaxLevel);
864+
newBg->StartBattleGround();
865+
createdNormalBg = true;
842866
}
843867
}
868+
869+
return createdPremadeBg || createdNormalBg;
870+
}
871+
872+
void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BattleGroundBracketId bracketId)
873+
{
874+
//ACE_Guard<ACE_Recursive_Thread_Mutex> guard(m_lock);
875+
876+
RemoveOfflinePlayer();
877+
878+
if (!HasPlayersInQueue(bracketId))
879+
return;
880+
881+
// Check if player can join to an existing battleground
882+
CheckFreeSlots(bgTypeId, bracketId);
883+
884+
// When all running battlegrounds are full or if there are no running bgs,
885+
// check if we can create a new one
886+
if (CheckCreateNewBg(bgTypeId, bracketId))
887+
{
888+
// Fix edge case:
889+
// If there are still players left in the queue for the same bracket,
890+
// check if they can join to the battleground which was just created
891+
CheckFreeSlots(bgTypeId, bracketId);
892+
}
844893
}
845894

846895
/*********************************************************/

0 commit comments

Comments
 (0)