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