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 Nov 16, 2024
1 parent e8da17c commit d77d726
Show file tree
Hide file tree
Showing 18 changed files with 2,500 additions and 1,981 deletions.
79 changes: 54 additions & 25 deletions src/game/BattleGround/BattleGround.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,9 +295,9 @@ BattleGround::~BattleGround()
BattleGroundBracketId bracketId = GetBracketId();
if (bracketId != BG_BRACKET_ID_TEMPLATE)
{
sBattleGroundMgr.GetMessager().AddMessage([typeId = GetTypeId(), bracketId, clientInstanceId = GetClientInstanceId()](BattleGroundMgr* mgr)
sWorld.GetBGQueue().GetMessager().AddMessage([bgTypeId = GetTypeId(), bracketId, clientInstanceId = GetClientInstanceId()](BattleGroundQueue* queue)
{
mgr->DeleteClientVisibleInstanceId(typeId, bracketId, clientInstanceId);
queue->DeleteClientVisibleInstanceId(bgTypeId, bracketId, clientInstanceId);
});
}

Expand All @@ -307,7 +307,7 @@ BattleGround::~BattleGround()
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 @@ -773,7 +773,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 @@ -1006,7 +1006,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(), GetMinLevel(), GetMaxLevel());
plr->GetSession()->SendPacket(data);
plr->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND, 1);
}
Expand Down Expand Up @@ -1041,6 +1041,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 @@ -1338,7 +1348,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, GetMinLevel(), GetMaxLevel());
player->GetSession()->SendPacket(data);
}

Expand Down Expand Up @@ -1367,15 +1377,23 @@ 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.GetMessager().AddMessage([bgQueueTypeId, bgTypeId, bracketId = GetBracketId()](BattleGroundMgr* mgr)
if (!AddToBgFreeSlotQueue()) // avoid setting two messages - if was already in queue, just update count
{
mgr->ScheduleQueueUpdate(0, ARENA_TYPE_NONE, bgQueueTypeId, bgTypeId, bracketId);
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);
});
}

Expand Down Expand Up @@ -1472,8 +1490,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 @@ -1698,33 +1715,45 @@ void BattleGround::RemovePlayer(Player* /*player*/, ObjectGuid /*guid*/)
/**
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 @@ -2167,7 +2196,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 @@ -2282,7 +2311,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(), GetMinLevel(), GetMaxLevel());
player->GetSession()->SendPacket(data);
}

Expand Down
30 changes: 4 additions & 26 deletions src/game/BattleGround/BattleGround.h
Original file line number Diff line number Diff line change
Expand Up @@ -270,27 +270,6 @@ enum BattleGroundStartingEventsIds
};
#define BG_STARTING_EVENT_COUNT 4

enum BattleGroundGroupJoinStatus
{
// positive values are indexes in BattlemasterList.dbc
BG_GROUP_JOIN_STATUS_BATTLEGROUND_FAIL = 0, // Your group has joined a battleground queue, but you are not eligible (showed for non existing BattlemasterList.dbc indexes)
BG_GROUP_JOIN_STATUS_NOT_ELIGIBLE = -1, // not show anything
BG_GROUP_JOIN_STATUS_DESERTERS = -2, // You cannot join the battleground yet because you or one of your party members is flagged as a Deserter.
BG_GROUP_JOIN_STATUS_NOT_IN_TEAM = -3, // Incorrect party size for this arena.
BG_GROUP_JOIN_STATUS_TOO_MANY_QUEUES = -4, // You can only be queued for 2 battles at once
BG_GROUP_JOIN_STATUS_CANNOT_QUEUE_FOR_RATED = -5, // You cannot queue for a rated match while queued for other battles
BG_GROUP_JOIN_STATUS_QUEUED_FOR_RATED = -6, // You cannot queue for another battle while queued for a rated arena match
BG_GROUP_JOIN_STATUS_TEAM_LEFT_QUEUE = -7, // Your team has left the arena queue
BG_GROUP_JOIN_STATUS_NOT_IN_BATTLEGROUND = -8, // You can't do that in a battleground.
BG_GROUP_JOIN_STATUS_XP_GAIN = -9, // wtf, doesn't exist in client...
BG_GROUP_JOIN_STATUS_JOIN_RANGE_INDEX = -10, // Cannot join the queue unless all members of your party are in the same battleground level range.
BG_GROUP_JOIN_STATUS_JOIN_TIMED_OUT = -11, // %s was unavailable to join the queue. (uint64 guid exist in client cache)
BG_GROUP_JOIN_STATUS_JOIN_FAILED = -12, // Join as a group failed (uint64 guid doesn't exist in client cache)
BG_GROUP_JOIN_STATUS_LFG_CANT_USE_BATTLEGROUND = -13, // You cannot queue for a battleground or arena while using the dungeon system.
BG_GROUP_JOIN_STATUS_IN_RANDOM_BG = -14, // Can't do that while in a Random Battleground queue.
BG_GROUP_JOIN_STATUS_IN_NON_RANDOM_BG = -15, // Can't queue for Random Battleground while in another Battleground queue.
};

/*
This class is used to keep the battleground score for each individual player
*/
Expand Down Expand Up @@ -383,7 +362,7 @@ class BattleGround
void SetRandomTypeId(BattleGroundTypeId typeId) { m_randomTypeId = typeId; }
// here we can count minlevel and maxlevel for players
void SetBracket(PvPDifficultyEntry const* bracketEntry);
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 @@ -402,12 +381,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
49 changes: 41 additions & 8 deletions src/game/BattleGround/BattleGroundDefines.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,45 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#ifndef MANGOSSERVER_BATTLEGROUND_DEFINES_H
#define MANGOSSERVER_BATTLEGROUND_DEFINES_H
#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
{
// positive values are indexes in BattlemasterList.dbc
BG_GROUP_JOIN_STATUS_BATTLEGROUND_FAIL = 0, // Your group has joined a battleground queue, but you are not eligible (showed for non existing BattlemasterList.dbc indexes)
BG_GROUP_JOIN_STATUS_NOT_ELIGIBLE = -1, // not show anything
BG_GROUP_JOIN_STATUS_DESERTERS = -2, // You cannot join the battleground yet because you or one of your party members is flagged as a Deserter.
BG_GROUP_JOIN_STATUS_NOT_IN_TEAM = -3, // Incorrect party size for this arena.
BG_GROUP_JOIN_STATUS_TOO_MANY_QUEUES = -4, // You can only be queued for 2 battles at once
BG_GROUP_JOIN_STATUS_CANNOT_QUEUE_FOR_RATED = -5, // You cannot queue for a rated match while queued for other battles
BG_GROUP_JOIN_STATUS_QUEUED_FOR_RATED = -6, // You cannot queue for another battle while queued for a rated arena match
BG_GROUP_JOIN_STATUS_TEAM_LEFT_QUEUE = -7, // Your team has left the arena queue
BG_GROUP_JOIN_STATUS_NOT_IN_BATTLEGROUND = -8, // You can't do that in a battleground.
BG_GROUP_JOIN_STATUS_XP_GAIN = -9, // wtf, doesn't exist in client...
BG_GROUP_JOIN_STATUS_JOIN_RANGE_INDEX = -10, // Cannot join the queue unless all members of your party are in the same battleground level range.
BG_GROUP_JOIN_STATUS_JOIN_TIMED_OUT = -11, // %s was unavailable to join the queue. (uint64 guid exist in client cache)
BG_GROUP_JOIN_STATUS_JOIN_FAILED = -12, // Join as a group failed (uint64 guid doesn't exist in client cache)
BG_GROUP_JOIN_STATUS_LFG_CANT_USE_BATTLEGROUND = -13, // You cannot queue for a battleground or arena while using the dungeon system.
BG_GROUP_JOIN_STATUS_IN_RANDOM_BG = -14, // Can't do that while in a Random Battleground queue.
BG_GROUP_JOIN_STATUS_IN_NON_RANDOM_BG = -15, // Can't queue for Random Battleground while in another Battleground queue.
};

// indexes of BattlemasterList.dbc
enum BattleGroundTypeId
{
Expand All @@ -43,13 +77,12 @@ enum BattleGroundTypeId

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
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 // MANGOSSERVER_BATTLEGROUND_DEFINES_H

#endif
Loading

0 comments on commit d77d726

Please sign in to comment.