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