예제 #1
0
void MapPersistentStateManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, bool warn, uint32 timeLeft)
{
    // 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("MapPersistentStateManager::ResetOrWarnAll: not valid difficulty or no reset delay for map %d", mapid);
            return;
        }

        // remove all binds to instances of the given map
        for(PersistentStateMap::iterator itr = m_instanceSaveByInstanceId.begin(); itr != m_instanceSaveByInstanceId.end();)
        {
            if (itr->second->GetMapId() == mapid && itr->second->GetDifficulty() == difficulty)
                _ResetSave(m_instanceSaveByInstanceId, itr);
            else
                ++itr;
        }

        // delete them from the DB, even if not loaded
        CharacterDatabase.BeginTransaction();
        CharacterDatabase.PExecute("DELETE FROM character_instance USING character_instance LEFT JOIN instance ON character_instance.instance = id WHERE map = '%u'", mapid);
        CharacterDatabase.PExecute("DELETE FROM group_instance USING group_instance LEFT JOIN instance ON group_instance.instance = id WHERE map = '%u'", mapid);
        CharacterDatabase.PExecute("DELETE FROM instance WHERE map = '%u'", mapid);
        CharacterDatabase.CommitTransaction();

        // calculate the next reset time
        time_t next_reset = DungeonResetScheduler::CalculateNextResetTime(mapDiff, now + timeLeft);
        // update it in the DB
        CharacterDatabase.PExecute("UPDATE instance_reset SET resettime = '%u' WHERE mapid = '%u' AND difficulty = '%u'", (uint64)next_reset, mapid, difficulty);
        m_Scheduler.SetResetTimeFor(mapid,difficulty,(time_t)next_reset);
        m_Scheduler.ScheduleReset(true, next_reset-3600, DungeonResetEvent(RESET_EVENT_INFORM_1, mapid, difficulty, 0));
    }

    // note: this isn't fast but it's meant to be executed very rarely
    const MapManager::MapMapType& maps = sMapMgr.Maps();

    MapManager::MapMapType::const_iterator iter_last = maps.lower_bound(MapID(mapid + 1));
    for(MapManager::MapMapType::const_iterator mitr = maps.lower_bound(MapID(mapid)); mitr != iter_last; ++mitr)
    {
        Map *map2 = mitr->second;
        if(map2->GetId() != mapid)
            break;

        if (warn)
            ((DungeonMap*)map2)->SendResetWarnings(timeLeft);
        else
            ((DungeonMap*)map2)->Reset(INSTANCE_RESET_GLOBAL);
    }
}
예제 #2
0
/*
- adding instance into manager
- called from DungeonMap::Add, _LoadBoundInstances, LoadGroups
*/
MapPersistentState* MapPersistentStateManager::AddPersistentState(MapEntry const* mapEntry, uint32 instanceId, Difficulty difficulty, time_t resetTime, bool canReset, bool load /*=false*/, bool initPools /*= true*/, uint32 completedEncountersMask /*= 0*/)
{
    if (MapPersistentState *old_save = GetPersistentState(mapEntry->MapID, instanceId))
        return old_save;

    if (mapEntry->IsDungeon())
    {
        if (!resetTime || resetTime < time(NULL))
        {
            // initialize reset time
            // for normal instances if no creatures are killed the instance will reset in two hours
            if (mapEntry->map_type == MAP_RAID || difficulty > DUNGEON_DIFFICULTY_NORMAL)
                resetTime = m_Scheduler.GetResetTimeFor(mapEntry->MapID, difficulty);
            else
            {
                resetTime = time(NULL) + 2 * HOUR;
                // normally this will be removed soon after in DungeonMap::Add, prevent error
                m_Scheduler.ScheduleReset(true, resetTime, DungeonResetEvent(RESET_EVENT_NORMAL_DUNGEON, mapEntry->MapID, difficulty, instanceId));
            }
        }
    }

    DEBUG_LOG("MapPersistentStateManager::AddPersistentState: mapid = %d, instanceid = %d, reset time = '" UI64FMTD "', canRset = %u", mapEntry->MapID, instanceId, uint64(resetTime), canReset ? 1 : 0);

    MapPersistentState* state = NULL;
    if (mapEntry->IsDungeon() && instanceId)
    {
        DungeonPersistentState* dungeonState = new DungeonPersistentState(mapEntry->MapID, instanceId, difficulty, resetTime, canReset, completedEncountersMask);
        if (!load)
            dungeonState->SaveToDB();
        state = dungeonState;
    }
    else if (mapEntry->IsBattleGroundOrArena())
        state = new BattleGroundPersistentState(mapEntry->MapID, instanceId, difficulty);
    else if (!instanceId)
        state = new WorldPersistentState(mapEntry->MapID);
    else
    {
        sLog.outError("MapPersistentStateManager::AddPersistentState cannot create persistent state for mapid = %d, instanceid = %d, reset time = %ld, canReset = %u", mapEntry->MapID, instanceId, resetTime, canReset ? 1 : 0);
        return state;
    }


    if (state && instanceId)
        m_instanceSaveByInstanceId[instanceId] = state;
    else if (state && !instanceId)
        m_instanceSaveByMapId[mapEntry->MapID] = state;

    if (state && initPools)
        state->InitPools();

    if (state)
        sWorldStateMgr.CreateInstanceState(mapEntry->MapID, instanceId);

    return state;
}
예제 #3
0
/*
- adding instance into manager
- called from DungeonMap::Add, _LoadBoundInstances, LoadGroups
*/
MapPersistentState* MapPersistentStateManager::AddPersistentState(MapEntry const* mapEntry, uint32 instanceId, time_t resetTime, bool canReset, bool load /*=false*/, bool initPools /*= true*/)
{
    if (MapPersistentState *old_save = GetPersistentState(mapEntry->MapID, instanceId))
        return old_save;

    if (mapEntry->IsDungeon())
    {
        if (!resetTime)
        {
            // initialize reset time
            // for normal instances if no creatures are killed the instance will reset in two hours
            if(mapEntry->map_type == MAP_RAID)
                resetTime = m_Scheduler.GetResetTimeFor(mapEntry->MapID);
            else
            {
                resetTime = time(NULL) + 2 * HOUR;
                // normally this will be removed soon after in DungeonMap::Add, prevent error
                m_Scheduler.ScheduleReset(true, resetTime, DungeonResetEvent(RESET_EVENT_NORMAL_DUNGEON, mapEntry->MapID, instanceId));
            }
        }
    }

    DEBUG_LOG("MapPersistentStateManager::AddPersistentState: mapid = %d, instanceid = %d, reset time = %u, canRset = %u", mapEntry->MapID, instanceId, resetTime, canReset ? 1 : 0);

    MapPersistentState *state;
    if (mapEntry->IsDungeon())
    {
        DungeonPersistentState* dungeonState = new DungeonPersistentState(mapEntry->MapID, instanceId, resetTime, canReset);
        if (!load)
            dungeonState->SaveToDB();
        state = dungeonState;
    }
    else if (mapEntry->IsBattleGround())
        state = new BattleGroundPersistentState(mapEntry->MapID, instanceId);
    else
        state = new WorldPersistentState(mapEntry->MapID);

    if (instanceId)
        m_instanceSaveByInstanceId[instanceId] = state;
    else
        m_instanceSaveByMapId[mapEntry->MapID] = state;

    if (initPools)
        state->InitPools();

    return state;
}
예제 #4
0
void DungeonResetScheduler::LoadResetTimes()
{
    time_t now = time(nullptr);
    time_t today = (now / DAY) * DAY;
    time_t nextWeek = today + (7 * 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::map<uint32, std::pair<uint32, time_t> > ResetTimeMapType;
    ResetTimeMapType InstResetTime;

    QueryResult* result = CharacterDatabase.Query("SELECT id, map, resettime FROM instance WHERE resettime > 0");
    if (result)
    {
        do
        {
            if (time_t resettime = time_t((*result)[2].GetUInt64()))
            {
                uint32 id = (*result)[0].GetUInt32();
                uint32 mapid = (*result)[1].GetUInt32();

                MapEntry const* mapEntry = sMapStore.LookupEntry(mapid);

                if (!mapEntry || !mapEntry->IsDungeon())
                {
                    sMapPersistentStateMgr.DeleteInstanceFromDB(id);
                    continue;
                }

                InstResetTime[id] = std::pair<uint32, uint64>(mapid, resettime);
            }
        }
        while (result->NextRow());
        delete result;

        // update reset time for normal instances with the max creature respawn time + X hours
        result = CharacterDatabase.Query("SELECT MAX(respawntime), instance FROM creature_respawn WHERE instance > 0 GROUP BY instance");
        if (result)
        {
            do
            {
                Field* fields = result->Fetch();

                time_t resettime    = time_t(fields[0].GetUInt64() + 2 * HOUR);
                uint32 instance     = fields[1].GetUInt32();

                ResetTimeMapType::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 (ResetTimeMapType::iterator itr = InstResetTime.begin(); itr != InstResetTime.end(); ++itr)
            if (itr->second.second > now)
                ScheduleReset(true, itr->second.second, DungeonResetEvent(RESET_EVENT_NORMAL_DUNGEON, 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;
    m_resetTimeByMapId.resize(sMapStore.GetNumRows() + 1);
    result = CharacterDatabase.Query("SELECT mapid, resettime FROM instance_reset");
    if (result)
    {
        do
        {
            Field* fields = result->Fetch();

            uint32 mapid            = fields[0].GetUInt32();

            MapEntry const* mapEntry = sMapStore.LookupEntry(mapid);

            if (!mapEntry || !mapEntry->IsDungeon() || !ObjectMgr::GetInstanceTemplate(mapid))
            {
                sLog.outError("MapPersistentStateManager::LoadResetTimes: invalid mapid %u in instance_reset!", mapid);
                CharacterDatabase.DirectPExecute("DELETE FROM instance_reset WHERE mapid = '%u'", mapid);
                continue;
            }

            // update the reset time if the hour in the configs changes
            uint64 oldresettime = fields[1].GetUInt64();
            uint64 newresettime = (oldresettime / DAY) * DAY + diff;
            if (oldresettime != newresettime)
                CharacterDatabase.DirectPExecute("UPDATE instance_reset SET resettime = '" UI64FMTD "' WHERE mapid = '%u'", newresettime, mapid);

            SetResetTimeFor(mapid, 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._CleanupExpiredInstancesAtTime(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 (uint32 i = 0; i < sInstanceTemplate.GetMaxEntry(); i++)
    {
        InstanceTemplate const* temp = ObjectMgr::GetInstanceTemplate(i);
        if (!temp)
            continue;

        // only raid/heroic maps have a global reset time
        MapEntry const* mapEntry = sMapStore.LookupEntry(temp->map);
        if (!mapEntry || !mapEntry->IsDungeon() || !mapEntry->HasResetTime())
            continue;

        uint32 period = GetMaxResetTimeFor(temp);
        time_t t = GetResetTimeFor(temp->map);
        if (!t)
        {
            // initialize the reset time
            // generate time by config on first server launch
            tm localTm = *localtime(&now);
            localTm.tm_hour = sWorld.getConfig(CONFIG_UINT32_QUEST_DAILY_RESET_HOUR);
            localTm.tm_min = 0;
            localTm.tm_sec = 0;
            if (period > DAY) // resets bigger than 1 day start on config day
                localTm.tm_mday += ((7 - localTm.tm_wday + sWorld.getConfig(CONFIG_UINT32_ARENA_FIRST_RESET_DAY)) % 7);
            else // resets day and less start on next day
                localTm.tm_mday += 1;
            localTm.tm_isdst = -1;
            t = mktime(&localTm);
            CharacterDatabase.DirectPExecute("INSERT INTO instance_reset VALUES ('%u','" UI64FMTD "')", temp->map, (uint64)t);
        }

        if (t < now || t > nextWeek)
        {
            // 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'", (uint64)t, temp->map);
        }

        SetResetTimeFor(temp->map, t);

        // schedule the global reset/warning
        ResetEventType type = RESET_EVENT_INFORM_1;
        for (; type < RESET_EVENT_INFORM_LAST; type = ResetEventType(type + 1))
            if (t > time_t(now + resetEventTypeDelay[type]))
                break;

        ScheduleReset(true, t - resetEventTypeDelay[type], DungeonResetEvent(type, temp->map, 0));
    }
}
예제 #5
0
void DungeonResetScheduler::LoadResetTimes()
{
    const time_t now = time(NULL);

    //time_t today = (now / DAY) * DAY;
    //time_t oldest_reset_time = now;

    // 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;

    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();

                MapEntry const* mapEntry = sMapStore.LookupEntry(mapid);
                MapDifficultyEntry const* mapDiff = GetMapDifficultyData(mapid,Difficulty(difficulty));

                if (!mapEntry || !mapEntry->IsDungeon() || !mapDiff)
                {
                    sMapPersistentStateMgr.DeleteInstanceFromDB(id);
                    continue;
                }
                //if in DBC no resettime - sedule resettime from DB
                if (!mapDiff->resetTime)
                    instResetTime[id] = ResetTimeMapDiffType(MAKE_PAIR32(mapid,difficulty), resettime);
            }
        }
        while (result->NextRow());
        delete result;

        // update reset time for normal instances with the max creature respawn time + X hours
        result = CharacterDatabase.Query("SELECT MAX(respawntime), instance FROM creature_respawn WHERE instance > 0 GROUP BY instance");
        if( result )
        {
            do
            {
                Field* fields = result->Fetch();

                time_t resettime    = time_t(fields[0].GetUInt64() + 2 * HOUR);
                uint32 instance     = fields[1].GetUInt32();

                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, DungeonResetEvent(RESET_EVENT_NORMAL_DUNGEON, 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();

            time_t oldresettime;
            uint32 mapid = fields[0].GetUInt32();
            Difficulty difficulty = Difficulty(fields[1].GetUInt32());
            uint64 _oldresettime = fields[2].GetUInt64();

            if (_oldresettime > uint64(time(NULL) + INSTANCE_MAX_RESET_OFFSET))
            {
                MapDifficultyEntry const* mapDiff = GetMapDifficultyData(mapid,Difficulty(difficulty));
                oldresettime = DungeonResetScheduler::CalculateNextResetTime(mapDiff);
                sLog.outErrorDb("Wrong reset time in group_instance corrected to: %ld", oldresettime);
            }
            else
                oldresettime = time_t(_oldresettime);

            MapEntry const* mapEntry = sMapStore.LookupEntry(mapid);

            if (!mapEntry || !mapEntry->IsDungeon() || !GetMapDifficultyData(mapid,difficulty))
            {
                sLog.outError("MapPersistentStateManager::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._CleanupExpiredInstancesAtTime(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));
        MapDifficultyEntry const* mapDiff = itr->second;

        // skip mapDiff without global reset time
        if (!mapDiff->resetTime)
            continue;

        MapEntry const* mapEntry = sMapStore.LookupEntry(mapid);
        if (!mapEntry || !mapEntry->IsDungeon())
            continue;

        //uint32 period = GetMaxResetTimeFor(mapDiff);

        time_t t = GetResetTimeFor(mapid,difficulty);

        if(!t || t < now)
        {
            t = CalculateNextResetTime(mapDiff);
            CharacterDatabase.DirectPExecute("REPLACE INTO instance_reset VALUES ('%u','%u','" UI64FMTD "')", mapid, difficulty, (uint64)t);
        }

        SetResetTimeFor(mapid,difficulty,t);

        // schedule the global reset/warning
        ResetEventType type = RESET_EVENT_INFORM_1;
        for (; type < RESET_EVENT_INFORM_LAST; type = ResetEventType(type + 1))
            if (t > time_t(now + resetEventTypeDelay[type]))
                break;

        ScheduleReset(true, t - resetEventTypeDelay[type], DungeonResetEvent(type, mapid, difficulty, 0));
    }
}
예제 #6
0
void MapPersistentStateManager::_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)
    {
        MapDifficultyEntry const* mapDiff = GetMapDifficultyData(mapid,difficulty);
        if (!mapDiff || !mapDiff->resetTime)
        {
            sLog.outError("MapPersistentStateManager::ResetOrWarnAll: not valid difficulty or no reset delay for map %d", mapid);
            return;
        }

        // remove all binds to instances of the given map
        for(PersistentStateMap::iterator itr = m_instanceSaveByInstanceId.begin(); itr != m_instanceSaveByInstanceId.end();)
        {
            if (itr->second->GetMapId() == mapid && itr->second->GetDifficulty() == difficulty)
            {
                if (!((DungeonPersistentState*)itr->second)->IsExtended())
                {
                    _ResetSave(m_instanceSaveByInstanceId, itr);
                    DeleteInstanceFromDB(itr->first, false);
                }
                else
                {
                    DeleteInstanceFromDB(itr->first, true);
                    ++itr;
                }
            }
            else
                ++itr;
        }

        // calculate the next reset time
        time_t next_reset = DungeonResetScheduler::CalculateNextResetTime(mapDiff, resetTime);
        // update it in the DB
        CharacterDatabase.PExecute("UPDATE instance_reset SET resettime = '%u' WHERE mapid = '%u' AND difficulty = '%u'", (uint64)next_reset, mapid, difficulty);
        m_Scheduler.SetResetTimeFor(mapid,difficulty,next_reset);
        m_Scheduler.ScheduleReset(true, next_reset-3600, DungeonResetEvent(RESET_EVENT_INFORM_1, mapid, difficulty, 0));
    }

    // note: this isn't fast but it's meant to be executed very rarely
    const MapManager::MapMapType& maps = sMapMgr.Maps();

    MapManager::MapMapType::const_iterator iter_last = maps.lower_bound(MapID(mapid + 1));
    for(MapManager::MapMapType::const_iterator mitr = maps.lower_bound(MapID(mapid)); mitr != iter_last; ++mitr)
    {
        Map *map2 = mitr->second;
        if(map2->GetId() != mapid)
            break;

        if ((DungeonPersistentState*)map2->GetPersistentState() && ((DungeonPersistentState*)map2->GetPersistentState())->IsExtended())
            break;

        if (warn)
            ((DungeonMap*)map2)->SendResetWarnings(resetTime - now);
        else
            ((DungeonMap*)map2)->Reset(INSTANCE_RESET_GLOBAL);
    }
}