From 67a789207517a18a70fd7ce10d0591773054d0d1 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Sun, 27 Jun 2010 21:01:29 +0400 Subject: [PATCH] [10114] Store associated InstanceSave for dungeon map in Map object --- src/game/Group.cpp | 4 +- src/game/InstanceSaveMgr.cpp | 4 +- src/game/InstanceSaveMgr.h | 21 +++++-- src/game/Level1.cpp | 2 +- src/game/Map.cpp | 104 +++++++++++++++++++---------------- src/game/Map.h | 3 + src/game/Player.cpp | 6 +- src/game/Unit.cpp | 5 +- src/shared/revision_nr.h | 2 +- 9 files changed, 89 insertions(+), 62 deletions(-) diff --git a/src/game/Group.cpp b/src/game/Group.cpp index e6db94f59..3f5a06aea 100644 --- a/src/game/Group.cpp +++ b/src/game/Group.cpp @@ -1736,8 +1736,8 @@ void Group::_homebindIfInstance(Player *player) { // leaving the group in an instance, the homebind timer is started // unless the player is permanently saved to the instance - InstanceSave *save = sInstanceSaveMgr.GetInstanceSave(player->GetInstanceId()); - InstancePlayerBind *playerBind = save ? player->GetBoundInstance(save->GetMapId(), save->GetDifficulty()) : NULL; + Map* map = player->GetMap(); + InstancePlayerBind *playerBind = map->IsDungeon() ? player->GetBoundInstance(map->GetId(), map->GetDifficulty()) : NULL; if(!playerBind || !playerBind->perm) player->m_InstanceValid = false; } diff --git a/src/game/InstanceSaveMgr.cpp b/src/game/InstanceSaveMgr.cpp index dc5bf2a02..a1959cf74 100644 --- a/src/game/InstanceSaveMgr.cpp +++ b/src/game/InstanceSaveMgr.cpp @@ -43,7 +43,7 @@ INSTANTIATE_SINGLETON_1( InstanceSaveManager ); InstanceSave::InstanceSave(uint16 MapId, uint32 InstanceId, Difficulty difficulty, time_t resetTime, bool canReset) : m_resetTime(resetTime), m_instanceid(InstanceId), m_mapid(MapId), - m_difficulty(difficulty), m_canReset(canReset) + m_difficulty(difficulty), m_canReset(canReset), m_usedByMap(false) { } @@ -113,7 +113,7 @@ void InstanceSave::DeleteFromDB() /* true if the instance save is still valid */ bool InstanceSave::UnloadIfEmpty() { - if(m_playerList.empty() && m_groupList.empty()) + if (m_playerList.empty() && m_groupList.empty() && !m_usedByMap) { sInstanceSaveMgr.RemoveInstanceSave(GetInstanceId()); return false; diff --git a/src/game/InstanceSaveMgr.h b/src/game/InstanceSaveMgr.h index 8af5610df..5114acaa2 100644 --- a/src/game/InstanceSaveMgr.h +++ b/src/game/InstanceSaveMgr.h @@ -95,9 +95,17 @@ class InstanceSave but that would depend on a lot of things that can easily change in future */ Difficulty GetDifficulty() { return m_difficulty; } + void SetUsedByMapState(bool state) + { + m_usedByMap = state; + if (!state) + UnloadIfEmpty(); + } + + private: typedef std::list PlayerListType; typedef std::list GroupListType; - private: + bool UnloadIfEmpty(); /* the only reason the instSave-object links are kept is because the object-instSave links need to be broken at reset time @@ -109,6 +117,7 @@ class InstanceSave uint32 m_mapid; Difficulty m_difficulty; bool m_canReset; + bool m_usedByMap; // true when instance map loaded }; /* resetTime is a global propery of each (raid/heroic) map @@ -170,9 +179,6 @@ class MANGOS_DLL_DECL InstanceSaveManager : public MaNGOS::Singleton InstanceSaveHashMap; - typedef UNORDERED_MAP InstanceSaveMapMap; - void CleanupInstances(); void PackInstances(); @@ -182,8 +188,6 @@ class MANGOS_DLL_DECL InstanceSaveManager : public MaNGOS::Singleton InstanceSaveHashMap; + typedef UNORDERED_MAP InstanceSaveMapMap; + + InstanceSave *GetInstanceSave(uint32 InstanceId); + // called by scheduler void _ResetOrWarnAll(uint32 mapid, Difficulty difficulty, bool warn, uint32 timeleft); void _ResetInstance(uint32 mapid, uint32 instanceId); diff --git a/src/game/Level1.cpp b/src/game/Level1.cpp index 12a561480..57a64dda6 100644 --- a/src/game/Level1.cpp +++ b/src/game/Level1.cpp @@ -552,7 +552,7 @@ bool ChatHandler::HandleGonameCommand(const char* args) InstanceGroupBind *gBind = group ? group->GetBoundInstance(target) : NULL; // if no bind exists, create a solo bind if (!gBind) - if (InstanceSave *save = sInstanceSaveMgr.GetInstanceSave(target->GetInstanceId())) + if (InstanceSave *save = target->GetMap()->GetInstanceSave()) _player->BindToInstance(save, !save->CanReset()); } diff --git a/src/game/Map.cpp b/src/game/Map.cpp index af4a58e4a..cf55e9875 100644 --- a/src/game/Map.cpp +++ b/src/game/Map.cpp @@ -54,6 +54,9 @@ Map::~Map() if(!m_scriptSchedule.empty()) sWorld.DecreaseScheduledScriptCount(m_scriptSchedule.size()); + + if (m_instanceSave) + m_instanceSave->SetUsedByMapState(false); // field pointer can be deleted after this } void Map::LoadVMap(int gx,int gy) @@ -126,7 +129,7 @@ void Map::LoadMapAndVMap(int gx,int gy) Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent) : i_mapEntry (sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode), i_id(id), i_InstanceId(InstanceId), m_unloadTimer(0), - m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE), + m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE), m_instanceSave(NULL), m_activeNonPlayersIter(m_activeNonPlayers.end()), i_gridExpiry(expiry), m_parentMap(_parent ? _parent : this) { @@ -1723,6 +1726,13 @@ InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 Spaw // the timer is started by default, and stopped when the first player joins // this make sure it gets unloaded if for some reason no player joins m_unloadTimer = std::max(sWorld.getConfig(CONFIG_UINT32_INSTANCE_UNLOAD_DELAY), (uint32)MIN_UNLOAD_DELAY); + + // Dungeon only code + if(IsDungeon()) + { + m_instanceSave = sInstanceSaveMgr.AddInstanceSave(GetId(), GetInstanceId(), Difficulty(GetSpawnMode()), 0, true); + m_instanceSave->SetUsedByMapState(true); + } } InstanceMap::~InstanceMap() @@ -1783,58 +1793,73 @@ bool InstanceMap::Add(Player *player) { Guard guard(*this); - if(!CanEnter(player)) + if (!CanEnter(player)) return false; // Dungeon only code - if(IsDungeon()) + if (IsDungeon()) { - // get or create an instance save for the map - InstanceSave *mapSave = sInstanceSaveMgr.GetInstanceSave(GetInstanceId()); - if(!mapSave) - { - DETAIL_LOG("InstanceMap::Add: creating instance save for map %d spawnmode %d with instance id %d", GetId(), GetSpawnMode(), GetInstanceId()); - mapSave = sInstanceSaveMgr.AddInstanceSave(GetId(), GetInstanceId(), Difficulty(GetSpawnMode()), 0, true); - } - // check for existing instance binds InstancePlayerBind *playerBind = player->GetBoundInstance(GetId(), Difficulty(GetSpawnMode())); - if(playerBind && playerBind->perm) + if (playerBind && playerBind->perm) { // cannot enter other instances if bound permanently - if(playerBind->save != mapSave) + if (playerBind->save != GetInstanceSave()) { - sLog.outError("InstanceMap::Add: player %s(%d) is permanently bound to instance %d,%d,%d,%d,%d,%d but he is being put in instance %d,%d,%d,%d,%d,%d", player->GetName(), player->GetGUIDLow(), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), playerBind->save->GetDifficulty(), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset()); + sLog.outError("InstanceMap::Add: player %s(%d) is permanently bound to instance %d,%d,%d,%d,%d,%d but he is being put in instance %d,%d,%d,%d,%d,%d", + player->GetName(), player->GetGUIDLow(), playerBind->save->GetMapId(), + playerBind->save->GetInstanceId(), playerBind->save->GetDifficulty(), + playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), + playerBind->save->CanReset(), + GetInstanceSave()->GetMapId(), GetInstanceSave()->GetInstanceId(), + GetInstanceSave()->GetDifficulty(), GetInstanceSave()->GetPlayerCount(), + GetInstanceSave()->GetGroupCount(), GetInstanceSave()->CanReset()); ASSERT(false); } } else { Group *pGroup = player->GetGroup(); - if(pGroup) + if (pGroup) { // solo saves should be reset when entering a group InstanceGroupBind *groupBind = pGroup->GetBoundInstance(this,GetDifficulty()); - if(playerBind) + if (playerBind) { - sLog.outError("InstanceMap::Add: player %s(%d) is being put in instance %d,%d,%d,%d,%d,%d but he is in group %d and is bound to instance %d,%d,%d,%d,%d,%d!", player->GetName(), player->GetGUIDLow(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset(), GUID_LOPART(pGroup->GetLeaderGUID()), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), playerBind->save->GetDifficulty(), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset()); - if(groupBind) sLog.outError("InstanceMap::Add: the group is bound to instance %d,%d,%d,%d,%d,%d", groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), groupBind->save->GetDifficulty(), groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount(), groupBind->save->CanReset()); + sLog.outError("InstanceMap::Add: player %s(%d) is being put in instance %d,%d,%d,%d,%d,%d but he is in group %d and is bound to instance %d,%d,%d,%d,%d,%d!", + player->GetName(), player->GetGUIDLow(), GetInstanceSave()->GetMapId(), GetInstanceSave()->GetInstanceId(), + GetInstanceSave()->GetDifficulty(), GetInstanceSave()->GetPlayerCount(), GetInstanceSave()->GetGroupCount(), + GetInstanceSave()->CanReset(), GUID_LOPART(pGroup->GetLeaderGUID()), + playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), playerBind->save->GetDifficulty(), + playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset()); + + if (groupBind) + sLog.outError("InstanceMap::Add: the group is bound to instance %d,%d,%d,%d,%d,%d", + groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), groupBind->save->GetDifficulty(), + groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount(), groupBind->save->CanReset()); ASSERT(false); } // bind to the group or keep using the group save - if(!groupBind) - pGroup->BindToInstance(mapSave, false); + if (!groupBind) + pGroup->BindToInstance(GetInstanceSave(), false); else { // cannot jump to a different instance without resetting it - if(groupBind->save != mapSave) + if (groupBind->save != GetInstanceSave()) { - sLog.outError("InstanceMap::Add: player %s(%d) is being put in instance %d,%d,%d but he is in group %d which is bound to instance %d,%d,%d!", player->GetName(), player->GetGUIDLow(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), GUID_LOPART(pGroup->GetLeaderGUID()), groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), groupBind->save->GetDifficulty()); - if(mapSave) - sLog.outError("MapSave players: %d, group count: %d", mapSave->GetPlayerCount(), mapSave->GetGroupCount()); + sLog.outError("InstanceMap::Add: player %s(%d) is being put in instance %d,%d,%d but he is in group %d which is bound to instance %d,%d,%d!", + player->GetName(), player->GetGUIDLow(), GetInstanceSave()->GetMapId(), + GetInstanceSave()->GetInstanceId(), GetInstanceSave()->GetDifficulty(), + GUID_LOPART(pGroup->GetLeaderGUID()), groupBind->save->GetMapId(), + groupBind->save->GetInstanceId(), groupBind->save->GetDifficulty()); + + if (GetInstanceSave()) + sLog.outError("MapSave players: %d, group count: %d", + GetInstanceSave()->GetPlayerCount(), GetInstanceSave()->GetGroupCount()); else sLog.outError("MapSave NULL"); - if(groupBind->save) + + if (groupBind->save) sLog.outError("GroupBind save players: %d, group count: %d", groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount()); else sLog.outError("GroupBind save NULL"); @@ -1842,12 +1867,12 @@ bool InstanceMap::Add(Player *player) } // if the group/leader is permanently bound to the instance // players also become permanently bound when they enter - if(groupBind->perm) + if (groupBind->perm) { WorldPacket data(SMSG_INSTANCE_SAVE_CREATED, 4); data << uint32(0); player->GetSession()->SendPacket(&data); - player->BindToInstance(mapSave, true); + player->BindToInstance(GetInstanceSave(), true); } } } @@ -1855,10 +1880,10 @@ bool InstanceMap::Add(Player *player) { // set up a solo bind or continue using it if(!playerBind) - player->BindToInstance(mapSave, false); + player->BindToInstance(GetInstanceSave(), false); else // cannot jump to a different instance without resetting it - ASSERT(playerBind->save == mapSave); + ASSERT(playerBind->save == GetInstanceSave()); } } } @@ -1993,13 +2018,6 @@ void InstanceMap::PermBindAllPlayers(Player *player) if(!IsDungeon()) return; - InstanceSave *save = sInstanceSaveMgr.GetInstanceSave(GetInstanceId()); - if(!save) - { - sLog.outError("Cannot bind players, no instance save available for map!"); - return; - } - Group *group = player->GetGroup(); // group members outside the instance group don't get bound for(MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) @@ -2007,10 +2025,10 @@ void InstanceMap::PermBindAllPlayers(Player *player) Player* plr = itr->getSource(); // players inside an instance cannot be bound to other instances // some players may already be permanently bound, in this case nothing happens - InstancePlayerBind *bind = plr->GetBoundInstance(save->GetMapId(), save->GetDifficulty()); + InstancePlayerBind *bind = plr->GetBoundInstance(GetId(), GetDifficulty()); if(!bind || !bind->perm) { - plr->BindToInstance(save, true); + plr->BindToInstance(GetInstanceSave(), true); WorldPacket data(SMSG_INSTANCE_SAVE_CREATED, 4); data << uint32(0); plr->GetSession()->SendPacket(&data); @@ -2018,7 +2036,7 @@ void InstanceMap::PermBindAllPlayers(Player *player) // if the leader is not in the instance the group will not get a perm bind if(group && group->GetLeaderGUID() == plr->GetGUID()) - group->BindToInstance(save, true); + group->BindToInstance(GetInstanceSave(), true); } } @@ -2052,13 +2070,7 @@ void InstanceMap::SetResetSchedule(bool on) // the reset time is only scheduled when there are no payers inside // it is assumed that the reset time will rarely (if ever) change while the reset is scheduled if(IsDungeon() && !HavePlayers() && !IsRaidOrHeroicDungeon()) - { - InstanceSave *save = sInstanceSaveMgr.GetInstanceSave(GetInstanceId()); - if (!save) - sLog.outError("InstanceMap::SetResetSchedule: cannot turn schedule %s, no save available for instance %d of %d", on ? "on" : "off", GetInstanceId(), GetId()); - else - sInstanceSaveMgr.GetScheduler().ScheduleReset(on, save->GetResetTime(), InstanceResetEvent(0, GetId(), Difficulty(GetSpawnMode()), GetInstanceId())); - } + sInstanceSaveMgr.GetScheduler().ScheduleReset(on, GetInstanceSave()->GetResetTime(), InstanceResetEvent(0, GetId(), Difficulty(GetSpawnMode()), GetInstanceId())); } /* ******* Battleground Instance Maps ******* */ diff --git a/src/game/Map.h b/src/game/Map.h index 1a2efe97a..3ac49fb60 100644 --- a/src/game/Map.h +++ b/src/game/Map.h @@ -210,6 +210,8 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj bool IsBattleArena() const { return i_mapEntry && i_mapEntry->IsBattleArena(); } bool IsBattleGroundOrArena() const { return i_mapEntry && i_mapEntry->IsBattleGroundOrArena(); } + InstanceSave* GetInstanceSave() const { return m_instanceSave; } + void AddObjectToRemoveList(WorldObject *obj); void UpdateObjectVisibility(WorldObject* obj, Cell cell, CellPair cellpair); @@ -312,6 +314,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj uint32 i_InstanceId; uint32 m_unloadTimer; float m_VisibleDistance; + InstanceSave* m_instanceSave; // can be NULL for non dungeons... MapRefManager m_mapRefManager; MapRefManager::iterator m_mapRefIter; diff --git a/src/game/Player.cpp b/src/game/Player.cpp index e44d34d3d..3ef6d9027 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -15213,12 +15213,14 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) } } - // NOW player must have valid map + // player bounded instance saves loaded in _LoadBoundInstances, group versions at group loading + InstanceSave* instanceSave = GetBoundInstanceSaveForSelfOrGroup(GetMapId()); + // load the player's map here if it's not already loaded SetMap(sMapMgr.CreateMap(GetMapId(), this)); // if the player is in an instance and it has been reset in the meantime teleport him to the entrance - if(GetInstanceId() && !sInstanceSaveMgr.GetInstanceSave(GetInstanceId())) + if(GetInstanceId() && !instanceSave) { AreaTrigger const* at = sObjectMgr.GetMapEntranceTrigger(GetMapId()); if(at) diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index a280dd8d6..77bfa8fc8 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -841,8 +841,9 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa // the reset time is set but not added to the scheduler // until the players leave the instance time_t resettime = cVictim->GetRespawnTimeEx() + 2 * HOUR; - if(InstanceSave *save = sInstanceSaveMgr.GetInstanceSave(cVictim->GetInstanceId())) - if(save->GetResetTime() < resettime) save->SetResetTime(resettime); + if (InstanceSave *save = m->GetInstanceSave()) + if (save->GetResetTime() < resettime) + save->SetResetTime(resettime); } } } diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index b33cab190..ad55c560f 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 "10113" + #define REVISION_NR "10114" #endif // __REVISION_NR_H__