Skip to content

Commit

Permalink
BG: Rework BG queue to be asynchronous and resolve race conditions
Browse files Browse the repository at this point in the history
Thx to insunaa for making it compile on linux
  • Loading branch information
killerwife committed Oct 9, 2024
1 parent 910d594 commit f0e5bdc
Show file tree
Hide file tree
Showing 20 changed files with 2,494 additions and 1,965 deletions.
85 changes: 61 additions & 24 deletions src/game/BattleGround/BattleGround.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,15 +264,20 @@ BattleGround::~BattleGround()
// skip template bgs as they were never added to visible bg list
BattleGroundBracketId bracketId = GetBracketId();
if (bracketId != BG_BRACKET_ID_TEMPLATE)
sBattleGroundMgr.DeleteClientVisibleInstanceId(GetTypeId(), bracketId, GetClientInstanceId());
{
sWorld.GetBGQueue().GetMessager().AddMessage([bgTypeId = GetTypeId(), bracketId, clientInstanceId = GetClientInstanceId()](BattleGroundQueue* queue)
{
queue->DeleteClientVisibleInstanceId(bgTypeId, bracketId, clientInstanceId);
});
}

// unload map
// map can be null at bg destruction
if (m_bgMap)
m_bgMap->SetUnload();

// remove from bg free slot queue
this->RemoveFromBgFreeSlotQueue();
this->RemovedFromBgFreeSlotQueue(true);

for (BattleGroundScoreMap::const_iterator itr = m_playerScores.begin(); itr != m_playerScores.end(); ++itr)
delete itr->second;
Expand Down Expand Up @@ -402,7 +407,7 @@ void BattleGround::Update(uint32 diff)
BattleGroundTypeId BgTypeId = GetTypeId();

if (!IsArena())
sWorld.SendWorldText(LANG_BG_STARTED_ANNOUNCE_WORLD, GetName(), Player::GetMinLevelForBattleGroundBracketId(bracketId, BgTypeId), Player::GetMaxLevelForBattleGroundBracketId(bracketId, BgTypeId));
sWorld.SendWorldText(LANG_BG_STARTED_ANNOUNCE_WORLD, GetName(), sBattleGroundMgr.GetMinLevelForBattleGroundBracketId(bracketId, BgTypeId), sBattleGroundMgr.GetMaxLevelForBattleGroundBracketId(bracketId, BgTypeId));
else
sWorld.SendWorldText(LANG_ARENA_STARTED_ANNOUNCE_WORLD, GetName(), GetArenaType(), GetArenaType());
}
Expand Down Expand Up @@ -735,7 +740,7 @@ void BattleGround::UpdateWorldStateForPlayer(uint32 field, uint32 value, Player*
*/
void BattleGround::EndBattleGround(Team winner)
{
this->RemoveFromBgFreeSlotQueue();
this->RemovedFromBgFreeSlotQueue(true);

ArenaTeam* winner_arena_team = nullptr;
ArenaTeam* loser_arena_team = nullptr;
Expand Down Expand Up @@ -928,7 +933,7 @@ void BattleGround::EndBattleGround(Team winner)
plr->GetSession()->SendPacket(data);

BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BgQueueTypeId(GetTypeId(), GetArenaType());
sBattleGroundMgr.BuildBattleGroundStatusPacket(data, this, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime(), GetArenaType(), plr->GetBGTeam());
sBattleGroundMgr.BuildBattleGroundStatusPacket(data, true, GetTypeId(), GetClientInstanceId(), IsRated(), GetMapId(), plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime(), GetArenaType(), plr->GetBGTeam());
plr->GetSession()->SendPacket(data);
}

Expand Down Expand Up @@ -962,6 +967,16 @@ uint32 BattleGround::GetBonusHonorFromKill(uint32 kills) const
return (uint32)MaNGOS::Honor::hk_honor_at_level(GetMaxLevel(), kills);
}

void BattleGround::SetStatus(BattleGroundStatus status)
{
m_status = status;
sWorld.GetBGQueue().GetMessager().AddMessage([status, bgTypeId = GetTypeId(), instanceId = GetInstanceId()](BattleGroundQueue* queue)
{
if (BattleGroundInQueueInfo* bgInstance = queue->GetFreeSlotInstance(bgTypeId, instanceId))
bgInstance->status = status;
});
}

/**
Function that returns the battleground master entry
*/
Expand Down Expand Up @@ -1237,7 +1252,7 @@ void BattleGround::RemovePlayerAtLeave(ObjectGuid playerGuid, bool isOnTransport
if (doSendPacket)
{
WorldPacket data;
sBattleGroundMgr.BuildBattleGroundStatusPacket(data, this, player->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0, ARENA_TYPE_NONE, TEAM_NONE);
sBattleGroundMgr.BuildBattleGroundStatusPacket(data, true, GetTypeId(), GetClientInstanceId(), IsRated(), GetMapId(), player->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0, ARENA_TYPE_NONE, TEAM_NONE);
player->GetSession()->SendPacket(data);
}

Expand Down Expand Up @@ -1266,13 +1281,24 @@ void BattleGround::RemovePlayerAtLeave(ObjectGuid playerGuid, bool isOnTransport
delete group;
}
}
DecreaseInvitedCount(team);

SetInvitedCount(team, GetInvitedCount(team) - 1); // change ahead of free slot queue - will be synched again after
// we should update battleground queue, but only if bg isn't ending
if (IsBattleGround() && GetStatus() < STATUS_WAIT_LEAVE)
{
// a player has left the battleground, so there are free slots -> add to queue
AddToBgFreeSlotQueue();
sBattleGroundMgr.ScheduleQueueUpdate(0, ARENA_TYPE_NONE, bgQueueTypeId, bgTypeId, GetBracketId());
if (!AddToBgFreeSlotQueue()) // avoid setting two messages - if was already in queue, just update count
{
sWorld.GetBGQueue().GetMessager().AddMessage([bgTypeId, instanceId = GetInstanceId(), team](BattleGroundQueue* queue)
{
if (BattleGroundInQueueInfo* bgInstance = queue->GetFreeSlotInstance(bgTypeId, instanceId))
bgInstance->DecreaseInvitedCount(team);
});
}
sWorld.GetBGQueue().GetMessager().AddMessage([bgQueueTypeId, bgTypeId, bracketId = GetBracketId()](BattleGroundQueue* queue)
{
queue->ScheduleQueueUpdate(0, ARENA_TYPE_NONE, bgQueueTypeId, bgTypeId, bracketId);
});
}

// Let others know
Expand Down Expand Up @@ -1340,8 +1366,7 @@ void BattleGround::StartBattleGround()
{
SetStartTime(0);

// add BG to free slot queue
AddToBgFreeSlotQueue();
// expects to be already added in free queue

// add bg to update list
// This must be done here, because we need to have already invited some players when first BG::Update() method is executed
Expand Down Expand Up @@ -1504,33 +1529,45 @@ void BattleGround::EventPlayerLoggedOut(Player* player)
/**
Function that returns the number of players that can join a battleground based on the provided team
*/
void BattleGround::AddToBgFreeSlotQueue()
bool BattleGround::AddToBgFreeSlotQueue()
{
// make sure to add only once
if (!m_hasBgFreeSlotQueue && IsBattleGround())
{
sBattleGroundMgr.BgFreeSlotQueue[m_typeId].push_front(this);
m_hasBgFreeSlotQueue = true;
BattleGroundInQueueInfo bgInfo;
bgInfo.Fill(this);
sWorld.GetBGQueue().GetMessager().AddMessage([bgInfo](BattleGroundQueue* queue)
{
queue->AddBgToFreeSlots(bgInfo);
});
return true;
}
return false;
}

/**
Method that removes this battleground from free queue - it must be called when deleting battleground
*/
void BattleGround::RemoveFromBgFreeSlotQueue()
void BattleGround::RemovedFromBgFreeSlotQueue(bool removeFromQueue)
{
// set to be able to re-add if needed
m_hasBgFreeSlotQueue = false;
BgFreeSlotQueueType& bgFreeSlot = sBattleGroundMgr.BgFreeSlotQueue[m_typeId];

for (BgFreeSlotQueueType::iterator itr = bgFreeSlot.begin(); itr != bgFreeSlot.end(); ++itr)
if (m_hasBgFreeSlotQueue && removeFromQueue)
{
if ((*itr)->GetInstanceId() == GetInstanceId())
sWorld.GetBGQueue().GetMessager().AddMessage([bgTypeId = GetTypeId(), instanceId = GetInstanceId()](BattleGroundQueue* queue)
{
bgFreeSlot.erase(itr);
return;
}
queue->RemoveBgFromFreeSlots(bgTypeId, instanceId);
});
}
m_hasBgFreeSlotQueue = false;
}

void BattleGround::SetInvitedCount(Team team, uint32 count)
{
if (team == ALLIANCE)
m_invitedAlliance = count;
else
m_invitedHorde = count;
}

/**
Expand Down Expand Up @@ -1963,7 +2000,7 @@ void BattleGround::SendBcdToTeam(int32 bcdEntry, ChatMsg msgtype, Creature const
*/
void BattleGround::EndNow()
{
RemoveFromBgFreeSlotQueue();
RemovedFromBgFreeSlotQueue(true);
SetStatus(STATUS_WAIT_LEAVE);
SetEndTime(0);
}
Expand Down Expand Up @@ -2058,7 +2095,7 @@ void BattleGround::PlayerAddedToBgCheckIfBgIsRunning(Player* player)
sBattleGroundMgr.BuildPvpLogDataPacket(data, this);
player->GetSession()->SendPacket(data);

sBattleGroundMgr.BuildBattleGroundStatusPacket(data, this, player->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, GetEndTime(), GetStartTime(), GetArenaType(), player->GetBGTeam());
sBattleGroundMgr.BuildBattleGroundStatusPacket(data, true, GetTypeId(), GetClientInstanceId(), IsRated(), GetMapId(), player->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, GetEndTime(), GetStartTime(), GetArenaType(), player->GetBGTeam());
player->GetSession()->SendPacket(data);
}

Expand Down
10 changes: 5 additions & 5 deletions src/game/BattleGround/BattleGround.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "Maps/Map.h"
#include "Util/ByteBuffer.h"
#include "Entities/ObjectGuid.h"
#include "BattleGround/BattleGroundDefines.h"

// magic event-numbers
#define BG_EVENT_NONE 255
Expand Down Expand Up @@ -335,7 +336,7 @@ class BattleGround
void SetName(char const* name) { m_name = name; }
void SetTypeId(BattleGroundTypeId typeId) { m_typeId = typeId; }
void SetBracketId(BattleGroundBracketId id) { m_bracketId = id; }
void SetStatus(BattleGroundStatus status) { m_status = status; }
void SetStatus(BattleGroundStatus status);
void SetClientInstanceId(uint32 instanceId) { m_clientInstanceId = instanceId; }
void SetStartTime(uint32 time) { m_startTime = time; }
void SetEndTime(uint32 time) { m_endTime = time; }
Expand All @@ -353,12 +354,11 @@ class BattleGround
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
bool AddToBgFreeSlotQueue(); // this queue will be useful when more battlegrounds instances will be available
void RemovedFromBgFreeSlotQueue(bool removeFromQueue); // this method could delete whole BG instance, if another free is available

// Functions to decrease or increase player count
void DecreaseInvitedCount(Team team) { (team == ALLIANCE) ? --m_invitedAlliance : --m_invitedHorde; }
void IncreaseInvitedCount(Team team) { (team == ALLIANCE) ? ++m_invitedAlliance : ++m_invitedHorde; }
void SetInvitedCount(Team team, uint32 count);
uint32 GetInvitedCount(Team team) const
{
if (team == ALLIANCE)
Expand Down
74 changes: 74 additions & 0 deletions src/game/BattleGround/BattleGroundDefines.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* This file is part of the CMaNGOS Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#ifndef _BG_DEFINES_H
#define _BG_DEFINES_H

#include "Common.h"

#define BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY 86400 // seconds in a day
#define COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME 10

enum BattleGroundQueueGroupTypes
{
BG_QUEUE_PREMADE_ALLIANCE = 0,
BG_QUEUE_PREMADE_HORDE = 1,
BG_QUEUE_NORMAL_ALLIANCE = 2,
BG_QUEUE_NORMAL_HORDE = 3
};

#define BG_QUEUE_GROUP_TYPES_COUNT 4

enum BattleGroundGroupJoinStatus
{
BG_GROUP_JOIN_STATUS_TEAM_LEFT_QUEUE = -7,
BG_GROUP_JOIN_STATUS_QUEUED_FOR_RATED = -6,
BG_GROUP_JOIN_STATUS_CANNOT_QUEUE_FOR_RATED = -5,
BG_GROUP_JOIN_STATUS_TOO_MANY_QUEUES = -4,
BG_GROUP_JOIN_STATUS_NOT_IN_TEAM = -3,
BG_GROUP_JOIN_STATUS_DESERTERS = -2,
BG_GROUP_JOIN_STATUS_NOT_ELIGIBLE = -1,
BG_GROUP_JOIN_STATUS_SUCCESS = 0,
};

// indexes of BattlemasterList.dbc
enum BattleGroundTypeId
{
BATTLEGROUND_TYPE_NONE = 0,
BATTLEGROUND_AV = 1,
BATTLEGROUND_WS = 2,
BATTLEGROUND_AB = 3,
BATTLEGROUND_NA = 4,
BATTLEGROUND_BE = 5,
BATTLEGROUND_AA = 6, // all arenas
BATTLEGROUND_EY = 7,
BATTLEGROUND_RL = 8
};
#define MAX_BATTLEGROUND_TYPE_ID 9

enum ArenaType
{
ARENA_TYPE_NONE = 0, // used for mark non-arenas or problematic cases
ARENA_TYPE_2v2 = 2,
ARENA_TYPE_3v3 = 3,
ARENA_TYPE_5v5 = 5
};

inline bool IsArenaTypeValid(ArenaType type) { return type == ARENA_TYPE_2v2 || type == ARENA_TYPE_3v3 || type == ARENA_TYPE_5v5; }

#endif
Loading

0 comments on commit f0e5bdc

Please sign in to comment.