/* - adding instance into manager - called from InstanceMap::Add, _LoadBoundInstances, LoadGroups */ InstanceSave* InstanceSaveManager::AddInstanceSave(uint32 mapId, uint32 instanceId, uint8 difficulty, time_t resetTime, bool canReset, bool load) { InstanceSave *save = GetInstanceSave(instanceId); if(save) return save; const MapEntry* entry = sMapStore.LookupEntry(mapId); if(!entry || instanceId == 0) { sLog.outError("InstanceSaveManager::AddInstanceSave: mapid = %d, instanceid = %d!", mapId, instanceId); return NULL; } if(!resetTime) { // 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 == DIFFICULTY_HEROIC) resetTime = GetResetTimeFor(mapId); else { resetTime = time(NULL) + 2 * HOUR; // normally this will be removed soon after in InstanceMap::Add, prevent error ScheduleReset(true, resetTime, InstResetEvent(0, mapId, instanceId)); } } sLog.outDebug("InstanceSaveManager::AddInstanceSave: mapid = %d, instanceid = %d", mapId, instanceId); save = new InstanceSave(mapId, instanceId, difficulty, resetTime, canReset); if(!load) save->SaveToDB(); m_instanceSaveById[instanceId] = save; return save; }
void InstanceSaveManager::UnloadInstanceSave(uint32 InstanceId) { if (InstanceSave* save = GetInstanceSave(InstanceId)) { save->UnloadIfEmpty(); if (save->m_toDelete) delete save; } }
/* - adding instance into manager - called from InstanceMap::Add, _LoadBoundInstances, LoadGroups */ InstanceSave* InstanceSaveManager::AddInstanceSave(uint32 mapId, uint32 instanceId, Difficulty difficulty, time_t resetTime, bool canReset, bool load) { if (InstanceSave *old_save = GetInstanceSave(instanceId)) return old_save; const MapEntry* entry = sMapStore.LookupEntry(mapId); if (!entry) { sLog->outError( "InstanceSaveManager::AddInstanceSave: wrong mapid = %d, instanceid = %d!", mapId, instanceId); return NULL; } if (instanceId == 0) { sLog->outError( "InstanceSaveManager::AddInstanceSave: mapid = %d, wrong instanceid = %d!", mapId, instanceId); return NULL; } if (difficulty >= (entry->IsRaid() ? MAX_RAID_DIFFICULTY : MAX_DUNGEON_DIFFICULTY)) { sLog->outError( "InstanceSaveManager::AddInstanceSave: mapid = %d, instanceid = %d, wrong dificalty %u!", mapId, instanceId, difficulty); return NULL; } if (!resetTime) { // 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); 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)); } } sLog->outDebug(LOG_FILTER_MAPS, "InstanceSaveManager::AddInstanceSave: mapid = %d, instanceid = %d", mapId, instanceId); InstanceSave *save = new InstanceSave(mapId, instanceId, difficulty, resetTime, canReset); if (!load) save->SaveToDB(); m_instanceSaveById[instanceId] = save; return save; }
/* - adding instance into manager - called from InstanceMap::Add, _LoadBoundInstances, LoadGroups */ InstanceSave* InstanceSaveManager::AddInstanceSave(uint32 mapId, uint32 instanceId, Difficulty difficulty, time_t resetTime, uint32 entranceId, bool canReset, bool load) { if (InstanceSave* old_save = GetInstanceSave(instanceId)) return old_save; const MapEntry* entry = sMapStore.LookupEntry(mapId); if (!entry) { TC_LOG_ERROR("misc", "InstanceSaveManager::AddInstanceSave: wrong mapid = %d, instanceid = %d!", mapId, instanceId); return NULL; } if (instanceId == 0) { TC_LOG_ERROR("misc", "InstanceSaveManager::AddInstanceSave: mapid = %d, wrong instanceid = %d!", mapId, instanceId); return NULL; } DifficultyEntry const* difficultyEntry = sDifficultyStore.LookupEntry(difficulty); if (!difficultyEntry || difficultyEntry->InstanceType != entry->InstanceType) { TC_LOG_ERROR("misc", "InstanceSaveManager::AddInstanceSave: mapid = %d, instanceid = %d, wrong dificalty %u!", mapId, instanceId, difficulty); return NULL; } if (entranceId && !sWorldSafeLocsStore.LookupEntry(entranceId)) { TC_LOG_WARN("misc", "InstanceSaveManager::AddInstanceSave: invalid entranceId = %d defined for instance save with mapid = %d, instanceid = %d!", entranceId, mapId, instanceId); entranceId = 0; } if (!resetTime) { // initialize reset time // for normal instances if no creatures are killed the instance will reset in two hours if (entry->IsRaid() || difficulty > DIFFICULTY_NORMAL) resetTime = 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)); } } TC_LOG_DEBUG("maps", "InstanceSaveManager::AddInstanceSave: mapid = %d, instanceid = %d", mapId, instanceId); InstanceSave* save = new InstanceSave(mapId, instanceId, difficulty, entranceId, resetTime, canReset); if (!load) save->SaveToDB(); m_instanceSaveById[instanceId] = save; return save; }
void InstanceSaveManager::LoadCharacterBinds() { lock_instLists = true; QueryResult result = CharacterDatabase.Query("SELECT guid, instance, permanent, extended FROM character_instance"); if (result) { do { Field* fields = result->Fetch(); uint32 guid = fields[0].GetUInt32(); uint32 instanceId = fields[1].GetUInt32(); bool perm = fields[2].GetBool(); bool extended = fields[3].GetBool(); if (InstanceSave* save = GetInstanceSave(instanceId)) { PlayerCreateBoundInstancesMaps(guid); InstancePlayerBind& bind = playerBindStorage[guid]->m[save->GetDifficulty()][save->GetMapId()]; if (bind.save) // pussywizard: another bind for the same map and difficulty! may happen because of mysql thread races { if (bind.perm) // already loaded perm -> delete currently checked one from db { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INSTANCE_BY_INSTANCE_GUID); stmt->setUInt32(0, guid); stmt->setUInt32(1, instanceId); CharacterDatabase.Execute(stmt); continue; } else // override temp bind by newest one { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INSTANCE_BY_INSTANCE_GUID); stmt->setUInt32(0, guid); stmt->setUInt32(1, bind.save->GetInstanceId()); CharacterDatabase.Execute(stmt); bind.save->RemovePlayer(guid, this); } } bind.save = save; bind.perm = perm; bind.extended = extended; save->AddPlayer(guid); if (perm) save->SetCanReset(false); } } while (result->NextRow()); } lock_instLists = false; }
void InstanceSaveManager::Update() { time_t now = time(NULL); time_t t, t2; while (!m_resetTimeQueue.empty()) { t = m_resetTimeQueue.begin()->first; if (t >= now) break; // if m_resetTime has new resetTime, then write it to Queue, not delete the active instance.. InstResetEvent &event = m_resetTimeQueue.begin()->second; time_t resetTime = GetResetTimeFor(event.mapid, event.difficulty); if (InstanceSave* save = GetInstanceSave(event.instanceId)) { if (t2 = save->GetResetTime()) if (t2 >= t) { m_resetTimeQueue.erase(m_resetTimeQueue.begin()); m_resetTimeQueue.insert(std::pair<time_t, InstResetEvent>(t2, event)); break; } } 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 _ResetOrWarnAll(event.mapid, event.difficulty, event.type != 4, resetTime); if (event.type != 4) { // schedule the next warning/reset ++event.type; ScheduleReset(true, resetTime - ResetTimeDelay[event.type - 1], event); } m_resetTimeQueue.erase(m_resetTimeQueue.begin()); } } }
/* - adding instance into manager */ InstanceSave* InstanceSaveManager::AddInstanceSave(uint32 mapId, uint32 instanceId, Difficulty difficulty, bool startup /*=false*/) { ASSERT(!GetInstanceSave(instanceId)); const MapEntry* entry = sMapStore.LookupEntry(mapId); if (!entry) { sLog->outError("InstanceSaveManager::AddInstanceSave: wrong mapid = %d, instanceid = %d!", mapId, instanceId); return NULL; } if (instanceId == 0) { sLog->outError("InstanceSaveManager::AddInstanceSave: mapid = %d, wrong instanceid = %d!", mapId, instanceId); return NULL; } if (difficulty >= (entry->IsRaid() ? MAX_RAID_DIFFICULTY : MAX_DUNGEON_DIFFICULTY)) { sLog->outError("InstanceSaveManager::AddInstanceSave: mapid = %d, instanceid = %d, wrong dificalty %u!", mapId, instanceId, difficulty); return NULL; } time_t resetTime, extendedResetTime; if (entry->map_type == MAP_RAID || difficulty > DUNGEON_DIFFICULTY_NORMAL) { resetTime = GetResetTimeFor(mapId, difficulty); extendedResetTime = GetExtendedResetTimeFor(mapId, difficulty); } else { resetTime = time(NULL) + 3*DAY; // normals expire after 3 days even if someone is still bound to them, cleared on startup extendedResetTime = 0; } InstanceSave* save = new InstanceSave(mapId, instanceId, difficulty, resetTime, extendedResetTime); if (!startup) save->InsertToDB(); m_instanceSaveById[instanceId] = save; return save; }
bool InstanceSaveManager::DeleteInstanceSaveIfNeeded(uint32 InstanceId, bool skipMapCheck) { return DeleteInstanceSaveIfNeeded(GetInstanceSave(InstanceId), skipMapCheck); }
void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, bool warn, time_t resetTime) { // global reset for all instances of the given map MapEntry const* mapEntry = sMapStore.LookupEntry(mapid); if (!mapEntry->Instanceable()) return; time_t now = time(NULL); if (!warn) { MapDifficulty const* mapDiff = GetMapDifficultyData(mapid, difficulty); if (!mapDiff || !mapDiff->resetTime) { sLog->outError("InstanceSaveManager::ResetOrWarnAll: not valid difficulty or no reset delay for map %d", mapid); return; } // calculate the next reset time uint32 diff = sWorld->getIntConfig(CONFIG_INSTANCE_RESET_TIME_HOUR) * HOUR; uint32 period = uint32(((mapDiff->resetTime * sWorld->getRate(RATE_INSTANCE_RESET_TIME))/DAY) * DAY); if (period < DAY) period = DAY; uint32 next_reset = uint32(((resetTime + MINUTE) / DAY * DAY) + period + diff); SetResetTimeFor(mapid, difficulty, next_reset); SetExtendedResetTimeFor(mapid, difficulty, next_reset + period); ScheduleReset(time_t(next_reset-3600), InstResetEvent(1, mapid, difficulty)); // update it in the DB PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GLOBAL_INSTANCE_RESETTIME); stmt->setUInt32(0, next_reset); stmt->setUInt16(1, uint16(mapid)); stmt->setUInt8(2, uint8(difficulty)); CharacterDatabase.Execute(stmt); // remove all binds to instances of the given map and delete from db (delete per instance id, no mass deletion!) // do this after new reset time is calculated for (InstanceSaveHashMap::iterator itr = m_instanceSaveById.begin(), itr2; itr != m_instanceSaveById.end(); ) { itr2 = itr++; if (itr2->second->GetMapId() == mapid && itr2->second->GetDifficulty() == difficulty) _ResetSave(itr2); } } // now loop all existing maps to warn / reset Map const* map = sMapMgr->CreateBaseMap(mapid); MapInstanced::InstancedMaps &instMaps = ((MapInstanced*)map)->GetInstancedMaps(); MapInstanced::InstancedMaps::iterator mitr; uint32 timeLeft; for (mitr = instMaps.begin(); mitr != instMaps.end(); ++mitr) { Map* map2 = mitr->second; if (!map2->IsDungeon() || map2->GetDifficulty() != difficulty) continue; if (warn) { if (now >= resetTime) timeLeft = 0; else timeLeft = uint32(resetTime - now); map2->ToInstanceMap()->SendResetWarnings(timeLeft); } else { InstanceSave* save = GetInstanceSave(map2->GetInstanceId()); map2->ToInstanceMap()->Reset(INSTANCE_RESET_GLOBAL, (save ? &(save->m_playerList) : NULL)); } } }
void InstanceSaveManager::UnloadInstanceSave(uint32 InstanceId) { if (InstanceSave* save = GetInstanceSave(InstanceId)) save->UnloadIfEmpty(); }