TrinityCore
Loading...
Searching...
No Matches
BattlegroundMgr.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 "BattlegroundMgr.h"
19#include "Arena.h"
20#include "BattlegroundPackets.h"
21#include "Containers.h"
22#include "DB2Stores.h"
23#include "DatabaseEnv.h"
24#include "DisableMgr.h"
25#include "GameEventMgr.h"
26#include "GossipDef.h"
27#include "Language.h"
28#include "Log.h"
29#include "MapManager.h"
30#include "MapUtils.h"
31#include "ObjectMgr.h"
32#include "Player.h"
33#include "SharedDefines.h"
34#include "World.h"
35#include "WorldSession.h"
36
41
46
51
56
61
62/*********************************************************/
63/*** BATTLEGROUND MANAGER ***/
64/*********************************************************/
65
67 m_NextRatedArenaUpdate(sWorld->getIntConfig(CONFIG_ARENA_RATED_UPDATE_TIMER)),
68 m_UpdateTimer(0), m_ArenaTesting(0), m_Testing(false)
69{ }
70
75
77{
78 for (auto& [_, data] : m_BGFreeSlotQueue)
79 for (Battleground* battleground : data)
80 battleground->RemoveFromBGFreeSlotQueueOnShutdown();
81
82 bgDataStore.clear();
83 m_BGFreeSlotQueue.clear();
84}
85
91
92// used to update running battlegrounds, and delete finished ones
94{
95 m_UpdateTimer += diff;
97 {
98 for (BattlegroundDataContainer::iterator itr1 = bgDataStore.begin(); itr1 != bgDataStore.end(); ++itr1)
99 {
100 BattlegroundContainer& bgs = itr1->second.m_Battlegrounds;
101 BattlegroundContainer::iterator itrDelete = bgs.begin();
102 for (BattlegroundContainer::iterator itr = itrDelete; itr != bgs.end();)
103 {
104 itrDelete = itr++;
105 Battleground* bg = itrDelete->second.get();
106
108 if (bg->ToBeDeleted())
109 {
110 BattlegroundClientIdsContainer& clients = itr1->second.m_ClientBattlegroundIds[bg->GetBracketId()];
111 if (!clients.empty())
112 clients.erase(bg->GetClientInstanceID());
113
114 // move out unique_ptr to delete after erasing
115 Trinity::unique_trackable_ptr<Battleground> bgPtr = std::move(itrDelete->second);
116
117 bgs.erase(itrDelete);
118 }
119 }
120 }
121
122 m_UpdateTimer = 0;
123 }
124
125 // update events timer
126 for (std::pair<BattlegroundQueueTypeId const, BattlegroundQueue>& pair : m_BattlegroundQueues)
127 pair.second.UpdateEvents(diff);
128
129 // update scheduled queues
130 if (!m_QueueUpdateScheduler.empty())
131 {
132 std::vector<ScheduledQueueUpdate> scheduled;
133 std::swap(scheduled, m_QueueUpdateScheduler);
134
135 for (auto& [arenaMMRating, bgQueueTypeId, bracket_id] : scheduled)
136 GetBattlegroundQueue(bgQueueTypeId).BattlegroundQueueUpdate(diff, bracket_id, arenaMMRating);
137 }
138
139 // if rating difference counts, maybe force-update queues
141 {
142 // it's time to force update
143 if (m_NextRatedArenaUpdate < diff)
144 {
145 // forced update for rated arenas (scan all, but skipped non rated)
146 TC_LOG_TRACE("bg.arena", "BattlegroundMgr: UPDATING ARENA QUEUES");
148 {
150 for (int bracket = BG_BRACKET_ID_FIRST; bracket < MAX_BATTLEGROUND_BRACKETS; ++bracket)
151 GetBattlegroundQueue(ratedArenaQueueId).BattlegroundQueueUpdate(diff, BattlegroundBracketId(bracket), 0);
152 }
153
155 }
156 else
158 }
159}
160
162{
163 header->Ticket.RequesterGuid = player->GetGUID();
164 header->Ticket.Id = ticketId;
166 header->Ticket.Time = joinTime;
167 header->QueueID.push_back(queueId.GetPacked());
168 header->RangeMin = 0; // seems to always be 0
169 header->RangeMax = GetMaxLevelForExpansion(CURRENT_EXPANSION); // alwyas max level of current expansion. Might be limited to account
170 header->TeamSize = queueId.TeamSize;
171 header->InstanceID = 0; // seems to always be 0
172 header->RegisteredMatch = queueId.Rated;
173 header->TournamentRules = false;
174}
175
177{
178 battlefieldStatus->Ticket.RequesterGuid = player->GetGUID();
179 battlefieldStatus->Ticket.Id = ticketId;
181 battlefieldStatus->Ticket.Time = joinTime;
182}
183
185{
186 BuildBattlegroundStatusHeader(&battlefieldStatus->Hdr, player, ticketId, joinTime, queueId);
187 battlefieldStatus->Mapid = bg->GetMapId();
188 battlefieldStatus->Timeout = timeout;
189 battlefieldStatus->Role = 0;
190}
191
193{
194 BuildBattlegroundStatusHeader(&battlefieldStatus->Hdr, player, ticketId, joinTime, queueId);
195 battlefieldStatus->ShutdownTimer = bg->GetRemainingTime();
196 battlefieldStatus->ArenaFaction = player->GetBGTeam() == HORDE ? PVP_TEAM_HORDE : PVP_TEAM_ALLIANCE;
197 battlefieldStatus->LeftEarly = false;
198 battlefieldStatus->StartTimer = bg->GetElapsedTime();
199 battlefieldStatus->Mapid = bg->GetMapId();
200}
201
202void BattlegroundMgr::BuildBattlegroundStatusQueued(WorldPackets::Battleground::BattlefieldStatusQueued* battlefieldStatus, Player const* player, uint32 ticketId, uint32 joinTime, BattlegroundQueueTypeId queueId, uint32 avgWaitTime, bool asGroup)
203{
204 BuildBattlegroundStatusHeader(&battlefieldStatus->Hdr, player, ticketId, joinTime, queueId);
205 battlefieldStatus->AverageWaitTime = avgWaitTime;
206 battlefieldStatus->AsGroup = asGroup;
207 battlefieldStatus->SuspendedQueue = false;
208 battlefieldStatus->EligibleForMatchmaking = true;
209 battlefieldStatus->WaitTime = GetMSTimeDiffToNow(joinTime);
210}
211
213{
214 battlefieldStatus->Ticket.RequesterGuid = player->GetGUID();
215 battlefieldStatus->Ticket.Id = ticketId;
217 battlefieldStatus->Ticket.Time = player->GetBattlegroundQueueJoinTime(queueId);
218 battlefieldStatus->QueueID = queueId.GetPacked();
219 battlefieldStatus->Reason = result;
220 if (errorGuid && (result == ERR_BATTLEGROUND_NOT_IN_BATTLEGROUND || result == ERR_BATTLEGROUND_JOIN_TIMED_OUT))
221 battlefieldStatus->ClientID = *errorGuid;
222}
223
225{
226 if (!instanceId)
227 return nullptr;
228
229 BattlegroundDataContainer::const_iterator begin, end;
230
231 if (bgTypeId == BATTLEGROUND_TYPE_NONE || IsRandomBattleground(bgTypeId))
232 {
233 begin = bgDataStore.begin();
234 end = bgDataStore.end();
235 }
236 else
237 {
238 end = bgDataStore.find(bgTypeId);
239 if (end == bgDataStore.end())
240 return nullptr;
241 begin = end++;
242 }
243
244 for (BattlegroundDataContainer::const_iterator it = begin; it != end; ++it)
245 {
246 BattlegroundContainer const& bgs = it->second.m_Battlegrounds;
247 BattlegroundContainer::const_iterator itr = bgs.find(instanceId);
248 if (itr != bgs.end())
249 return itr->second.get();
250 }
251
252 return nullptr;
253}
254
256{
257 uint32 oldMSTime = getMSTime();
258 // 0 1 2
259 QueryResult result = WorldDatabase.Query("SELECT MapId, BattlemasterListId, ScriptName FROM battleground_scripts");
260
261 if (!result)
262 {
263 TC_LOG_INFO("server.loading", ">> Loaded 0 battleground scripts. DB table `battleground_scripts` is empty!");
264 return;
265 }
266
267 uint32 count = 0;
268 do
269 {
270 Field* fields = result->Fetch();
271
272 uint32 mapID = fields[0].GetUInt32();
273
274 MapEntry const* mapEntry = sMapStore.LookupEntry(mapID);
275 if (!mapEntry || !mapEntry->IsBattlegroundOrArena())
276 {
277 TC_LOG_ERROR("sql.sql", "BattlegroundMgr::LoadBattlegroundScriptTemplate: bad mapid {}! Map doesn't exist or is not a battleground/arena!", mapID);
278 continue;
279 }
280
281 BattlegroundTypeId bgTypeId = static_cast<BattlegroundTypeId>(fields[1].GetUInt32());
283 {
284 TC_LOG_ERROR("sql.sql", "BattlegroundMgr::LoadBattlegroundScriptTemplate: bad battlemasterlist id {}! Battleground doesn't exist or is not supported in battleground_template!", bgTypeId);
285 continue;
286 }
287
288 BattlegroundScriptTemplate& scriptTemplate = _battlegroundScriptTemplates[{ mapID, bgTypeId }];
289 scriptTemplate.MapId = mapID;
290 scriptTemplate.Id = bgTypeId;
291 scriptTemplate.ScriptId = sObjectMgr->GetScriptId(fields[2].GetStringView());
292
293 ++count;
294 } while (result->NextRow());
295
296 TC_LOG_INFO("server.loading", ">> Loaded {} battleground scripts in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
297}
298
300{
302 return scriptTemplate;
303
304 // fall back to 0 for no specific battleground type id
306}
307
308void BattlegroundMgr::QueuePlayerForArena(Player const* player, uint8 teamSize, uint8 roles)
309{
311 packet.TeamSizeIndex = teamSize;
312 packet.Roles = roles;
313
314 player->GetSession()->HandleBattlemasterJoinArena(packet);
315}
316
318{
319 if (IsArenaType(bgTypeId))
320 return 0; //arenas don't have client-instanceids
321
322 // we create here an instanceid, which is just for
323 // displaying this to the client and without any other use..
324 // the client-instanceIds are unique for each battleground-type
325 // the instance-id just needs to be as low as possible, beginning with 1
326 // the following works, because std::set is default ordered with "<"
327 // the optimalization would be to use as bitmask std::vector<uint32> - but that would only make code unreadable
328
329 BattlegroundClientIdsContainer& clientIds = bgDataStore[bgTypeId].m_ClientBattlegroundIds[bracket_id];
330 uint32 lastId = 0;
331 for (BattlegroundClientIdsContainer::const_iterator itr = clientIds.begin(); itr != clientIds.end();)
332 {
333 if ((++lastId) != *itr) //if there is a gap between the ids, we will break..
334 break;
335 lastId = *itr;
336 }
337
338 clientIds.insert(++lastId);
339 return lastId;
340}
341
342// create a new battleground that will really be used to play
344{
346
347 // get the template BG
348 BattlegroundTemplate const* bg_template = GetBattlegroundTemplateByTypeId(bgTypeId);
349
350 if (!bg_template)
351 {
352 TC_LOG_ERROR("bg.battleground", "Battleground: CreateNewBattleground - bg template not found for {}", bgTypeId);
353 return nullptr;
354 }
355
356 PVPDifficultyEntry const* bracketEntry = DB2Manager::GetBattlegroundBracketById(bg_template->MapIDs.front(), bracketId);
357 if (!bracketEntry)
358 {
359 TC_LOG_ERROR("bg.battleground", "Battleground: CreateNewBattleground: bg bracket entry not found for map {} bracket id {}", bg_template->MapIDs.front(), bracketId);
360 return nullptr;
361 }
362
363 Battleground* bg = nullptr;
364 if (bg_template->IsArena())
365 bg = new Arena(bg_template);
366 else
367 bg = new Battleground(bg_template);
368
369 bg->SetBracket(bracketEntry);
370 bg->SetInstanceID(sMapMgr->GenerateInstanceId());
372 // reset the new bg (set status to status_wait_queue from status_none)
373 // this shouldn't be needed anymore as a new Battleground instance is created each time. But some bg sub classes still depend on it.
374 bg->Reset();
375 bg->SetStatus(STATUS_WAIT_JOIN); // start the joining of the bg
376 bg->SetArenaType(queueId.TeamSize);
377 bg->SetRated(queueId.Rated);
378
379 return bg;
380}
381
383{
384 uint32 oldMSTime = getMSTime();
385
386 // 0 1 2 3 4 5
387 QueryResult result = WorldDatabase.Query("SELECT ID, AllianceStartLoc, HordeStartLoc, StartMaxDist, Weight, ScriptName FROM battleground_template");
388 if (!result)
389 {
390 TC_LOG_INFO("server.loading", ">> Loaded 0 battlegrounds. DB table `battleground_template` is empty.");
391 return;
392 }
393
394 std::unordered_map<BattlegroundTypeId, std::vector<int32>> mapsByBattleground;
395 for (BattlemasterListXMapEntry const* battlemasterListXMap : sBattlemasterListXMapStore)
396 if (sBattlemasterListStore.HasRecord(battlemasterListXMap->BattlemasterListID) && sMapStore.HasRecord(battlemasterListXMap->MapID))
397 mapsByBattleground[BattlegroundTypeId(battlemasterListXMap->BattlemasterListID)].push_back(battlemasterListXMap->MapID);
398
399 uint32 count = 0;
400
401 do
402 {
403 Field* fields = result->Fetch();
404
405 BattlegroundTypeId bgTypeId = BattlegroundTypeId(fields[0].GetUInt32());
406
408 continue;
409
410 // can be overwrite by values from DB
411 BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId);
412 if (!bl)
413 {
414 TC_LOG_ERROR("bg.battleground", "Battleground ID {} could not be found in BattlemasterList.dbc. The battleground was not created.", bgTypeId);
415 continue;
416 }
417
418 BattlegroundTemplate& bgTemplate = _battlegroundTemplates[bgTypeId];
419 bgTemplate.Id = bgTypeId;
420 float dist = fields[3].GetFloat();
421 bgTemplate.MaxStartDistSq = dist * dist;
422 bgTemplate.Weight = fields[4].GetUInt8();
423 bgTemplate.ScriptId = sObjectMgr->GetScriptId(fields[5].GetStringView());
424 bgTemplate.BattlemasterEntry = bl;
425 bgTemplate.MapIDs = std::move(mapsByBattleground[bgTypeId]);
426
427 if (bgTemplate.Id != BATTLEGROUND_AA && !IsRandomBattleground(bgTemplate.Id))
428 {
429 uint32 startId = fields[1].GetUInt32();
430 if (WorldSafeLocsEntry const* start = sObjectMgr->GetWorldSafeLoc(startId))
431 bgTemplate.StartLocation[TEAM_ALLIANCE] = start;
432 else if (bgTemplate.StartLocation[TEAM_ALLIANCE]) // reload case
433 TC_LOG_ERROR("sql.sql", "Table `battleground_template` for id {} contains a non-existing WorldSafeLocs.dbc id {} in field `AllianceStartLoc`. Ignoring.", bgTemplate.Id, startId);
434 else
435 {
436 TC_LOG_ERROR("sql.sql", "Table `battleground_template` for id {} contains a non-existing WorldSafeLocs.dbc id {} in field `AllianceStartLoc`. BG not created.", bgTemplate.Id, startId);
437 _battlegroundTemplates.erase(bgTypeId);
438 continue;
439 }
440
441 startId = fields[2].GetUInt32();
442 if (WorldSafeLocsEntry const* start = sObjectMgr->GetWorldSafeLoc(startId))
443 bgTemplate.StartLocation[TEAM_HORDE] = start;
444 else if (bgTemplate.StartLocation[TEAM_HORDE]) // reload case
445 TC_LOG_ERROR("sql.sql", "Table `battleground_template` for id {} contains a non-existing WorldSafeLocs.dbc id {} in field `HordeStartLoc`. Ignoring.", bgTemplate.Id, startId);
446 else
447 {
448 TC_LOG_ERROR("sql.sql", "Table `battleground_template` for id {} contains a non-existing WorldSafeLocs.dbc id {} in field `HordeStartLoc`. BG not created.", bgTemplate.Id, startId);
449 _battlegroundTemplates.erase(bgTypeId);
450 continue;
451 }
452 }
453
454 if (bgTemplate.MapIDs.size() == 1)
455 _battlegroundMapTemplates[bgTemplate.MapIDs.front()] = &_battlegroundTemplates[bgTypeId];
456
457 ++count;
458 }
459 while (result->NextRow());
460
461 TC_LOG_INFO("server.loading", ">> Loaded {} battlegrounds in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
462}
463
465{
466 BattlegroundTemplate const* bgTemplate = GetBattlegroundTemplateByTypeId(bgTypeId);
467 if (!bgTemplate)
468 return;
469
470 player->PlayerTalkClass->GetInteractionData().StartInteraction(guid, PlayerInteractionType::BattleMaster);
471
473 battlefieldList.BattlemasterGuid = guid;
474 battlefieldList.BattlemasterListID = bgTypeId;
475 battlefieldList.MinLevel = bgTemplate->GetMinLevel();
476 battlefieldList.MaxLevel = bgTemplate->GetMaxLevel();
477 battlefieldList.PvpAnywhere = guid.IsEmpty();
478 battlefieldList.HasRandomWinToday = player->GetRandomWinner();
479 player->SendDirectMessage(battlefieldList.Write());
480}
481
482/*static*/ void BattlegroundMgr::SendToBattleground(Player* player, Battleground const* battleground)
483{
484 if (!battleground)
485 {
486 TC_LOG_ERROR("bg.battleground", "BattlegroundMgr::SendToBattleground: Battleground not found while trying to teleport player {}", player->GetName());
487 return;
488 }
489
490 uint32 mapid = battleground->GetMapId();
491 Team team = player->GetBGTeam();
492
494 TC_LOG_DEBUG("bg.battleground", "BattlegroundMgr::SendToBattleground: Sending {} to map {}, {} (bgType {})", player->GetName(), mapid, pos->Loc, battleground->GetTypeID());
495 player->TeleportTo({ .Location = pos->Loc, .TransportGuid = pos->TransportSpawnId ? ObjectGuid::Create<HighGuid::Transport>(*pos->TransportSpawnId) : ObjectGuid::Empty });
496}
497
499{
500 return bgTypeId == BATTLEGROUND_AA
501 || bgTypeId == BATTLEGROUND_BE
502 || bgTypeId == BATTLEGROUND_NA
503 || bgTypeId == BATTLEGROUND_DS
504 || bgTypeId == BATTLEGROUND_RV
505 || bgTypeId == BATTLEGROUND_RL;
506}
507
509{
510 return battlemasterListId == BATTLEGROUND_RB || battlemasterListId == BATTLEGROUND_RANDOM_EPIC;
511}
512
514{
515 return { .BattlemasterListId = battlemasterListId, .Type = AsUnderlyingType(type), .Rated = rated, .TeamSize = teamSize };
516}
517
523
525{
526 if (battlemasterListId != 0)
527 {
528 BattlegroundTemplate const* bgTemplate = GetBattlegroundTemplateByTypeId(static_cast<BattlegroundTypeId>(battlemasterListId));
529 if (!bgTemplate)
530 return false;
531
532 if (!bgTemplate->IsArena())
533 return false;
534 }
535
536 if (m_ArenaTesting != battlemasterListId)
537 sWorld->SendWorldText((battlemasterListId != 0) ? LANG_DEBUG_ARENA_ON : LANG_DEBUG_ARENA_OFF);
538
539 m_ArenaTesting = battlemasterListId;
540 return true;
541}
542
544{
545 BattlemasterListEntry const* battlemasterList = sBattlemasterListStore.LookupEntry(bgQueueTypeId.BattlemasterListId);
546 if (!battlemasterList)
547 return false;
548
549 switch (BattlegroundQueueIdType(bgQueueTypeId.Type))
550 {
552 if (battlemasterList->GetType() != BattlemasterType::Battleground)
553 return false;
554 if (bgQueueTypeId.TeamSize)
555 return false;
556 break;
558 if (battlemasterList->GetType() != BattlemasterType::Arena)
559 return false;
560 if (!bgQueueTypeId.Rated)
561 return false;
562 if (!bgQueueTypeId.TeamSize)
563 return false;
564 break;
566 if (bgQueueTypeId.Rated)
567 return false;
568 break;
570 if (battlemasterList->GetType() != BattlemasterType::Arena)
571 return false;
572 if (!bgQueueTypeId.Rated)
573 return false;
574 if (bgQueueTypeId.TeamSize != ARENA_TYPE_3v3)
575 return false;
576 break;
577 default:
578 return false;
579 }
580
581 return true;
582}
583
585{
586 //This method must be atomic, @todo add mutex
587 //we will use only 1 number created of bgTypeId and bracket_id
588 ScheduledQueueUpdate scheduleId{ arenaMatchmakerRating, bgQueueTypeId, bracket_id };
589 if (std::find(m_QueueUpdateScheduler.begin(), m_QueueUpdateScheduler.end(), scheduleId) == m_QueueUpdateScheduler.end())
590 m_QueueUpdateScheduler.push_back(scheduleId);
591}
592
594{
595 // this is for stupid people who can't use brain and set max rating difference to 0
597 if (diff == 0)
598 diff = 5000;
599 return diff;
600}
601
606
611
613{
614 uint32 oldMSTime = getMSTime();
615
616 mBattleMastersMap.clear(); // need for reload case
617
618 QueryResult result = WorldDatabase.Query("SELECT entry, bg_template FROM battlemaster_entry");
619
620 if (!result)
621 {
622 TC_LOG_INFO("server.loading", ">> Loaded 0 battlemaster entries. DB table `battlemaster_entry` is empty!");
623 return;
624 }
625
626 uint32 count = 0;
627
628 do
629 {
630 ++count;
631
632 Field* fields = result->Fetch();
633
634 uint32 entry = fields[0].GetUInt32();
635 if (CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(entry))
636 {
637 if ((cInfo->npcflag & UNIT_NPC_FLAG_BATTLEMASTER) == 0)
638 TC_LOG_ERROR("sql.sql", "Creature (Entry: {}) listed in `battlemaster_entry` is not a battlemaster.", entry);
639 }
640 else
641 {
642 TC_LOG_ERROR("sql.sql", "Creature (Entry: {}) listed in `battlemaster_entry` does not exist.", entry);
643 continue;
644 }
645
646 uint32 bgTypeId = fields[1].GetUInt32();
647 if (!sBattlemasterListStore.LookupEntry(bgTypeId))
648 {
649 TC_LOG_ERROR("sql.sql", "Table `battlemaster_entry` contains entry {} for a non-existing battleground type {}, ignored.", entry, bgTypeId);
650 continue;
651 }
652
653 mBattleMastersMap[entry] = BattlegroundTypeId(bgTypeId);
654 }
655 while (result->NextRow());
656
658
659 TC_LOG_INFO("server.loading", ">> Loaded {} battlemaster entries in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
660}
661
663{
664 CreatureTemplateContainer const& ctc = sObjectMgr->GetCreatureTemplates();
665 for (auto const& creatureTemplatePair : ctc)
666 {
667 if ((creatureTemplatePair.second.npcflag & UNIT_NPC_FLAG_BATTLEMASTER) && !mBattleMastersMap.count(creatureTemplatePair.first))
668 {
669 TC_LOG_ERROR("sql.sql", "Creature_Template Entry: {} has UNIT_NPC_FLAG_BATTLEMASTER, but no data in the `battlemaster_entry` table. Removing flag.", creatureTemplatePair.first);
670 const_cast<CreatureTemplate&>(creatureTemplatePair.second).npcflag &= ~UNIT_NPC_FLAG_BATTLEMASTER;
671 }
672 }
673}
674
690
706
711
713{
714 if (BattlegroundTemplate const* bgTemplate = GetBattlegroundTemplateByTypeId(bgTypeId))
715 {
716 if (bgTemplate->IsArena() && isArenaTesting())
717 return static_cast<BattlegroundTypeId>(m_ArenaTesting);
718
719 std::vector<BattlegroundTemplate const*> ids;
720 ids.reserve(bgTemplate->MapIDs.size());
721 for (int32 mapId : bgTemplate->MapIDs)
723 ids.push_back(bg);
724
725 if (!ids.empty())
726 return (*Trinity::Containers::SelectRandomWeightedContainerElement(ids, [](BattlegroundTemplate const* bg) { return bg->Weight; }))->Id;
727 }
728
730}
731
736
741
743{
745 {
746 auto itr = std::ranges::find(*freeSlotQueue, instanceId, [](Battleground const* bg) { return bg->GetInstanceID(); });
747 if (itr != freeSlotQueue->end())
748 freeSlotQueue->erase(itr);
749 }
750}
751
753{
754 if (bg)
755 {
757 ptr.reset(bg);
758 bg->SetWeakPtr(ptr);
759 }
760}
@ BATTLEGROUND_OBJECTIVE_UPDATE_INTERVAL
std::set< uint32 > BattlegroundClientIdsContainer
std::map< uint32, Trinity::unique_trackable_ptr< Battleground > > BattlegroundContainer
std::list< Battleground * > BGFreeSlotQueueContainer
@ ARENA_TYPE_5v5
@ ARENA_TYPE_3v3
@ ARENA_TYPE_2v2
BattlegroundQueueIdType
@ STATUS_WAIT_JOIN
DB2Storage< BattlemasterListEntry > sBattlemasterListStore("BattlemasterList.db2", &BattlemasterListLoadInfo::Instance)
DB2Storage< MapEntry > sMapStore("Map.db2", &MapLoadInfo::Instance)
DB2Storage< BattlemasterListXMapEntry > sBattlemasterListXMapStore("BattlemasterListXMap.db2", &BattlemasterListXMapLoadInfo::Instance)
BattlegroundBracketId
Definition DBCEnums.h:53
@ BG_BRACKET_ID_FIRST
Definition DBCEnums.h:54
@ MAX_BATTLEGROUND_BRACKETS
Definition DBCEnums.h:58
std::shared_ptr< ResultSet > QueryResult
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
uint8_t uint8
Definition Define.h:156
int32_t int32
Definition Define.h:150
uint16_t uint16
Definition Define.h:155
uint32_t uint32
Definition Define.h:154
@ DISABLE_TYPE_BATTLEGROUND
Definition DisableMgr.h:30
bool IsHolidayActive(HolidayIds id)
@ LANG_DEBUG_BG_OFF
Definition Language.h:733
@ LANG_DEBUG_ARENA_OFF
Definition Language.h:731
@ LANG_DEBUG_BG_ON
Definition Language.h:732
@ LANG_DEBUG_ARENA_ON
Definition Language.h:730
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition Log.h:173
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:182
#define TC_LOG_INFO(filterType__, message__,...)
Definition Log.h:176
#define TC_LOG_TRACE(filterType__, message__,...)
Definition Log.h:170
#define sMapMgr
Definition MapManager.h:186
#define sObjectMgr
Definition ObjectMgr.h:1873
std::unordered_map< uint32, CreatureTemplate > CreatureTemplateContainer
Definition ObjectMgr.h:487
@ CMSG_BATTLEMASTER_JOIN_ARENA
Definition Opcodes.h:107
GroupJoinBattlegroundResult
@ ERR_BATTLEGROUND_JOIN_TIMED_OUT
@ ERR_BATTLEGROUND_NOT_IN_BATTLEGROUND
#define CURRENT_EXPANSION
constexpr uint32 GetMaxLevelForExpansion(uint32 expansion)
@ TEAM_ALLIANCE
@ TEAM_HORDE
@ HORDE
BattlegroundTypeId
@ BATTLEGROUND_BFG
@ BATTLEGROUND_IC
@ BATTLEGROUND_AA
@ BATTLEGROUND_WS
@ BATTLEGROUND_EY
@ BATTLEGROUND_AV
@ BATTLEGROUND_BE
@ BATTLEGROUND_TP
@ BATTLEGROUND_RV
@ BATTLEGROUND_TYPE_NONE
@ BATTLEGROUND_NA
@ BATTLEGROUND_RANDOM_EPIC
@ BATTLEGROUND_DS
@ BATTLEGROUND_SA
@ BATTLEGROUND_AB
@ BATTLEGROUND_RL
@ BATTLEGROUND_RB
HolidayIds
@ HOLIDAY_NONE
@ HOLIDAY_CALL_TO_ARMS_AB
@ HOLIDAY_CALL_TO_ARMS_ES
@ HOLIDAY_CALL_TO_ARMS_SA
@ HOLIDAY_CALL_TO_ARMS_IC
@ HOLIDAY_CALL_TO_ARMS_BG
@ HOLIDAY_CALL_TO_ARMS_AV
@ HOLIDAY_CALL_TO_ARMS_WG
@ HOLIDAY_CALL_TO_ARMS_TP
@ PVP_TEAM_HORDE
@ PVP_TEAM_ALLIANCE
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition Timer.h:57
uint32 getMSTime()
Definition Timer.h:33
@ UNIT_NPC_FLAG_BATTLEMASTER
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition Util.h:565
Definition Arena.h:57
ObjectGuid const & GetGUID() const
Definition BaseEntity.h:163
BattlegroundMapTemplateContainer _battlegroundMapTemplates
static void BuildBattlegroundStatusHeader(WorldPackets::Battleground::BattlefieldStatusHeader *header, Player const *player, uint32 ticketId, uint32 joinTime, BattlegroundQueueTypeId queueId)
static void BuildBattlegroundStatusNeedConfirmation(WorldPackets::Battleground::BattlefieldStatusNeedConfirmation *battlefieldStatus, Battleground const *bg, Player const *player, uint32 ticketId, uint32 joinTime, uint32 timeout, BattlegroundQueueTypeId queueId)
std::map< BattlegroundQueueTypeId, BattlegroundQueue > m_BattlegroundQueues
BattlegroundTemplate const * GetBattlegroundTemplateByMapId(uint32 mapId)
static void BuildBattlegroundStatusActive(WorldPackets::Battleground::BattlefieldStatusActive *battlefieldStatus, Battleground const *bg, Player const *player, uint32 ticketId, uint32 joinTime, BattlegroundQueueTypeId queueId)
std::vector< ScheduledQueueUpdate > m_QueueUpdateScheduler
Battleground * GetBattleground(uint32 InstanceID, BattlegroundTypeId bgTypeId)
BattlegroundTemplateMap _battlegroundTemplates
static BattlegroundQueueTypeId BGQueueTypeId(uint16 battlemasterListId, BattlegroundQueueIdType type, bool rated, uint8 teamSize)
void LoadBattlegroundScriptTemplate()
uint32 GetMaxRatingDifference() const
static void QueuePlayerForArena(Player const *player, uint8 teamSize, uint8 roles)
static void SendToBattleground(Player *player, Battleground const *battleground)
static BattlegroundMgr * instance()
BGFreeSlotQueueContainer & GetBGFreeSlotQueueStore(uint32 mapId)
static bool IsValidQueueId(BattlegroundQueueTypeId bgQueueTypeId)
BattlegroundTypeId GetRandomBG(BattlegroundTypeId id)
static bool IsArenaType(BattlegroundTypeId bgTypeId)
static void BuildBattlegroundStatusNone(WorldPackets::Battleground::BattlefieldStatusNone *battlefieldStatus, Player const *player, uint32 ticketId, uint32 joinTime)
bool isArenaTesting() const
BattlegroundQueue & GetBattlegroundQueue(BattlegroundQueueTypeId bgQueueTypeId)
void AddBattleground(Battleground *bg)
void AddToBGFreeSlotQueue(Battleground *bg)
BattleMastersMap mBattleMastersMap
std::map< uint32, BGFreeSlotQueueContainer > m_BGFreeSlotQueue
static bool IsRandomBattleground(uint32 battlemasterListId)
void ScheduleQueueUpdate(uint32 arenaMatchmakerRating, BattlegroundQueueTypeId bgQueueTypeId, BattlegroundBracketId bracket_id)
void SendBattlegroundList(Player *player, ObjectGuid const &guid, BattlegroundTypeId bgTypeId)
BattlegroundTemplate const * GetBattlegroundTemplateByTypeId(BattlegroundTypeId id)
Battleground * CreateNewBattleground(BattlegroundQueueTypeId queueId, BattlegroundBracketId bracketId)
void RemoveFromBGFreeSlotQueue(uint32 mapId, uint32 instanceId)
uint32 GetRatingDiscardTimer() const
bool ToggleArenaTesting(uint32 battlemasterListId)
static BattlegroundTypeId WeekendHolidayIdToBGType(HolidayIds holiday)
static HolidayIds BGTypeToWeekendHolidayId(BattlegroundTypeId bgTypeId)
static void BuildBattlegroundStatusQueued(WorldPackets::Battleground::BattlefieldStatusQueued *battlefieldStatus, Player const *player, uint32 ticketId, uint32 joinTime, BattlegroundQueueTypeId queueId, uint32 avgWaitTime, bool asGroup)
uint32 GetPrematureFinishTime() const
uint32 CreateClientVisibleInstanceId(BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id)
void Update(uint32 diff)
uint32 m_NextRatedArenaUpdate
BattlegroundScriptTemplate const * FindBattlegroundScriptTemplate(uint32 mapId, BattlegroundTypeId bgTypeId) const
std::map< std::pair< int32, uint32 >, BattlegroundScriptTemplate > _battlegroundScriptTemplates
static bool IsBGWeekend(BattlegroundTypeId bgTypeId)
static void BuildBattlegroundStatusFailed(WorldPackets::Battleground::BattlefieldStatusFailed *battlefieldStatus, BattlegroundQueueTypeId queueId, Player const *player, uint32 ticketId, GroupJoinBattlegroundResult result, ObjectGuid const *errorGuid=nullptr)
BattlegroundDataContainer bgDataStore
void BattlegroundQueueUpdate(uint32 diff, BattlegroundBracketId bracket_id, uint32 minRating=0)
void SetInstanceID(uint32 InstanceID)
WorldSafeLocsEntry const * GetTeamStartPosition(TeamId teamId) const
uint32 GetMapId() const
bool ToBeDeleted() const
void SetRated(bool state)
uint32 GetRemainingTime() const
BattlegroundTypeId GetTypeID() const
void Update(uint32 diff)
uint32 GetInstanceID() const
uint32 GetClientInstanceID() const
void SetClientInstanceID(uint32 InstanceID)
static TeamId GetTeamIndexByTeamId(Team team)
void SetStatus(BattlegroundStatus Status)
void SetArenaType(uint8 type)
BattlegroundBracketId GetBracketId() const
uint32 GetElapsedTime() const
void SetBracket(PVPDifficultyEntry const *bracketEntry)
void SetWeakPtr(Trinity::unique_weak_ptr< Battleground > weakRef)
static PVPDifficultyEntry const * GetBattlegroundBracketById(uint32 mapid, BattlegroundBracketId id)
Class used to access individual fields of database query result.
Definition Field.h:94
float GetFloat() const noexcept
Definition Field.cpp:85
uint32 GetUInt32() const noexcept
Definition Field.cpp:57
uint8 GetUInt8() const noexcept
Definition Field.cpp:29
static ObjectGuid const Empty
Definition ObjectGuid.h:314
bool IsEmpty() const
Definition ObjectGuid.h:362
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6193
uint32 GetBattlegroundQueueJoinTime(BattlegroundQueueTypeId bgQueueTypeId) const
Definition Player.cpp:25658
WorldSession * GetSession() const
Definition Player.h:2256
bool GetRandomWinner() const
Definition Player.h:2610
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, TeleportToOptions options=TELE_TO_NONE, Optional< uint32 > instanceId={}, uint32 teleportSpellId=0)
Definition Player.cpp:1181
Team GetBGTeam() const
Definition Player.cpp:24277
std::unique_ptr< PlayerMenu > PlayerTalkClass
Definition Player.h:2556
Specialized variant of std::shared_ptr that enforces unique ownership and/or std::unique_ptr with std...
std::string const & GetName() const
Definition Object.h:342
void HandleBattlemasterJoinArena(WorldPackets::Battleground::BattlemasterJoinArena &packet)
#define sWorld
Definition World.h:919
@ CONFIG_ARENA_MAX_RATING_DIFFERENCE
Definition World.h:341
@ CONFIG_ARENA_RATED_UPDATE_TIMER
Definition World.h:343
@ CONFIG_ARENA_RATING_DISCARD_TIMER
Definition World.h:342
@ CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER
Definition World.h:338
bool IsDisabledFor(DisableType type, uint32 entry, WorldObject const *ref, uint8 flags)
auto SelectRandomWeightedContainerElement(C const &container, std::span< double > const &weights) -> decltype(std::ranges::begin(container))
Definition Containers.h:127
auto MapGetValuePtr(M &map, typename M::key_type const &key)
Definition MapUtils.h:37
Definition Service.h:30
constexpr uint64 GetPacked() const
BattlegroundTypeId Id
BattlemasterListEntry const * BattlemasterEntry
uint16 GetMaxPlayersPerTeam() const
std::vector< int32 > MapIDs
WorldSafeLocsEntry const * StartLocation[PVP_TEAMS_COUNT]
uint16 GetMinPlayersPerTeam() const
BattlemasterType GetType() const
bool IsBattlegroundOrArena() const
BattlegroundBracketId GetBracketId() const
Optional< ObjectGuid::LowType > TransportSpawnId
Definition ObjectMgr.h:836
WorldLocation Loc
Definition ObjectMgr.h:835