feat(Core/Battleground): rework bg queue system (#10817)

This commit is contained in:
Kargatum
2022-03-16 00:36:49 +07:00
committed by GitHub
parent 6c60dc3841
commit 78bdc89881
29 changed files with 1354 additions and 963 deletions

View File

@@ -137,7 +137,7 @@ bool ArenaSpectator::HandleSpectatorSpectateCommand(ChatHandler* handler, std::s
if (uint32 inviteInstanceId = player->GetPendingSpectatorInviteInstanceId())
{
if (Battleground* tbg = sBattlegroundMgr->GetBattleground(inviteInstanceId))
if (Battleground* tbg = sBattlegroundMgr->GetBattleground(inviteInstanceId, BATTLEGROUND_TYPE_NONE))
tbg->RemoveToBeTeleported(player->GetGUID());
player->SetPendingSpectatorInviteInstanceId(0);
}

View File

@@ -312,6 +312,10 @@ void Arena::EndBattleground(TeamId winnerTeamId)
}
}
// update previous opponents for arena queue
winnerArenaTeam->SetPreviousOpponents(loserArenaTeam->GetId());
loserArenaTeam->SetPreviousOpponents(winnerArenaTeam->GetId());
// save the stat changes
if (bValidArena)
{

View File

@@ -61,7 +61,7 @@ protected:
{
RatingChange = ratingChange;
MatchmakerRating = matchMakerRating;
TeamName = teamName;
TeamName = std::string(teamName);
}
void BuildRatingInfoBlock(WorldPacket& data);

View File

@@ -345,7 +345,7 @@ void ArenaTeam::DelMember(ObjectGuid guid, bool cleanDb)
WorldPacket data;
playerMember->RemoveBattlegroundQueueId(bgQueue);
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, nullptr, playerMember->GetBattlegroundQueueIndex(bgQueue), STATUS_NONE, 0, 0, 0, TEAM_NEUTRAL);
queue.RemovePlayer(playerMember->GetGUID(), true, 0);
queue.RemovePlayer(playerMember->GetGUID(), true);
playerMember->GetSession()->SendPacket(&data);
}
}

View File

@@ -209,6 +209,9 @@ public:
void FinishWeek();
void FinishGame(int32 mod, const Map* bgMap);
void SetPreviousOpponents(uint32 arenaTeamId) { PreviousOpponents = arenaTeamId; }
uint32 GetPreviousOpponents() { return PreviousOpponents; }
void CreateTempArenaTeam(std::vector<Player*> playerList, uint8 type, std::string const& teamName);
// Containers
@@ -229,5 +232,7 @@ protected:
MemberList Members;
ArenaTeamStats Stats;
uint32 PreviousOpponents = 0;
};
#endif

View File

@@ -232,6 +232,9 @@ Battleground::~Battleground()
m_Map = nullptr;
}
// remove from bg free slot queue
RemoveFromBGFreeSlotQueue();
for (auto const& itr : PlayerScores)
delete itr.second;
}
@@ -251,8 +254,21 @@ void Battleground::Update(uint32 diff)
if (!GetPlayersSize())
{
//BG is empty
// if there are no players invited, delete BG
// this will delete arena or bg object, where any player entered
// [[ but if you use battleground object again (more battles possible to be played on 1 instance)
// then this condition should be removed and code:
// if (!GetInvitedCount(TEAM_HORDE) && !GetInvitedCount(TEAM_ALLIANCE))
// AddToFreeBGObjectsQueue(); // not yet implemented
// should be used instead of current
// ]]
// Battleground Template instance cannot be updated, because it would be deleted
if (!GetInvitedCount(TEAM_HORDE) && !GetInvitedCount(TEAM_ALLIANCE))
{
m_SetDeleteThis = true;
}
return;
}
@@ -768,6 +784,7 @@ void Battleground::EndBattleground(PvPTeamId winnerTeamId)
if (GetStatus() == STATUS_WAIT_LEAVE)
return;
RemoveFromBGFreeSlotQueue();
SetStatus(STATUS_WAIT_LEAVE);
SetWinner(winnerTeamId);
@@ -956,13 +973,17 @@ void Battleground::RemovePlayerAtLeave(Player* player)
// if the player was a match participant
if (participant)
{
WorldPacket data;
player->ClearAfkReports();
WorldPacket data;
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetCurrentBattlegroundQueueSlot(), STATUS_NONE, 0, 0, 0, TEAM_NEUTRAL);
player->GetSession()->SendPacket(&data);
BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(GetBgTypeID(), GetArenaType());
// this call is important, because player, when joins to battleground, this method is not called, so it must be called when leaving bg
player->RemoveBattlegroundQueueId(bgQueueTypeId);
// remove from raid group if player is member
if (Group* group = GetBgRaid(teamId))
if (group->IsMember(player->GetGUID()))
@@ -977,6 +998,19 @@ void Battleground::RemovePlayerAtLeave(Player* player)
if (isBattleground() && !player->IsGameMaster() && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_CAST_DESERTER))
if (status == STATUS_IN_PROGRESS || status == STATUS_WAIT_JOIN)
player->ScheduleDelayedOperation(DELAYED_SPELL_CAST_DESERTER);
DecreaseInvitedCount(teamId);
//we should update battleground queue, but only if bg isn't ending
if (isBattleground() && GetStatus() < STATUS_WAIT_LEAVE)
{
BattlegroundTypeId bgTypeId = GetBgTypeID();
BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(GetBgTypeID(), GetArenaType());
// a player has left the battleground, so there are free slots -> add to queue
AddToBGFreeSlotQueue();
sBattlegroundMgr->ScheduleQueueUpdate(0, 0, bgQueueTypeId, bgTypeId, GetBracketId());
}
}
// Remove shapeshift auras
@@ -1009,6 +1043,7 @@ void Battleground::Init()
m_BgInvitedPlayers[TEAM_ALLIANCE] = 0;
m_BgInvitedPlayers[TEAM_HORDE] = 0;
_InBGFreeSlotQueue = false;
m_Players.clear();
@@ -1028,9 +1063,15 @@ void Battleground::StartBattleground()
SetStartTime(0);
SetLastResurrectTime(0);
// add BG to free slot queue
AddToBGFreeSlotQueue();
// add bg to update list
// this must be done here, because we need to have already invited some players when first Battleground::Update() method is executed
sBattlegroundMgr->AddBattleground(this);
if (m_IsRated)
LOG_DEBUG("bg.arena", "Arena match type: {} for Team1Id: {} - Team2Id: {} started.", m_ArenaType, m_ArenaTeamIds[TEAM_ALLIANCE], m_ArenaTeamIds[TEAM_HORDE]);
}
void Battleground::AddPlayer(Player* player)
@@ -1129,6 +1170,26 @@ void Battleground::AddOrSetPlayerToCorrectBgGroup(Player* player, TeamId teamId)
}
}
// This method should be called only once ... it adds pointer to queue
void Battleground::AddToBGFreeSlotQueue()
{
if (!_InBGFreeSlotQueue && isBattleground())
{
sBattlegroundMgr->AddToBGFreeSlotQueue(m_RealTypeID, this);
_InBGFreeSlotQueue = true;
}
}
// This method removes this battleground from free queue - it must be called when deleting battleground
void Battleground::RemoveFromBGFreeSlotQueue()
{
if (_InBGFreeSlotQueue)
{
sBattlegroundMgr->RemoveFromBGFreeSlotQueue(m_RealTypeID, m_InstanceID);
_InBGFreeSlotQueue = false;
}
}
uint32 Battleground::GetFreeSlotsForTeam(TeamId teamId) const
{
if (!(GetStatus() == STATUS_IN_PROGRESS || GetStatus() == STATUS_WAIT_JOIN))
@@ -1611,6 +1672,7 @@ void Battleground::SendMessage2ToAll(uint32 entry, ChatMsg type, Player const* s
void Battleground::EndNow()
{
RemoveFromBGFreeSlotQueue();
SetStatus(STATUS_WAIT_LEAVE);
SetEndTime(0);
}
@@ -1777,6 +1839,12 @@ GraveyardStruct const* Battleground::GetClosestGraveyard(Player* player)
return sGraveyard->GetClosestGraveyard(player, player->GetBgTeamId());
}
void Battleground::SetBracket(PvPDifficultyEntry const* bracketEntry)
{
m_BracketId = bracketEntry->GetBracketId();
SetLevelRange(bracketEntry->minLevel, bracketEntry->maxLevel);
}
void Battleground::StartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry)
{
for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)

View File

@@ -316,6 +316,7 @@ public:
// Get methods:
[[nodiscard]] std::string GetName() const { return m_Name; }
[[nodiscard]] BattlegroundTypeId GetBgTypeID(bool GetRandom = false) const { return GetRandom ? m_RandomTypeID : m_RealTypeID; }
[[nodiscard]] BattlegroundBracketId GetBracketId() const { return m_BracketId; }
[[nodiscard]] uint32 GetInstanceID() const { return m_InstanceID; }
[[nodiscard]] BattlegroundStatus GetStatus() const { return m_Status; }
[[nodiscard]] uint32 GetClientInstanceID() const { return m_ClientInstanceID; }
@@ -341,6 +342,7 @@ public:
void SetName(std::string_view name) { m_Name = std::string(name); }
void SetBgTypeID(BattlegroundTypeId TypeID) { m_RealTypeID = TypeID; }
void SetRandomTypeID(BattlegroundTypeId TypeID) { m_RandomTypeID = TypeID; }
void SetBracket(PvPDifficultyEntry const* bracketEntry);
void SetInstanceID(uint32 InstanceID) { m_InstanceID = InstanceID; }
void SetStatus(BattlegroundStatus Status) { m_Status = Status; }
void SetClientInstanceID(uint32 InstanceID) { m_ClientInstanceID = InstanceID; }
@@ -361,6 +363,9 @@ public:
void SetMaxPlayersPerTeam(uint32 MaxPlayers) { m_MaxPlayersPerTeam = MaxPlayers; }
void SetMinPlayersPerTeam(uint32 MinPlayers) { m_MinPlayersPerTeam = MinPlayers; }
void AddToBGFreeSlotQueue(); // this queue will be useful when more battlegrounds instances will be available
void RemoveFromBGFreeSlotQueue(); // this method could delete whole BG instance, if another free is available
void DecreaseInvitedCount(TeamId teamId) { if (m_BgInvitedPlayers[teamId]) --m_BgInvitedPlayers[teamId]; }
void IncreaseInvitedCount(TeamId teamId) { ++m_BgInvitedPlayers[teamId]; }
[[nodiscard]] uint32 GetInvitedCount(TeamId teamId) const { return m_BgInvitedPlayers[teamId]; }
@@ -642,7 +647,9 @@ private:
uint32 m_ValidStartPositionTimer;
int32 m_EndTime; // it is set to 120000 when bg is ending and it decreases itself
uint32 m_LastResurrectTime;
BattlegroundBracketId m_BracketId{ BG_BRACKET_ID_FIRST };
uint8 m_ArenaType; // 2=2v2, 3=3v3, 5=5v5
bool _InBGFreeSlotQueue{ false }; // used to make sure that BG is only once inserted into the BattlegroundMgr.BGFreeSlotQueue[bgTypeId] deque
bool m_SetDeleteThis; // used for safe deletion of the bg after end / all players leave
bool m_IsArena;
PvPTeamId m_WinnerId;

View File

@@ -48,15 +48,22 @@
#include "WorldPacket.h"
#include <unordered_map>
bool BattlegroundTemplate::IsArena() const
{
return BattlemasterEntry->type == MAP_ARENA;
}
/*********************************************************/
/*** BATTLEGROUND MANAGER ***/
/*********************************************************/
BattlegroundMgr::BattlegroundMgr() : m_ArenaTesting(false), m_Testing(false),
m_lastClientVisibleInstanceId(0), m_NextAutoDistributionTime(0), m_AutoDistributionTimeChecker(0), m_NextPeriodicQueueUpdateTime(5 * IN_MILLISECONDS)
BattlegroundMgr::BattlegroundMgr() :
m_ArenaTesting(false),
m_Testing(false),
m_NextAutoDistributionTime(0),
m_AutoDistributionTimeChecker(0),
m_NextPeriodicQueueUpdateTime(5 * IN_MILLISECONDS)
{
for (uint32 qtype = BATTLEGROUND_QUEUE_NONE; qtype < MAX_BATTLEGROUND_QUEUE_TYPES; ++qtype)
m_BattlegroundQueues[qtype].SetBgTypeIdAndArenaType(BGTemplateId(BattlegroundQueueTypeId(qtype)), BGArenaType(BattlegroundQueueTypeId(qtype)));
}
BattlegroundMgr::~BattlegroundMgr()
@@ -72,47 +79,68 @@ BattlegroundMgr* BattlegroundMgr::instance()
void BattlegroundMgr::DeleteAllBattlegrounds()
{
while (!m_Battlegrounds.empty())
delete m_Battlegrounds.begin()->second;
m_Battlegrounds.clear();
for (auto& [_, data] : bgDataStore)
{
while (!data._Battlegrounds.empty())
delete data._Battlegrounds.begin()->second;
while (!m_BattlegroundTemplates.empty())
delete m_BattlegroundTemplates.begin()->second;
m_BattlegroundTemplates.clear();
data._Battlegrounds.clear();
while (!data.BGFreeSlotQueue.empty())
delete data.BGFreeSlotQueue.front();
}
bgDataStore.clear();
}
// used to update running battlegrounds, and delete finished ones
void BattlegroundMgr::Update(uint32 diff)
{
// update all battlegrounds and delete if needed
for (BattlegroundContainer::iterator itr = m_Battlegrounds.begin(), itrDelete; itr != m_Battlegrounds.end(); )
for (auto& [_, bgData] : bgDataStore)
{
itrDelete = itr++;
Battleground* bg = itrDelete->second;
bg->Update(diff);
if (bg->ToBeDeleted())
auto& bgList = bgData._Battlegrounds;
auto itrDelete = bgList.begin();
// first one is template and should not be deleted
for (BattlegroundContainer::iterator itr = ++itrDelete; itr != bgList.end();)
{
itrDelete->second = nullptr;
m_Battlegrounds.erase(itrDelete);
delete bg;
itrDelete = itr++;
Battleground* bg = itrDelete->second;
bg->Update(diff);
if (bg->ToBeDeleted())
{
itrDelete->second = nullptr;
bgList.erase(itrDelete);
BattlegroundClientIdsContainer& clients = bgData._ClientBattlegroundIds[bg->GetBracketId()];
if (!clients.empty())
clients.erase(bg->GetClientInstanceID());
delete bg;
}
}
}
// update events
for (int qtype = BATTLEGROUND_QUEUE_NONE; qtype < MAX_BATTLEGROUND_QUEUE_TYPES; ++qtype)
for (uint8 qtype = BATTLEGROUND_QUEUE_NONE; qtype < MAX_BATTLEGROUND_QUEUE_TYPES; ++qtype)
m_BattlegroundQueues[qtype].UpdateEvents(diff);
// update using scheduled tasks (used only for rated arenas, initial opponent search works differently than periodic queue update)
if (!m_ArenaQueueUpdateScheduler.empty())
if (!m_QueueUpdateScheduler.empty())
{
std::vector<uint64> scheduled;
std::swap(scheduled, m_ArenaQueueUpdateScheduler);
std::swap(scheduled, m_QueueUpdateScheduler);
for (uint8 i = 0; i < scheduled.size(); i++)
{
uint32 arenaRatedTeamId = scheduled[i] >> 32;
uint32 arenaMMRating = scheduled[i] >> 32;
uint8 arenaType = scheduled[i] >> 24 & 255;
BattlegroundQueueTypeId bgQueueTypeId = BattlegroundQueueTypeId(scheduled[i] >> 16 & 255);
BattlegroundTypeId bgTypeId = BattlegroundTypeId((scheduled[i] >> 8) & 255);
BattlegroundBracketId bracket_id = BattlegroundBracketId(scheduled[i] & 255);
m_BattlegroundQueues[bgQueueTypeId].BattlegroundQueueUpdate(diff, bracket_id, true, arenaRatedTeamId); // pussywizard: looking for opponents only for this team
m_BattlegroundQueues[bgQueueTypeId].BattlegroundQueueUpdate(diff, bgTypeId, bracket_id, arenaType, arenaMMRating > 0, arenaMMRating);
}
}
@@ -121,16 +149,16 @@ void BattlegroundMgr::Update(uint32 diff)
{
m_NextPeriodicQueueUpdateTime = 5 * IN_MILLISECONDS;
LOG_TRACE("bg.arena", "BattlegroundMgr: UPDATING ARENA QUEUES");
// for rated arenas
for (uint32 qtype = BATTLEGROUND_QUEUE_2v2; qtype < MAX_BATTLEGROUND_QUEUE_TYPES; ++qtype)
{
for (uint32 bracket = BG_BRACKET_ID_FIRST; bracket < MAX_BATTLEGROUND_BRACKETS; ++bracket)
m_BattlegroundQueues[qtype].BattlegroundQueueUpdate(m_NextPeriodicQueueUpdateTime, BattlegroundBracketId(bracket), true, 0); // pussywizard: 0 for rated means looking for opponents for every team
// for battlegrounds and not rated arenas
// in first loop try to fill already running battlegrounds, then in a second loop try to create new battlegrounds
for (uint32 qtype = BATTLEGROUND_QUEUE_AV; qtype < MAX_BATTLEGROUND_QUEUE_TYPES; ++qtype)
for (uint32 bracket = BG_BRACKET_ID_FIRST; bracket < MAX_BATTLEGROUND_BRACKETS; ++bracket)
m_BattlegroundQueues[qtype].BattlegroundQueueUpdate(m_NextPeriodicQueueUpdateTime, BattlegroundBracketId(bracket), false, 0);
{
m_BattlegroundQueues[qtype].BattlegroundQueueUpdate(diff, BATTLEGROUND_AA, BattlegroundBracketId(bracket), BattlegroundMgr::BGArenaType(BattlegroundQueueTypeId(qtype)), true, 0);
}
}
}
else
m_NextPeriodicQueueUpdateTime -= diff;
@@ -225,36 +253,108 @@ void BattlegroundMgr::BuildPlayerJoinedBattlegroundPacket(WorldPacket* data, Pla
*data << player->GetGUID();
}
Battleground* BattlegroundMgr::GetBattleground(uint32 instanceId)
Battleground* BattlegroundMgr::GetBattlegroundThroughClientInstance(uint32 instanceId, BattlegroundTypeId bgTypeId)
{
//cause at HandleBattlegroundJoinOpcode the clients sends the instanceid he gets from
//SMSG_BATTLEFIELD_LIST we need to find the battleground with this clientinstance-id
Battleground* bg = GetBattlegroundTemplate(bgTypeId);
if (!bg)
return nullptr;
if (bg->isArena())
return GetBattleground(instanceId, bgTypeId);
auto const& it = bgDataStore.find(bgTypeId);
if (it == bgDataStore.end())
return nullptr;
for (auto const& itr : it->second._Battlegrounds)
{
if (itr.second->GetClientInstanceID() == instanceId)
return itr.second;
}
return nullptr;
}
Battleground* BattlegroundMgr::GetBattleground(uint32 instanceId, BattlegroundTypeId bgTypeId)
{
if (!instanceId)
return nullptr;
BattlegroundContainer::const_iterator itr = m_Battlegrounds.find(instanceId);
if (itr != m_Battlegrounds.end())
return itr->second;
auto GetBgWithInstanceID = [instanceId](BattlegroundData const* bgData) -> Battleground*
{
auto const& itr = bgData->_Battlegrounds.find(instanceId);
if (itr != bgData->_Battlegrounds.end())
return itr->second;
return nullptr;
};
if (bgTypeId == BATTLEGROUND_TYPE_NONE)
{
for (auto const& [bgType, bgData] : bgDataStore)
{
if (auto bg = GetBgWithInstanceID(&bgData))
return bg;
}
}
else
{
auto const& itr = bgDataStore.find(bgTypeId);
if (itr == bgDataStore.end())
return nullptr;
if (auto bg = GetBgWithInstanceID(&itr->second))
return bg;
}
return nullptr;
}
Battleground* BattlegroundMgr::GetBattlegroundTemplate(BattlegroundTypeId bgTypeId)
{
BattlegroundTemplateContainer::const_iterator itr = m_BattlegroundTemplates.find(bgTypeId);
if (itr != m_BattlegroundTemplates.end())
return itr->second;
BattlegroundDataContainer::const_iterator itr = bgDataStore.find(bgTypeId);
if (itr == bgDataStore.end())
return nullptr;
return nullptr;
BattlegroundContainer const& bgs = itr->second._Battlegrounds;
// map is sorted and we can be sure that lowest instance id has only BG template
return bgs.empty() ? nullptr : bgs.begin()->second;
}
uint32 BattlegroundMgr::GetNextClientVisibleInstanceId()
uint32 BattlegroundMgr::CreateClientVisibleInstanceId(BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id)
{
return ++m_lastClientVisibleInstanceId;
if (IsArenaType(bgTypeId))
return 0; // arenas don't have client-instanceids
// we create here an instanceid, which is just for
// displaying this to the client and without any other use..
// the client-instanceIds are unique for each battleground-type
// the instance-id just needs to be as low as possible, beginning with 1
// the following works, because std::set is default ordered with "<"
// the optimalization would be to use as bitmask std::vector<uint32> - but that would only make code unreadable
BattlegroundClientIdsContainer& clientIds = bgDataStore[bgTypeId]._ClientBattlegroundIds[bracket_id];
uint32 lastId = 0;
for (BattlegroundClientIdsContainer::const_iterator itr = clientIds.begin(); itr != clientIds.end();)
{
if ((++lastId) != *itr) // if there is a gap between the ids, we will break..
break;
lastId = *itr;
}
clientIds.emplace(++lastId);
return lastId;
}
// create a new battleground that will really be used to play
Battleground* BattlegroundMgr::CreateNewBattleground(BattlegroundTypeId originalBgTypeId, uint32 minLevel, uint32 maxLevel, uint8 arenaType, bool isRated)
Battleground* BattlegroundMgr::CreateNewBattleground(BattlegroundTypeId originalBgTypeId, PvPDifficultyEntry const* bracketEntry, uint8 arenaType, bool isRated)
{
BattlegroundTypeId bgTypeId = GetRandomBG(originalBgTypeId, minLevel);
BattlegroundTypeId bgTypeId = GetRandomBG(originalBgTypeId, bracketEntry->minLevel);
if (originalBgTypeId == BATTLEGROUND_AA)
originalBgTypeId = bgTypeId;
@@ -262,9 +362,13 @@ Battleground* BattlegroundMgr::CreateNewBattleground(BattlegroundTypeId original
// get the template BG
Battleground* bg_template = GetBattlegroundTemplate(bgTypeId);
if (!bg_template)
{
LOG_ERROR("bg.battleground", "Battleground: CreateNewBattleground - bg template not found for {}", bgTypeId);
return nullptr;
}
Battleground* bg = nullptr;
// create a copy of the BG template
if (BattlegroundMgr::bgTypeToTemplate.find(bgTypeId) == BattlegroundMgr::bgTypeToTemplate.end())
{
@@ -275,9 +379,9 @@ Battleground* BattlegroundMgr::CreateNewBattleground(BattlegroundTypeId original
bool isRandom = bgTypeId != originalBgTypeId && !bg->isArena();
bg->SetLevelRange(minLevel, maxLevel);
bg->SetBracket(bracketEntry);
bg->SetInstanceID(sMapMgr->GenerateInstanceId());
bg->SetClientInstanceID(IsArenaType(originalBgTypeId) ? 0 : GetNextClientVisibleInstanceId());
bg->SetClientInstanceID(CreateClientVisibleInstanceId(originalBgTypeId, bracketEntry->GetBracketId()));
bg->Init();
bg->SetStatus(STATUS_WAIT_JOIN); // start the joining of the bg
bg->SetArenaType(arenaType);
@@ -298,37 +402,40 @@ Battleground* BattlegroundMgr::CreateNewBattleground(BattlegroundTypeId original
}
// used to create the BG templates
bool BattlegroundMgr::CreateBattleground(CreateBattlegroundData& data)
bool BattlegroundMgr::CreateBattleground(BattlegroundTemplate const* bgTemplate)
{
// Create the BG
Battleground* bg = nullptr;
bg = BattlegroundMgr::bgtypeToBattleground[data.bgTypeId];
Battleground* bg = GetBattlegroundTemplate(bgTemplate->Id);
if (bg == nullptr)
return false;
if (!bg)
{
bg = BattlegroundMgr::bgtypeToBattleground[bgTemplate->Id];
if (data.bgTypeId == BATTLEGROUND_RB)
bg->SetRandom(true);
ASSERT(bg);
bg->SetMapId(data.MapID);
bg->SetBgTypeID(data.bgTypeId);
bg->SetInstanceID(0);
bg->SetArenaorBGType(data.IsArena);
bg->SetMinPlayersPerTeam(data.MinPlayersPerTeam);
bg->SetMaxPlayersPerTeam(data.MaxPlayersPerTeam);
bg->SetName(data.BattlegroundName);
bg->SetTeamStartPosition(TEAM_ALLIANCE, data.StartLocation[TEAM_ALLIANCE]);
bg->SetTeamStartPosition(TEAM_HORDE, data.StartLocation[TEAM_HORDE]);
bg->SetStartMaxDist(data.StartMaxDist);
bg->SetLevelRange(data.LevelMin, data.LevelMax);
bg->SetScriptId(data.scriptId);
if (bgTemplate->Id == BATTLEGROUND_RB)
bg->SetRandom(true);
AddBattleground(bg);
bg->SetBgTypeID(bgTemplate->Id);
bg->SetInstanceID(0);
AddBattleground(bg);
}
bg->SetMapId(bgTemplate->BattlemasterEntry->mapid[0]);
bg->SetName(bgTemplate->BattlemasterEntry->name[sWorld->GetDefaultDbcLocale()]);
bg->SetArenaorBGType(bgTemplate->IsArena());
bg->SetMinPlayersPerTeam(bgTemplate->MinPlayersPerTeam);
bg->SetMaxPlayersPerTeam(bgTemplate->MaxPlayersPerTeam);
bg->SetTeamStartPosition(TEAM_ALLIANCE, bgTemplate->StartLocation[TEAM_ALLIANCE]);
bg->SetTeamStartPosition(TEAM_HORDE, bgTemplate->StartLocation[TEAM_HORDE]);
bg->SetStartMaxDist(bgTemplate->MaxStartDistSq);
bg->SetLevelRange(bgTemplate->MinLevel, bgTemplate->MaxLevel);
bg->SetScriptId(bgTemplate->ScriptId);
return true;
}
void BattlegroundMgr::CreateInitialBattlegrounds()
void BattlegroundMgr::LoadBattlegroundTemplates()
{
uint32 oldMSTime = getMSTime();
@@ -344,13 +451,11 @@ void BattlegroundMgr::CreateInitialBattlegrounds()
return;
}
uint32 count = 0;
do
{
Field* fields = result->Fetch();
uint32 bgTypeId = fields[0].Get<uint32>();
BattlegroundTypeId bgTypeId = static_cast<BattlegroundTypeId>(fields[0].Get<uint32>());
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, bgTypeId, nullptr))
continue;
@@ -363,72 +468,69 @@ void BattlegroundMgr::CreateInitialBattlegrounds()
continue;
}
CreateBattlegroundData data;
data.bgTypeId = BattlegroundTypeId(bgTypeId);
data.IsArena = (bl->type == TYPE_ARENA);
data.MinPlayersPerTeam = fields[1].Get<uint16>();
data.MaxPlayersPerTeam = fields[2].Get<uint16>();
data.LevelMin = fields[3].Get<uint8>();
data.LevelMax = fields[4].Get<uint8>();
BattlegroundTemplate bgTemplate;
bgTemplate.Id = bgTypeId;
bgTemplate.MinPlayersPerTeam = fields[1].Get<uint16>();
bgTemplate.MaxPlayersPerTeam = fields[2].Get<uint16>();
bgTemplate.MinLevel = fields[3].Get<uint8>();
bgTemplate.MaxLevel = fields[4].Get<uint8>();
float dist = fields[9].Get<float>();
data.StartMaxDist = dist * dist;
data.Weight = fields[10].Get<uint8>();
bgTemplate.MaxStartDistSq = dist * dist;
bgTemplate.Weight = fields[10].Get<uint8>();
bgTemplate.ScriptId = sObjectMgr->GetScriptId(fields[11].Get<std::string>());
bgTemplate.BattlemasterEntry = bl;
data.scriptId = sObjectMgr->GetScriptId(fields[11].Get<std::string>());
data.BattlegroundName = bl->name[sWorld->GetDefaultDbcLocale()];
data.MapID = bl->mapid[0];
if (data.MaxPlayersPerTeam == 0 || data.MinPlayersPerTeam > data.MaxPlayersPerTeam)
if (bgTemplate.MaxPlayersPerTeam == 0 || bgTemplate.MinPlayersPerTeam > bgTemplate.MaxPlayersPerTeam)
{
LOG_ERROR("bg.battleground", "Table `battleground_template` for id {} has bad values for MinPlayersPerTeam ({}) and MaxPlayersPerTeam({})",
data.bgTypeId, data.MinPlayersPerTeam, data.MaxPlayersPerTeam);
LOG_ERROR("sql.sql", "Table `battleground_template` for id {} contains bad values for MinPlayersPerTeam ({}) and MaxPlayersPerTeam({}).",
bgTemplate.Id, bgTemplate.MinPlayersPerTeam, bgTemplate.MaxPlayersPerTeam);
continue;
}
if (data.LevelMin == 0 || data.LevelMax == 0 || data.LevelMin > data.LevelMax)
if (bgTemplate.MinLevel == 0 || bgTemplate.MaxLevel == 0 || bgTemplate.MinLevel > bgTemplate.MaxLevel)
{
LOG_ERROR("bg.battleground", "Table `battleground_template` for id {} has bad values for LevelMin ({}) and LevelMax({})",
data.bgTypeId, data.LevelMin, data.LevelMax);
LOG_ERROR("sql.sql", "Table `battleground_template` for id {} has bad values for LevelMin ({}) and LevelMax({})",
bgTemplate.Id, bgTemplate.MinLevel, bgTemplate.MaxLevel);
continue;
}
if (data.bgTypeId != BATTLEGROUND_AA && data.bgTypeId != BATTLEGROUND_RB)
if (bgTemplate.Id != BATTLEGROUND_AA && bgTemplate.Id != BATTLEGROUND_RB)
{
uint32 startId = fields[5].Get<uint32>();
if (GraveyardStruct const* start = sGraveyard->GetGraveyard(startId))
{
data.StartLocation[TEAM_ALLIANCE].Relocate(start->x, start->y, start->z, fields[6].Get<float>());
bgTemplate.StartLocation[TEAM_ALLIANCE].Relocate(start->x, start->y, start->z, fields[6].Get<float>());
}
else
{
LOG_ERROR("sql.sql", "Table `battleground_template` for id %u contains a non-existing WorldSafeLocs.dbc id %u in field `AllianceStartLoc`. BG not created.", data.bgTypeId, startId);
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);
continue;
}
startId = fields[7].Get<uint32>();
if (GraveyardStruct const* start = sGraveyard->GetGraveyard(startId))
{
data.StartLocation[TEAM_HORDE].Relocate(start->x, start->y, start->z, fields[8].Get<float>());
bgTemplate.StartLocation[TEAM_HORDE].Relocate(start->x, start->y, start->z, fields[8].Get<float>());
}
else
{
LOG_ERROR("sql.sql", "Table `battleground_template` for id %u contains a non-existing WorldSafeLocs.dbc id %u in field `HordeStartLoc`. BG not created.", data.bgTypeId, startId);
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);
continue;
}
}
if (!CreateBattleground(data))
if (!CreateBattleground(&bgTemplate))
continue;
_battlegroundTemplates[BattlegroundTypeId(bgTypeId)] = data;
_battlegroundTemplates[bgTypeId] = bgTemplate;
if (bl->mapid[1] == -1) // in this case we have only one mapId
_battlegroundMapTemplates[bl->mapid[0]] = &_battlegroundTemplates[BattlegroundTypeId(bgTypeId)];
if (bgTemplate.BattlemasterEntry->mapid[1] == -1) // in this case we have only one mapId
_battlegroundMapTemplates[bgTemplate.BattlemasterEntry->mapid[0]] = &_battlegroundTemplates[bgTypeId];
++count;
} while (result->NextRow());
LOG_INFO("server.loading", ">> Loaded {} battlegrounds in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", ">> Loaded {} battlegrounds in {} ms", _battlegroundTemplates.size(), GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", " ");
}
@@ -499,23 +601,31 @@ void BattlegroundMgr::BuildBattlegroundListPacket(WorldPacket* data, ObjectGuid
size_t count_pos = data->wpos();
*data << uint32(0); // number of bg instances
if (Battleground* bgt = GetBattlegroundTemplate(bgTypeId))
if (GetBattlegroundBracketByLevel(bgt->GetMapId(), player->getLevel()))
auto const& it = bgDataStore.find(bgTypeId);
if (it != bgDataStore.end())
{
// expected bracket entry
if (PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(it->second._Battlegrounds.begin()->second->GetMapId(), player->getLevel()))
{
uint32 count = 0;
/*for (BattlegroundClientIdsContainer::const_iterator itr = clientIds.begin(); itr != clientIds.end(); ++itr)
BattlegroundBracketId bracketId = bracketEntry->GetBracketId();
BattlegroundClientIdsContainer& clientIds = it->second._ClientBattlegroundIds[bracketId];
for (auto const& itr : clientIds)
{
*data << uint32(*itr);
*data << uint32(itr);
++count;
}*/
}
data->put<uint32>(count_pos, count);
}
}
}
}
void BattlegroundMgr::SendToBattleground(Player* player, uint32 instanceId, BattlegroundTypeId bgTypeId)
{
if (Battleground* bg = GetBattleground(instanceId))
if (Battleground* bg = GetBattleground(instanceId, bgTypeId))
{
uint32 mapid = bg->GetMapId();
Position const* pos = bg->GetTeamStartPosition(player->GetBgTeamId());
@@ -636,11 +746,25 @@ void BattlegroundMgr::SetHolidayWeekends(uint32 mask)
}
}
void BattlegroundMgr::ScheduleArenaQueueUpdate(uint32 arenaRatedTeamId, BattlegroundQueueTypeId bgQueueTypeId, BattlegroundBracketId bracket_id)
void BattlegroundMgr::ScheduleQueueUpdate(uint32 arenaMatchmakerRating, uint8 arenaType, BattlegroundQueueTypeId bgQueueTypeId, BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id)
{
uint64 const scheduleId = ((uint64)arenaRatedTeamId << 32) | (bgQueueTypeId << 16) | bracket_id;
if (std::find(m_ArenaQueueUpdateScheduler.begin(), m_ArenaQueueUpdateScheduler.end(), scheduleId) == m_ArenaQueueUpdateScheduler.end())
m_ArenaQueueUpdateScheduler.push_back(scheduleId);
//This method must be atomic, @todo add mutex
//we will use only 1 number created of bgTypeId and bracket_id
uint64 const scheduleId = ((uint64)arenaMatchmakerRating << 32) | ((uint64)arenaType << 24) | ((uint64)bgQueueTypeId << 16) | ((uint64)bgTypeId << 8) | (uint64)bracket_id;
if (std::find(m_QueueUpdateScheduler.begin(), m_QueueUpdateScheduler.end(), scheduleId) == m_QueueUpdateScheduler.end())
m_QueueUpdateScheduler.emplace_back(scheduleId);
}
uint32 BattlegroundMgr::GetMaxRatingDifference() const
{
uint32 diff = sWorld->getIntConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE);
if (diff == 0)
{
diff = 5000;
}
return diff;
}
uint32 BattlegroundMgr::GetRatingDiscardTimer() const
@@ -766,24 +890,23 @@ bool BattlegroundMgr::IsBGWeekend(BattlegroundTypeId bgTypeId)
BattlegroundTypeId BattlegroundMgr::GetRandomBG(BattlegroundTypeId bgTypeId, uint32 minLevel)
{
if (GetBattlegroundTemplateByTypeId(bgTypeId))
if (BattlegroundTemplate const* bgTemplate = GetBattlegroundTemplateByTypeId(bgTypeId))
{
std::vector<BattlegroundTypeId> ids;
ids.reserve(16);
std::vector<double> weights;
weights.reserve(16);
BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId);
for (int32 mapId : bl->mapid)
for (int32 mapId : bgTemplate->BattlemasterEntry->mapid)
{
if (mapId == -1)
break;
if (CreateBattlegroundData const* bg = GetBattlegroundTemplateByMapId(mapId))
if (BattlegroundTemplate const* bg = GetBattlegroundTemplateByMapId(mapId))
{
if (bg->LevelMin <= minLevel)
if (bg->MinLevel <= minLevel)
{
ids.push_back(bg->bgTypeId);
ids.push_back(bg->Id);
weights.push_back(bg->Weight);
}
}
@@ -795,30 +918,38 @@ BattlegroundTypeId BattlegroundMgr::GetRandomBG(BattlegroundTypeId bgTypeId, uin
return BATTLEGROUND_TYPE_NONE;
}
BGFreeSlotQueueContainer& BattlegroundMgr::GetBGFreeSlotQueueStore(BattlegroundTypeId bgTypeId)
{
return bgDataStore[bgTypeId].BGFreeSlotQueue;
}
void BattlegroundMgr::AddToBGFreeSlotQueue(BattlegroundTypeId bgTypeId, Battleground* bg)
{
bgDataStore[bgTypeId].BGFreeSlotQueue.push_front(bg);
}
void BattlegroundMgr::RemoveFromBGFreeSlotQueue(BattlegroundTypeId bgTypeId, uint32 instanceId)
{
BGFreeSlotQueueContainer& queues = bgDataStore[bgTypeId].BGFreeSlotQueue;
for (BGFreeSlotQueueContainer::iterator itr = queues.begin(); itr != queues.end(); ++itr)
if ((*itr)->GetInstanceID() == instanceId)
{
queues.erase(itr);
return;
}
}
void BattlegroundMgr::AddBattleground(Battleground* bg)
{
if (bg->GetInstanceID() == 0)
m_BattlegroundTemplates[bg->GetBgTypeID()] = bg;
else
m_Battlegrounds[bg->GetInstanceID()] = bg;
if (bg)
bgDataStore[bg->GetBgTypeID()]._Battlegrounds[bg->GetInstanceID()] = bg;
sScriptMgr->OnBattlegroundCreate(bg);
}
void BattlegroundMgr::RemoveBattleground(BattlegroundTypeId bgTypeId, uint32 instanceId)
{
if (instanceId == 0)
m_BattlegroundTemplates.erase(bgTypeId);
else
m_Battlegrounds.erase(instanceId);
}
void BattlegroundMgr::DoForAllBattlegrounds(std::function<void(Battleground*)> const& worker)
{
for (auto const& [_, bg] : m_Battlegrounds)
{
worker(bg);
}
bgDataStore[bgTypeId]._Battlegrounds.erase(instanceId);
}
// init/update unordered_map

View File

@@ -27,29 +27,38 @@
#include <functional>
typedef std::map<uint32, Battleground*> BattlegroundContainer;
typedef std::set<uint32> BattlegroundClientIdsContainer;
typedef std::unordered_map<uint32, BattlegroundTypeId> BattleMastersMap;
typedef Battleground* (*bgRef)(Battleground*);
typedef void(*bgMapRef)(WorldPacket*, Battleground::BattlegroundScoreMap::const_iterator);
typedef void(*bgTypeRef)(WorldPacket*, Battleground::BattlegroundScoreMap::const_iterator, Battleground*);
struct CreateBattlegroundData
// this container can't be deque, because deque doesn't like removing the last element - if you remove it, it invalidates next iterator and crash appears
using BGFreeSlotQueueContainer = std::list<Battleground*>;
struct BattlegroundData
{
BattlegroundTypeId bgTypeId;
bool IsArena;
uint32 MinPlayersPerTeam;
uint32 MaxPlayersPerTeam;
uint32 LevelMin;
uint32 LevelMax;
char const* BattlegroundName;
uint32 MapID;
float StartMaxDist;
std::array<Position, PVP_TEAMS_COUNT> StartLocation;
uint32 scriptId;
uint8 Weight;
BattlegroundContainer _Battlegrounds;
std::array<BattlegroundClientIdsContainer, MAX_BATTLEGROUND_BRACKETS> _ClientBattlegroundIds;
BGFreeSlotQueueContainer BGFreeSlotQueue;
};
struct GroupQueueInfo;
struct BattlegroundTemplate
{
BattlegroundTypeId Id;
uint16 MinPlayersPerTeam;
uint16 MaxPlayersPerTeam;
uint8 MinLevel;
uint8 MaxLevel;
std::array<Position, PVP_TEAMS_COUNT> StartLocation;
float MaxStartDistSq;
uint8 Weight;
uint32 ScriptId;
BattlemasterListEntry const* BattlemasterEntry;
bool IsArena() const;
};
class BattlegroundMgr
{
@@ -71,21 +80,25 @@ public:
void SendAreaSpiritHealerQueryOpcode(Player* player, Battleground* bg, ObjectGuid guid);
/* Battlegrounds */
Battleground* GetBattleground(uint32 InstanceID);
Battleground* GetBattlegroundThroughClientInstance(uint32 instanceId, BattlegroundTypeId bgTypeId);
Battleground* GetBattleground(uint32 instanceID, BattlegroundTypeId bgTypeId);
Battleground* GetBattlegroundTemplate(BattlegroundTypeId bgTypeId);
Battleground* CreateNewBattleground(BattlegroundTypeId bgTypeId, uint32 minLevel, uint32 maxLevel, uint8 arenaType, bool isRated);
Battleground* CreateNewBattleground(BattlegroundTypeId bgTypeId, PvPDifficultyEntry const* bracketEntry, uint8 arenaType, bool isRated);
void AddBattleground(Battleground* bg);
void RemoveBattleground(BattlegroundTypeId bgTypeId, uint32 instanceId);
void AddToBGFreeSlotQueue(BattlegroundTypeId bgTypeId, Battleground* bg);
void RemoveFromBGFreeSlotQueue(BattlegroundTypeId bgTypeId, uint32 instanceId);
BGFreeSlotQueueContainer& GetBGFreeSlotQueueStore(BattlegroundTypeId bgTypeId);
void CreateInitialBattlegrounds();
void LoadBattlegroundTemplates();
void DeleteAllBattlegrounds();
void SendToBattleground(Player* player, uint32 InstanceID, BattlegroundTypeId bgTypeId);
/* Battleground queues */
BattlegroundQueue& GetBattlegroundQueue(BattlegroundQueueTypeId bgQueueTypeId) { return m_BattlegroundQueues[bgQueueTypeId]; }
void ScheduleArenaQueueUpdate(uint32 arenaRatedTeamId, BattlegroundQueueTypeId bgQueueTypeId, BattlegroundBracketId bracket_id);
void ScheduleQueueUpdate(uint32 arenaMatchmakerRating, uint8 arenaType, BattlegroundQueueTypeId bgQueueTypeId, BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id);
uint32 GetPrematureFinishTime() const;
void ToggleArenaTesting();
@@ -105,10 +118,12 @@ public:
static BattlegroundTypeId WeekendHolidayIdToBGType(HolidayIds holiday);
static bool IsBGWeekend(BattlegroundTypeId bgTypeId);
uint32 GetRatingDiscardTimer() const;
uint32 GetMaxRatingDifference() const;
uint32 GetRatingDiscardTimer() const;
void InitAutomaticArenaPointDistribution();
void LoadBattleMastersEntry();
void CheckBattleMasters();
BattlegroundTypeId GetBattleMasterBG(uint32 entry) const
{
BattleMastersMap::const_iterator itr = mBattleMastersMap.find(entry);
@@ -117,8 +132,6 @@ public:
return BATTLEGROUND_TYPE_NONE;
}
const BattlegroundContainer& GetBattlegroundList() { return m_Battlegrounds; } // pussywizard
static std::unordered_map<int, BattlegroundQueueTypeId> bgToQueue; // BattlegroundTypeId -> BattlegroundQueueTypeId
static std::unordered_map<int, BattlegroundTypeId> queueToBg; // BattlegroundQueueTypeId -> BattlegroundTypeId
static std::unordered_map<int, Battleground*> bgtypeToBattleground; // BattlegroundTypeId -> Battleground*
@@ -128,48 +141,46 @@ public:
static std::unordered_map<uint32, BattlegroundQueueTypeId> ArenaTypeToQueue; // ArenaType -> BattlegroundQueueTypeId
static std::unordered_map<uint32, ArenaType> QueueToArenaType; // BattlegroundQueueTypeId -> ArenaType
void DoForAllBattlegrounds(std::function<void(Battleground*)> const& worker);
private:
bool CreateBattleground(CreateBattlegroundData& data);
uint32 GetNextClientVisibleInstanceId();
bool CreateBattleground(BattlegroundTemplate const* bgTemplate);
uint32 CreateClientVisibleInstanceId(BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id);
BattlegroundTypeId GetRandomBG(BattlegroundTypeId id, uint32 minLevel);
typedef std::map<BattlegroundTypeId, Battleground*> BattlegroundTemplateContainer;
BattlegroundTemplateContainer m_BattlegroundTemplates;
BattlegroundContainer m_Battlegrounds;
typedef std::map<BattlegroundTypeId, BattlegroundData> BattlegroundDataContainer;
BattlegroundDataContainer bgDataStore;
BattlegroundQueue m_BattlegroundQueues[MAX_BATTLEGROUND_QUEUE_TYPES];
std::vector<uint64> m_ArenaQueueUpdateScheduler;
std::vector<uint64> m_QueueUpdateScheduler;
bool m_ArenaTesting;
bool m_Testing;
uint32 m_lastClientVisibleInstanceId;
Seconds m_NextAutoDistributionTime;
uint32 m_AutoDistributionTimeChecker;
uint32 m_NextPeriodicQueueUpdateTime;
BattleMastersMap mBattleMastersMap;
CreateBattlegroundData const* GetBattlegroundTemplateByTypeId(BattlegroundTypeId id)
BattlegroundTemplate const* GetBattlegroundTemplateByTypeId(BattlegroundTypeId id)
{
BattlegroundTemplateMap::const_iterator itr = _battlegroundTemplates.find(id);
auto const& itr = _battlegroundTemplates.find(id);
if (itr != _battlegroundTemplates.end())
return &itr->second;
return nullptr;
}
CreateBattlegroundData const* GetBattlegroundTemplateByMapId(uint32 mapId)
BattlegroundTemplate const* GetBattlegroundTemplateByMapId(uint32 mapId)
{
BattlegroundMapTemplateContainer::const_iterator itr = _battlegroundMapTemplates.find(mapId);
auto const& itr = _battlegroundMapTemplates.find(mapId);
if (itr != _battlegroundMapTemplates.end())
return itr->second;
return nullptr;
}
typedef std::map<BattlegroundTypeId, uint8 /*weight*/> BattlegroundSelectionWeightMap;
typedef std::map<BattlegroundTypeId, CreateBattlegroundData> BattlegroundTemplateMap;
typedef std::map<uint32 /*mapId*/, CreateBattlegroundData*> BattlegroundMapTemplateContainer;
typedef std::map<BattlegroundTypeId, BattlegroundTemplate> BattlegroundTemplateMap;
typedef std::map<uint32 /*mapId*/, BattlegroundTemplate*> BattlegroundMapTemplateContainer;
BattlegroundTemplateMap _battlegroundTemplates;
BattlegroundMapTemplateContainer _battlegroundMapTemplates;
};

File diff suppressed because it is too large Load Diff

View File

@@ -25,7 +25,7 @@
#include <array>
#include <deque>
#define COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME 10
constexpr auto COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME = 10;
struct GroupQueueInfo // stores information about the group in queue (also used when joined as solo!)
{
@@ -43,10 +43,9 @@ struct GroupQueueInfo // stores informatio
uint32 ArenaMatchmakerRating; // if rated match, inited to the rating of the team
uint32 OpponentsTeamRating; // for rated arena matches
uint32 OpponentsMatchmakerRating; // for rated arena matches
// pussywizard: for internal use
uint8 _bracketId;
uint8 _groupType;
uint32 PreviousOpponentsTeamId; // excluded from the current queue until the timer is met
uint8 BracketId; // BattlegroundBracketId
uint8 GroupType; // BattlegroundQueueGroupTypes
};
enum BattlegroundQueueGroupTypes
@@ -61,22 +60,21 @@ enum BattlegroundQueueGroupTypes
BG_QUEUE_MAX = 10
};
class Battleground;
class BattlegroundQueue
{
public:
BattlegroundQueue();
~BattlegroundQueue();
void BattlegroundQueueUpdate(uint32 diff, BattlegroundBracketId bracket_id, bool isRated, uint32 arenaRatedTeamId);
void BattlegroundQueueUpdate(uint32 diff, BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id, uint8 arenaType, bool isRated, uint32 arenaRating);
void UpdateEvents(uint32 diff);
void FillPlayersToBG(Battleground* bg, int32 aliFree, int32 hordeFree, BattlegroundBracketId bracket_id);
void FillPlayersToBG(Battleground* bg, BattlegroundBracketId bracket_id);
bool CheckPremadeMatch(BattlegroundBracketId bracket_id, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam);
bool CheckNormalMatch(Battleground* bgTemplate, BattlegroundBracketId bracket_id, uint32 minPlayers, uint32 maxPlayers);
bool CheckSkirmishForSameFaction(BattlegroundBracketId bracket_id, uint32 minPlayersPerTeam);
GroupQueueInfo* AddGroup(Player* leader, Group* group, PvPDifficultyEntry const* bracketEntry, bool isRated, bool isPremade, uint32 ArenaRating, uint32 MatchmakerRating, uint32 ArenaTeamId);
void RemovePlayer(ObjectGuid guid, bool sentToBg, uint32 playerQueueSlot);
GroupQueueInfo* AddGroup(Player* leader, Group* group, BattlegroundTypeId bgTypeId, PvPDifficultyEntry const* bracketEntry, uint8 arenaType, bool isRated, bool isPremade, uint32 arenaRating, uint32 matchmakerRating, uint32 arenaTeamId = 0, uint32 opponentsArenaTeamId = 0);
void RemovePlayer(ObjectGuid guid, bool decreaseInvitedCount);
bool IsPlayerInvitedToRatedArena(ObjectGuid pl_guid);
bool IsPlayerInvited(ObjectGuid pl_guid, uint32 bgInstanceGuid, uint32 removeTime);
bool GetPlayerGroupInfoData(ObjectGuid guid, GroupQueueInfo* ginfo);
@@ -89,7 +87,6 @@ public:
void SendJoinMessageArenaQueue(Player* leader, GroupQueueInfo* ginfo, PvPDifficultyEntry const* bracketEntry, bool isRated);
void SendExitMessageArenaQueue(GroupQueueInfo* ginfo);
void SetBgTypeIdAndArenaType(BattlegroundTypeId b, uint8 a) { m_bgTypeId = b; m_arenaType = ArenaType(a); } // pussywizard
void AddEvent(BasicEvent* Event, uint64 e_time);
typedef std::map<ObjectGuid, GroupQueueInfo*> QueuedPlayersMap;
@@ -127,15 +124,10 @@ public:
//one selection pool for horde, other one for alliance
SelectionPool m_SelectionPools[PVP_TEAMS_COUNT];
ArenaType GetArenaType() { return m_arenaType; }
BattlegroundTypeId GetBGTypeID() { return m_bgTypeId; }
void SetQueueAnnouncementTimer(uint32 bracketId, int32 timer, bool isCrossFactionBG = true);
[[nodiscard]] int32 GetQueueAnnouncementTimer(uint32 bracketId) const;
private:
BattlegroundTypeId m_bgTypeId;
ArenaType m_arenaType;
uint32 m_WaitTimes[PVP_TEAMS_COUNT][MAX_BATTLEGROUND_BRACKETS][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME];
uint32 m_WaitTimeLastIndex[PVP_TEAMS_COUNT][MAX_BATTLEGROUND_BRACKETS];
@@ -176,9 +168,8 @@ private:
class BGQueueRemoveEvent : public BasicEvent
{
public:
BGQueueRemoveEvent(ObjectGuid pl_guid, uint32 bgInstanceGUID, BattlegroundQueueTypeId bgQueueTypeId, uint32 removeTime)
: m_PlayerGuid(pl_guid), m_BgInstanceGUID(bgInstanceGUID), m_RemoveTime(removeTime), m_BgQueueTypeId(bgQueueTypeId)
{}
BGQueueRemoveEvent(ObjectGuid pl_guid, uint32 bgInstanceGUID, BattlegroundTypeId BgTypeId, BattlegroundQueueTypeId bgQueueTypeId, uint32 removeTime) :
m_PlayerGuid(pl_guid), m_BgInstanceGUID(bgInstanceGUID), m_RemoveTime(removeTime), m_BgTypeId(BgTypeId), m_BgQueueTypeId(bgQueueTypeId) { }
~BGQueueRemoveEvent() override = default;
@@ -188,6 +179,7 @@ private:
ObjectGuid m_PlayerGuid;
uint32 m_BgInstanceGUID;
uint32 m_RemoveTime;
BattlegroundTypeId m_BgTypeId;
BattlegroundQueueTypeId m_BgQueueTypeId;
};

View File

@@ -1708,7 +1708,7 @@ namespace lfg
if (bgQueueTypeId != BATTLEGROUND_QUEUE_NONE)
{
plr->RemoveBattlegroundQueueId(bgQueueTypeId);
sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId).RemovePlayer(plr->GetGUID(), false, i);
sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId).RemovePlayer(plr->GetGUID(), true);
}
}
}

View File

@@ -248,7 +248,10 @@ Player::Player(WorldSession* session): Unit(true), m_mover(this)
m_swingErrorMsg = 0;
for (uint8 j = 0; j < PLAYER_MAX_BATTLEGROUND_QUEUES; ++j)
m_bgBattlegroundQueueID[j] = BATTLEGROUND_QUEUE_NONE;
{
_BgBattlegroundQueueID[j].bgQueueTypeId = BATTLEGROUND_QUEUE_NONE;
_BgBattlegroundQueueID[j].invitedToInstance = 0;
}
m_logintime = GameTime::GetGameTime().count();
m_Last_tick = m_logintime;
@@ -11025,6 +11028,8 @@ void Player::LeaveBattleground(Battleground* bg)
sScriptMgr->OnBattlegroundDesertion(this, BG_DESERTION_TYPE_LEAVE_BG);
}
bg->RemovePlayerAtLeave(this);
// xinef: reset corpse reclaim time
m_deathExpireTime = GameTime::GetGameTime().count();
@@ -11853,10 +11858,102 @@ Battleground* Player::GetBattleground(bool create) const
if (GetBattlegroundId() == 0)
return nullptr;
Battleground* bg = sBattlegroundMgr->GetBattleground(GetBattlegroundId());
Battleground* bg = sBattlegroundMgr->GetBattleground(GetBattlegroundId(), GetBattlegroundTypeId());
return (create || (bg && bg->FindBgMap()) ? bg : nullptr);
}
bool Player::InBattlegroundQueue(bool ignoreArena) const
{
for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
if (_BgBattlegroundQueueID[i].bgQueueTypeId != BATTLEGROUND_QUEUE_NONE &&
(!ignoreArena || (_BgBattlegroundQueueID[i].bgQueueTypeId != BATTLEGROUND_QUEUE_2v2 &&
_BgBattlegroundQueueID[i].bgQueueTypeId != BATTLEGROUND_QUEUE_3v3 &&
_BgBattlegroundQueueID[i].bgQueueTypeId != BATTLEGROUND_QUEUE_5v5)))
return true;
return false;
}
BattlegroundQueueTypeId Player::GetBattlegroundQueueTypeId(uint32 index) const
{
return _BgBattlegroundQueueID[index].bgQueueTypeId;
}
uint32 Player::GetBattlegroundQueueIndex(BattlegroundQueueTypeId bgQueueTypeId) const
{
for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
if (_BgBattlegroundQueueID[i].bgQueueTypeId == bgQueueTypeId)
return i;
return PLAYER_MAX_BATTLEGROUND_QUEUES;
}
bool Player::IsInvitedForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId) const
{
for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
if (_BgBattlegroundQueueID[i].bgQueueTypeId == bgQueueTypeId)
return _BgBattlegroundQueueID[i].invitedToInstance != 0;
return false;
}
bool Player::InBattlegroundQueueForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId) const
{
return GetBattlegroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES;
}
uint32 Player::AddBattlegroundQueueId(BattlegroundQueueTypeId val)
{
for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
{
if (_BgBattlegroundQueueID[i].bgQueueTypeId == BATTLEGROUND_QUEUE_NONE || _BgBattlegroundQueueID[i].bgQueueTypeId == val)
{
_BgBattlegroundQueueID[i].bgQueueTypeId = val;
_BgBattlegroundQueueID[i].invitedToInstance = 0;
return i;
}
}
return PLAYER_MAX_BATTLEGROUND_QUEUES;
}
bool Player::HasFreeBattlegroundQueueId() const
{
for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
if (_BgBattlegroundQueueID[i].bgQueueTypeId == BATTLEGROUND_QUEUE_NONE)
return true;
return false;
}
void Player::RemoveBattlegroundQueueId(BattlegroundQueueTypeId val)
{
for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
{
if (_BgBattlegroundQueueID[i].bgQueueTypeId == val)
{
_BgBattlegroundQueueID[i].bgQueueTypeId = BATTLEGROUND_QUEUE_NONE;
_BgBattlegroundQueueID[i].invitedToInstance = 0;
return;
}
}
}
void Player::SetInviteForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId, uint32 instanceId)
{
for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
if (_BgBattlegroundQueueID[i].bgQueueTypeId == bgQueueTypeId)
_BgBattlegroundQueueID[i].invitedToInstance = instanceId;
}
bool Player::IsInvitedForBattlegroundInstance(uint32 instanceId) const
{
for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
if (_BgBattlegroundQueueID[i].invitedToInstance == instanceId)
return true;
return false;
}
bool Player::InArena() const
{
Battleground* bg = GetBattleground();
@@ -11868,16 +11965,6 @@ bool Player::InArena() const
void Player::SetBattlegroundId(uint32 id, BattlegroundTypeId bgTypeId, uint32 queueSlot, bool invited, bool isRandom, TeamId teamId)
{
// if leaving current bg (and was invited) - decrease invited count for current one
if (m_bgData.bgInstanceID && m_bgData.isInvited)
if (Battleground* bg = sBattlegroundMgr->GetBattleground(m_bgData.bgInstanceID))
bg->DecreaseInvitedCount(m_bgData.bgTeamId);
// if entering new bg (and is invited) - increase invited count for new one
if (id && invited)
if (Battleground* bg = sBattlegroundMgr->GetBattleground(id))
bg->IncreaseInvitedCount(teamId);
m_bgData.bgInstanceID = id;
m_bgData.bgTypeID = bgTypeId;
m_bgData.bgQueueSlot = queueSlot;

View File

@@ -177,7 +177,7 @@ enum TalentTree // talent tabs
// Spell modifier (used for modify other spells)
struct SpellModifier
{
SpellModifier(Aura* _ownerAura = nullptr) : op(SPELLMOD_DAMAGE), type(SPELLMOD_FLAT), charges(0), mask(), ownerAura(_ownerAura) {}
SpellModifier(Aura* _ownerAura = nullptr) : op(SPELLMOD_DAMAGE), type(SPELLMOD_FLAT), charges(0), mask(), ownerAura(_ownerAura) {}
SpellModOp op : 8;
SpellModType type : 8;
int16 charges : 16;
@@ -2188,59 +2188,20 @@ public:
void SetBGData(BGData& bgdata) { m_bgData = bgdata; }
[[nodiscard]] Battleground* GetBattleground(bool create = false) const;
[[nodiscard]] bool InBattlegroundQueue() const
{
for (auto i : m_bgBattlegroundQueueID)
if (i != BATTLEGROUND_QUEUE_NONE)
return true;
return false;
}
[[nodiscard]] bool InBattlegroundQueue(bool ignoreArena = false) const;
[[nodiscard]] bool IsDeserter() const { return HasAura(26013); }
[[nodiscard]] BattlegroundQueueTypeId GetBattlegroundQueueTypeId(uint32 index) const { return m_bgBattlegroundQueueID[index]; }
[[nodiscard]] uint32 GetBattlegroundQueueIndex(BattlegroundQueueTypeId bgQueueTypeId) const
{
for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
if (m_bgBattlegroundQueueID[i] == bgQueueTypeId)
return i;
return PLAYER_MAX_BATTLEGROUND_QUEUES;
}
[[nodiscard]] bool InBattlegroundQueueForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId) const
{
return GetBattlegroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES;
}
[[nodiscard]] BattlegroundQueueTypeId GetBattlegroundQueueTypeId(uint32 index) const;
[[nodiscard]] uint32 GetBattlegroundQueueIndex(BattlegroundQueueTypeId bgQueueTypeId) const;
[[nodiscard]] bool IsInvitedForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId) const;
[[nodiscard]] bool InBattlegroundQueueForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId) const;
void SetBattlegroundId(uint32 id, BattlegroundTypeId bgTypeId, uint32 queueSlot, bool invited, bool isRandom, TeamId teamId);
uint32 AddBattlegroundQueueId(BattlegroundQueueTypeId val)
{
for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
if (m_bgBattlegroundQueueID[i] == BATTLEGROUND_QUEUE_NONE || m_bgBattlegroundQueueID[i] == val)
{
m_bgBattlegroundQueueID[i] = val;
return i;
}
return PLAYER_MAX_BATTLEGROUND_QUEUES;
}
bool HasFreeBattlegroundQueueId()
{
for (auto & i : m_bgBattlegroundQueueID)
if (i == BATTLEGROUND_QUEUE_NONE)
return true;
return false;
}
void RemoveBattlegroundQueueId(BattlegroundQueueTypeId val)
{
for (auto & i : m_bgBattlegroundQueueID)
if (i == val)
{
i = BATTLEGROUND_QUEUE_NONE;
return;
}
}
uint32 AddBattlegroundQueueId(BattlegroundQueueTypeId val);
bool HasFreeBattlegroundQueueId() const;
void RemoveBattlegroundQueueId(BattlegroundQueueTypeId val);
void SetInviteForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId, uint32 instanceId);
bool IsInvitedForBattlegroundInstance(uint32 instanceId) const;
[[nodiscard]] TeamId GetBgTeamId() const { return m_bgData.bgTeamId != TEAM_NEUTRAL ? m_bgData.bgTeamId : GetTeamId(); }
@@ -2601,7 +2562,13 @@ public:
/*** BATTLEGROUND SYSTEM ***/
/*********************************************************/
BattlegroundQueueTypeId m_bgBattlegroundQueueID[PLAYER_MAX_BATTLEGROUND_QUEUES];
struct BgBattlegroundQueueID_Rec
{
BattlegroundQueueTypeId bgQueueTypeId;
uint32 invitedToInstance;
};
std::array<BgBattlegroundQueueID_Rec, PLAYER_MAX_BATTLEGROUND_QUEUES> _BgBattlegroundQueueID;
BGData m_bgData;
bool m_IsBGRandomWinner;

View File

@@ -2189,6 +2189,11 @@ ObjectGuid Group::GetLeaderGUID() const
return m_leaderGuid;
}
Player* Group::GetLeader()
{
return ObjectAccessor::FindConnectedPlayer(m_leaderGuid);
}
ObjectGuid Group::GetGUID() const
{
return m_guid;
@@ -2425,3 +2430,15 @@ void Group::SetDifficultyChangePrevention(DifficultyPreventionChangeType type)
_difficultyChangePreventionTime = GameTime::GetGameTime().count() + MINUTE;
_difficultyChangePreventionType = type;
}
void Group::DoForAllMembers(std::function<void(Player*)> const& worker)
{
for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next())
{
Player* member = itr->GetSource();
if (!member)
continue;
worker(member);
}
}

View File

@@ -23,6 +23,7 @@
#include "LootMgr.h"
#include "QueryResult.h"
#include "SharedDefines.h"
#include <functional>
class Battlefield;
class Battleground;
@@ -214,6 +215,7 @@ public:
bool isBGGroup() const;
bool IsCreated() const;
ObjectGuid GetLeaderGUID() const;
Player* GetLeader();
ObjectGuid GetGUID() const;
const char* GetLeaderName() const;
LootMethod GetLootMethod() const;
@@ -313,6 +315,8 @@ public:
DifficultyPreventionChangeType GetDifficultyChangePreventionReason() const { return _difficultyChangePreventionType; }
void SetDifficultyChangePrevention(DifficultyPreventionChangeType type);
void DoForAllMembers(std::function<void(Player*)> const& worker);
protected:
void _homebindIfInstance(Player* player);
void _cancelHomebindIfInstance(Player* player);

View File

@@ -72,8 +72,9 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
{
ObjectGuid guid;
uint32 bgTypeId_;
uint32 instanceId; // sent to queue for particular bg from battlemaster's list, currently not used
uint32 instanceId;
uint8 joinAsGroup;
bool isPremade = false;
recvData >> guid; // battlemaster guid
recvData >> bgTypeId_; // battleground type id (DBC id)
@@ -82,7 +83,10 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
// entry not found
if (!sBattlemasterListStore.LookupEntry(bgTypeId_))
{
LOG_ERROR("network", "Battleground: invalid bgtype ({}) received. possible cheater? player {}", bgTypeId_, _player->GetGUID().ToString());
return;
}
// chosen battleground type is disabled
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, bgTypeId_, nullptr))
@@ -91,6 +95,8 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
return;
}
LOG_DEBUG("network", "WORLD: Recvd CMSG_BATTLEMASTER_JOIN Message from {}", guid.ToString());
// get queue typeid and random typeid to check if already queued for them
BattlegroundTypeId bgTypeId = BattlegroundTypeId(bgTypeId_);
BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, 0);
@@ -100,35 +106,26 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
if (bgQueueTypeId == BATTLEGROUND_QUEUE_NONE)
return;
// get bg template
Battleground* bgt = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId);
if (!bgt)
// ignore if player is already in BG
if (_player->InBattleground())
return;
// get bg instance or bg template if instance not found
Battleground* bg = nullptr;
if (instanceId)
bg = sBattlegroundMgr->GetBattlegroundThroughClientInstance(instanceId, bgTypeId);
if (!bg)
bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId);
if (!bg)
return;
// expected bracket entry
PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bgt->GetMapId(), _player->getLevel());
PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel());
if (!bracketEntry)
return;
// pussywizard: if trying to queue for already queued
// just remove from queue and it will requeue!
uint32 qSlot = _player->GetBattlegroundQueueIndex(bgQueueTypeId);
if (qSlot < PLAYER_MAX_BATTLEGROUND_QUEUES)
{
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
if (bgQueue.IsPlayerInvitedToRatedArena(_player->GetGUID()))
{
WorldPacket data;
sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_BATTLEGROUND_JOIN_FAILED);
SendPacket(&data);
return;
}
bgQueue.RemovePlayer(_player->GetGUID(), false, qSlot);
_player->RemoveBattlegroundQueueId(bgQueueTypeId);
}
// must have free queue slot
if (!_player->HasFreeBattlegroundQueueId())
{
@@ -139,7 +136,7 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
}
// queue result (default ok)
GroupJoinBattlegroundResult err = GroupJoinBattlegroundResult(bgt->GetBgTypeID());
GroupJoinBattlegroundResult err = GroupJoinBattlegroundResult(bg->GetBgTypeID());
if (!sScriptMgr->CanJoinInBattlegroundQueue(_player, guid, bgTypeId, joinAsGroup, err) && err <= 0)
{
@@ -149,6 +146,8 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
return;
}
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
// check if player can queue:
if (!joinAsGroup)
{
@@ -169,6 +168,10 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
{
err = ERR_IN_RANDOM_BG;
}
else if (_player->InBattlegroundQueueForBattlegroundQueueType(bgQueueTypeId)) // queued for this bg
{
err = ERR_BATTLEGROUND_NONE;
}
else if (_player->InBattlegroundQueue() && bgTypeId == BATTLEGROUND_RB) // already in queue, so can't queue for random
{
err = ERR_IN_NON_RANDOM_BG;
@@ -193,15 +196,13 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
return;
}
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, nullptr, bracketEntry, false, false, 0, 0, 0);
GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, nullptr, bgTypeId, bracketEntry, 0, false, isPremade, 0, 0);
uint32 avgWaitTime = bgQueue.GetAverageQueueWaitTime(ginfo);
uint32 queueSlot = _player->AddBattlegroundQueueId(bgQueueTypeId);
// send status packet
WorldPacket data;
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bgt, queueSlot, STATUS_WAIT_QUEUE, avgWaitTime, 0, 0, TEAM_NEUTRAL);
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgWaitTime, 0, 0, TEAM_NEUTRAL);
SendPacket(&data);
sScriptMgr->OnPlayerJoinBG(_player);
@@ -214,30 +215,6 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
if (!grp || grp->GetLeaderGUID() != _player->GetGUID())
return;
// pussywizard: for party members - remove queues for which leader is not queued to!
std::set<uint32> leaderQueueTypeIds;
for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
leaderQueueTypeIds.insert((uint32)_player->GetBattlegroundQueueTypeId(i));
for (GroupReference* itr = grp->GetFirstMember(); itr != nullptr; itr = itr->next())
if (Player* member = itr->GetSource())
for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
if (BattlegroundQueueTypeId mqtid = member->GetBattlegroundQueueTypeId(i))
if (leaderQueueTypeIds.count((uint32)mqtid) == 0)
{
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(mqtid);
if (bgQueue.IsPlayerInvitedToRatedArena(member->GetGUID()))
{
WorldPacket data;
sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_BATTLEGROUND_JOIN_FAILED);
SendPacket(&data);
return;
}
bgQueue.RemovePlayer(member->GetGUID(), false, i);
member->RemoveBattlegroundQueueId(mqtid);
}
if (_player->InBattlegroundQueueForBattlegroundQueueType(bgQueueTypeIdRandom)) // queued for random bg, so can't queue for anything else
err = ERR_IN_RANDOM_BG;
else if (_player->InBattlegroundQueue() && bgTypeId == BATTLEGROUND_RB) // already in queue, so can't queue for random
@@ -248,44 +225,42 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
err = ERR_BATTLEGROUND_QUEUED_FOR_RATED;
if (err > 0)
err = grp->CanJoinBattlegroundQueue(bgt, bgQueueTypeId, 0, bgt->GetMaxPlayersPerTeam(), false, 0);
err = grp->CanJoinBattlegroundQueue(bg, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0);
bool isPremade = (grp->GetMembersCount() >= bgt->GetMinPlayersPerTeam() && bgTypeId != BATTLEGROUND_RB);
isPremade = (grp->GetMembersCount() >= bg->GetMinPlayersPerTeam() && bgTypeId != BATTLEGROUND_RB);
uint32 avgWaitTime = 0;
if (err > 0)
{
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, grp, bracketEntry, false, isPremade, 0, 0, 0);
GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, bracketEntry, 0, false, isPremade, 0, 0);
avgWaitTime = bgQueue.GetAverageQueueWaitTime(ginfo);
}
WorldPacket data;
for (GroupReference* itr = grp->GetFirstMember(); itr != nullptr; itr = itr->next())
grp->DoForAllMembers([bg, err, bgQueueTypeId, avgWaitTime](Player* member)
{
Player* member = itr->GetSource();
if (!member)
continue;
WorldPacket data;
if (err <= 0)
{
sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err);
member->GetSession()->SendPacket(&data);
continue;
return;
}
uint32 queueSlot = member->AddBattlegroundQueueId(bgQueueTypeId);
// send status packet
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bgt, queueSlot, STATUS_WAIT_QUEUE, avgWaitTime, 0, 0, TEAM_NEUTRAL);
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgWaitTime, 0, 0, TEAM_NEUTRAL);
member->GetSession()->SendPacket(&data);
sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err);
member->GetSession()->SendPacket(&data);
sScriptMgr->OnPlayerJoinBG(member);
}
});
}
sBattlegroundMgr->ScheduleQueueUpdate(0, 0, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId());
}
void WorldSession::HandleBattlegroundPlayerPositionsOpcode(WorldPacket& /*recvData*/)
@@ -373,7 +348,10 @@ void WorldSession::HandleBattlefieldListOpcode(WorldPacket& recvData)
BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId);
if (!bl)
{
LOG_DEBUG("bg.battleground", "BattlegroundHandler: invalid bgtype ({}) with player (Name: {}, {}) received.", bgTypeId, _player->GetName(), _player->GetGUID().ToString());
return;
}
WorldPacket data;
sBattlegroundMgr->BuildBattlegroundListPacket(&data, ObjectGuid::Empty, _player, BattlegroundTypeId(bgTypeId), fromWhere);
@@ -382,21 +360,27 @@ void WorldSession::HandleBattlefieldListOpcode(WorldPacket& recvData)
void WorldSession::HandleBattleFieldPortOpcode(WorldPacket& recvData)
{
uint8 arenaType; // arenatype if arena
uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1
uint32 bgTypeId_; // type id from dbc
uint16 unk; // 0x1F90 constant?
uint8 action; // enter battle 0x1, leave queue 0x0
uint8 arenaType; // arenatype if arena
uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1
uint32 bgTypeId_; // type id from dbc
uint16 unk; // 0x1F90 constant?
uint8 action; // enter battle 0x1, leave queue 0x0
recvData >> arenaType >> unk2 >> bgTypeId_ >> unk >> action;
// bgTypeId not valid
if (!sBattlemasterListStore.LookupEntry(bgTypeId_))
{
LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} ArenaType: {}, Unk: {}, BgType: {}, Action: {}. Invalid BgType!", GetPlayerInfo(), arenaType, unk2, bgTypeId_, action);
return;
}
// player not in any queue, so can't really answer
if (!_player->InBattlegroundQueue())
{
LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} ArenaType: {}, Unk: {}, BgType: {}, Action: {}. Player not in queue!", GetPlayerInfo(), arenaType, unk2, bgTypeId_, action);
return;
}
// get BattlegroundQueue for received
BattlegroundTypeId bgTypeId = BattlegroundTypeId(bgTypeId_);
@@ -409,20 +393,40 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket& recvData)
// get group info from queue
GroupQueueInfo ginfo;
if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo))
{
LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} ArenaType: {}, Unk: {}, BgType: {}, Action: {}. Player not in queue (No player Group Info)!",
GetPlayerInfo(), arenaType, unk2, bgTypeId_, action);
return;
}
// to accept, player must be invited to particular battleground id
if (!ginfo.IsInvitedToBGInstanceGUID && action == 1)
{
LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} ArenaType: {}, Unk: {}, BgType: {}, Action: {}. Player is not invited to any bg!",
GetPlayerInfo(), arenaType, unk2, bgTypeId_, action);
return;
}
Battleground* bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID);
// use template if leaving queue (instance might not be created yet)
if (!bg && action == 0)
bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId);
Battleground* bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId);
if (!bg)
return;
{
if (action)
{
LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} ArenaType: {}, Unk: {}, BgType: {}, Action: {}. Cant find BG with id {}!",
GetPlayerInfo(), arenaType, unk2, bgTypeId_, action, ginfo.IsInvitedToBGInstanceGUID);
return;
}
bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId);
if (!bg)
{
LOG_ERROR("network", "BattlegroundHandler: bg_template not found for type id {}.", bgTypeId);
return;
}
}
LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} ArenaType: {}, Unk: {}, BgType: {}, Action: {}.",
GetPlayerInfo(), arenaType, unk2, bgTypeId_, action);
// expected bracket entry
PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel());
@@ -439,74 +443,90 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket& recvData)
sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS);
SendPacket(&data);
action = 0;
LOG_DEBUG("bg.battleground", "Player {} {} has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUID().ToString());
}
if (_player->getLevel() > bg->GetMaxLevel())
{
LOG_ERROR("network", "Player {} {} has level ({}) higher than maxlevel ({}) of battleground ({})! Do not port him to battleground!",
_player->GetName(), _player->GetGUID().ToString(), _player->getLevel(), bg->GetMaxLevel(), bg->GetBgTypeID());
action = 0;
}
}
// get player queue slot index for this bg (can be in up to 2 queues at the same time)
uint32 queueSlot = _player->GetBattlegroundQueueIndex(bgQueueTypeId);
WorldPacket data;
switch (action)
if (action) // accept
{
case 1: // accept
// check Freeze debuff
if (_player->HasAura(9454))
return;
if (!_player->IsInvitedForBattlegroundQueueType(bgQueueTypeId))
return; // cheating?
// set entry point if not in battleground
if (!_player->InBattleground())
_player->SetEntryPoint();
// resurrect the player
if (!_player->IsAlive())
{
_player->ResurrectPlayer(1.0f);
_player->SpawnCorpseBones();
}
TeamId teamId = ginfo.teamId;
// send status packet
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType(), teamId);
SendPacket(&data);
// remove battleground queue status from BGmgr
bgQueue.RemovePlayer(_player->GetGUID(), false);
// this is still needed here if battleground "jumping" shouldn't add deserter debuff
// also this is required to prevent stuck at old battleground after SetBattlegroundId set to new
if (Battleground* currentBg = _player->GetBattleground())
currentBg->RemovePlayerAtLeave(_player);
// Remove from LFG queues
sLFGMgr->LeaveAllLfgQueues(_player->GetGUID(), false);
_player->SetBattlegroundId(bg->GetInstanceID(), bg->GetBgTypeID(), queueSlot, true, bgTypeId == BATTLEGROUND_RB, teamId);
sBattlegroundMgr->SendToBattleground(_player, ginfo.IsInvitedToBGInstanceGUID, bgTypeId);
LOG_DEBUG("bg.battleground", "Battleground: player {} {} joined battle for bg {}, bgtype {}, queue type {}.", _player->GetName(), _player->GetGUID().ToString(), bg->GetInstanceID(), bg->GetBgTypeID(), bgQueueTypeId);
}
else // leave queue
{
bgQueue.RemovePlayer(_player->GetGUID(), true);
_player->RemoveBattlegroundQueueId(bgQueueTypeId);
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0, TEAM_NEUTRAL);
SendPacket(&data);
LOG_DEBUG("bg.battleground", "Battleground: player {} {} left queue for bgtype {}, queue type {}.", _player->GetName(), _player->GetGUID().ToString(), bg->GetBgTypeID(), bgQueueTypeId);
// player left queue, we should update it - do not update Arena Queue
if (!ginfo.ArenaType)
sBattlegroundMgr->ScheduleQueueUpdate(ginfo.ArenaMatchmakerRating, ginfo.ArenaType, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId());
// track if player refuses to join the BG after being invited
if (bg->isBattleground() && (bg->GetStatus() == STATUS_IN_PROGRESS || bg->GetStatus() == STATUS_WAIT_JOIN))
{
if (sWorld->getBoolConfig(CONFIG_BATTLEGROUND_TRACK_DESERTERS))
{
// set entry point if not in battleground
if (!_player->InBattleground())
_player->SetEntryPoint();
// resurrect the player
if (!_player->IsAlive())
{
_player->ResurrectPlayer(1.0f);
_player->SpawnCorpseBones();
}
TeamId teamId = ginfo.teamId;
// remove player from all bg queues
for (uint32 qslot = 0; qslot < PLAYER_MAX_BATTLEGROUND_QUEUES; ++qslot)
if (BattlegroundQueueTypeId q = _player->GetBattlegroundQueueTypeId(qslot))
{
BattlegroundQueue& queue = sBattlegroundMgr->GetBattlegroundQueue(q);
queue.RemovePlayer(_player->GetGUID(), (bgQueueTypeId == q), qslot);
_player->RemoveBattlegroundQueueId(q);
}
// send status packet
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType(), teamId);
SendPacket(&data);
// Remove from LFG queues
sLFGMgr->LeaveAllLfgQueues(_player->GetGUID(), false);
_player->SetBattlegroundId(bg->GetInstanceID(), bg->GetBgTypeID(), queueSlot, true, bgTypeId == BATTLEGROUND_RB, teamId);
sBattlegroundMgr->SendToBattleground(_player, ginfo.IsInvitedToBGInstanceGUID, bgTypeId);
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_DESERTER_TRACK);
stmt->SetData(0, _player->GetGUID().GetCounter());
stmt->SetData(1, BG_DESERTION_TYPE_LEAVE_QUEUE);
CharacterDatabase.Execute(stmt);
}
break;
case 0: // leave queue
{
bgQueue.RemovePlayer(_player->GetGUID(), false, queueSlot);
_player->RemoveBattlegroundQueueId(bgQueueTypeId);
// track if player refuses to join the BG after being invited
if (bg->isBattleground() && (bg->GetStatus() == STATUS_IN_PROGRESS || bg->GetStatus() == STATUS_WAIT_JOIN))
{
if (sWorld->getBoolConfig(CONFIG_BATTLEGROUND_TRACK_DESERTERS))
{
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_DESERTER_TRACK);
stmt->SetData(0, _player->GetGUID().GetCounter());
stmt->SetData(1, BG_DESERTION_TYPE_LEAVE_QUEUE);
CharacterDatabase.Execute(stmt);
}
sScriptMgr->OnBattlegroundDesertion(_player, BG_DESERTION_TYPE_LEAVE_QUEUE);
}
}
break;
default:
break;
sScriptMgr->OnBattlegroundDesertion(_player, BG_DESERTION_TYPE_LEAVE_QUEUE);
}
}
}
@@ -562,7 +582,7 @@ void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket& /*recvData*/)
// if invited - send STATUS_WAIT_JOIN
if (ginfo.IsInvitedToBGInstanceGUID)
{
Battleground* bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID);
Battleground* bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId);
if (!bg)
continue;
@@ -591,10 +611,12 @@ void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket& /*recvData*/)
void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData)
{
ObjectGuid guid; // arena Battlemaster guid
uint8 arenaslot; // 2v2, 3v3 or 5v5
uint8 asGroup; // asGroup
uint8 isRated; // isRated
LOG_DEBUG("network", "WORLD: CMSG_BATTLEMASTER_JOIN_ARENA");
ObjectGuid guid; // arena Battlemaster guid
uint8 arenaslot; // 2v2, 3v3 or 5v5
uint8 asGroup; // asGroup
uint8 isRated; // isRated
recvData >> guid >> arenaslot >> asGroup >> isRated;
@@ -602,6 +624,10 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData)
if (isRated && !asGroup)
return;
// ignore if we already in BG or BG queue
if (_player->InBattleground())
return;
// find creature by guid
Creature* unit = GetPlayer()->GetMap()->GetCreature(guid);
if (!unit || !unit->IsBattleMaster())
@@ -609,6 +635,11 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData)
// get arena type
uint8 arenatype = 0;
uint32 ateamId = 0;
uint32 arenaRating = 0;
uint32 matchmakerRating = 0;
uint32 previousOpponents = 0;
switch (arenaslot)
{
case 0:
@@ -621,13 +652,17 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData)
arenatype = ARENA_TYPE_5v5;
break;
default:
LOG_ERROR("network", "Unknown arena slot {} at HandleBattlemasterJoinArena()", arenaslot);
return;
}
// get template for all arenas
Battleground* bgt = sBattlegroundMgr->GetBattlegroundTemplate(BATTLEGROUND_AA);
if (!bgt)
{
LOG_ERROR("network", "Battleground: template bg (all arenas) not found");
return;
}
// arenas disabled
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, BATTLEGROUND_AA, nullptr))
@@ -637,32 +672,12 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData)
}
BattlegroundTypeId bgTypeId = bgt->GetBgTypeID();
BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, arenatype);
// expected bracket entry
PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bgt->GetMapId(), _player->getLevel());
if (!bracketEntry)
return;
// pussywizard: if trying to queue for already queued
// just remove from queue and it will requeue!
uint32 qSlot = _player->GetBattlegroundQueueIndex(bgQueueTypeId);
if (qSlot < PLAYER_MAX_BATTLEGROUND_QUEUES)
{
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
if (bgQueue.IsPlayerInvitedToRatedArena(_player->GetGUID()))
{
WorldPacket data;
sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_BATTLEGROUND_JOIN_FAILED);
SendPacket(&data);
return;
}
bgQueue.RemovePlayer(_player->GetGUID(), false, qSlot);
_player->RemoveBattlegroundQueueId(bgQueueTypeId);
}
// must have free queue slot
// pussywizard: allow being queued only in one arena queue, and it even cannot be together with bg queues
if (_player->InBattlegroundQueue())
@@ -684,6 +699,9 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData)
return;
}
BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, arenatype);
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
// check if player can queue:
if (!asGroup)
{
@@ -705,16 +723,25 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData)
return;
}
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, nullptr, bracketEntry, false, false, 0, 0, 0);
uint32 avgWaitTime = bgQueue.GetAverageQueueWaitTime(ginfo);
// check if already in queue
if (_player->GetBattlegroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
//player is already in this queue
return;
// check if has free queue slots
if (!_player->HasFreeBattlegroundQueueId())
return;
GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, nullptr, bgTypeId, bracketEntry, arenatype, isRated != 0, false, arenaRating, matchmakerRating, ateamId, previousOpponents);
uint32 avgWaitTime = bgQueue.GetAverageQueueWaitTime(ginfo);
uint32 queueSlot = _player->AddBattlegroundQueueId(bgQueueTypeId);
WorldPacket data;
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bgt, queueSlot, STATUS_WAIT_QUEUE, avgWaitTime, 0, arenatype, TEAM_NEUTRAL);
SendPacket(&data);
LOG_DEBUG("bg.battleground", "Battleground: player joined queue for arena, skirmish, bg queue type {} bg type {}: {}, NAME {}", bgQueueTypeId, bgTypeId, _player->GetGUID().ToString(), _player->GetName());
sScriptMgr->OnPlayerJoinArena(_player);
}
// check if group can queue:
@@ -725,34 +752,6 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData)
if (!grp || grp->GetLeaderGUID() != _player->GetGUID())
return;
// pussywizard: for party members - remove queues for which leader is not queued to!
std::set<uint32> leaderQueueTypeIds;
for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
leaderQueueTypeIds.insert((uint32)_player->GetBattlegroundQueueTypeId(i));
for (GroupReference* itr = grp->GetFirstMember(); itr != nullptr; itr = itr->next())
if (Player* member = itr->GetSource())
for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
if (BattlegroundQueueTypeId mqtid = member->GetBattlegroundQueueTypeId(i))
if (leaderQueueTypeIds.count((uint32)mqtid) == 0)
{
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(mqtid);
if (bgQueue.IsPlayerInvitedToRatedArena(member->GetGUID()))
{
WorldPacket data;
sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_BATTLEGROUND_JOIN_FAILED);
SendPacket(&data);
return;
}
bgQueue.RemovePlayer(member->GetGUID(), false, i);
member->RemoveBattlegroundQueueId(mqtid);
}
uint32 ateamId = 0;
uint32 arenaRating = 0;
uint32 matchmakerRating = 0;
// additional checks for rated arenas
if (isRated)
{
@@ -775,15 +774,40 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData)
matchmakerRating = at->GetAverageMMR(grp);
if (arenaRating <= 0)
arenaRating = 1;
previousOpponents = at->GetPreviousOpponents();
}
err = grp->CanJoinBattlegroundQueue(bgt, bgQueueTypeId, arenatype, arenatype, (bool)isRated, arenaslot);
// Check queue group members
if (err)
{
grp->DoForAllMembers([&bgQueue, &err](Player* member)
{
if (bgQueue.IsPlayerInvitedToRatedArena(member->GetGUID()))
{
err = ERR_BATTLEGROUND_JOIN_FAILED;
}
});
}
uint32 avgWaitTime = 0;
if (err > 0)
{
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, grp, bracketEntry, isRated, false, arenaRating, matchmakerRating, ateamId);
LOG_DEBUG("bg.battleground", "Battleground: arena join as group start");
if (isRated)
{
LOG_DEBUG("bg.battleground", "Battleground: arena team id {}, leader {} queued with matchmaker rating {} for type {}", _player->GetArenaTeamId(arenaslot), _player->GetName(), matchmakerRating, arenatype);
bgt->SetRated(true);
}
else
{
bgt->SetRated(false);
}
GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, bracketEntry, arenatype, isRated != 0, false, arenaRating, matchmakerRating, ateamId, previousOpponents);
avgWaitTime = bgQueue.GetAverageQueueWaitTime(ginfo);
}
@@ -810,13 +834,13 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData)
sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err);
member->GetSession()->SendPacket(&data);
LOG_DEBUG("bg.battleground", "Battleground: player joined queue for arena as group bg queue type {} bg type {}: {}, NAME {}", bgQueueTypeId, bgTypeId, member->GetGUID().ToString(), member->GetName());
sScriptMgr->OnPlayerJoinArena(member);
}
// pussywizard: schedule update for rated arena
if (ateamId)
sBattlegroundMgr->ScheduleArenaQueueUpdate(ateamId, bgQueueTypeId, bracketEntry->GetBracketId());
}
sBattlegroundMgr->ScheduleQueueUpdate(matchmakerRating, arenatype, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId());
}
void WorldSession::HandleReportPvPAFK(WorldPacket& recvData)

View File

@@ -170,7 +170,7 @@ void WorldSession::HandleMoveWorldportAck()
if (uint32 inviteInstanceId = _player->GetPendingSpectatorInviteInstanceId())
{
if (Battleground* tbg = sBattlegroundMgr->GetBattleground(inviteInstanceId))
if (Battleground* tbg = sBattlegroundMgr->GetBattleground(inviteInstanceId, BATTLEGROUND_TYPE_NONE))
tbg->RemoveToBeTeleported(_player->GetGUID());
_player->SetPendingSpectatorInviteInstanceId(0);
}
@@ -904,14 +904,14 @@ void WorldSession::ComputeNewClockDelta()
std::vector<uint32> latencies;
std::vector<int64> clockDeltasAfterFiltering;
for (auto pair : _timeSyncClockDeltaQueue.content())
for (auto& pair : _timeSyncClockDeltaQueue.content())
latencies.push_back(pair.second);
uint32 latencyMedian = median(latencies);
uint32 latencyStandardDeviation = standard_deviation(latencies);
uint32 sampleSizeAfterFiltering = 0;
for (auto pair : _timeSyncClockDeltaQueue.content())
for (auto& pair : _timeSyncClockDeltaQueue.content())
{
if (pair.second <= latencyMedian + latencyStandardDeviation) {
clockDeltasAfterFiltering.push_back(pair.first);

View File

@@ -66,58 +66,41 @@ void ScriptMgr::OnBattlegroundRemovePlayerAtLeave(Battleground* bg, Player* play
});
}
void ScriptMgr::OnAddGroup(BattlegroundQueue* queue, GroupQueueInfo* ginfo, uint32& index, Player* leader, Group* grp, PvPDifficultyEntry const* bracketEntry, bool isPremade)
void ScriptMgr::OnAddGroup(BattlegroundQueue* queue, GroupQueueInfo* ginfo, uint32& index, Player* leader, Group* group, BattlegroundTypeId bgTypeId, PvPDifficultyEntry const* bracketEntry,
uint8 arenaType, bool isRated, bool isPremade, uint32 arenaRating, uint32 matchmakerRating, uint32 arenaTeamId, uint32 opponentsArenaTeamId)
{
ExecuteScript<BGScript>([&](BGScript* script)
{
script->OnAddGroup(queue, ginfo, index, leader, grp, bracketEntry, isPremade);
script->OnAddGroup(queue, ginfo, index, leader, group, bgTypeId, bracketEntry,
arenaType, isRated, isPremade, arenaRating, matchmakerRating, arenaTeamId, opponentsArenaTeamId);
});
}
bool ScriptMgr::CanFillPlayersToBG(BattlegroundQueue* queue, Battleground* bg, const int32 aliFree, const int32 hordeFree, BattlegroundBracketId bracket_id)
bool ScriptMgr::CanFillPlayersToBG(BattlegroundQueue* queue, Battleground* bg, BattlegroundBracketId bracket_id)
{
auto ret = IsValidBoolScript<BGScript>([&](BGScript* script)
{
return !script->CanFillPlayersToBG(queue, bg, aliFree, hordeFree, bracket_id);
return !script->CanFillPlayersToBG(queue, bg, bracket_id);
});
if (ret && *ret)
{
return false;
}
return true;
return ReturnValidBool(ret);
}
bool ScriptMgr::CanFillPlayersToBGWithSpecific(BattlegroundQueue* queue, Battleground* bg, const int32 aliFree, const int32 hordeFree,
BattlegroundBracketId thisBracketId, BattlegroundQueue* specificQueue, BattlegroundBracketId specificBracketId)
bool ScriptMgr::IsCheckNormalMatch(BattlegroundQueue* queue, Battleground* bgTemplate, BattlegroundBracketId bracket_id, uint32 minPlayers, uint32 maxPlayers)
{
auto ret = IsValidBoolScript<BGScript>([&](BGScript* script)
{
return !script->CanFillPlayersToBGWithSpecific(queue, bg, aliFree, hordeFree, thisBracketId, specificQueue, specificBracketId);
return script->IsCheckNormalMatch(queue, bgTemplate, bracket_id, minPlayers, maxPlayers);
});
if (ret && *ret)
{
return false;
}
return true;
return ReturnValidBool(ret, true);
}
void ScriptMgr::OnCheckNormalMatch(BattlegroundQueue* queue, uint32& Coef, Battleground* bgTemplate, BattlegroundBracketId bracket_id, uint32& minPlayers, uint32& maxPlayers)
void ScriptMgr::OnQueueUpdate(BattlegroundQueue* queue, uint32 diff, BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id, uint8 arenaType, bool isRated, uint32 arenaRating)
{
ExecuteScript<BGScript>([&](BGScript* script)
{
script->OnCheckNormalMatch(queue, Coef, bgTemplate, bracket_id, minPlayers, maxPlayers);
});
}
void ScriptMgr::OnQueueUpdate(BattlegroundQueue* queue, BattlegroundBracketId bracket_id, bool isRated, uint32 arenaRatedTeamId)
{
ExecuteScript<BGScript>([&](BGScript* script)
{
script->OnQueueUpdate(queue, bracket_id, isRated, arenaRatedTeamId);
script->OnQueueUpdate(queue, diff, bgTypeId, bracket_id, arenaType, isRated, arenaRating);
});
}
@@ -128,12 +111,7 @@ bool ScriptMgr::CanSendMessageBGQueue(BattlegroundQueue* queue, Player* leader,
return !script->CanSendMessageBGQueue(queue, leader, bg, bracketEntry);
});
if (ret && *ret)
{
return false;
}
return true;
return ReturnValidBool(ret);
}
bool ScriptMgr::OnBeforeSendJoinMessageArenaQueue(BattlegroundQueue* queue, Player* leader, GroupQueueInfo* ginfo, PvPDifficultyEntry const* bracketEntry, bool isRated)
@@ -143,12 +121,7 @@ bool ScriptMgr::OnBeforeSendJoinMessageArenaQueue(BattlegroundQueue* queue, Play
return !script->OnBeforeSendJoinMessageArenaQueue(queue, leader, ginfo, bracketEntry, isRated);
});
if (ret && *ret)
{
return false;
}
return true;
return ReturnValidBool(ret);
}
bool ScriptMgr::OnBeforeSendExitMessageArenaQueue(BattlegroundQueue* queue, GroupQueueInfo* ginfo)
@@ -158,12 +131,7 @@ bool ScriptMgr::OnBeforeSendExitMessageArenaQueue(BattlegroundQueue* queue, Grou
return !script->OnBeforeSendExitMessageArenaQueue(queue, ginfo);
});
if (ret && *ret)
{
return false;
}
return true;
return ReturnValidBool(ret);
}
void ScriptMgr::OnBattlegroundEnd(Battleground* bg, TeamId winnerTeam)

View File

@@ -1566,16 +1566,14 @@ public:
// Remove player at leave BG
virtual void OnBattlegroundRemovePlayerAtLeave(Battleground* /*bg*/, Player* /*player*/) { }
virtual void OnQueueUpdate(BattlegroundQueue* /*queue*/, BattlegroundBracketId /*bracket_id*/, bool /*isRated*/, uint32 /*arenaRatedTeamId*/) { }
virtual void OnQueueUpdate(BattlegroundQueue* /*queue*/, uint32 /* diff */, BattlegroundTypeId /* bgTypeId */, BattlegroundBracketId /* bracket_id */, uint8 /* arenaType */, bool /* isRated */, uint32 /* arenaRating */) { }
virtual void OnAddGroup(BattlegroundQueue* /*queue*/, GroupQueueInfo* /*ginfo*/, uint32& /*index*/, Player* /*leader*/, Group* /*grp*/, PvPDifficultyEntry const* /*bracketEntry*/, bool /*isPremade*/) { }
virtual void OnAddGroup(BattlegroundQueue* /*queue*/, GroupQueueInfo* /*ginfo*/, uint32& /*index*/, Player* /*leader*/, Group* /*group*/, BattlegroundTypeId /* bgTypeId */, PvPDifficultyEntry const* /* bracketEntry */,
uint8 /* arenaType */, bool /* isRated */, bool /* isPremade */, uint32 /* arenaRating */, uint32 /* matchmakerRating */, uint32 /* arenaTeamId */, uint32 /* opponentsArenaTeamId */) { }
[[nodiscard]] virtual bool CanFillPlayersToBG(BattlegroundQueue* /*queue*/, Battleground* /*bg*/, const int32 /*aliFree*/, const int32 /*hordeFree*/, BattlegroundBracketId /*bracket_id*/) { return true; }
[[nodiscard]] virtual bool CanFillPlayersToBG(BattlegroundQueue* /*queue*/, Battleground* /*bg*/, BattlegroundBracketId /*bracket_id*/) { return true; }
[[nodiscard]] virtual bool CanFillPlayersToBGWithSpecific(BattlegroundQueue* /*queue*/, Battleground* /*bg*/, const int32 /*aliFree*/, const int32 /*hordeFree*/,
BattlegroundBracketId /*thisBracketId*/, BattlegroundQueue* /*specificQueue*/, BattlegroundBracketId /*specificBracketId*/) { return true; }
virtual void OnCheckNormalMatch(BattlegroundQueue* /*queue*/, uint32& /*Coef*/, Battleground* /*bgTemplate*/, BattlegroundBracketId /*bracket_id*/, uint32& /*minPlayers*/, uint32& /*maxPlayers*/) { }
[[nodiscard]] virtual bool IsCheckNormalMatch(BattlegroundQueue* /*queue*/, Battleground* /*bgTemplate*/, BattlegroundBracketId /*bracket_id*/, uint32 /*minPlayers*/, uint32 /*maxPlayers*/) { return false; };
[[nodiscard]] virtual bool CanSendMessageBGQueue(BattlegroundQueue* /*queue*/, Player* /*leader*/, Battleground* /*bg*/, PvPDifficultyEntry const* /*bracketEntry*/) { return true; }
@@ -2402,12 +2400,11 @@ public: /* BGScript */
void OnBattlegroundAddPlayer(Battleground* bg, Player* player);
void OnBattlegroundBeforeAddPlayer(Battleground* bg, Player* player);
void OnBattlegroundRemovePlayerAtLeave(Battleground* bg, Player* player);
void OnQueueUpdate(BattlegroundQueue* queue, BattlegroundBracketId bracket_id, bool isRated, uint32 arenaRatedTeamId);
void OnAddGroup(BattlegroundQueue* queue, GroupQueueInfo* ginfo, uint32& index, Player* leader, Group* grp, PvPDifficultyEntry const* bracketEntry, bool isPremade);
bool CanFillPlayersToBG(BattlegroundQueue* queue, Battleground* bg, const int32 aliFree, const int32 hordeFree, BattlegroundBracketId bracket_id);
bool CanFillPlayersToBGWithSpecific(BattlegroundQueue* queue, Battleground* bg, const int32 aliFree, const int32 hordeFree,
BattlegroundBracketId thisBracketId, BattlegroundQueue* specificQueue, BattlegroundBracketId specificBracketId);
void OnCheckNormalMatch(BattlegroundQueue* queue, uint32& Coef, Battleground* bgTemplate, BattlegroundBracketId bracket_id, uint32& minPlayers, uint32& maxPlayers);
void OnQueueUpdate(BattlegroundQueue* queue, uint32 diff, BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id, uint8 arenaType, bool isRated, uint32 arenaRating);
void OnAddGroup(BattlegroundQueue* queue, GroupQueueInfo* ginfo, uint32& index, Player* leader, Group* group, BattlegroundTypeId bgTypeId, PvPDifficultyEntry const* bracketEntry,
uint8 arenaType, bool isRated, bool isPremade, uint32 arenaRating, uint32 matchmakerRating, uint32 arenaTeamId, uint32 opponentsArenaTeamId);
bool CanFillPlayersToBG(BattlegroundQueue* queue, Battleground* bg, BattlegroundBracketId bracket_id);
bool IsCheckNormalMatch(BattlegroundQueue* queue, Battleground* bgTemplate, BattlegroundBracketId bracket_id, uint32 minPlayers, uint32 maxPlayers);
bool CanSendMessageBGQueue(BattlegroundQueue* queue, Player* leader, Battleground* bg, PvPDifficultyEntry const* bracketEntry);
bool OnBeforeSendJoinMessageArenaQueue(BattlegroundQueue* queue, Player* leader, GroupQueueInfo* ginfo, PvPDifficultyEntry const* bracketEntry, bool isRated);
bool OnBeforeSendExitMessageArenaQueue(BattlegroundQueue* queue, GroupQueueInfo* ginfo);

View File

@@ -64,4 +64,9 @@ inline void ExecuteScript(std::function<void(ScriptName*)> executeHook)
}
}
inline bool ReturnValidBool(Optional<bool> ret, bool need = false)
{
return ret && *ret ? need : !need;
}
#endif // _SCRIPT_MGR_MACRO_H_

View File

@@ -587,8 +587,6 @@ void WorldSession::LogoutPlayer(bool save)
for (int i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
if (BattlegroundQueueTypeId bgQueueTypeId = _player->GetBattlegroundQueueTypeId(i))
{
_player->RemoveBattlegroundQueueId(bgQueueTypeId);
sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId).RemovePlayer(_player->GetGUID(), false, i);
// track if player logs out after invited to join BG
if (_player->IsInvitedForBattlegroundInstance())
{
@@ -599,8 +597,12 @@ void WorldSession::LogoutPlayer(bool save)
stmt->SetData(1, BG_DESERTION_TYPE_INVITE_LOGOUT);
CharacterDatabase.Execute(stmt);
}
sScriptMgr->OnBattlegroundDesertion(_player, BG_DESERTION_TYPE_INVITE_LOGOUT);
}
_player->RemoveBattlegroundQueueId(bgQueueTypeId);
sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId).RemovePlayer(_player->GetGUID(), true);
}
///- If the player is in a guild, update the guild roster and broadcast a logout message to other guild members

View File

@@ -307,6 +307,7 @@ enum WorldIntConfigs
CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_LIMIT_MIN_PLAYERS,
CONFIG_ARENA_MAX_RATING_DIFFERENCE,
CONFIG_ARENA_RATING_DISCARD_TIMER,
CONFIG_ARENA_PREV_OPPONENTS_DISCARD_TIMER,
CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS,
CONFIG_ARENA_GAMES_REQUIRED,
CONFIG_ARENA_SEASON_ID,

View File

@@ -1163,25 +1163,26 @@ void World::LoadConfigSettings(bool reload)
m_int_configs[CONFIG_BATTLEGROUND_SPEED_BUFF_RESPAWN] = 150;
}
m_int_configs[CONFIG_ARENA_MAX_RATING_DIFFERENCE] = sConfigMgr->GetOption<int32> ("Arena.MaxRatingDifference", 150);
m_int_configs[CONFIG_ARENA_RATING_DISCARD_TIMER] = sConfigMgr->GetOption<int32> ("Arena.RatingDiscardTimer", 10 * MINUTE * IN_MILLISECONDS);
m_int_configs[CONFIG_ARENA_MAX_RATING_DIFFERENCE] = sConfigMgr->GetOption<uint32>("Arena.MaxRatingDifference", 150);
m_int_configs[CONFIG_ARENA_RATING_DISCARD_TIMER] = sConfigMgr->GetOption<uint32>("Arena.RatingDiscardTimer", 10 * MINUTE * IN_MILLISECONDS);
m_int_configs[CONFIG_ARENA_PREV_OPPONENTS_DISCARD_TIMER] = sConfigMgr->GetOption<uint32>("Arena.PreviousOpponentsDiscardTimer", 2 * MINUTE * IN_MILLISECONDS);
m_bool_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS] = sConfigMgr->GetOption<bool>("Arena.AutoDistributePoints", false);
m_int_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS] = sConfigMgr->GetOption<int32> ("Arena.AutoDistributeInterval", 7); // pussywizard: spoiled by implementing constant day and hour, always 7 now
m_int_configs[CONFIG_ARENA_GAMES_REQUIRED] = sConfigMgr->GetOption<int32> ("Arena.GamesRequired", 10);
m_int_configs[CONFIG_ARENA_SEASON_ID] = sConfigMgr->GetOption<int32> ("Arena.ArenaSeason.ID", 1);
m_int_configs[CONFIG_ARENA_START_RATING] = sConfigMgr->GetOption<int32> ("Arena.ArenaStartRating", 0);
m_int_configs[CONFIG_ARENA_START_PERSONAL_RATING] = sConfigMgr->GetOption<int32> ("Arena.ArenaStartPersonalRating", 1000);
m_int_configs[CONFIG_ARENA_START_MATCHMAKER_RATING] = sConfigMgr->GetOption<int32> ("Arena.ArenaStartMatchmakerRating", 1500);
m_int_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS] = sConfigMgr->GetOption<uint32>("Arena.AutoDistributeInterval", 7); // pussywizard: spoiled by implementing constant day and hour, always 7 now
m_int_configs[CONFIG_ARENA_GAMES_REQUIRED] = sConfigMgr->GetOption<uint32>("Arena.GamesRequired", 10);
m_int_configs[CONFIG_ARENA_SEASON_ID] = sConfigMgr->GetOption<uint32>("Arena.ArenaSeason.ID", 1);
m_int_configs[CONFIG_ARENA_START_RATING] = sConfigMgr->GetOption<uint32>("Arena.ArenaStartRating", 0);
m_int_configs[CONFIG_ARENA_START_PERSONAL_RATING] = sConfigMgr->GetOption<uint32>("Arena.ArenaStartPersonalRating", 1000);
m_int_configs[CONFIG_ARENA_START_MATCHMAKER_RATING] = sConfigMgr->GetOption<uint32>("Arena.ArenaStartMatchmakerRating", 1500);
m_bool_configs[CONFIG_ARENA_SEASON_IN_PROGRESS] = sConfigMgr->GetOption<bool>("Arena.ArenaSeason.InProgress", true);
m_float_configs[CONFIG_ARENA_WIN_RATING_MODIFIER_1] = sConfigMgr->GetOption<float>("Arena.ArenaWinRatingModifier1", 48.0f);
m_float_configs[CONFIG_ARENA_WIN_RATING_MODIFIER_2] = sConfigMgr->GetOption<float>("Arena.ArenaWinRatingModifier2", 24.0f);
m_float_configs[CONFIG_ARENA_LOSE_RATING_MODIFIER] = sConfigMgr->GetOption<float>("Arena.ArenaLoseRatingModifier", 24.0f);
m_float_configs[CONFIG_ARENA_MATCHMAKER_RATING_MODIFIER] = sConfigMgr->GetOption<float>("Arena.ArenaMatchmakerRatingModifier", 24.0f);
m_bool_configs[CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE] = sConfigMgr->GetOption<bool> ("Arena.QueueAnnouncer.Enable", false);
m_bool_configs[CONFIG_ARENA_QUEUE_ANNOUNCER_PLAYERONLY] = sConfigMgr->GetOption<bool> ("Arena.QueueAnnouncer.PlayerOnly", false);
m_bool_configs[CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE] = sConfigMgr->GetOption<bool>("Arena.QueueAnnouncer.Enable", false);
m_bool_configs[CONFIG_ARENA_QUEUE_ANNOUNCER_PLAYERONLY] = sConfigMgr->GetOption<bool>("Arena.QueueAnnouncer.PlayerOnly", false);
m_bool_configs[CONFIG_OFFHAND_CHECK_AT_SPELL_UNLEARN] = sConfigMgr->GetOption<bool>("OffhandCheckAtSpellUnlearn", true);
m_int_configs[CONFIG_CREATURE_STOP_FOR_PLAYER] = sConfigMgr->GetOption<int32>("Creature.MovingStopTimeForPlayer", 3 * MINUTE * IN_MILLISECONDS);
m_int_configs[CONFIG_CREATURE_STOP_FOR_PLAYER] = sConfigMgr->GetOption<uint32>("Creature.MovingStopTimeForPlayer", 3 * MINUTE * IN_MILLISECONDS);
if (int32 clientCacheId = sConfigMgr->GetOption<int32>("ClientCacheVersion", 0))
{
@@ -2046,7 +2047,7 @@ void World::SetInitialWorldSettings()
///- Initialize Battlegrounds
LOG_INFO("server.loading", "Starting Battleground System");
sBattlegroundMgr->CreateInitialBattlegrounds();
sBattlegroundMgr->LoadBattlegroundTemplates();
sBattlegroundMgr->InitAutomaticArenaPointDistribution();
///- Initialize outdoor pvp

View File

@@ -412,7 +412,7 @@ public:
return false;
}
Battleground* bg = sBattlegroundMgr->CreateNewBattleground(randomizedArenaBgTypeId, 80, 80, ArenaType(hcnt >= 2 ? hcnt : 2), false);
Battleground* bg = sBattlegroundMgr->CreateNewBattleground(randomizedArenaBgTypeId, GetBattlegroundBracketById(bgt->GetMapId(), bgt->GetBracketId()), ArenaType(hcnt >= 2 ? hcnt : 2), false);
if (!bg)
{
handler->PSendSysMessage("Couldn't create arena map!");

View File

@@ -215,7 +215,7 @@ public:
static bool HandleReloadBattlegroundTemplate(ChatHandler* handler)
{
LOG_INFO("server.loading", "Re-Loading Battleground Templates...");
sBattlegroundMgr->CreateInitialBattlegrounds();
sBattlegroundMgr->LoadBattlegroundTemplates();
handler->SendGlobalGMSysMessage("DB table `battleground_template` reloaded.");
return true;
}

View File

@@ -2923,6 +2923,14 @@ Arena.MaxRatingDifference = 150
Arena.RatingDiscardTimer = 600000
#
# Arena.PreviousOpponentsDiscardTimer
# Description: Time (in milliseconds) after which the previous opponents will be ignored.
# Default: 120000 - (Enabled, 2 minutes - Blizzlike)
# 0 - (Disabled)
Arena.PreviousOpponentsDiscardTimer = 120000
#
# Arena.AutoDistributePoints
# Description: Automatically distribute arena points.