From a11a6195aff0ae7dceb4bb51c61bf44c2916f903 Mon Sep 17 00:00:00 2001 From: ratkosrb Date: Mon, 13 May 2024 15:37:30 +0300 Subject: [PATCH] Fix battlegrounds remaining open if player logs out after being invited. --- src/game/Battlegrounds/BattleGround.cpp | 7 ++++ src/game/Battlegrounds/BattleGroundMgr.cpp | 44 +++++++++++++++++++--- src/game/Chat/Chat.cpp | 1 + src/game/Chat/Chat.h | 1 + src/game/Commands/ServerCommands.cpp | 9 +++++ src/game/Handlers/BattleGroundHandler.cpp | 11 ++++++ src/game/Maps/Map.cpp | 5 ++- src/game/Maps/Map.h | 2 + 8 files changed, 74 insertions(+), 6 deletions(-) diff --git a/src/game/Battlegrounds/BattleGround.cpp b/src/game/Battlegrounds/BattleGround.cpp index e01a958dd3f..1f580180717 100644 --- a/src/game/Battlegrounds/BattleGround.cpp +++ b/src/game/Battlegrounds/BattleGround.cpp @@ -293,6 +293,9 @@ void BattleGround::Update(uint32 diff) // BattleGround Template instance cannot be updated, because it would be deleted if (!GetInvitedCount(HORDE) && !GetInvitedCount(ALLIANCE)) delete this; + // update queue to avoid bg remaining indefinitely until player logs back in if he logs out after it pops + else if (GetStatus() <= STATUS_WAIT_JOIN && (GetBgMap()->GetCreateTime() + 2 * MINUTE) < time(nullptr)) + sBattleGroundMgr.ScheduleQueueUpdate(BattleGroundMgr::BgQueueTypeId(GetTypeID()), GetTypeID(), GetBracketId()); return; } @@ -741,6 +744,10 @@ void BattleGround::EndBattleGround(Team winner) #else DoOrSimulateScriptTextForMap(winTextId, GetHeraldEntry(), GetBgMap()); #endif + + // remove any invited players from the queue when bg ends + if (GetInvitedCount(HORDE) || GetInvitedCount(ALLIANCE)) + sBattleGroundMgr.ScheduleQueueUpdate(BattleGroundMgr::BgQueueTypeId(GetTypeID()), GetTypeID(), GetBracketId()); } uint32 BattleGround::GetBonusHonorFromKill(uint32 kills) const diff --git a/src/game/Battlegrounds/BattleGroundMgr.cpp b/src/game/Battlegrounds/BattleGroundMgr.cpp index f354b533bfe..dbc063412b7 100644 --- a/src/game/Battlegrounds/BattleGroundMgr.cpp +++ b/src/game/Battlegrounds/BattleGroundMgr.cpp @@ -639,19 +639,53 @@ should be called from BattleGround::RemovePlayer function in some cases void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BattleGroundBracketId bracketId) { //ACE_Guard guard(m_lock); - // First, remove old offline players + + // First, remove players who shouldn't be in queue anymore QueuedPlayersMap::iterator itrOffline = m_queuedPlayers.begin(); while (itrOffline != m_queuedPlayers.end()) { + // remove offline players if (!itrOffline->second.online && WorldTimer::getMSTimeDiffToNow(itrOffline->second.lastOnlineTime) > OFFLINE_BG_QUEUE_TIME) { RemovePlayer(itrOffline->first, true); itrOffline = m_queuedPlayers.begin(); + continue; } - else - ++itrOffline; + + // remove players who are in queue for bg that has ended + GroupQueueInfo* group = itrOffline->second.groupInfo; + if (group->isInvitedToBgInstanceGuid) + { + BattleGround* bg; + if ((bg = sBattleGroundMgr.GetBattleGround(group->isInvitedToBgInstanceGuid, group->bgTypeId)) && bg->GetStatus() == STATUS_WAIT_LEAVE) + { + if (itrOffline->second.online) + { + if (Player* player = ObjectAccessor::FindPlayerNotInWorld(itrOffline->first)) + { + BattleGroundQueueTypeId queueTypeId = BattleGroundMgr::BgQueueTypeId(group->bgTypeId); + uint32 queueSlot = player->GetBattleGroundQueueIndex(queueTypeId); + if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) + { + player->RemoveBattleGroundQueueId(queueTypeId); + + WorldPacket data; + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0); + player->GetSession()->SendPacket(&data); + } + } + } + + RemovePlayer(itrOffline->first, true); + itrOffline = m_queuedPlayers.begin(); + continue; + } + } + + ++itrOffline; } - //if no players in queue - do nothing + + // if no players in queue - do nothing if (m_queuedGroups[bracketId][BG_QUEUE_PREMADE_ALLIANCE].empty() && m_queuedGroups[bracketId][BG_QUEUE_PREMADE_HORDE].empty() && m_queuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE].empty() && @@ -669,7 +703,7 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BattleGroundBracketI std::default_random_engine(seed)); } - //battleground with free slot for player should be always in the beginning of the queue + // battleground with free slot for player should be always in the beginning of the queue // maybe it would be better to create bgfreeslotqueue for each bracketId BgFreeSlotQueueType::iterator itr, next; for (itr = sBattleGroundMgr.m_bgFreeSlotQueue[bgTypeId].begin(); itr != sBattleGroundMgr.m_bgFreeSlotQueue[bgTypeId].end(); itr = next) diff --git a/src/game/Chat/Chat.cpp b/src/game/Chat/Chat.cpp index ca81842ebf6..ef877da97d1 100644 --- a/src/game/Chat/Chat.cpp +++ b/src/game/Chat/Chat.cpp @@ -519,6 +519,7 @@ ChatCommand * ChatHandler::getCommandTable() { "item", SEC_TICKETMASTER, true, &ChatHandler::HandleListItemCommand, "", nullptr }, { "object", SEC_TICKETMASTER, true, &ChatHandler::HandleListObjectCommand, "", nullptr }, { "talents", SEC_TICKETMASTER, false, &ChatHandler::HandleListTalentsCommand, "", nullptr }, + { "maps", SEC_TICKETMASTER, true, &ChatHandler::HandleListMapsCommand, "", nullptr }, { "movegens", SEC_TICKETMASTER, false, &ChatHandler::HandleListMoveGensCommand, "", nullptr }, { "hostilerefs", SEC_TICKETMASTER, false, &ChatHandler::HandleListHostileRefsCommand, "", nullptr }, { "threat", SEC_TICKETMASTER, false, &ChatHandler::HandleListThreatCommand, "", nullptr }, diff --git a/src/game/Chat/Chat.h b/src/game/Chat/Chat.h index f163ff79b2b..075f2867617 100644 --- a/src/game/Chat/Chat.h +++ b/src/game/Chat/Chat.h @@ -607,6 +607,7 @@ class ChatHandler bool HandleListItemCommand(char* args); bool HandleListObjectCommand(char* args); bool HandleListTalentsCommand(char* args); + bool HandleListMapsCommand(char* args); bool HandleListMoveGensCommand(char* args); bool HandleListHostileRefsCommand(char* args); bool HandleListThreatCommand(char* args); diff --git a/src/game/Commands/ServerCommands.cpp b/src/game/Commands/ServerCommands.cpp index 1402a2e8ae5..9f5b51ef404 100644 --- a/src/game/Commands/ServerCommands.cpp +++ b/src/game/Commands/ServerCommands.cpp @@ -2027,3 +2027,12 @@ bool ChatHandler::HandleWarEffortSetStageCommand(char* args) return true; } + +bool ChatHandler::HandleListMapsCommand(char* /*args*/) +{ + SendSysMessage("Listing all currently created maps:"); + for (auto const& itr : sMapMgr.Maps()) + PSendSysMessage("%u-%u - %s - Players %u - Created %s ago", itr.first.nMapId, itr.first.nInstanceId, playerLink(itr.second->GetMapName()).c_str(), itr.second->GetPlayersCountExceptGMs(), secsToTimeString(time(nullptr) - itr.second->GetCreateTime(), true).c_str()); + + return true; +} diff --git a/src/game/Handlers/BattleGroundHandler.cpp b/src/game/Handlers/BattleGroundHandler.cpp index f5976c8f04b..0f39501bdd4 100644 --- a/src/game/Handlers/BattleGroundHandler.cpp +++ b/src/game/Handlers/BattleGroundHandler.cpp @@ -428,6 +428,7 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket& recv_data) // 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.Out(LOG_BASIC, LOG_LVL_DEBUG, "BattlegroundHandler: bgTemplate not found for type id %u.", bgTypeId); @@ -447,6 +448,7 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket& recv_data) action = 0; sLog.Out(LOG_BASIC, LOG_LVL_DEBUG, "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()) { @@ -454,7 +456,16 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket& recv_data) _player->GetName(), _player->GetGUIDLow(), _player->GetLevel(), bg->GetMaxLevel(), bg->GetTypeID()); action = 0; } + + // do not allow entering bg which is already over + if (bg->GetStatus() == STATUS_WAIT_LEAVE) + { + sLog.Out(LOG_BASIC, LOG_LVL_ERROR, "Battleground: Player %s (%u) is attempting to enter battleground (%u) which has already ended!", + _player->GetName(), _player->GetGUIDLow(), bg->GetTypeID()); + action = 0; + } } + uint32 queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId); WorldPacket data; switch (action) diff --git a/src/game/Maps/Map.cpp b/src/game/Maps/Map.cpp index 070491ba4be..5168b7d3e9e 100644 --- a/src/game/Maps/Map.cpp +++ b/src/game/Maps/Map.cpp @@ -124,7 +124,7 @@ Map::Map(uint32 id, time_t expiry, uint32 InstanceId) i_id(id), i_InstanceId(InstanceId), m_unloadTimer(0), m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE), m_persistentState(nullptr), m_activeNonPlayersIter(m_activeNonPlayers.end()), m_transportsUpdateIter(m_transports.end()), - i_gridExpiry(expiry), m_TerrainData(sTerrainMgr.LoadTerrain(id)), + m_createTime(time(nullptr)), i_gridExpiry(expiry), m_TerrainData(sTerrainMgr.LoadTerrain(id)), i_data(nullptr), i_script_id(0), m_unloading(false), m_crashed(false), _processingSendObjUpdates(false), _processingUnitsRelocation(false), m_updateFinished(false), m_updateDiffMod(0), m_GridActivationDistance(DEFAULT_VISIBILITY_DISTANCE), @@ -2411,6 +2411,8 @@ DungeonPersistentState* DungeonMap::GetPersistanceState() const /* ******* Battleground Instance Maps ******* */ +static uint32 s_bgCount = 0; + BattleGroundMap::BattleGroundMap(uint32 id, time_t expiry, uint32 InstanceId) : Map(id, expiry, InstanceId), m_bg(nullptr) { @@ -2427,6 +2429,7 @@ void BattleGroundMap::Update(uint32 diff) { if (!GetBG()) return; + Map::Update(diff); GetBG()->Update(diff); diff --git a/src/game/Maps/Map.h b/src/game/Maps/Map.h index 28e57209cf5..731618713e8 100644 --- a/src/game/Maps/Map.h +++ b/src/game/Maps/Map.h @@ -403,6 +403,7 @@ class Map : public GridRefManager } time_t GetGridExpiry(void) const { return i_gridExpiry; } + time_t GetCreateTime() const { return m_createTime; } uint32 GetId(void) const { return i_id; } // some calls like isInWater should not use vmaps due to processor power @@ -701,6 +702,7 @@ class Map : public GridRefManager TimePoint m_currentTime; uint32 m_lastMvtSpellsUpdate = 0; private: + time_t m_createTime; // time when map was created time_t i_gridExpiry; NGridType* i_grids[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS];