diff --git a/CMakeLists.txt b/CMakeLists.txt
index e3dc736ee..5a028c745 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -113,6 +113,7 @@ if(WIN32)
     set(ENV{OPENALDIR} ${PROJECT_SOURCE_DIR}/${DEPENDENCIES})
     add_definitions(-D_IRR_STATIC_LIB_)
     add_definitions(-DNO_IRR_COMPILE_WITH_X11_)
+    include_directories(${PROJECT_SOURCE_DIR}/${DEPENDENCIES}/include)
 endif()
 
 if(USE_GLES2)
diff --git a/data/stk_config.xml b/data/stk_config.xml
index 5ea4a4178..434fdf33a 100644
--- a/data/stk_config.xml
+++ b/data/stk_config.xml
@@ -203,8 +203,11 @@
 
   <!-- Networking 
        state-frequency: how many states the server will send per second.
+       steering-reduction: Reduce a remote kart's steering by this factor
+           each frame. This helps reduces oversteering by high latency
+           clients when they only do minor steering adjustments.
   -->
-  <networking state-frequency="10"/>
+  <networking state-frequency="10" steering-reduction="1.0"/>
 
   <!-- The field od views for 1-4 player split screen. fov-3 is
        actually not used (since 3 player split screen uses the
diff --git a/lib/irrlicht/CMakeLists.txt b/lib/irrlicht/CMakeLists.txt
index 3c5a3907b..419caf9a6 100644
--- a/lib/irrlicht/CMakeLists.txt
+++ b/lib/irrlicht/CMakeLists.txt
@@ -1,18 +1,21 @@
 # CMakeLists.txt for Irrlicht in STK
-find_package(PNG REQUIRED)
-find_package(JPEG REQUIRED)
-
-include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include/"
-                    "${JPEG_INCLUDE_DIR}"
-                    "${PNG_INCLUDE_DIRS}"
-                    "${ZLIB_INCLUDE_DIR}")
-
-if(MSVC OR APPLE)
-    include_directories("${CMAKE_CURRENT_BINARY_DIR}/../zlib/" # For zconf.h on WIN32
-                        "${CMAKE_CURRENT_BINARY_DIR}/../libpng/")
-endif()
-
 if(NOT SERVER_ONLY)
+    find_package(PNG REQUIRED)
+    find_package(JPEG REQUIRED)
+
+    include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include/"
+                        "${JPEG_INCLUDE_DIR}"
+                        "${PNG_INCLUDE_DIRS}"
+                        "${ZLIB_INCLUDE_DIR}")
+
+    if(MSVC)
+        include_directories("${CMAKE_CURRENT_BINARY_DIR}/../zlib/") # For zconf.h on WIN32
+    endif()
+
+    if(MSVC OR APPLE)
+        include_directories("${CMAKE_CURRENT_BINARY_DIR}/../libpng/")
+    endif()
+
     if(NOT USE_GLES2)
         find_package(OpenGL REQUIRED)
         include_directories(${OPENGL_INCLUDE_DIR})
@@ -58,6 +61,13 @@ if(NOT SERVER_ONLY)
         endif()        
     endif()
 else()
+    include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include/")
+    if(MSVC)
+        include_directories("${CMAKE_CURRENT_BINARY_DIR}/../zlib/")
+    else()
+        find_package(ZLIB REQUIRED)
+        include_directories("${ZLIB_INCLUDE_DIR}")
+    endif()
     add_definitions(-DNO_IRR_COMPILE_WITH_LIBPNG_)
     add_definitions(-DNO_IRR_COMPILE_WITH_LIBJPEG_)
     add_definitions(-DNO_IRR_COMPILE_WITH_BMP_LOADER_)
diff --git a/sources.cmake b/sources.cmake
index d4f28ae4d..ba4868d71 100644
--- a/sources.cmake
+++ b/sources.cmake
@@ -1,5 +1,5 @@
 # Modify this file to change the last-modified date when you add/remove a file.
-# This will then trigger a new cmake run automatically.
+# This will then trigger a new cmake run automatically. 
 file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp")
 file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp")
 file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*")
diff --git a/src/animations/animation_base.hpp b/src/animations/animation_base.hpp
index 8de3102b7..a462e3823 100644
--- a/src/animations/animation_base.hpp
+++ b/src/animations/animation_base.hpp
@@ -47,9 +47,6 @@ private:
     *  one time only (which might get triggered more than once). */
     enum AnimTimeType { ATT_CYCLIC, ATT_CYCLIC_ONCE } m_anim_type;
 
-    /** The current time used in the IPOs. */
-    float m_current_time;
-
     /** The inital position of this object. */
     Vec3 m_initial_xyz;
 
@@ -67,6 +64,9 @@ protected:
 
     float m_animation_duration;
 
+    /** The current time used in the IPOs. */
+    float m_current_time;
+
 public:
                  AnimationBase(const XMLNode &node);
                  AnimationBase(Ipo *ipo);
diff --git a/src/animations/three_d_animation.cpp b/src/animations/three_d_animation.cpp
index 5627d0dc0..a1ab67294 100644
--- a/src/animations/three_d_animation.cpp
+++ b/src/animations/three_d_animation.cpp
@@ -75,15 +75,13 @@ void ThreeDAnimation::updateWithWorldTicks()
     Vec3 xyz   = m_object->getPosition();
     Vec3 scale = m_object->getScale();
 
-    float position = 0.0f;
     if (!m_is_paused)
     {
         int cur_ticks = World::getWorld()->getTicksSinceStart();
-        float cur_time = stk_config->ticks2Time(cur_ticks);
-        position = fmodf(cur_time, m_animation_duration);
+        m_current_time = stk_config->ticks2Time(cur_ticks);
     }
 
-    AnimationBase::getAt(position, &xyz, &m_hpr, &scale);     //updates all IPOs
+    AnimationBase::getAt(m_current_time, &xyz, &m_hpr, &scale);     //updates all IPOs
     //m_node->setPosition(xyz.toIrrVector());
     //m_node->setScale(scale.toIrrVector());
 
diff --git a/src/config/stk_config.cpp b/src/config/stk_config.cpp
old mode 100644
new mode 100755
index 2828d4d86..d1d3be65c
--- a/src/config/stk_config.cpp
+++ b/src/config/stk_config.cpp
@@ -149,8 +149,10 @@ void STKConfig::load(const std::string &filename)
     CHECK_NEG(m_minimap_ai_icon,           "minimap ai_icon"            );
     CHECK_NEG(m_minimap_player_icon,       "minimap player_icon"        );
     CHECK_NEG(m_smooth_angle_limit,        "physics smooth-angle-limit" );
-    CHECK_NEG(m_default_track_friction,    "physics default-track-friction"   );
-    CHECK_NEG(m_physics_fps,               "physics fps"                      );
+    CHECK_NEG(m_default_track_friction,    "physics default-track-friction");
+    CHECK_NEG(m_physics_fps,               "physics fps"                );
+    CHECK_NEG(m_network_state_frequeny,    "network state-frequency"    );
+    CHECK_NEG(m_network_steering_reduction,"network steering-reduction" );
     CHECK_NEG(m_default_moveable_friction, "physics default-moveable-friction");
     CHECK_NEG(m_solver_iterations,         "physics: solver-iterations"       );
     CHECK_NEG(m_network_state_frequeny,    "network solver-state-frequency"   );
@@ -200,6 +202,7 @@ void STKConfig::init_defaults()
     m_solver_iterations          = -100;
     m_solver_set_flags           = 0;
     m_solver_reset_flags         = 0;
+    m_network_steering_reduction = 1.0f;
     m_title_music                = NULL;
     m_solver_split_impulse       = false;
     m_smooth_normals             = false;
@@ -433,6 +436,7 @@ void STKConfig::getAllData(const XMLNode * root)
     if (const XMLNode *networking_node = root->getNode("networking"))
     {
         networking_node->get("state-frequency", &m_network_state_frequeny);
+        networking_node->get("steering-reduction", &m_network_steering_reduction);
     }
 
     if(const XMLNode *replay_node = root->getNode("replay"))
diff --git a/src/config/stk_config.hpp b/src/config/stk_config.hpp
index 786d186ab..922800c9d 100644
--- a/src/config/stk_config.hpp
+++ b/src/config/stk_config.hpp
@@ -89,6 +89,11 @@ public:
     /** How many state updates per second the server will send. */
     int m_network_state_frequeny;
 
+    /** In case of a network race, remote karts will get their steering somewhat
+     *  reduced each frame. This reduces stutter when a kart only does small
+     *  steering adjustments. */
+    float m_network_steering_reduction;
+
     /** If the angle between a normal on a vertex and the normal of the
      *  triangle are more than this value, the physics will use the normal
      *  of the triangle in smoothing normal. */
diff --git a/src/items/bowling.hpp b/src/items/bowling.hpp
index a75d82414..0309b0081 100644
--- a/src/items/bowling.hpp
+++ b/src/items/bowling.hpp
@@ -53,9 +53,9 @@ public:
              Bowling(AbstractKart* kart);
     virtual ~Bowling();
     static  void init(const XMLNode &node, scene::IMesh *bowling);
-    virtual bool updateAndDelete(int ticks);
-    virtual bool hit(AbstractKart* kart, PhysicalObject* obj=NULL);
-    virtual HitEffect *getHitEffect() const;
+    virtual bool updateAndDelete(int ticks) OVERRIDE;
+    virtual bool hit(AbstractKart* kart, PhysicalObject* obj=NULL) OVERRIDE;
+    virtual HitEffect *getHitEffect() const OVERRIDE;
 
 
 };   // Bowling
diff --git a/src/items/cake.cpp b/src/items/cake.cpp
index 5b302a753..a7f7c0128 100644
--- a/src/items/cake.cpp
+++ b/src/items/cake.cpp
@@ -119,11 +119,7 @@ Cake::Cake (AbstractKart *kart) : Flyable(kart, PowerupManager::POWERUP_CAKE)
 
     //do not adjust height according to terrain
     setAdjustUpVelocity(false);
-
-    m_body->setActivationState(DISABLE_DEACTIVATION);
-
-    m_body->applyTorque( btVector3(5,-3,7) );
-
+    additionalPhysicsProperties();
 }   // Cake
 
 // -----------------------------------------------------------------------------
diff --git a/src/items/cake.hpp b/src/items/cake.hpp
index d22b71679..4d6184248 100644
--- a/src/items/cake.hpp
+++ b/src/items/cake.hpp
@@ -46,24 +46,36 @@ private:
 
     /** Which kart is targeted by this projectile (NULL if none). */
     Moveable*    m_target;
+
+    // ------------------------------------------------------------------------
+    virtual void additionalPhysicsProperties() OVERRIDE
+    {
+        m_body->setActivationState(DISABLE_DEACTIVATION);
+        m_body->clearForces();
+        m_body->applyTorque(btVector3(5.0f, -3.0f, 7.0f));
+    }
+
 public:
                  Cake (AbstractKart *kart);
     static  void init     (const XMLNode &node, scene::IMesh *cake_model);
-    virtual bool hit(AbstractKart* kart, PhysicalObject* obj=NULL);
+    virtual bool hit(AbstractKart* kart, PhysicalObject* obj=NULL) OVERRIDE;
     // ------------------------------------------------------------------------
-    virtual void hitTrack ()                      { hit(NULL);               }
+    virtual void hitTrack () OVERRIDE              { hit(NULL);               }
     // ------------------------------------------------------------------------
     /** Kinematic objects are not allowed to have a velocity (assertion in
      *  bullet), so we have to do our own velocity handling here. This
      *  function returns the velocity of this object. */
-    virtual const btVector3 &getVelocity() const  {return m_initial_velocity;}
+    virtual const btVector3 &getVelocity() const OVERRIDE
+                                                 { return m_initial_velocity; }
     // ------------------------------------------------------------------------
     /** Kinematic objects are not allowed to have a velocity (assertion in
      *  bullet), so we have to do our own velocity handling here. This
      *  function sets the velocity of this object.
      *  \param v Linear velocity of this object.
      */
-    virtual void  setVelocity(const btVector3& v) {m_initial_velocity=v;     }
+    virtual void setVelocity(const btVector3& v) OVERRIDE
+                                                    { m_initial_velocity = v; }
+
 };   // Cake
 
 #endif
diff --git a/src/items/flyable.cpp b/src/items/flyable.cpp
index 63e2d2127..1037fd974 100644
--- a/src/items/flyable.cpp
+++ b/src/items/flyable.cpp
@@ -37,6 +37,11 @@
 #include "karts/explosion_animation.hpp"
 #include "modes/linear_world.hpp"
 #include "modes/soccer_world.hpp"
+#include "network/compress_network_body.hpp"
+#include "network/network_config.hpp"
+#include "network/network_string.hpp"
+#include "network/rewind_info.hpp"
+#include "network/rewind_manager.hpp"
 #include "physics/physics.hpp"
 #include "tracks/track.hpp"
 #include "utils/constants.hpp"
@@ -75,6 +80,10 @@ Flyable::Flyable(AbstractKart *kart, PowerupManager::PowerupType type,
     m_owner_has_temporary_immunity = true;
     m_do_terrain_info              = true;
     m_max_lifespan                 = -1;
+    m_undo_creation                = false;
+    m_has_undone_destruction       = false;
+    m_has_server_state             = false;
+    m_check_created_ticks          = -1;
 
     // Add the graphical model
 #ifndef SERVER_ONLY
@@ -160,6 +169,10 @@ void Flyable::createPhysics(float forw_offset, const Vec3 &velocity,
     m_body->setCollisionFlags(m_body->getCollisionFlags() |
                               btCollisionObject::CF_NO_CONTACT_RESPONSE);
 
+    m_saved_transform = getTrans();
+    m_saved_lv = m_body->getLinearVelocity();
+    m_saved_av = m_body->getAngularVelocity();
+    m_saved_gravity = gravity;
 }   // createPhysics
 
 // -----------------------------------------------------------------------------
@@ -378,7 +391,7 @@ void Flyable::setAnimation(AbstractKartAnimation *animation)
  */
 void Flyable::updateGraphics(float dt)
 {
-    updateSmoothedGraphics(dt);
+    Moveable::updateSmoothedGraphics(dt);
     Moveable::updateGraphics();
 }   // updateGraphics
 
@@ -390,6 +403,9 @@ void Flyable::updateGraphics(float dt)
  */
 bool Flyable::updateAndDelete(int ticks)
 {
+    if (m_undo_creation)
+        return false;
+
     if (hasAnimation())
     {
         m_animation->update(stk_config->ticks2Time(ticks));
@@ -502,6 +518,8 @@ bool Flyable::isOwnerImmunity(const AbstractKart* kart_hit) const
  */
 bool Flyable::hit(AbstractKart *kart_hit, PhysicalObject* object)
 {
+    if (m_undo_creation)
+        return false;
     // the owner of this flyable should not be hit by his own flyable
     if(isOwnerImmunity(kart_hit)) return false;
     m_has_hit_something=true;
@@ -573,5 +591,140 @@ HitEffect* Flyable::getHitEffect() const
 unsigned int Flyable::getOwnerId()
 {
     return m_owner->getWorldKartId();
-}
+}   // getOwnerId
+
+// ----------------------------------------------------------------------------
+BareNetworkString* Flyable::saveState(std::vector<std::string>* ru)
+{
+    ru->push_back(getUniqueIdentity());
+    BareNetworkString *buffer = new BareNetworkString();
+    CompressNetworkBody::compress(m_body->getWorldTransform(),
+        m_body->getLinearVelocity(), m_body->getAngularVelocity(), buffer);
+    uint16_t hit_and_ticks = (m_has_hit_something ? 1 << 15 : 0) |
+        m_ticks_since_thrown;
+    buffer->addUInt16(hit_and_ticks);
+    return buffer;
+}   // saveState
+
+// ----------------------------------------------------------------------------
+void Flyable::restoreState(BareNetworkString *buffer, int count)
+{
+    btTransform t;
+    Vec3 lv, av;
+    CompressNetworkBody::decompress(buffer, &t, &lv, &av);
+
+    m_body->setWorldTransform(t);
+    m_motion_state->setWorldTransform(t);
+    m_body->setInterpolationWorldTransform(t);
+    m_body->setLinearVelocity(lv);
+    m_body->setAngularVelocity(av);
+    m_body->setInterpolationLinearVelocity(lv);
+    m_body->setInterpolationAngularVelocity(av);
+    uint16_t hit_and_ticks = buffer->getUInt16();
+    m_has_hit_something = (hit_and_ticks >> 15) == 1;
+    m_ticks_since_thrown = hit_and_ticks & ~(1 << 15);
+    if (!m_has_server_state)
+        m_has_server_state = true;
+}   // restoreState
+
+// ----------------------------------------------------------------------------
+void Flyable::addForRewind(const std::string& uid)
+{
+    SmoothNetworkBody::setEnable(true);
+    SmoothNetworkBody::setSmoothRotation(false);
+    SmoothNetworkBody::setAdjustVerticalOffset(false);
+    Rewinder::setUniqueIdentity(uid);
+    Rewinder::rewinderAdd();
+}   // addForRewind
+
+// ----------------------------------------------------------------------------
+void Flyable::addRewindInfoEventFunctionAfterFiring()
+{
+    if (!NetworkConfig::get()->isNetworking() ||
+        NetworkConfig::get()->isServer())
+        return;
+
+    std::shared_ptr<Flyable> f = getShared<Flyable>();
+    RewindManager::get()->addRewindInfoEventFunction(new
+    RewindInfoEventFunction(World::getWorld()->getTicksSinceStart(),
+        /*undo_function*/[f]()
+        {
+            f->m_undo_creation = true;
+            const Vec3 *min, *max;
+            Track::getCurrentTrack()->getAABB(&min, &max);
+            btTransform t = f->m_body->getWorldTransform();
+            // Move it to (almost infinity), avoiding affecting current
+            // rewinding
+            t.setOrigin(*max * 2.0f);
+            f->m_body->setWorldTransform(t);
+            f->m_motion_state->setWorldTransform(t);
+            f->m_body->setInterpolationWorldTransform(t);
+            f->m_body->setGravity(Vec3(0.0f));
+        },
+        /*replay_function*/[f]()
+        {
+            f->m_undo_creation = false;
+            f->m_body->setWorldTransform(f->m_saved_transform);
+            f->m_motion_state->setWorldTransform(f->m_saved_transform);
+            f->m_body->setInterpolationWorldTransform(f->m_saved_transform);
+            f->m_body->setLinearVelocity(f->m_saved_lv);
+            f->m_body->setAngularVelocity(f->m_saved_av);
+            f->m_body->setInterpolationLinearVelocity(f->m_saved_lv);
+            f->m_body->setInterpolationAngularVelocity(f->m_saved_av);
+            f->m_body->setGravity(f->m_saved_gravity);
+            f->m_ticks_since_thrown = 0;
+            f->m_has_hit_something = false;
+            f->additionalPhysicsProperties();
+        },
+        /*delete_function*/[f]()
+        {
+            f->m_check_created_ticks = World::getWorld()->getTicksSinceStart();
+        }));
+}   // addRewindInfoEventFunctionAfterFiring
+
+// ----------------------------------------------------------------------------
+void Flyable::handleUndoDestruction()
+{
+    if (!NetworkConfig::get()->isNetworking() ||
+        NetworkConfig::get()->isServer() ||
+        m_has_undone_destruction)
+        return;
+
+    m_has_undone_destruction = true;
+
+    // If destroyed during rewind, than in theroy it should be safe to delete
+    // without undo
+    if (RewindManager::get()->isRewinding())
+        return;
+
+    // We don't bother seeing the mesh during rewinding
+    m_node->setVisible(false);
+    std::shared_ptr<Flyable> f = getShared<Flyable>();
+    std::string uid = f->getUniqueIdentity();
+    RewindManager::get()->addRewindInfoEventFunction(new
+    RewindInfoEventFunction(World::getWorld()->getTicksSinceStart(),
+        /*undo_function*/[f, uid]()
+        {
+            projectile_manager->addByUID(uid, f);
+        },
+        /*replay_function*/[uid]()
+        {
+            projectile_manager->removeByUID(uid);
+        }));
+}   // handleUndoDestruction
+
+// ----------------------------------------------------------------------------
+void Flyable::computeError()
+{
+    Moveable::checkSmoothing();
+    if (!m_has_server_state && m_check_created_ticks != -1 &&
+        World::getWorld()->getTicksSinceStart() > m_check_created_ticks)
+    {
+        const std::string& uid = getUniqueIdentity();
+        Log::warn("Flyable", "Item %s failed to be created on server, "
+            "remove it locally", uid.c_str());
+        projectile_manager->removeByUID(uid);
+    }
+}   // computeError
+
 /* EOF */
diff --git a/src/items/flyable.hpp b/src/items/flyable.hpp
index 8eba2bc6e..7d19159ba 100644
--- a/src/items/flyable.hpp
+++ b/src/items/flyable.hpp
@@ -24,6 +24,7 @@
 
 #include "items/powerup_manager.hpp"
 #include "karts/moveable.hpp"
+#include "network/rewinder.hpp"
 #include "tracks/terrain_info.hpp"
 #include "utils/cpp2011.hpp"
 
@@ -43,7 +44,8 @@ class XMLNode;
 /**
   * \ingroup items
   */
-class Flyable : public Moveable, public TerrainInfo
+class Flyable : public Moveable, public TerrainInfo,
+                public Rewinder
 {
 public:
 private:
@@ -103,6 +105,11 @@ protected:
     /** Size of this flyable. */
     Vec3              m_extend;
 
+    bool              m_undo_creation;
+    bool              m_has_undone_destruction;
+    bool              m_has_server_state;
+    int               m_check_created_ticks;
+
     // The flyable class stores the values for each flyable type, e.g.
     // speed, min_height, max_height. These variables must be static,
     // so we need arrays of these variables to have different values
@@ -128,11 +135,11 @@ protected:
 
     /** Time since thrown. used so a kart can't hit himself when trying
      *  something, and also to put some time limit to some collectibles */
-    int               m_ticks_since_thrown;
+    int16_t           m_ticks_since_thrown;
 
     /** Set to something > -1 if this flyable should auto-destrcut after
      *  that may ticks. */
-    int                m_max_lifespan;
+    int               m_max_lifespan;
 
     /** If set to true, the kart that throwns this flyable can't collide
      *  with it for a short time. */
@@ -160,6 +167,13 @@ protected:
                                     const bool rotates=false,
                                     const bool turn_around=false,
                                     const btTransform* customDirection=NULL);
+
+    /** Used when undoing creation or destruction. */
+    btTransform m_saved_transform;
+    Vec3 m_saved_lv, m_saved_av, m_saved_gravity;
+
+    virtual void additionalPhysicsProperties() {}
+
 public:
 
                  Flyable     (AbstractKart* kart,
@@ -217,6 +231,31 @@ public:
     /** Returns the size (extend) of the mesh. */
     const Vec3 &getExtend() const { return m_extend;  }
     // ------------------------------------------------------------------------
+    void addForRewind(const std::string& uid);
+    // ------------------------------------------------------------------------
+    virtual void undoEvent(BareNetworkString *buffer) OVERRIDE {}
+    // ------------------------------------------------------------------------
+    virtual void rewindToEvent(BareNetworkString *buffer) OVERRIDE {}
+    // ------------------------------------------------------------------------
+    virtual void undoState(BareNetworkString *buffer) OVERRIDE {}
+    // ------------------------------------------------------------------------
+    virtual void saveTransform() OVERRIDE     { Moveable::prepareSmoothing(); }
+    // ------------------------------------------------------------------------
+    virtual void computeError() OVERRIDE;
+    // ------------------------------------------------------------------------
+    virtual BareNetworkString* saveState(std::vector<std::string>* ru)
+        OVERRIDE;
+    // ------------------------------------------------------------------------
+    virtual void restoreState(BareNetworkString *buffer, int count) OVERRIDE;
+    // ------------------------------------------------------------------------
+    virtual void addRewindInfoEventFunctionAfterFiring();
+    // ------------------------------------------------------------------------
+    bool isUndoCreation() const                     { return m_undo_creation; }
+    // ------------------------------------------------------------------------
+    bool hasUndoneDestruction() const      { return m_has_undone_destruction; }
+    // ------------------------------------------------------------------------
+    void handleUndoDestruction();
+
 };   // Flyable
 
 #endif
diff --git a/src/items/item_manager.cpp b/src/items/item_manager.cpp
index 4fcf76c8e..49842321a 100644
--- a/src/items/item_manager.cpp
+++ b/src/items/item_manager.cpp
@@ -43,19 +43,20 @@
 #include <string>
 
 
-std::vector<scene::IMesh *> ItemManager::m_item_mesh;
-std::vector<scene::IMesh *> ItemManager::m_item_lowres_mesh;
-std::vector<video::SColorf> ItemManager::m_glow_color;
-bool                        ItemManager::m_disable_item_collection = false;
-ItemManager *               ItemManager::m_item_manager = NULL;
-std::mt19937                ItemManager::m_random_engine;
+std::vector<scene::IMesh *>  ItemManager::m_item_mesh;
+std::vector<scene::IMesh *>  ItemManager::m_item_lowres_mesh;
+std::vector<video::SColorf>  ItemManager::m_glow_color;
+bool                         ItemManager::m_disable_item_collection = false;
+std::shared_ptr<ItemManager> ItemManager::m_item_manager;
+std::mt19937                 ItemManager::m_random_engine;
 
 //-----------------------------------------------------------------------------
 /** Creates one instance of the item manager. */
 void ItemManager::create()
 {
     assert(!m_item_manager);
-    m_item_manager = new ItemManager();
+    // Due to protected constructor use new instead of make_shared
+    m_item_manager = std::shared_ptr<ItemManager>(new ItemManager());
 }   // create
 
 //-----------------------------------------------------------------------------
@@ -63,8 +64,7 @@ void ItemManager::create()
 void ItemManager::destroy()
 {
     assert(m_item_manager);
-    delete m_item_manager;
-    m_item_manager = NULL;
+    m_item_manager = nullptr;
 }   // destroy
 
 //-----------------------------------------------------------------------------
diff --git a/src/items/item_manager.hpp b/src/items/item_manager.hpp
index 53924b5bc..83f5f9a9e 100644
--- a/src/items/item_manager.hpp
+++ b/src/items/item_manager.hpp
@@ -60,7 +60,7 @@ private:
     static std::mt19937 m_random_engine;
 protected:
     /** The instance of ItemManager while a race is on. */
-    static ItemManager *m_item_manager;
+    static std::shared_ptr<ItemManager> m_item_manager;
 public:
     static void loadDefaultItemMeshes();
     static void removeTextures();
@@ -90,9 +90,10 @@ public:
     // ------------------------------------------------------------------------
     /** Return an instance of the item manager (it does not automatically
      *  create one, call create for that). */
-    static ItemManager *get() {
+    static ItemManager *get()
+    {
         assert(m_item_manager);
-        return m_item_manager;
+        return m_item_manager.get();
     }   // get
 
     // ========================================================================
@@ -119,9 +120,9 @@ protected:
     virtual unsigned int insertItem(Item *item);
     void setSwitchItems(const std::vector<int> &switch_items);
              ItemManager();
+public:
     virtual ~ItemManager();
 
-public:
     virtual Item*  placeItem       (ItemState::ItemType type, const Vec3& xyz,
                                     const Vec3 &normal);
     virtual Item*  dropNewItem     (ItemState::ItemType type,
diff --git a/src/items/network_item_manager.cpp b/src/items/network_item_manager.cpp
index f07235b28..b1070f228 100644
--- a/src/items/network_item_manager.cpp
+++ b/src/items/network_item_manager.cpp
@@ -31,16 +31,16 @@
 void NetworkItemManager::create()
 {
     assert(!m_item_manager);
-    m_item_manager = new NetworkItemManager();
+    auto nim = std::shared_ptr<NetworkItemManager>(new NetworkItemManager());
+    nim->rewinderAdd();
+    m_item_manager = nim;
 }   // create
 
-
 // ============================================================================
 /** Creates a new instance of the item manager. This is done at startup
  *  of each race. */
 NetworkItemManager::NetworkItemManager()
-                  : Rewinder("N", /*can be deleted*/false),
-                    ItemManager()
+                  : Rewinder("N"), ItemManager()
 {
     m_last_confirmed_item_ticks.clear();
 
diff --git a/src/items/network_item_manager.hpp b/src/items/network_item_manager.hpp
index cfeec8e3d..1e1d93ff9 100644
--- a/src/items/network_item_manager.hpp
+++ b/src/items/network_item_manager.hpp
@@ -61,10 +61,10 @@ private:
     void forwardTime(int ticks);
 
     NetworkItemManager();
-    virtual ~NetworkItemManager();
 
 public:
     static void create();
+    virtual ~NetworkItemManager();
 
     void setSwitchItems(const std::vector<int> &switch_items);
     void sendItemUpdate();
diff --git a/src/items/plunger.cpp b/src/items/plunger.cpp
index 65501a6d8..9cbafa6c3 100644
--- a/src/items/plunger.cpp
+++ b/src/items/plunger.cpp
@@ -100,7 +100,7 @@ Plunger::Plunger(AbstractKart *kart)
     {
         m_rubber_band = new RubberBand(this, kart);
     }
-    m_keep_alive = -1;
+    additionalPhysicsProperties();
 }   // Plunger
 
 // ----------------------------------------------------------------------------
diff --git a/src/items/plunger.hpp b/src/items/plunger.hpp
index 91283a3c2..a74e9ed09 100644
--- a/src/items/plunger.hpp
+++ b/src/items/plunger.hpp
@@ -47,13 +47,17 @@ private:
     btVector3    m_initial_velocity;
 
     bool m_reverse_mode;
+
+    virtual void additionalPhysicsProperties() OVERRIDE { m_keep_alive = -1; }
+
 public:
                  Plunger(AbstractKart *kart);
                 ~Plunger();
     static  void init(const XMLNode &node, scene::IMesh* missile);
-    virtual bool updateAndDelete(int ticks);
-    virtual void hitTrack ();
-    virtual bool hit      (AbstractKart *kart, PhysicalObject *obj=NULL);
+    virtual bool updateAndDelete(int ticks) OVERRIDE;
+    virtual void hitTrack () OVERRIDE;
+    virtual bool hit      (AbstractKart *kart, PhysicalObject *obj=NULL)
+        OVERRIDE;
 
     // ------------------------------------------------------------------------
     /** Sets the keep-alive value. Setting it to 0 will remove the plunger
@@ -62,7 +66,7 @@ public:
     void setKeepAlive(int ticks) {m_keep_alive = ticks;}
     // ------------------------------------------------------------------------
     /** No hit effect when it ends. */
-    virtual HitEffect *getHitEffect() const {return NULL; }
+    virtual HitEffect *getHitEffect() const OVERRIDE { return NULL; }
     // ------------------------------------------------------------------------
 };   // Plunger
 
diff --git a/src/items/powerup.cpp b/src/items/powerup.cpp
index fc3f0895c..70f08dff3 100644
--- a/src/items/powerup.cpp
+++ b/src/items/powerup.cpp
@@ -32,6 +32,7 @@
 #include "karts/controller/controller.hpp"
 #include "karts/kart_properties.hpp"
 #include "modes/world.hpp"
+#include "network/rewind_manager.hpp"
 #include "physics/triangle_mesh.hpp"
 #include "tracks/track.hpp"
 #include "utils/string_utils.hpp"
@@ -211,6 +212,13 @@ void  Powerup::adjustSound()
     }
 }   // adjustSound
 
+//-----------------------------------------------------------------------------
+void Powerup::playSound()
+{
+    if (!RewindManager::get()->isRewinding())
+        m_sound_use->play();
+}   // playSound
+
 //-----------------------------------------------------------------------------
 /** Use (fire) this powerup.
  */
@@ -248,7 +256,7 @@ void Powerup::use()
         {
             ItemManager::get()->switchItems();
             m_sound_use->setPosition(m_kart->getXYZ());
-            m_sound_use->play();
+            playSound();
             break;
         }
     case PowerupManager::POWERUP_CAKE:
@@ -258,7 +266,7 @@ void Powerup::use()
         if(stk_config->m_shield_restrict_weapons)
             m_kart->setShieldTime(0.0f); // make weapon usage destroy the shield
         Powerup::adjustSound();
-        m_sound_use->play();
+        playSound();
 
         projectile_manager->newProjectile(m_kart, m_type);
         break ;
@@ -280,7 +288,7 @@ void Powerup::use()
             if(!new_item) return;
 
             Powerup::adjustSound();
-            m_sound_use->play();
+            playSound();
         }
         else // if the kart is looking forward, use the bubblegum as a shield
         {
@@ -330,7 +338,7 @@ void Powerup::use()
             //In this case this is a workaround, since the bubblegum item has two different sounds.
 
             Powerup::adjustSound();
-            m_sound_use->play();
+            playSound();
 
         }   // end of PowerupManager::POWERUP_BUBBLEGUM
         break;
@@ -359,7 +367,7 @@ void Powerup::use()
                 else
                     m_sound_use->setPosition(m_kart->getXYZ());
 
-                m_sound_use->play();
+                playSound();
                 break;
             }
         }
@@ -418,7 +426,7 @@ void Powerup::use()
                 m_sound_use->setPosition(m_kart->getXYZ());
             else if(player_kart)
                 m_sound_use->setPosition(player_kart->getXYZ());
-            m_sound_use->play();
+            playSound();
         }
         break;
 
diff --git a/src/items/powerup.hpp b/src/items/powerup.hpp
index 9077495da..4e4965f80 100644
--- a/src/items/powerup.hpp
+++ b/src/items/powerup.hpp
@@ -36,9 +36,6 @@ class SFXBase;
 class Powerup : public NoCopy
 {
 private:
-    /** A synchronised random number generator for network games. */
-    RandomGenerator             m_random;
-
     /** Sound effect that is being played. */
     SFXBase                    *m_sound_use;
 
@@ -51,6 +48,7 @@ private:
     /** The owner (kart) of this powerup. */
     AbstractKart*               m_kart;
 
+    void playSound();
 public:
                     Powerup      (AbstractKart* kart_);
                    ~Powerup      ();
diff --git a/src/items/powerup_manager.cpp b/src/items/powerup_manager.cpp
index d2f1d3b53..07aeb0f15 100644
--- a/src/items/powerup_manager.cpp
+++ b/src/items/powerup_manager.cpp
@@ -298,7 +298,7 @@ void PowerupManager::WeightsData::convertRankToSection(int rank, int *prev,
     }
 
     // The last kart always uses the data for the last section
-    if (rank == m_num_karts)
+    if (rank == (int)m_num_karts)
     {
         *prev = *next = m_weights_for_section.size() - 1;
         *weight = 1.0f;
@@ -600,9 +600,11 @@ void PowerupManager::unitTesting()
     int num_weights = wd.m_summed_weights_for_rank[0].back();
     for(int i=0; i<num_weights; i++)
     {
+#ifdef DEBUG
         unsigned int n;
         assert( powerup_manager->getRandomPowerup(1, &n, i)==POWERUP_BOWLING );
         assert(n==3);
+#endif
     }
 
     // Test 2: Test all possible random numbers for 5 karts and rank 5
diff --git a/src/items/powerup_manager.hpp b/src/items/powerup_manager.hpp
index f68b68dc2..bb2ef0cf1 100644
--- a/src/items/powerup_manager.hpp
+++ b/src/items/powerup_manager.hpp
@@ -139,7 +139,6 @@ public:
     };
 
 private:
-    const int     RAND_CLASS_RANGE = 1000;
 
     /** The icon for each powerup. */
     Material*     m_all_icons [POWERUP_MAX];
diff --git a/src/items/projectile_manager.cpp b/src/items/projectile_manager.cpp
index 907c77ca4..b72724cd2 100644
--- a/src/items/projectile_manager.cpp
+++ b/src/items/projectile_manager.cpp
@@ -27,6 +27,8 @@
 #include "items/powerup.hpp"
 #include "items/rubber_ball.hpp"
 #include "karts/abstract_kart.hpp"
+#include "modes/world.hpp"
+#include "network/rewind_manager.hpp"
 
 ProjectileManager *projectile_manager=0;
 
@@ -45,12 +47,6 @@ void ProjectileManager::removeTextures()
 //-----------------------------------------------------------------------------
 void ProjectileManager::cleanup()
 {
-    for(Projectiles::iterator i = m_active_projectiles.begin();
-        i != m_active_projectiles.end(); ++i)
-    {
-        delete *i;
-    }
-
     m_active_projectiles.clear();
     for(HitEffects::iterator i  = m_active_hit_effects.begin();
         i != m_active_hit_effects.end(); ++i)
@@ -68,12 +64,8 @@ void ProjectileManager::cleanup()
  */
 void ProjectileManager::updateGraphics(float dt)
 {
-    for (auto p  = m_active_projectiles.begin(); 
-              p != m_active_projectiles.end();   ++p)
-    {
-        (*p)->updateGraphics(dt);
-    }
-
+    for (auto& p : m_active_projectiles)
+        p.second->updateGraphics(dt);
 }   // updateGraphics
 
 // -----------------------------------------------------------------------------
@@ -82,6 +74,8 @@ void ProjectileManager::update(int ticks)
 {
     updateServer(ticks);
 
+    if (RewindManager::get()->isRewinding())
+        return;
     HitEffects::iterator he = m_active_hit_effects.begin();
     while(he!=m_active_hit_effects.end())
     {
@@ -107,24 +101,30 @@ void ProjectileManager::update(int ticks)
 /** Updates all rockets on the server (or no networking). */
 void ProjectileManager::updateServer(int ticks)
 {
-    Projectiles::iterator p = m_active_projectiles.begin();
-    while(p!=m_active_projectiles.end())
+    auto p = m_active_projectiles.begin();
+    while (p != m_active_projectiles.end())
     {
-        bool can_be_deleted = (*p)->updateAndDelete(ticks);
-        if(can_be_deleted)
+        if (p->second->isUndoCreation())
         {
-            HitEffect *he = (*p)->getHitEffect();
-            if(he)
-                addHitEffect(he);
-            Flyable *f=*p;
-            Projectiles::iterator p_next=m_active_projectiles.erase(p);
-            delete f;
-            p=p_next;
+            p++;
+            continue;
+        }
+        bool can_be_deleted = p->second->updateAndDelete(ticks);
+        if (can_be_deleted)
+        {
+            if (!p->second->hasUndoneDestruction())
+            {
+                HitEffect *he = p->second->getHitEffect();
+                if (he)
+                    addHitEffect(he);
+            }
+            p->second->handleUndoDestruction();
+            p = m_active_projectiles.erase(p);
         }
         else
             p++;
     }   // while p!=m_active_projectiles.end()
-    
+
 }   // updateServer
 
 // -----------------------------------------------------------------------------
@@ -132,20 +132,40 @@ void ProjectileManager::updateServer(int ticks)
  *  \param kart The kart which shoots the projectile.
  *  \param type Type of projectile.
  */
-Flyable *ProjectileManager::newProjectile(AbstractKart *kart,
-                                          PowerupManager::PowerupType type)
+std::shared_ptr<Flyable>
+    ProjectileManager::newProjectile(AbstractKart *kart,
+                                     PowerupManager::PowerupType type)
 {
-    Flyable *f;
+    const std::string& uid = getUniqueIdentity(kart, type);
+    auto it = m_active_projectiles.find(uid);
+    // Flyable already created during rewind
+    if (it != m_active_projectiles.end())
+        return it->second;
+
+    std::shared_ptr<Flyable> f;
     switch(type)
     {
-        case PowerupManager::POWERUP_BOWLING:    f = new Bowling(kart);  break;
-        case PowerupManager::POWERUP_PLUNGER:    f = new Plunger(kart);  break;
-        case PowerupManager::POWERUP_CAKE:       f = new Cake(kart);     break;
-        case PowerupManager::POWERUP_RUBBERBALL: f = new RubberBall(kart);
-                                                                         break;
-        default:              return NULL;
+        case PowerupManager::POWERUP_BOWLING:
+            f = std::make_shared<Bowling>(kart);
+            break;
+        case PowerupManager::POWERUP_PLUNGER:
+            f = std::make_shared<Plunger>(kart);
+            break;
+        case PowerupManager::POWERUP_CAKE:
+            f = std::make_shared<Cake>(kart);
+            break;
+        case PowerupManager::POWERUP_RUBBERBALL:
+            f = std::make_shared<RubberBall>(kart);
+            break;
+        default:
+            return nullptr;
+    }
+    m_active_projectiles[uid] = f;
+    if (RewindManager::get()->isEnabled())
+    {
+        f->addForRewind(uid);
+        f->addRewindInfoEventFunctionAfterFiring();
     }
-    m_active_projectiles.push_back(f);
     return f;
 }   // newProjectile
 
@@ -158,13 +178,15 @@ Flyable *ProjectileManager::newProjectile(AbstractKart *kart,
 bool ProjectileManager::projectileIsClose(const AbstractKart * const kart,
                                          float radius)
 {
-    float r2 = radius*radius;
-
-    for(Projectiles::iterator i  = m_active_projectiles.begin();
-                              i != m_active_projectiles.end();   i++)
+    float r2 = radius * radius;
+    for (auto i = m_active_projectiles.begin(); i != m_active_projectiles.end();
+        i++)
     {
-        float dist2 = (*i)->getXYZ().distance2(kart->getXYZ());
-        if(dist2<r2) return true;
+        if (i->second->isUndoCreation())
+            continue;
+        float dist2 = i->second->getXYZ().distance2(kart->getXYZ());
+        if (dist2 < r2)
+            return true;
     }
     return false;
 }   // projectileIsClose
@@ -179,21 +201,101 @@ bool ProjectileManager::projectileIsClose(const AbstractKart * const kart,
 int ProjectileManager::getNearbyProjectileCount(const AbstractKart * const kart,
                                          float radius, PowerupManager::PowerupType type)
 {
-    float r2 = radius*radius;
-    int projectileCount = 0;
-
-    for(Projectiles::iterator i  = m_active_projectiles.begin();
-                              i != m_active_projectiles.end();   i++)
+    float r2 = radius * radius;
+    int projectile_count = 0;
+    for (auto i = m_active_projectiles.begin(); i != m_active_projectiles.end();
+         i++)
     {
-        if ((*i)->getType() == type)
+        if (i->second->isUndoCreation())
+            continue;
+        if (i->second->getType() == type)
         {
-            float dist2 = (*i)->getXYZ().distance2(kart->getXYZ());
-            if(dist2<r2)
+            float dist2 = i->second->getXYZ().distance2(kart->getXYZ());
+            if (dist2 < r2)
             {
-
-                projectileCount++;
+                projectile_count++;
             }
         }
     }
-    return projectileCount;
+    return projectile_count;
 }   // getNearbyProjectileCount
+
+// -----------------------------------------------------------------------------
+std::string ProjectileManager::getUniqueIdentity(AbstractKart* kart,
+                                                 PowerupManager::PowerupType t)
+{
+    switch (t)
+    {
+        case PowerupManager::POWERUP_BOWLING:
+            return std::string("B_") +
+                StringUtils::toString(kart->getWorldKartId()) + "_" +
+                StringUtils::toString(World::getWorld()->getTicksSinceStart());
+        case PowerupManager::POWERUP_PLUNGER:
+            return std::string("P_") +
+                StringUtils::toString(kart->getWorldKartId()) + "_" +
+                StringUtils::toString(World::getWorld()->getTicksSinceStart());
+        case PowerupManager::POWERUP_CAKE:
+            return std::string("C_") +
+                StringUtils::toString(kart->getWorldKartId()) + "_" +
+                StringUtils::toString(World::getWorld()->getTicksSinceStart());
+        case PowerupManager::POWERUP_RUBBERBALL:
+            return std::string("R_") +
+                StringUtils::toString(kart->getWorldKartId()) + "_" +
+                StringUtils::toString(World::getWorld()->getTicksSinceStart());
+        default:
+            assert(false);
+            return "";
+    }
+}   // getUniqueIdentity
+
+// -----------------------------------------------------------------------------
+std::shared_ptr<Rewinder>
+          ProjectileManager::addRewinderFromNetworkState(const std::string& uid)
+{
+    std::vector<std::string> id = StringUtils::split(uid, '_');
+    if (id.size() != 3)
+        return nullptr;
+    if (!(id[0] == "B" || id[0] == "P" || id[0] == "C" || id[0] == "R"))
+        return nullptr;
+    int world_id = -1;
+    if (!StringUtils::fromString(id[1], world_id))
+        return nullptr;
+    AbstractKart* kart = World::getWorld()->getKart(world_id);
+    char first_id = id[0][0];
+    Log::debug("ProjectileManager", "Missed a firing event or locally deleted,"
+        " add the flyable %s manually", uid.c_str());
+    switch (first_id)
+    {
+        case 'B':
+        {
+            auto f = std::make_shared<Bowling>(kart);
+            f->addForRewind(uid);
+            m_active_projectiles[uid] = f;
+            return f;
+        }
+        case 'P':
+        {
+            auto f = std::make_shared<Plunger>(kart);
+            f->addForRewind(uid);
+            m_active_projectiles[uid] = f;
+            return f;
+        }
+        case 'C':
+        {
+            auto f = std::make_shared<Cake>(kart);
+            f->addForRewind(uid);
+            m_active_projectiles[uid] = f;
+            return f;
+        }
+        case 'R':
+        {
+            auto f = std::make_shared<RubberBall>(kart);
+            f->addForRewind(uid);
+            m_active_projectiles[uid] = f;
+            return f;
+        }
+        default:
+            assert(false);
+            return nullptr;
+    }
+}   // addProjectileFromNetworkState
diff --git a/src/items/projectile_manager.hpp b/src/items/projectile_manager.hpp
index 9518ccec2..bfae1cdd6 100644
--- a/src/items/projectile_manager.hpp
+++ b/src/items/projectile_manager.hpp
@@ -19,6 +19,8 @@
 #ifndef HEADER_PROJECTILEMANAGER_HPP
 #define HEADER_PROJECTILEMANAGER_HPP
 
+#include <map>
+#include <memory>
 #include <vector>
 
 namespace irr
@@ -32,6 +34,7 @@ namespace irr
 class AbstractKart;
 class Flyable;
 class HitEffect;
+class Rewinder;
 class Track;
 class Vec3;
 
@@ -41,17 +44,18 @@ class Vec3;
 class ProjectileManager : public NoCopy
 {
 private:
-    typedef std::vector<Flyable*>   Projectiles;
     typedef std::vector<HitEffect*> HitEffects;
 
     /** The list of all active projectiles, i.e. projectiles which are
      *  currently moving on the track. */
-    Projectiles      m_active_projectiles;
+    std::map<std::string, std::shared_ptr<Flyable> > m_active_projectiles;
 
     /** All active hit effects, i.e. hit effects which are currently
      *  being shown or have a sfx playing. */
     HitEffects       m_active_hit_effects;
 
+    std::string      getUniqueIdentity(AbstractKart* kart,
+                                       PowerupManager::PowerupType type);
     void             updateServer(int ticks);
 public:
                      ProjectileManager() {}
@@ -60,9 +64,6 @@ public:
     void             cleanup          ();
     void             update           (int ticks);
     void             updateGraphics   (float dt);
-    Flyable*         newProjectile    (AbstractKart *kart,
-                                       PowerupManager::PowerupType type);
-    void             Deactivate       (Flyable *p) {}
     void             removeTextures   ();
     bool             projectileIsClose(const AbstractKart * const kart,
                                        float radius);
@@ -74,6 +75,19 @@ public:
      *  \param hit_effect The hit effect to be added. */
     void             addHitEffect(HitEffect *hit_effect)
                                 { m_active_hit_effects.push_back(hit_effect); }
+    // ------------------------------------------------------------------------
+    std::shared_ptr<Rewinder>
+                           addRewinderFromNetworkState(const std::string& uid);
+    // ------------------------------------------------------------------------
+    std::shared_ptr<Flyable> newProjectile(AbstractKart *kart,
+                                           PowerupManager::PowerupType type);
+    // ------------------------------------------------------------------------
+    void addByUID(const std::string& uid, std::shared_ptr<Flyable> f)
+                                             { m_active_projectiles[uid] = f; }
+    // ------------------------------------------------------------------------
+    void removeByUID(const std::string& uid)
+                                           { m_active_projectiles.erase(uid); }
+
 };
 
 extern ProjectileManager *projectile_manager;
diff --git a/src/karts/abstract_kart_animation.cpp b/src/karts/abstract_kart_animation.cpp
index d4424a656..539ac7412 100644
--- a/src/karts/abstract_kart_animation.cpp
+++ b/src/karts/abstract_kart_animation.cpp
@@ -89,7 +89,7 @@ AbstractKartAnimation::~AbstractKartAnimation()
             Vec3 linear_velocity = kart->getBody()->getLinearVelocity();
             Vec3 angular_velocity = kart->getBody()->getAngularVelocity();
             btTransform transform = kart->getBody()->getWorldTransform();
-            RewindManager::get()->getRewindQueue().insertRewindInfo(new
+            RewindManager::get()->addRewindInfoEventFunction(new
                 RewindInfoEventFunction(
                 World::getWorld()->getTicksSinceStart(),
                 [kart]()
diff --git a/src/karts/controller/controller.cpp b/src/karts/controller/controller.cpp
index 26d8311d2..fe04be88e 100644
--- a/src/karts/controller/controller.cpp
+++ b/src/karts/controller/controller.cpp
@@ -35,7 +35,8 @@ Controller::Controller(AbstractKart *kart)
     setControllerName("Controller");
 }   // Controller
 
+// ----------------------------------------------------------------------------
 core::stringw Controller::getName() const
 {
     return translations->fribidize(m_kart->getName());
-}
+}   // getName
diff --git a/src/karts/controller/network_player_controller.hpp b/src/karts/controller/network_player_controller.hpp
old mode 100644
new mode 100755
index 0bff1464d..0aca2962c
--- a/src/karts/controller/network_player_controller.hpp
+++ b/src/karts/controller/network_player_controller.hpp
@@ -18,6 +18,7 @@
 #define HEADER_NETWORK_PLAYER_CONTROLLER_HPP
 
 #include "karts/controller/player_controller.hpp"
+#include "network/network_config.hpp"
 
 class AbstractKart;
 class Player;
@@ -42,6 +43,23 @@ public:
         return false; 
     }   // isLocal
     // ------------------------------------------------------------------------
+    /** Update for network controller. For player with a high ping it is
+     *  useful to reduce shaking by reducing the steering somewhat in each
+     *  frame: If the player does a quick correction only, because of the high
+     *  latency the predicted path will curve way too much. By automatically 
+     *  reducing it, this error is reduced. And even if the player steers more
+     *  the error is hopefully acceptable. */
+    virtual void update(int ticks)
+    {
+        PlayerController::update(ticks);
+        if (NetworkConfig::get()->isClient())
+        {
+            m_controls->setSteer(  m_controls->getSteer()
+                                 * stk_config->m_network_steering_reduction);
+        }
+    }   // update
+
+    // ------------------------------------------------------------------------
 };   // NetworkPlayerController
 
 #endif // NETWORK_PLAYER_CONTROLLER_HPP
diff --git a/src/karts/ghost_kart.cpp b/src/karts/ghost_kart.cpp
index 6c7c0c343..058991b7e 100644
--- a/src/karts/ghost_kart.cpp
+++ b/src/karts/ghost_kart.cpp
@@ -47,6 +47,7 @@ void GhostKart::reset()
     Kart::reset();
     // This will set the correct start position
     update(0);
+    updateGraphics(0);
     m_last_egg_idx = 0;
 }   // reset
 
diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp
index b23094a20..2563d96cf 100644
--- a/src/karts/kart.cpp
+++ b/src/karts/kart.cpp
@@ -91,6 +91,7 @@
 
 #include <algorithm> // for min and max
 #include <iostream>
+#include <limits>
 #include <cmath>
 
 
@@ -129,7 +130,7 @@ Kart::Kart (const std::string& ident, unsigned int world_kart_id,
     m_bubblegum_ticks      = 0;
     m_bubblegum_torque     = 0.0f;
     m_invulnerable_ticks   = 0;
-    m_squash_ticks         = 0;
+    m_squash_time          = std::numeric_limits<float>::max();
 
     m_shadow               = NULL;
     m_wheel_box            = NULL;
@@ -366,7 +367,7 @@ void Kart::reset()
     m_bubblegum_ticks      = 0;
     m_bubblegum_torque     = 0.0f;
     m_invulnerable_ticks   = 0;
-    m_squash_ticks         = 0;
+    m_squash_time          = std::numeric_limits<float>::max();
     m_node->setScale(core::vector3df(1.0f, 1.0f, 1.0f));
     m_collected_energy     = 0;
     m_has_started          = false;
@@ -858,6 +859,8 @@ void Kart::adjustSpeed(float f)
  */
 void Kart::updateWeight()
 {
+    if (!m_body)
+        return;
     float mass = m_kart_properties->getMass() + m_attachment->weightAdjust();
     if (m_weight != mass)
     {
@@ -1280,34 +1283,12 @@ void Kart::update(int ticks)
     // Reset any instand speed increase in the bullet kart
     m_vehicle->setMinSpeed(0);
 
-    if(m_squash_ticks>=0)
-    {
-        m_squash_ticks-=ticks;
-        // If squasing time ends, reset the model
-        if(m_squash_ticks<=0)
-        {
-            m_node->setScale(core::vector3df(1.0f, 1.0f, 1.0f));
-            scene::ISceneNode* node =
-                m_kart_model->getAnimatedNode() ?
-                m_kart_model->getAnimatedNode() : m_node;
-            if (m_vehicle->getNumWheels() > 0)
-            {
-                scene::ISceneNode **wheels = m_kart_model->getWheelNodes();
-                for (int i = 0; i < 4 && i < m_vehicle->getNumWheels(); ++i)
-                {
-                    if (wheels[i])
-                        wheels[i]->setParent(node);
-                }
-            }
-        }
-    }   // if squashed
-
-    if (m_bubblegum_ticks > 0.0f)
+    if (m_bubblegum_ticks > 0)
     {
         m_bubblegum_ticks -= ticks;
-        if (m_bubblegum_ticks <= 0.0f)
+        if (m_bubblegum_ticks <= 0)
         {
-            m_bubblegum_torque = 0.0f;
+            m_bubblegum_torque = 0;
         }
     }
 
@@ -1757,23 +1738,42 @@ void Kart::setSquash(float time, float slowdown)
         ExplosionAnimation::create(this);
         return;
     }
-    m_node->setScale(core::vector3df(1.0f, 0.5f, 1.0f));
+
     m_max_speed->setSlowdown(MaxSpeed::MS_DECREASE_SQUASH, slowdown,
                              stk_config->time2Ticks(0.1f), 
                              stk_config->time2Ticks(time));
-    if (m_vehicle->getNumWheels() > 0)
+
+#ifndef SERVER_ONLY
+    if (m_squash_time == std::numeric_limits<float>::max())
     {
-        if (!m_wheel_box)
-            m_wheel_box = irr_driver->getSceneManager()->addDummyTransformationSceneNode(m_node);
-        scene::ISceneNode **wheels = m_kart_model->getWheelNodes();
-        for (int i = 0; i < 4 && i < m_vehicle->getNumWheels(); ++i)
+        m_node->setScale(core::vector3df(1.0f, 0.5f, 1.0f));
+        if (m_vehicle->getNumWheels() > 0)
         {
-            if (wheels[i])
-                wheels[i]->setParent(m_wheel_box);
+            if (!m_wheel_box)
+            {
+                m_wheel_box = irr_driver->getSceneManager()
+                    ->addDummyTransformationSceneNode(m_node);
+            }
+            scene::ISceneNode **wheels = m_kart_model->getWheelNodes();
+            for (int i = 0; i < 4 && i < m_vehicle->getNumWheels(); i++)
+            {
+                if (wheels[i])
+                    wheels[i]->setParent(m_wheel_box);
+            }
+            m_wheel_box->getRelativeTransformationMatrix()
+                .setScale(core::vector3df(1.0f, 2.0f, 1.0f));
         }
-        m_wheel_box->getRelativeTransformationMatrix().setScale(core::vector3df(1.0f, 2.0f, 1.0f));
+        m_squash_time = time;
     }
-    m_squash_ticks  = stk_config->time2Ticks(time);
+#endif
+}   // setSquash
+
+//-----------------------------------------------------------------------------
+/** Returns if the kart is currently being squashed
+  */
+bool Kart::isSquashed() const
+{
+    return m_max_speed->isSpeedDecreaseActive(MaxSpeed::MS_DECREASE_SQUASH);
 }   // setSquash
 
 //-----------------------------------------------------------------------------
@@ -2946,6 +2946,30 @@ void Kart::updateGraphics(float dt)
         if (m_custom_sounds[n] != NULL) m_custom_sounds[n]->position(getXYZ());
     }
      */
+
+    if (m_squash_time != std::numeric_limits<float>::max())
+    {
+        m_squash_time -= dt;
+        // If squasing time ends, reset the model
+        if (m_squash_time <= 0.0f)
+        {
+            m_squash_time = std::numeric_limits<float>::max();
+            m_node->setScale(core::vector3df(1.0f, 1.0f, 1.0f));
+            scene::ISceneNode* node =
+                m_kart_model->getAnimatedNode() ?
+                m_kart_model->getAnimatedNode() : m_node;
+            if (m_vehicle->getNumWheels() > 0)
+            {
+                scene::ISceneNode **wheels = m_kart_model->getWheelNodes();
+                for (int i = 0; i < 4 && i < m_vehicle->getNumWheels(); ++i)
+                {
+                    if (wheels[i])
+                        wheels[i]->setParent(node);
+                }
+            }
+        }
+    }   // if squashed
+
     for (int i = 0; i < EMITTER_COUNT; i++)
         m_emitters[i]->setPosition(getXYZ());
     m_skid_sound->setPosition(getXYZ());
diff --git a/src/karts/kart.hpp b/src/karts/kart.hpp
index 9e78fe8d0..1fb864f82 100644
--- a/src/karts/kart.hpp
+++ b/src/karts/kart.hpp
@@ -160,17 +160,17 @@ protected:
     int          m_bounce_back_ticks;
 
     /** Time a kart is invulnerable. */
-    int          m_invulnerable_ticks;
+    int16_t      m_invulnerable_ticks;
 
     /** How long a kart is being squashed. If this is >0
      *  the kart is squashed. */
-    int          m_squash_ticks;
+    float        m_squash_time;
 
     /** Current leaning of the kart. */
     float        m_current_lean;
 
     /** If > 0 then bubble gum effect is on. This is the sliding when hitting a gum on the floor, not the shield. */
-    int          m_bubblegum_ticks;
+    int16_t      m_bubblegum_ticks;
 
     /** The torque to apply after hitting a bubble gum. */
     float        m_bubblegum_torque;
@@ -218,13 +218,10 @@ protected:
 
     /** When a kart has its view blocked by the plunger, this variable will be
      *  > 0 the number it contains is the time left before removing plunger. */
-    int           m_view_blocked_by_plunger;
+    int16_t       m_view_blocked_by_plunger;
     /** The current speed (i.e. length of velocity vector) of this kart. */
     float         m_speed;
-    /** For camera handling an exponentially smoothened value is used, which
-     *  reduces stuttering of the camera. */
-    float         m_smoothed_speed;
-    
+
     /** For smoothing engine sound**/
     float         m_last_factor_engine_sound;
 
@@ -499,7 +496,7 @@ public:
     virtual bool isOnMinNitroTime() const OVERRIDE { return m_min_nitro_ticks > 0; }
     // ------------------------------------------------------------------------
     /** Returns if the kart is currently being squashed. */
-    virtual bool isSquashed() const OVERRIDE { return m_squash_ticks >0; }
+    virtual bool isSquashed() const OVERRIDE;
     // ------------------------------------------------------------------------
     /** Shows the star effect for a certain time. */
     virtual void showStarEffect(float t) OVERRIDE;
diff --git a/src/karts/kart_rewinder.cpp b/src/karts/kart_rewinder.cpp
index 83e8edf0c..c0dfc0491 100644
--- a/src/karts/kart_rewinder.cpp
+++ b/src/karts/kart_rewinder.cpp
@@ -38,8 +38,7 @@ KartRewinder::KartRewinder(const std::string& ident,
                            const btTransform& init_transform,
                            PerPlayerDifficulty difficulty,
                            std::shared_ptr<RenderInfo> ri)
-            : Rewinder(std::string("K") + StringUtils::toString(world_kart_id),
-                       /*can_be_destroyed*/ false)
+            : Rewinder(std::string("K") + StringUtils::toString(world_kart_id))
             , Kart(ident, world_kart_id, position, init_transform, difficulty,
                    ri)
 {
@@ -144,6 +143,15 @@ BareNetworkString* KartRewinder::saveState(std::vector<std::string>* ru)
     // -----------
     m_skidding->saveState(buffer);
 
+    // 6) Firing and related handling
+    // -----------
+    buffer->addUInt16(m_bubblegum_ticks);
+    buffer->addUInt16(m_view_blocked_by_plunger);
+    // m_invulnerable_ticks will not be negative
+    uint16_t fire_and_invulnerable = (m_fire_clicked ? 1 << 15 : 0) |
+        m_invulnerable_ticks;
+    buffer->addUInt16(fire_and_invulnerable);
+
     return buffer;
 }   // saveState
 
@@ -203,15 +211,21 @@ void KartRewinder::restoreState(BareNetworkString *buffer, int count)
     float nitro = buffer->getFloat();
     setEnergy(nitro);
 
-    // 5) Max speed info
+    // 4) Max speed info
     // ------------------
     m_max_speed->rewindTo(buffer);
 
-    // 6) Skidding
+    // 5) Skidding
     // -----------
     m_skidding->rewindTo(buffer);
 
-    return;
+    // 6) Firing and related handling
+    // -----------
+    m_bubblegum_ticks = buffer->getUInt16();
+    m_view_blocked_by_plunger = buffer->getUInt16();
+    uint16_t fire_and_invulnerable = buffer->getUInt16();
+    m_fire_clicked = (fire_and_invulnerable >> 15) == 1;
+    m_invulnerable_ticks = fire_and_invulnerable & ~(1 << 15);
 }   // restoreState
 
 // ----------------------------------------------------------------------------
@@ -223,25 +237,16 @@ void KartRewinder::update(int ticks)
     Kart::update(ticks);
 }   // update
 
-// ----------------------------------------------------------------------------
-void KartRewinder::rewindToEvent(BareNetworkString *buffer)
-{
-}   // rewindToEvent
-
 // ----------------------------------------------------------------------------
 std::function<void()> KartRewinder::getLocalStateRestoreFunction()
 {
     if (m_eliminated)
         return nullptr;
 
-    // In theory all ticks / boolean related stuff can be saved locally
+    // Variable can be saved locally if its adjustment only depends on the kart
+    // itself
     bool has_started = m_has_started;
-    int bubblegum_ticks = m_bubblegum_ticks;
     int bounce_back_ticks = m_bounce_back_ticks;
-    int invulnerable_ticks = m_invulnerable_ticks;
-    int squash_ticks = m_squash_ticks;
-    bool fire_clicked = m_fire_clicked;
-    int view_blocked_by_plunger = m_view_blocked_by_plunger;
     int brake_ticks = m_brake_ticks;
     int8_t min_nitro_ticks = m_min_nitro_ticks;
 
@@ -259,18 +264,11 @@ std::function<void()> KartRewinder::getLocalStateRestoreFunction()
         steer_val_r = pc->m_steer_val_r;
     }
 
-    return [has_started, bubblegum_ticks, bounce_back_ticks,
-        invulnerable_ticks, squash_ticks, fire_clicked,
-        view_blocked_by_plunger, brake_ticks, min_nitro_ticks, initial_speed,
-        node_scale, steer_val_l, steer_val_r, this]()
+    return [has_started, bounce_back_ticks, brake_ticks, min_nitro_ticks,
+        initial_speed, node_scale, steer_val_l, steer_val_r, this]()
     {
         m_has_started = has_started;
-        m_bubblegum_ticks = bubblegum_ticks;
         m_bounce_back_ticks = bounce_back_ticks;
-        m_invulnerable_ticks = invulnerable_ticks;
-        m_squash_ticks = squash_ticks;
-        m_fire_clicked = fire_clicked;
-        m_view_blocked_by_plunger = view_blocked_by_plunger;
         m_brake_ticks = brake_ticks;
         m_min_nitro_ticks = min_nitro_ticks;
         getAttachment()->setInitialSpeed(initial_speed);
diff --git a/src/karts/kart_rewinder.hpp b/src/karts/kart_rewinder.hpp
index ebdd39b35..1c9beb254 100644
--- a/src/karts/kart_rewinder.hpp
+++ b/src/karts/kart_rewinder.hpp
@@ -48,7 +48,7 @@ public:
         OVERRIDE;
     void reset() OVERRIDE;
     virtual void restoreState(BareNetworkString *p, int count) OVERRIDE;
-    virtual void rewindToEvent(BareNetworkString *p) OVERRIDE;
+    virtual void rewindToEvent(BareNetworkString *p) OVERRIDE {}
     virtual void update(int ticks) OVERRIDE;
     // -------------------------------------------------------------------------
     virtual float getSteerPercent() const OVERRIDE
diff --git a/src/karts/max_speed.cpp b/src/karts/max_speed.cpp
index ad707c74e..fde8c6121 100644
--- a/src/karts/max_speed.cpp
+++ b/src/karts/max_speed.cpp
@@ -280,6 +280,15 @@ int MaxSpeed::getSpeedIncreaseTicksLeft(unsigned int category)
     return m_speed_increase[category].getTimeLeft();
 }   // getSpeedIncreaseTimeLeft
 
+// ----------------------------------------------------------------------------
+/** Returns if decreased speed is active in the given category.
+ *  \param category Which category to report on.
+ */
+int MaxSpeed::isSpeedDecreaseActive(unsigned int category)
+{
+    return m_speed_decrease[category].isActive();
+}   // isSpeedDecreaseActive
+
 // ----------------------------------------------------------------------------
 /** Updates all speed increase and decrease objects, and determines the
  *  current maximum speed. Note that the function can be called with
diff --git a/src/karts/max_speed.hpp b/src/karts/max_speed.hpp
index f22c17890..d3ec211a8 100644
--- a/src/karts/max_speed.hpp
+++ b/src/karts/max_speed.hpp
@@ -158,11 +158,13 @@ private:
         // --------------------------------------------------------------------
         /** Returns the current slowdown fracftion, taking a 'fade in'
          *  into account. */
-        float getSlowdownFraction() const {return m_current_fraction;}
+        float getSlowdownFraction() const        { return m_current_fraction; }
+        // --------------------------------------------------------------------
+        int getTimeLeft() const                          { return m_duration; }
         // --------------------------------------------------------------------
         /** Returns if this speed decrease is active atm. A duration of
          *  -1 indicates an ongoing effect. */
-        bool isActive() const { return m_duration > 0 || m_duration <= -1.0f; }
+        bool isActive() const    { return m_duration > 0 || m_duration <= -1; }
     };   // SpeedDecrease
 
     // ------------------------------------------------------------------------
@@ -188,6 +190,7 @@ public:
     void  setSlowdown(unsigned int category, float max_speed_fraction,
                       int fade_in_time, int duration=-1);
     int   getSpeedIncreaseTicksLeft(unsigned int category);
+    int   isSpeedDecreaseActive(unsigned int category);
     void  update(int ticks);
     void  reset();
     void  saveState(BareNetworkString *buffer) const;
diff --git a/src/karts/moveable.cpp b/src/karts/moveable.cpp
index de92b5d21..cf16491fe 100644
--- a/src/karts/moveable.cpp
+++ b/src/karts/moveable.cpp
@@ -62,7 +62,10 @@ void Moveable::setNode(scene::ISceneNode *n)
 //-----------------------------------------------------------------------------
 void Moveable::updateSmoothedGraphics(float dt)
 {
-    SmoothNetworkBody::updateSmoothedGraphics(m_transform, getVelocity(), dt);
+    Vec3 velocity;
+    if (m_body)
+        velocity = m_body->getLinearVelocity();
+    SmoothNetworkBody::updateSmoothedGraphics(m_transform, velocity, dt);
 #undef DEBUG_SMOOTHING
 #ifdef DEBUG_SMOOTHING
     // Gnuplot compare command
diff --git a/src/main.cpp b/src/main.cpp
index 08cef4d72..0a303d139 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -603,11 +603,13 @@ void cmdLineHelp()
     "       --disable-lan      Disable LAN detection (connect using WAN).\n"
     "       --auto-connect     Automatically connect to fist server and start race\n"
     "       --max-players=n    Maximum number of clients (server only).\n"
+    "       --min-players=n    Minimum number of clients (server only).\n"
     "       --motd             Message showing in all lobby of clients, can specify a .txt file.\n"
     "       --auto-end         Automatically end network game after 1st player finished\n"
     "                          for some time (currently his finished time * 0.25 + 15.0). \n"
     "       --team-choosing    Allow choosing team in lobby, implicitly allowed in lan or\n"
-    "                          password protected server.\n"
+    "                          password protected server. This function cannot be used in\n"
+    "                          owner-less server.\n"
     "       --soccer-timed     Use time limit mode in network soccer game.\n"
     "       --soccer-goals     Use goals limit mode in network soccer game.\n"
     "       --network-gp=n     Specify number of tracks used in network grand prix.\n"
@@ -1139,12 +1141,28 @@ int handleCmdLine()
         NetworkConfig::get()->setServerIdFile(
             file_manager->getUserConfigFile(s));
     }
-    if(CommandLine::has("--disable-polling"))
+    if (CommandLine::has("--disable-polling"))
+    {
         Online::RequestManager::m_disable_polling = true;
-    if(CommandLine::has("--max-players", &n))
-        UserConfigParams::m_server_max_players=n;
-    NetworkConfig::get()->
-        setMaxPlayers(UserConfigParams::m_server_max_players);
+    }
+    if (CommandLine::has("--max-players", &n))
+    {
+        UserConfigParams::m_server_max_players = n;
+    }
+    
+    if (UserConfigParams::m_server_max_players < 1)
+    {
+        UserConfigParams::m_server_max_players = 1;
+    }
+    NetworkConfig::get()->setMaxPlayers(UserConfigParams::m_server_max_players);
+        
+    if (CommandLine::has("--min-players", &n))
+    {
+        float threshold = ((float)(n) - 0.5f) / 
+                                         UserConfigParams::m_server_max_players;
+        threshold = std::max(std::min(threshold, 1.0f), 0.0f);
+        UserConfigParams::m_start_game_threshold = threshold;
+    }
     if (CommandLine::has("--port", &n))
     {
         // We don't know if this instance is going to be a client
@@ -1158,7 +1176,8 @@ int handleCmdLine()
     }
     if (CommandLine::has("--team-choosing"))
     {
-        NetworkConfig::get()->setTeamChoosing(true);
+        if (!NetworkConfig::get()->isOwnerLess())
+            NetworkConfig::get()->setTeamChoosing(true);
     }
     if (CommandLine::has("--connect-now", &s))
     {
diff --git a/src/modes/cutscene_world.cpp b/src/modes/cutscene_world.cpp
index e8a018b01..32a2e6de7 100644
--- a/src/modes/cutscene_world.cpp
+++ b/src/modes/cutscene_world.cpp
@@ -56,7 +56,8 @@ CutsceneWorld::CutsceneWorld() : World()
 {
     m_time_at_second_reset = 0.0f;
     m_aborted = false;
-    WorldStatus::setClockMode(CLOCK_NONE);
+    WorldStatus::setClockMode(CLOCK_CHRONO);
+    m_phase = RACE_PHASE;
     m_use_highscores = false;
     m_play_track_intro_sound = false;
     m_play_ready_set_go_sounds = false;
@@ -170,7 +171,12 @@ void CutsceneWorld::init()
 CutsceneWorld::~CutsceneWorld()
 {
 }   // ~CutsceneWorld
-
+//-----------------------------------------------------------------------------
+void CutsceneWorld::reset()
+{
+    World::reset();
+    m_phase = RACE_PHASE;
+}
 //-----------------------------------------------------------------------------
 /** Returns the internal identifier for this race.
  */
@@ -231,7 +237,6 @@ void CutsceneWorld::update(int ticks)
     {
         // this way of calculating time and dt is more in line with what
         // irrlicht does and provides better synchronisation
-        double prev_time = m_time;
         double now = StkTime::getRealTime();
         m_time = now - m_time_at_second_reset;
     }
diff --git a/src/modes/cutscene_world.hpp b/src/modes/cutscene_world.hpp
index 5b8fd84bc..cc30a7672 100644
--- a/src/modes/cutscene_world.hpp
+++ b/src/modes/cutscene_world.hpp
@@ -65,6 +65,8 @@ public:
 
     virtual void init() OVERRIDE;
 
+    virtual void reset() OVERRIDE;
+
     // clock events
     virtual bool isRaceOver() OVERRIDE;
 
diff --git a/src/modes/linear_world.cpp b/src/modes/linear_world.cpp
index e03eab9f7..c5f7f7059 100644
--- a/src/modes/linear_world.cpp
+++ b/src/modes/linear_world.cpp
@@ -176,7 +176,7 @@ void LinearWorld::update(int ticks)
     for(unsigned int n=0; n<kart_amount; n++)
     {
         KartInfo& kart_info = m_kart_info[n];
-        AbstractKart* kart = m_karts[n];
+        AbstractKart* kart = m_karts[n].get();
 
         // Nothing to do for karts that are currently being
         // rescued or eliminated
@@ -218,7 +218,7 @@ void LinearWorld::update(int ticks)
         // Update the estimated finish time.
         // This is used by the AI
         m_kart_info[i].m_estimated_finish =
-                estimateFinishTimeForKart(m_karts[i]);
+                estimateFinishTimeForKart(m_karts[i].get());
     }
     // If one player and a ghost, or two compared ghosts,
     // compute the live time difference
@@ -328,7 +328,7 @@ void LinearWorld::updateLiveDifference()
 void LinearWorld::newLap(unsigned int kart_index)
 {
     KartInfo &kart_info = m_kart_info[kart_index];
-    AbstractKart *kart  = m_karts[kart_index];
+    AbstractKart *kart  = m_karts[kart_index].get();
 
     // Reset reset-after-lap achievements
     PlayerProfile *p = PlayerManager::getCurrentPlayer();
@@ -556,7 +556,7 @@ void LinearWorld::getKartsDisplayInfo(
     for(unsigned int i = 0; i < kart_amount ; i++)
     {
         RaceGUIBase::KartIconDisplayInfo& rank_info = (*info)[i];
-        AbstractKart* kart = m_karts[i];
+        AbstractKart* kart = m_karts[i].get();
 
         // reset color
         rank_info.m_color = video::SColor(255, 255, 255, 255);
@@ -585,7 +585,7 @@ void LinearWorld::getKartsDisplayInfo(
     {
         RaceGUIBase::KartIconDisplayInfo& rank_info = (*info)[i];
         KartInfo& kart_info = m_kart_info[i];
-        AbstractKart* kart = m_karts[i];
+        AbstractKart* kart = m_karts[i].get();
 
         const int position = kart->getPosition();
 
@@ -799,7 +799,7 @@ void LinearWorld::updateRacePosition()
     // so that debug output is still correct!!!!!!!!!!!
     for (unsigned int i=0; i<kart_amount; i++)
     {
-        AbstractKart* kart = m_karts[i];
+        AbstractKart* kart = m_karts[i].get();
         // Karts that are either eliminated or have finished the
         // race already have their (final) position assigned. If
         // these karts would get their rank updated, it could happen
@@ -898,7 +898,7 @@ void LinearWorld::updateRacePosition()
         Log::debug("[LinearWorld]", "Counting laps at %u seconds.", getTime());
         for (unsigned int i=0; i<kart_amount; i++)
         {
-            AbstractKart* kart = m_karts[i];
+            AbstractKart* kart = m_karts[i].get();
             Log::debug("[LinearWorld]", "counting karts ahead of %s (laps %u,"
                         " progress %u, finished %d, eliminated %d, initial position %u.",
                         kart->getIdent().c_str(),
@@ -973,7 +973,7 @@ void LinearWorld::checkForWrongDirection(unsigned int i, float dt)
 
     KartInfo &ki = m_kart_info[i];
     
-    const AbstractKart *kart=m_karts[i];
+    const AbstractKart *kart=m_karts[i].get();
     // If the kart can go in more than one directions from the current track
     // don't do any reverse message handling, since it is likely that there
     // will be one direction in which it isn't going backwards anyway.
diff --git a/src/modes/profile_world.cpp b/src/modes/profile_world.cpp
index 6f735b92e..147577aa0 100644
--- a/src/modes/profile_world.cpp
+++ b/src/modes/profile_world.cpp
@@ -103,19 +103,18 @@ void ProfileWorld::setProfileModeLaps(int laps)
  *         this player globally (i.e. including network players).
  *  \param init_pos The start XYZ coordinates.
  */
-AbstractKart *ProfileWorld::createKart(const std::string &kart_ident, int index,
-                                       int local_player_id, int global_player_id,
-                                       RaceManager::KartType type,
-                                       PerPlayerDifficulty difficulty)
+std::shared_ptr<AbstractKart> ProfileWorld::createKart
+    (const std::string &kart_ident, int index, int local_player_id,
+    int global_player_id, RaceManager::KartType kart_type,
+    PerPlayerDifficulty difficulty)
 {
     btTransform init_pos   = getStartTransform(index);
 
-    Kart *new_kart         = new KartWithStats(kart_ident,
-                                               /*world kart id*/ index,
-                                               /*position*/ index+1,
-                                               init_pos, difficulty);
+    std::shared_ptr<KartWithStats> new_kart =
+        std::make_shared<KartWithStats>(kart_ident, /*world kart id*/ index,
+        /*position*/ index + 1, init_pos, difficulty);
     new_kart->init(RaceManager::KT_AI);
-    Controller *controller = loadAIController(new_kart);
+    Controller *controller = loadAIController(new_kart.get());
     new_kart->setController(controller);
 
     // Create a camera for the last kart (since this way more of the
@@ -123,7 +122,7 @@ AbstractKart *ProfileWorld::createKart(const std::string &kart_ident, int index,
     if (index == (int)race_manager->getNumberOfKarts()-1)
     {
         // The camera keeps track of all cameras and will free them
-        Camera::createCamera(new_kart, local_player_id);
+        Camera::createCamera(new_kart.get(), local_player_id);
     }
     return new_kart;
 }   // createKart
@@ -197,7 +196,7 @@ void ProfileWorld::enterRaceOverState()
         // ---------- update rank ------
         if (m_karts[i]->hasFinishedRace() || m_karts[i]->isEliminated())
             continue;
-        m_karts[i]->finishedRace(estimateFinishTimeForKart(m_karts[i]));
+        m_karts[i]->finishedRace(estimateFinishTimeForKart(m_karts[i].get()));
     }
 
     // Print framerate statistics
@@ -229,9 +228,9 @@ void ProfileWorld::enterRaceOverState()
 
     std::set<std::string> all_groups;
 
-    for ( KartList::size_type i = 0; i < m_karts.size(); ++i)
+    for (KartList::size_type i = 0; i < m_karts.size(); ++i)
     {
-        KartWithStats* kart = dynamic_cast<KartWithStats*>(m_karts[i]);
+        auto kart = std::dynamic_pointer_cast<KartWithStats>(m_karts[i]);
 
         max_t = std::max(max_t, kart->getFinishTime());
         min_t = std::min(min_t, kart->getFinishTime());
@@ -285,7 +284,7 @@ void ProfileWorld::enterRaceOverState()
         float av_time       = 0.0f, energy          = 0;
         for ( unsigned int i = 0; i < (unsigned int)m_karts.size(); ++i)
         {
-            KartWithStats* kart = dynamic_cast<KartWithStats*>(m_karts[i]);
+            auto kart = std::dynamic_pointer_cast<KartWithStats>(m_karts[i]);
             const std::string &name=kart->getController()->getControllerName();
             if(name!=*it)
                 continue;
diff --git a/src/modes/profile_world.hpp b/src/modes/profile_world.hpp
index c4c1e0e00..255e9a4ba 100644
--- a/src/modes/profile_world.hpp
+++ b/src/modes/profile_world.hpp
@@ -72,10 +72,10 @@ protected:
      *  used by DemoWorld. */
     static int   m_num_laps;
 
-    virtual AbstractKart *createKart(const std::string &kart_ident, int index,
-                                     int local_player_id, int global_player_id,
-                                     RaceManager::KartType type,
-                                     PerPlayerDifficulty difficulty);
+    virtual std::shared_ptr<AbstractKart> createKart
+        (const std::string &kart_ident, int index, int local_player_id,
+        int global_player_id, RaceManager::KartType type,
+        PerPlayerDifficulty difficulty);
 
 public:
                           ProfileWorld();
diff --git a/src/modes/soccer_world.cpp b/src/modes/soccer_world.cpp
index b1e11448b..fbb4db5e7 100644
--- a/src/modes/soccer_world.cpp
+++ b/src/modes/soccer_world.cpp
@@ -38,6 +38,8 @@
 #include "network/stk_host.hpp"
 #include "physics/physics.hpp"
 #include "states_screens/race_gui_base.hpp"
+#include "tracks/graph.hpp"
+#include "tracks/quad.hpp"
 #include "tracks/track.hpp"
 #include "tracks/track_object_manager.hpp"
 #include "tracks/track_sector.hpp"
@@ -120,6 +122,7 @@ void SoccerWorld::init()
         Log::fatal("SoccerWorld","Ball is missing in soccer field, abort.");
 
     m_bgd.init(m_ball->getPhysicalObject()->getRadius());
+    m_ball_body->setActivationState(DISABLE_DEACTIVATION);
 
 }   // init
 
@@ -211,10 +214,10 @@ const std::string& SoccerWorld::getIdent() const
 void SoccerWorld::update(int ticks)
 {
     updateBallPosition(ticks);
+    updateSectorForKarts();
     if (Track::getCurrentTrack()->hasNavMesh() &&
         !NetworkConfig::get()->isNetworking())
     {
-        updateSectorForKarts();
         updateAIData();
     }
 
@@ -225,7 +228,7 @@ void SoccerWorld::update(int ticks)
     {
         for (unsigned int i = 0; i < m_karts.size(); i++)
         {
-            AbstractKart* kart = m_karts[i];
+            auto& kart = m_karts[i];
             if (kart->isEliminated())
                 continue;
             kart->getBody()->setLinearVelocity(Vec3(0.0f));
@@ -332,7 +335,7 @@ void SoccerWorld::onCheckGoalTriggered(bool first_goal)
     }
     for (unsigned i = 0; i < m_karts.size(); i++)
     {
-        AbstractKart* kart = m_karts[i];
+        auto& kart = m_karts[i];
         if (kart->isEliminated())
             continue;
         kart->getBody()->setLinearVelocity(Vec3(0.0f));
@@ -353,7 +356,7 @@ void SoccerWorld::handleResetBallFromServer(const NetworkString& ns)
             "%d when reset player", ticks_back_to_own_goal, ticks_now);
         return;
     }
-    RewindManager::get()->getRewindQueue().insertRewindInfo(new
+    RewindManager::get()->addRewindInfoEventFunction(new
         RewindInfoEventFunction(ticks_back_to_own_goal,
         [](){}, std::bind(&SoccerWorld::resetKartsToSelfGoals, this)));
 
@@ -403,7 +406,7 @@ void SoccerWorld::handlePlayerGoalFromServer(const NetworkString& ns)
     m_ball->setEnabled(false);
     for (unsigned i = 0; i < m_karts.size(); i++)
     {
-        AbstractKart* kart = m_karts[i];
+        auto& kart = m_karts[i];
         if (kart->isEliminated())
             continue;
         btTransform transform_now = kart->getBody()->getWorldTransform();
@@ -413,7 +416,7 @@ void SoccerWorld::handlePlayerGoalFromServer(const NetworkString& ns)
         kart->setTrans(transform_now);
         m_goal_transforms[i] = transform_now;
     }
-    RewindManager::get()->getRewindQueue().insertRewindInfo(new
+    RewindManager::get()->addRewindInfoEventFunction(new
         RewindInfoEventFunction(ticks_back_to_own_goal,
         [](){}, std::bind(&SoccerWorld::resetKartsToSelfGoals, this)));
 
@@ -428,7 +431,7 @@ void SoccerWorld::resetKartsToSelfGoals()
     setPhase(WorldStatus::RACE_PHASE);
     for (unsigned i = 0; i < m_karts.size(); i++)
     {
-        AbstractKart* kart = m_karts[i];
+        auto& kart = m_karts[i];
         if (kart->isEliminated())
             continue;
 
@@ -436,7 +439,7 @@ void SoccerWorld::resetKartsToSelfGoals()
         kart->getBody()->setAngularVelocity(Vec3(0.0f));
         unsigned index = m_kart_position_map.at(kart->getWorldKartId());
         btTransform t = Track::getCurrentTrack()->getStartTransform(index);
-        moveKartTo(kart, t);
+        moveKartTo(kart.get(), t);
     }
 }   // resetKartsToSelfGoals
 
@@ -529,10 +532,10 @@ bool SoccerWorld::getKartSoccerResult(unsigned int kart_id) const
 }   // getKartSoccerResult
 
 //-----------------------------------------------------------------------------
-AbstractKart *SoccerWorld::createKart(const std::string &kart_ident, int index,
-                                int local_player_id, int global_player_id,
-                                RaceManager::KartType kart_type,
-                                PerPlayerDifficulty difficulty)
+std::shared_ptr<AbstractKart> SoccerWorld::createKart
+    (const std::string &kart_ident, int index, int local_player_id,
+    int global_player_id, RaceManager::KartType kart_type,
+    PerPlayerDifficulty difficulty)
 {
     int cur_red = getTeamNum(SOCCER_TEAM_RED);
     int cur_blue = getTeamNum(SOCCER_TEAM_BLUE);
@@ -587,16 +590,19 @@ AbstractKart *SoccerWorld::createKart(const std::string &kart_ident, int index,
     std::shared_ptr<RenderInfo> ri = std::make_shared<RenderInfo>();
     ri = (team == SOCCER_TEAM_BLUE ? std::make_shared<RenderInfo>(0.66f) :
         std::make_shared<RenderInfo>(1.0f));
-    AbstractKart* new_kart;
+
+    std::shared_ptr<AbstractKart> new_kart;
     if (RewindManager::get()->isEnabled())
     {
-        new_kart = new KartRewinder(kart_ident, index, position, init_pos,
-            difficulty, ri);
+        auto kr = std::make_shared<KartRewinder>(kart_ident, index, position,
+            init_pos, difficulty, ri);
+        kr->rewinderAdd();
+        new_kart = kr;
     }
     else
     {
-        new_kart = new Kart(kart_ident, index, position, init_pos, difficulty,
-            ri);
+        new_kart = std::make_shared<Kart>(kart_ident, index, position,
+            init_pos, difficulty, ri);
     }
 
     new_kart->init(race_manager->getKartType(index));
@@ -605,18 +611,18 @@ AbstractKart *SoccerWorld::createKart(const std::string &kart_ident, int index,
     switch(kart_type)
     {
     case RaceManager::KT_PLAYER:
-        controller = new LocalPlayerController(new_kart, local_player_id,
+        controller = new LocalPlayerController(new_kart.get(), local_player_id,
             difficulty);
         m_num_players ++;
         break;
     case RaceManager::KT_NETWORK_PLAYER:
-        controller = new NetworkPlayerController(new_kart);
+        controller = new NetworkPlayerController(new_kart.get());
         if (!online_name.empty())
             new_kart->setOnScreenText(online_name.c_str());
         m_num_players++;
         break;
     case RaceManager::KT_AI:
-        controller = loadAIController(new_kart);
+        controller = loadAIController(new_kart.get());
         break;
     case RaceManager::KT_GHOST:
         break;
@@ -808,13 +814,26 @@ int SoccerWorld::getTeamNum(SoccerTeam team) const
 //-----------------------------------------------------------------------------
 unsigned int SoccerWorld::getRescuePositionIndex(AbstractKart *kart)
 {
-    std::map<int, unsigned int>::const_iterator n =
-        m_kart_position_map.find(kart->getWorldKartId());
-
-    assert (n != m_kart_position_map.end());
-    return n->second;
+    int last_valid_node =
+        getTrackSector(kart->getWorldKartId())->getLastValidGraphNode();
+    if (last_valid_node >= 0)
+        return last_valid_node;
+    Log::warn("SoccerWorld", "Missing last valid node for rescuing");
+    return 0;
 }   // getRescuePositionIndex
 
+//-----------------------------------------------------------------------------
+btTransform SoccerWorld::getRescueTransform(unsigned int rescue_pos) const
+{
+    const Vec3 &xyz = Graph::get()->getQuad(rescue_pos)->getCenter();
+    const Vec3 &normal = Graph::get()->getQuad(rescue_pos)->getNormal();
+    btTransform pos;
+    pos.setOrigin(xyz);
+    btQuaternion q1 = shortestArcQuat(Vec3(0.0f, 1.0f, 0.0f), normal);
+    pos.setRotation(q1);
+    return pos;
+}   // getRescueTransform
+
 //-----------------------------------------------------------------------------
 void SoccerWorld::enterRaceOverState()
 {
diff --git a/src/modes/soccer_world.hpp b/src/modes/soccer_world.hpp
index 3fe790aa5..190f76b3a 100644
--- a/src/modes/soccer_world.hpp
+++ b/src/modes/soccer_world.hpp
@@ -51,10 +51,10 @@ public:
     };   // ScorerData
 
 protected:
-    virtual AbstractKart *createKart(const std::string &kart_ident, int index,
-                             int local_player_id, int global_player_id,
-                             RaceManager::KartType type,
-                             PerPlayerDifficulty difficulty) OVERRIDE;
+    virtual std::shared_ptr<AbstractKart> createKart
+        (const std::string &kart_ident, int index, int local_player_id,
+        int global_player_id, RaceManager::KartType type,
+        PerPlayerDifficulty difficulty) OVERRIDE;
 
 private:
     class KartDistanceMap
@@ -329,7 +329,8 @@ public:
     virtual void reset() OVERRIDE;
 
     virtual unsigned int getRescuePositionIndex(AbstractKart *kart) OVERRIDE;
-
+    virtual btTransform getRescueTransform(unsigned int rescue_pos) const
+        OVERRIDE;
     virtual bool useFastMusicNearEnd() const OVERRIDE { return false; }
     virtual void getKartsDisplayInfo(
                std::vector<RaceGUIBase::KartIconDisplayInfo> *info) OVERRIDE {}
diff --git a/src/modes/standard_race.cpp b/src/modes/standard_race.cpp
index e701c6e6b..b90152369 100644
--- a/src/modes/standard_race.cpp
+++ b/src/modes/standard_race.cpp
@@ -103,7 +103,7 @@ void StandardRace::endRaceEarly()
     for (unsigned int i = 1; i <= kart_amount; i++)
     {
         int kartid = m_position_index[i-1];
-        AbstractKart* kart = m_karts[kartid];
+        AbstractKart* kart = m_karts[kartid].get();
 
         if (kart->hasFinishedRace())
         {
@@ -140,7 +140,7 @@ void StandardRace::endRaceEarly()
         int kartid = active_players[i];
         int position = getNumKarts() - (int) active_players.size() + 1 + i;
         setKartPosition(kartid, position);
-        float punished_time = estimateFinishTimeForKart(m_karts[kartid])
+        float punished_time = estimateFinishTimeForKart(m_karts[kartid].get())
                               + worse_finish_time - WorldStatus::getTime();
         m_karts[kartid]->finishedRace(punished_time);
 
diff --git a/src/modes/three_strikes_battle.cpp b/src/modes/three_strikes_battle.cpp
index b21d504f8..14c930854 100644
--- a/src/modes/three_strikes_battle.cpp
+++ b/src/modes/three_strikes_battle.cpp
@@ -722,18 +722,18 @@ void ThreeStrikesBattle::loadCustomModels()
             // Now add them
             for (unsigned int i = 0; i < pos.size(); i++)
             {
-                AbstractKart* sta = new Kart(sta_list[i], (int)m_karts.size(),
+                auto sta = std::make_shared<Kart>(sta_list[i], (int)m_karts.size(),
                     (int)m_karts.size() + 1, pos[i], PLAYER_DIFFICULTY_NORMAL,
                     std::make_shared<RenderInfo>(1.0f));
                 sta->init(RaceManager::KartType::KT_SPARE_TIRE);
-                sta->setController(new SpareTireAI(sta));
+                sta->setController(new SpareTireAI(sta.get()));
 
                 m_karts.push_back(sta);
                 race_manager->addSpareTireKart(sta_list[i]);
 
                 // Copy STA pointer to m_spare_tire_karts array, allowing them
                 // to respawn easily
-                m_spare_tire_karts.push_back(sta);
+                m_spare_tire_karts.push_back(sta.get());
             }
             unsigned int sta_num = race_manager->getNumSpareTireKarts();
             assert(m_spare_tire_karts.size() == sta_num);
diff --git a/src/modes/world.cpp b/src/modes/world.cpp
index 2d434bf7b..bb2b0c54c 100644
--- a/src/modes/world.cpp
+++ b/src/modes/world.cpp
@@ -120,7 +120,7 @@ World* World::m_world = NULL;
  */
 World::World() : WorldStatus()
 {
-
+    RewindManager::setEnable(NetworkConfig::get()->isNetworking());
 #ifdef DEBUG
     m_magic_number = 0xB01D6543;
 #endif
@@ -212,10 +212,9 @@ void World::init()
                                : race_manager->getKartIdent(i);
         int local_player_id  = race_manager->getKartLocalPlayerId(i);
         int global_player_id = race_manager->getKartGlobalPlayerId(i);
-        AbstractKart* newkart = createKart(kart_ident, i, local_player_id,
-                                   global_player_id,
-                                   race_manager->getKartType(i),
-                                   race_manager->getPlayerDifficulty(i));
+        auto newkart = createKart(kart_ident, i, local_player_id,
+            global_player_id, race_manager->getKartType(i),
+            race_manager->getPlayerDifficulty(i));
         m_karts.push_back(newkart);
 
     }  // for i
@@ -301,6 +300,7 @@ void World::reset()
     SFXManager::get()->resumeAll();
 
     projectile_manager->cleanup();
+    RewindManager::get()->reset();
     race_manager->reset();
     // Make sure to overwrite the data from the previous race.
     if(!history->replayHistory()) history->initRecording();
@@ -334,10 +334,10 @@ void World::createRaceGUI()
  *  \param global_player_id If the kart is a player kart this is the index of
  *         this player globally (i.e. including network players).
  */
-AbstractKart *World::createKart(const std::string &kart_ident, int index,
-                                int local_player_id, int global_player_id,
-                                RaceManager::KartType kart_type,
-                                PerPlayerDifficulty difficulty)
+std::shared_ptr<AbstractKart> World::createKart
+    (const std::string &kart_ident, int index, int local_player_id,
+    int global_player_id, RaceManager::KartType kart_type,
+    PerPlayerDifficulty difficulty)
 {
     unsigned int gk = 0;
     if (race_manager->hasGhostKarts())
@@ -355,13 +355,19 @@ AbstractKart *World::createKart(const std::string &kart_ident, int index,
 
     int position           = index+1;
     btTransform init_pos   = getStartTransform(index - gk);
-    AbstractKart *new_kart;
+    std::shared_ptr<AbstractKart> new_kart;
     if (RewindManager::get()->isEnabled())
-        new_kart = new KartRewinder(kart_ident, index, position, init_pos,
-                                    difficulty, ri);
+    {
+        auto kr = std::make_shared<KartRewinder>(kart_ident, index, position,
+            init_pos, difficulty, ri);
+        kr->rewinderAdd();
+        new_kart = kr;
+    }
     else
-        new_kart = new Kart(kart_ident, index, position, init_pos, difficulty,
-                            ri);
+    {
+        new_kart = std::make_shared<Kart>(kart_ident, index, position,
+            init_pos, difficulty, ri);
+    }
 
     new_kart->init(race_manager->getKartType(index));
     Controller *controller = NULL;
@@ -369,7 +375,7 @@ AbstractKart *World::createKart(const std::string &kart_ident, int index,
     {
     case RaceManager::KT_PLAYER:
     {
-        controller = new LocalPlayerController(new_kart, local_player_id,
+        controller = new LocalPlayerController(new_kart.get(), local_player_id,
             difficulty);
         const PlayerProfile* p = StateManager::get()
             ->getActivePlayer(local_player_id)->getConstProfile();
@@ -383,7 +389,7 @@ AbstractKart *World::createKart(const std::string &kart_ident, int index,
     }
     case RaceManager::KT_NETWORK_PLAYER:
     {
-        controller = new NetworkPlayerController(new_kart);
+        controller = new NetworkPlayerController(new_kart.get());
         if (!online_name.empty())
             new_kart->setOnScreenText(online_name.c_str());
         m_num_players++;
@@ -391,7 +397,7 @@ AbstractKart *World::createKart(const std::string &kart_ident, int index,
     }
     case RaceManager::KT_AI:
     {
-        controller = loadAIController(new_kart);
+        controller = loadAIController(new_kart.get());
         break;
     }
     case RaceManager::KT_GHOST:
@@ -417,7 +423,7 @@ const btTransform &World::getStartTransform(int index)
 /** Creates an AI controller for the kart.
  *  \param kart The kart to be controlled by an AI.
  */
-Controller* World::loadAIController(AbstractKart *kart)
+Controller* World::loadAIController(AbstractKart* kart)
 {
     Controller *controller;
     int turn=0;
@@ -485,13 +491,7 @@ World::~World()
     
     Weather::kill();
 
-    for ( unsigned int i = 0 ; i < m_karts.size() ; i++ )
-    {
-        // Let ReplayPlay destroy the ghost karts
-        if (m_karts[i]->isGhostKart()) continue;
-        delete m_karts[i];
-    }
-
+    m_karts.clear();
     if(race_manager->hasGhostKarts() || race_manager->isRecordingRace())
     {
         // Destroy the old replay object, which also stored the ghost
@@ -502,7 +502,6 @@ World::~World()
         ReplayPlay::destroy();
         ReplayPlay::create();
     }
-    m_karts.clear();
     if(race_manager->isRecordingRace())
         ReplayRecorder::get()->reset();
     race_manager->setRaceGhostKarts(false);
@@ -567,7 +566,8 @@ void World::terminateRace()
     {
         if(!m_karts[i]->hasFinishedRace() && !m_karts[i]->isEliminated())
         {
-            m_karts[i]->finishedRace(estimateFinishTimeForKart(m_karts[i]));
+            m_karts[i]->finishedRace(
+                estimateFinishTimeForKart(m_karts[i].get()));
 
         }
     }   // i<kart_amount
@@ -699,7 +699,7 @@ void World::resetAllKarts()
                 btTransform t = getRescueTransform(rescue_pos);
                 // This will print out warnings if there is no terrain under
                 // the kart, or the kart is being dropped on a reset texture
-                moveKartTo(m_karts[kart_id], t);
+                moveKartTo(m_karts[kart_id].get(), t);
 
             }   // rescue_pos<getNumberOfRescuePositions
 
@@ -725,7 +725,7 @@ void World::resetAllKarts()
         Vec3 up_offset = (*i)->getNormal() * (0.5f * ((*i)->getKartHeight()));
         (*i)->setXYZ(xyz+up_offset);
 
-        bool kart_over_ground = Track::getCurrentTrack()->findGround(*i);
+        bool kart_over_ground = Track::getCurrentTrack()->findGround(i->get());
 
         if (!kart_over_ground)
         {
@@ -1055,14 +1055,16 @@ void World::update(int ticks)
             m_karts[i]->update(ticks);
     }
     PROFILER_POP_CPU_MARKER();
-
     if(race_manager->isRecordingRace()) ReplayRecorder::get()->update(ticks);
-    Physics::getInstance()->update(ticks);
 
     PROFILER_PUSH_CPU_MARKER("World::update (projectiles)", 0xa0, 0x7F, 0x00);
     projectile_manager->update(ticks);
     PROFILER_POP_CPU_MARKER();
 
+    PROFILER_PUSH_CPU_MARKER("World::update (physics)", 0xa0, 0x7F, 0x00);
+    Physics::getInstance()->update(ticks);
+    PROFILER_POP_CPU_MARKER();
+
     PROFILER_POP_CPU_MARKER();
 
 #ifdef DEBUG
@@ -1165,7 +1167,7 @@ void World::updateHighscores(int* best_highscore_rank)
         if (!m_karts[index[pos]]->hasFinishedRace()) continue;
 
         assert(index[pos] < m_karts.size());
-        Kart *k = (Kart*)m_karts[index[pos]];
+        Kart *k = (Kart*)m_karts[index[pos]].get();
 
         Highscores* highscores = getHighscores();
 
@@ -1197,14 +1199,17 @@ void World::updateHighscores(int* best_highscore_rank)
  */
 AbstractKart *World::getPlayerKart(unsigned int n) const
 {
-    unsigned int count=-1;
+    unsigned int count = -1;
 
-    for(unsigned int i=0; i<m_karts.size(); i++)
-        if(m_karts[i]->getController()->isPlayerController())
+    for(unsigned int i = 0; i < m_karts.size(); i++)
+    {
+        if (m_karts[i]->getController()->isPlayerController())
         {
             count++;
-            if(count==n) return m_karts[i];
+            if (count == n)
+                return m_karts[i].get();
         }
+    }
     return NULL;
 }   // getPlayerKart
 
@@ -1225,7 +1230,7 @@ AbstractKart *World::getLocalPlayerKart(unsigned int n) const
 void World::eliminateKart(int kart_id, bool notify_of_elimination)
 {
     assert(kart_id < (int)m_karts.size());
-    AbstractKart *kart = m_karts[kart_id];
+    AbstractKart *kart = m_karts[kart_id].get();
     if (kart->isGhostKart()) return;
 
     // Display a message about the eliminated kart in the race guia
diff --git a/src/modes/world.hpp b/src/modes/world.hpp
index 4be4522e6..34ba7a37d 100644
--- a/src/modes/world.hpp
+++ b/src/modes/world.hpp
@@ -25,6 +25,7 @@
   * battle, etc.)
   */
 
+#include <memory>
 #include <vector>
 #include <stdexcept>
 
@@ -80,7 +81,7 @@ public:
 class World : public WorldStatus
 {
 public:
-    typedef std::vector<AbstractKart*> KartList;
+    typedef std::vector<std::shared_ptr<AbstractKart> > KartList;
 private:
     /** A pointer to the global world object for a race. */
     static World *m_world;
@@ -117,10 +118,10 @@ protected:
     Controller*
           loadAIController  (AbstractKart *kart);
 
-    virtual AbstractKart *createKart(const std::string &kart_ident, int index,
-                             int local_player_id, int global_player_id,
-                             RaceManager::KartType type,
-                             PerPlayerDifficulty difficulty);
+    virtual std::shared_ptr<AbstractKart> createKart
+        (const std::string &kart_ident, int index, int local_player_id,
+        int global_player_id, RaceManager::KartType type,
+        PerPlayerDifficulty difficulty);
 
     /** Pointer to the race GUI. The race GUI is handled by world. */
     RaceGUIBase *m_race_gui;
@@ -293,7 +294,7 @@ public:
     /** Returns the kart with a given world id. */
     AbstractKart       *getKart(int kartId) const {
                         assert(kartId >= 0 && kartId < int(m_karts.size()));
-                        return m_karts[kartId];                              }
+                        return m_karts[kartId].get();                              }
     // ------------------------------------------------------------------------
     /** Returns all karts. */
     const KartList & getKarts() const { return m_karts; }
diff --git a/src/modes/world_status.hpp b/src/modes/world_status.hpp
index 66afdacda..4da315508 100644
--- a/src/modes/world_status.hpp
+++ b/src/modes/world_status.hpp
@@ -112,9 +112,9 @@ private:
 protected:
     bool            m_play_track_intro_sound;
     bool            m_play_ready_set_go_sounds;
+    Phase           m_phase;
 
 private:
-    Phase           m_phase;
 
     /**
       * Remember previous phase e.g. on pause
diff --git a/src/modes/world_with_rank.cpp b/src/modes/world_with_rank.cpp
index 6d23e20f2..862b3182d 100644
--- a/src/modes/world_with_rank.cpp
+++ b/src/modes/world_with_rank.cpp
@@ -82,7 +82,7 @@ AbstractKart* WorldWithRank::getKartAtPosition(unsigned int p) const
     if(p<1 || p>m_position_index.size())
         return NULL;
 
-    return m_karts[m_position_index[p-1]];
+    return m_karts[m_position_index[p-1]].get();
 }   // getKartAtPosition
 
 //-----------------------------------------------------------------------------
diff --git a/src/network/network_string.hpp b/src/network/network_string.hpp
index 760f0b4bd..ea9563558 100644
--- a/src/network/network_string.hpp
+++ b/src/network/network_string.hpp
@@ -74,6 +74,10 @@ protected:
     */
     std::string getString(int len) const
     {
+        if (m_current_offset > (int)m_buffer.size() ||
+            m_current_offset + len > (int)m_buffer.size())
+            throw std::out_of_range("getString out of range.");
+
         std::string a(m_buffer.begin() + (m_current_offset      ),
                       m_buffer.begin() + (m_current_offset + len));
         m_current_offset += len;
@@ -101,7 +105,7 @@ protected:
         {
             result <<= 8; // offset one byte
                           // add the data to result
-            result += m_buffer[offset - a];
+            result += m_buffer.at(offset - a);
         }
         return result;
     }   // get(int pos)
@@ -110,7 +114,7 @@ protected:
     template<typename T>
     T get() const
     {
-        return m_buffer[m_current_offset++];
+        return m_buffer.at(m_current_offset++);
     }   // get
 
 public:
@@ -195,7 +199,8 @@ public:
     {
         return (char*)(m_buffer.data()+m_current_offset); 
     }   // getCurrentData
-
+    // ------------------------------------------------------------------------
+    int getCurrentOffset() const                   { return m_current_offset; }
     // ------------------------------------------------------------------------
     /** Returns the remaining length of the network string. */
     unsigned int size() const { return (int)m_buffer.size()-m_current_offset; }
@@ -424,8 +429,7 @@ public:
     /** Returns the protocol type of this message. */
     ProtocolType getProtocolType() const
     {
-        assert(!m_buffer.empty());
-        return (ProtocolType)(m_buffer[0] & ~PROTOCOL_SYNCHRONOUS);
+        return (ProtocolType)(m_buffer.at(0) & ~PROTOCOL_SYNCHRONOUS);
     }   // getProtocolType
 
     // ------------------------------------------------------------------------
diff --git a/src/network/protocol_manager.cpp b/src/network/protocol_manager.cpp
index f0b740efc..4fe3cb5a2 100644
--- a/src/network/protocol_manager.cpp
+++ b/src/network/protocol_manager.cpp
@@ -378,14 +378,15 @@ bool ProtocolManager::sendEvent(Event* event)
     bool can_be_deleted = false;
     if (event->getType() == EVENT_TYPE_MESSAGE)
     {
-        OneProtocolType &opt = m_all_protocols[event->data().getProtocolType()];
+        OneProtocolType &opt =
+            m_all_protocols.at(event->data().getProtocolType());
         can_be_deleted = opt.notifyEvent(event);
     }
     else   // connect or disconnect event --> test all protocols
     {
         for (unsigned int i = 0; i < m_all_protocols.size(); i++)
         {
-            can_be_deleted |= m_all_protocols[i].notifyEvent(event);
+            can_be_deleted |= m_all_protocols.at(i).notifyEvent(event);
         }
     }
     return can_be_deleted || StkTime::getTimeSinceEpoch() - event->getArrivalTime()
@@ -432,7 +433,16 @@ void ProtocolManager::update(int ticks)
     while (i != m_sync_events_to_process.getData().end())
     {
         m_sync_events_to_process.unlock();
-        bool can_be_deleted = sendEvent(*i);
+        bool can_be_deleted = true;
+        try
+        {
+            can_be_deleted = sendEvent(*i);
+        }
+        catch (std::exception& e)
+        {
+            Log::error("ProtocolManager", "Synchronous event error: %s",
+                e.what());
+        }
         m_sync_events_to_process.lock();
         if (can_be_deleted)
         {
@@ -478,7 +488,16 @@ void ProtocolManager::asynchronousUpdate()
         m_async_events_to_process.unlock();
 
         m_all_protocols[(*i)->getType()].lock();
-        bool result = sendEvent(*i);
+        bool result = true;
+        try
+        {
+            result = sendEvent(*i);
+        }
+        catch (std::exception& e)
+        {
+            Log::error("ProtocolManager", "Asynchronous event error: %s",
+                e.what());
+        }
         m_all_protocols[(*i)->getType()].unlock();
 
         m_async_events_to_process.lock();
diff --git a/src/network/protocols/client_lobby.cpp b/src/network/protocols/client_lobby.cpp
index 2b5753b02..8415e4218 100644
--- a/src/network/protocols/client_lobby.cpp
+++ b/src/network/protocols/client_lobby.cpp
@@ -166,6 +166,7 @@ bool ClientLobby::notifyEventAsynchronous(Event* event)
             case LE_CONNECTION_REFUSED: connectionRefused(event);        break;
             case LE_VOTE: displayPlayerVote(event);                      break;
             case LE_SERVER_OWNERSHIP: becomingServerOwner();             break;
+            case LE_BAD_TEAM: handleBadTeam();                           break;
             default:                                                     break;
         }   // switch
 
@@ -610,10 +611,21 @@ void ClientLobby::updatePlayerList(Event* event)
     NetworkingLobby::getInstance()->updatePlayers(players);
 }   // updatePlayerList
 
+//-----------------------------------------------------------------------------
+void ClientLobby::handleBadTeam()
+{
+    SFXManager::get()->quickSound("anvil");
+    //I18N: Display when all players are in red or blue team, which the race
+    //will not be allowed to start
+    core::stringw msg = _("All players joined red or blue team.");
+    MessageQueue::add(MessageQueue::MT_ERROR, msg);
+}   // handleBadTeam
+
 //-----------------------------------------------------------------------------
 void ClientLobby::becomingServerOwner()
 {
     SFXManager::get()->quickSound("wee");
+    //I18N: Display when a player is allow to control the server
     core::stringw msg = _("You are now the owner of server.");
     MessageQueue::add(MessageQueue::MT_GENERIC, msg);
     STKHost::get()->setAuthorisedToControl(true);
diff --git a/src/network/protocols/client_lobby.hpp b/src/network/protocols/client_lobby.hpp
index 9efc4c801..389d24675 100644
--- a/src/network/protocols/client_lobby.hpp
+++ b/src/network/protocols/client_lobby.hpp
@@ -45,6 +45,7 @@ private:
     void updatePlayerList(Event* event);
     void handleChat(Event* event);
     void handleServerInfo(Event* event);
+    void handleBadTeam();
     void becomingServerOwner();
 
     void clearPlayers();
diff --git a/src/network/protocols/game_events_protocol.cpp b/src/network/protocols/game_events_protocol.cpp
index f7f8f7ebc..21ef36afd 100644
--- a/src/network/protocols/game_events_protocol.cpp
+++ b/src/network/protocols/game_events_protocol.cpp
@@ -54,14 +54,14 @@ bool GameEventsProtocol::notifyEvent(Event* event)
     case GE_RESET_BALL:
     {
         if (!sw)
-            throw("No soccer world");
+            throw std::invalid_argument("No soccer world");
         sw->handleResetBallFromServer(data);
         break;
     }
     case GE_PLAYER_GOAL:
     {
         if (!sw)
-            throw("No soccer world");
+            throw std::invalid_argument("No soccer world");
         sw->handlePlayerGoalFromServer(data);
         break;
     }
diff --git a/src/network/protocols/lobby_protocol.cpp b/src/network/protocols/lobby_protocol.cpp
index db6850259..7813238ea 100644
--- a/src/network/protocols/lobby_protocol.cpp
+++ b/src/network/protocols/lobby_protocol.cpp
@@ -28,7 +28,6 @@
 #include "network/protocols/game_protocol.hpp"
 #include "network/protocols/game_events_protocol.hpp"
 #include "network/race_event_manager.hpp"
-#include "network/rewind_manager.hpp"
 #include "race/race_manager.hpp"
 #include "states_screens/state_manager.hpp"
 
@@ -59,8 +58,6 @@ LobbyProtocol::~LobbyProtocol()
 void LobbyProtocol::loadWorld()
 {
     Log::info("LobbyProtocol", "Ready !");
-    RewindManager::setEnable(true);
-
     // Race startup sequence
     // ---------------------
     // This creates the network world.
diff --git a/src/network/protocols/lobby_protocol.hpp b/src/network/protocols/lobby_protocol.hpp
index 27a1929cb..b047d5188 100644
--- a/src/network/protocols/lobby_protocol.hpp
+++ b/src/network/protocols/lobby_protocol.hpp
@@ -60,7 +60,8 @@ public:
         LE_CHAT,
         LE_SERVER_OWNERSHIP,
         LE_KICK_HOST,
-        LE_CHANGE_TEAM
+        LE_CHANGE_TEAM,
+        LE_BAD_TEAM
     };
 
     enum RejectReason : uint8_t
diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp
index d30e80985..e7746949c 100644
--- a/src/network/protocols/server_lobby.cpp
+++ b/src/network/protocols/server_lobby.cpp
@@ -381,7 +381,7 @@ void ServerLobby::asynchronousUpdate()
         if (NetworkConfig::get()->isOwnerLess())
         {
             auto players = m_game_setup->getPlayers();
-            if (((float)players.size() >
+            if (((float)players.size() >=
                 (float)NetworkConfig::get()->getMaxPlayers() *
                 UserConfigParams::m_start_game_threshold ||
                 m_game_setup->isGrandPrixStarted()) &&
@@ -761,6 +761,31 @@ void ServerLobby::startSelection(const Event *event)
         }
     }
 
+    if (NetworkConfig::get()->hasTeamChoosing())
+    {
+        int red_count = 0;
+        int blue_count = 0;
+        auto players = m_game_setup->getConnectedPlayers();
+        for (auto& player : players)
+        {
+            if (player->getTeam() == SOCCER_TEAM_RED)
+                red_count++;
+            else if (player->getTeam() == SOCCER_TEAM_BLUE)
+                blue_count++;
+            if (red_count != 0 && blue_count != 0)
+                break;
+        }
+        if ((red_count == 0 || blue_count == 0) && players.size() != 1)
+        {
+            Log::warn("ServerLobby", "Bad team choosing.");
+            NetworkString* bt = getNetworkString();
+            bt->addUInt8(LE_BAD_TEAM);
+            sendMessageToPeers(bt, true/*reliable*/);
+            delete bt;
+            return;
+        }
+    }
+
     ProtocolManager::lock()->findAndTerminate(PROTOCOL_CONNECTION);
     if (NetworkConfig::get()->isWAN())
     {
@@ -1857,16 +1882,25 @@ void ServerLobby::handlePendingConnection()
             auto key = m_keys.find(online_id);
             if (key != m_keys.end() && key->second.m_tried == false)
             {
-                if (decryptConnectionRequest(peer, it->second.second,
-                    key->second.m_aes_key, key->second.m_aes_iv, online_id,
-                    key->second.m_name))
+                try
                 {
-                    it = m_pending_connection.erase(it);
-                    m_keys.erase(online_id);
-                    continue;
+                    if (decryptConnectionRequest(peer, it->second.second,
+                        key->second.m_aes_key, key->second.m_aes_iv, online_id,
+                        key->second.m_name))
+                    {
+                        it = m_pending_connection.erase(it);
+                        m_keys.erase(online_id);
+                        continue;
+                    }
+                    else
+                        key->second.m_tried = true;
                 }
-                else
+                catch (std::exception& e)
+                {
+                    Log::error("ServerLobby",
+                        "handlePendingConnection error: %s", e.what());
                     key->second.m_tried = true;
+                }
             }
             it++;
         }
diff --git a/src/network/rewind_info.cpp b/src/network/rewind_info.cpp
index e0c19cd10..676e68115 100644
--- a/src/network/rewind_info.cpp
+++ b/src/network/rewind_info.cpp
@@ -19,8 +19,9 @@
 #include "network/rewind_info.hpp"
 
 #include "network/network_config.hpp"
+#include "network/rewinder.hpp"
 #include "network/rewind_manager.hpp"
-#include "physics/physics.hpp"
+#include "items/projectile_manager.hpp"
 
 /** Constructor for a state: it only takes the size, and allocates a buffer
  *  for all state info.
@@ -63,16 +64,44 @@ void RewindInfoState::restore()
     m_buffer->reset();
     for (const std::string& name : m_rewinder_using)
     {
-        uint16_t count = m_buffer->getUInt16();
-        Rewinder* r = RewindManager::get()->getRewinder(name);
-        if (r == NULL)
+        const uint16_t data_size = m_buffer->getUInt16();
+        const unsigned current_offset_now = m_buffer->getCurrentOffset();
+        std::shared_ptr<Rewinder> r =
+            RewindManager::get()->getRewinder(name);
+
+        if (!r)
+        {
+            // For now we only need to get missing rewinder from
+            // projectile_manager
+            r = projectile_manager->addRewinderFromNetworkState(name);
+        }
+        if (!r)
         {
             Log::error("RewindInfoState", "Missing rewinder %s",
                 name.c_str());
-            m_buffer->skip(count);
+            m_buffer->skip(data_size);
             continue;
         }
-        r->restoreState(m_buffer, count);
+        try
+        {
+            r->restoreState(m_buffer, data_size);
+        }
+        catch (std::exception& e)
+        {
+            Log::error("RewindInfoState", "Restore state error: %s",
+                e.what());
+            m_buffer->reset();
+            m_buffer->skip(current_offset_now + data_size);
+            continue;
+        }
+
+        if (m_buffer->getCurrentOffset() - current_offset_now != data_size)
+        {
+            Log::error("RewindInfoState", "Wrong size read when restore "
+                "state, incompatible binary?");
+            m_buffer->reset();
+            m_buffer->skip(current_offset_now + data_size);
+        }
     }   // for all rewinder
 }   // restore
 
diff --git a/src/network/rewind_info.hpp b/src/network/rewind_info.hpp
index 5ca1bf0cb..26310ea74 100644
--- a/src/network/rewind_info.hpp
+++ b/src/network/rewind_info.hpp
@@ -21,7 +21,6 @@
 
 #include "network/event_rewinder.hpp"
 #include "network/network_string.hpp"
-#include "network/rewinder.hpp"
 #include "utils/cpp2011.hpp"
 #include "utils/leak_check.hpp"
 #include "utils/ptr_vector.hpp"
@@ -173,14 +172,18 @@ public:
 class RewindInfoEventFunction : public RewindInfo
 {
 private:
-    const std::function<void()> m_undo_function, m_replay_function;
+    const std::function<void()> m_undo_function, m_replay_function,
+        m_destroy_function;
 public:
     RewindInfoEventFunction(int ticks,
                             std::function<void()> undo_function = [](){},
                             std::function<void()> replay_function = [](){},
-                            bool is_confirmed = true)
-        : RewindInfo(ticks, is_confirmed),
-        m_undo_function(undo_function), m_replay_function(replay_function)   {}
+                            std::function<void()> destroy_function = [](){})
+        : RewindInfo(ticks, true/*is_confirmed*/),
+        m_undo_function(undo_function), m_replay_function(replay_function),
+        m_destroy_function(destroy_function) {}
+    // ------------------------------------------------------------------------
+    ~RewindInfoEventFunction()                       {  m_destroy_function(); }
     // ------------------------------------------------------------------------
     /** An event is never 'restored', it is only rewound. */
     void restore() {}
diff --git a/src/network/rewind_manager.cpp b/src/network/rewind_manager.cpp
index eb37d92b2..c881f99b9 100644
--- a/src/network/rewind_manager.cpp
+++ b/src/network/rewind_manager.cpp
@@ -82,18 +82,7 @@ void RewindManager::reset()
 
     if (!m_enable_rewind_manager) return;
 
-    for (auto it = m_all_rewinder.begin(); it != m_all_rewinder.end();)
-    {
-        if (!it->second->canBeDestroyed())
-        {
-            it++;
-            continue;
-        }
-        Rewinder* rewinder = it->second;
-        it = m_all_rewinder.erase(it);
-        delete rewinder;
-    }
-
+    clearExpiredRewinder();
     m_rewind_queue.reset();
 }   // reset
 
@@ -166,7 +155,9 @@ void RewindManager::saveState()
     {
         // TODO: check if it's worth passing in a sufficiently large buffer from
         // GameProtocol - this would save the copy operation.
-        BareNetworkString* buffer = p.second->saveState(&rewinder_using);
+        BareNetworkString* buffer = NULL;
+        if (auto r = p.second.lock())
+            buffer = r->saveState(&rewinder_using);
         if (buffer != NULL)
         {
             m_overall_state_size += buffer->size();
@@ -197,12 +188,16 @@ void RewindManager::update(int ticks_not_used)
     if (ticks - m_last_saved_state < m_state_frequency)
         return;
 
-    // Save state
+    // Save state, remove expired rewinder first
+    clearExpiredRewinder();
     if (NetworkConfig::get()->isClient())
     {
         auto& ret = m_local_state[ticks];
         for (auto& p : m_all_rewinder)
-            ret.push_back(p.second->getLocalStateRestoreFunction());
+        {
+            if (auto r = p.second.lock())
+                ret.push_back(r->getLocalStateRestoreFunction());
+        }
     }
     else
     {
@@ -222,6 +217,10 @@ void RewindManager::update(int ticks_not_used)
  */
 void RewindManager::playEventsTill(int world_ticks, int *ticks)
 {
+    // We add the RewindInfoEventFunction to rewind queue before and after
+    // possible rewind, some RewindInfoEventFunction can be created during
+    // rewind
+    mergeRewindInfoEventFunction();
     bool needs_rewind;
     int rewind_ticks;
 
@@ -255,6 +254,20 @@ void RewindManager::playEventsTill(int world_ticks, int *ticks)
     m_is_rewinding = false;
 }   // playEventsTill
 
+// ----------------------------------------------------------------------------
+/** Adds a Rewinder to the list of all rewinders.
+ *  \return true If successfully added, false otherwise.
+ */
+bool RewindManager::addRewinder(std::shared_ptr<Rewinder> rewinder)
+{
+    if (!m_enable_rewind_manager) return false;
+    // Maximum 1 bit to store no of rewinder used
+    if (m_all_rewinder.size() == 255)
+        return false;
+    m_all_rewinder[rewinder->getUniqueIdentity()] = rewinder;
+    return true;
+}   // addRewinder
+
 // ----------------------------------------------------------------------------
 /** Rewinds to the specified time, then goes forward till the current
  *  World::getTime() is reached again: it will replay everything before
@@ -274,7 +287,10 @@ void RewindManager::rewindTo(int rewind_ticks, int now_ticks)
     // can be computed between the transforms before and after
     // the rewind.
     for (auto& p : m_all_rewinder)
-        p.second->saveTransform();
+    {
+        if (auto r = p.second.lock())
+            r->saveTransform();
+    }
 
     // Then undo the rewind infos going backwards in time
     // --------------------------------------------------
@@ -348,10 +364,14 @@ void RewindManager::rewindTo(int rewind_ticks, int now_ticks)
 
     // Now compute the errors which need to be visually smoothed
     for (auto& p : m_all_rewinder)
-        p.second->computeError();
+    {
+        if (auto r = p.second.lock())
+            r->computeError();
+    }
 
     history->setReplayHistory(is_history);
     m_is_rewinding = false;
+    mergeRewindInfoEventFunction();
 }   // rewindTo
 
 // ----------------------------------------------------------------------------
@@ -360,3 +380,11 @@ bool RewindManager::useLocalEvent() const
     return NetworkConfig::get()->isNetworking() &&
         NetworkConfig::get()->isClient() && !m_is_rewinding;
 }   // useLocalEvent
+
+// ----------------------------------------------------------------------------
+void RewindManager::mergeRewindInfoEventFunction()
+{
+    for (RewindInfoEventFunction* rief : m_pending_rief)
+        m_rewind_queue.insertRewindInfo(rief);
+    m_pending_rief.clear();
+}   // mergeRewindInfoEventFunction
diff --git a/src/network/rewind_manager.hpp b/src/network/rewind_manager.hpp
index ef945b34b..6b3319b2e 100644
--- a/src/network/rewind_manager.hpp
+++ b/src/network/rewind_manager.hpp
@@ -19,7 +19,6 @@
 #ifndef HEADER_REWIND_MANAGER_HPP
 #define HEADER_REWIND_MANAGER_HPP
 
-#include "network/rewinder.hpp"
 #include "network/rewind_queue.hpp"
 #include "utils/ptr_vector.hpp"
 #include "utils/synchronised.hpp"
@@ -27,10 +26,15 @@
 #include <assert.h>
 #include <atomic>
 #include <functional>
+#include <memory>
 #include <map>
+#include <set>
+#include <string>
 #include <vector>
 
+class Rewinder;
 class RewindInfo;
+class RewindInfoEventFunction;
 class EventRewinder;
 
 /** \ingroup network
@@ -93,7 +97,7 @@ private:
     std::map<int, std::vector<std::function<void()> > > m_local_state;
 
     /** A list of all objects that can be rewound. */
-    std::map<std::string, Rewinder*> m_all_rewinder;
+    std::map<std::string, std::weak_ptr<Rewinder> > m_all_rewinder;
 
     /** The queue that stores all rewind infos. */
     RewindQueue m_rewind_queue;
@@ -115,8 +119,25 @@ private:
      *  rewinds. */
     std::atomic<int> m_not_rewound_ticks;
 
+    std::vector<RewindInfoEventFunction*> m_pending_rief;
+
     RewindManager();
    ~RewindManager();
+    // ------------------------------------------------------------------------
+    void clearExpiredRewinder()
+    {
+        for (auto it = m_all_rewinder.begin(); it != m_all_rewinder.end();)
+        {
+            if (it->second.expired())
+            {
+                it = m_all_rewinder.erase(it);
+                continue;
+            }
+            it++;
+        }
+    }
+    // ------------------------------------------------------------------------
+    void mergeRewindInfoEventFunction();
 
 public:
     // First static functions to manage rewinding.
@@ -151,27 +172,18 @@ public:
     void addNetworkState(BareNetworkString *buffer, int ticks);
     void saveState();
     // ------------------------------------------------------------------------
-    Rewinder* getRewinder(const std::string& name)
+    std::shared_ptr<Rewinder> getRewinder(const std::string& name)
     {
         auto it = m_all_rewinder.find(name);
-        if (it == m_all_rewinder.end())
-            return NULL;
-        return it->second;
+        if (it != m_all_rewinder.end())
+        {
+            if (auto r = it->second.lock())
+                return r;
+        }
+        return nullptr;
     }
     // ------------------------------------------------------------------------
-    /** Adds a Rewinder to the list of all rewinders.
-     *  \return true If rewinding is enabled, false otherwise. 
-     */
-    bool addRewinder(Rewinder *rewinder)
-    {
-        if (!m_enable_rewind_manager) return false;
-        // Maximum 1 bit to store no of rewinder used
-        if (m_all_rewinder.size() == 255)
-            return false;
-        m_all_rewinder[rewinder->getUniqueIdentity()] = rewinder;
-        return true;
-    }   // addRewinder
-
+    bool addRewinder(std::shared_ptr<Rewinder> rewinder);
     // ------------------------------------------------------------------------
     /** Returns true if currently a rewind is happening. */
     bool isRewinding() const { return m_is_rewinding; }
@@ -182,8 +194,6 @@ public:
         return m_not_rewound_ticks.load(std::memory_order_relaxed);
     }   // getNotRewoundWorldTicks
     // ------------------------------------------------------------------------
-    RewindQueue& getRewindQueue()                    { return m_rewind_queue; }
-    // ------------------------------------------------------------------------
     /** Returns the time of the latest confirmed state. */
     int getLatestConfirmedState() const
     {
@@ -200,6 +210,9 @@ public:
                                            { return m_current_rewinder_using; }
     // ------------------------------------------------------------------------
     bool useLocalEvent() const;
+    // ------------------------------------------------------------------------
+    void addRewindInfoEventFunction(RewindInfoEventFunction* rief)
+                                            { m_pending_rief.push_back(rief); }
 
 };   // RewindManager
 
diff --git a/src/network/rewind_queue.cpp b/src/network/rewind_queue.cpp
index ab14482d6..b9475c4fb 100644
--- a/src/network/rewind_queue.cpp
+++ b/src/network/rewind_queue.cpp
@@ -21,6 +21,7 @@
 #include "config/stk_config.hpp"
 #include "modes/world.hpp"
 #include "network/network_config.hpp"
+#include "network/rewinder.hpp"
 #include "network/rewind_info.hpp"
 #include "network/rewind_manager.hpp"
 
@@ -353,8 +354,10 @@ int RewindQueue::undoUntil(int undo_ticks)
 {
     // A rewind is done after a state in the past is inserted. This function
     // makes sure that m_current is not end()
-    assert(m_current != m_all_rewind_info.end());
-    
+    //assert(m_current != m_all_rewind_info.end());
+    assert(!m_all_rewind_info.empty());
+    m_current = m_all_rewind_info.end();
+    m_current--;
     while((*m_current)->getTicks() > undo_ticks ||
         (*m_current)->isEvent() || !(*m_current)->isConfirmed())
     {
@@ -418,9 +421,9 @@ void RewindQueue::unitTesting()
         virtual void rewind(BareNetworkString *s) {}
         virtual void saveTransform() {}
         virtual void computeError() {}
-        DummyRewinder() : Rewinder("dummy_rewinder", true) {}
+        DummyRewinder() : Rewinder() {}
     };
-    DummyRewinder *dummy_rewinder = new DummyRewinder();
+    auto dummy_rewinder = std::make_shared<DummyRewinder>();
 
     // First tests: add a state first, then an event, and make
     // sure the state stays first
@@ -434,7 +437,7 @@ void RewindQueue::unitTesting()
     assert(q0.hasMoreRewindInfo());
     assert(q0.undoUntil(0) == 0);
 
-    q0.addNetworkEvent(dummy_rewinder, NULL, 0);
+    q0.addNetworkEvent(dummy_rewinder.get(), NULL, 0);
     // Network events are not immediately merged
     assert(q0.m_all_rewind_info.size() == 1);
 
@@ -462,9 +465,9 @@ void RewindQueue::unitTesting()
     assert((*rii)->isEvent());
 
     // Test time base comparisons: adding an event to the end
-    q0.addLocalEvent(dummy_rewinder, NULL, true, 4);
+    q0.addLocalEvent(dummy_rewinder.get(), NULL, true, 4);
     // Then adding an earlier event
-    q0.addLocalEvent(dummy_rewinder, NULL, false, 1);
+    q0.addLocalEvent(dummy_rewinder.get(), NULL, false, 1);
     // rii points to the 3rd element, the ones added just now
     // should be elements4 and 5:
     rii++;
diff --git a/src/network/rewind_queue.hpp b/src/network/rewind_queue.hpp
index 98f03290b..90f1b39fc 100644
--- a/src/network/rewind_queue.hpp
+++ b/src/network/rewind_queue.hpp
@@ -19,14 +19,13 @@
 #ifndef HEADER_REWIND_QUEUE_HPP
 #define HEADER_REWIND_QUEUE_HPP
 
-#include "network/rewinder.hpp"
-#include "utils/ptr_vector.hpp"
 #include "utils/synchronised.hpp"
 
 #include <assert.h>
 #include <list>
 #include <vector>
 
+class BareNetworkString;
 class EventRewinder;
 class RewindInfo;
 class TimeStepInfo;
diff --git a/src/network/rewinder.cpp b/src/network/rewinder.cpp
index 48b8c9b41..00d76c1dc 100644
--- a/src/network/rewinder.cpp
+++ b/src/network/rewinder.cpp
@@ -20,27 +20,11 @@
 
 #include "network/rewind_manager.hpp"
 
-/** Constructor. It will add this object to the list of all rewindable
+// ----------------------------------------------------------------------------
+/** Add this object to the list of all rewindable
  *  objects in the rewind manager.
  */
-Rewinder::Rewinder(const std::string& ui, bool can_be_destroyed, bool auto_add)
-        : m_unique_identity(ui)
+bool Rewinder::rewinderAdd()
 {
-    assert(!m_unique_identity.empty() && m_unique_identity.size() < 255);
-    m_can_be_destroyed = can_be_destroyed;
-    if (auto_add)
-        add();
-}   // Rewinder
-
-// ----------------------------------------------------------------------------
-/** Destructor.
- */
-Rewinder::~Rewinder()
-{
-}   // ~Rewinder
-
-// ----------------------------------------------------------------------------
-void Rewinder::add()
-{
-    RewindManager::get()->addRewinder(this);
-}   // Rewinder
+    return RewindManager::get()->addRewinder(shared_from_this());
+}   // rewinderAdd
diff --git a/src/network/rewinder.hpp b/src/network/rewinder.hpp
index 364023d29..e314152dd 100644
--- a/src/network/rewinder.hpp
+++ b/src/network/rewinder.hpp
@@ -19,33 +19,25 @@
 #ifndef HEADER_REWINDER_HPP
 #define HEADER_REWINDER_HPP
 
+#include <cassert>
 #include <functional>
 #include <string>
+#include <memory>
 #include <vector>
 
 class BareNetworkString;
 
-class Rewinder
+class Rewinder : public std::enable_shared_from_this<Rewinder>
 {
 protected:
-    void add();
-    // -------------------------------------------------------------------------
     void setUniqueIdentity(const std::string& uid)  { m_unique_identity = uid; }
-
 private:
     std::string m_unique_identity;
 
-    /** True if this object can be destroyed, i.e. if this object is a 'stand
-     *  alone' (i.e. not used in inheritance). If the object is used in
-     *  inheritance (e.g. KartRewinder, which is a Rewinder and Kart), then
-     *  freeing the kart will free this rewinder instance as well.
-     */
-    bool m_can_be_destroyed;
-
 public:
-             Rewinder(const std::string& ui, bool can_be_destroyed,
-                      bool auto_add = true);
-    virtual ~Rewinder();
+    Rewinder(const std::string& ui = "")             { m_unique_identity = ui; }
+
+    virtual ~Rewinder() {}
 
     /** Called before a rewind. Is used to save the previous position of an
      *  object before a rewind, so that the error due to a rewind can be
@@ -89,14 +81,20 @@ public:
     /** Nothing to do here. */
     virtual void reset() {}
     // -------------------------------------------------------------------------
-    /** True if this rewinder can be destroyed. Karts can not be destroyed,
-     *  cakes can. This is used by the RewindManager in reset. */
-    bool canBeDestroyed() const { return m_can_be_destroyed; }
-    // -------------------------------------------------------------------------
     virtual std::function<void()> getLocalStateRestoreFunction()
                                                              { return nullptr; }
     // -------------------------------------------------------------------------
-    const std::string& getUniqueIdentity() const   { return m_unique_identity; }
+    const std::string& getUniqueIdentity() const
+    {
+        assert(!m_unique_identity.empty() && m_unique_identity.size() < 255);
+        return m_unique_identity;
+    }
+    // -------------------------------------------------------------------------
+    bool rewinderAdd();
+    // -------------------------------------------------------------------------
+    template<typename T> std::shared_ptr<T> getShared()
+                    { return std::dynamic_pointer_cast<T>(shared_from_this()); }
+
 };   // Rewinder
 #endif
 
diff --git a/src/network/stk_host.cpp b/src/network/stk_host.cpp
index 046bcfc54..c707c25bc 100644
--- a/src/network/stk_host.cpp
+++ b/src/network/stk_host.cpp
@@ -720,7 +720,15 @@ void STKHost::mainLoop()
         auto sl = LobbyProtocol::get<ServerLobby>();
         if (direct_socket && sl && sl->waitingForPlayers())
         {
-            handleDirectSocketRequest(direct_socket, sl);
+            try
+            {
+                handleDirectSocketRequest(direct_socket, sl);
+            }
+            catch (std::exception& e)
+            {
+                Log::warn("STKHost", "Direct socket error: %s",
+                    e.what());
+            }
         }   // if discovery host
 
         if (is_server)
diff --git a/src/online/online_player_profile.cpp b/src/online/online_player_profile.cpp
index 3ebb7bc33..aeef259a5 100644
--- a/src/online/online_player_profile.cpp
+++ b/src/online/online_player_profile.cpp
@@ -344,6 +344,14 @@ namespace Online
         request->queue();
     }   // requestPoll()
 
+    // ------------------------------------------------------------------------
+    OnlinePlayerProfile::PollRequest::PollRequest()
+                       : XMLRequest(true)
+    {
+        m_disable_sending_log = NetworkConfig::get()->isNetworking() &&
+            NetworkConfig::get()->isServer();
+    }   // PollRequest
+
     // ------------------------------------------------------------------------
     /** Callback for the poll request. Parses the information and spawns
      *  notifications accordingly.
diff --git a/src/online/online_player_profile.hpp b/src/online/online_player_profile.hpp
index 9f2935b56..2a7b9a222 100644
--- a/src/online/online_player_profile.hpp
+++ b/src/online/online_player_profile.hpp
@@ -61,7 +61,7 @@ namespace Online
         {
             virtual void callback ();
         public:
-            PollRequest() : XMLRequest(true) {}
+            PollRequest();
         };   // PollRequest
 
     private:
diff --git a/src/physics/btKartRaycast.cpp b/src/physics/btKartRaycast.cpp
index 2a607a3ab..331e80a59 100644
--- a/src/physics/btKartRaycast.cpp
+++ b/src/physics/btKartRaycast.cpp
@@ -71,8 +71,6 @@ void* btKartRaycaster::castRay(const btVector3& from, const btVector3& to,
             result.m_hitNormalInWorld.normalize();
             result.m_distFraction = rayCallback.m_closestHitFraction;
             result.m_triangle_index = -1;
-            const TriangleMesh &tm =
-                Track::getCurrentTrack()->getTriangleMesh();
             // FIXME: this code assumes atm that the object the kart is
             // driving on is the main track (and not e.g. a physical object).
             // If this should not be the case (i.e. the object hit by the
diff --git a/src/physics/physical_object.cpp b/src/physics/physical_object.cpp
index d7434414e..8482861ae 100644
--- a/src/physics/physical_object.cpp
+++ b/src/physics/physical_object.cpp
@@ -123,12 +123,11 @@ void PhysicalObject::Settings::init()
 }   // Settings
 
 // ============================================================================
-PhysicalObject* PhysicalObject::fromXML(bool is_dynamic,
-                                        const XMLNode &xml_node,
-                                        TrackObject* object)
+std::shared_ptr<PhysicalObject> PhysicalObject::fromXML
+    (bool is_dynamic, const XMLNode &xml_node, TrackObject* object)
 {
     PhysicalObject::Settings settings(xml_node);
-    return new PhysicalObject(is_dynamic, settings, object);
+    return std::make_shared<PhysicalObject>(is_dynamic, settings, object);
 }   // fromXML
 
 // ----------------------------------------------------------------------------
@@ -136,7 +135,6 @@ PhysicalObject* PhysicalObject::fromXML(bool is_dynamic,
 PhysicalObject::PhysicalObject(bool is_dynamic,
                                const PhysicalObject::Settings& settings,
                                TrackObject* object)
-              : Rewinder("P", false/*can_be_destroyed*/, false/*auto_add*/)
 {
     m_shape              = NULL;
     m_body               = NULL;
@@ -793,7 +791,7 @@ void PhysicalObject::addForRewind()
     SmoothNetworkBody::setAdjustVerticalOffset(false);
     Rewinder::setUniqueIdentity(std::string("P") + StringUtils::toString
         (Track::getCurrentTrack()->getPhysicalObjectUID()));
-    Rewinder::add();
+    Rewinder::rewinderAdd();
 }   // addForRewind
 
 // ----------------------------------------------------------------------------
diff --git a/src/physics/physical_object.hpp b/src/physics/physical_object.hpp
index a2c115d55..480e5ca5f 100644
--- a/src/physics/physical_object.hpp
+++ b/src/physics/physical_object.hpp
@@ -197,8 +197,8 @@ public:
                     PhysicalObject(bool is_dynamic, const Settings& settings,
                                    TrackObject* object);
 
-    static PhysicalObject* fromXML(bool is_dynamic, const XMLNode &node,
-                                   TrackObject* object);
+    static std::shared_ptr<PhysicalObject> fromXML
+        (bool is_dynamic, const XMLNode &node, TrackObject* object);
 
     virtual     ~PhysicalObject ();
     virtual void reset          ();
diff --git a/src/race/history.cpp b/src/race/history.cpp
index c7dcbced4..b51f99ce1 100644
--- a/src/race/history.cpp
+++ b/src/race/history.cpp
@@ -296,11 +296,13 @@ void History::Load()
     {
         fgets(s, 1023, fd);
         InputEvent &ie = m_all_input_events[i];
+        int action = 0;
         if (sscanf(s, "%d %d %d %d\n", &ie.m_world_ticks, &ie.m_kart_index,
-                   &ie.m_action, &ie.m_value) != 4                          )
+            &action, &ie.m_value) != 4)
         {
             Log::warn("History", "Problems reading event: '%s'", s);
         }
+        ie.m_action = (PlayerAction)action;
     }   // for i
     RewindManager::setEnable(rewind_manager_was_enabled);
 
diff --git a/src/replay/replay_play.cpp b/src/replay/replay_play.cpp
index 9be552705..6207cf77d 100644
--- a/src/replay/replay_play.cpp
+++ b/src/replay/replay_play.cpp
@@ -58,7 +58,7 @@ void ReplayPlay::reset()
 {
     for(unsigned int i=0; i<(unsigned int)m_ghost_karts.size(); i++)
     {
-        m_ghost_karts[i].reset();
+        m_ghost_karts[i]->reset();
     }
 }   // reset
 
@@ -297,7 +297,7 @@ bool ReplayPlay::addReplayFile(const std::string& fn, bool custom_replay, int ca
 //-----------------------------------------------------------------------------
 void ReplayPlay::load()
 {
-    m_ghost_karts.clearAndDeleteAll();
+    m_ghost_karts.clear();
 
     if (m_second_replay_enabled)
         loadFile(/* second replay */ true);
@@ -365,11 +365,11 @@ void ReplayPlay::readKartData(FILE *fd, char *next_line, bool second_replay)
         first_loaded_f_num = m_replay_file_list.at(m_second_replay_file).m_kart_list.size();
 
     ReplayData &rd = m_replay_file_list[replay_index];
-    m_ghost_karts.push_back(new GhostKart(rd.m_kart_list.at(kart_num-first_loaded_f_num),
-                                          kart_num, kart_num + 1,
-                                          rd.m_kart_color.at(kart_num-first_loaded_f_num)));
-    m_ghost_karts[kart_num].init(RaceManager::KT_GHOST);
-    Controller* controller = new GhostController(getGhostKart(kart_num),
+    m_ghost_karts.push_back(std::make_shared<GhostKart>
+        (rd.m_kart_list.at(kart_num-first_loaded_f_num), kart_num, kart_num + 1,
+        rd.m_kart_color.at(kart_num-first_loaded_f_num)));
+    m_ghost_karts[kart_num]->init(RaceManager::KT_GHOST);
+    Controller* controller = new GhostController(getGhostKart(kart_num).get(),
                                                  rd.m_name_list[kart_num-first_loaded_f_num]);
     getGhostKart(kart_num)->setController(controller);
 
@@ -423,7 +423,7 @@ void ReplayPlay::readKartData(FILE *fd, char *next_line, bool second_replay)
                 kre.m_skidding_effect     = skidding;
                 kre.m_red_skidding        = red_skidding!=0;
                 kre.m_jumping             = jumping != 0;
-                m_ghost_karts[kart_num].addReplayEvent(time,
+                m_ghost_karts[kart_num]->addReplayEvent(time,
                     btTransform(q, xyz), pi, bi, kre);
             }
             else
@@ -472,7 +472,7 @@ void ReplayPlay::readKartData(FILE *fd, char *next_line, bool second_replay)
                 kre.m_skidding_effect     = skidding;
                 kre.m_red_skidding        = red_skidding!=0;
                 kre.m_jumping             = jumping != 0;
-                m_ghost_karts[kart_num].addReplayEvent(time,
+                m_ghost_karts[kart_num]->addReplayEvent(time,
                     btTransform(q, xyz), pi, bi, kre);
             }
             else
diff --git a/src/replay/replay_play.hpp b/src/replay/replay_play.hpp
index ad0b1a703..ec12e4c30 100644
--- a/src/replay/replay_play.hpp
+++ b/src/replay/replay_play.hpp
@@ -20,10 +20,10 @@
 #define HEADER_REPLAY__PLAY_HPP
 
 #include "replay/replay_base.hpp"
-#include "utils/ptr_vector.hpp"
 
 #include "irrString.h"
 #include <algorithm>
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -118,7 +118,7 @@ private:
     std::vector<ReplayData>  m_replay_file_list;
 
     /** All ghost karts. */
-    PtrVector<GhostKart>     m_ghost_karts;
+    std::vector<std::shared_ptr<GhostKart> > m_ghost_karts;
 
           ReplayPlay();
          ~ReplayPlay();
@@ -162,7 +162,7 @@ public:
     const unsigned int getNumReplayFile() const
                            { return (unsigned int)m_replay_file_list.size(); }
     // ------------------------------------------------------------------------
-    GhostKart*         getGhostKart(int n)    { return m_ghost_karts.get(n); }
+    std::shared_ptr<GhostKart> getGhostKart(int n) { return m_ghost_karts[n]; }
     // ------------------------------------------------------------------------
     const unsigned int getNumGhostKart() const
     {
diff --git a/src/states_screens/networking_lobby.cpp b/src/states_screens/networking_lobby.cpp
index 33bc0c2c6..a7b8a84cf 100644
--- a/src/states_screens/networking_lobby.cpp
+++ b/src/states_screens/networking_lobby.cpp
@@ -17,6 +17,7 @@
 
 #include "states_screens/networking_lobby.hpp"
 
+#include <cmath>
 #include <algorithm>
 #include <string>
 
@@ -212,7 +213,7 @@ void NetworkingLobby::onUpdate(float delta)
     if (m_timeout_message->isVisible() && m_player_list)
     {
         float cur_player = (float)(m_player_list->getItemCount());
-        if (cur_player > m_server_max_player * m_start_threshold &&
+        if (cur_player >= m_server_max_player * m_start_threshold &&
             m_cur_starting_timer == std::numeric_limits<float>::max())
         {
             m_cur_starting_timer = m_start_timeout;
@@ -220,7 +221,13 @@ void NetworkingLobby::onUpdate(float delta)
         else if (cur_player < m_server_max_player * m_start_threshold)
         {
             m_cur_starting_timer = std::numeric_limits<float>::max();
-            m_timeout_message->setText(L"", true);
+            //I18N: In the networking lobby, display the number of players
+            //required to start a game for owner-less server
+            core::stringw msg =
+                _P("Game will start if there is more than %d player.",
+               "Game will start if there are more than %d players.",
+               (int)ceil(m_server_max_player * m_start_threshold) - 1);
+            m_timeout_message->setText(msg, true);
         }
 
         if (m_cur_starting_timer != std::numeric_limits<float>::max())
diff --git a/src/states_screens/race_gui_base.cpp b/src/states_screens/race_gui_base.cpp
index 0db5a8265..6706c1d5f 100644
--- a/src/states_screens/race_gui_base.cpp
+++ b/src/states_screens/race_gui_base.cpp
@@ -1029,7 +1029,7 @@ void RaceGUIBase::drawPlungerInFace(const Camera *camera, float dt)
         if(m_plunger_move_time < dt && m_plunger_state!=PLUNGER_STATE_FAST)
         {
             const float fast_time = 0.3f;
-            if(kart->getBlockedByPlungerTicks()<fast_time)
+            if(kart->getBlockedByPlungerTicks()<stk_config->time2Ticks(fast_time))
             {
                 // First time we reach faste state: select random target point
                 // at top of screen and set speed accordingly
diff --git a/src/states_screens/race_gui_overworld.cpp b/src/states_screens/race_gui_overworld.cpp
index 0b7405760..35ff7d434 100644
--- a/src/states_screens/race_gui_overworld.cpp
+++ b/src/states_screens/race_gui_overworld.cpp
@@ -189,10 +189,6 @@ void RaceGUIOverworld::renderGlobal(float dt)
     if (race_manager->getIfEmptyScreenSpaceExists() &&
         !GUIEngine::ModalDialog::isADialogActive())
     {
-        const float sqrt_num_players =
-            sqrtf((float)race_manager->getNumLocalPlayers());
-        const int rows = (int)ceil(sqrt_num_players);
-        const int cols = (int)round(sqrt_num_players);
         static video::SColor black = video::SColor(255,0,0,0);
         GL32_draw2DRectangle(black, irr_driver->getSplitscreenWindow(
             race_manager->getNumLocalPlayers()));
diff --git a/src/states_screens/tracks_screen.cpp b/src/states_screens/tracks_screen.cpp
index d72106858..7862585d6 100644
--- a/src/states_screens/tracks_screen.cpp
+++ b/src/states_screens/tracks_screen.cpp
@@ -277,12 +277,16 @@ void TracksScreen::init()
                 //I18N: In track screen
                 getWidget<LabelWidget>("lap-text")->setText(_("Number of goals to win"), false);
                 m_laps->setValue(UserConfigParams::m_num_goals);
+                m_laps->setMin(1);
+                m_laps->setMax(10);
             }
             else
             {
                 //I18N: In track screen
                 getWidget<LabelWidget>("lap-text")->setText(_("Maximum time (min.)"), false);
                 m_laps->setValue(UserConfigParams::m_soccer_time_limit);
+                m_laps->setMin(1);
+                m_laps->setMax(15);
             }
             getWidget("reverse-text")->setVisible(true);
             //I18N: In track screen
@@ -296,6 +300,8 @@ void TracksScreen::init()
             //I18N: In track screen
             getWidget<LabelWidget>("lap-text")->setText(_("Number of laps"), false);
             m_laps->setVisible(true);
+            m_laps->setMin(1);
+            m_laps->setMax(20);
             m_laps->setValue(UserConfigParams::m_num_laps);
             getWidget("reverse-text")->setVisible(true);
             //I18N: In track screen
diff --git a/src/tracks/ambient_light_sphere.cpp b/src/tracks/ambient_light_sphere.cpp
deleted file mode 100644
index bf31836c3..000000000
--- a/src/tracks/ambient_light_sphere.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-//
-//  SuperTuxKart - a fun racing game with go-kart
-//  Copyright (C) 2009-2015  Joerg Henrichs
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 3
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-#include "tracks/ambient_light_sphere.hpp"
-
-#include <string>
-#include <stdio.h>
-
-#include "graphics/camera.hpp"
-#include "io/xml_node.hpp"
-#include "karts/abstract_kart.hpp"
-#include "race/race_manager.hpp"
-#include "tracks/track.hpp"
-
-/** Constructor for a checksphere.
- *  \param node XML node containing the parameters for this checkline.
- */
-AmbientLightSphere::AmbientLightSphere(const XMLNode &node,
-                                       unsigned int index)
-                  : CheckSphere(node, index)
-{
-    m_ambient_color = video::SColor(255, 0, 255, 0);   // green
-    m_inner_radius2 = 1;
-    node.get("inner-radius", &m_inner_radius2);
-    m_inner_radius2 *= m_inner_radius2;   // store the squared value
-    node.get("color", &m_ambient_color);
-}   // AmbientLightSphere
-
-// ----------------------------------------------------------------------------
-void AmbientLightSphere::update(float dt)
-{
-    CheckStructure::update(dt);
-
-    for(unsigned int i=0; i<Camera::getNumCameras(); i++)
-    {
-        Camera *camera = Camera::getCamera(i);
-        const AbstractKart *kart=camera->getKart();
-        if(!kart) continue;
-        if(isInside(i))
-        {
-            float d2=getDistance2ForKart(i);
-            video::SColor color;
-            Track *track=Track::getCurrentTrack();
-            if(d2<m_inner_radius2)
-            {   // Inside inner radius --> use new ambient color
-                color = m_ambient_color;
-            }
-            else   //  Interpolate between default and this ambient color
-            {
-                float f = (getRadius2()-d2)/(getRadius2()-m_inner_radius2);
-                const video::SColor &def = track->getDefaultAmbientColor();
-                color = m_ambient_color.getInterpolated(def, f);
-            }
-            camera->setAmbientLight(color);
-        }   // if active
-    }   // for i<num_karts
-}   // update
-
-// ----------------------------------------------------------------------------
-/** Only calls the sphere check if the kart is a player kart, since other
- *  karts won't change the ambient light.
- *  \param old_pos  Position in previous frame.
- *  \param new_pos  Position in current frame.
- *  \param indx     Index of the kart, can be used to store kart specific
- *                  additional data.
- */
-bool AmbientLightSphere::isTriggered(const Vec3 &old_pos, const Vec3 &new_pos,
-                                     unsigned int indx)
-{
-    for(unsigned int i=0; i<Camera::getNumCameras(); i++)
-    {
-        if(Camera::getCamera(i)->getKart()->getWorldKartId()==indx)
-            return CheckSphere::isTriggered(old_pos, new_pos, indx);
-    }
-    return false;
-}   // isTriggered
diff --git a/src/tracks/ambient_light_sphere.hpp b/src/tracks/ambient_light_sphere.hpp
deleted file mode 100644
index d3dd28d93..000000000
--- a/src/tracks/ambient_light_sphere.hpp
+++ /dev/null
@@ -1,60 +0,0 @@
-//
-//  SuperTuxKart - a fun racing game with go-kart
-//  Copyright (C) 2009-2015  Joerg Henrichs
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 3
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-#ifndef HEADER_AMBIENT_LIGHT_SPHERE_HPP
-#define HEADER_AMBIENT_LIGHT_SPHERE_HPP
-
-#include <SColor.h>
-using namespace irr;
-
-#include "tracks/check_sphere.hpp"
-
-class XMLNode;
-class CheckManager;
-
-/**
- * \brief This class implements a check sphere that is used to change the ambient
- *  light if a kart is inside this sphere.
- *
- *  Besides a normal radius this sphere also has a 2nd 'inner' radius: player karts
- *  inside the inner radius will have the full new ambient light, karts outside the
- *  default light, and karts in between will mix the light dependent on distance.
- *
- * \ingroup tracks
- */
-class AmbientLightSphere : public CheckSphere
-{
-private:
-    /** The inner radius defines the area during which the ambient light
-     *  is extrapolated. The square of the value specified in the scene
-     *  file is stored. */
-    float         m_inner_radius2;
-
-    /** THe full ambient color to use once the kart is inside the
-     *  inner radius. */
-    video::SColor m_ambient_color;
-public:
-                  AmbientLightSphere(const XMLNode &node, unsigned int index);
-    virtual      ~AmbientLightSphere() {};
-    virtual void  update(float dt);
-    virtual bool  isTriggered(const Vec3 &old_pos, const Vec3 &new_pos,
-                              unsigned int indx);
-};   // AmbientLightSphere
-
-#endif
-
diff --git a/src/tracks/check_manager.cpp b/src/tracks/check_manager.cpp
index 19c9a85c3..a678aeac5 100644
--- a/src/tracks/check_manager.cpp
+++ b/src/tracks/check_manager.cpp
@@ -23,11 +23,11 @@
 
 #include "io/xml_node.hpp"
 #include "karts/abstract_kart.hpp"
-#include "tracks/ambient_light_sphere.hpp"
 #include "tracks/check_cannon.hpp"
 #include "tracks/check_goal.hpp"
 #include "tracks/check_lap.hpp"
 #include "tracks/check_line.hpp"
+#include "tracks/check_sphere.hpp"
 #include "tracks/check_structure.hpp"
 #include "tracks/drive_graph.hpp"
 #include "utils/log.hpp"
diff --git a/src/tracks/graph.cpp b/src/tracks/graph.cpp
index 5ef0876dc..b53db294f 100644
--- a/src/tracks/graph.cpp
+++ b/src/tracks/graph.cpp
@@ -120,7 +120,7 @@ void Graph::cleanupDebugMesh()
 /** Creates the actual mesh that is used by createDebugMesh() or makeMiniMap()
  */
 void Graph::createMesh(bool show_invisible, bool enable_transparency,
-                       const video::SColor *track_color)
+                       const video::SColor *track_color, bool invert_x_z)
 {
 #ifndef SERVER_ONLY
     // The debug track will not be lighted or culled.
@@ -172,6 +172,18 @@ void Graph::createMesh(bool show_invisible, bool enable_transparency,
         differentNodeColor(count, &this_color);
         // Transfer the 4 points of the current quad to the list of vertices
         m_all_nodes[count]->getVertices(new_v+4*i, this_color);
+        if (invert_x_z)
+        {
+            auto* vptr = new_v + 4 * i;
+            vptr[0].Pos.X = -vptr[0].Pos.X;
+            vptr[0].Pos.Z = -vptr[0].Pos.Z;
+            vptr[1].Pos.X = -vptr[1].Pos.X;
+            vptr[1].Pos.Z = -vptr[1].Pos.Z;
+            vptr[2].Pos.X = -vptr[2].Pos.X;
+            vptr[2].Pos.Z = -vptr[2].Pos.Z;
+            vptr[3].Pos.X = -vptr[3].Pos.X;
+            vptr[3].Pos.Z = -vptr[3].Pos.Z;
+        }
 
         // Set up the indices for the triangles
         // (note, afaik with opengl we could use quads directly, but the code
@@ -244,7 +256,7 @@ void Graph::createMesh(bool show_invisible, bool enable_transparency,
 /** Creates the actual mesh that is used by createDebugMesh() or makeMiniMap()
  */
 void Graph::createMeshSP(bool show_invisible, bool enable_transparency,
-                         const video::SColor *track_color)
+                         const video::SColor *track_color, bool invert_x_z)
 {
 #ifndef SERVER_ONLY
 
@@ -294,6 +306,18 @@ void Graph::createMeshSP(bool show_invisible, bool enable_transparency,
         differentNodeColor(count, &this_color);
         // Transfer the 4 points of the current quad to the list of vertices
         m_all_nodes[count]->getSPMVertices(vertices.data() + (4 * i), this_color);
+        if (invert_x_z)
+        {
+            auto* vptr = vertices.data() + (4 * i);
+            vptr[0].m_position.X = -vptr[0].m_position.X;
+            vptr[0].m_position.Z = -vptr[0].m_position.Z;
+            vptr[1].m_position.X = -vptr[1].m_position.X;
+            vptr[1].m_position.Z = -vptr[1].m_position.Z;
+            vptr[2].m_position.X = -vptr[2].m_position.X;
+            vptr[2].m_position.Z = -vptr[2].m_position.Z;
+            vptr[3].m_position.X = -vptr[3].m_position.X;
+            vptr[3].m_position.Z = -vptr[3].m_position.Z;
+        }
 
         // Set up the indices for the triangles
         indices[6 * i] = 4 * i + 2;  // First triangle: vertex 0, 1, 2
@@ -366,7 +390,8 @@ void Graph::createMeshSP(bool show_invisible, bool enable_transparency,
  */
 RenderTarget* Graph::makeMiniMap(const core::dimension2du &dimension,
                                  const std::string &name,
-                                 const video::SColor &fill_color)
+                                 const video::SColor &fill_color,
+                                 bool invert_x_z)
 {
     // Skip minimap when profiling
     if (ProfileWorld::isNoGraphics()) return NULL;
@@ -384,14 +409,14 @@ RenderTarget* Graph::makeMiniMap(const core::dimension2du &dimension,
     if (CVS->isGLSL())
     {
         createMeshSP(/*show_invisible part of the track*/ false,
-                     /*enable_transparency*/ false,
-                     /*track_color*/    &fill_color);
+            /*enable_transparency*/ false, /*track_color*/&fill_color,
+            invert_x_z);
     }
     else
     {
         createMesh(/*show_invisible part of the track*/ false,
-                   /*enable_transparency*/ false,
-                   /*track_color*/    &fill_color);
+            /*enable_transparency*/ false, /*track_color*/&fill_color,
+            invert_x_z);
     }
 #endif
 
diff --git a/src/tracks/graph.hpp b/src/tracks/graph.hpp
index b1079354a..b19a7de8c 100644
--- a/src/tracks/graph.hpp
+++ b/src/tracks/graph.hpp
@@ -93,11 +93,13 @@ private:
     // ------------------------------------------------------------------------
     void createMesh(bool show_invisible=true,
                     bool enable_transparency=false,
-                    const video::SColor *track_color=NULL);
+                    const video::SColor *track_color=NULL,
+                    bool invert_x_z = false);
     // ------------------------------------------------------------------------
     void createMeshSP(bool show_invisible=true,
                       bool enable_transparency=false,
-                      const video::SColor *track_color=NULL);
+                      const video::SColor *track_color=NULL,
+                      bool invert_x_z = false);
     // ------------------------------------------------------------------------
     void cleanupDebugMesh();
     // ------------------------------------------------------------------------
@@ -143,7 +145,8 @@ public:
     // ------------------------------------------------------------------------
     RenderTarget* makeMiniMap(const core::dimension2du &dimension,
                               const std::string &name,
-                              const video::SColor &fill_color);
+                              const video::SColor &fill_color,
+                              bool invert_x_z);
     // ------------------------------------------------------------------------
     void mapPoint2MiniMap(const Vec3 &xyz, Vec3 *out) const;
     // ------------------------------------------------------------------------
diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp
index 82bf23c50..3256a0ed0 100644
--- a/src/tracks/track.cpp
+++ b/src/tracks/track.cpp
@@ -105,6 +105,7 @@ Track::Track(const std::string &filename)
     m_magic_number          = 0x17AC3802;
 #endif
 
+    m_minimap_invert_x_z    = false;
     m_materials_loaded      = false;
     m_filename              = filename;
     m_root                  =
@@ -709,6 +710,23 @@ void Track::startMusic() const
  */
 void Track::loadArenaGraph(const XMLNode &node)
 {
+    // Determine if rotate minimap is needed for soccer mode (for blue team)
+    // Only need to test local player
+    if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER)
+    {
+        const unsigned pk = race_manager->getNumPlayers();
+        for (unsigned i = 0; i < pk; i++)
+        {
+            if (!race_manager->getKartInfo(i).isNetworkPlayer() &&
+                race_manager->getKartInfo(i).getSoccerTeam() ==
+                SOCCER_TEAM_BLUE)
+            {
+                m_minimap_invert_x_z = true;
+                break;
+            }
+        }
+    }
+
     ArenaGraph* graph = new ArenaGraph(m_root+"navmesh.xml", &node);
     Graph::setGraph(graph);
 
@@ -786,7 +804,15 @@ void Track::loadDriveGraph(unsigned int mode_id, const bool reverse)
 
 void Track::mapPoint2MiniMap(const Vec3 &xyz, Vec3 *draw_at) const
 {
-    Graph::get()->mapPoint2MiniMap(xyz, draw_at);
+    if (m_minimap_invert_x_z)
+    {
+        Vec3 invert = xyz;
+        invert.setX(-xyz.x());
+        invert.setZ(-xyz.z());
+        Graph::get()->mapPoint2MiniMap(invert, draw_at);
+    }
+    else
+        Graph::get()->mapPoint2MiniMap(xyz, draw_at);
     draw_at->setX(draw_at->getX() * m_minimap_x_scale);
     draw_at->setY(draw_at->getY() * m_minimap_y_scale);
 }
@@ -1115,7 +1141,9 @@ void Track::loadMinimap()
     m_mini_map_size = World::getWorld()->getRaceGUI()->getMiniMapSize();
 
     //Use twice the size of the rendered minimap to reduce significantly aliasing
-    m_render_target = Graph::get()->makeMiniMap(m_mini_map_size*2, "minimap::" + m_ident, video::SColor(127, 255, 255, 255));
+    m_render_target = Graph::get()->makeMiniMap(m_mini_map_size * 2,
+        "minimap::" + m_ident, video::SColor(127, 255, 255, 255),
+        m_minimap_invert_x_z);
     if (!m_render_target) return;
 
     core::dimension2du mini_map_texture_size = m_render_target->getTextureSize();
@@ -1737,6 +1765,7 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id)
     }
 
     CameraEnd::clearEndCameras();
+    m_minimap_invert_x_z   = false;
     m_sky_type             = SKY_NONE;
     m_track_object_manager = new TrackObjectManager();
 
diff --git a/src/tracks/track.hpp b/src/tracks/track.hpp
index e4547d592..d91f4ef55 100644
--- a/src/tracks/track.hpp
+++ b/src/tracks/track.hpp
@@ -365,6 +365,8 @@ private:
     float m_displacement_speed;
     int m_physical_object_uid;
 
+    bool m_minimap_invert_x_z;
+
     /** The levels for color correction
      * m_color_inlevel(black, gamma, white)
      * m_color_outlevel(black, white)*/
diff --git a/src/tracks/track_object.cpp b/src/tracks/track_object.cpp
index 58b9636ac..a4fc0f856 100644
--- a/src/tracks/track_object.cpp
+++ b/src/tracks/track_object.cpp
@@ -74,7 +74,6 @@ TrackObject::TrackObject(const core::vector3df& xyz, const core::vector3df& hpr,
     m_enabled         = true;
     m_presentation    = NULL;
     m_animator        = NULL;
-    m_physical_object = NULL;
     m_parent_library  = NULL;
     m_interaction     = interaction;
     m_presentation    = presentation;
@@ -86,9 +85,8 @@ TrackObject::TrackObject(const core::vector3df& xyz, const core::vector3df& hpr,
     if (m_interaction != "ghost" && m_interaction != "none" &&
         physics_settings )
     {
-        m_physical_object = new PhysicalObject(is_dynamic,
-                                               *physics_settings,
-                                               this);
+        m_physical_object = std::make_shared<PhysicalObject>
+            (is_dynamic, *physics_settings, this);
     }
 
     reset();
@@ -112,7 +110,6 @@ void TrackObject::init(const XMLNode &xml_node, scene::ISceneNode* parent,
     m_presentation = NULL;
     m_animator = NULL;
     m_parent_library = parent_library;
-    m_physical_object = NULL;
 
     xml_node.get("id",      &m_id        );
     xml_node.get("model",   &m_name      );
@@ -455,7 +452,6 @@ TrackObject::~TrackObject()
 {
     delete m_presentation;
     delete m_animator;
-    delete m_physical_object;
 }   // ~TrackObject
 
 // ----------------------------------------------------------------------------
@@ -482,7 +478,7 @@ void TrackObject::setEnabled(bool enabled)
 
     if (getType() == "mesh")
     {
-        if (m_physical_object != NULL)
+        if (m_physical_object)
         {
             if (enabled)
                 m_physical_object->addBody();
@@ -508,7 +504,7 @@ void TrackObject::resetEnabled()
 
     if (getType() == "mesh")
     {
-        if (m_physical_object != NULL)
+        if (m_physical_object)
         {
             if (m_initially_visible)
                 m_physical_object->addBody();
@@ -581,7 +577,7 @@ void TrackObject::move(const core::vector3df& xyz, const core::vector3df& hpr,
     if (m_presentation != NULL)
         m_presentation->move(xyz, hpr, scale, isAbsoluteCoord);
 
-    if (update_rigid_body && m_physical_object != NULL)
+    if (update_rigid_body && m_physical_object)
     {
         movePhysicalBodyToGraphicalNode(xyz, hpr);
     }
diff --git a/src/tracks/track_object.hpp b/src/tracks/track_object.hpp
index 65905a040..e16b302cb 100644
--- a/src/tracks/track_object.hpp
+++ b/src/tracks/track_object.hpp
@@ -86,7 +86,7 @@ protected:
     /** True if a kart can drive on this object. This will */
     bool                           m_is_driveable;
 
-    PhysicalObject*                m_physical_object;
+    std::shared_ptr<PhysicalObject> m_physical_object;
 
     ThreeDAnimation*               m_animator;
 
@@ -164,9 +164,10 @@ public:
     // ------------------------------------------------------------------------
     bool isSoccerBall() const { return m_soccer_ball; }
     // ------------------------------------------------------------------------
-    const PhysicalObject* getPhysicalObject() const { return m_physical_object; }
+    const PhysicalObject* getPhysicalObject() const
+                                            { return m_physical_object.get(); }
     // ------------------------------------------------------------------------
-    PhysicalObject* getPhysicalObject() { return m_physical_object; }
+    PhysicalObject* getPhysicalObject()     { return m_physical_object.get(); }
     // ------------------------------------------------------------------------
     const core::vector3df getInitXYZ() const { return m_init_xyz; }
     // ------------------------------------------------------------------------
@@ -214,7 +215,7 @@ public:
     /** Get the physics representation of an object.
       * On the script side, the returned object is of type : @ref Scripting_PhysicalObject
       */
-    PhysicalObject* getPhysics() { return m_physical_object; }
+    PhysicalObject* getPhysics() { return m_physical_object.get(); }
     /** Hide or show the object */
     void setEnabled(bool mode);
 
diff --git a/src/tracks/track_sector.cpp b/src/tracks/track_sector.cpp
index b57fe5fb5..5f131e7eb 100644
--- a/src/tracks/track_sector.cpp
+++ b/src/tracks/track_sector.cpp
@@ -74,18 +74,21 @@ void TrackSector::update(const Vec3 &xyz, bool ignore_vertical)
             prev_sector, test_nodes, ignore_vertical);
     }
 
-    // ArenaGraph (battle and soccer mode) doesn't need the code below
-    if (ag) return;
+    // Keep the last valid graph node for arena mode
+    if (ag)
+    {
+        if (prev_sector != Graph::UNKNOWN_SECTOR)
+            m_last_valid_graph_node = prev_sector;
+        return;
+    }
 
     // keep the current quad as the latest valid one IF the player has one
     // of the required checklines
     const DriveNode* dn = DriveGraph::get()->getNode(m_current_graph_node);
     const std::vector<int>& checkline_requirements = dn->getChecklineRequirements();
 
-    bool isValidQuad = false;
     if (checkline_requirements.size() == 0)
     {
-        isValidQuad = true;
         if (m_on_road)
             m_last_valid_graph_node = m_current_graph_node;
     }
@@ -98,7 +101,6 @@ void TrackSector::update(const Vec3 &xyz, bool ignore_vertical)
                 //has_prerequisite = true;
                 if (m_on_road)
                     m_last_valid_graph_node = m_current_graph_node;
-                isValidQuad = true;
                 break;
             }
         }
diff --git a/src/tracks/track_sector.hpp b/src/tracks/track_sector.hpp
index 08e60ef32..ed1ee45f4 100644
--- a/src/tracks/track_sector.hpp
+++ b/src/tracks/track_sector.hpp
@@ -81,6 +81,8 @@ public:
     bool isOnRoad() const { return m_on_road; }
     // ------------------------------------------------------------------------
     void setLastTriggeredCheckline(int i) { m_last_triggered_checkline = i; }
+    // ------------------------------------------------------------------------
+    int getLastValidGraphNode() const { return m_last_valid_graph_node; }
 
 };   // TrackSector