[10094] Extract instance reset scheduler from InstanceSaveMgr

Reset scheduler code not need explicit access to instance saves,
and no reson mix it with instance save managment code in single class
This commit is contained in:
VladimirMangos 2010-06-22 04:35:07 +04:00
parent 79f70e9a81
commit e88a718c5d
5 changed files with 296 additions and 241 deletions

View file

@ -123,9 +123,221 @@ bool InstanceSave::UnloadIfEmpty()
return true;
}
//== InstanceResetScheduler functions ======================
void InstanceResetScheduler::LoadResetTimes()
{
time_t now = time(NULL);
time_t today = (now / DAY) * DAY;
// NOTE: Use DirectPExecute for tables that will be queried later
// get the current reset times for normal instances (these may need to be updated)
// these are only kept in memory for InstanceSaves that are loaded later
// resettime = 0 in the DB for raid/heroic instances so those are skipped
typedef std::pair<uint32 /*PAIR32(map,difficulty)*/, time_t> ResetTimeMapDiffType;
typedef std::map<uint32, ResetTimeMapDiffType> InstResetTimeMapDiffType;
InstResetTimeMapDiffType instResetTime;
// index instance ids by map/difficulty pairs for fast reset warning send
typedef std::multimap<uint32 /*PAIR32(map,difficulty)*/, uint32 /*instanceid*/ > ResetTimeMapDiffInstances;
ResetTimeMapDiffInstances mapDiffResetInstances;
QueryResult *result = CharacterDatabase.Query("SELECT id, map, difficulty, resettime FROM instance WHERE resettime > 0");
if( result )
{
do
{
if(time_t resettime = time_t((*result)[3].GetUInt64()))
{
uint32 id = (*result)[0].GetUInt32();
uint32 mapid = (*result)[1].GetUInt32();
uint32 difficulty = (*result)[2].GetUInt32();
instResetTime[id] = ResetTimeMapDiffType(MAKE_PAIR32(mapid,difficulty), resettime);
mapDiffResetInstances.insert(ResetTimeMapDiffInstances::value_type(MAKE_PAIR32(mapid,difficulty),id));
}
}
while (result->NextRow());
delete result;
// update reset time for normal instances with the max creature respawn time + X hours
result = WorldDatabase.Query("SELECT MAX(respawntime), instance FROM creature_respawn WHERE instance > 0 GROUP BY instance");
if( result )
{
do
{
Field *fields = result->Fetch();
uint32 instance = fields[1].GetUInt32();
time_t resettime = time_t(fields[0].GetUInt64() + 2 * HOUR);
InstResetTimeMapDiffType::iterator itr = instResetTime.find(instance);
if(itr != instResetTime.end() && itr->second.second != resettime)
{
CharacterDatabase.DirectPExecute("UPDATE instance SET resettime = '"UI64FMTD"' WHERE id = '%u'", uint64(resettime), instance);
itr->second.second = resettime;
}
}
while (result->NextRow());
delete result;
}
// schedule the reset times
for(InstResetTimeMapDiffType::iterator itr = instResetTime.begin(); itr != instResetTime.end(); ++itr)
if(itr->second.second > now)
ScheduleReset(true, itr->second.second, InstanceResetEvent(0, PAIR32_LOPART(itr->second.first),Difficulty(PAIR32_HIPART(itr->second.first)),itr->first));
}
// load the global respawn times for raid/heroic instances
uint32 diff = sWorld.getConfig(CONFIG_UINT32_INSTANCE_RESET_TIME_HOUR) * HOUR;
result = CharacterDatabase.Query("SELECT mapid, difficulty, resettime FROM instance_reset");
if(result)
{
do
{
Field *fields = result->Fetch();
uint32 mapid = fields[0].GetUInt32();
Difficulty difficulty = Difficulty(fields[1].GetUInt32());
uint64 oldresettime = fields[2].GetUInt64();
MapDifficulty const* mapDiff = GetMapDifficultyData(mapid,difficulty);
if(!mapDiff)
{
sLog.outError("InstanceSaveManager::LoadResetTimes: invalid mapid(%u)/difficulty(%u) pair in instance_reset!", mapid, difficulty);
CharacterDatabase.DirectPExecute("DELETE FROM instance_reset WHERE mapid = '%u' AND difficulty = '%u'", mapid,difficulty);
continue;
}
// update the reset time if the hour in the configs changes
uint64 newresettime = (oldresettime / DAY) * DAY + diff;
if(oldresettime != newresettime)
CharacterDatabase.DirectPExecute("UPDATE instance_reset SET resettime = '"UI64FMTD"' WHERE mapid = '%u' AND difficulty = '%u'", newresettime, mapid, difficulty);
SetResetTimeFor(mapid,difficulty,newresettime);
} while(result->NextRow());
delete result;
}
// clean expired instances, references to them will be deleted in CleanupInstances
// must be done before calculating new reset times
m_InstanceSaves._CleanupExiredInstancesAtTime(now);
// calculate new global reset times for expired instances and those that have never been reset yet
// add the global reset times to the priority queue
for(MapDifficultyMap::const_iterator itr = sMapDifficultyMap.begin(); itr != sMapDifficultyMap.end(); ++itr)
{
uint32 map_diff_pair = itr->first;
uint32 mapid = PAIR32_LOPART(map_diff_pair);
Difficulty difficulty = Difficulty(PAIR32_HIPART(map_diff_pair));
MapDifficulty const* mapDiff = &itr->second;
if (!mapDiff->resetTime)
continue;
// the reset_delay must be at least one day
uint32 period = uint32(mapDiff->resetTime / DAY * sWorld.getConfig(CONFIG_FLOAT_RATE_INSTANCE_RESET_TIME)) * DAY;
if (period < DAY)
period = DAY;
time_t t = GetResetTimeFor(mapid,difficulty);
if(!t)
{
// initialize the reset time
t = today + period + diff;
CharacterDatabase.DirectPExecute("INSERT INTO instance_reset VALUES ('%u','%u','"UI64FMTD"')", mapid, difficulty, (uint64)t);
}
if(t < now)
{
// assume that expired instances have already been cleaned
// calculate the next reset time
t = (t / DAY) * DAY;
t += ((today - t) / period + 1) * period + diff;
CharacterDatabase.DirectPExecute("UPDATE instance_reset SET resettime = '"UI64FMTD"' WHERE mapid = '%u' AND difficulty= '%u'", (uint64)t, mapid, difficulty);
}
SetResetTimeFor(mapid,difficulty,t);
// schedule the global reset/warning
uint8 type = 1;
static int tim[4] = {3600, 900, 300, 60};
for(; type < 4; type++)
if(t - tim[type-1] > now)
break;
for(ResetTimeMapDiffInstances::const_iterator in_itr = mapDiffResetInstances.lower_bound(map_diff_pair);
in_itr != mapDiffResetInstances.upper_bound(map_diff_pair); ++in_itr)
{
ScheduleReset(true, t - tim[type-1], InstanceResetEvent(type, mapid, difficulty, in_itr->second));
}
}
}
void InstanceResetScheduler::ScheduleReset(bool add, time_t time, InstanceResetEvent event)
{
if (add)
m_resetTimeQueue.insert(std::pair<time_t, InstanceResetEvent>(time, event));
else
{
// find the event in the queue and remove it
ResetTimeQueue::iterator itr;
std::pair<ResetTimeQueue::iterator, ResetTimeQueue::iterator> range;
range = m_resetTimeQueue.equal_range(time);
for(itr = range.first; itr != range.second; ++itr)
{
if (itr->second == event)
{
m_resetTimeQueue.erase(itr);
return;
}
}
// in case the reset time changed (should happen very rarely), we search the whole queue
if(itr == range.second)
{
for(itr = m_resetTimeQueue.begin(); itr != m_resetTimeQueue.end(); ++itr)
{
if(itr->second == event)
{
m_resetTimeQueue.erase(itr);
return;
}
}
if(itr == m_resetTimeQueue.end())
sLog.outError("InstanceResetScheduler::ScheduleReset: cannot cancel the reset, the event(%d,%d,%d) was not found!", event.type, event.mapid, event.instanceId);
}
}
}
void InstanceResetScheduler::Update()
{
time_t now = time(NULL), t;
while(!m_resetTimeQueue.empty() && (t = m_resetTimeQueue.begin()->first) < now)
{
InstanceResetEvent &event = m_resetTimeQueue.begin()->second;
if(event.type == 0)
{
// for individual normal instances, max creature respawn + X hours
m_InstanceSaves._ResetInstance(event.mapid, event.instanceId);
m_resetTimeQueue.erase(m_resetTimeQueue.begin());
}
else
{
// global reset/warning for a certain map
time_t resetTime = GetResetTimeFor(event.mapid,event.difficulty);
m_InstanceSaves._ResetOrWarnAll(event.mapid, event.difficulty, event.type != 4, uint32(resetTime - now));
if(event.type != 4)
{
// schedule the next warning/reset
event.type++;
static int tim[4] = {3600, 900, 300, 60};
ScheduleReset(true, resetTime - tim[event.type-1], event);
}
m_resetTimeQueue.erase(m_resetTimeQueue.begin());
}
}
}
//== InstanceSaveManager functions =========================
InstanceSaveManager::InstanceSaveManager() : lock_instLists(false)
InstanceSaveManager::InstanceSaveManager() : lock_instLists(false), m_Scheduler(*this)
{
}
@ -171,12 +383,12 @@ InstanceSave* InstanceSaveManager::AddInstanceSave(uint32 mapId, uint32 instance
// initialize reset time
// for normal instances if no creatures are killed the instance will reset in two hours
if(entry->map_type == MAP_RAID || difficulty > DUNGEON_DIFFICULTY_NORMAL)
resetTime = GetResetTimeFor(mapId,difficulty);
resetTime = m_Scheduler.GetResetTimeFor(mapId,difficulty);
else
{
resetTime = time(NULL) + 2 * HOUR;
// normally this will be removed soon after in InstanceMap::Add, prevent error
ScheduleReset(true, resetTime, InstResetEvent(0, mapId, difficulty, instanceId));
m_Scheduler.ScheduleReset(true, resetTime, InstanceResetEvent(0, mapId, difficulty, instanceId));
}
}
@ -254,7 +466,7 @@ void InstanceSaveManager::CleanupInstances()
bar.step();
// load reset times and clean expired instances
LoadResetTimes();
m_Scheduler.LoadResetTimes();
// clean character/group - instance binds with invalid group/characters
_DelHelper(CharacterDatabase, "character_instance.guid, instance", "character_instance", "LEFT JOIN characters ON character_instance.guid = characters.guid WHERE characters.guid IS NULL");
@ -364,202 +576,6 @@ void InstanceSaveManager::PackInstances()
sLog.outString();
}
void InstanceSaveManager::LoadResetTimes()
{
time_t now = time(NULL);
time_t today = (now / DAY) * DAY;
// NOTE: Use DirectPExecute for tables that will be queried later
// get the current reset times for normal instances (these may need to be updated)
// these are only kept in memory for InstanceSaves that are loaded later
// resettime = 0 in the DB for raid/heroic instances so those are skipped
typedef std::pair<uint32 /*PAIR32(map,difficulty)*/, time_t> ResetTimeMapDiffType;
typedef std::map<uint32, ResetTimeMapDiffType> InstResetTimeMapDiffType;
InstResetTimeMapDiffType instResetTime;
// index instance ids by map/difficulty pairs for fast reset warning send
typedef std::multimap<uint32 /*PAIR32(map,difficulty)*/, uint32 /*instanceid*/ > ResetTimeMapDiffInstances;
ResetTimeMapDiffInstances mapDiffResetInstances;
QueryResult *result = CharacterDatabase.Query("SELECT id, map, difficulty, resettime FROM instance WHERE resettime > 0");
if( result )
{
do
{
if(time_t resettime = time_t((*result)[3].GetUInt64()))
{
uint32 id = (*result)[0].GetUInt32();
uint32 mapid = (*result)[1].GetUInt32();
uint32 difficulty = (*result)[2].GetUInt32();
instResetTime[id] = ResetTimeMapDiffType(MAKE_PAIR32(mapid,difficulty), resettime);
mapDiffResetInstances.insert(ResetTimeMapDiffInstances::value_type(MAKE_PAIR32(mapid,difficulty),id));
}
}
while (result->NextRow());
delete result;
// update reset time for normal instances with the max creature respawn time + X hours
result = WorldDatabase.Query("SELECT MAX(respawntime), instance FROM creature_respawn WHERE instance > 0 GROUP BY instance");
if( result )
{
do
{
Field *fields = result->Fetch();
uint32 instance = fields[1].GetUInt32();
time_t resettime = time_t(fields[0].GetUInt64() + 2 * HOUR);
InstResetTimeMapDiffType::iterator itr = instResetTime.find(instance);
if(itr != instResetTime.end() && itr->second.second != resettime)
{
CharacterDatabase.DirectPExecute("UPDATE instance SET resettime = '"UI64FMTD"' WHERE id = '%u'", uint64(resettime), instance);
itr->second.second = resettime;
}
}
while (result->NextRow());
delete result;
}
// schedule the reset times
for(InstResetTimeMapDiffType::iterator itr = instResetTime.begin(); itr != instResetTime.end(); ++itr)
if(itr->second.second > now)
ScheduleReset(true, itr->second.second, InstResetEvent(0, PAIR32_LOPART(itr->second.first),Difficulty(PAIR32_HIPART(itr->second.first)),itr->first));
}
// load the global respawn times for raid/heroic instances
uint32 diff = sWorld.getConfig(CONFIG_UINT32_INSTANCE_RESET_TIME_HOUR) * HOUR;
result = CharacterDatabase.Query("SELECT mapid, difficulty, resettime FROM instance_reset");
if(result)
{
do
{
Field *fields = result->Fetch();
uint32 mapid = fields[0].GetUInt32();
Difficulty difficulty = Difficulty(fields[1].GetUInt32());
uint64 oldresettime = fields[2].GetUInt64();
MapDifficulty const* mapDiff = GetMapDifficultyData(mapid,difficulty);
if(!mapDiff)
{
sLog.outError("InstanceSaveManager::LoadResetTimes: invalid mapid(%u)/difficulty(%u) pair in instance_reset!", mapid, difficulty);
CharacterDatabase.DirectPExecute("DELETE FROM instance_reset WHERE mapid = '%u' AND difficulty = '%u'", mapid,difficulty);
continue;
}
// update the reset time if the hour in the configs changes
uint64 newresettime = (oldresettime / DAY) * DAY + diff;
if(oldresettime != newresettime)
CharacterDatabase.DirectPExecute("UPDATE instance_reset SET resettime = '"UI64FMTD"' WHERE mapid = '%u' AND difficulty = '%u'", newresettime, mapid, difficulty);
SetResetTimeFor(mapid,difficulty,newresettime);
} while(result->NextRow());
delete result;
}
// clean expired instances, references to them will be deleted in CleanupInstances
// must be done before calculating new reset times
_DelHelper(CharacterDatabase, "id, map, instance.difficulty", "instance", "LEFT JOIN instance_reset ON mapid = map AND instance.difficulty = instance_reset.difficulty WHERE (instance.resettime < '"UI64FMTD"' AND instance.resettime > '0') OR (NOT instance_reset.resettime IS NULL AND instance_reset.resettime < '"UI64FMTD"')", (uint64)now, (uint64)now);
// calculate new global reset times for expired instances and those that have never been reset yet
// add the global reset times to the priority queue
for(MapDifficultyMap::const_iterator itr = sMapDifficultyMap.begin(); itr != sMapDifficultyMap.end(); ++itr)
{
uint32 map_diff_pair = itr->first;
uint32 mapid = PAIR32_LOPART(map_diff_pair);
Difficulty difficulty = Difficulty(PAIR32_HIPART(map_diff_pair));
MapDifficulty const* mapDiff = &itr->second;
if (!mapDiff->resetTime)
continue;
// the reset_delay must be at least one day
uint32 period = uint32(mapDiff->resetTime / DAY * sWorld.getConfig(CONFIG_FLOAT_RATE_INSTANCE_RESET_TIME)) * DAY;
if (period < DAY)
period = DAY;
time_t t = GetResetTimeFor(mapid,difficulty);
if(!t)
{
// initialize the reset time
t = today + period + diff;
CharacterDatabase.DirectPExecute("INSERT INTO instance_reset VALUES ('%u','%u','"UI64FMTD"')", mapid, difficulty, (uint64)t);
}
if(t < now)
{
// assume that expired instances have already been cleaned
// calculate the next reset time
t = (t / DAY) * DAY;
t += ((today - t) / period + 1) * period + diff;
CharacterDatabase.DirectPExecute("UPDATE instance_reset SET resettime = '"UI64FMTD"' WHERE mapid = '%u' AND difficulty= '%u'", (uint64)t, mapid, difficulty);
}
SetResetTimeFor(mapid,difficulty,t);
// schedule the global reset/warning
uint8 type = 1;
static int tim[4] = {3600, 900, 300, 60};
for(; type < 4; type++)
if(t - tim[type-1] > now)
break;
for(ResetTimeMapDiffInstances::const_iterator in_itr = mapDiffResetInstances.lower_bound(map_diff_pair);
in_itr != mapDiffResetInstances.upper_bound(map_diff_pair); ++in_itr)
{
ScheduleReset(true, t - tim[type-1], InstResetEvent(type, mapid, difficulty, in_itr->second));
}
}
}
void InstanceSaveManager::ScheduleReset(bool add, time_t time, InstResetEvent event)
{
if(add) m_resetTimeQueue.insert(std::pair<time_t, InstResetEvent>(time, event));
else
{
// find the event in the queue and remove it
ResetTimeQueue::iterator itr;
std::pair<ResetTimeQueue::iterator, ResetTimeQueue::iterator> range;
range = m_resetTimeQueue.equal_range(time);
for(itr = range.first; itr != range.second; ++itr)
if(itr->second == event) { m_resetTimeQueue.erase(itr); return; }
// in case the reset time changed (should happen very rarely), we search the whole queue
if(itr == range.second)
{
for(itr = m_resetTimeQueue.begin(); itr != m_resetTimeQueue.end(); ++itr)
if(itr->second == event) { m_resetTimeQueue.erase(itr); return; }
if(itr == m_resetTimeQueue.end())
sLog.outError("InstanceSaveManager::ScheduleReset: cannot cancel the reset, the event(%d,%d,%d) was not found!", event.type, event.mapid, event.instanceId);
}
}
}
void InstanceSaveManager::Update()
{
time_t now = time(NULL), t;
while(!m_resetTimeQueue.empty() && (t = m_resetTimeQueue.begin()->first) < now)
{
InstResetEvent &event = m_resetTimeQueue.begin()->second;
if(event.type == 0)
{
// for individual normal instances, max creature respawn + X hours
_ResetInstance(event.mapid, event.instanceId);
m_resetTimeQueue.erase(m_resetTimeQueue.begin());
}
else
{
// global reset/warning for a certain map
time_t resetTime = GetResetTimeFor(event.mapid,event.difficulty);
_ResetOrWarnAll(event.mapid, event.difficulty, event.type != 4, uint32(resetTime - now));
if(event.type != 4)
{
// schedule the next warning/reset
event.type++;
static int tim[4] = {3600, 900, 300, 60};
ScheduleReset(true, resetTime - tim[event.type-1], event);
}
m_resetTimeQueue.erase(m_resetTimeQueue.begin());
}
}
}
void InstanceSaveManager::_ResetSave(InstanceSaveHashMap::iterator &itr)
{
// unbind all players bound to the instance
@ -574,16 +590,20 @@ void InstanceSaveManager::_ResetInstance(uint32 mapid, uint32 instanceId)
{
DEBUG_LOG("InstanceSaveMgr::_ResetInstance %u, %u", mapid, instanceId);
Map *map = (MapInstanced*)sMapMgr.CreateBaseMap(mapid);
if(!map->Instanceable())
if (!map->Instanceable())
return;
InstanceSaveHashMap::iterator itr = m_instanceSaveById.find(instanceId);
if(itr != m_instanceSaveById.end()) _ResetSave(itr);
if (itr != m_instanceSaveById.end())
_ResetSave(itr);
DeleteInstanceFromDB(instanceId); // even if save not loaded
Map* iMap = ((MapInstanced*)map)->FindMap(instanceId);
if(iMap && iMap->IsDungeon()) ((InstanceMap*)iMap)->Reset(INSTANCE_RESET_RESPAWN_DELAY);
else sObjectMgr.DeleteRespawnTimeForInstance(instanceId); // even if map is not loaded
if (iMap && iMap->IsDungeon())
((InstanceMap*)iMap)->Reset(INSTANCE_RESET_RESPAWN_DELAY);
else
sObjectMgr.DeleteRespawnTimeForInstance(instanceId);// even if map is not loaded
}
void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, bool warn, uint32 timeLeft)
@ -662,3 +682,8 @@ uint32 InstanceSaveManager::GetNumBoundGroupsTotal()
ret += itr->second->GetGroupCount();
return ret;
}
void InstanceSaveManager::_CleanupExiredInstancesAtTime( time_t t )
{
_DelHelper(CharacterDatabase, "id, map, instance.difficulty", "instance", "LEFT JOIN instance_reset ON mapid = map AND instance.difficulty = instance_reset.difficulty WHERE (instance.resettime < '"UI64FMTD"' AND instance.resettime > '0') OR (NOT instance_reset.resettime IS NULL AND instance_reset.resettime < '"UI64FMTD"')", (uint64)t, (uint64)t);
}

View file

@ -112,9 +112,62 @@ class InstanceSave
bool m_canReset;
};
/* resetTime is a global propery of each (raid/heroic) map
all instances of that map reset at the same time */
struct InstanceResetEvent
{
uint8 type;
Difficulty difficulty:8;
uint16 mapid;
uint16 instanceId;
InstanceResetEvent() : type(0), difficulty(DUNGEON_DIFFICULTY_NORMAL), mapid(0), instanceId(0) {}
InstanceResetEvent(uint8 t, uint32 _mapid, Difficulty d, uint16 _instanceid)
: type(t), difficulty(d), mapid(_mapid), instanceId(_instanceid) {}
bool operator == (const InstanceResetEvent& e) { return e.instanceId == instanceId; }
};
class InstanceSaveManager;
class InstanceResetScheduler
{
public: // constructors
explicit InstanceResetScheduler(InstanceSaveManager& mgr) : m_InstanceSaves(mgr) {}
void LoadResetTimes();
public: // accessors
time_t GetResetTimeFor(uint32 mapid, Difficulty d) const
{
ResetTimeByMapDifficultyMap::const_iterator itr = m_resetTimeByMapDifficulty.find(MAKE_PAIR32(mapid,d));
return itr != m_resetTimeByMapDifficulty.end() ? itr->second : 0;
}
public: // modifiers
void SetResetTimeFor(uint32 mapid, Difficulty d, time_t t)
{
m_resetTimeByMapDifficulty[MAKE_PAIR32(mapid,d)] = t;
}
void ScheduleReset(bool add, time_t time, InstanceResetEvent event);
void Update();
private: // fields
InstanceSaveManager& m_InstanceSaves;
// fast lookup for reset times (always use existed functions for access/set)
typedef UNORDERED_MAP<uint32 /*PAIR32(map,difficulty)*/,time_t /*resetTime*/> ResetTimeByMapDifficultyMap;
ResetTimeByMapDifficultyMap m_resetTimeByMapDifficulty;
typedef std::multimap<time_t /*resetTime*/, InstanceResetEvent> ResetTimeQueue;
ResetTimeQueue m_resetTimeQueue;
};
class MANGOS_DLL_DECL InstanceSaveManager : public MaNGOS::Singleton<InstanceSaveManager, MaNGOS::ClassLevelLockable<InstanceSaveManager, ACE_Thread_Mutex> >
{
friend class InstanceSave;
friend class InstanceResetScheduler;
public:
InstanceSaveManager();
~InstanceSaveManager();
@ -122,39 +175,10 @@ class MANGOS_DLL_DECL InstanceSaveManager : public MaNGOS::Singleton<InstanceSav
typedef UNORDERED_MAP<uint32 /*InstanceId*/, InstanceSave*> InstanceSaveHashMap;
typedef UNORDERED_MAP<uint32 /*mapId*/, InstanceSaveHashMap> InstanceSaveMapMap;
/* resetTime is a global propery of each (raid/heroic) map
all instances of that map reset at the same time */
struct InstResetEvent
{
uint8 type;
Difficulty difficulty:8;
uint16 mapid;
uint16 instanceId;
InstResetEvent() : type(0), difficulty(DUNGEON_DIFFICULTY_NORMAL), mapid(0), instanceId(0) {}
InstResetEvent(uint8 t, uint32 _mapid, Difficulty d, uint16 _instanceid)
: type(t), difficulty(d), mapid(_mapid), instanceId(_instanceid) {}
bool operator == (const InstResetEvent& e) { return e.instanceId == instanceId; }
};
typedef std::multimap<time_t /*resetTime*/, InstResetEvent> ResetTimeQueue;
typedef UNORDERED_MAP<uint32 /*PAIR32(map,difficulty)*/,time_t /*resetTime*/> ResetTimeByMapDifficultyMap;
void CleanupInstances();
void PackInstances();
void LoadResetTimes();
time_t GetResetTimeFor(uint32 mapid, Difficulty d) const
{
ResetTimeByMapDifficultyMap::const_iterator itr = m_resetTimeByMapDifficulty.find(MAKE_PAIR32(mapid,d));
return itr != m_resetTimeByMapDifficulty.end() ? itr->second : 0;
}
void SetResetTimeFor(uint32 mapid, Difficulty d, time_t t)
{
m_resetTimeByMapDifficulty[MAKE_PAIR32(mapid,d)] = t;
}
void ScheduleReset(bool add, time_t time, InstResetEvent event);
void Update();
InstanceResetScheduler& GetScheduler() { return m_Scheduler; }
InstanceSave* AddInstanceSave(uint32 mapId, uint32 instanceId, Difficulty difficulty, time_t resetTime, bool canReset, bool load = false);
void RemoveInstanceSave(uint32 InstanceId);
@ -167,18 +191,22 @@ class MANGOS_DLL_DECL InstanceSaveManager : public MaNGOS::Singleton<InstanceSav
uint32 GetNumBoundPlayersTotal();
uint32 GetNumBoundGroupsTotal();
void Update() { m_Scheduler.Update(); }
private:
// called by scheduler
void _ResetOrWarnAll(uint32 mapid, Difficulty difficulty, bool warn, uint32 timeleft);
void _ResetInstance(uint32 mapid, uint32 instanceId);
void _CleanupExiredInstancesAtTime(time_t t);
void _ResetSave(InstanceSaveHashMap::iterator &itr);
void _DelHelper(DatabaseType &db, const char *fields, const char *table, const char *queryTail,...);
// used during global instance resets
bool lock_instLists;
// fast lookup by instance id
InstanceSaveHashMap m_instanceSaveById;
// fast lookup for reset times (always use existed functions for access/set)
ResetTimeByMapDifficultyMap m_resetTimeByMapDifficulty;
ResetTimeQueue m_resetTimeQueue;
InstanceResetScheduler m_Scheduler;
};
#define sInstanceSaveMgr MaNGOS::Singleton<InstanceSaveManager>::Instance()

View file

@ -2054,8 +2054,10 @@ void InstanceMap::SetResetSchedule(bool on)
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.ScheduleReset(on, save->GetResetTime(), InstanceSaveManager::InstResetEvent(0, GetId(), Difficulty(GetSpawnMode()), 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()));
}
}

View file

@ -144,7 +144,7 @@ void WorldSession::HandleMoveWorldportAckOpcode()
{
if (mapDiff->resetTime)
{
if (time_t timeReset = sInstanceSaveMgr.GetResetTimeFor(mEntry->MapID,diff))
if (time_t timeReset = sInstanceSaveMgr.GetScheduler().GetResetTimeFor(mEntry->MapID,diff))
{
uint32 timeleft = uint32(timeReset - time(NULL));
GetPlayer()->SendInstanceResetWarning(mEntry->MapID, diff, timeleft);

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "10093"
#define REVISION_NR "10094"
#endif // __REVISION_NR_H__