Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
InstanceSaveMgr.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
6#include "CellImpl.h"
7#include "Common.h"
8#include "Config.h"
9#include "GridNotifiers.h"
10#include "GridNotifiersImpl.h"
11#include "GridStates.h"
12#include "Group.h"
13#include "InstanceSaveMgr.h"
14#include "InstanceScript.h"
15#include "Log.h"
16#include "Map.h"
17#include "MapInstanced.h"
18#include "MapManager.h"
19#include "ObjectMgr.h"
20#include "Player.h"
21#include "Timer.h"
22#include "Transport.h"
23#include "World.h"
24
25uint16 InstanceSaveManager::ResetTimeDelay[] = { 3600, 900, 300, 60 };
26
28{
29 // it is undefined whether this or objectmgr will be unloaded first
30 // so we must be prepared for both cases
31 lock_instLists = true;
32 for (InstanceSaveHashMap::iterator itr = m_instanceSaveById.begin(); itr != m_instanceSaveById.end(); ++itr)
33 {
34 InstanceSave* save = itr->second;
35
36 for (InstanceSave::PlayerListType::iterator itr2 = save->m_playerList.begin(), next = itr2; itr2 != save->m_playerList.end(); itr2 = next)
37 {
38 ++next;
39 (*itr2)->UnbindInstance(save->GetMapId(), save->GetDifficulty(), true);
40 }
41
42 for (InstanceSave::GroupListType::iterator itr2 = save->m_groupList.begin(), next = itr2; itr2 != save->m_groupList.end(); itr2 = next)
43 {
44 ++next;
45 (*itr2)->UnbindInstance(save->GetMapId(), save->GetDifficulty(), true);
46 }
47
48 delete save;
49 }
50}
51
52/*
53- adding instance into manager
54- called from InstanceMap::Add, _LoadBoundInstances, LoadGroups
55*/
56InstanceSave* InstanceSaveManager::AddInstanceSave(uint32 mapId, uint32 instanceId, DifficultyID difficulty, time_t resetTime, bool canReset, bool load)
57{
58 if (InstanceSave* old_save = GetInstanceSave(instanceId))
59 return old_save;
60
61 const MapEntry* entry = sMapStore.LookupEntry(mapId);
62 if (!entry)
63 {
64 SF_LOG_ERROR("misc", "InstanceSaveManager::AddInstanceSave: wrong mapid = %d, instanceid = %d!", mapId, instanceId);
65 return NULL;
66 }
67
68 if (instanceId == 0)
69 {
70 SF_LOG_ERROR("misc", "InstanceSaveManager::AddInstanceSave: mapid = %d, wrong instanceid = %d!", mapId, instanceId);
71 return NULL;
72 }
73
74 if (difficulty >= 14)
75 {
76 SF_LOG_ERROR("misc", "InstanceSaveManager::AddInstanceSave: mapid = %d, instanceid = %d, wrong dificalty %u!", mapId, instanceId, difficulty);
77 return NULL;
78 }
79
80 if (!resetTime)
81 {
82 // initialize reset time
83 // for normal instances if no creatures are killed the instance will reset in two hours
84 if (entry->map_type == MAP_RAID || difficulty > DIFFICULTY_NORMAL)
85 resetTime = GetResetTimeFor(mapId, difficulty);
86 else
87 {
88 resetTime = time(NULL) + 2 * HOUR;
89 // normally this will be removed soon after in InstanceMap::Add, prevent error
90 ScheduleReset(true, resetTime, InstResetEvent(0, mapId, difficulty, instanceId));
91 }
92 }
93
94 SF_LOG_DEBUG("maps", "InstanceSaveManager::AddInstanceSave: mapid = %d, instanceid = %d", mapId, instanceId);
95
96 InstanceSave* save = new InstanceSave(mapId, instanceId, difficulty, resetTime, canReset);
97 if (!load)
98 save->SaveToDB();
99
100 m_instanceSaveById[instanceId] = save;
101 return save;
102}
103
105{
106 InstanceSaveHashMap::iterator itr = m_instanceSaveById.find(InstanceId);
107 return itr != m_instanceSaveById.end() ? itr->second : NULL;
108}
109
111{
112 SQLTransaction trans = CharacterDatabase.BeginTransaction();
113
115 stmt->setUInt32(0, instanceid);
116 trans->Append(stmt);
117
118 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INSTANCE_BY_INSTANCE);
119 stmt->setUInt32(0, instanceid);
120 trans->Append(stmt);
121
122 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GROUP_INSTANCE_BY_INSTANCE);
123 stmt->setUInt32(0, instanceid);
124 trans->Append(stmt);
125
126 CharacterDatabase.CommitTransaction(trans);
127 // Respawn times should be deleted only when the map gets unloaded
128}
129
131{
132 InstanceSaveHashMap::iterator itr = m_instanceSaveById.find(InstanceId);
133 if (itr != m_instanceSaveById.end())
134 {
135 // save the resettime for normal instances only when they get unloaded
136 if (time_t resettime = itr->second->GetResetTimeForDB())
137 {
139
140 stmt->setUInt32(0, uint32(resettime));
141 stmt->setUInt32(1, InstanceId);
142
143 CharacterDatabase.Execute(stmt);
144 }
145
146 itr->second->SetToDelete(true);
147 m_instanceSaveById.erase(itr);
148 }
149}
150
151InstanceSave::InstanceSave(uint16 MapId, uint32 InstanceId, DifficultyID difficulty, time_t resetTime, bool canReset)
152 : m_resetTime(resetTime), m_instanceid(InstanceId), m_mapid(MapId),
153 m_difficulty(difficulty), m_canReset(canReset), m_toDelete(false) { }
154
156{
157 // the players and groups must be unbound before deleting the save
158 ASSERT(m_playerList.empty() && m_groupList.empty());
159}
160
161/*
162 Called from AddInstanceSave
163*/
165{
166 // save instance data too
167 std::string data;
168 uint32 completedEncounters = 0;
169
170 Map* map = sMapMgr->FindMap(GetMapId(), m_instanceid);
171 if (map)
172 {
173 ASSERT(map->IsInstance());
174 if (InstanceScript* instanceScript = ((InstanceMap*)map)->GetInstanceScript())
175 {
176 data = instanceScript->GetSaveData();
177 completedEncounters = instanceScript->GetCompletedEncounterMask();
178 }
179 }
180
181 PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_INSTANCE_SAVE);
182 stmt->setUInt32(0, m_instanceid);
183 stmt->setUInt16(1, GetMapId());
185 stmt->setUInt8(3, uint8(GetDifficulty()));
186 stmt->setUInt32(4, completedEncounters);
187 stmt->setString(5, data);
188 CharacterDatabase.Execute(stmt);
189}
190
192{
193 // only save the reset time for normal instances
194 const MapEntry* entry = sMapStore.LookupEntry(GetMapId());
195 if (!entry || entry->map_type == MAP_RAID || GetDifficulty() == DIFFICULTY_HEROIC)
196 return 0;
197 else
198 return GetResetTime();
199}
200
201// to cache or not to cache, that is the question
203{
204 return sObjectMgr->GetInstanceTemplate(m_mapid);
205}
206
208{
209 return sMapStore.LookupEntry(m_mapid);
210}
211
216
217/* true if the instance save is still valid */
219{
220 if (m_playerList.empty() && m_groupList.empty())
221 {
222 if (!sInstanceSaveMgr->lock_instLists)
223 sInstanceSaveMgr->RemoveInstanceSave(GetInstanceId());
224
225 return false;
226 }
227 else
228 return true;
229}
230
232{
233 uint32 oldMSTime = getMSTime();
234
235 // Delete expired instances (Instance related spawns are removed in the following cleanup queries)
236 CharacterDatabase.DirectExecute("DELETE i FROM instance i LEFT JOIN instance_reset ir ON mapid = map AND i.difficulty = ir.difficulty "
237 "WHERE (i.resettime > 0 AND i.resettime < UNIX_TIMESTAMP()) OR (ir.resettime IS NOT NULL AND ir.resettime < UNIX_TIMESTAMP())");
238
239 // Delete invalid character_instance and party_instance references
240 CharacterDatabase.DirectExecute("DELETE ci.* FROM character_instance AS ci LEFT JOIN characters AS c ON ci.guid = c.guid WHERE c.guid IS NULL");
241 CharacterDatabase.DirectExecute("DELETE gi.* FROM party_instance AS gi LEFT JOIN parties AS g ON gi.guid = g.guid WHERE g.guid IS NULL");
242
243 // Delete invalid instance references
244 CharacterDatabase.DirectExecute("DELETE i.* FROM instance AS i LEFT JOIN character_instance AS ci ON i.id = ci.instance LEFT JOIN party_instance AS gi ON i.id = gi.instance WHERE ci.guid IS NULL AND gi.guid IS NULL");
245
246 // Delete invalid references to instance
247 CharacterDatabase.DirectExecute("DELETE FROM creature_respawn WHERE instanceId > 0 AND instanceId NOT IN (SELECT id FROM instance)");
248 CharacterDatabase.DirectExecute("DELETE FROM gameobject_respawn WHERE instanceId > 0 AND instanceId NOT IN (SELECT id FROM instance)");
249 CharacterDatabase.DirectExecute("DELETE tmp.* FROM character_instance AS tmp LEFT JOIN instance ON tmp.instance = instance.id WHERE tmp.instance > 0 AND instance.id IS NULL");
250 CharacterDatabase.DirectExecute("DELETE tmp.* FROM party_instance AS tmp LEFT JOIN instance ON tmp.instance = instance.id WHERE tmp.instance > 0 AND instance.id IS NULL");
251
252 // Clean invalid references to instance
253 CharacterDatabase.DirectExecute("UPDATE corpse SET instanceId = 0 WHERE instanceId > 0 AND instanceId NOT IN (SELECT id FROM instance)");
254 CharacterDatabase.DirectExecute("UPDATE characters AS tmp LEFT JOIN instance ON tmp.instance_id = instance.id SET tmp.instance_id = 0 WHERE tmp.instance_id > 0 AND instance.id IS NULL");
255
256 // Initialize instance id storage (Needs to be done after the trash has been clean out)
257 sMapMgr->InitInstanceIds();
258
259 // Load reset times and clean expired instances
260 sInstanceSaveMgr->LoadResetTimes();
261
262 SF_LOG_INFO("server.loading", ">> Loaded instances in %u ms", GetMSTimeDiffToNow(oldMSTime));
263}
264
266{
267 time_t now = time(NULL);
268 time_t today = (now / DAY) * DAY;
269
270 // NOTE: Use DirectPExecute for tables that will be queried later
271
272 // get the current reset times for normal instances (these may need to be updated)
273 // these are only kept in memory for InstanceSaves that are loaded later
274 // resettime = 0 in the DB for raid/heroic instances so those are skipped
275 typedef std::pair<uint32 /*PAIR32(map, difficulty)*/, time_t> ResetTimeMapDiffType;
276 typedef std::map<uint32, ResetTimeMapDiffType> InstResetTimeMapDiffType;
277 InstResetTimeMapDiffType instResetTime;
278
279 // index instance ids by map/difficulty pairs for fast reset warning send
280 typedef std::multimap<uint32 /*PAIR32(map, difficulty)*/, uint32 /*instanceid*/ > ResetTimeMapDiffInstances;
281 typedef std::pair<ResetTimeMapDiffInstances::const_iterator, ResetTimeMapDiffInstances::const_iterator> ResetTimeMapDiffInstancesBounds;
282 ResetTimeMapDiffInstances mapDiffResetInstances;
283
284 QueryResult result = CharacterDatabase.Query("SELECT id, map, difficulty, resettime FROM instance ORDER BY id ASC");
285 if (result)
286 {
287 do
288 {
289 Field* fields = result->Fetch();
290
291 uint32 instanceId = fields[0].GetUInt32();
292
293 // Instances are pulled in ascending order from db and nextInstanceId is initialized with 1,
294 // so if the instance id is used, increment until we find the first unused one for a potential new instance
295 if (sMapMgr->GetNextInstanceId() == instanceId)
296 sMapMgr->SetNextInstanceId(instanceId + 1);
297
298 // Mark instance id as being used
299 sMapMgr->RegisterInstanceId(instanceId);
300
301 if (time_t resettime = time_t(fields[3].GetUInt32()))
302 {
303 uint32 mapid = fields[1].GetUInt16();
304 uint32 difficulty = fields[2].GetUInt8();
305
306 instResetTime[instanceId] = ResetTimeMapDiffType(MAKE_PAIR32(mapid, difficulty), resettime);
307 mapDiffResetInstances.insert(ResetTimeMapDiffInstances::value_type(MAKE_PAIR32(mapid, difficulty), instanceId));
308 }
309 } while (result->NextRow());
310
311 // update reset time for normal instances with the max creature respawn time + X hours
313 {
314 do
315 {
316 Field* fields = result2->Fetch();
317 uint32 instance = fields[1].GetUInt32();
318 time_t resettime = time_t(fields[0].GetUInt32() + 2 * uint32(HOUR));
319 InstResetTimeMapDiffType::iterator itr = instResetTime.find(instance);
320 if (itr != instResetTime.end() && itr->second.second != resettime)
321 {
322 CharacterDatabase.DirectPExecute("UPDATE instance SET resettime = '" UI64FMTD "' WHERE id = '%u'", uint64(resettime), instance);
323 itr->second.second = resettime;
324 }
325 } while (result->NextRow());
326 }
327
328 // schedule the reset times
329 for (InstResetTimeMapDiffType::iterator itr = instResetTime.begin(); itr != instResetTime.end(); ++itr)
330 if (itr->second.second > now)
331 ScheduleReset(true, itr->second.second, InstResetEvent(0, PAIR32_LOPART(itr->second.first), DifficultyID(PAIR32_HIPART(itr->second.first)), itr->first));
332 }
333
334 // load the global respawn times for raid/heroic instances
336 result = CharacterDatabase.Query("SELECT mapid, difficulty, resettime FROM instance_reset");
337 if (result)
338 {
339 do
340 {
341 Field* fields = result->Fetch();
342 uint32 mapid = fields[0].GetUInt16();
343 DifficultyID difficulty = DifficultyID(fields[1].GetUInt8());
344 uint64 oldresettime = fields[2].GetUInt32();
345
346 MapDifficulty const* mapDiff = GetMapDifficultyData(mapid, difficulty);
347 if (!mapDiff)
348 {
349 SF_LOG_ERROR("misc", "InstanceSaveManager::LoadResetTimes: invalid mapid(%u)/difficulty(%u) pair in instance_reset!", mapid, difficulty);
350 CharacterDatabase.DirectPExecute("DELETE FROM instance_reset WHERE mapid = '%u' AND difficulty = '%u'", mapid, difficulty);
351 continue;
352 }
353
354 // update the reset time if the hour in the configs changes
355 uint64 newresettime = (oldresettime / DAY) * DAY + diff;
356 if (oldresettime != newresettime)
357 CharacterDatabase.DirectPExecute("UPDATE instance_reset SET resettime = '%u' WHERE mapid = '%u' AND difficulty = '%u'", uint32(newresettime), mapid, difficulty);
358
359 SetResetTimeFor(mapid, difficulty, newresettime);
360 } while (result->NextRow());
361 }
362
363 // calculate new global reset times for expired instances and those that have never been reset yet
364 // add the global reset times to the priority queue
365 for (auto& mapDifficultyPair : sMapDifficultyMap)
366 {
367 uint32 mapid = mapDifficultyPair.first;
368
369 for (auto& difficultyPair : mapDifficultyPair.second)
370 {
371 DifficultyID difficulty = DifficultyID(difficultyPair.first);
372 MapDifficulty const* mapDiff = &difficultyPair.second;
373 if (!mapDiff->resetTime)
374 continue;
375
376 // the reset_delay must be at least one day
377 uint32 period = uint32(((mapDiff->resetTime * sWorld->getRate(Rates::RATE_INSTANCE_RESET_TIME)) / uint32(DAY)) * uint32(DAY));
378 if (period < DAY)
379 period = DAY;
380
381 time_t t = GetResetTimeFor(mapid, difficulty);
382 if (!t)
383 {
384 // initialize the reset time
385 t = today + period + diff;
386 CharacterDatabase.DirectPExecute("INSERT INTO instance_reset VALUES ('%u', '%u', '%u')", mapid, difficulty, (uint32)t);
387 }
388
389 if (t < now)
390 {
391 // assume that expired instances have already been cleaned
392 // calculate the next reset time
393 t = (t / DAY) * DAY;
394 t += ((today - t) / period + 1) * period + diff;
395 CharacterDatabase.DirectPExecute("UPDATE instance_reset SET resettime = '" UI64FMTD "' WHERE mapid = '%u' AND difficulty= '%u'", (uint64)t, mapid, difficulty);
396 }
397
398 SetResetTimeFor(mapid, difficulty, t);
399
400 // schedule the global reset/warning
401 uint8 type;
402 for (type = 1; type < 4; ++type)
403 if (t - ResetTimeDelay[type - 1] > now)
404 break;
405
406 ScheduleReset(true, t - ResetTimeDelay[type - 1], InstResetEvent(type, mapid, difficulty, 0));
407
408 ResetTimeMapDiffInstancesBounds range = mapDiffResetInstances.equal_range(MAKE_PAIR32(mapid, difficulty));
409 for (; range.first != range.second; ++range.first)
410 ScheduleReset(true, t - ResetTimeDelay[type - 1], InstResetEvent(type, mapid, difficulty, range.first->second));
411 }
412 }
413}
414
415void InstanceSaveManager::ScheduleReset(bool add, time_t time, InstResetEvent event)
416{
417 if (!add)
418 {
419 // find the event in the queue and remove it
420 ResetTimeQueue::iterator itr;
421 std::pair<ResetTimeQueue::iterator, ResetTimeQueue::iterator> range;
422 range = m_resetTimeQueue.equal_range(time);
423 for (itr = range.first; itr != range.second; ++itr)
424 {
425 if (itr->second == event)
426 {
427 m_resetTimeQueue.erase(itr);
428 return;
429 }
430 }
431
432 // in case the reset time changed (should happen very rarely), we search the whole queue
433 if (itr == range.second)
434 {
435 for (itr = m_resetTimeQueue.begin(); itr != m_resetTimeQueue.end(); ++itr)
436 {
437 if (itr->second == event)
438 {
439 m_resetTimeQueue.erase(itr);
440 return;
441 }
442 }
443
444 if (itr == m_resetTimeQueue.end())
445 SF_LOG_ERROR("misc", "InstanceSaveManager::ScheduleReset: cannot cancel the reset, the event(%d, %d, %d) was not found!", event.type, event.mapid, event.instanceId);
446 }
447 }
448 else
449 m_resetTimeQueue.insert(std::pair<time_t, InstResetEvent>(time, event));
450}
451
453{
454 time_t now = time(NULL);
455 time_t t;
456
457 while (!m_resetTimeQueue.empty())
458 {
459 t = m_resetTimeQueue.begin()->first;
460 if (t >= now)
461 break;
462
463 InstResetEvent& event = m_resetTimeQueue.begin()->second;
464 if (event.type == 0)
465 {
466 // for individual normal instances, max creature respawn + X hours
467 _ResetInstance(event.mapid, event.instanceId);
468 m_resetTimeQueue.erase(m_resetTimeQueue.begin());
469 }
470 else
471 {
472 // global reset/warning for a certain map
473 time_t resetTime = GetResetTimeFor(event.mapid, event.difficulty);
474 _ResetOrWarnAll(event.mapid, event.difficulty, event.type != 4, resetTime);
475 if (event.type != 4)
476 {
477 // schedule the next warning/reset
478 ++event.type;
479 ScheduleReset(true, resetTime - ResetTimeDelay[event.type - 1], event);
480 }
481 m_resetTimeQueue.erase(m_resetTimeQueue.begin());
482 }
483 }
484}
485
486void InstanceSaveManager::_ResetSave(InstanceSaveHashMap::iterator& itr)
487{
488 // unbind all players bound to the instance
489 // do not allow UnbindInstance to automatically unload the InstanceSaves
490 lock_instLists = true;
491
492 InstanceSave::PlayerListType& pList = itr->second->m_playerList;
493 while (!pList.empty())
494 {
495 Player* player = *(pList.begin());
496 player->UnbindInstance(itr->second->GetMapId(), itr->second->GetDifficulty(), true);
497 }
498
499 InstanceSave::GroupListType& gList = itr->second->m_groupList;
500 while (!gList.empty())
501 {
502 Group* group = *(gList.begin());
503 group->UnbindInstance(itr->second->GetMapId(), itr->second->GetDifficulty(), true);
504 }
505
506 delete itr->second;
507 m_instanceSaveById.erase(itr++);
508
509 lock_instLists = false;
510}
511
513{
514 SF_LOG_DEBUG("maps", "InstanceSaveMgr::_ResetInstance %u, %u", mapid, instanceId);
515 Map const* map = sMapMgr->CreateBaseMap(mapid);
516 if (!map->Instanceable())
517 return;
518
519 InstanceSaveHashMap::iterator itr = m_instanceSaveById.find(instanceId);
520 if (itr != m_instanceSaveById.end())
521 _ResetSave(itr);
522
523 DeleteInstanceFromDB(instanceId); // even if save not loaded
524
525 Map* iMap = ((MapInstanced*)map)->FindInstanceMap(instanceId);
526
527 if (iMap && iMap->IsInstance())
529
530 if (iMap)
531 iMap->DeleteRespawnTimes();
532 else
533 Map::DeleteRespawnTimesInDB(mapid, instanceId);
534
535 // Free up the instance id and allow it to be reused
536 sMapMgr->FreeInstanceId(instanceId);
537}
538
539void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, DifficultyID difficulty, bool warn, time_t resetTime)
540{
541 // global reset for all instances of the given map
542 MapEntry const* mapEntry = sMapStore.LookupEntry(mapid);
543 if (!mapEntry->Instanceable())
544 return;
545
546 time_t now = time(NULL);
547
548 if (!warn)
549 {
550 MapDifficulty const* mapDiff = GetMapDifficultyData(mapid, difficulty);
551 if (!mapDiff || !mapDiff->resetTime)
552 {
553 SF_LOG_ERROR("misc", "InstanceSaveManager::ResetOrWarnAll: not valid difficulty or no reset delay for map %d", mapid);
554 return;
555 }
556
557 // remove all binds to instances of the given map
558 for (InstanceSaveHashMap::iterator itr = m_instanceSaveById.begin(); itr != m_instanceSaveById.end();)
559 {
560 if (itr->second->GetMapId() == mapid && itr->second->GetDifficulty() == difficulty)
561 _ResetSave(itr);
562 else
563 ++itr;
564 }
565
566 // delete them from the DB, even if not loaded
567 SQLTransaction trans = CharacterDatabase.BeginTransaction();
568
570 stmt->setUInt16(0, uint16(mapid));
571 stmt->setUInt8(1, uint8(difficulty));
572 trans->Append(stmt);
573
574 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GROUP_INSTANCE_BY_MAP_DIFF);
575 stmt->setUInt16(0, uint16(mapid));
576 stmt->setUInt8(1, uint8(difficulty));
577 trans->Append(stmt);
578
579 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INSTANCE_BY_MAP_DIFF);
580 stmt->setUInt16(0, uint16(mapid));
581 stmt->setUInt8(1, uint8(difficulty));
582 trans->Append(stmt);
583
584 CharacterDatabase.CommitTransaction(trans);
585
586 // calculate the next reset time
588
589 uint32 period = uint32(((mapDiff->resetTime * sWorld->getRate(Rates::RATE_INSTANCE_RESET_TIME)) / uint32(DAY)) * uint32(DAY));
590 if (period < DAY)
591 period = DAY;
592
593 uint32 next_reset = uint32(((resetTime + MINUTE) / DAY * DAY) + period + diff);
594
595 SetResetTimeFor(mapid, difficulty, next_reset);
596 ScheduleReset(true, time_t(next_reset - 3600), InstResetEvent(1, mapid, difficulty, 0));
597
598 // Update it in the DB
599 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GLOBAL_INSTANCE_RESETTIME);
600
601 stmt->setUInt32(0, next_reset);
602 stmt->setUInt16(1, uint16(mapid));
603 stmt->setUInt8(2, uint8(difficulty));
604
605 CharacterDatabase.Execute(stmt);
606 }
607
608 // note: this isn't fast but it's meant to be executed very rarely
609 Map const* map = sMapMgr->CreateBaseMap(mapid); // _not_ include difficulty
610 MapInstanced::InstancedMaps& instMaps = ((MapInstanced*)map)->GetInstancedMaps();
611 MapInstanced::InstancedMaps::iterator mitr;
612 uint32 timeLeft;
613
614 for (mitr = instMaps.begin(); mitr != instMaps.end(); ++mitr)
615 {
616 Map* map2 = mitr->second;
617 if (!map2->IsInstance())
618 continue;
619
620 if (warn)
621 {
622 if (now <= resetTime)
623 timeLeft = 0;
624 else
625 timeLeft = uint32(now - resetTime);
626
627 ((InstanceMap*)map2)->SendResetWarnings(timeLeft);
628 }
629 else
631 }
632
634}
635
637{
638 uint32 ret = 0;
639 for (InstanceSaveHashMap::iterator itr = m_instanceSaveById.begin(); itr != m_instanceSaveById.end(); ++itr)
640 ret += itr->second->GetPlayerCount();
641
642 return ret;
643}
644
646{
647 uint32 ret = 0;
648 for (InstanceSaveHashMap::iterator itr = m_instanceSaveById.begin(); itr != m_instanceSaveById.end(); ++itr)
649 ret += itr->second->GetGroupCount();
650
651 return ret;
652}
@ CHAR_UPD_GLOBAL_INSTANCE_RESETTIME
@ CHAR_SEL_MAX_CREATURE_RESPAWNS
@ CHAR_DEL_CHAR_INSTANCE_BY_MAP_DIFF
@ CHAR_DEL_GROUP_INSTANCE_BY_INSTANCE
@ CHAR_INS_INSTANCE_SAVE
@ CHAR_DEL_GROUP_INSTANCE_BY_MAP_DIFF
@ CHAR_DEL_INSTANCE_BY_INSTANCE
@ CHAR_DEL_CHAR_INSTANCE_BY_INSTANCE
@ CHAR_DEL_INSTANCE_BY_MAP_DIFF
@ CHAR_UPD_INSTANCE_RESETTIME
@ MINUTE
Definition Common.h:119
@ HOUR
Definition Common.h:120
@ DAY
Definition Common.h:121
@ MAP_RAID
Definition DBCEnums.h:395
DifficultyID
Definition DBCEnums.h:330
@ DIFFICULTY_NORMAL
Definition DBCEnums.h:332
@ DIFFICULTY_HEROIC
Definition DBCEnums.h:333
MapDifficulty const * GetMapDifficultyData(uint32 mapId, DifficultyID difficulty)
MapDifficultyMap sMapDifficultyMap
DBCStorage< MapEntry > sMapStore(MapEntryfmt)
#define UI64FMTD
Definition Define.h:64
std::uint8_t uint8
Definition Define.h:79
std::uint32_t uint32
Definition Define.h:77
std::uint64_t uint64
Definition Define.h:76
std::uint16_t uint16
Definition Define.h:78
#define ASSERT
Definition Errors.h:29
#define sInstanceSaveMgr
#define SF_LOG_DEBUG(filterType__,...)
Definition Log.h:134
#define SF_LOG_ERROR(filterType__,...)
Definition Log.h:143
#define SF_LOG_INFO(filterType__,...)
Definition Log.h:137
@ INSTANCE_RESET_GLOBAL
Definition Map.h:630
@ INSTANCE_RESET_RESPAWN_DELAY
Definition Map.h:633
#define sMapMgr
Definition MapManager.h:145
uint32 MAKE_PAIR32(uint16 l, uint16 h)
uint16 PAIR32_HIPART(uint32 x)
uint16 PAIR32_LOPART(uint32 x)
#define sObjectMgr
Definition ObjectMgr.h:1617
Skyfire::AutoPtr< PreparedResultSet, Skyfire::Mutex > PreparedQueryResult
Definition QueryResult.h:94
Skyfire::AutoPtr< ResultSet, Skyfire::Mutex > QueryResult
Definition QueryResult.h:48
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition Timer.h:22
uint32 getMSTime()
Definition Timer.h:12
Skyfire::AutoPtr< Transaction, Skyfire::Mutex > SQLTransaction
Definition Transaction.h:42
Definition Field.h:16
uint8 GetUInt8() const
Definition Field.h:26
uint16 GetUInt16() const
Definition Field.h:69
uint32 GetUInt32() const
Definition Field.h:105
Definition Group.h:147
void UnbindInstance(uint32 mapid, uint8 difficulty, bool unload=false)
Definition Group.cpp:2459
DifficultyID GetDifficulty() const
DifficultyID m_difficulty
InstanceTemplate const * GetTemplate()
MapEntry const * GetMapEntry()
time_t GetResetTimeForDB()
uint32 GetInstanceId() const
std::list< Group * > GroupListType
uint32 GetMapId() const
PlayerListType m_playerList
std::list< Player * > PlayerListType
InstanceSave(uint16 MapId, uint32 InstanceId, DifficultyID difficulty, time_t resetTime, bool canReset)
GroupListType m_groupList
time_t GetResetTime() const
InstanceSave * GetInstanceSave(uint32 InstanceId)
static void DeleteInstanceFromDB(uint32 instanceid)
void SetResetTimeFor(uint32 mapid, DifficultyID d, time_t t)
void _ResetInstance(uint32 mapid, uint32 instanceId)
InstanceSaveHashMap m_instanceSaveById
static uint16 ResetTimeDelay[]
friend class InstanceSave
void RemoveInstanceSave(uint32 InstanceId)
void ScheduleReset(bool add, time_t time, InstResetEvent event)
void _ResetOrWarnAll(uint32 mapid, DifficultyID difficulty, bool warn, time_t resetTime)
InstanceSave * AddInstanceSave(uint32 mapId, uint32 instanceId, DifficultyID difficulty, time_t resetTime, bool canReset, bool load=false)
ResetTimeQueue m_resetTimeQueue
void _ResetSave(InstanceSaveHashMap::iterator &itr)
time_t GetResetTimeFor(uint32 mapid, DifficultyID d) const
Definition Map.h:238
static void DeleteRespawnTimesInDB(uint16 mapId, uint32 instanceId)
Definition Map.cpp:3313
void DeleteRespawnTimes()
Definition Map.cpp:3305
bool Instanceable() const
Definition Map.h:367
bool IsInstance() const
Definition Map.h:368
UNORDERED_MAP< uint32, Map * > InstancedMaps
void UnbindInstance(uint32 mapid, DifficultyID difficulty, bool unload=false)
Definition Player.cpp:13904
void setString(const uint8 index, const std::string &value)
void setUInt16(const uint8 index, const uint16 value)
void setUInt32(const uint8 index, const uint32 value)
void setUInt8(const uint8 index, const uint8 value)
CharacterDatabaseWorkerPool CharacterDatabase
Accessor to the character database.
Definition Main.cpp:41
#define sWorld
Definition World.h:910
@ CONFIG_INSTANCE_RESET_TIME_HOUR
Definition World.h:242
@ RATE_INSTANCE_RESET_TIME
Definition World.h:432
uint32 map_type
bool Instanceable() const