From a69fe0cb1da000145455a25ca53efec6804434fb Mon Sep 17 00:00:00 2001 From: XTZGZoReX Date: Sat, 14 Nov 2009 15:07:00 +0100 Subject: [PATCH] [8813] Re-implement some changes in [8799], but with mutex calls commented. --- src/game/BattleGround.cpp | 2 +- src/game/BattleGroundHandler.cpp | 289 +++++++++++++------------------ src/game/BattleGroundMgr.cpp | 80 ++++++--- src/game/BattleGroundMgr.h | 20 ++- src/shared/revision_nr.h | 2 +- 5 files changed, 187 insertions(+), 206 deletions(-) diff --git a/src/game/BattleGround.cpp b/src/game/BattleGround.cpp index 9517b206a..fa41ad7ea 100644 --- a/src/game/BattleGround.cpp +++ b/src/game/BattleGround.cpp @@ -1084,7 +1084,7 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac { // a player has left the battleground, so there are free slots -> add to queue AddToBGFreeSlotQueue(); - sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, GetQueueId()); + sBattleGroundMgr.ScheduleQueueUpdate(0, 0, bgQueueTypeId, bgTypeId, GetQueueId()); } // Let others know diff --git a/src/game/BattleGroundHandler.cpp b/src/game/BattleGroundHandler.cpp index 903a5de89..30d98ee3e 100644 --- a/src/game/BattleGroundHandler.cpp +++ b/src/game/BattleGroundHandler.cpp @@ -148,8 +148,9 @@ void WorldSession::HandleBattlemasterJoinOpcode( WorldPacket & recv_data ) // if we're here, then the conditions to join a bg are met. We can proceed in joining. // _player->GetGroup() was already checked, grp is already initialized - GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, isPremade, 0); - uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(ginfo, _player->GetBattleGroundQueueIdFromLevel()); + BattleGroundQueue& bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId]; + GroupQueueInfo * ginfo = bgQueue.AddGroup(_player, bgTypeId, 0, false, isPremade, 0); + uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, _player->GetBattleGroundQueueIdFromLevel()); if (joinAsGroup /* && _player->GetGroup()*/) { sLog.outDebug("Battleground: the following players are joining as group:"); @@ -166,7 +167,7 @@ void WorldSession::HandleBattlemasterJoinOpcode( WorldPacket & recv_data ) member->GetSession()->SendPacket(&data); sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId); member->GetSession()->SendPacket(&data); - sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(member, ginfo); + bgQueue.AddPlayer(member, ginfo); sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName()); } sLog.outDebug("Battleground: group end"); @@ -181,12 +182,11 @@ void WorldSession::HandleBattlemasterJoinOpcode( WorldPacket & recv_data ) sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType); SendPacket(&data); - sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo); + bgQueue.AddPlayer(_player, ginfo); sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName()); } - sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel()); - if (!ginfo->IsInvitedToBGInstanceGUID) - sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AnnounceWorld(ginfo, _player->GetGUID(), true); + sBattleGroundMgr.ScheduleQueueUpdate(0, 0, bgQueueTypeId, bgTypeId, _player->GetBattleGroundQueueIdFromLevel()); + //we should announce queue status here, if we want } void WorldSession::HandleBattleGroundPlayerPositionsOpcode( WorldPacket & /*recv_data*/ ) @@ -303,7 +303,6 @@ void WorldSession::HandleBattleFieldPortOpcode( WorldPacket &recv_data ) uint8 type; // arenatype if arena uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1 - uint32 instanceId; uint32 bgTypeId_; // type id from dbc uint16 unk; // 0x1F90 constant? uint8 action; // enter battle 0x1, leave queue 0x0 @@ -312,183 +311,131 @@ void WorldSession::HandleBattleFieldPortOpcode( WorldPacket &recv_data ) if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) { - sLog.outError("Battleground: invalid bgtype (%u) received.", bgTypeId_); - // update battleground slots for the player to fix his UI and sent data. - // this is a HACK, I don't know why the client starts sending invalid packets in the first place. - // it usually happens with extremely high latency (if debugging / stepping in the code for example) - if (_player->InBattleGroundQueue()) - { - // update all queues, send invitation info if player is invited, queue info if queued - for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) - { - BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i); - if (!bgQueueTypeId) - continue; - BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId); - BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers; - BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID()); - // if the player is not in queue, continue or no group information - this should never happen - if (itrPlayerStatus == qpMap.end() || !itrPlayerStatus->second.GroupInfo) - continue; - - BattleGround * bg = NULL; - // get possibly needed data from groupinfo - uint8 arenatype = itrPlayerStatus->second.GroupInfo->ArenaType; - uint8 status = 0; - - if (!itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID) - { - // not invited to bg, get template - bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); - status = STATUS_WAIT_QUEUE; - } - else - { - // get the bg we're invited to - bg = sBattleGroundMgr.GetBattleGround(itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID, bgTypeId); - status = STATUS_WAIT_JOIN; - } - - // if bg not found, then continue, don't invite if already in the instance - if (!bg || (_player->InBattleGround() && _player->GetBattleGround() && _player->GetBattleGround()->GetInstanceID() == bg->GetInstanceID())) - continue; - - // re - invite player with proper data - WorldPacket data; - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, status, INVITE_ACCEPT_WAIT_TIME, 0, arenatype); - SendPacket(&data); - } - } + sLog.outError("BattlegroundHandler: invalid bgtype (%u) received.", bgTypeId_); + return; + } + if (!_player->InBattleGroundQueue()) + { + sLog.outError("BattlegroundHandler: Invalid CMSG_BATTLEFIELD_PORT received from player (%u), he is not in bg_queue.", _player->GetGUIDLow()); return; } //get GroupQueueInfo from BattleGroundQueue BattleGroundTypeId bgTypeId = BattleGroundTypeId(bgTypeId_); BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, type); - BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers; - BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID()); - if (itrPlayerStatus == qpMap.end()) + BattleGroundQueue& bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId]; + //we must use temporary variable, because GroupQueueInfo pointer can be deleted in BattleGroundQueue::RemovePlayer() function + GroupQueueInfo ginfo; + if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo)) { - sLog.outError("Battleground: itrplayerstatus not found."); + sLog.outError("BattlegroundHandler: itrplayerstatus not found."); return; } - - instanceId = itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID; // if action == 1, then instanceId is required - if (!instanceId && action == 1) + if (!ginfo.IsInvitedToBGInstanceGUID && action == 1) { - sLog.outError("Battleground: instance not found."); + sLog.outError("BattlegroundHandler: instance not found."); return; } - BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId, bgTypeId); + BattleGround *bg = sBattleGroundMgr.GetBattleGround(ginfo.IsInvitedToBGInstanceGUID, bgTypeId); // bg template might and must be used in case of leaving queue, when instance is not created yet if (!bg && action == 0) bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); if (!bg) { - sLog.outError("Battleground: bg_template not found for type id %u.", bgTypeId); + sLog.outError("BattlegroundHandler: bg_template not found for type id %u.", bgTypeId); return; } - if (_player->InBattleGroundQueue()) + //some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it + if (action == 1 && ginfo.ArenaType == 0) { - //we must use temporary variables, because GroupQueueInfo pointer can be deleted in BattleGroundQueue::RemovePlayer() function! - uint32 team = itrPlayerStatus->second.GroupInfo->Team; - uint32 arenaType = itrPlayerStatus->second.GroupInfo->ArenaType; - uint32 isRated = itrPlayerStatus->second.GroupInfo->IsRated; - uint32 rating = itrPlayerStatus->second.GroupInfo->ArenaTeamRating; - uint32 opponentsRating = itrPlayerStatus->second.GroupInfo->OpponentsTeamRating; - - //some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it - if (action == 1 && arenaType == 0) + //if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue + if (!_player->CanJoinToBattleground()) { - //if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue - if (!_player->CanJoinToBattleground()) - { - //send bg command result to show nice message - WorldPacket data2(SMSG_GROUP_JOINED_BATTLEGROUND, 4); - data2 << uint32(0xFFFFFFFE); - _player->GetSession()->SendPacket(&data2); - action = 0; - sLog.outDebug("Battleground: player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUIDLow()); - } - //if player don't match battleground max level, then do not allow him to enter! (this might happen when player leveled up during his waiting in queue - if (_player->getLevel() > bg->GetMaxLevel()) - { - sLog.outError("Battleground: Player %s (%u) has level higher than maxlevel of battleground! Do not port him to battleground!", _player->GetName(), _player->GetGUIDLow()); - action = 0; - } + //send bg command result to show nice message + WorldPacket data2(SMSG_GROUP_JOINED_BATTLEGROUND, 4); + data2 << uint32(0xFFFFFFFE); + _player->GetSession()->SendPacket(&data2); + action = 0; + sLog.outDebug("Battleground: player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUIDLow()); } - uint32 queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId); - WorldPacket data; - switch( action ) + //if player don't match battleground max level, then do not allow him to enter! (this might happen when player leveled up during his waiting in queue + if (_player->getLevel() > bg->GetMaxLevel()) { - case 1: // port to battleground - if (!_player->IsInvitedForBattleGroundQueueType(bgQueueTypeId)) - return; // cheating? - - _player->SetBattleGroundEntryPoint(); - - // resurrect the player - if (!_player->isAlive()) - { - _player->ResurrectPlayer(1.0f); - _player->SpawnCorpseBones(); - } - // stop taxi flight at port - if (_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->m_taxi.ClearTaxiDestinations(); - } - - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType()); - _player->GetSession()->SendPacket(&data); - // remove battleground queue status from BGmgr - sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].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->GetGUID(), false, true); - - // set the destination instance id - _player->SetBattleGroundId(bg->GetInstanceID(), bgTypeId); - // set the destination team - _player->SetBGTeam(team); - // bg->HandleBeforeTeleportToBattleGround(_player); - sBattleGroundMgr.SendToBattleGround(_player, instanceId, bgTypeId); - // add only in HandleMoveWorldPortAck() - // bg->AddPlayer(_player,team); - sLog.outDebug("Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetInstanceID(), bg->GetTypeID(), bgQueueTypeId); - break; - case 0: // leave queue - // if player leaves rated arena match before match start, it is counted as he played but he lost - if (isRated) - { - ArenaTeam * at = sObjectMgr.GetArenaTeamById(team); - if (at) - { - sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u, because he has left queue!", GUID_LOPART(_player->GetGUID()), opponentsRating); - at->MemberLost(_player, opponentsRating); - at->SaveToDB(); - } - } - _player->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0); - sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), true); - // player left queue, we should update it - do not update Arena Queue - if (!arenaType) - sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(), arenaType, isRated, rating); - SendPacket(&data); - sLog.outDebug("Battleground: player %s (%u) left queue for bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetTypeID(), bgQueueTypeId); - break; - default: - sLog.outError("Battleground port: unknown action %u", action); - break; + sLog.outError("Battleground: Player %s (%u) has level higher than maxlevel of battleground! Do not port him to battleground!", _player->GetName(), _player->GetGUIDLow()); + action = 0; } } + uint32 queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId); + WorldPacket data; + switch( action ) + { + case 1: // port to battleground + if (!_player->IsInvitedForBattleGroundQueueType(bgQueueTypeId)) + return; // cheating? + + _player->SetBattleGroundEntryPoint(); + + // resurrect the player + if (!_player->isAlive()) + { + _player->ResurrectPlayer(1.0f); + _player->SpawnCorpseBones(); + } + // stop taxi flight at port + if (_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->m_taxi.ClearTaxiDestinations(); + } + + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType()); + _player->GetSession()->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->GetGUID(), false, true); + + // set the destination instance id + _player->SetBattleGroundId(bg->GetInstanceID(), bgTypeId); + // set the destination team + _player->SetBGTeam(ginfo.Team); + // bg->HandleBeforeTeleportToBattleGround(_player); + sBattleGroundMgr.SendToBattleGround(_player, ginfo.IsInvitedToBGInstanceGUID, bgTypeId); + // add only in HandleMoveWorldPortAck() + // bg->AddPlayer(_player,team); + sLog.outDebug("Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetInstanceID(), bg->GetTypeID(), bgQueueTypeId); + break; + case 0: // leave queue + // if player leaves rated arena match before match start, it is counted as he played but he lost + if (ginfo.IsRated) + { + ArenaTeam * at = sObjectMgr.GetArenaTeamById(ginfo.Team); + if (at) + { + sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u, because he has left queue!", GUID_LOPART(_player->GetGUID()), ginfo.OpponentsTeamRating); + at->MemberLost(_player, ginfo.OpponentsTeamRating); + at->SaveToDB(); + } + } + _player->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0); + bgQueue.RemovePlayer(_player->GetGUID(), true); + // player left queue, we should update it - do not update Arena Queue + if (!ginfo.ArenaType) + sBattleGroundMgr.ScheduleQueueUpdate(ginfo.ArenaTeamRating, ginfo.ArenaType, bgQueueTypeId, bgTypeId, _player->GetBattleGroundQueueIdFromLevel()); + SendPacket(&data); + sLog.outDebug("Battleground: player %s (%u) left queue for bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetTypeID(), bgQueueTypeId); + break; + default: + sLog.outError("Battleground port: unknown action %u", action); + break; + } } void WorldSession::HandleLeaveBattlefieldOpcode( WorldPacket & /*recv_data*/ ) @@ -544,16 +491,16 @@ void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ ) } //we are sending update to player about queue - he can be invited there! //get GroupQueueInfo for queue status - BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers; - BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID()); - if (itrPlayerStatus == qpMap.end()) + BattleGroundQueue& bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId]; + GroupQueueInfo ginfo; + if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo)) continue; - if (itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID) + if (ginfo.IsInvitedToBGInstanceGUID) { - bg = sBattleGroundMgr.GetBattleGround(itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID, bgTypeId); + bg = sBattleGroundMgr.GetBattleGround(ginfo.IsInvitedToBGInstanceGUID, bgTypeId); if (!bg) continue; - uint32 remainingTime = getMSTimeDiff(getMSTime(), itrPlayerStatus->second.GroupInfo->RemoveInviteTime); + uint32 remainingTime = getMSTimeDiff(getMSTime(), ginfo.RemoveInviteTime); // send status invited to BattleGround sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_JOIN, remainingTime, 0, arenaType); SendPacket(&data); @@ -563,9 +510,9 @@ void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ ) bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); if (!bg) continue; - uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(itrPlayerStatus->second.GroupInfo, _player->GetBattleGroundQueueIdFromLevel()); + uint32 avgTime = bgQueue.GetAverageQueueWaitTime(&ginfo, _player->GetBattleGroundQueueIdFromLevel()); // send status in BattleGround Queue - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, getMSTimeDiff(itrPlayerStatus->second.GroupInfo->JoinTime, getMSTime()), arenaType); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, getMSTimeDiff(ginfo.JoinTime, getMSTime()), arenaType); SendPacket(&data); } } @@ -725,8 +672,9 @@ void WorldSession::HandleBattlemasterJoinArena( WorldPacket & recv_data ) arenaRating = avg_pers_rating; } - GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, false, arenaRating, ateamId); - uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(ginfo, _player->GetBattleGroundQueueIdFromLevel()); + BattleGroundQueue &bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId]; + GroupQueueInfo * ginfo = bgQueue.AddGroup(_player, bgTypeId, arenatype, isRated, false, arenaRating, ateamId); + uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, _player->GetBattleGroundQueueIdFromLevel()); if (asGroup) { sLog.outDebug("Battleground: arena join as group start"); @@ -745,12 +693,11 @@ void WorldSession::HandleBattlemasterJoinArena( WorldPacket & recv_data ) member->GetSession()->SendPacket(&data); sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId); member->GetSession()->SendPacket(&data); - sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(member, ginfo); + bgQueue.AddPlayer(member, ginfo); sLog.outDebug("Battleground: player joined queue for arena as group bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName()); } sLog.outDebug("Battleground: arena join as group end"); - if (isRated) - sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AnnounceWorld(ginfo, _player->GetGUID(), true); + //announce to world ... removed } else { @@ -760,10 +707,10 @@ void WorldSession::HandleBattlemasterJoinArena( WorldPacket & recv_data ) // send status packet (in queue) sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype); SendPacket(&data); - sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo); + bgQueue.AddPlayer(_player, ginfo); sLog.outDebug("Battleground: player joined queue for arena, skirmish, bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName()); } - sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(), arenatype, isRated, arenaRating); + sBattleGroundMgr.ScheduleQueueUpdate(arenaRating, arenatype, bgQueueTypeId, bgTypeId, _player->GetBattleGroundQueueIdFromLevel()); } void WorldSession::HandleReportPvPAFK( WorldPacket & recv_data ) diff --git a/src/game/BattleGroundMgr.cpp b/src/game/BattleGroundMgr.cpp index 2f23cbd5e..e79d12978 100644 --- a/src/game/BattleGroundMgr.cpp +++ b/src/game/BattleGroundMgr.cpp @@ -177,6 +177,7 @@ GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, BattleGroundTypeId index++; sLog.outDebug("Adding Group to BattleGroundQueue bgTypeId : %u, queue_id : %u, index : %u", BgTypeId, queue_id, index); + //ACE_Guard guard(m_Lock); m_QueuedGroups[queue_id][index].push_back(ginfo); // return ginfo, because it is needed to add players to this group info @@ -186,6 +187,8 @@ GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, BattleGroundTypeId //add player to playermap void BattleGroundQueue::AddPlayer(Player *plr, GroupQueueInfo *ginfo) { + //ACE_Guard guard(m_Lock); + //if player isn't in queue, he is added, if already is, then values are overwritten, no memory leak PlayerQueueInfo& info = m_QueuedPlayers[plr->GetGUID()]; info.LastOnlineTime = getMSTime(); @@ -248,6 +251,7 @@ uint32 BattleGroundQueue::GetAverageQueueWaitTime(GroupQueueInfo* ginfo, BGQueue void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCount) { //Player *plr = sObjectMgr.GetPlayer(guid); + //ACE_Guard guard(m_Lock); int32 queue_id = -1; // signed for proper for-loop finish QueuedPlayersMap::iterator itr; @@ -364,6 +368,26 @@ void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCou } } +//returns true when player pl_guid is in queue and is invited to bgInstanceGuid +bool BattleGroundQueue::IsPlayerInvited(const uint64& pl_guid, const uint32 bgInstanceGuid, const uint32 removeTime) +{ + //ACE_Guard g(m_Lock); + QueuedPlayersMap::const_iterator qItr = m_QueuedPlayers.find(pl_guid); + return ( qItr != m_QueuedPlayers.end() + && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == bgInstanceGuid + && qItr->second.GroupInfo->RemoveInviteTime == removeTime ); +} + +bool BattleGroundQueue::GetPlayerGroupInfoData(const uint64& guid, GroupQueueInfo* ginfo) +{ + //ACE_Guard g(m_Lock); + QueuedPlayersMap::const_iterator qItr = m_QueuedPlayers.find(guid); + if (qItr == m_QueuedPlayers.end()) + return false; + *ginfo = *(qItr->second.GroupInfo); + return true; +} + //Announce world message void BattleGroundQueue::AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playerGUID, bool isAddedToQueue) { @@ -461,7 +485,7 @@ bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * b plr->SetInviteForBattleGroundQueueType(bgQueueTypeId, ginfo->IsInvitedToBGInstanceGUID); // create remind invite events - BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(plr->GetGUID(), ginfo->IsInvitedToBGInstanceGUID, bgTypeId, ginfo->RemoveInviteTime); + BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(plr->GetGUID(), ginfo->IsInvitedToBGInstanceGUID, bgTypeId, ginfo->ArenaType, ginfo->RemoveInviteTime); plr->m_Events.AddEvent(inviteEvent, plr->m_Events.CalculateTime(INVITATION_REMIND_TIME)); // create automatic remove events BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), ginfo->IsInvitedToBGInstanceGUID, bgTypeId, bgQueueTypeId, ginfo->RemoveInviteTime); @@ -732,6 +756,7 @@ should be called from BattleGround::RemovePlayer function in some cases */ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType, bool isRated, uint32 arenaRating) { + //ACE_Guard guard(m_Lock); //if no players in queue - do nothing if( m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty() && m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty() && @@ -1021,17 +1046,15 @@ bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType()); uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId); - if( queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES ) // player is in queue or in battleground + if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue or in battleground { // check if player is invited to this bg - BattleGroundQueue::QueuedPlayersMap const& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers; - BattleGroundQueue::QueuedPlayersMap::const_iterator qItr = qpMap.find(m_PlayerGuid); - if( qItr != qpMap.end() && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID - && qItr->second.GroupInfo->RemoveInviteTime == m_RemoveTime ) + BattleGroundQueue &bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId]; + if (bgQueue.IsPlayerInvited(m_PlayerGuid, m_BgInstanceGUID, m_RemoveTime)) { WorldPacket data; //we must send remaining time in queue - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME - INVITATION_REMIND_TIME, 0, qItr->second.GroupInfo->ArenaType); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME - INVITATION_REMIND_TIME, 0, m_ArenaType); plr->GetSession()->SendPacket(&data); } } @@ -1064,22 +1087,19 @@ bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) //bg pointer can be NULL! so use it carefully! uint32 queueSlot = plr->GetBattleGroundQueueIndex(m_BgQueueTypeId); - if( queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES ) // player is in queue, or in Battleground + if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue, or in Battleground { // check if player is in queue for this BG and if we are removing his invite event - BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[m_BgQueueTypeId].m_QueuedPlayers; - BattleGroundQueue::QueuedPlayersMap::iterator qMapItr = qpMap.find(m_PlayerGuid); - if( qMapItr != qpMap.end() && qMapItr->second.GroupInfo - && qMapItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID - && qMapItr->second.GroupInfo->RemoveInviteTime == m_RemoveTime ) + BattleGroundQueue &bgQueue = sBattleGroundMgr.m_BattleGroundQueues[m_BgQueueTypeId]; + if (bgQueue.IsPlayerInvited(m_PlayerGuid, m_BgInstanceGUID, m_RemoveTime)) { sLog.outDebug("Battleground: removing player %u from bg queue for instance %u because of not pressing enter battle in time.",plr->GetGUIDLow(),m_BgInstanceGUID); plr->RemoveBattleGroundQueueId(m_BgQueueTypeId); - sBattleGroundMgr.m_BattleGroundQueues[m_BgQueueTypeId].RemovePlayer(m_PlayerGuid, true); + bgQueue.RemovePlayer(m_PlayerGuid, true); //update queues if battleground isn't ended - if (bg) - sBattleGroundMgr.ScheduleQueueUpdate(m_BgQueueTypeId, m_BgTypeId, bg->GetQueueId()); + if (bg && bg->isBattleGround() && bg->GetStatus() != STATUS_WAIT_LEAVE) + sBattleGroundMgr.ScheduleQueueUpdate(0, 0, m_BgQueueTypeId, m_BgTypeId, bg->GetQueueId()); WorldPacket data; sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0); @@ -1167,18 +1187,24 @@ void BattleGroundMgr::Update(uint32 diff) // update scheduled queues if (!m_QueueUpdateScheduler.empty()) { - //copy vector and clear the other - // TODO add lock - // TODO maybe std::list would be better and then unlock after end of cycle - std::vector scheduled(m_QueueUpdateScheduler); - m_QueueUpdateScheduler.clear(); - // TODO drop lock + std::vector scheduled; + { + //create mutex + //ACE_Guard guard(SchedulerLock); + //copy vector and clear the other + scheduled = std::vector(m_QueueUpdateScheduler); + m_QueueUpdateScheduler.clear(); + //release lock + } + for (uint8 i = 0; i < scheduled.size(); i++) { - BattleGroundQueueTypeId bgQueueTypeId = BattleGroundQueueTypeId(scheduled[i] >> 16); + uint32 arenaRating = scheduled[i] >> 32; + uint8 arenaType = scheduled[i] >> 24 & 255; + BattleGroundQueueTypeId bgQueueTypeId = BattleGroundQueueTypeId(scheduled[i] >> 16 & 255); BattleGroundTypeId bgTypeId = BattleGroundTypeId((scheduled[i] >> 8) & 255); BGQueueIdBasedOnLevel queue_id = BGQueueIdBasedOnLevel(scheduled[i] & 255); - m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, queue_id); + m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, queue_id, arenaType, arenaRating > 0, arenaRating); } } @@ -2008,11 +2034,11 @@ void BattleGroundMgr::ToggleArenaTesting() sWorld.SendWorldText(LANG_DEBUG_ARENA_OFF); } -void BattleGroundMgr::ScheduleQueueUpdate(BattleGroundQueueTypeId bgQueueTypeId, BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id) +void BattleGroundMgr::ScheduleQueueUpdate(uint32 arenaRating, uint8 arenaType, BattleGroundQueueTypeId bgQueueTypeId, BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id) { - //This method must be atomic, TODO add mutex + //ACE_Guard guard(SchedulerLock); //we will use only 1 number created of bgTypeId and queue_id - uint32 schedule_id = (bgQueueTypeId << 16) | (bgTypeId << 8) | queue_id; + uint64 schedule_id = ((uint64)arenaRating << 32) | (arenaType << 24) | (bgQueueTypeId << 16) | (bgTypeId << 8) | queue_id; bool found = false; for (uint8 i = 0; i < m_QueueUpdateScheduler.size(); i++) { diff --git a/src/game/BattleGroundMgr.h b/src/game/BattleGroundMgr.h index 4d72d9656..36f097cdb 100644 --- a/src/game/BattleGroundMgr.h +++ b/src/game/BattleGroundMgr.h @@ -23,6 +23,7 @@ #include "Policies/Singleton.h" #include "Utilities/EventProcessor.h" #include "BattleGround.h" +#include "ace/Recursive_Thread_Mutex.h" typedef std::map BattleGroundSet; @@ -83,12 +84,19 @@ class BattleGroundQueue GroupQueueInfo * AddGroup(Player * leader, BattleGroundTypeId bgTypeId, uint8 ArenaType, bool isRated, bool isPremade, uint32 ArenaRating, uint32 ArenaTeamId = 0); void AddPlayer(Player *plr, GroupQueueInfo *ginfo); void RemovePlayer(const uint64& guid, bool decreaseInvitedCount); + bool IsPlayerInvited(const uint64& pl_guid, const uint32 bgInstanceGuid, const uint32 removeTime); + bool GetPlayerGroupInfoData(const uint64& guid, GroupQueueInfo* ginfo); void PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id); uint32 GetAverageQueueWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id); void DecreaseGroupLength(uint32 queueId, uint32 AsGroup); void AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playerGUID, bool isAddedToQueue); + private: + //mutex that should not allow changing private data, nor allowing to update Queue during private data change. + ACE_Recursive_Thread_Mutex m_Lock; + + typedef std::map QueuedPlayersMap; QueuedPlayersMap m_QueuedPlayers; @@ -123,8 +131,6 @@ class BattleGroundQueue //one selection pool for horde, other one for alliance SelectionPool m_SelectionPools[BG_TEAMS_COUNT]; - private: - bool InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side); uint32 m_WaitTimes[BG_TEAMS_COUNT][MAX_BATTLEGROUND_QUEUES][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME]; uint32 m_WaitTimeLastPlayer[BG_TEAMS_COUNT][MAX_BATTLEGROUND_QUEUES]; @@ -138,8 +144,8 @@ class BattleGroundQueue class BGQueueInviteEvent : public BasicEvent { public: - BGQueueInviteEvent(const uint64& pl_guid, uint32 BgInstanceGUID, BattleGroundTypeId BgTypeId, uint32 removeTime) : - m_PlayerGuid(pl_guid), m_BgInstanceGUID(BgInstanceGUID), m_BgTypeId(BgTypeId), m_RemoveTime(removeTime) + BGQueueInviteEvent(const uint64& pl_guid, uint32 BgInstanceGUID, BattleGroundTypeId BgTypeId, uint8 arenaType, uint32 removeTime) : + m_PlayerGuid(pl_guid), m_BgInstanceGUID(BgInstanceGUID), m_BgTypeId(BgTypeId), m_ArenaType(arenaType), m_RemoveTime(removeTime) { }; virtual ~BGQueueInviteEvent() {}; @@ -150,6 +156,7 @@ class BGQueueInviteEvent : public BasicEvent uint64 m_PlayerGuid; uint32 m_BgInstanceGUID; BattleGroundTypeId m_BgTypeId; + uint8 m_ArenaType; uint32 m_RemoveTime; }; @@ -219,7 +226,7 @@ class BattleGroundMgr BGFreeSlotQueueType BGFreeSlotQueue[MAX_BATTLEGROUND_TYPE_ID]; - void ScheduleQueueUpdate(BattleGroundQueueTypeId bgQueueTypeId, BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id); + void ScheduleQueueUpdate(uint32 arenaRating, uint8 arenaType, BattleGroundQueueTypeId bgQueueTypeId, BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id); uint32 GetMaxRatingDifference() const; uint32 GetRatingDiscardTimer() const; uint32 GetPrematureFinishTime() const; @@ -265,13 +272,14 @@ class BattleGroundMgr static bool IsBGWeekend(BattleGroundTypeId bgTypeId); private: + ACE_Thread_Mutex SchedulerLock; BattleMastersMap mBattleMastersMap; CreatureBattleEventIndexesMap m_CreatureBattleEventIndexMap; GameObjectBattleEventIndexesMap m_GameObjectBattleEventIndexMap; /* Battlegrounds */ BattleGroundSet m_BattleGrounds[MAX_BATTLEGROUND_TYPE_ID]; - std::vectorm_QueueUpdateScheduler; + std::vector m_QueueUpdateScheduler; std::set m_ClientBattleGroundIds[MAX_BATTLEGROUND_TYPE_ID][MAX_BATTLEGROUND_QUEUES]; //the instanceids just visible for the client uint32 m_NextRatingDiscardUpdate; time_t m_NextAutoDistributionTime; diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 1aac25873..dccf7867c 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "8812" + #define REVISION_NR "8813" #endif // __REVISION_NR_H__