Refactored RewindInfo into astand-alone class/file with separate
classes for time, event, and states.
This commit is contained in:
parent
3eb94e023d
commit
1025e25846
55
src/network/rewind_info.cpp
Normal file
55
src/network/rewind_info.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2016 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 "network/rewind_info.hpp"
|
||||
|
||||
#include "modes/world.hpp"
|
||||
#include "physics/physics.hpp"
|
||||
|
||||
/** Constructor for a state: it only takes the size, and allocates a buffer
|
||||
* for all state info.
|
||||
* \param size Necessary buffer size for a state.
|
||||
*/
|
||||
RewindInfo::RewindInfo(float time, bool is_confirmed)
|
||||
{
|
||||
m_time = time;
|
||||
m_is_confirmed = is_confirmed;
|
||||
} // RewindInfo
|
||||
|
||||
// ============================================================================
|
||||
RewindInfoTime::RewindInfoTime(float time)
|
||||
: RewindInfo(time, /*is_confirmed*/true)
|
||||
{
|
||||
} // RewindInfoTime
|
||||
|
||||
// ============================================================================
|
||||
RewindInfoState::RewindInfoState(float time, Rewinder *rewinder, char *buffer,
|
||||
bool is_confirmed)
|
||||
: RewindInfoRewinder(time, rewinder, buffer, is_confirmed)
|
||||
{
|
||||
m_local_physics_time = World::getWorld()->getPhysics()->getPhysicsWorld()
|
||||
->getLocalTime();
|
||||
} // RewindInfoState
|
||||
|
||||
// ============================================================================
|
||||
RewindInfoEvent::RewindInfoEvent(float time, Rewinder *rewinder, char *buffer,
|
||||
bool is_confirmed)
|
||||
: RewindInfoRewinder(time, rewinder, buffer, is_confirmed)
|
||||
{
|
||||
} // RewindInfoEvent
|
||||
|
199
src/network/rewind_info.hpp
Normal file
199
src/network/rewind_info.hpp
Normal file
@ -0,0 +1,199 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2016 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_REWIND_INFO_HPP
|
||||
#define HEADER_REWIND_INFO_HPP
|
||||
|
||||
#include "network/rewinder.hpp"
|
||||
#include "utils/ptr_vector.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
#include <vector>
|
||||
|
||||
/** Used to store rewind information for a given time for all rewind
|
||||
* instances.
|
||||
* Rewind information can either be a state (for example a kart would
|
||||
* have position, rotation, linear and angular velocity, ... as state),
|
||||
* or an event (for a kart that would be pressing or releasing of a key).
|
||||
* State changes and events can be delivered in different frequencies,
|
||||
* and might be released (to save memory) differently: A state can be
|
||||
* reproduced from a previous state by replaying the simulation taking
|
||||
* all events into account.
|
||||
*/
|
||||
class RewindInfo
|
||||
{
|
||||
private:
|
||||
/** Time when this state was taken. */
|
||||
float m_time;
|
||||
|
||||
/** A confirmed event is one that was sent from the server. When
|
||||
* rewinding we have to start with a confirmed state for each
|
||||
* object. */
|
||||
bool m_is_confirmed;
|
||||
|
||||
public:
|
||||
RewindInfo(float time, bool is_confirmed);
|
||||
|
||||
/** Called when going back in time to undo any rewind information. */
|
||||
virtual void undo() = 0;
|
||||
|
||||
/** This is called while going forwards in time again to reach current
|
||||
* time. */
|
||||
virtual void rewind() = 0;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
virtual ~RewindInfo() { }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the time at which this rewind state was saved. */
|
||||
float getTime() const { return m_time; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns if this state is confirmed. */
|
||||
bool isConfirmed() const { return m_is_confirmed; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** If this rewind info is an event. Subclasses will overwrite this. */
|
||||
virtual bool isEvent() const { return false; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** If this rewind info is time info. Subclasses will overwrite this. */
|
||||
virtual bool isTime() const { return false; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** If this rewind info is an event. Subclasses will overwrite this. */
|
||||
virtual bool isState() const { return false; }
|
||||
// ------------------------------------------------------------------------
|
||||
}; // RewindInfo
|
||||
|
||||
// ============================================================================
|
||||
/** A rewind info abstract class that keeps track of a rewinder object.
|
||||
*/
|
||||
class RewindInfoRewinder : public RewindInfo
|
||||
{
|
||||
protected:
|
||||
/** The Rewinder instance for which this data is. */
|
||||
Rewinder *m_rewinder;
|
||||
|
||||
/** Pointer to the buffer which stores all states. */
|
||||
char *m_buffer;
|
||||
|
||||
public:
|
||||
RewindInfoRewinder(float time, Rewinder *rewinder, char *buffer,
|
||||
bool is_confirmed)
|
||||
: RewindInfo(time, is_confirmed)
|
||||
{
|
||||
m_rewinder = rewinder;
|
||||
m_buffer = buffer;
|
||||
} // RewindInfoRewinder
|
||||
// ------------------------------------------------------------------------
|
||||
~RewindInfoRewinder()
|
||||
{
|
||||
} // ~RewindInfoRewinder
|
||||
|
||||
}; // RewindInfoRewinder
|
||||
|
||||
// ============================================================================
|
||||
class RewindInfoTime : public RewindInfo
|
||||
{
|
||||
private:
|
||||
|
||||
public:
|
||||
RewindInfoTime(float time);
|
||||
virtual ~RewindInfoTime() {};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
virtual bool isTime() const { return true; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Called when going back in time to undo any rewind information.
|
||||
* Does actually nothing. */
|
||||
virtual void undo() {}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Rewinds to this state. Nothing to be done for time info. */
|
||||
virtual void rewind() {}
|
||||
}; // class RewindInfoTime
|
||||
|
||||
// ============================================================================
|
||||
class RewindInfoState: public RewindInfoRewinder
|
||||
{
|
||||
private:
|
||||
/** The 'left over' time from the physics. */
|
||||
float m_local_physics_time;
|
||||
|
||||
public:
|
||||
RewindInfoState(float time, Rewinder *rewinder, char *buffer,
|
||||
bool is_confirmed);
|
||||
virtual ~RewindInfoState() {};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the left-over physics time. */
|
||||
float getLocalPhysicsTime() const { return m_local_physics_time; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns a pointer to the state buffer. */
|
||||
char *getBuffer() const { return m_buffer; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual bool isState() const { return true; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Called when going back in time to undo any rewind information.
|
||||
* It calls undoState in the rewinder. */
|
||||
virtual void undo()
|
||||
{
|
||||
m_rewinder->undoState(m_buffer);
|
||||
} // undoEvent
|
||||
// ------------------------------------------------------------------------
|
||||
/** Rewinds to this state. This is called while going forwards in time
|
||||
* again to reach current time. It will call rewindToState(char *)
|
||||
* if the state is a confirmed state. */
|
||||
virtual void rewind()
|
||||
{
|
||||
if (isConfirmed())
|
||||
m_rewinder->rewindToState(m_buffer);
|
||||
else
|
||||
{
|
||||
// TODO
|
||||
// Handle replacing of stored states.
|
||||
}
|
||||
} // rewind
|
||||
}; // class RewindInfoState
|
||||
|
||||
// ============================================================================
|
||||
class RewindInfoEvent : public RewindInfoRewinder
|
||||
{
|
||||
public:
|
||||
RewindInfoEvent(float time, Rewinder *rewinder, char *buffer,
|
||||
bool is_confirmed);
|
||||
virtual ~RewindInfoEvent() {}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns a pointer to the state buffer. */
|
||||
char *getBuffer() const { return m_buffer; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual bool isEvent() const { return true; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Called when going back in time to undo any rewind information.
|
||||
* It calls undoEvent in the rewinder. */
|
||||
virtual void undo()
|
||||
{
|
||||
m_rewinder->undoEvent(m_buffer);
|
||||
} // undo
|
||||
// ------------------------------------------------------------------------
|
||||
/** This is called while going forwards in time again to reach current
|
||||
* time. Calls rewindEvent(char*).
|
||||
*/
|
||||
virtual void rewind()
|
||||
{
|
||||
m_rewinder->rewindToEvent(m_buffer);
|
||||
} // rewind
|
||||
}; // class RewindIndoEvent
|
||||
|
||||
#endif
|
@ -21,6 +21,7 @@
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "network/rewinder.hpp"
|
||||
#include "network/rewind_info.hpp"
|
||||
#include "physics/physics.hpp"
|
||||
#include "race/history.hpp"
|
||||
#include "utils/log.hpp"
|
||||
@ -45,35 +46,6 @@ void RewindManager::destroy()
|
||||
m_rewind_manager = NULL;
|
||||
} // destroy
|
||||
|
||||
// ============================================================================
|
||||
/** Constructor for a state: it only takes the size, and allocates a buffer
|
||||
* for all state info.
|
||||
* \param size Necessary buffer size for a state.
|
||||
*/
|
||||
RewindManager::RewindInfo::RewindInfo(Rewinder *rewinder, char *buffer,
|
||||
bool is_event, bool is_confirmed)
|
||||
{
|
||||
m_rewinder = rewinder;
|
||||
m_time = RewindManager::get()->getCurrentTime();
|
||||
m_time_step = RewindManager::get()->getCurrentTimeStep();
|
||||
m_local_physics_time = World::getWorld()->getPhysics()->getPhysicsWorld()->getLocalTime();
|
||||
m_buffer = buffer;
|
||||
m_type = is_event ? RIT_EVENT : RIT_STATE;
|
||||
m_is_confirmed = is_confirmed;
|
||||
} // RewindInfo
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
RewindManager::RewindInfo::RewindInfo()
|
||||
{
|
||||
m_rewinder = NULL;
|
||||
m_time = RewindManager::get()->getCurrentTime();
|
||||
m_time_step = RewindManager::get()->getCurrentTimeStep();
|
||||
m_local_physics_time = World::getWorld()->getPhysics()->getPhysicsWorld()->getLocalTime();
|
||||
m_buffer = NULL;
|
||||
m_type = RIT_TIME;
|
||||
m_is_confirmed = true;
|
||||
} // RewindInfo
|
||||
|
||||
// ============================================================================
|
||||
/** The constructor.
|
||||
*/
|
||||
@ -239,8 +211,8 @@ unsigned int RewindManager::findFirstIndex(float target_time) const
|
||||
void RewindManager::addEvent(Rewinder *rewinder, char *buffer)
|
||||
{
|
||||
if(m_is_rewinding) return;
|
||||
RewindInfo *ri = new RewindInfo(rewinder, buffer, /*is_event*/true,
|
||||
/*is_confirmed*/true);
|
||||
RewindInfo *ri = new RewindInfoEvent(getCurrentTime(), rewinder,
|
||||
buffer, /*is_confirmed*/true );
|
||||
insertRewindInfo(ri);
|
||||
} // addEvent
|
||||
|
||||
@ -260,7 +232,7 @@ void RewindManager::saveStates()
|
||||
{
|
||||
// No full state necessary, add a dummy entry for the time
|
||||
// which increases replay precision (same time step size)
|
||||
RewindInfo *ri = new RewindInfo();
|
||||
RewindInfo *ri = new RewindInfoTime(getCurrentTime());
|
||||
insertRewindInfo(ri);
|
||||
return;
|
||||
}
|
||||
@ -273,9 +245,9 @@ void RewindManager::saveStates()
|
||||
if(size>=0)
|
||||
{
|
||||
m_overall_state_size += size;
|
||||
RewindInfo *ri = new RewindInfo(m_all_rewinder[i], p,
|
||||
/*is_event*/false,
|
||||
/*is_confirmed*/true);
|
||||
RewindInfo *ri = new RewindInfoState(getCurrentTime(),
|
||||
m_all_rewinder[i], p,
|
||||
/*is_confirmed*/true);
|
||||
assert(ri);
|
||||
insertRewindInfo(ri);
|
||||
} // size >= 0
|
||||
@ -302,18 +274,18 @@ void RewindManager::rewindTo(float rewind_time)
|
||||
|
||||
// First find the state to which we need to rewind
|
||||
// ------------------------------------------------
|
||||
int state = findFirstIndex(rewind_time);
|
||||
int state_index = findFirstIndex(rewind_time);
|
||||
|
||||
if(!m_rewind_info[state]->isState())
|
||||
if(!m_rewind_info[state_index]->isState())
|
||||
{
|
||||
Log::error("RewindManager", "No state for rewind to %f, state %d.",
|
||||
rewind_time, state);
|
||||
rewind_time, state_index);
|
||||
return;
|
||||
}
|
||||
|
||||
// Then undo the states that are skipped
|
||||
// -------------------------------------
|
||||
for(int i=m_rewind_info.size()-1; i>(int)state; i--)
|
||||
for(int i=m_rewind_info.size()-1; i>(int)state_index; i--)
|
||||
{
|
||||
m_rewind_info[i]->undo();
|
||||
} // for i>state
|
||||
@ -335,8 +307,11 @@ void RewindManager::rewindTo(float rewind_time)
|
||||
|
||||
// Rewind to the required state
|
||||
// ----------------------------
|
||||
float exact_rewind_time = m_rewind_info[state]->getTime();
|
||||
float local_physics_time = m_rewind_info[state]->getLocalPhysicsTime();
|
||||
|
||||
RewindInfoState *state =
|
||||
dynamic_cast<RewindInfoState*>(m_rewind_info[state_index]);
|
||||
float exact_rewind_time = state->getTime();
|
||||
float local_physics_time = state->getLocalPhysicsTime();
|
||||
World *world = World::getWorld();
|
||||
world->getPhysics()->getPhysicsWorld()->setLocalTime(local_physics_time);
|
||||
|
||||
@ -353,22 +328,21 @@ void RewindManager::rewindTo(float rewind_time)
|
||||
// Now go forward through the saved states, and
|
||||
// replay taking the events into account.
|
||||
while( world->getTime() < current_time &&
|
||||
state < (int)m_rewind_info.size() )
|
||||
state_index < (int)m_rewind_info.size() )
|
||||
{
|
||||
|
||||
float dt = determineTimeStepSize(state, current_time);
|
||||
|
||||
// Now set all events and confirmed states
|
||||
while(state < (int)m_rewind_info.size() &&
|
||||
m_rewind_info[state]->getTime()<=world->getTime()+0.001f)
|
||||
while(state_index < (int)m_rewind_info.size() &&
|
||||
m_rewind_info[state_index]->getTime()<=world->getTime()+0.001f)
|
||||
{
|
||||
if(m_rewind_info[state]->isEvent() ||
|
||||
m_rewind_info[state]->isConfirmed() )
|
||||
if(m_rewind_info[state_index]->isEvent() ||
|
||||
m_rewind_info[state_index]->isConfirmed() )
|
||||
{
|
||||
m_rewind_info[state]->rewind();
|
||||
m_rewind_info[state_index]->rewind();
|
||||
}
|
||||
state++;
|
||||
state_index++;
|
||||
}
|
||||
float dt = determineTimeStepSize(state_index, current_time);
|
||||
world->updateWorld(dt);
|
||||
#define SHOW_ROLLBACK
|
||||
#ifdef SHOW_ROLLBACK
|
||||
@ -391,9 +365,17 @@ void RewindManager::rewindTo(float rewind_time)
|
||||
*/
|
||||
float RewindManager::determineTimeStepSize(int next_state, float end_time)
|
||||
{
|
||||
return m_rewind_info[next_state]->getTimeStep();
|
||||
// If there is a next state (which is known to have a different time)
|
||||
// use the time difference to determine the time step size.
|
||||
if(next_state < m_rewind_info.size())
|
||||
return m_rewind_info[next_state]->getTime() - World::getWorld()->getTime();
|
||||
|
||||
// Otherwise, i.e. we are rewinding the last state/event, take the
|
||||
// difference between that time and the world time at which the rewind
|
||||
// was triggered.
|
||||
return end_time - m_rewind_info[next_state-1]->getTime();
|
||||
|
||||
|
||||
return m_rewind_info[next_state]->getTime()-World::getWorld()->getTime();
|
||||
|
||||
float dt = 1.0f/60.0f;
|
||||
float t = World::getWorld()->getTime();
|
||||
|
@ -25,6 +25,8 @@
|
||||
#include <assert.h>
|
||||
#include <vector>
|
||||
|
||||
class RewindInfo;
|
||||
|
||||
/** \ingroup network
|
||||
* This class manages rewinding. It keeps track of:
|
||||
* - states for each rewindable object (for example a kart would have
|
||||
@ -85,113 +87,6 @@ private:
|
||||
/** A list of all objects that can be rewound. */
|
||||
AllRewinder m_all_rewinder;
|
||||
|
||||
// ========================================================================
|
||||
/** Used to store rewind information for a given time for all rewind
|
||||
* instances.
|
||||
* Rewind information can either be a state (for example a kart would
|
||||
* have position, rotation, linear and angular velocity, ... as state),
|
||||
* or an event (for a kart that would be pressing or releasing of a key).
|
||||
* State changes and events can be delivered in different frequencies,
|
||||
* and might be released (to save memory) differently: A state can be
|
||||
* reproduced from a previous state by replaying the simulation taking
|
||||
* all events into account.
|
||||
*/
|
||||
class RewindInfo
|
||||
{
|
||||
private:
|
||||
/** The different information types that can be saved. */
|
||||
enum RewindInfoType {RIT_TIME, RIT_STATE, RIT_EVENT};
|
||||
|
||||
/** Pointer to the buffer which stores all states. */
|
||||
char *m_buffer;
|
||||
|
||||
/** Time when this state was taken. */
|
||||
float m_time;
|
||||
|
||||
/** Time step size. */
|
||||
float m_time_step;
|
||||
|
||||
/** The 'left over' time from the physics. */
|
||||
float m_local_physics_time;
|
||||
|
||||
/** Type of this information. */
|
||||
RewindInfoType m_type;
|
||||
|
||||
/** A confirmed event is one that was sent from the server. When
|
||||
* rewinding we have to start with a confirmed state for each
|
||||
* object. */
|
||||
bool m_is_confirmed;
|
||||
|
||||
/** The Rewinder instance for which this data is. */
|
||||
Rewinder *m_rewinder;
|
||||
public:
|
||||
RewindInfo(Rewinder *rewinder, char *buffer,
|
||||
bool is_event, bool is_confirmed);
|
||||
// --------------------------------------------------------------------
|
||||
RewindInfo();
|
||||
// --------------------------------------------------------------------
|
||||
~RewindInfo()
|
||||
{
|
||||
delete m_buffer;
|
||||
} // ~RewindInfo
|
||||
// --------------------------------------------------------------------
|
||||
/** Returns a pointer to the state buffer. */
|
||||
char *getBuffer() const { return m_buffer; }
|
||||
// --------------------------------------------------------------------
|
||||
/** Returns the time at which this rewind state was saved. */
|
||||
float getTime() const { return m_time; }
|
||||
// --------------------------------------------------------------------
|
||||
/** Time step size. */
|
||||
float getTimeStep() const { return m_time_step; }
|
||||
// --------------------------------------------------------------------
|
||||
bool isEvent() const { return m_type==RIT_EVENT; }
|
||||
// --------------------------------------------------------------------
|
||||
bool isTime() const { return m_type==RIT_TIME; }
|
||||
// --------------------------------------------------------------------
|
||||
bool isState() const { return m_type==RIT_STATE; }
|
||||
// --------------------------------------------------------------------
|
||||
/** Returns if this state is confirmed. */
|
||||
bool isConfirmed() const { return m_is_confirmed; }
|
||||
// --------------------------------------------------------------------
|
||||
/** Returns the left-over physics time. */
|
||||
float getLocalPhysicsTime() const { return m_local_physics_time; }
|
||||
// --------------------------------------------------------------------
|
||||
/** Called when going back in time to undo any rewind information.
|
||||
* It calls either undoEvent or undoState in the rewinder. */
|
||||
void undo()
|
||||
{
|
||||
if(m_type==RIT_EVENT)
|
||||
m_rewinder->undoEvent(m_buffer);
|
||||
else if(m_type==RIT_STATE)
|
||||
m_rewinder->undoState(m_buffer);
|
||||
// time evnet can be ignored.
|
||||
} // undoEvent
|
||||
// --------------------------------------------------------------------
|
||||
/** Rewinds to this state. This is called while going forwards in time
|
||||
* again to reach current time. If the info is a state, it will
|
||||
* call rewindToState(char *) if the state is a confirmed state, or
|
||||
* rewindReplace(char*) in order to discard the old stored data,
|
||||
* and replace it with the new state at that time. In case of an
|
||||
* event, rewindEvent(char*) is called.
|
||||
*/
|
||||
void rewind()
|
||||
{
|
||||
if(m_type==RIT_EVENT)
|
||||
m_rewinder->rewindToEvent(m_buffer);
|
||||
else if(m_type==RIT_STATE)
|
||||
{
|
||||
if(m_is_confirmed)
|
||||
m_rewinder->rewindToState(m_buffer);
|
||||
else
|
||||
{
|
||||
// TODO
|
||||
// Handle replacing of stored states.
|
||||
}
|
||||
} // time information can be ignored
|
||||
} // rewind
|
||||
}; // RewindInfo
|
||||
// ========================================================================
|
||||
|
||||
/** Pointer to all saved states. */
|
||||
typedef std::vector<RewindInfo*> AllRewindInfo;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user