replay ghost works very basic.
* no interpolation of ghosts position between sampled frames * no transparency or something else to distinguish to see it: * run a game, rename file replay/test.rph to replay/test1.rph - this file is shown in replay git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/trunk/supertuxkart@1253 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
parent
e5fd4c885c
commit
0a44bf57d5
@ -23,7 +23,6 @@
|
|||||||
#ifdef HAVE_GHOST_REPLAY
|
#ifdef HAVE_GHOST_REPLAY
|
||||||
|
|
||||||
|
|
||||||
#include <new>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <plib/sg.h>
|
#include <plib/sg.h>
|
||||||
|
|
||||||
@ -60,7 +59,6 @@ public:
|
|||||||
|
|
||||||
virtual void destroy();
|
virtual void destroy();
|
||||||
|
|
||||||
bool loadReplayHumanReadable( FILE *fd, size_t number_cars ) { return m_ReplayBuffers.loadReplayHumanReadable( fd, number_cars ); }
|
|
||||||
bool saveReplayHumanReadable( FILE *fd ) const { return m_ReplayBuffers.saveReplayHumanReadable( fd ); }
|
bool saveReplayHumanReadable( FILE *fd ) const { return m_ReplayBuffers.saveReplayHumanReadable( fd ); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -60,16 +60,16 @@ private:
|
|||||||
public:
|
public:
|
||||||
bool init( size_t number_preallocated_objects );
|
bool init( size_t number_preallocated_objects );
|
||||||
void destroy();
|
void destroy();
|
||||||
|
// this is false, if a reallocation failed
|
||||||
bool isHealthy() const { return m_healthy; }
|
bool isHealthy() const { return m_healthy; }
|
||||||
// returns a new *free* object, allocated memory if necessary
|
// returns a new *free* object, allocated memory if necessary
|
||||||
T* getNewObject();
|
T* getNewObject();
|
||||||
// returns a new *free* array of objects
|
|
||||||
//T* getNewObjects( size_t number_objects );
|
|
||||||
// returs object at given position, like usual array access,
|
// returs object at given position, like usual array access,
|
||||||
// does not allocate memory
|
// does not allocate memory, index must be < getNumberObjectsUsed()
|
||||||
T const* getObjectAt( size_t index ) const;
|
T const* getObjectAt( size_t index ) const;
|
||||||
T* getObjectAt( size_t index );
|
T* getObjectAt( size_t index );
|
||||||
size_t getNumberObjectsUsed() const { return m_number_objects_used; }
|
size_t getNumberObjectsUsed() const { return m_number_objects_used; }
|
||||||
|
size_t getNumberBlocks() const { return m_number_blocks; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// adds a new block of objects to m_pp_blocks with a size of m_block_size
|
// adds a new block of objects to m_pp_blocks with a size of m_block_size
|
||||||
@ -121,6 +121,7 @@ public:
|
|||||||
T const* getArrayAt( size_t index ) const { assert( m_array_size ); return m_Buffer.getObjectAt( m_array_size * index ); }
|
T const* getArrayAt( size_t index ) const { assert( m_array_size ); return m_Buffer.getObjectAt( m_array_size * index ); }
|
||||||
T* getArrayAt( size_t index ) { assert( m_array_size ); return m_Buffer.getObjectAt( m_array_size * index ); }
|
T* getArrayAt( size_t index ) { assert( m_array_size ); return m_Buffer.getObjectAt( m_array_size * index ); }
|
||||||
size_t getNumberArraysUsed() const { return m_Buffer.getNumberObjectsUsed() / m_array_size; }
|
size_t getNumberArraysUsed() const { return m_Buffer.getNumberObjectsUsed() / m_array_size; }
|
||||||
|
size_t getNumberBlocks() const { return m_Buffer.getNumberBlocks(); }
|
||||||
bool isHealthy() const { return m_Buffer.isHealthy(); }
|
bool isHealthy() const { return m_Buffer.isHealthy(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -57,24 +57,18 @@ ReplayBuffers::getNewFrame()
|
|||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReplayFrame const*
|
|
||||||
ReplayBuffers::getFrame( size_t frame_index ) const
|
|
||||||
{
|
|
||||||
return m_BufferFrame.getObjectAt( frame_index );
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ReplayBuffers::saveReplayHumanReadable( FILE *fd ) const
|
bool ReplayBuffers::saveReplayHumanReadable( FILE *fd ) const
|
||||||
{
|
{
|
||||||
if( !isHealthy() ) return false;
|
if( !isHealthy() ) return false;
|
||||||
|
|
||||||
if( fprintf( fd, "frames: %u\n", getNumberFramesUsed() ) < 1 ) return false;
|
if( fprintf( fd, "frames: %u\n", getNumberFrames() ) < 1 ) return false;
|
||||||
|
|
||||||
unsigned int frame_idx, kart_idx;
|
unsigned int frame_idx, kart_idx;
|
||||||
ReplayFrame const *frame;
|
ReplayFrame const *frame;
|
||||||
ReplayKartState const *kart;
|
ReplayKartState const *kart;
|
||||||
for( frame_idx = 0; frame_idx < getNumberFramesUsed(); ++frame_idx )
|
for( frame_idx = 0; frame_idx < getNumberFrames(); ++frame_idx )
|
||||||
{
|
{
|
||||||
frame = getFrame( frame_idx );
|
frame = getFrameAt( frame_idx );
|
||||||
if( fprintf( fd, "frame %u time %f\n", frame_idx, frame->time ) < 1 ) return false;
|
if( fprintf( fd, "frame %u time %f\n", frame_idx, frame->time ) < 1 ) return false;
|
||||||
|
|
||||||
for( kart_idx = 0; kart_idx < m_number_cars; ++kart_idx )
|
for( kart_idx = 0; kart_idx < m_number_cars; ++kart_idx )
|
||||||
@ -100,14 +94,13 @@ bool ReplayBuffers::loadReplayHumanReadable( FILE *fd, size_t number_cars )
|
|||||||
unsigned int frame_idx, kart_idx, tmp;
|
unsigned int frame_idx, kart_idx, tmp;
|
||||||
ReplayFrame *frame;
|
ReplayFrame *frame;
|
||||||
ReplayKartState *kart;
|
ReplayKartState *kart;
|
||||||
for( frame_idx = 0; frame_idx < getNumberFramesUsed(); ++frame_idx )
|
for( frame_idx = 0; frame_idx < frames; ++frame_idx )
|
||||||
{
|
{
|
||||||
frame = m_BufferFrame.getObjectAt( frame_idx );
|
// if we are here, it cant fail, since enough objects have to be allocated above
|
||||||
|
frame = getNewFrame();
|
||||||
assert( frame );
|
assert( frame );
|
||||||
if( fscanf( fd, "frame %u time %f\n", &tmp, &frame->time ) != 2 ) return false;
|
|
||||||
|
|
||||||
frame->p_kart_states = m_BufferKartState.getArrayAt( frame_idx );
|
if( fscanf( fd, "frame %u time %f\n", &tmp, &frame->time ) != 2 ) return false;
|
||||||
assert( frame->p_kart_states );
|
|
||||||
|
|
||||||
for( kart_idx = 0; kart_idx < number_cars; ++kart_idx )
|
for( kart_idx = 0; kart_idx < number_cars; ++kart_idx )
|
||||||
{
|
{
|
||||||
@ -119,6 +112,14 @@ bool ReplayBuffers::loadReplayHumanReadable( FILE *fd, size_t number_cars )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert( frames == getNumberFrames() );
|
||||||
|
assert( m_BufferFrame.getNumberObjectsUsed() == getNumberFrames() );
|
||||||
|
assert( m_BufferKartState.getNumberArraysUsed() == getNumberFrames() );
|
||||||
|
|
||||||
|
// there should be no reallocation ..
|
||||||
|
assert( m_BufferFrame.getNumberBlocks() == 1 );
|
||||||
|
assert( m_BufferKartState.getNumberBlocks() == 1 );
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <new>
|
|
||||||
|
|
||||||
#include "replay_buffer_tpl.hpp"
|
#include "replay_buffer_tpl.hpp"
|
||||||
|
|
||||||
@ -51,14 +50,16 @@ public:
|
|||||||
|
|
||||||
// returs frame at given position from replay data
|
// returs frame at given position from replay data
|
||||||
// used to *show* the replay
|
// used to *show* the replay
|
||||||
ReplayFrame const* getFrame( size_t frame_index ) const;
|
// if frame_index >= num_frames -> returns NULL
|
||||||
|
ReplayFrame const* getFrameAt( size_t frame_index ) const { return m_BufferFrame.getObjectAt( frame_index ); }
|
||||||
|
|
||||||
|
size_t getNumberFrames() const { return m_BufferFrame.getNumberObjectsUsed(); }
|
||||||
|
|
||||||
bool saveReplayHumanReadable( FILE *fd ) const;
|
bool saveReplayHumanReadable( FILE *fd ) const;
|
||||||
bool loadReplayHumanReadable( FILE *fd, size_t number_cars );
|
bool loadReplayHumanReadable( FILE *fd, size_t number_cars );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isHealthy() const { return m_BufferFrame.isHealthy() && m_BufferKartState.isHealthy(); }
|
bool isHealthy() const { return m_BufferFrame.isHealthy() && m_BufferKartState.isHealthy(); }
|
||||||
size_t getNumberFramesUsed() const { return m_BufferFrame.getNumberObjectsUsed(); }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef Buffer<ReplayFrame> BufferFrame;
|
typedef Buffer<ReplayFrame> BufferFrame;
|
||||||
|
@ -1,11 +1,137 @@
|
|||||||
#ifdef HAVE_GHOST_REPLAY
|
#ifdef HAVE_GHOST_REPLAY
|
||||||
|
|
||||||
|
#include "kart_properties_manager.hpp"
|
||||||
|
#include "kart_properties.hpp"
|
||||||
|
|
||||||
#include "replay_player.hpp"
|
#include "replay_player.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
ReplayKart::ReplayKart()
|
||||||
|
: m_kart_properties(NULL), m_model(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ReplayKart::~ReplayKart()
|
||||||
|
{
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReplayKart::destroy()
|
||||||
|
{
|
||||||
|
m_kart_properties = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReplayKart::init( const std::string &strKartIdent )
|
||||||
|
{
|
||||||
|
assert( !m_kart_properties );
|
||||||
|
|
||||||
|
m_model = new ssgTransform();
|
||||||
|
m_model->ref();
|
||||||
|
|
||||||
|
m_kart_properties = kart_properties_manager->getKart( strKartIdent );
|
||||||
|
if( NULL == m_kart_properties ) return false;
|
||||||
|
|
||||||
|
ssgEntity *obj = m_kart_properties->getModel();
|
||||||
|
assert( obj );
|
||||||
|
// Optimize the model, this can't be done while loading the model
|
||||||
|
// because it seems that it removes the name of the wheels or something
|
||||||
|
// else needed to load the wheels as a separate object.
|
||||||
|
ssgFlatten(obj);
|
||||||
|
|
||||||
|
ssgRangeSelector *lod = new ssgRangeSelector;
|
||||||
|
|
||||||
|
float r [ 2 ] = { -10.0f, 100.0f } ;
|
||||||
|
lod -> addKid ( obj ) ;
|
||||||
|
lod -> setRanges ( r, 2 ) ;
|
||||||
|
|
||||||
|
m_model -> addKid ( lod ) ;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "scene.hpp"
|
||||||
|
|
||||||
|
ReplayPlayer::ReplayPlayer()
|
||||||
|
: ReplayBase(), m_current_frame_index(-1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ReplayPlayer::~ReplayPlayer()
|
||||||
|
{
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReplayPlayer::destroy()
|
||||||
|
{
|
||||||
|
m_current_frame_index = -1;
|
||||||
|
m_Karts.clear();
|
||||||
|
ReplayBase::destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReplayPlayer::loadReplayHumanReadable( FILE *fd )
|
||||||
|
{
|
||||||
|
destroy();
|
||||||
|
|
||||||
|
bool blnRet = false;
|
||||||
|
int intTemp;
|
||||||
|
char buff[1000];
|
||||||
|
size_t number_karts;
|
||||||
|
if( fscanf( fd, "Version: %s\n", buff ) != 1 ) return false;
|
||||||
|
if( fscanf( fd, "numkarts: %u\n", &number_karts ) != 1 ) return false;
|
||||||
|
if( fscanf( fd, "numplayers: %s\n", buff ) != 1 ) return false;
|
||||||
|
if( fscanf( fd, "difficulty: %s\n", buff ) != 1 ) return false;
|
||||||
|
if( fscanf( fd, "track: %s\n", buff ) != 1 ) return false;
|
||||||
|
for( size_t k = 0; k < number_karts; ++k )
|
||||||
|
{
|
||||||
|
if( fscanf( fd, "model %d: %s\n", &intTemp, buff ) != 2 ) return false;
|
||||||
|
|
||||||
|
m_Karts.resize( m_Karts.size() + 1 );
|
||||||
|
ReplayKart &kart = m_Karts[ m_Karts.size() - 1 ];
|
||||||
|
if( !kart.init( buff ) ) return false;
|
||||||
|
|
||||||
|
scene->add ( kart.getModel() );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !m_ReplayBuffers.loadReplayHumanReadable( fd, number_karts ) ) return false;
|
||||||
|
|
||||||
|
m_current_frame_index = 0;
|
||||||
|
updateObjects();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReplayPlayer::showReplayAt( float abs_time )
|
||||||
|
{
|
||||||
|
assert( m_current_frame_index > -1 );
|
||||||
|
assert( (size_t)m_current_frame_index < m_ReplayBuffers.getNumberFrames() );
|
||||||
|
|
||||||
|
ReplayFrame const* frame;
|
||||||
|
|
||||||
|
// find the current frame, we only scroll forward ..
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
// end reached?
|
||||||
|
if( (m_current_frame_index + 1) == m_ReplayBuffers.getNumberFrames() ) break;
|
||||||
|
|
||||||
|
// check time of next frame
|
||||||
|
frame = m_ReplayBuffers.getFrameAt( m_current_frame_index+1 );
|
||||||
|
if( frame->time > abs_time ) break;
|
||||||
|
|
||||||
|
++m_current_frame_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReplayPlayer::updateObjects()
|
||||||
|
{
|
||||||
|
ReplayFrame const* frame = m_ReplayBuffers.getFrameAt( m_current_frame_index );
|
||||||
|
|
||||||
|
for( size_t k = 0; k < m_Karts.size(); ++k )
|
||||||
|
{
|
||||||
|
m_Karts[ k ].setPosition( frame->p_kart_states[ k ].position );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif // HAVE_GHOST_REPLAY
|
#endif // HAVE_GHOST_REPLAY
|
||||||
|
@ -22,23 +22,67 @@
|
|||||||
|
|
||||||
#ifdef HAVE_GHOST_REPLAY
|
#ifdef HAVE_GHOST_REPLAY
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <plib/ssg.h>
|
||||||
|
|
||||||
#include "replay_base.hpp"
|
#include "replay_base.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
class KartProperties;
|
||||||
|
class ReplayKart
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ReplayKart();
|
||||||
|
~ReplayKart();
|
||||||
|
|
||||||
|
ReplayKart( ReplayKart const &kart ) { *this = kart; }
|
||||||
|
ReplayKart& operator=( ReplayKart const &kart )
|
||||||
|
{
|
||||||
|
assert( this != &kart );
|
||||||
|
m_kart_properties = kart.m_kart_properties;
|
||||||
|
m_model = kart.m_model;
|
||||||
|
sgCopyCoord ( &m_position, &kart.m_position );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
bool init( const std::string &strKartIdent );
|
||||||
|
void destroy();
|
||||||
|
|
||||||
|
ssgTransform* getModel() { return m_model; }
|
||||||
|
|
||||||
|
void setPosition( const sgCoord &pos ) { sgCopyCoord ( &m_position, &pos ); m_model->setTransform(&m_position); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const KartProperties *m_kart_properties;
|
||||||
|
sgCoord m_position;
|
||||||
|
ssgTransform *m_model;
|
||||||
|
};
|
||||||
|
|
||||||
// class managing:
|
// class managing:
|
||||||
// - the loading of replay-file
|
// - the loading of replay-file
|
||||||
// - the rendering of the replay (interpolation if needed)
|
// - the rendering of the replay (interpolation if needed)
|
||||||
class ReplayPlayer : public ReplayBase
|
class ReplayPlayer : public ReplayBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ReplayPlayer() : ReplayBase() {}
|
ReplayPlayer();
|
||||||
virtual ~ReplayPlayer() { destroy(); }
|
virtual ~ReplayPlayer();
|
||||||
|
|
||||||
void destroy() { ReplayBase::destroy(); }
|
void destroy();
|
||||||
|
|
||||||
|
bool loadReplayHumanReadable( FILE *fd );
|
||||||
|
|
||||||
|
void showReplayAt( float abs_time );
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateObjects();
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef std::vector<ReplayKart> ReplayKarts;
|
||||||
|
|
||||||
|
int m_current_frame_index;
|
||||||
|
ReplayKarts m_Karts;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // HAVE_GHOST_REPLAY
|
#endif // HAVE_GHOST_REPLAY
|
||||||
|
|
||||||
#endif // HEADER_REPLAYPLAYER_H
|
#endif // HEADER_REPLAYPLAYER_H
|
||||||
|
@ -52,7 +52,6 @@
|
|||||||
#include "highscore_manager.hpp"
|
#include "highscore_manager.hpp"
|
||||||
#include "scene.hpp"
|
#include "scene.hpp"
|
||||||
#include "camera.hpp"
|
#include "camera.hpp"
|
||||||
|
|
||||||
#include "robots/default_robot.hpp"
|
#include "robots/default_robot.hpp"
|
||||||
#ifdef HAVE_GHOST_REPLAY
|
#ifdef HAVE_GHOST_REPLAY
|
||||||
# include "replay_player.hpp"
|
# include "replay_player.hpp"
|
||||||
@ -207,12 +206,14 @@ World::World(const RaceSetup& raceSetup_) : m_race_setup(raceSetup_)
|
|||||||
|
|
||||||
#ifdef HAVE_GHOST_REPLAY
|
#ifdef HAVE_GHOST_REPLAY
|
||||||
m_replay_recorder.initRecorder( m_race_setup.getNumKarts() );
|
m_replay_recorder.initRecorder( m_race_setup.getNumKarts() );
|
||||||
|
|
||||||
m_p_replay_player = new ReplayPlayer;
|
m_p_replay_player = new ReplayPlayer;
|
||||||
if( !loadReplayHumanReadable( "test1" ) )
|
if( !loadReplayHumanReadable( "test1" ) )
|
||||||
{
|
{
|
||||||
delete m_p_replay_player;
|
delete m_p_replay_player;
|
||||||
m_p_replay_player = NULL;
|
m_p_replay_player = NULL;
|
||||||
}
|
}
|
||||||
|
if( m_p_replay_player ) m_p_replay_player->showReplayAt( m_clock );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,9 +293,13 @@ void World::draw()
|
|||||||
void World::update(float delta)
|
void World::update(float delta)
|
||||||
{
|
{
|
||||||
if(user_config->m_replay_history) delta=history->GetNextDelta();
|
if(user_config->m_replay_history) delta=history->GetNextDelta();
|
||||||
m_clock += delta;
|
|
||||||
|
|
||||||
checkRaceStatus();
|
checkRaceStatus();
|
||||||
|
// this line was before checkRaceStatus. but m_clock is set to 0.0 in
|
||||||
|
// checkRaceStatus on start, so m_clock would not be synchron and the
|
||||||
|
// first delta would not be added .. that would cause a gap in
|
||||||
|
// replay-recording
|
||||||
|
m_clock += delta;
|
||||||
|
|
||||||
// Count the number of collision in the next 'FRAMES_FOR_TRAFFIC_JAM' frames.
|
// Count the number of collision in the next 'FRAMES_FOR_TRAFFIC_JAM' frames.
|
||||||
// If a kart has more than one hit, play 'traffic jam' noise.
|
// If a kart has more than one hit, play 'traffic jam' noise.
|
||||||
@ -400,7 +405,13 @@ void World::update(float delta)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_GHOST_REPLAY
|
#ifdef HAVE_GHOST_REPLAY
|
||||||
|
// we start recording after START_PHASE, since during start-phase m_clock is incremented
|
||||||
|
// normally, but after switching to RACE_PHASE m_clock is set back to 0.0
|
||||||
|
if( m_phase != START_PHASE )
|
||||||
|
{
|
||||||
pushReplayFrameData();
|
pushReplayFrameData();
|
||||||
|
if( m_p_replay_player ) m_p_replay_player->showReplayAt( m_clock );
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,6 +419,9 @@ void World::update(float delta)
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void World::pushReplayFrameData()
|
void World::pushReplayFrameData()
|
||||||
{
|
{
|
||||||
|
// we dpnt record the startphase ..
|
||||||
|
assert( m_phase != START_PHASE );
|
||||||
|
|
||||||
ReplayFrame *pFrame = m_replay_recorder.getNewFrame();
|
ReplayFrame *pFrame = m_replay_recorder.getNewFrame();
|
||||||
if( !pFrame ) return;
|
if( !pFrame ) return;
|
||||||
|
|
||||||
@ -457,9 +471,11 @@ bool World::saveReplayHumanReadable( std::string const &filename ) const
|
|||||||
fprintf(fd, "numplayers: %d\n", m_race_setup.getNumPlayers());
|
fprintf(fd, "numplayers: %d\n", m_race_setup.getNumPlayers());
|
||||||
fprintf(fd, "difficulty: %d\n", m_race_setup.m_difficulty);
|
fprintf(fd, "difficulty: %d\n", m_race_setup.m_difficulty);
|
||||||
fprintf(fd, "track: %s\n", m_track->getIdent());
|
fprintf(fd, "track: %s\n", m_track->getIdent());
|
||||||
for( size_t k = 0; k < m_kart.size(); ++k )
|
|
||||||
|
for (RaceSetup::Karts::const_iterator i = m_race_setup.m_karts.begin() ;
|
||||||
|
i != m_race_setup.m_karts.end() ; ++i )
|
||||||
{
|
{
|
||||||
fprintf(fd, "model %d: %s\n",k, m_kart[k]->getName().c_str());
|
fprintf(fd, "model %d: %s\n", i-m_race_setup.m_karts.begin(), (*i).c_str());
|
||||||
}
|
}
|
||||||
if( !m_replay_recorder.saveReplayHumanReadable( fd ) )
|
if( !m_replay_recorder.saveReplayHumanReadable( fd ) )
|
||||||
{
|
{
|
||||||
@ -501,26 +517,8 @@ bool World::loadReplayHumanReadable( std::string const &filename )
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool blnRet = false;
|
bool blnRet = m_p_replay_player->loadReplayHumanReadable( fd );
|
||||||
int intTemp;
|
|
||||||
char buff[1000];
|
|
||||||
size_t number_karts;
|
|
||||||
size_t frames;
|
|
||||||
if( fscanf( fd, "Version: %s\n", buff ) != 1 ) goto close;
|
|
||||||
if( fscanf( fd, "numkarts: %u\n", &number_karts ) != 1 ) goto close;
|
|
||||||
if( fscanf( fd, "numplayers: %s\n", buff ) != 1 ) goto close;
|
|
||||||
if( fscanf( fd, "difficulty: %s\n", buff ) != 1 ) goto close;
|
|
||||||
if( fscanf( fd, "track: %s\n", buff ) != 1 ) goto close;
|
|
||||||
for( size_t k = 0; k < m_kart.size(); ++k )
|
|
||||||
{
|
|
||||||
if( fscanf( fd, "model %d: %s\n", &intTemp, buff ) != 2 ) goto close;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !m_p_replay_player->loadReplayHumanReadable( fd, number_karts ) ) goto close;
|
|
||||||
|
|
||||||
blnRet = true;
|
|
||||||
|
|
||||||
close:
|
|
||||||
fclose( fd ); fd = NULL;
|
fclose( fd ); fd = NULL;
|
||||||
|
|
||||||
return blnRet;
|
return blnRet;
|
||||||
@ -542,6 +540,10 @@ void World::checkRaceStatus()
|
|||||||
m_phase = RACE_PHASE;
|
m_phase = RACE_PHASE;
|
||||||
m_clock = 0.0f;
|
m_clock = 0.0f;
|
||||||
sound_manager->playSfx(SOUND_START);
|
sound_manager->playSfx(SOUND_START);
|
||||||
|
#ifdef HAVE_GHOST_REPLAY
|
||||||
|
// push positions at time 0.0 to replay-data
|
||||||
|
pushReplayFrameData();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else if (m_clock > 1.0 && m_ready_set_go == 2)
|
else if (m_clock > 1.0 && m_ready_set_go == 2)
|
||||||
{
|
{
|
||||||
|
@ -130,6 +130,7 @@ private:
|
|||||||
sgCoord init_pos);
|
sgCoord init_pos);
|
||||||
|
|
||||||
#ifdef HAVE_GHOST_REPLAY
|
#ifdef HAVE_GHOST_REPLAY
|
||||||
|
private:
|
||||||
void pushReplayFrameData();
|
void pushReplayFrameData();
|
||||||
bool saveReplayHumanReadable( std::string const &filename ) const;
|
bool saveReplayHumanReadable( std::string const &filename ) const;
|
||||||
bool loadReplayHumanReadable( std::string const &filename );
|
bool loadReplayHumanReadable( std::string const &filename );
|
||||||
@ -137,6 +138,7 @@ private:
|
|||||||
ReplayRecorder m_replay_recorder;
|
ReplayRecorder m_replay_recorder;
|
||||||
ReplayPlayer *m_p_replay_player;
|
ReplayPlayer *m_p_replay_player;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern World* world;
|
extern World* world;
|
||||||
|
Loading…
Reference in New Issue
Block a user