Skip to content

Commit

Permalink
Fix oflline check while reseting instance
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
cyberium committed Jun 29, 2017
1 parent cc85e04 commit 611abc5
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 7 deletions.
3 changes: 3 additions & 0 deletions src/game/Entities/Player.cpp
Expand Up @@ -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);
Expand Down
19 changes: 19 additions & 0 deletions src/game/Globals/ObjectMgr.cpp
Expand Up @@ -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
{
Expand Down
1 change: 1 addition & 0 deletions src/game/Globals/ObjectMgr.h
Expand Up @@ -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;
Expand Down
48 changes: 41 additions & 7 deletions src/game/Groups/Group.cpp
Expand Up @@ -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);
Expand Down Expand Up @@ -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<uint32> OfflineMapSet;
OfflineMapSet mapsWithOfflinePlayer; // to store map of offline players
typedef std::set<uint32> 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);
}
}
}

Expand All @@ -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);

Expand Down

0 comments on commit 611abc5

Please sign in to comment.