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