From 611abc5b57ab7480bb01cafec2e448819ab07b21 Mon Sep 17 00:00:00 2001 From: cyberium Date: Tue, 27 Jun 2017 17:06:05 +0200 Subject: [PATCH] Fix oflline check while reseting instance lastMap was never initialized when group was loaded from db. Now send correct error message if one member of the group is offline or trying to teleport the the instance. --- src/game/Entities/Player.cpp | 3 +++ src/game/Globals/ObjectMgr.cpp | 19 ++++++++++++++ src/game/Globals/ObjectMgr.h | 1 + src/game/Groups/Group.cpp | 48 +++++++++++++++++++++++++++++----- 4 files changed, 64 insertions(+), 7 deletions(-) diff --git a/src/game/Entities/Player.cpp b/src/game/Entities/Player.cpp index 61459d79d4b..41672c14b4e 100644 --- a/src/game/Entities/Player.cpp +++ b/src/game/Entities/Player.cpp @@ -18174,6 +18174,9 @@ void Player::SendResetInstanceSuccess(uint32 MapId) const void Player::SendResetInstanceFailed(uint32 reason, uint32 MapId) const { // TODO: find what other fail reasons there are besides players in the instance + // 0 - at least one player is in the instance + // 1 - at least one player is offline + // 2 - at least one player try to enter the instance (being teleported in) WorldPacket data(SMSG_INSTANCE_RESET_FAILED, 4); data << uint32(reason); data << uint32(MapId); diff --git a/src/game/Globals/ObjectMgr.cpp b/src/game/Globals/ObjectMgr.cpp index 0b32f9a9f91..b71aa59c2e4 100644 --- a/src/game/Globals/ObjectMgr.cpp +++ b/src/game/Globals/ObjectMgr.cpp @@ -1759,6 +1759,25 @@ void ObjectMgr::RemoveGameobjectFromGrid(uint32 guid, GameObjectData const* data } } +// Get player map id of offline player. Return -1 if not found! +int32 ObjectMgr::GetPlayerMapIdByGUID(ObjectGuid const& guid) const +{ + // prevent DB access for online player + if (Player* player = GetPlayer(guid)) + return int32(player->GetMapId()); + + QueryResult* result = CharacterDatabase.PQuery("SELECT map FROM characters WHERE guid = '%u'", guid.GetCounter()); + + if (result) + { + uint32 mapId = (*result)[0].GetUInt32(); + delete result; + return int32(mapId); + } + + return -1; +} + // name must be checked to correctness (if received) before call this function ObjectGuid ObjectMgr::GetPlayerGuidByName(std::string name) const { diff --git a/src/game/Globals/ObjectMgr.h b/src/game/Globals/ObjectMgr.h index faa5a0a19c9..4e5095f4dc0 100644 --- a/src/game/Globals/ObjectMgr.h +++ b/src/game/Globals/ObjectMgr.h @@ -553,6 +553,7 @@ class ObjectMgr void GetPlayerLevelInfo(uint32 race, uint32 class_, uint32 level, PlayerLevelInfo* info) const; ObjectGuid GetPlayerGuidByName(std::string name) const; + int32 GetPlayerMapIdByGUID(ObjectGuid const& guid) const; bool GetPlayerNameByGUID(ObjectGuid guid, std::string& name) const; Team GetPlayerTeamByGUID(ObjectGuid guid) const; uint32 GetPlayerAccountIdByGUID(ObjectGuid guid) const; diff --git a/src/game/Groups/Group.cpp b/src/game/Groups/Group.cpp index 5056be38ead..9a7d9e9833a 100644 --- a/src/game/Groups/Group.cpp +++ b/src/game/Groups/Group.cpp @@ -198,6 +198,15 @@ bool Group::LoadMemberFromDB(uint32 guidLow, uint8 subgroup, bool assistant) member.group = subgroup; member.assistant = assistant; + + int32 lastMap = sObjectMgr.GetPlayerMapIdByGUID(member.guid); + if (lastMap < 0) + { + sLog.outError("Group::LoadMemberFromDB> MapId is not found for %s.", member.guid.GetString().c_str()); + return false; + } + member.lastMap = uint32(lastMap); + m_memberSlots.push_back(member); SubGroupCounterIncrease(subgroup); @@ -1211,16 +1220,27 @@ void Group::ResetInstances(InstanceResetMethod method, bool isRaid, Player* Send // we assume that when the difficulty changes, all instances that can be reset will be Difficulty diff = GetDifficulty(isRaid); - typedef std::set OfflineMapSet; - OfflineMapSet mapsWithOfflinePlayer; // to store map of offline players + typedef std::set Uint32Set; + Uint32Set mapsWithOfflinePlayer; // to store map of offline players + Uint32Set mapsWithBeingTeleportedPlayer; // to store map of offline players if (method != INSTANCE_RESET_GROUP_DISBAND) { // Store maps in which are offline members for instance reset check. for (member_citerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr) { - if (!ObjectAccessor::FindPlayer(itr->guid)) - mapsWithOfflinePlayer.insert(itr->lastMap); // add last map from offline player + Player* plr = ObjectAccessor::FindPlayer(itr->guid); + if (!plr) + { + // add last map from offline player + mapsWithOfflinePlayer.insert(itr->lastMap); + } + else + { + // add teleport destination map + if (plr->IsBeingTeleported()) + mapsWithBeingTeleportedPlayer.insert(plr->GetTeleportDest().mapid); + } } } @@ -1244,13 +1264,27 @@ void Group::ResetInstances(InstanceResetMethod method, bool isRaid, Player* Send } } - bool isEmpty = true; // check if there are offline members on the map if (method != INSTANCE_RESET_GROUP_DISBAND && mapsWithOfflinePlayer.find(state->GetMapId()) != mapsWithOfflinePlayer.end()) - isEmpty = false; + { + if (SendMsgTo) + SendMsgTo->SendResetInstanceFailed(1, state->GetMapId()); + ++itr; + continue; + } + + // check if there are teleporting members to the map + if (method != INSTANCE_RESET_GROUP_DISBAND && mapsWithBeingTeleportedPlayer.find(state->GetMapId()) != mapsWithBeingTeleportedPlayer.end()) + { + if (SendMsgTo) + SendMsgTo->SendResetInstanceFailed(2, state->GetMapId()); + ++itr; + continue; + } + bool isEmpty = true; // if the map is loaded, reset it if can - if (isEmpty && entry->IsDungeon() && !(method == INSTANCE_RESET_GROUP_DISBAND && !state->CanReset())) + if (entry->IsDungeon() && !(method == INSTANCE_RESET_GROUP_DISBAND && !state->CanReset())) if (Map* map = sMapMgr.FindMap(state->GetMapId(), state->GetInstanceId())) isEmpty = ((DungeonMap*)map)->Reset(method);