TrinityCore
Loading...
Searching...
No Matches
BattlegroundQueue.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "BattlegroundQueue.h"
19#include "ArenaTeam.h"
20#include "ArenaTeamMgr.h"
21#include "BattlegroundMgr.h"
22#include "BattlegroundPackets.h"
23#include "Chat.h"
24#include "DatabaseEnv.h"
25#include "DBCStores.h"
26#include "GameTime.h"
27#include "Group.h"
28#include "Language.h"
29#include "Log.h"
30#include "ObjectAccessor.h"
31#include "Player.h"
32#include "World.h"
33
34/*********************************************************/
35/*** BATTLEGROUND QUEUE SYSTEM ***/
36/*********************************************************/
37
39{
40 for (uint32 i = 0; i < PVP_TEAMS_COUNT; ++i)
41 {
42 m_SumOfWaitTimes[i] = 0;
45 m_WaitTimes[i][k] = 0;
46 }
47}
48
50{
52
53 for (uint32 j = 0; j < BG_QUEUE_GROUP_TYPES_COUNT; ++j)
54 for (GroupsQueueType::iterator itr = m_QueuedGroups[j].begin(); itr!= m_QueuedGroups[j].end(); ++itr)
55 delete (*itr);
56}
57
58/*********************************************************/
59/*** BATTLEGROUND QUEUE SELECTION POOLS ***/
60/*********************************************************/
61
62// selection pool initialization, used to clean up from prev selection
68
69// remove group info from selection pool
70// returns true when we need to try to add new group to selection pool
71// returns false when selection pool is ok or when we kicked smaller group than we need to kick
72// sometimes it can be called on empty selection pool
74{
75 //find maxgroup or LAST group with size == size and kick it
76 bool found = false;
77 GroupsQueueType::iterator groupToKick = SelectedGroups.begin();
78 for (GroupsQueueType::iterator itr = groupToKick; itr != SelectedGroups.end(); ++itr)
79 {
80 if (abs((int32)((*itr)->Players.size() - size)) <= 1)
81 {
82 groupToKick = itr;
83 found = true;
84 }
85 else if (!found && (*itr)->Players.size() >= (*groupToKick)->Players.size())
86 groupToKick = itr;
87 }
88 //if pool is empty, do nothing
89 if (GetPlayerCount())
90 {
91 //update player count
92 GroupQueueInfo* ginfo = (*groupToKick);
93 SelectedGroups.erase(groupToKick);
94 PlayerCount -= ginfo->Players.size();
95 //return false if we kicked smaller group or there are enough players in selection pool
96 if (ginfo->Players.size() <= size + 1)
97 return false;
98 }
99 return true;
100}
101
102// add group to selection pool
103// used when building selection pools
104// returns true if we can invite more players, or when we added group to selection pool
105// returns false when selection pool is full
107{
108 //if group is larger than desired count - don't allow to add it to pool
109 if (!ginfo->IsInvitedToBGInstanceGUID && desiredCount >= PlayerCount + ginfo->Players.size())
110 {
111 SelectedGroups.push_back(ginfo);
112 // increase selected players count
113 PlayerCount += ginfo->Players.size();
114 return true;
115 }
116 if (PlayerCount < desiredCount)
117 return true;
118 return false;
119}
120
121/*********************************************************/
122/*** BATTLEGROUND QUEUES ***/
123/*********************************************************/
124
125// add group or player (grp == NULL) to bg queue with the given leader and bg specifications
126GroupQueueInfo* BattlegroundQueue::AddGroup(Player* leader, Group const* group, PvPDifficultyEntry const* bracketEntry, bool isRated, bool isPremade, uint32 ArenaRating, uint32 MatchmakerRating, uint32 arenateamid, uint32 PreviousOpponentsArenaTeamId)
127{
128 // create new ginfo
129 GroupQueueInfo* ginfo = new GroupQueueInfo;
130 ginfo->ArenaTeamId = arenateamid;
131 ginfo->IsRated = isRated;
132 ginfo->IsInvitedToBGInstanceGUID = 0;
134 ginfo->RemoveInviteTime = 0;
135 ginfo->Team = Team(leader->GetTeam());
136 ginfo->ArenaTeamRating = ArenaRating;
137 ginfo->ArenaMatchmakerRating = MatchmakerRating;
138 ginfo->PreviousOpponentsTeamId = PreviousOpponentsArenaTeamId;
139 ginfo->OpponentsTeamRating = 0;
140 ginfo->OpponentsMatchmakerRating = 0;
141
142 ginfo->Players.clear();
143
144 //compute index (if group is premade or joined a rated match) to queues
145 uint32 index = 0;
146 if (!isRated && !isPremade)
147 index += PVP_TEAMS_COUNT;
148 if (ginfo->Team == HORDE)
149 index++;
150 TC_LOG_DEBUG("bg.battleground", "Adding Group to BattlegroundQueue bgTypeId : {}, bracket_id : {}, index : {}", m_queueId.BattlemasterListId, m_queueId.BracketId, index);
151
152 uint32 lastOnlineTime = GameTime::GetGameTimeMS();
153
154 //announce world (this don't need mutex)
155 if (isRated && sWorld->getBoolConfig(CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE))
156 {
157 ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(arenateamid);
158 if (team)
160 }
161
162 //add players from group to ginfo
163 if (group)
164 {
165 for (GroupReference const* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
166 {
167 Player* member = itr->GetSource();
168 if (!member)
169 continue; // this should never happen
170 PlayerQueueInfo& pl_info = m_QueuedPlayers[member->GetGUID()];
171 pl_info.LastOnlineTime = lastOnlineTime;
172 pl_info.GroupInfo = ginfo;
173 // add the pinfo to ginfo's list
174 ginfo->Players[member->GetGUID()] = &pl_info;
175 }
176 }
177 else
178 {
179 PlayerQueueInfo& pl_info = m_QueuedPlayers[leader->GetGUID()];
180 pl_info.LastOnlineTime = lastOnlineTime;
181 pl_info.GroupInfo = ginfo;
182 ginfo->Players[leader->GetGUID()] = &pl_info;
183 }
184
185 //add GroupInfo to m_QueuedGroups
186 {
187 m_QueuedGroups[index].push_back(ginfo);
188
189 //announce to world, this code needs mutex
190 if (!isRated && !isPremade && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE))
191 {
193 {
194 uint32 MinPlayers = bg->GetMinPlayersPerTeam();
195 uint32 qHorde = 0;
196 uint32 qAlliance = 0;
197 uint32 q_min_level = bracketEntry->MinLevel;
198 uint32 q_max_level = bracketEntry->MaxLevel;
199 GroupsQueueType::const_iterator itr;
200 for (itr = m_QueuedGroups[BG_QUEUE_NORMAL_ALLIANCE].begin(); itr != m_QueuedGroups[BG_QUEUE_NORMAL_ALLIANCE].end(); ++itr)
201 if (!(*itr)->IsInvitedToBGInstanceGUID)
202 qAlliance += (*itr)->Players.size();
203 for (itr = m_QueuedGroups[BG_QUEUE_NORMAL_HORDE].begin(); itr != m_QueuedGroups[BG_QUEUE_NORMAL_HORDE].end(); ++itr)
204 if (!(*itr)->IsInvitedToBGInstanceGUID)
205 qHorde += (*itr)->Players.size();
206
207 // Show queue status to player only (when joining queue)
209 {
210 ChatHandler(leader->GetSession()).PSendSysMessage(LANG_BG_QUEUE_ANNOUNCE_SELF, bg->GetName().c_str(), q_min_level, q_max_level,
211 qAlliance, (MinPlayers > qAlliance) ? MinPlayers - qAlliance : (uint32)0, qHorde, (MinPlayers > qHorde) ? MinPlayers - qHorde : (uint32)0);
212 }
213 // System message
214 else
215 {
216 sWorld->SendWorldText(LANG_BG_QUEUE_ANNOUNCE_WORLD, bg->GetName().c_str(), q_min_level, q_max_level,
217 qAlliance, (MinPlayers > qAlliance) ? MinPlayers - qAlliance : (uint32)0, qHorde, (MinPlayers > qHorde) ? MinPlayers - qHorde : (uint32)0);
218 }
219 }
220 }
221 //release mutex
222 }
223
224 return ginfo;
225}
226
228{
229 uint32 timeInQueue = getMSTimeDiff(ginfo->JoinTime, GameTime::GetGameTimeMS());
230 uint8 team_index = TEAM_ALLIANCE; //default set to TEAM_ALLIANCE - or non rated arenas!
231 if (!m_queueId.TeamSize)
232 {
233 if (ginfo->Team == HORDE)
234 team_index = TEAM_HORDE;
235 }
236 else
237 {
238 if (ginfo->IsRated)
239 team_index = TEAM_HORDE; //for rated arenas use TEAM_HORDE
240 }
241
242 //store pointer to arrayindex of player that was added first
243 uint32* lastPlayerAddedPointer = &(m_WaitTimeLastPlayer[team_index]);
244 //remove his time from sum
245 m_SumOfWaitTimes[team_index] -= m_WaitTimes[team_index][(*lastPlayerAddedPointer)];
246 //set average time to new
247 m_WaitTimes[team_index][(*lastPlayerAddedPointer)] = timeInQueue;
248 //add new time to sum
249 m_SumOfWaitTimes[team_index] += timeInQueue;
250 //set index of last player added to next one
251 (*lastPlayerAddedPointer)++;
252 (*lastPlayerAddedPointer) %= COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME;
253}
254
256{
257 uint8 team_index = TEAM_ALLIANCE; //default set to TEAM_ALLIANCE - or non rated arenas!
258 if (!m_queueId.TeamSize)
259 {
260 if (ginfo->Team == HORDE)
261 team_index = TEAM_HORDE;
262 }
263 else
264 {
265 if (ginfo->IsRated)
266 team_index = TEAM_HORDE; //for rated arenas use TEAM_HORDE
267 }
268 //check if there is enought values(we always add values > 0)
271 else
272 //if there aren't enough values return 0 - not available
273 return 0;
274}
275
276//remove player from queue and from group info, if group info is empty then remove it too
277void BattlegroundQueue::RemovePlayer(ObjectGuid guid, bool decreaseInvitedCount)
278{
279 int32 bracket_id = -1; // signed for proper for-loop finish
280 QueuedPlayersMap::iterator itr;
281
282 //remove player from map, if he's there
283 itr = m_QueuedPlayers.find(guid);
284 if (itr == m_QueuedPlayers.end())
285 {
286 //This happens if a player logs out while in a bg because WorldSession::LogoutPlayer() notifies the bg twice
287 std::string playerName = "Unknown";
288 if (Player* player = ObjectAccessor::FindPlayer(guid))
289 playerName = player->GetName();
290 TC_LOG_DEBUG("bg.battleground", "BattlegroundQueue: couldn't find player {} ({})", playerName, guid.ToString());
291 return;
292 }
293
294 GroupQueueInfo* group = itr->second.GroupInfo;
295 GroupsQueueType::iterator group_itr;
296 // mostly people with the highest levels are in battlegrounds, thats why
297 // we count from MAX_BATTLEGROUND_QUEUES - 1 to 0
298
300
301 //we must check premade and normal team's queue - because when players from premade are joining bg,
302 //they leave groupinfo so we can't use its players size to find out index
303 for (uint32 j = index; j < BG_QUEUE_GROUP_TYPES_COUNT; j += PVP_TEAMS_COUNT)
304 {
305 GroupsQueueType::iterator k = m_QueuedGroups[j].begin();
306 for (; k != m_QueuedGroups[j].end(); ++k)
307 {
308 if ((*k) == group)
309 {
310 bracket_id = m_queueId.BracketId;
311 group_itr = k;
312 //we must store index to be able to erase iterator
313 index = j;
314 break;
315 }
316 }
317 }
318
319 //player can't be in queue without group, but just in case
320 if (bracket_id == -1)
321 {
322 TC_LOG_ERROR("bg.battleground", "BattlegroundQueue: ERROR Cannot find groupinfo for {}", guid.ToString());
323 return;
324 }
325 TC_LOG_DEBUG("bg.battleground", "BattlegroundQueue: Removing {}, from bracket_id {}", guid.ToString(), (uint32)bracket_id);
326
327 // ALL variables are correctly set
328 // We can ignore leveling up in queue - it should not cause crash
329 // remove player from group
330 // if only one player there, remove group
331
332 // remove player queue info from group queue info
333 std::map<ObjectGuid, PlayerQueueInfo*>::iterator pitr = group->Players.find(guid);
334 if (pitr != group->Players.end())
335 group->Players.erase(pitr);
336
337 // if invited to bg, and should decrease invited count, then do it
338 if (decreaseInvitedCount && group->IsInvitedToBGInstanceGUID)
340 bg->DecreaseInvitedCount(group->Team);
341
342 // remove player queue info
343 m_QueuedPlayers.erase(itr);
344
345 // announce to world if arena team left queue for rated match, show only once
346 if (m_queueId.TeamSize && group->IsRated && group->Players.empty() && sWorld->getBoolConfig(CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE))
347 if (ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(group->ArenaTeamId))
348 sWorld->SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_EXIT, team->GetName().c_str(), m_queueId.TeamSize, m_queueId.TeamSize, group->ArenaTeamRating);
349
350 // if player leaves queue and he is invited to rated arena match, then he have to lose
351 if (group->IsInvitedToBGInstanceGUID && group->IsRated && decreaseInvitedCount)
352 {
353 if (ArenaTeam* at = sArenaTeamMgr->GetArenaTeamById(group->ArenaTeamId))
354 {
355 TC_LOG_DEBUG("bg.battleground", "UPDATING memberLost's personal arena rating for {} by opponents rating: {}", guid.ToString(), group->OpponentsTeamRating);
357 at->MemberLost(player, group->OpponentsMatchmakerRating);
358 else
359 at->OfflineMemberLost(guid, group->OpponentsMatchmakerRating);
360 at->SaveToDB();
361 }
362 }
363
364 // remove group queue info if needed
365 if (group->Players.empty())
366 {
367 m_QueuedGroups[index].erase(group_itr);
368 delete group;
369 return;
370 }
371
372 // if group wasn't empty, so it wasn't deleted, and player have left a rated
373 // queue -> everyone from the group should leave too
374 // don't remove recursively if already invited to bg!
375 if (!group->IsInvitedToBGInstanceGUID && group->IsRated)
376 {
377 // remove next player, this is recursive
378 // first send removal information
379 if (Player* plr2 = ObjectAccessor::FindConnectedPlayer(group->Players.begin()->first))
380 {
381 uint32 queueSlot = plr2->GetBattlegroundQueueIndex(m_queueId);
382
383 plr2->RemoveBattlegroundQueueId(m_queueId); // must be called this way, because if you move this call to
384 // queue->removeplayer, it causes bugs
385
387 BattlegroundMgr::BuildBattlegroundStatusNone(&battlefieldStatus, queueSlot);
388 plr2->SendDirectMessage(battlefieldStatus.Write());
389 }
390 // then actually delete, this may delete the group as well!
391 RemovePlayer(group->Players.begin()->first, decreaseInvitedCount);
392 }
393}
394
395//returns true when player pl_guid is in queue and is invited to bgInstanceGuid
396bool BattlegroundQueue::IsPlayerInvited(ObjectGuid pl_guid, const uint32 bgInstanceGuid, const uint32 removeTime)
397{
398 QueuedPlayersMap::const_iterator qItr = m_QueuedPlayers.find(pl_guid);
399 return (qItr != m_QueuedPlayers.end()
400 && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == bgInstanceGuid
401 && qItr->second.GroupInfo->RemoveInviteTime == removeTime);
402}
403
405{
406 QueuedPlayersMap::const_iterator qItr = m_QueuedPlayers.find(guid);
407 if (qItr == m_QueuedPlayers.end())
408 return false;
409 *ginfo = *(qItr->second.GroupInfo);
410 return true;
411}
412
417
419{
420 // set side if needed
421 if (side)
422 ginfo->Team = side;
423
424 if (!ginfo->IsInvitedToBGInstanceGUID)
425 {
426 // not yet invited
427 // set invitation
430 BattlegroundQueueTypeId bgQueueTypeId = m_queueId;
431
432 // set ArenaTeamId for rated matches
433 if (bg->isArena() && bg->isRated())
434 bg->SetArenaTeamIdForTeam(ginfo->Team, ginfo->ArenaTeamId);
435
437
438 // loop through the players
439 for (std::map<ObjectGuid, PlayerQueueInfo*>::iterator itr = ginfo->Players.begin(); itr != ginfo->Players.end(); ++itr)
440 {
441 // get the player
442 Player* player = ObjectAccessor::FindConnectedPlayer(itr->first);
443 // if offline, skip him, this should not happen - player is removed from queue when he logs out
444 if (!player)
445 continue;
446
447 // invite the player
449 //sBattlegroundMgr->InvitePlayer(player, bg, ginfo->Team);
450
451 // set invited player counters
452 bg->IncreaseInvitedCount(ginfo->Team);
453
455
456 // create remind invite events
457 BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(player->GetGUID(), ginfo->IsInvitedToBGInstanceGUID, bgTypeId, ginfo->RemoveInviteTime, bgQueueTypeId);
459 // create automatic remove events
460 BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(player->GetGUID(), ginfo->IsInvitedToBGInstanceGUID, bgQueueTypeId, ginfo->RemoveInviteTime);
462
463 WorldPacket data;
464
465 uint32 queueSlot = player->GetBattlegroundQueueIndex(bgQueueTypeId);
466
467 TC_LOG_DEBUG("bg.battleground", "Battleground: invited player {} {} to BG instance {} queueindex {} bgtype {}",
468 player->GetName(), player->GetGUID().ToString(), bg->GetInstanceID(), queueSlot, bg->GetTypeID());
469
471 BattlegroundMgr::BuildBattlegroundStatusNeedConfirmation(&battlefieldStatus, bg, queueSlot, INVITE_ACCEPT_WAIT_TIME, bgQueueTypeId);
472 player->SendDirectMessage(battlefieldStatus.Write());
473 }
474 return true;
475 }
476
477 return false;
478}
479
480/*
481This function is inviting players to already running battlegrounds
482Invitation type is based on config file
483large groups are disadvantageous, because they will be kicked first if invitation type = 1
484*/
486{
487 int32 hordeFree = bg->GetFreeSlotsForTeam(HORDE);
488 int32 aliFree = bg->GetFreeSlotsForTeam(ALLIANCE);
490 uint32 hordeCount = m_QueuedGroups[BG_QUEUE_NORMAL_HORDE].size();
491
492 // try to get even teams
494 {
495 // check if the teams are even
496 if (hordeFree == 1 && aliFree == 1)
497 {
498 // if we are here, the teams have the same amount of players
499 // then we have to allow to join the same amount of players
500 int32 hordeExtra = hordeCount - aliCount;
501 int32 aliExtra = aliCount - hordeCount;
502
503 hordeExtra = std::max(hordeExtra, 0);
504 aliExtra = std::max(aliExtra, 0);
505
506 if (aliCount != hordeCount)
507 {
508 aliFree -= aliExtra;
509 hordeFree -= hordeExtra;
510
511 aliFree = std::max(aliFree, 0);
512 hordeFree = std::max(hordeFree, 0);
513 }
514 }
515 }
516
517 //iterator for iterating through bg queue
518 GroupsQueueType::const_iterator Ali_itr = m_QueuedGroups[BG_QUEUE_NORMAL_ALLIANCE].begin();
519 //count of groups in queue - used to stop cycles
520
521 //index to queue which group is current
522 uint32 aliIndex = 0;
523 for (; aliIndex < aliCount && m_SelectionPools[TEAM_ALLIANCE].AddGroup((*Ali_itr), aliFree); aliIndex++)
524 ++Ali_itr;
525 //the same thing for horde
526 GroupsQueueType::const_iterator Horde_itr = m_QueuedGroups[BG_QUEUE_NORMAL_HORDE].begin();
527
528 uint32 hordeIndex = 0;
529 for (; hordeIndex < hordeCount && m_SelectionPools[TEAM_HORDE].AddGroup((*Horde_itr), hordeFree); hordeIndex++)
530 ++Horde_itr;
531
532 //if ofc like BG queue invitation is set in config, then we are happy
534 return;
535
536 /*
537 if we reached this code, then we have to solve NP - complete problem called Subset sum problem
538 So one solution is to check all possible invitation subgroups, or we can use these conditions:
539 1. Last time when BattlegroundQueue::Update was executed we invited all possible players - so there is only small possibility
540 that we will invite now whole queue, because only 1 change has been made to queues from the last BattlegroundQueue::Update call
541 2. Other thing we should consider is group order in queue
542 */
543
544 // At first we need to compare free space in bg and our selection pool
545 int32 diffAli = aliFree - int32(m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount());
546 int32 diffHorde = hordeFree - int32(m_SelectionPools[TEAM_HORDE].GetPlayerCount());
547 while (abs(diffAli - diffHorde) > 1 && (m_SelectionPools[TEAM_HORDE].GetPlayerCount() > 0 || m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount() > 0))
548 {
549 //each cycle execution we need to kick at least 1 group
550 if (diffAli < diffHorde)
551 {
552 //kick alliance group, add to pool new group if needed
553 if (m_SelectionPools[TEAM_ALLIANCE].KickGroup(diffHorde - diffAli))
554 {
555 for (; aliIndex < aliCount && m_SelectionPools[TEAM_ALLIANCE].AddGroup((*Ali_itr), (aliFree >= diffHorde) ? aliFree - diffHorde : 0); aliIndex++)
556 ++Ali_itr;
557 }
558 //if ali selection is already empty, then kick horde group, but if there are less horde than ali in bg - break;
559 if (!m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount())
560 {
561 if (aliFree <= diffHorde + 1)
562 break;
563 m_SelectionPools[TEAM_HORDE].KickGroup(diffHorde - diffAli);
564 }
565 }
566 else
567 {
568 //kick horde group, add to pool new group if needed
569 if (m_SelectionPools[TEAM_HORDE].KickGroup(diffAli - diffHorde))
570 {
571 for (; hordeIndex < hordeCount && m_SelectionPools[TEAM_HORDE].AddGroup((*Horde_itr), (hordeFree >= diffAli) ? hordeFree - diffAli : 0); hordeIndex++)
572 ++Horde_itr;
573 }
574 if (!m_SelectionPools[TEAM_HORDE].GetPlayerCount())
575 {
576 if (hordeFree <= diffAli + 1)
577 break;
578 m_SelectionPools[TEAM_ALLIANCE].KickGroup(diffAli - diffHorde);
579 }
580 }
581 //count diffs after small update
582 diffAli = aliFree - int32(m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount());
583 diffHorde = hordeFree - int32(m_SelectionPools[TEAM_HORDE].GetPlayerCount());
584 }
585}
586
587// this method checks if premade versus premade battleground is possible
588// then after 30 mins (default) in queue it moves premade group to normal queue
589// it tries to invite as much players as it can - to MaxPlayersPerTeam, because premade groups have more than MinPlayersPerTeam players
590bool BattlegroundQueue::CheckPremadeMatch(uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam)
591{
592 //check match
594 {
595 //start premade match
596 //if groups aren't invited
597 GroupsQueueType::const_iterator ali_group, horde_group;
598 for (ali_group = m_QueuedGroups[BG_QUEUE_PREMADE_ALLIANCE].begin(); ali_group != m_QueuedGroups[BG_QUEUE_PREMADE_ALLIANCE].end(); ++ali_group)
599 if (!(*ali_group)->IsInvitedToBGInstanceGUID)
600 break;
601 for (horde_group = m_QueuedGroups[BG_QUEUE_PREMADE_HORDE].begin(); horde_group != m_QueuedGroups[BG_QUEUE_PREMADE_HORDE].end(); ++horde_group)
602 if (!(*horde_group)->IsInvitedToBGInstanceGUID)
603 break;
604
605 if (ali_group != m_QueuedGroups[BG_QUEUE_PREMADE_ALLIANCE].end() && horde_group != m_QueuedGroups[BG_QUEUE_PREMADE_HORDE].end())
606 {
607 m_SelectionPools[TEAM_ALLIANCE].AddGroup((*ali_group), MaxPlayersPerTeam);
608 m_SelectionPools[TEAM_HORDE].AddGroup((*horde_group), MaxPlayersPerTeam);
609 //add groups/players from normal queue to size of bigger group
610 uint32 maxPlayers = std::min(m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount(), m_SelectionPools[TEAM_HORDE].GetPlayerCount());
611 GroupsQueueType::const_iterator itr;
612 for (uint32 i = 0; i < PVP_TEAMS_COUNT; i++)
613 {
614 for (itr = m_QueuedGroups[BG_QUEUE_NORMAL_ALLIANCE + i].begin(); itr != m_QueuedGroups[BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++itr)
615 {
616 //if itr can join BG and player count is less that maxPlayers, then add group to selectionpool
617 if (!(*itr)->IsInvitedToBGInstanceGUID && !m_SelectionPools[i].AddGroup((*itr), maxPlayers))
618 break;
619 }
620 }
621 //premade selection pools are set
622 return true;
623 }
624 }
625 // now check if we can move group from Premade queue to normal queue (timer has expired) or group size lowered!!
626 // this could be 2 cycles but i'm checking only first team in queue - it can cause problem -
627 // if first is invited to BG and seconds timer expired, but we can ignore it, because players have only 80 seconds to click to enter bg
628 // and when they click or after 80 seconds the queue info is removed from queue
630 for (uint32 i = 0; i < PVP_TEAMS_COUNT; i++)
631 {
633 {
634 GroupsQueueType::iterator itr = m_QueuedGroups[BG_QUEUE_PREMADE_ALLIANCE + i].begin();
635 if (!(*itr)->IsInvitedToBGInstanceGUID && ((*itr)->JoinTime < time_before || (*itr)->Players.size() < MinPlayersPerTeam))
636 {
637 //we must insert group to normal queue and erase pointer from premade queue
638 m_QueuedGroups[BG_QUEUE_NORMAL_ALLIANCE + i].push_front((*itr));
640 }
641 }
642 }
643 //selection pools are not set
644 return false;
645}
646
647// this method tries to create battleground or arena with MinPlayersPerTeam against MinPlayersPerTeam
648bool BattlegroundQueue::CheckNormalMatch(Battleground* bg_template, uint32 minPlayers, uint32 maxPlayers)
649{
650 GroupsQueueType::const_iterator itr_team[PVP_TEAMS_COUNT];
651 for (uint32 i = 0; i < PVP_TEAMS_COUNT; i++)
652 {
653 itr_team[i] = m_QueuedGroups[BG_QUEUE_NORMAL_ALLIANCE + i].begin();
654 for (; itr_team[i] != m_QueuedGroups[BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++(itr_team[i]))
655 {
656 if (!(*(itr_team[i]))->IsInvitedToBGInstanceGUID)
657 {
658 m_SelectionPools[i].AddGroup(*(itr_team[i]), maxPlayers);
659 if (m_SelectionPools[i].GetPlayerCount() >= minPlayers)
660 break;
661 }
662 }
663 }
664 //try to invite same number of players - this cycle may cause longer wait time even if there are enough players in queue, but we want ballanced bg
667 j = TEAM_HORDE;
670 {
671 //we will try to invite more groups to team with less players indexed by j
672 ++(itr_team[j]); //this will not cause a crash, because for cycle above reached break;
673 for (; itr_team[j] != m_QueuedGroups[BG_QUEUE_NORMAL_ALLIANCE + j].end(); ++(itr_team[j]))
674 {
675 if (!(*(itr_team[j]))->IsInvitedToBGInstanceGUID)
676 if (!m_SelectionPools[j].AddGroup(*(itr_team[j]), m_SelectionPools[(j + 1) % PVP_TEAMS_COUNT].GetPlayerCount()))
677 break;
678 }
679 // do not allow to start bg with more than 2 players more on 1 faction
681 return false;
682 }
683 //allow 1v0 if debug bg
685 return true;
686 //return true if there are enough players in selection pools - enable to work .debug bg command correctly
688}
689
690// this method will check if we can invite players to same faction skirmish match
692{
693 if (m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount() < minPlayersPerTeam && m_SelectionPools[TEAM_HORDE].GetPlayerCount() < minPlayersPerTeam)
694 return false;
695 TeamId teamIndex = TEAM_ALLIANCE;
696 TeamId otherTeam = TEAM_HORDE;
697 Team otherTeamId = HORDE;
698 if (m_SelectionPools[TEAM_HORDE].GetPlayerCount() == minPlayersPerTeam)
699 {
700 teamIndex = TEAM_HORDE;
701 otherTeam = TEAM_ALLIANCE;
702 otherTeamId = ALLIANCE;
703 }
704 //clear other team's selection
705 m_SelectionPools[otherTeam].Init();
706 //store last ginfo pointer
707 GroupQueueInfo* ginfo = m_SelectionPools[teamIndex].SelectedGroups.back();
708 //set itr_team to group that was added to selection pool latest
709 GroupsQueueType::iterator itr_team = m_QueuedGroups[uint8(BG_QUEUE_NORMAL_ALLIANCE) + uint8(teamIndex)].begin();
710 for (; itr_team != m_QueuedGroups[uint8(BG_QUEUE_NORMAL_ALLIANCE) + uint8(teamIndex)].end(); ++itr_team)
711 if (ginfo == *itr_team)
712 break;
713 if (itr_team == m_QueuedGroups[uint8(BG_QUEUE_NORMAL_ALLIANCE) + uint8(teamIndex)].end())
714 return false;
715 GroupsQueueType::iterator itr_team2 = itr_team;
716 ++itr_team2;
717 //invite players to other selection pool
718 for (; itr_team2 != m_QueuedGroups[uint8(BG_QUEUE_NORMAL_ALLIANCE) + uint8(teamIndex)].end(); ++itr_team2)
719 {
720 //if selection pool is full then break;
721 if (!(*itr_team2)->IsInvitedToBGInstanceGUID && !m_SelectionPools[otherTeam].AddGroup(*itr_team2, minPlayersPerTeam))
722 break;
723 }
724 if (m_SelectionPools[otherTeam].GetPlayerCount() != minPlayersPerTeam)
725 return false;
726
727 //here we have correct 2 selections and we need to change one teams team and move selection pool teams to other team's queue
728 for (GroupsQueueType::iterator itr = m_SelectionPools[otherTeam].SelectedGroups.begin(); itr != m_SelectionPools[otherTeam].SelectedGroups.end(); ++itr)
729 {
730 //set correct team
731 (*itr)->Team = otherTeamId;
732 //add team to other queue
733 m_QueuedGroups[uint8(BG_QUEUE_NORMAL_ALLIANCE) + uint8(otherTeam)].push_front(*itr);
734 //remove team from old queue
735 GroupsQueueType::iterator itr2 = itr_team;
736 ++itr2;
737 for (; itr2 != m_QueuedGroups[uint8(BG_QUEUE_NORMAL_ALLIANCE) + uint8(teamIndex)].end(); ++itr2)
738 {
739 if (*itr2 == *itr)
740 {
741 m_QueuedGroups[uint8(BG_QUEUE_NORMAL_ALLIANCE) + uint8(teamIndex)].erase(itr2);
742 break;
743 }
744 }
745 }
746 return true;
747}
748
753
754/*
755this 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
756it must be called after fully adding the members of a group to ensure group joining
757should be called from Battleground::RemovePlayer function in some cases
758*/
759void BattlegroundQueue::BattlegroundQueueUpdate(uint32 /*diff*/, bool isRated, uint32 arenaRating)
760{
763 uint8 arenaType = m_queueId.TeamSize;
764
765 //if no players in queue - do nothing
770 return;
771
772 // battleground with free slot for player should be always in the beggining of the queue
773 // maybe it would be better to create bgfreeslotqueue for each bracket_id
774 BGFreeSlotQueueContainer& bgQueues = sBattlegroundMgr->GetBGFreeSlotQueueStore(bgTypeId);
775 for (BGFreeSlotQueueContainer::iterator itr = bgQueues.begin(); itr != bgQueues.end();)
776 {
777 Battleground* bg = *itr; ++itr;
778 // DO NOT allow queue manager to invite new player to rated games
779 if (!bg->isRated() && bg->GetTypeID() == bgTypeId && bg->GetBracketId() == bracket_id &&
781 {
782 // clear selection pools
785
786 // call a function that does the job for us
787 FillPlayersToBG(bg);
788
789 // now everything is set, invite players
790 for (GroupsQueueType::const_iterator citr = m_SelectionPools[TEAM_ALLIANCE].SelectedGroups.begin(); citr != m_SelectionPools[TEAM_ALLIANCE].SelectedGroups.end(); ++citr)
791 InviteGroupToBG((*citr), bg, (*citr)->Team);
792
793 for (GroupsQueueType::const_iterator citr = m_SelectionPools[TEAM_HORDE].SelectedGroups.begin(); citr != m_SelectionPools[TEAM_HORDE].SelectedGroups.end(); ++citr)
794 InviteGroupToBG((*citr), bg, (*citr)->Team);
795
796 if (!bg->HasFreeSlots())
798 }
799 }
800
801 // finished iterating through the bgs with free slots, maybe we need to create a new bg
802
803 Battleground* bg_template = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId);
804 if (!bg_template)
805 {
806 TC_LOG_ERROR("bg.battleground", "Battleground: Update: bg template not found for {}", bgTypeId);
807 return;
808 }
809
810 PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketById(bg_template->GetMapId(), bracket_id);
811 if (!bracketEntry)
812 {
813 TC_LOG_ERROR("bg.battleground", "Battleground: Update: bg bracket entry not found for map {} bracket id {}", bg_template->GetMapId(), bracket_id);
814 return;
815 }
816
817 // get the min. players per team, properly for larger arenas as well. (must have full teams for arena matches!)
818 uint32 MinPlayersPerTeam = bg_template->GetMinPlayersPerTeam();
819 uint32 MaxPlayersPerTeam = bg_template->GetMaxPlayersPerTeam();
820
821 if (bg_template->isArena())
822 {
823 MaxPlayersPerTeam = arenaType;
824 MinPlayersPerTeam = sBattlegroundMgr->isArenaTesting() ? 1 : arenaType;
825 }
826 else if (sBattlegroundMgr->isTesting())
827 MinPlayersPerTeam = 1;
828
831
832 if (bg_template->isBattleground())
833 {
834 if (CheckPremadeMatch(MinPlayersPerTeam, MaxPlayersPerTeam))
835 {
836 // create new battleground
837 Battleground* bg2 = sBattlegroundMgr->CreateNewBattleground(bgTypeId, bracketEntry, 0, false);
838 if (!bg2)
839 {
840 TC_LOG_ERROR("bg.battleground", "BattlegroundQueue::Update - Cannot create battleground: {}", bgTypeId);
841 return;
842 }
843 // invite those selection pools
844 for (uint32 i = 0; i < PVP_TEAMS_COUNT; i++)
845 for (GroupsQueueType::const_iterator citr = m_SelectionPools[TEAM_ALLIANCE + i].SelectedGroups.begin(); citr != m_SelectionPools[TEAM_ALLIANCE + i].SelectedGroups.end(); ++citr)
846 InviteGroupToBG((*citr), bg2, (*citr)->Team);
847
848 bg2->StartBattleground();
849 //clear structures
852 }
853 }
854
855 // now check if there are in queues enough players to start new game of (normal battleground, or non-rated arena)
856 if (!isRated)
857 {
858 // if there are enough players in pools, start new battleground or non rated arena
859 if (CheckNormalMatch(bg_template, MinPlayersPerTeam, MaxPlayersPerTeam)
860 || (bg_template->isArena() && CheckSkirmishForSameFaction(MinPlayersPerTeam)))
861 {
862 // we successfully created a pool
863 Battleground* bg2 = sBattlegroundMgr->CreateNewBattleground(bgTypeId, bracketEntry, arenaType, false);
864 if (!bg2)
865 {
866 TC_LOG_ERROR("bg.battleground", "BattlegroundQueue::Update - Cannot create battleground: {}", bgTypeId);
867 return;
868 }
869
870 // invite those selection pools
871 for (uint32 i = 0; i < PVP_TEAMS_COUNT; i++)
872 for (GroupsQueueType::const_iterator citr = m_SelectionPools[TEAM_ALLIANCE + i].SelectedGroups.begin(); citr != m_SelectionPools[TEAM_ALLIANCE + i].SelectedGroups.end(); ++citr)
873 InviteGroupToBG((*citr), bg2, (*citr)->Team);
874 // start bg
875 bg2->StartBattleground();
876 }
877 }
878 else if (bg_template->isArena())
879 {
880 // found out the minimum and maximum ratings the newly added team should battle against
881 // arenaRating is the rating of the latest joined team, or 0
882 // 0 is on (automatic update call) and we must set it to team's with longest wait time
883 if (!arenaRating)
884 {
885 GroupQueueInfo* front1 = nullptr;
886 GroupQueueInfo* front2 = nullptr;
888 {
890 arenaRating = front1->ArenaMatchmakerRating;
891 }
893 {
894 front2 = m_QueuedGroups[BG_QUEUE_PREMADE_HORDE].front();
895 arenaRating = front2->ArenaMatchmakerRating;
896 }
897 if (front1 && front2)
898 {
899 if (front1->JoinTime < front2->JoinTime)
900 arenaRating = front1->ArenaMatchmakerRating;
901 }
902 else if (!front1 && !front2)
903 return; //queues are empty
904 }
905
906 //set rating range
907 uint32 arenaMinRating = (arenaRating <= sBattlegroundMgr->GetMaxRatingDifference()) ? 0 : arenaRating - sBattlegroundMgr->GetMaxRatingDifference();
908 uint32 arenaMaxRating = arenaRating + sBattlegroundMgr->GetMaxRatingDifference();
909 // if max rating difference is set and the time past since server startup is greater than the rating discard time
910 // (after what time the ratings aren't taken into account when making teams) then
911 // the discard time is current_time - time_to_discard, teams that joined after that, will have their ratings taken into account
912 // else leave the discard time on 0, this way all ratings will be discarded
913 // this has to be signed value - when the server starts, this value would be negative and thus overflow
914 int32 discardTime = GameTime::GetGameTimeMS() - sBattlegroundMgr->GetRatingDiscardTimer();
915
916 // timer for previous opponents
917 int32 discardOpponentsTime = GameTime::GetGameTimeMS() - sWorld->getIntConfig(CONFIG_ARENA_PREV_OPPONENTS_DISCARD_TIMER);
918
919 // we need to find 2 teams which will play next game
920 GroupsQueueType::iterator itr_teams[PVP_TEAMS_COUNT];
921 uint8 found = 0;
922 uint8 team = 0;
923
925 {
926 // take the group that joined first
927 GroupsQueueType::iterator itr2 = m_QueuedGroups[i].begin();
928 for (; itr2 != m_QueuedGroups[i].end(); ++itr2)
929 {
930 // if group match conditions, then add it to pool
931 if (!(*itr2)->IsInvitedToBGInstanceGUID
932 && (((*itr2)->ArenaMatchmakerRating >= arenaMinRating && (*itr2)->ArenaMatchmakerRating <= arenaMaxRating)
933 || (int32)(*itr2)->JoinTime < discardTime))
934 {
935 itr_teams[found++] = itr2;
936 team = i;
937 break;
938 }
939 }
940 }
941
942 if (!found)
943 return;
944
945 if (found == 1)
946 {
947 for (GroupsQueueType::iterator itr3 = itr_teams[0]; itr3 != m_QueuedGroups[team].end(); ++itr3)
948 {
949 if (!(*itr3)->IsInvitedToBGInstanceGUID
950 && (((*itr3)->ArenaMatchmakerRating >= arenaMinRating && (*itr3)->ArenaMatchmakerRating <= arenaMaxRating) || (int32)(*itr3)->JoinTime < discardTime)
951 && ((*itr_teams[0])->ArenaTeamId != (*itr3)->PreviousOpponentsTeamId || ((int32)(*itr3)->JoinTime < discardOpponentsTime))
952 && (*itr_teams[0])->ArenaTeamId != (*itr3)->ArenaTeamId)
953 {
954 itr_teams[found++] = itr3;
955 break;
956 }
957 }
958 }
959
960 //if we have 2 teams, then start new arena and invite players!
961 if (found == 2)
962 {
963 GroupQueueInfo* aTeam = *itr_teams[TEAM_ALLIANCE];
964 GroupQueueInfo* hTeam = *itr_teams[TEAM_HORDE];
965 Battleground* arena = sBattlegroundMgr->CreateNewBattleground(bgTypeId, bracketEntry, arenaType, true);
966 if (!arena)
967 {
968 TC_LOG_ERROR("bg.battleground", "BattlegroundQueue::Update couldn't create arena instance for rated arena match!");
969 return;
970 }
971
972 aTeam->OpponentsTeamRating = hTeam->ArenaTeamRating;
973 hTeam->OpponentsTeamRating = aTeam->ArenaTeamRating;
976 TC_LOG_DEBUG("bg.battleground", "setting oposite teamrating for team {} to {}", aTeam->ArenaTeamId, aTeam->OpponentsTeamRating);
977 TC_LOG_DEBUG("bg.battleground", "setting oposite teamrating for team {} to {}", hTeam->ArenaTeamId, hTeam->OpponentsTeamRating);
978
979 // now we must move team if we changed its faction to another faction queue, because then we will spam log by errors in Queue::RemovePlayer
980 if (aTeam->Team != ALLIANCE)
981 {
982 m_QueuedGroups[BG_QUEUE_PREMADE_ALLIANCE].push_front(aTeam);
984 }
985 if (hTeam->Team != HORDE)
986 {
987 m_QueuedGroups[BG_QUEUE_PREMADE_HORDE].push_front(hTeam);
989 }
990
993 InviteGroupToBG(aTeam, arena, ALLIANCE);
994 InviteGroupToBG(hTeam, arena, HORDE);
995
996 TC_LOG_DEBUG("bg.battleground", "Starting rated arena match!");
997 arena->StartBattleground();
998 }
999 }
1000}
1001
1002/*********************************************************/
1003/*** BATTLEGROUND QUEUE EVENTS ***/
1004/*********************************************************/
1005
1006bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
1007{
1008 Player* player = ObjectAccessor::FindConnectedPlayer(m_PlayerGuid);
1009 // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
1010 if (!player)
1011 return true;
1012
1013 Battleground* bg = sBattlegroundMgr->GetBattleground(m_BgInstanceGUID, m_BgTypeId);
1014 //if battleground ended and its instance deleted - do nothing
1015 if (!bg)
1016 return true;
1017
1018 uint32 queueSlot = player->GetBattlegroundQueueIndex(m_QueueId);
1019 if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue or in battleground
1020 {
1021 // check if player is invited to this bg
1022 BattlegroundQueue &bgQueue = sBattlegroundMgr->GetBattlegroundQueue(m_QueueId);
1023 if (bgQueue.IsPlayerInvited(m_PlayerGuid, m_BgInstanceGUID, m_RemoveTime))
1024 {
1027 player->SendDirectMessage(battlefieldStatus.Write());
1028 }
1029 }
1030 return true; //event will be deleted
1031}
1032
1034{
1035 //do nothing
1036}
1037
1038/*
1039 this event has many possibilities when it is executed:
1040 1. player is in battleground (he clicked enter on invitation window)
1041 2. player left battleground queue and he isn't there any more
1042 3. player left battleground queue and he joined it again and IsInvitedToBGInstanceGUID = 0
1043 4. player left queue and he joined again and he has been invited to same battleground again -> we should not remove him from queue yet
1044 5. player is invited to bg and he didn't choose what to do and timer expired - only in this condition we should call queue::RemovePlayer
1045 we must remove player in the 5. case even if battleground object doesn't exist!
1046*/
1047bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
1048{
1049 Player* player = ObjectAccessor::FindConnectedPlayer(m_PlayerGuid);
1050 if (!player)
1051 // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
1052 return true;
1053
1054 Battleground* bg = sBattlegroundMgr->GetBattleground(m_BgInstanceGUID, BattlegroundTypeId(m_BgQueueTypeId.BattlemasterListId));
1055 //battleground can be deleted already when we are removing queue info
1056 //bg pointer can be NULL! so use it carefully!
1057
1058 uint32 queueSlot = player->GetBattlegroundQueueIndex(m_BgQueueTypeId);
1059 if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue, or in Battleground
1060 {
1061 // check if player is in queue for this BG and if we are removing his invite event
1062 BattlegroundQueue &bgQueue = sBattlegroundMgr->GetBattlegroundQueue(m_BgQueueTypeId);
1063 if (bgQueue.IsPlayerInvited(m_PlayerGuid, m_BgInstanceGUID, m_RemoveTime))
1064 {
1065 // track if player leaves the BG by not clicking enter button
1066 if (bg && bg->isBattleground() && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_TRACK_DESERTERS) &&
1068 {
1070 stmt->setUInt32(0, player->GetGUID().GetCounter());
1072 CharacterDatabase.Execute(stmt);
1073 }
1074
1075 TC_LOG_DEBUG("bg.battleground", "Battleground: removing player {} from bg queue for instance {} because of not pressing enter battle in time.", player->GetGUID().ToString(), m_BgInstanceGUID);
1076
1077 player->RemoveBattlegroundQueueId(m_BgQueueTypeId);
1078 bgQueue.RemovePlayer(m_PlayerGuid, true);
1079 //update queues if battleground isn't ended
1080 if (bg && bg->isBattleground() && bg->GetStatus() != STATUS_WAIT_LEAVE)
1081 sBattlegroundMgr->ScheduleQueueUpdate(0, m_BgQueueTypeId);
1082
1084 BattlegroundMgr::BuildBattlegroundStatusNone(&battlefieldStatus, queueSlot);
1085 player->SendDirectMessage(battlefieldStatus.Write());
1086 }
1087 }
1088
1089 //event will be deleted
1090 return true;
1091}
1092
1094{
1095 //do nothing
1096}
#define sArenaTeamMgr
#define sBattlegroundMgr
@ BG_QUEUE_INVITATION_TYPE_NO_BALANCE
@ BG_QUEUE_INVITATION_TYPE_EVEN
@ BG_QUEUE_PREMADE_HORDE
@ BG_QUEUE_NORMAL_ALLIANCE
@ BG_QUEUE_PREMADE_ALLIANCE
@ BG_QUEUE_NORMAL_HORDE
#define BG_QUEUE_GROUP_TYPES_COUNT
#define COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME
std::list< Battleground * > BGFreeSlotQueueContainer
@ INVITE_ACCEPT_WAIT_TIME
@ INVITATION_REMIND_TIME
@ BG_DESERTION_TYPE_NO_ENTER_BUTTON
@ STATUS_WAIT_QUEUE
@ STATUS_WAIT_LEAVE
@ STATUS_WAIT_JOIN
@ STATUS_IN_PROGRESS
@ CHAR_INS_DESERTER_TRACK
BattlegroundBracketId
Definition DBCEnums.h:57
PvPDifficultyEntry const * GetBattlegroundBracketById(uint32 mapid, BattlegroundBracketId id)
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
uint8_t uint8
Definition Define.h:135
int32_t int32
Definition Define.h:129
uint64_t uint64
Definition Define.h:132
uint32_t uint32
Definition Define.h:133
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition Duration.h:24
@ LANG_ARENA_QUEUE_ANNOUNCE_WORLD_EXIT
Definition Language.h:712
@ LANG_BG_QUEUE_ANNOUNCE_SELF
Definition Language.h:704
@ LANG_BG_QUEUE_ANNOUNCE_WORLD
Definition Language.h:705
@ LANG_ARENA_QUEUE_ANNOUNCE_WORLD_JOIN
Definition Language.h:711
#define TC_LOG_DEBUG(filterType__,...)
Definition Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition Log.h:165
TeamId
@ TEAM_ALLIANCE
@ TEAM_HORDE
uint8 constexpr PVP_TEAMS_COUNT
@ ALLIANCE
@ HORDE
BattlegroundTypeId
#define PLAYER_MAX_BATTLEGROUND_QUEUES
uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime)
Definition Timer.h:40
std::string const & GetName() const
Definition ArenaTeam.h:134
virtual void Abort(uint64 e_time) override
virtual bool Execute(uint64 e_time, uint32 p_time) override
virtual bool Execute(uint64 e_time, uint32 p_time) override
virtual void Abort(uint64 e_time) override
static void BuildBattlegroundStatusNeedConfirmation(WorldPackets::Battleground::BattlefieldStatusNeedConfirmation *battlefieldStatus, Battleground const *bg, uint32 queueSlot, uint32 timeout, BattlegroundQueueTypeId queueId)
static void BuildBattlegroundStatusNone(WorldPackets::Battleground::BattlefieldStatusNone *battlefieldStatus, uint32 queueSlot)
bool AddGroup(GroupQueueInfo *ginfo, uint32 desiredCount)
void UpdateEvents(uint32 diff)
void BattlegroundQueueUpdate(uint32 diff, bool isRated=false, uint32 minRating=0)
uint32 GetAverageQueueWaitTime(GroupQueueInfo *ginfo) const
uint32 m_WaitTimes[PVP_TEAMS_COUNT][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME]
bool CheckSkirmishForSameFaction(uint32 minPlayersPerTeam)
bool InviteGroupToBG(GroupQueueInfo *ginfo, Battleground *bg, Team side)
QueuedPlayersMap m_QueuedPlayers
bool CheckNormalMatch(Battleground *bg_template, uint32 minPlayers, uint32 maxPlayers)
bool GetPlayerGroupInfoData(ObjectGuid guid, GroupQueueInfo *ginfo)
GroupsQueueType m_QueuedGroups[BG_QUEUE_GROUP_TYPES_COUNT]
uint32 m_WaitTimeLastPlayer[PVP_TEAMS_COUNT]
void PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo *ginfo)
uint32 m_SumOfWaitTimes[PVP_TEAMS_COUNT]
BattlegroundQueue(BattlegroundQueueTypeId queueId)
void RemovePlayer(ObjectGuid guid, bool decreaseInvitedCount)
BattlegroundQueueTypeId m_queueId
SelectionPool m_SelectionPools[PVP_TEAMS_COUNT]
bool CheckPremadeMatch(uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam)
GroupQueueInfo * AddGroup(Player *leader, Group const *group, PvPDifficultyEntry const *bracketEntry, bool isRated, bool isPremade, uint32 ArenaRating, uint32 MatchmakerRating, uint32 ArenaTeamId=0, uint32 OpponentsArenaTeamId=0)
bool IsPlayerInvited(ObjectGuid pl_guid, const uint32 bgInstanceGuid, const uint32 removeTime)
void FillPlayersToBG(Battleground *bg)
uint32 GetPlayersInQueue(TeamId id)
EventProcessor m_events
void IncreaseInvitedCount(uint32 team)
uint32 GetMapId() const
BattlegroundTypeId GetTypeID(bool GetRandom=false) const
uint32 GetMinPlayersPerTeam() const
uint32 GetMaxPlayersPerTeam() const
bool isRated() const
void StartBattleground()
uint32 GetInstanceID() const
bool isArena() const
void SetArenaTeamIdForTeam(uint32 Team, uint32 ArenaTeamId)
void SetArenaMatchmakerRating(uint32 Team, uint32 MMR)
bool isBattleground() const
BattlegroundStatus GetStatus() const
bool HasFreeSlots() const
void RemoveFromBGFreeSlotQueue()
BattlegroundBracketId GetBracketId() const
uint32 GetFreeSlotsForTeam(uint32 Team) const
void PSendSysMessage(char const *fmt, Args &&... args)
Definition Chat.h:69
void KillAllEvents(bool force)
void Update(uint32 p_time)
void AddEvent(BasicEvent *event, Milliseconds e_time, bool set_addtime=true)
Milliseconds CalculateTime(Milliseconds t_offset) const
Definition Group.h:165
GroupReference * GetFirstMember()
Definition Group.h:247
LowType GetCounter() const
Definition ObjectGuid.h:156
std::string ToString() const
static ObjectGuid GetGUID(Object const *o)
Definition Object.h:78
uint32 GetTeam() const
Definition Player.h:1832
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6161
WorldSession * GetSession() const
Definition Player.h:1719
void RemoveBattlegroundQueueId(BattlegroundQueueTypeId val)
Definition Player.cpp:23120
uint32 GetBattlegroundQueueIndex(BattlegroundQueueTypeId bgQueueTypeId) const
Definition Player.cpp:23071
void SetInviteForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId, uint32 instanceId)
Definition Player.cpp:23133
void setUInt32(uint8 index, uint32 value)
void setUInt8(uint8 index, uint8 value)
std::string const & GetName() const
Definition Object.h:382
#define sWorld
Definition World.h:900
@ CONFIG_BATTLEGROUND_INVITATION_TYPE
Definition World.h:313
@ CONFIG_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH
Definition World.h:315
@ CONFIG_ARENA_PREV_OPPONENTS_DISCARD_TIMER
Definition World.h:319
@ CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY
Definition World.h:126
@ CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE
Definition World.h:131
@ CONFIG_BATTLEGROUND_TRACK_DESERTERS
Definition World.h:128
@ CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE
Definition World.h:125
uint32 GetGameTimeMS()
Definition GameTime.cpp:47
TC_GAME_API Player * FindPlayer(ObjectGuid const &)
TC_GAME_API Player * FindConnectedPlayer(ObjectGuid const &)
uint32 IsInvitedToBGInstanceGUID
std::map< ObjectGuid, PlayerQueueInfo * > Players
uint32 PreviousOpponentsTeamId
uint32 OpponentsMatchmakerRating
GroupQueueInfo * GroupInfo