/** Rewinds to the specified time, then goes forward till the current
 *  World::getTime() is reached again: it will replay everything before
 *  World::getTime(), but not the events at World::getTime() (or later)/
 *  \param rewind_ticks Time to rewind to.
 *  \param now_ticks Up to which ticks events are replayed: up to but 
 *         EXCLUDING new_ticks (the event at now_ticks are played in
 *         the calling subroutine playEventsTill).
 */
void RewindManager::rewindTo(int rewind_ticks, int now_ticks)
{
    assert(!m_is_rewinding);
    bool is_history = history->replayHistory();
    history->setReplayHistory(false);

    // First save all current transforms so that the error
    // can be computed between the transforms before and after
    // the rewind.
    AllRewinder::iterator rewinder;
    for (rewinder = m_all_rewinder.begin();
        rewinder != m_all_rewinder.end(); ++rewinder)
    {
        (*rewinder)->saveTransform();
    }

    // Then undo the rewind infos going backwards in time
    // --------------------------------------------------
    m_is_rewinding = true;

    // This will go back till the first confirmed state is found before
    // the specified rewind ticks.
    int exact_rewind_ticks = m_rewind_queue.undoUntil(rewind_ticks);

    // Rewind the required state(s)
    // ----------------------------
    World *world = World::getWorld();

    // Now start the rewind with the full state:
    world->setTicks(exact_rewind_ticks);

    // Get the (first) full state to which we have to rewind
    RewindInfo *current = m_rewind_queue.getCurrent();
    assert(current->isState());

    // Restore states from the exact rewind time
    // -----------------------------------------
    // A loop in case that we should split states into several smaller ones:
    while (current && current->getTicks() == exact_rewind_ticks && 
          current->isState()                                        )
    {
        current->rewind();
        m_rewind_queue.next();
        current = m_rewind_queue.getCurrent();
    }

    // Now go forward through the list of rewind infos till we reach 'now':
    while(world->getTimeTicks() < now_ticks )
    { 
        m_rewind_queue.replayAllEvents(world->getTimeTicks());

        // Now simulate the next time step
        world->updateWorld(1);
#undef SHOW_ROLLBACK
#ifdef SHOW_ROLLBACK
        irr_driver->update(stk_config->ticks2Time(1));
#endif
        world->updateTime(1);

    }   // while (world->getTicks() < current_ticks)

    // Now compute the errors which need to be visually smoothed
    for (rewinder = m_all_rewinder.begin();
        rewinder != m_all_rewinder.end(); ++rewinder)
    {
        (*rewinder)->computeError();
    }

    history->setReplayHistory(is_history);
    m_is_rewinding = false;
}   // rewindTo
Ejemplo n.º 2
0
/** Rewinds to the specified time, then goes forward till the current
 *  World::getTime() is reached again: it will replay everything before
 *  World::getTime(), but not the events at World::getTime() (or later)/
 *  \param rewind_ticks Time to rewind to.
 *  \param now_ticks Up to which ticks events are replayed: up to but 
 *         EXCLUDING new_ticks (the event at now_ticks are played in
 *         the calling subroutine playEventsTill).
 *  \param fast_forward If true, then only rewinders in network will be
 *  updated, but not the physics.
 */
void RewindManager::rewindTo(int rewind_ticks, int now_ticks,
                             bool fast_forward)
{
    assert(!m_is_rewinding);
    bool is_history = history->replayHistory();
    history->setReplayHistory(false);

    // First save all current transforms so that the error
    // can be computed between the transforms before and after
    // the rewind.
    for (auto& p : m_all_rewinder)
    {
        if (auto r = p.second.lock())
            r->saveTransform();
    }

    // Then undo the rewind infos going backwards in time
    // --------------------------------------------------
    m_is_rewinding = true;

    // This will go back till the first confirmed state is found before
    // the specified rewind ticks.
    int exact_rewind_ticks = m_rewind_queue.undoUntil(rewind_ticks);

    // Rewind the required state(s)
    // ----------------------------
    World *world = World::getWorld();

    // Now start the rewind with the full state. It is important that the
    // world time is set first, since e.g. the NetworkItem manager relies
    // on having the access to the 'confirmed' state time using 
    // the world timer.
    world->setTicksForRewind(exact_rewind_ticks);

    // Get the (first) full state to which we have to rewind
    RewindInfo *current = m_rewind_queue.getCurrent();
    assert(current->isState());

    // Restore states from the exact rewind time
    // -----------------------------------------
    auto it = m_local_state.find(exact_rewind_ticks);
    if (it != m_local_state.end())
    {
        for (auto& restore_local_state : it->second)
        {
            if (restore_local_state)
                restore_local_state();
        }
        for (auto it = m_local_state.begin(); it != m_local_state.end();)
        {
            if (it->first <= exact_rewind_ticks)
                it = m_local_state.erase(it);
            else
                break;
        }
    }
    else if (!fast_forward)
    {
        Log::warn("RewindManager", "Missing local state at ticks %d",
            exact_rewind_ticks);
    }

    // A loop in case that we should split states into several smaller ones:
    while (current && current->getTicks() == exact_rewind_ticks && 
           current->isState()                                        )
    {
        current->restore();
        m_rewind_queue.next();
        current = m_rewind_queue.getCurrent();
    }

    // Now go forward through the list of rewind infos till we reach 'now':
    while (world->getTicksSinceStart() < now_ticks)
    { 
        m_rewind_queue.replayAllEvents(world->getTicksSinceStart());

        // Now simulate the next time step
        if (!fast_forward)
            world->updateWorld(1);
#undef SHOW_ROLLBACK
#ifdef SHOW_ROLLBACK
        irr_driver->update(stk_config->ticks2Time(1));
#endif
        world->updateTime(1);

    }   // while (world->getTicks() < current_ticks)

    // Now compute the errors which need to be visually smoothed
    for (auto& p : m_all_rewinder)
    {
        if (auto r = p.second.lock())
            r->computeError();
    }

    history->setReplayHistory(is_history);
    m_is_rewinding = false;
    mergeRewindInfoEventFunction();
}   // rewindTo