diff --git a/src/karts/controller/kart_control.cpp b/src/karts/controller/kart_control.cpp index 9173d896a..97cf13c8c 100644 --- a/src/karts/controller/kart_control.cpp +++ b/src/karts/controller/kart_control.cpp @@ -18,6 +18,7 @@ #include "karts/controller/kart_control.hpp" +#include "network/protocols/game_protocol.hpp" #include "network/rewind_manager.hpp" @@ -46,23 +47,6 @@ void KartControl::rewind(BareNetworkString *buffer) } } // rewind -// ------------------------------------------------------------------------ -/** Sets this KartControl form the given value (basically a copy). This - * function uses the explicit setSteer() etc function, which means that - * rewind information will be collected. - */ -void KartControl::set(const KartControl &c) -{ - setAccel(c.getAccel()); - setBrake(c.getBrake()); - setFire(c.getFire()); - setLookBack(c.getLookBack()); - setNitro(c.getNitro()); - setRescue(c.getRescue()); - setSkidControl(c.getSkidControl()); - setSteer(c.getSteer()); -} // set - // ------------------------------------------------------------------------ /** Sets the current steering value. */ void KartControl::setSteer(float f) diff --git a/src/karts/controller/kart_control.hpp b/src/karts/controller/kart_control.hpp index c7865c16d..cbc7cda4c 100644 --- a/src/karts/controller/kart_control.hpp +++ b/src/karts/controller/kart_control.hpp @@ -61,7 +61,6 @@ public: void setRescue(bool b); void setFire(bool b); void setLookBack(bool b); - void set(const KartControl &c); // ------------------------------------------------------------------------ KartControl() diff --git a/src/karts/controller/local_player_controller.cpp b/src/karts/controller/local_player_controller.cpp index e53dd4c6f..9e5e661de 100644 --- a/src/karts/controller/local_player_controller.cpp +++ b/src/karts/controller/local_player_controller.cpp @@ -149,6 +149,10 @@ bool LocalPlayerController::action(PlayerAction action, int value, // optimises traffic to the server and other clients. if (!PlayerController::action(action, value, /*dry_run*/true)) return false; + // Register event with history + if(!history->replayHistory()) + history->addEvent(m_kart->getWorldKartId(), action, value); + // If this is a client, send the action to networking layer if (World::getWorld()->isNetworkWorld() && NetworkConfig::get()->isClient() && diff --git a/src/karts/controller/player_controller.cpp b/src/karts/controller/player_controller.cpp index af15445c1..49aaa7330 100644 --- a/src/karts/controller/player_controller.cpp +++ b/src/karts/controller/player_controller.cpp @@ -318,7 +318,7 @@ void PlayerController::update(float dt) // Don't do steering if it's replay. In position only replay it doesn't // matter, but if it's physics replay the gradual steering causes // incorrect results, since the stored values are already adjusted. - if (!history->replayHistory()) + if (!history->replayHistory() || !history->dontDoPhysics()) steer(dt, m_steer_val); if (World::getWorld()->getPhase() == World::GOAL_PHASE) diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp index 7790b2d9a..bd8008f24 100644 --- a/src/karts/kart.cpp +++ b/src/karts/kart.cpp @@ -1262,7 +1262,7 @@ void Kart::update(float dt) // is used furthermore for engine power, camera distance etc updateSpeed(); - if(!history->replayHistory()) + if(!history->replayHistory() || !history->dontDoPhysics()) m_controller->update(dt); #undef DEBUG_CAMERA_SHAKE diff --git a/src/main.cpp b/src/main.cpp index af2dc284a..47cc944ca 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1272,7 +1272,8 @@ int handleCmdLine() history->doReplayHistory( (History::HistoryReplayMode)n); // Force the no-start screen flag, since this initialises // the player structures correctly. - UserConfigParams::m_no_start_screen = true; + if(!MainMenuScreen::m_enable_online) + UserConfigParams::m_no_start_screen = true; } // --history=%d if(CommandLine::has("--history")) // handy default for --history=1 @@ -1780,13 +1781,17 @@ int main(int argc, char *argv[] ) { // This will setup the race manager etc. history->Load(); - race_manager->setupPlayerKartInfo(); - race_manager->startNew(false); - main_loop->run(); - // well, actually run() will never return, since - // it exits after replaying history (see history::GetNextDT()). - // So the next line is just to make this obvious here! - exit(-3); + if (!MainMenuScreen::m_enable_online) + { + race_manager->setupPlayerKartInfo(); + race_manager->startNew(false); + main_loop->run(); + // well, actually run() will never return, since + // it either loops or exits after replaying history (see + // history::updateReplayAndGetDT()). + // So the next line is just to make this obvious here! + exit(-3); + } // if !online } // Not replaying diff --git a/src/main_loop.cpp b/src/main_loop.cpp index e8683ecce..b2205ce19 100644 --- a/src/main_loop.cpp +++ b/src/main_loop.cpp @@ -64,13 +64,6 @@ MainLoop::~MainLoop() float MainLoop::getLimitedDt() { float dt = 0; - // If we are doing a replay, use the dt from the history file - if (World::getWorld() && history->replayHistory() ) - { - dt = history->updateReplayAndGetDT(); - return dt; - } - // In profile mode without graphics, run with a fixed dt of 1/60 if ((ProfileWorld::isProfileMode() && ProfileWorld::isNoGraphics()) || @@ -155,6 +148,14 @@ float MainLoop::getLimitedDt() { dt = World::getWorld()->adjustDT(dt); } + + // If we are doing a replay, use the dt from the history file if this + // is not networked, otherwise history will use current time and dt + // to findout which events to replay + if (World::getWorld() && history->replayHistory() ) + { + dt = history->updateReplayAndGetDT(World::getWorld()->getTime(), dt); + } return dt; } // getLimitedDt diff --git a/src/network/rewind_manager.cpp b/src/network/rewind_manager.cpp index d38665056..b52df770b 100755 --- a/src/network/rewind_manager.cpp +++ b/src/network/rewind_manager.cpp @@ -211,7 +211,6 @@ void RewindManager::update(float dt) PROFILER_PUSH_CPU_MARKER("RewindManager - send state", 0x20, 0x7F, 0x40); GameProtocol::getInstance()->sendState(); PROFILER_POP_CPU_MARKER(); - m_last_saved_state = time; } // update @@ -241,6 +240,7 @@ void RewindManager::playEventsTill(float time, float *dt) Log::setPrefix(""); TimeStepInfo *tsi = m_rewind_queue.getCurrent(); World::getWorld()->setTime(tsi->getTime()); + Physics::getInstance()->getPhysicsWorld()->resetLocalTime(); } // This is necessary to avoid that rewinding an event will store the @@ -275,6 +275,7 @@ void RewindManager::playEventsTill(float time, float *dt) void RewindManager::rewindTo(float rewind_time) { assert(!m_is_rewinding); + bool is_history = history->replayHistory(); history->doReplayHistory(History::HISTORY_NONE); // First save all current transforms so that the error @@ -316,6 +317,7 @@ void RewindManager::rewindTo(float rewind_time) if (World::getWorld()->getPhase() == WorldStatus::IN_GAME_MENU_PHASE) { m_is_rewinding = false; + history->doReplayHistory(History::HISTORY_PHYSICS); return; } @@ -351,8 +353,8 @@ void RewindManager::rewindTo(float rewind_time) { (*rewinder)->computeError(); } - - + if(is_history) + history->doReplayHistory(History::HISTORY_PHYSICS); m_is_rewinding = false; } // rewindTo diff --git a/src/race/history.cpp b/src/race/history.cpp index b53d762f1..c47414428 100644 --- a/src/race/history.cpp +++ b/src/race/history.cpp @@ -23,9 +23,12 @@ #include "io/file_manager.hpp" #include "modes/world.hpp" #include "karts/abstract_kart.hpp" +#include "karts/controller/controller.hpp" +#include "network/network_config.hpp" #include "network/rewind_manager.hpp" #include "physics/physics.hpp" #include "race/race_manager.hpp" +#include "states_screens/main_menu_screen.hpp" #include "tracks/track.hpp" #include "utils/constants.hpp" @@ -36,17 +39,10 @@ History* history = 0; */ History::History() { - m_replay_mode = HISTORY_NONE; + m_replay_mode = HISTORY_NONE; + m_history_time = 0.0f; } // History -//----------------------------------------------------------------------------- -/** Starts replay from the history file in the current directory. - */ -void History::startReplay() -{ - Load(); -} // startReplay - //----------------------------------------------------------------------------- /** Initialise the history for a new recording. It especially allocates memory * to store the history. @@ -56,9 +52,10 @@ void History::initRecording() unsigned int max_frames = (unsigned int)( stk_config->m_replay_max_time / stk_config->m_replay_dt ); allocateMemory(max_frames); - m_current = -1; - m_wrapped = false; - m_size = 0; + m_current = -1; + m_event_index = 0; + m_wrapped = false; + m_size = 0; } // initRecording //----------------------------------------------------------------------------- @@ -75,6 +72,24 @@ void History::allocateMemory(int number_of_frames) m_all_rotations.resize(number_of_frames*num_karts); } // allocateMemory +//----------------------------------------------------------------------------- +/** Stores an input event (e.g. acceleration or steering event) into the + * history data for physics replay. + * \param kart_id The kart index which triggered the event. + * \param pa The action. + * \param value Value of the action (0=release, 32768 = pressed), in + * between in case of analog devices. + */ +void History::addEvent(int kart_id, PlayerAction pa, int value) +{ + InputEvent ie; + ie.m_index = m_current; + ie.m_action = pa; + ie.m_value = value; + ie.m_kart_index = kart_id; + m_all_input_events.emplace_back(ie); +} // addEvent + //----------------------------------------------------------------------------- /** Saves the current history. * \param dt Time step size. @@ -109,44 +124,70 @@ void History::updateSaving(float dt) //----------------------------------------------------------------------------- /** Sets the kart position and controls to the recorded history value. - * \param dt Time step size. + * \return dt Time step size. */ -float History::updateReplayAndGetDT() +float History::updateReplayAndGetDT(float world_time, float dt) { - m_current++; + if (m_history_time >= world_time) return dt; World *world = World::getWorld(); - if(m_current>=(int)m_all_deltas.size()) + + do { - Log::info("History", "Replay finished"); - m_current = 0; - // This is useful to use a reproducable rewind problem: - // replay it with history, for debugging only + m_current++; + if (m_current >= (int)m_all_deltas.size()) + { + Log::info("History", "Replay finished"); + m_current = 0; + m_history_time = 0; + // This is useful to use a reproducable rewind problem: + // replay it with history, for debugging only #undef DO_REWIND_AT_END_OF_HISTORY #ifdef DO_REWIND_AT_END_OF_HISTORY - RewindManager::get()->rewindTo(5.0f); - exit(-1); + RewindManager::get()->rewindTo(5.0f); + exit(-1); #else - // Note that for physics replay all physics parameters - // need to be reset, e.g. velocity, ... - world->reset(); + // Note that for physics replay all physics parameters + // need to be reset, e.g. velocity, ... + world->reset(); #endif - } - unsigned int num_karts = world->getNumKarts(); - for(unsigned k=0; kgetKart(k); - unsigned int index=m_current*num_karts+k; - if(m_replay_mode==HISTORY_POSITION) - { - kart->setXYZ(m_all_xyz[index]); - kart->setRotation(m_all_rotations[index]); } - else + + unsigned int num_karts = world->getNumKarts(); + for (unsigned k = 0; k < num_karts; k++) { - kart->getControls().set(m_all_controls[index]); - } - } - return m_all_deltas[m_current]; + AbstractKart *kart = world->getKart(k); + unsigned int index = m_current*num_karts + k; + if (m_replay_mode == HISTORY_POSITION) + { + kart->setXYZ(m_all_xyz[index]); + kart->setRotation(m_all_rotations[index]); + } + else // HISTORY_PHYSICS + { + while (m_event_index < m_all_input_events.size() && + m_all_input_events[m_event_index].m_index == m_current) + { + const InputEvent &ie = m_all_input_events[m_event_index]; + AbstractKart *kart = world->getKart(ie.m_kart_index); + kart->getController()->action(ie.m_action, ie.m_value); + m_event_index++; + } + + //kart->getControls().set(m_all_controls[index]); + } + } // for k < num_karts + + m_history_time += m_all_deltas[m_current]; + + // If this is not networked, exit the loop after one iteration + // and return the new dt + if(!NetworkConfig::get()->isNetworking()) + return m_all_deltas[m_current]; + + } while (m_history_time < world_time + dt); + + // In network mode, don't adjust dt, just return the input value + return dt; } // updateReplayAndGetDT //----------------------------------------------------------------------------- @@ -175,7 +216,7 @@ void History::Save() World *world = World::getWorld(); const int num_karts = world->getNumKarts(); - fprintf(fd, "Version: %s\n", STK_VERSION); + fprintf(fd, "Version-1: %s\n", STK_VERSION); fprintf(fd, "numkarts: %d\n", num_karts); fprintf(fd, "numplayers: %d\n", race_manager->getNumPlayers()); fprintf(fd, "difficulty: %d\n", race_manager->getDifficulty()); @@ -199,24 +240,42 @@ void History::Save() index=(index+1)%m_size; } - index = num_karts * (m_wrapped ? m_current : 0); + index = m_wrapped ? m_current : 0; + int event_index = 0; for(int i=0; igetNumPlayers()) + if(igetNumPlayers() && !MainMenuScreen::m_enable_online) { race_manager->setPlayerKart(i, s1); } @@ -303,7 +370,8 @@ void History::Load() Log::fatal("History", "Number of records not found in history file."); allocateMemory(m_size); - m_current = -1; + m_current = -1; + m_event_index = 0; for(int i=0; i m_all_controls; + /** For networking: keep track of the replay time so that the + * right event can be replayed. */ + float m_history_time; + /** Stores the coordinates (for simple replay). */ AlignedArray m_all_xyz; @@ -76,15 +84,32 @@ private: /** The identities of the karts to use. */ std::vector m_kart_ident; + // ------------------------------------------------------------------------ + struct InputEvent + { + /** Index at which the even happened. */ + int m_index; + /** For which kart the event was. */ + int m_kart_index; + /** Which action it was. */ + PlayerAction m_action; + /** The value to use. */ + int m_value; + }; // InputEvent + // ------------------------------------------------------------------------ + + /** All input events. */ + std::vector m_all_input_events; + void allocateMemory(int number_of_frames); public: History (); - void startReplay (); void initRecording (); void Save (); void Load (); void updateSaving(float dt); - float updateReplayAndGetDT(); + float updateReplayAndGetDT(float time, float dt); + void addEvent(int kart_id, PlayerAction pa, int value); // -------------------I----------------------------------------------------- /** Returns the identifier of the n-th kart. */