diff --git a/src/items/attachment.cpp b/src/items/attachment.cpp index a6a32d44b..f2486399c 100644 --- a/src/items/attachment.cpp +++ b/src/items/attachment.cpp @@ -191,7 +191,7 @@ void Attachment::set(AttachmentType type, float time, { BareNetworkString *buffer = new BareNetworkString(2); saveState(buffer); - rwm->addEvent(this, buffer); + rwm->addEvent(this, buffer, /*confirmed*/true); } #endif } // set diff --git a/src/karts/controller/kart_control.cpp b/src/karts/controller/kart_control.cpp index 8075a68f2..7ba61b354 100644 --- a/src/karts/controller/kart_control.cpp +++ b/src/karts/controller/kart_control.cpp @@ -75,7 +75,7 @@ void KartControl::setSteer(float f) // Save full status BareNetworkString *buffer = new BareNetworkString(getLength()); copyToBuffer(buffer); - RewindManager::get()->addEvent(this, buffer); + RewindManager::get()->addEvent(this, buffer, true); } } // setSteer @@ -90,7 +90,7 @@ void KartControl::setAccel(float f) { BareNetworkString *buffer = new BareNetworkString(getLength()); copyToBuffer(buffer); - RewindManager::get()->addEvent(this, buffer); + RewindManager::get()->addEvent(this, buffer, true); } } // setAccel @@ -106,7 +106,7 @@ void KartControl::setBrake(bool b) // Only store the buttons in this case BareNetworkString *buffer = new BareNetworkString(1); buffer->addUInt8(getButtonsCompressed()); - RewindManager::get()->addEvent(this, buffer); + RewindManager::get()->addEvent(this, buffer, true); } } // setBrake // ---------------------------------------------------------------------------- @@ -120,7 +120,7 @@ void KartControl::setNitro(bool b) { BareNetworkString *buffer = new BareNetworkString(1); buffer->addUInt8(getButtonsCompressed()); - RewindManager::get()->addEvent(this, buffer); + RewindManager::get()->addEvent(this, buffer, true); } } // setNitro @@ -135,7 +135,7 @@ void KartControl::setSkidControl(SkidControl sc) { BareNetworkString *buffer = new BareNetworkString(1); buffer->addUInt8(getButtonsCompressed()); - RewindManager::get()->addEvent(this, buffer); + RewindManager::get()->addEvent(this, buffer, true); } } // seSkidControl @@ -150,7 +150,7 @@ void KartControl::setRescue(bool b) { BareNetworkString *buffer = new BareNetworkString(1); buffer->addUInt8(getButtonsCompressed()); - RewindManager::get()->addEvent(this, buffer); + RewindManager::get()->addEvent(this, buffer, true); } } // setRescue @@ -165,7 +165,7 @@ void KartControl::setFire(bool b) { BareNetworkString *buffer = new BareNetworkString(1); buffer->addUInt8(getButtonsCompressed()); - RewindManager::get()->addEvent(this, buffer); + RewindManager::get()->addEvent(this, buffer, true); } } // setFire @@ -180,6 +180,6 @@ void KartControl::setLookBack(bool b) { BareNetworkString *buffer = new BareNetworkString(1); buffer->addUInt8(getButtonsCompressed()); - RewindManager::get()->addEvent(this, buffer); + RewindManager::get()->addEvent(this, buffer, true); } } // setLookBack diff --git a/src/karts/controller/local_player_controller.cpp b/src/karts/controller/local_player_controller.cpp index d08d3d972..7bc300185 100644 --- a/src/karts/controller/local_player_controller.cpp +++ b/src/karts/controller/local_player_controller.cpp @@ -39,6 +39,7 @@ #include "modes/world.hpp" #include "network/network_config.hpp" #include "network/protocols/game_protocol.hpp" +#include "network/rewind_manager.hpp" #include "race/history.hpp" #include "states_screens/race_gui_base.hpp" #include "tracks/track.hpp" @@ -143,9 +144,10 @@ void LocalPlayerController::action(PlayerAction action, int value) { PlayerController::action(action, value); - // If this is a client, send the action to the server + // If this is a client, send the action to networking layer if (World::getWorld()->isNetworkWorld() && - NetworkConfig::get()->isClient() ) + NetworkConfig::get()->isClient() && + !RewindManager::get()->isRewinding() ) { GameProtocol::getInstance()->controllerAction(m_kart->getWorldKartId(), action, value); diff --git a/src/modes/world.cpp b/src/modes/world.cpp index 97c947537..e72904a09 100644 --- a/src/modes/world.cpp +++ b/src/modes/world.cpp @@ -1022,7 +1022,7 @@ void World::update(float dt) void World::updateTime(const float dt) { WorldStatus::updateTime(dt); - RewindManager::get()->setCurrentTime(getTime(), dt); + RewindManager::get()->setCurrentTime(getTime()); } // updateTime // ---------------------------------------------------------------------------- diff --git a/src/network/protocols/game_protocol.cpp b/src/network/protocols/game_protocol.cpp index 282321126..9f3f9eab0 100644 --- a/src/network/protocols/game_protocol.cpp +++ b/src/network/protocols/game_protocol.cpp @@ -19,7 +19,7 @@ #include "modes/world.hpp" #include "karts/abstract_kart.hpp" -#include "karts/controller/controller.hpp" +#include "karts/controller/player_controller.hpp" #include "network/event.hpp" #include "network/network_config.hpp" #include "network/network_player_profile.hpp" @@ -27,6 +27,7 @@ #include "network/network_config.hpp" #include "network/network_string.hpp" #include "network/protocol_manager.hpp" +#include "network/rewind_manager.hpp" #include "network/stk_host.hpp" #include "network/stk_peer.hpp" #include "utils/log.hpp" @@ -56,14 +57,14 @@ bool GameProtocol::notifyEventAsynchronous(Event* event) { float time = data.getFloat(); uint8_t kart_id = data.getUInt8(); + assert(kart_id < World::getWorld()->getNumKarts()); PlayerAction action = (PlayerAction)(data.getUInt8()); int value = data.getUInt32(); Log::info("GameProtocol", "Action at %f: %d %d %d", time, kart_id, action, value); - assert(kart_id < World::getWorld()->getNumKarts()); - Controller *controller = World::getWorld()->getKart(kart_id) - ->getController(); - controller->action(action, value); + BareNetworkString *s = new BareNetworkString(3); + s->addUInt8(kart_id).addUInt8(action).addUInt16(value); + RewindManager::get()->addEvent(this, s, /*confirmed*/ true, time); } if (data.size() > 0 ) @@ -107,8 +108,8 @@ void GameProtocol::update(float dt) //----------------------------------------------------------------------------- /** Called from the local kart controller when an action (like steering, - * acceleration, ...) was triggered. It compresses the current kart control - * state and sends a message with the new info to the server. + * acceleration, ...) was triggered. It sends a message with the new info + * to the server and informs the rewind manager to store the event. * \param Kart id that triggered the action. * \param action Which action was triggered. * \param value New value for the given action. @@ -116,6 +117,8 @@ void GameProtocol::update(float dt) void GameProtocol::controllerAction(int kart_id, PlayerAction action, int value) { + // Store the action in the list of actions that will be sent to the + // server next. assert(NetworkConfig::get()->isClient()); Action a; a.m_kart_id = kart_id; @@ -125,6 +128,36 @@ void GameProtocol::controllerAction(int kart_id, PlayerAction action, m_all_actions.push_back(a); - - Log::info("GameProtocol", "Action %d value %d", action, value); + // Store the event in the rewind manager, which is responsible + // for freeing the allocated memory + BareNetworkString *s = new BareNetworkString(4); + s->addUInt8(kart_id).addUInt8(action).addUInt16(uint16_t(value)); + RewindManager::get()->addEvent(this, s, /*confirmed*/true, + World::getWorld()->getTime() ); + + Log::info("GameProtocol", "Action at %f: %d value %d", + World::getWorld()->getTime(), action, value); } // controllerAction + +// ---------------------------------------------------------------------------- +/** Called from the RewindManager when rolling back. + * \param buffer Pointer to the saved state information. + */ +void GameProtocol::undo(BareNetworkString *buffer) +{ + +} // undo + +// ---------------------------------------------------------------------------- +/** Called from the RewindManager after a rollback to replay the stored + * events. + * \param buffer Pointer to the saved state information. + */ +void GameProtocol::rewind(BareNetworkString *buffer) +{ + int kart_id = buffer->getUInt8(); + PlayerAction action = PlayerAction(buffer->getUInt8()); + int value = buffer->getUInt16(); + Controller *c = World::getWorld()->getKart(kart_id)->getController(); + c->action(action, value); +} // rewind diff --git a/src/network/protocols/game_protocol.hpp b/src/network/protocols/game_protocol.hpp index 7f9dcf63c..7065917da 100644 --- a/src/network/protocols/game_protocol.hpp +++ b/src/network/protocols/game_protocol.hpp @@ -19,6 +19,7 @@ #ifndef GAME_PROTOCOL_HPP #define GAME_PROTOCOL_HPP +#include "network/event_rewinder.hpp" #include "network/protocol.hpp" #include "input/input.hpp" // for PlayerAction @@ -27,10 +28,11 @@ #include +class BareNetworkString; class NetworkString; - class GameProtocol : public Protocol + , public EventRewinder , public Singleton { private: @@ -59,13 +61,16 @@ public: virtual bool notifyEventAsynchronous(Event* event) OVERRIDE; virtual void update(float dt) OVERRIDE; + void controllerAction(int kart_id, PlayerAction action, int value); + virtual void undo(BareNetworkString *buffer) OVERRIDE; + virtual void rewind(BareNetworkString *buffer) OVERRIDE; // ------------------------------------------------------------------------ virtual void setup() OVERRIDE {}; // ------------------------------------------------------------------------ virtual void asynchronousUpdate() OVERRIDE {} - + }; // class GameProtocol #endif // GAME_PROTOCOL_HPP diff --git a/src/network/protocols/lobby_protocol.cpp b/src/network/protocols/lobby_protocol.cpp index 74d1435a0..b084be5d9 100644 --- a/src/network/protocols/lobby_protocol.cpp +++ b/src/network/protocols/lobby_protocol.cpp @@ -28,6 +28,7 @@ #include "network/protocols/game_events_protocol.hpp" #include "network/protocols/latency_protocol.hpp" #include "network/race_event_manager.hpp" +#include "network/rewind_manager.hpp" #include "network/stk_host.hpp" #include "race/race_manager.hpp" #include "states_screens/state_manager.hpp" @@ -56,6 +57,7 @@ LobbyProtocol::~LobbyProtocol() void LobbyProtocol::loadWorld() { Log::info("LobbyProtocol", "Ready !"); + RewindManager::setEnable(true); // Race startup sequence // --------------------- diff --git a/src/network/race_event_manager.cpp b/src/network/race_event_manager.cpp index e802a8f98..51a69ad39 100644 --- a/src/network/race_event_manager.cpp +++ b/src/network/race_event_manager.cpp @@ -6,6 +6,7 @@ #include "network/network_config.hpp" #include "network/protocol_manager.hpp" #include "network/protocols/game_events_protocol.hpp" +#include "network/rewind_manager.hpp" RaceEventManager::RaceEventManager() @@ -29,6 +30,9 @@ void RaceEventManager::update(float dt) if(!ProtocolManager::getInstance()) return; + // Replay all recorded events up to the current time: + RewindManager::get()->playEventsTill(World::getWorld()->getTime()); + World::getWorld()->updateWorld(dt); // if the race is over diff --git a/src/network/rewind_manager.cpp b/src/network/rewind_manager.cpp index 7d33a764a..1e9ca5a1c 100644 --- a/src/network/rewind_manager.cpp +++ b/src/network/rewind_manager.cpp @@ -83,6 +83,7 @@ void RewindManager::reset() m_overall_state_size = 0; m_state_frequency = 0.1f; // save 10 states a second m_last_saved_state = -9999.9f; // forces initial state save + m_next_event = 0; if(!m_enable_rewind_manager) return; @@ -108,6 +109,12 @@ void RewindManager::reset() } // reset // ---------------------------------------------------------------------------- +/** Inserts a RewindInfo object in the list of all events at the correct time. + * If there are several RewindInfo at the exact same time, state RewindInfo + * will be insert at the front, and event and time info at the end of the + * RewindInfo with the same time. + * \param ri The RewindInfo object to insert. + */ void RewindManager::insertRewindInfo(RewindInfo *ri) { #ifdef REWIND_SEARCH_STATS @@ -211,7 +218,8 @@ unsigned int RewindManager::findFirstIndex(float target_time) const * \param buffer Pointer to the event data. */ void RewindManager::addEvent(EventRewinder *event_rewinder, - BareNetworkString *buffer) + BareNetworkString *buffer, bool confirmed, + float time ) { if(m_is_rewinding) { @@ -219,8 +227,11 @@ void RewindManager::addEvent(EventRewinder *event_rewinder, Log::error("RewindManager", "Adding event when rewinding"); return; } - RewindInfo *ri = new RewindInfoEvent(getCurrentTime(), event_rewinder, - buffer, /*is confirmed*/true); + Log::verbose("time", "wolrd %f rewind %f", World::getWorld()->getTime(), getCurrentTime()); + if (time < 0) + time = getCurrentTime(); + RewindInfo *ri = new RewindInfoEvent(time, event_rewinder, + buffer, confirmed); insertRewindInfo(ri); } // addEvent @@ -270,6 +281,29 @@ void RewindManager::saveStates() m_last_saved_state = time; } // saveStates +// ---------------------------------------------------------------------------- +/** Replays all events from the last event played till the specified time. + * \param time Up to (and inclusive) which time events will be replayed. + */ +void RewindManager::playEventsTill(float time) +{ + assert(!m_is_rewinding); + m_is_rewinding = true; + while (m_next_event < m_rewind_info.size()) + { + RewindInfo *ri = m_rewind_info[m_next_event]; + if (ri->getTime() > time) + { + m_is_rewinding = false; + return; + } + m_next_event++; + if(ri->isEvent()) + ri->rewind(); + } + m_is_rewinding = false; +} // playEventsTill + // ---------------------------------------------------------------------------- /** Rewinds to the specified time. * \param t Time to rewind to. diff --git a/src/network/rewind_manager.hpp b/src/network/rewind_manager.hpp index 653072e47..7e2cc498d 100644 --- a/src/network/rewind_manager.hpp +++ b/src/network/rewind_manager.hpp @@ -93,6 +93,9 @@ private: AllRewindInfo m_rewind_info; + /** Index of the next event to be used when playing events. */ + unsigned int m_next_event; + /** Overall amount of memory allocated by states. */ unsigned int m_overall_state_size; @@ -111,9 +114,6 @@ private: * events later. */ float m_current_time; - /** The current time step size. */ - float m_time_step; - #define REWIND_SEARCH_STATS #ifdef REWIND_SEARCH_STATS @@ -134,33 +134,13 @@ public: static RewindManager *create(); static void destroy(); // ------------------------------------------------------------------------ - /** Sets the time that is to be used for all further states or events, - * and the time step size. This is necessary so that states/events before - * and after World::m_time is increased have the same time stamp. - * \param t Time. - * \param dt Time step size. - */ - void setCurrentTime(float t, float dt) - { - m_current_time = t; - m_time_step = dt; - } // setCurrentTime - - // ------------------------------------------------------------------------ - /** Returns the current time. */ - float getCurrentTime() const { return m_current_time; } - // ------------------------------------------------------------------------ - float getCurrentTimeStep() const { return m_time_step; } - // ------------------------------------------------------------------------ /** En- or disables rewinding. */ - static void setEnable(bool m) { m_enable_rewind_manager = m;} - + static void setEnable(bool m) { m_enable_rewind_manager = m; } // ------------------------------------------------------------------------ /** Returns if rewinding is enabled or not. */ static bool isEnabled() { return m_enable_rewind_manager; } - // ------------------------------------------------------------------------ - /** Returns the singleton. This function will not automatically create + /** Returns the singleton. This function will not automatically create * the singleton. */ static RewindManager *get() { @@ -168,12 +148,30 @@ public: return m_rewind_manager; } // get - // ------------------------------------------------------------------------ + // Non-static functtion declarations: void reset(); void saveStates(); void rewindTo(float target_time); - void addEvent(EventRewinder *event_rewinder, BareNetworkString *buffer); + void playEventsTill(float time); + void addEvent(EventRewinder *event_rewinder, BareNetworkString *buffer, + bool confirmed, float time = -1.0f); + // ------------------------------------------------------------------------ + /** Sets the time that is to be used for all further states or events, + * and the time step size. This is necessary so that states/events before + * and after World::m_time is increased have the same time stamp. + * \param t Time. + * \param dt Time step size. + */ + void setCurrentTime(float t) + { + m_current_time = t; + } // setCurrentTime + + // ------------------------------------------------------------------------ + /** Returns the current time. */ + float getCurrentTime() const { return m_current_time; } + // ------------------------------------------------------------------------ /** Adds a Rewinder to the list of all rewinders. * \return true If rewinding is enabled, false otherwise.