[11137] Fixed crash at reset normal dungeon while map loaded.

* Map Persistent noe have direct pointer back to map if map loaded.
  That let simplify some code and avoid map search.
* Crash showup in result changes in code logic related to reset processing.
* Also fix more old bug with reset normal dungeon with not loaded map.
* Reverse MapPersistentState::HasRespawnTimes and MapPersistentState::HasBounds() results
  to expected for function names and update related calls.

Thanks to Schmoozerd for help in research problem.
This commit is contained in:
VladimirMangos 2011-02-12 03:14:50 +03:00
parent 5858aae4d9
commit 47060fe4b1
5 changed files with 30 additions and 23 deletions

View file

@ -47,7 +47,7 @@ Map::~Map()
sWorld.DecreaseScheduledScriptCount(m_scriptSchedule.size()); sWorld.DecreaseScheduledScriptCount(m_scriptSchedule.size());
if (m_persistentState) if (m_persistentState)
m_persistentState->SetUsedByMapState(false); // field pointer can be deleted after this m_persistentState->SetUsedByMapState(NULL); // field pointer can be deleted after this
if(i_data) if(i_data)
{ {
@ -96,7 +96,7 @@ Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode)
m_TerrainData->AddRef(); m_TerrainData->AddRef();
m_persistentState = sMapPersistentStateMgr.AddPersistentState(i_mapEntry, GetInstanceId(), GetDifficulty(), 0, IsDungeon()); m_persistentState = sMapPersistentStateMgr.AddPersistentState(i_mapEntry, GetInstanceId(), GetDifficulty(), 0, IsDungeon());
m_persistentState->SetUsedByMapState(true); m_persistentState->SetUsedByMapState(this);
} }
void Map::InitVisibilityDistance() void Map::InitVisibilityDistance()

View file

@ -43,7 +43,7 @@ static uint32 resetEventTypeDelay[MAX_RESET_EVENT_TYPE] = { 0, 3600, 900, 300, 6
MapPersistentState::MapPersistentState(uint16 MapId, uint32 InstanceId, Difficulty difficulty) MapPersistentState::MapPersistentState(uint16 MapId, uint32 InstanceId, Difficulty difficulty)
: m_instanceid(InstanceId), m_mapid(MapId), : m_instanceid(InstanceId), m_mapid(MapId),
m_difficulty(difficulty), m_usedByMap(false) m_difficulty(difficulty), m_usedByMap(NULL)
{ {
} }
@ -134,7 +134,7 @@ bool WorldPersistentState::CanBeUnload() const
{ {
// prevent unload if used for loaded map // prevent unload if used for loaded map
// prevent unload if respawn data still exist (will not prevent reset by scheduler) // prevent unload if respawn data still exist (will not prevent reset by scheduler)
return MapPersistentState::CanBeUnload() && HasRespawnTimes(); return MapPersistentState::CanBeUnload() && !HasRespawnTimes();
} }
//== DungeonPersistentState functions ===================== //== DungeonPersistentState functions =====================
@ -161,7 +161,7 @@ DungeonPersistentState::~DungeonPersistentState()
bool DungeonPersistentState::CanBeUnload() const bool DungeonPersistentState::CanBeUnload() const
{ {
// prevent unload if any bounded groups or online bounded player still exists // prevent unload if any bounded groups or online bounded player still exists
return MapPersistentState::CanBeUnload() && HasBounds() && HasRespawnTimes(); return MapPersistentState::CanBeUnload() && !HasBounds() && !HasRespawnTimes();
} }
/* /*
@ -172,7 +172,7 @@ void DungeonPersistentState::SaveToDB()
// state instance data too // state instance data too
std::string data; std::string data;
if (Map *map = sMapMgr.FindMap(GetMapId(), GetInstanceId())) if (Map *map = GetMap())
{ {
InstanceData *iData = map->GetInstanceData(); InstanceData *iData = map->GetInstanceData();
if(iData && iData->Save()) if(iData && iData->Save())
@ -192,7 +192,7 @@ void DungeonPersistentState::DeleteRespawnTimes()
CharacterDatabase.PExecute("DELETE FROM gameobject_respawn WHERE instance = '%u'", GetInstanceId()); CharacterDatabase.PExecute("DELETE FROM gameobject_respawn WHERE instance = '%u'", GetInstanceId());
CharacterDatabase.CommitTransaction(); CharacterDatabase.CommitTransaction();
ClearRespawnTimes(); ClearRespawnTimes(); // state can be deleted at call if only respawn data prevent unload
} }
void DungeonPersistentState::DeleteFromDB() void DungeonPersistentState::DeleteFromDB()
@ -711,19 +711,25 @@ void MapPersistentStateManager::_ResetSave(PersistentStateMap& holder, Persisten
void MapPersistentStateManager::_ResetInstance(uint32 mapid, uint32 instanceId) void MapPersistentStateManager::_ResetInstance(uint32 mapid, uint32 instanceId)
{ {
DEBUG_LOG("InstanceSaveMgr::_ResetInstance %u, %u", mapid, instanceId); DEBUG_LOG("MapPersistentStateManager::_ResetInstance %u, %u", mapid, instanceId);
Map * iMap = sMapMgr.FindMap(mapid, instanceId);
if (!iMap || !iMap->Instanceable())
return;
PersistentStateMap::iterator itr = m_instanceSaveByInstanceId.find(instanceId); PersistentStateMap::iterator itr = m_instanceSaveByInstanceId.find(instanceId);
if (itr != m_instanceSaveByInstanceId.end()) if (itr != m_instanceSaveByInstanceId.end())
{
// delay reset until map unload for loaded map
if (Map * iMap = itr->second->GetMap())
{
MANGOS_ASSERT(iMap->IsDungeon());
((DungeonMap*)iMap)->Reset(INSTANCE_RESET_RESPAWN_DELAY);
return;
}
_ResetSave(m_instanceSaveByInstanceId, itr); _ResetSave(m_instanceSaveByInstanceId, itr);
}
DeleteInstanceFromDB(instanceId); // even if state not loaded DeleteInstanceFromDB(instanceId); // even if state not loaded
if (iMap->IsDungeon())
((DungeonMap*)iMap)->Reset(INSTANCE_RESET_RESPAWN_DELAY);
} }
void MapPersistentStateManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, bool warn, uint32 timeLeft) void MapPersistentStateManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, bool warn, uint32 timeLeft)

View file

@ -65,10 +65,11 @@ class MapPersistentState
Difficulty GetDifficulty() const { return m_difficulty; } Difficulty GetDifficulty() const { return m_difficulty; }
bool IsUsedByMap() const { return m_usedByMap; } bool IsUsedByMap() const { return m_usedByMap; }
void SetUsedByMapState(bool state) Map* GetMap() const { return m_usedByMap; } // Can be NULL if map not loaded for persistent state
void SetUsedByMapState(Map* map)
{ {
m_usedByMap = state; m_usedByMap = map;
if (!state) if (!map)
UnloadIfEmpty(); UnloadIfEmpty();
} }
@ -90,7 +91,7 @@ class MapPersistentState
bool UnloadIfEmpty(); bool UnloadIfEmpty();
void ClearRespawnTimes(); void ClearRespawnTimes();
bool HasRespawnTimes() const { return m_creatureRespawnTimes.empty() && m_goRespawnTimes.empty(); } bool HasRespawnTimes() const { return !m_creatureRespawnTimes.empty() || !m_goRespawnTimes.empty(); }
private: private:
void SetCreatureRespawnTime(uint32 loguid, time_t t); void SetCreatureRespawnTime(uint32 loguid, time_t t);
@ -102,7 +103,7 @@ class MapPersistentState
uint32 m_instanceid; uint32 m_instanceid;
uint32 m_mapid; uint32 m_mapid;
Difficulty m_difficulty; Difficulty m_difficulty;
bool m_usedByMap; // true when instance map loaded, lock MapPersistentState from unload Map* m_usedByMap; // NULL if map not loaded, non-NULL lock MapPersistentState from unload
// persistent data // persistent data
RespawnTimes m_creatureRespawnTimes; // lock MapPersistentState from unload, for example for temporary bound dungeon unload delay RespawnTimes m_creatureRespawnTimes; // lock MapPersistentState from unload, for example for temporary bound dungeon unload delay
@ -184,7 +185,7 @@ class DungeonPersistentState : public MapPersistentState
protected: protected:
bool CanBeUnload() const; // overwrite MapPersistentState::CanBeUnload bool CanBeUnload() const; // overwrite MapPersistentState::CanBeUnload
bool HasBounds() const { return m_playerList.empty() && m_groupList.empty(); } bool HasBounds() const { return !m_playerList.empty() || !m_groupList.empty(); }
private: private:
typedef std::list<Player*> PlayerListType; typedef std::list<Player*> PlayerListType;
@ -315,7 +316,7 @@ class MANGOS_DLL_DECL MapPersistentStateManager : public MaNGOS::Singleton<MapPe
private: private:
typedef UNORDERED_MAP<uint32 /*InstanceId or MapId*/, MapPersistentState*> PersistentStateMap; typedef UNORDERED_MAP<uint32 /*InstanceId or MapId*/, MapPersistentState*> PersistentStateMap;
// called by scheduler // called by scheduler for DungeonPersistentStates
void _ResetOrWarnAll(uint32 mapid, Difficulty difficulty, bool warn, uint32 timeleft); void _ResetOrWarnAll(uint32 mapid, Difficulty difficulty, bool warn, uint32 timeleft);
void _ResetInstance(uint32 mapid, uint32 instanceId); void _ResetInstance(uint32 mapid, uint32 instanceId);
void _CleanupExpiredInstancesAtTime(time_t t); void _CleanupExpiredInstancesAtTime(time_t t);

View file

@ -2496,7 +2496,7 @@ enum InstanceResetMethod
INSTANCE_RESET_GLOBAL, INSTANCE_RESET_GLOBAL,
INSTANCE_RESET_GROUP_DISBAND, INSTANCE_RESET_GROUP_DISBAND,
INSTANCE_RESET_GROUP_JOIN, INSTANCE_RESET_GROUP_JOIN,
INSTANCE_RESET_RESPAWN_DELAY INSTANCE_RESET_RESPAWN_DELAY // called from reset scheduler for request reset at map unload when map loaded at reset attempt for normal dungeon difficulty
}; };
// byte value (UNIT_FIELD_BYTES_2,3) // byte value (UNIT_FIELD_BYTES_2,3)

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__ #ifndef __REVISION_NR_H__
#define __REVISION_NR_H__ #define __REVISION_NR_H__
#define REVISION_NR "11136" #define REVISION_NR "11137"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__