From 3fc43d4d14633f47354ad66e8ea84f0c2bcc11e0 Mon Sep 17 00:00:00 2001 From: hikerstk Date: Tue, 28 Feb 2012 22:33:49 +0000 Subject: [PATCH] Refactored replay by splitting it into one base class, and dedicated classes for recording and for replaying. Added compression (by use of interpolation) settings to stk_config - atm only using a certain frequency (delta-t setting in stk_config) is used. git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@10904 178a84e3-b1eb-0310-8ba1-8eac791a3b58 --- data/stk_config.xml | 9 + src/config/stk_config.cpp | 14 ++ src/config/stk_config.hpp | 15 +- src/ide/vc9/supertuxkart.vcproj | 20 +- src/input/input_manager.cpp | 6 +- src/karts/ghost_kart.cpp | 2 +- src/main.cpp | 9 +- src/modes/world.cpp | 18 +- src/replay/replay.cpp | 347 -------------------------------- src/replay/replay.hpp | 108 ---------- src/replay/replay_base.cpp | 46 +++++ src/replay/replay_base.hpp | 61 ++++++ src/replay/replay_play.cpp | 230 +++++++++++++++++++++ src/replay/replay_play.hpp | 62 ++++++ src/replay/replay_recorder.cpp | 166 +++++++++++++++ src/replay/replay_recorder.hpp | 80 ++++++++ 16 files changed, 719 insertions(+), 474 deletions(-) delete mode 100644 src/replay/replay.cpp delete mode 100644 src/replay/replay.hpp create mode 100644 src/replay/replay_base.cpp create mode 100644 src/replay/replay_base.hpp create mode 100644 src/replay/replay_play.cpp create mode 100644 src/replay/replay_play.hpp create mode 100644 src/replay/replay_recorder.cpp create mode 100644 src/replay/replay_recorder.hpp diff --git a/data/stk_config.xml b/data/stk_config.xml index 6f665f99b..14c078668 100644 --- a/data/stk_config.xml +++ b/data/stk_config.xml @@ -52,6 +52,15 @@ + + + diff --git a/src/config/stk_config.cpp b/src/config/stk_config.cpp index 636866311..20311e4cd 100644 --- a/src/config/stk_config.cpp +++ b/src/config/stk_config.cpp @@ -138,7 +138,12 @@ void STKConfig::load(const std::string &filename) CHECK_NEG(m_leader_time_per_kart, "leader time-per-kart" ); CHECK_NEG(m_penalty_time, "penalty-time" ); CHECK_NEG(m_max_display_news, "max-display-news" ); + CHECK_NEG(m_replay_delta_angle, "replay delta-angle" ); + CHECK_NEG(m_replay_delta_pos2, "replay delta-position" ); + CHECK_NEG(m_replay_dt, "replay delta-t" ); + // Square distance to make distance checks cheaper (no sqrt) + m_replay_delta_pos2 *= m_replay_delta_pos2; m_default_kart_properties->checkAllSet(filename); } // load @@ -167,6 +172,9 @@ void STKConfig::init_defaults() m_min_track_version = -100; m_max_track_version = -100; m_max_display_news = -100; + m_replay_delta_angle = -100; + m_replay_delta_pos2 = -100; + m_replay_dt = -100; m_title_music = NULL; m_enable_networking = true; m_smooth_normals = false; @@ -345,6 +353,12 @@ void STKConfig::getAllData(const XMLNode * root) if(const XMLNode *networking_node= root->getNode("networking")) networking_node->get("enable", &m_enable_networking); + if(const XMLNode *replay_node = root->getNode("replay")) + { + replay_node->get("delta-angle", &m_replay_delta_angle); + replay_node->get("delta-pos", &m_replay_delta_pos2 ); + replay_node->get("delta-t", &m_replay_dt ); + } // Get the default KartProperties // ------------------------------ const XMLNode *node = root -> getNode("general-kart-defaults"); diff --git a/src/config/stk_config.hpp b/src/config/stk_config.hpp index 6a7323156..24335bfbd 100644 --- a/src/config/stk_config.hpp +++ b/src/config/stk_config.hpp @@ -119,8 +119,21 @@ public: * position is computed. */ std::vector m_score_increase; + /** Filename of the title music to play.*/ MusicInformation - *m_title_music; /** + + + + @@ -2207,7 +2215,15 @@ Name="replay" > + + + + diff --git a/src/input/input_manager.cpp b/src/input/input_manager.cpp index f5c1ee10d..d8275e1a3 100644 --- a/src/input/input_manager.cpp +++ b/src/input/input_manager.cpp @@ -35,7 +35,7 @@ #include "modes/profile_world.hpp" #include "modes/world.hpp" #include "race/history.hpp" -#include "replay/replay.hpp" +#include "replay/replay_recorder.hpp" #include "states_screens/kart_selection.hpp" #include "states_screens/options_screen_input2.hpp" #include "states_screens/state_manager.hpp" @@ -237,8 +237,8 @@ void InputManager::handleStaticAction(int key, int value) case KEY_F10: if(world && value) { - if(control_is_pressed) - Replay::get()->Save(); + if(control_is_pressed && ReplayRecorder::get()) + ReplayRecorder::get()->Save(); else history->Save(); } diff --git a/src/karts/ghost_kart.cpp b/src/karts/ghost_kart.cpp index 6d03f90f3..51f71aac7 100644 --- a/src/karts/ghost_kart.cpp +++ b/src/karts/ghost_kart.cpp @@ -68,7 +68,7 @@ void GhostKart::update(float dt) { m_current ++; } - if(m_current+1==m_all_times.size()) + if(m_current+1>=m_all_times.size()) { m_node->setVisible(false); return; diff --git a/src/main.cpp b/src/main.cpp index 08ea43810..810e64f82 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -172,7 +172,8 @@ #include "race/highscore_manager.hpp" #include "race/history.hpp" #include "race/race_manager.hpp" -#include "replay/replay.hpp" +#include "replay/replay_play.hpp" +#include "replay/replay_recorder.hpp" #include "states_screens/story_mode_lobby.hpp" #include "states_screens/state_manager.hpp" #include "states_screens/dialogs/message_dialog.hpp" @@ -915,7 +916,7 @@ int handleCmdLine(int argc, char **argv) } else if( !strcmp(argv[i], "--ghost")) { - Replay::get()->doReplay(); + ReplayPlay::create(); // Force the no-start screen flag, since this initialises // the player structures correctly. UserConfigParams::m_no_start_screen = true; @@ -1058,7 +1059,7 @@ void initRest() // The order here can be important, e.g. KartPropertiesManager needs // defaultKartProperties, which are defined in stk_config. history = new History (); - Replay::create(); + ReplayRecorder::create(); material_manager = new MaterialManager (); track_manager = new TrackManager (); kart_properties_manager = new KartPropertiesManager(); @@ -1122,7 +1123,7 @@ void cleanSuperTuxKart() if(track_manager) delete track_manager; if(material_manager) delete material_manager; if(history) delete history; - Replay::destroy(); + ReplayRecorder::destroy(); if(sfx_manager) delete sfx_manager; if(music_manager) delete music_manager; delete ParticleKindManager::get(); diff --git a/src/modes/world.cpp b/src/modes/world.cpp index 56256efa3..f815f6058 100644 --- a/src/modes/world.cpp +++ b/src/modes/world.cpp @@ -46,7 +46,8 @@ #include "race/highscore_manager.hpp" #include "race/history.hpp" #include "race/race_manager.hpp" -#include "replay/replay.hpp" +#include "replay/replay_play.hpp" +#include "replay/replay_recorder.hpp" #include "states_screens/state_manager.hpp" #include "states_screens/race_gui_base.hpp" #include "states_screens/race_gui.hpp" @@ -150,8 +151,8 @@ void World::init() } // for i - if(Replay::get()->isReplay()) - Replay::get()->Load(); + if(ReplayPlay::get()) + ReplayPlay::get()->Load(); resetAllKarts(); // Note: track reset must be called after all karts exist, since check @@ -160,7 +161,7 @@ void World::init() m_track->reset(); if(!history->replayHistory()) history->initRecording(); - if(!Replay::get()->isReplay()) Replay::get()->initRecording(); + if(ReplayRecorder::get()) ReplayRecorder::get()->init(); network_manager->worldLoaded(); powerup_manager->updateWeightsForRace(num_karts); @@ -635,7 +636,8 @@ void World::update(float dt) #endif history->update(dt); - Replay::get()->update(dt); + if(ReplayRecorder::get()) ReplayRecorder::get()->update(dt); + if(ReplayPlay::get()) ReplayPlay::get()->update(dt); if(history->replayHistory()) dt=history->getNextDelta(); WorldStatus::update(dt); // Clear race state so that new information can be stored @@ -912,8 +914,8 @@ void World::restartRace() { (*i)->reset(); } - if(Replay::get()->isReplay()) - Replay::get()->reset(); + if(ReplayPlay::get()) + ReplayPlay::get()->reset(); resetAllKarts(); // Start music from beginning @@ -927,7 +929,7 @@ void World::restartRace() race_manager->reset(); // Make sure to overwrite the data from the previous race. if(!history->replayHistory()) history->initRecording(); - if(!Replay::get()->isReplay()) Replay::get()->initRecording(); + if(ReplayRecorder::get()) ReplayRecorder::get()->init(); } // restartRace diff --git a/src/replay/replay.cpp b/src/replay/replay.cpp deleted file mode 100644 index d03b27ddd..000000000 --- a/src/replay/replay.cpp +++ /dev/null @@ -1,347 +0,0 @@ -// -// SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2006 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 "replay/replay.hpp" - - -#include "io/file_manager.hpp" -#include "modes/world.hpp" -#include "karts/ghost_kart.hpp" -#include "karts/kart.hpp" -#include "physics/physics.hpp" -#include "race/race_manager.hpp" -#include "tracks/track.hpp" -#include "utils/constants.hpp" - -#include -#include - -bool Replay::m_do_replay = false; -Replay *Replay::m_replay = NULL; - -//----------------------------------------------------------------------------- -/** Initialises the Replay engine - */ -Replay::Replay() -{ - m_next = 0; - m_num_ghost_karts = 0; -} // Replay - -//----------------------------------------------------------------------------- -/** Frees all stored data. */ -Replay::~Replay() -{ - m_events.clear(); -} // ~Replay - -//----------------------------------------------------------------------------- -/** Starts replay from the replay file in the current directory. - */ -void Replay::initReplay() -{ - m_next = 0; - Load(); -} // initReplayd - -//----------------------------------------------------------------------------- -/** Initialise the replay for a new recording. It especially allocates memory - * to store the replay data. - */ -void Replay::initRecording() -{ - unsigned int size = stk_config->m_max_history - * race_manager->getNumberOfKarts(); - m_events.resize(size); - m_next = 0; - m_ghost_karts.clear(); -} // initRecording - -//----------------------------------------------------------------------------- -/** Resets all ghost karts back to start position. - */ -void Replay::reset() -{ - m_next = 0; - for(unsigned int i=0; ireset(); - } -} // reset - -//----------------------------------------------------------------------------- -/** Depending on mode either saves the data for the current time step, or - * replays the data. - * /param dt Time step. - */ -void Replay::update(float dt) -{ - if(m_do_replay) - updateReplay(dt); - else - updateRecording(dt); -} // update - -//----------------------------------------------------------------------------- -/** Saves the current replay data. - * \param dt Time step size. - */ -void Replay::updateRecording(float dt) -{ - World *world = World::getWorld(); - unsigned int num_karts = world->getNumKarts(); - - if(m_next + num_karts>=m_events.size()) - { - printf("Can't store more replay information.\n"); - return; - } - - // Once we use interpolate results, we don't have to increase - // m_next by num_karts, so count how often to increase - unsigned int count = 0; - for(unsigned int i=0; igetKart(i); - p->m_time = World::getWorld()->getTime(); - p->m_type = ReplayEvent::EV_TRANSFORM; - p->m_kart_id = i; - p->m_event.m_t = kart->getTrans(); - count ++; - } // for i - m_next += count; -} // updateRecording - -//----------------------------------------------------------------------------- -/** Updates all ghost karts. - * \param dt Time step size. - */ -void Replay::updateReplay(float dt) -{ - // First update all ghost karts - for(unsigned int i=0; iupdate(dt); - -} // updateReplay - -//----------------------------------------------------------------------------- -/** Saves the replay data stored in the internal data structures. - */ -void Replay::Save() -{ - std::string filename = file_manager->getConfigDir()+"/" - + race_manager->getTrackName()+".replay"; - FILE *fd = fopen(filename.c_str(),"w"); - if(!fd) - { - filename = race_manager->getTrackName()+".replay"; - fd = fopen(filename.c_str(), "w"); - } - if(!fd) - { - printf("Can't open '%s' for writing - can't save replay data.\n", - filename.c_str()); - return; - } - printf("Replay saved in '%s'.\n", filename.c_str()); - - World *world = World::getWorld(); - int num_karts = world->getNumKarts(); - fprintf(fd, "Version: %s\n", STK_VERSION); - fprintf(fd, "difficulty: %d\n", race_manager->getDifficulty()); - fprintf(fd, "track: %s\n", world->getTrack()->getIdent().c_str()); - fprintf(fd, "Laps: %d\n", race_manager->getNumLaps()); - fprintf(fd, "numkarts: %d\n", num_karts); - - int k; - for(k=0; kgetKart(k)->getIdent().c_str()); - } - fprintf(fd, "size: %d\n", m_next); - - for(unsigned int i=0; im_type==ReplayEvent::EV_TRANSFORM) - fprintf(fd, "%d %f %d %f %f %f %f %f %f %f\n", - p->m_type, p->m_time, p->m_kart_id, - p->m_event.m_t.getOrigin().getX(), - p->m_event.m_t.getOrigin().getY(), - p->m_event.m_t.getOrigin().getZ(), - p->m_event.m_t.getRotation().getX(), - p->m_event.m_t.getRotation().getY(), - p->m_event.m_t.getRotation().getZ(), - p->m_event.m_t.getRotation().getW() - ); - } // for k - fprintf(fd, "Replay file end.\n"); - fclose(fd); -} // Save - -//----------------------------------------------------------------------------- -/** Loads a replay data from file called 'trackname'.replay. - */ -void Replay::Load() -{ - char s[1024], s1[1024]; - int n; - - std::string filename = file_manager->getConfigDir()+"/" - + race_manager->getTrackName() + ".replay"; - - FILE *fd = fopen(filename.c_str(),"r"); - if(!fd) - { - filename = race_manager->getTrackName()+".replay"; - fd = fopen(filename.c_str(), "r"); - if(!fd) - { - printf("Can't read '%s', ghost replay disabled.\n", - filename.c_str()); - m_do_replay = false; - initRecording(); - return; - } - } - printf("Reading replay file '%s'.\n", filename.c_str()); - - if (fgets(s, 1023, fd) == NULL) - { - fprintf(stderr, "ERROR: could not read '%s'.\n", filename.c_str()); - exit(-2); - } - - if (sscanf(s,"Version: %s",s1)!=1) - { - fprintf(stderr, "ERROR: no Version information found in replay file" - " (bogus replay file)\n"); - exit(-2); - } - else - { - if (strcmp(s1,STK_VERSION)) - { - fprintf(stderr, "WARNING: replay is version '%s'\n",s1); - fprintf(stderr, " STK version is '%s'\n",STK_VERSION); - } - } - - if (fgets(s, 1023, fd) == NULL) - { - fprintf(stderr, "ERROR: could not read '%s'.\n", filename.c_str()); - exit(-2); - } - - if(sscanf(s, "difficulty: %d",&n)!=1) - { - fprintf(stderr,"WARNING: No difficulty found in replay file.\n"); - exit(-2); - } - - if(race_manager->getDifficulty()!=(RaceManager::Difficulty)n) - printf("Warning, difficulty of replay is '%d', " - "while '%d' is selected.\n", - race_manager->getDifficulty(), n); - - fgets(s, 1023, fd); - if(sscanf(s, "track: %s",s1)!=1) - { - fprintf(stderr,"WARNING: Track not found in replay file.\n"); - } - assert(std::string(s1)==race_manager->getTrackName()); - race_manager->setTrack(s1); - - unsigned int num_laps; - fgets(s, 1023, fd); - if(sscanf(s, "Laps: %d",&num_laps)!=1) - { - fprintf(stderr,"WARNING: No number of laps found in replay file.\n"); - exit(-2); - } - race_manager->setNumLaps(num_laps); - - fgets(s, 1023, fd); - if(sscanf(s, "numkarts: %d",&m_num_ghost_karts)!=1) - { - fprintf(stderr,"WARNING: No number of karts found in replay file.\n"); - exit(-2); - } - - for(unsigned int i=0; igetNumPlayers()) - { - race_manager->setLocalKartInfo(i, s1); - } - } // for iaddTransform(time, btTransform(q, xyz)); - } - else - { - // Invalid record found - // --------------------- - fprintf(stderr, "Can't read replay data line %d:\n", i); - fprintf(stderr, "%s", s); - fprintf(stderr, "Ignored.\n"); - } - } // for k - fprintf(fd, "Replay file end.\n"); - fclose(fd); -} // Load - diff --git a/src/replay/replay.hpp b/src/replay/replay.hpp deleted file mode 100644 index 5d46f8fd5..000000000 --- a/src/replay/replay.hpp +++ /dev/null @@ -1,108 +0,0 @@ -// -// SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2012 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_REPLAY_HPP -#define HEADER_REPLAY_HPP - -#include "LinearMath/btTransform.h" -#include "utils/no_copy.hpp" - -#include -#include - -class GhostKart; - -/** - * \ingroup race - */ -class Replay : public NoCopy -{ -private: - struct ReplayEvent - { - /** The id of the kart for which triggers this event. */ - unsigned int m_kart_id; - /** Time at which this event happens. */ - float m_time; - enum {EV_TRANSFORM, EV_NONE} m_type; - struct { - btTransform m_t; - } m_event; // union - }; // ReplayEvent - // ------------------------------------------------------------------------ - - /** The array storing all events. */ - std::vector m_events; - - /** Static pointer to the one instance of the replay object. */ - static Replay *m_replay; - - /** True if a replay is done. */ - static bool m_do_replay; - - /** Points to the next free entry. */ - unsigned int m_next; - - /** Number of (ghost) karts contained in the replay file. */ - unsigned int m_num_ghost_karts; - - /** The identities of the karts to use. */ - std::vector m_kart_ident; - - /** All ghost karts. */ - std::vector m_ghost_karts; - - void updateRecording (float dt); - void updateReplay(float dt); - Replay(); - ~Replay(); -public: - void initReplay(); - void initRecording(); - void update(float dt); - void reset(); - void Save(); - void Load(); - - // ------------------------------------------------------------------------ - /** Creates a new instance of the replay object. */ - static void create() { m_replay = new Replay(); } - // ------------------------------------------------------------------------ - /** Returns the instance of the replay object. */ - static Replay *get() { assert(m_replay); return m_replay; } - // ------------------------------------------------------------------------ - /** Delete the instance of the replay object. */ - static void destroy() { delete m_replay; m_replay=NULL; } - // ------------------------------------------------------------------------ - /** Sets that a replay is to be done. */ - static void doReplay() { m_do_replay = true; } - // ------------------------------------------------------------------------ - /** Returns if a replay is to be done. */ - static bool isReplay() { return m_do_replay; } - // ------------------------------------------------------------------------ - /** Returns the identifier of the n-th kart. */ - const std::string& getKartIdent(unsigned int n) const - { - return m_kart_ident[n]; - } - // ------------------------------------------------------------------------ - /** Returns the number of karts contained in the replay file. */ - unsigned int getNumberGhostKarts() const { return m_num_ghost_karts;} -}; // Replay - -#endif diff --git a/src/replay/replay_base.cpp b/src/replay/replay_base.cpp new file mode 100644 index 000000000..e17d1087c --- /dev/null +++ b/src/replay/replay_base.cpp @@ -0,0 +1,46 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2012 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 "replay/replay_base.hpp" + +#include "io/file_manager.hpp" +#include "race/race_manager.hpp" + +// ----------------------------------------------------------------------------- +ReplayBase::ReplayBase() +{ + m_filename = ""; +} // ReplayBaese +// ----------------------------------------------------------------------------- +/** Opens a replay file (depending on the track name, which is taken from + * the race manager). + * \param writeable True if the file should be opened for writing. + * \return A FILE *, or NULL if the file could not be opened. + */ +FILE* ReplayBase::openReplayFile(bool writeable) +{ + m_filename = file_manager->getConfigDir()+"/" + + race_manager->getTrackName()+".replay"; + FILE *fd = fopen(m_filename.c_str(), writeable ? "w" : "r"); + if(!fd) + { + m_filename = race_manager->getTrackName()+".replay"; + fd = fopen(m_filename.c_str(), writeable ? "w" : "r"); + } + return fd; + +} // openReplayFilen \ No newline at end of file diff --git a/src/replay/replay_base.hpp b/src/replay/replay_base.hpp new file mode 100644 index 000000000..15d189c01 --- /dev/null +++ b/src/replay/replay_base.hpp @@ -0,0 +1,61 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2012 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_REPLAY_BASE_HPP +#define HEADER_REPLAY_BASE_HPP + +#include "LinearMath/btTransform.h" +#include "utils/no_copy.hpp" + +#include +#include + +/** + * \ingroup race + */ +class ReplayBase : public NoCopy +{ +private: + /** The filename of the replay file. Only defined after calling + * openReplayFile. */ + std::string m_filename; +protected: + /** Stores a transform event, i.e. a position and rotation of a kart + * at a certain time. */ + struct TransformEvent + { + /** Time at which this event happens. */ + float m_time; + /** The transform at a certain time. */ + btTransform m_transform; + }; // TransformEvent + // ------------------------------------------------------------------------ + ReplayBase(); + // ------------------------------------------------------------------------ + FILE *openReplayFile(bool writeable); + // ---------------------------------------------------------------------- + /** Returns the filename that was opened. */ + const std::string &getReplayFilename() const { return m_filename;} + // ---------------------------------------------------------------------- + /** Returns the version number of the replay file. This is used to check + * that a loaded replay file can still be understood by this + * executable. */ + unsigned int getReplayVersion() const { return 1; } +}; // ReplayBase + +#endif diff --git a/src/replay/replay_play.cpp b/src/replay/replay_play.cpp new file mode 100644 index 000000000..b6ddb7868 --- /dev/null +++ b/src/replay/replay_play.cpp @@ -0,0 +1,230 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2012 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 "replay/replay_play.hpp" + +#include "config/stk_config.hpp" +#include "io/file_manager.hpp" +#include "karts/ghost_kart.hpp" +#include "modes/world.hpp" +#include "race/race_manager.hpp" +#include "tracks/track.hpp" + +#include +#include + +ReplayPlay *ReplayPlay::m_replay_play = NULL; + +//----------------------------------------------------------------------------- +/** Initialises the Replay engine + */ +ReplayPlay::ReplayPlay() +{ + m_next = 0; +} // ReplayPlay + +//----------------------------------------------------------------------------- +/** Frees all stored data. */ +ReplayPlay::~ReplayPlay() +{ +} // ~Replay + +//----------------------------------------------------------------------------- +/** Starts replay from the replay file in the current directory. + */ +void ReplayPlay::init() +{ + m_next = 0; + Load(); +} // init + +//----------------------------------------------------------------------------- +/** Resets all ghost karts back to start position. + */ +void ReplayPlay::reset() +{ + m_next = 0; + for(unsigned int i=0; ireset(); + } +} // reset + +//----------------------------------------------------------------------------- +/** Updates all ghost karts. + * \param dt Time step size. + */ +void ReplayPlay::update(float dt) +{ + // First update all ghost karts + for(unsigned int i=0; iupdate(dt); + +} // update + +//----------------------------------------------------------------------------- +/** Loads a replay data from file called 'trackname'.replay. + */ +void ReplayPlay::Load() +{ + for(unsigned int i=0; igetDifficulty()!=(RaceManager::Difficulty)n) + printf("Warning, difficulty of replay is '%d', " + "while '%d' is selected.\n", + race_manager->getDifficulty(), n); + + fgets(s, 1023, fd); + if(sscanf(s, "track: %s",s1)!=1) + { + fprintf(stderr,"WARNING: Track not found in replay file.\n"); + } + assert(std::string(s1)==race_manager->getTrackName()); + race_manager->setTrack(s1); + + unsigned int num_laps; + fgets(s, 1023, fd); + if(sscanf(s, "Laps: %d",&num_laps)!=1) + { + fprintf(stderr,"WARNING: No number of laps found in replay file.\n"); + exit(-2); + } + race_manager->setNumLaps(num_laps); + + fgets(s, 1023, fd); + unsigned int num_ghost_karts; + if(sscanf(s, "numkarts: %d",&num_ghost_karts)!=1) + { + fprintf(stderr,"WARNING: No number of karts found in replay file.\n"); + exit(-2); + } + + for(unsigned int k=0; kaddTransform(time, btTransform(q, xyz)); + } + else + { + // Invalid record found + // --------------------- + fprintf(stderr, "Can't read replay data line %d:\n", i); + fprintf(stderr, "%s", s); + fprintf(stderr, "Ignored.\n"); + } + } // for k + + } // for i +#include + +class GhostKart; + +/** + * \ingroup replay + */ +class ReplayPlay : public ReplayBase +{ +private: + static ReplayPlay *m_replay_play; + + /** Points to the next free entry. */ + unsigned int m_next; + + /** All ghost karts. */ + std::vector m_ghost_karts; + + ReplayPlay(); + ~ReplayPlay(); +public: + void init(); + void update(float dt); + void reset(); + void Load(); + + // ------------------------------------------------------------------------ + /** Creates a new instance of the replay object. */ + static void create() { m_replay_play = new ReplayPlay(); } + // ------------------------------------------------------------------------ + /** Returns the instance of the replay object. */ + static ReplayPlay *get() { return m_replay_play; } + // ------------------------------------------------------------------------ + /** Delete the instance of the replay object. */ + static void destroy() { delete m_replay_play; m_replay_play=NULL; } +}; // Replay + +#endif diff --git a/src/replay/replay_recorder.cpp b/src/replay/replay_recorder.cpp new file mode 100644 index 000000000..b9e15234f --- /dev/null +++ b/src/replay/replay_recorder.cpp @@ -0,0 +1,166 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2012 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 "replay/replay_recorder.hpp" + +#include "config/stk_config.hpp" +#include "io/file_manager.hpp" +#include "karts/ghost_kart.hpp" +#include "modes/world.hpp" +#include "race/race_manager.hpp" +#include "tracks/track.hpp" + +#include +#include + +ReplayRecorder *ReplayRecorder::m_replay_recorder = NULL; + +//----------------------------------------------------------------------------- +/** Initialises the Replay engine + */ +ReplayRecorder::ReplayRecorder() +{ +} // ReplayRecorder + +//----------------------------------------------------------------------------- +/** Frees all stored data. */ +ReplayRecorder::~ReplayRecorder() +{ + m_transform_events.clear(); +} // ~Replay + +//----------------------------------------------------------------------------- +/** Initialise the replay recorder. It especially allocates memory + * to store the replay data. + */ +void ReplayRecorder::init() +{ + m_transform_events.clear(); + m_transform_events.resize(race_manager->getNumberOfKarts()); + for(unsigned int i=0; igetNumberOfKarts(); i++) + { + m_transform_events[i].resize(stk_config->m_max_history); + } + m_count_transforms.clear(); + m_count_transforms.resize(race_manager->getNumberOfKarts(), 0); + m_last_saved_time.clear(); + m_last_saved_time.resize(race_manager->getNumberOfKarts(), -1.0f); + +#ifdef DEBUG + m_count = 0; + m_count_skipped_time = 0; + m_count_skipped_interpolation = 0; +#endif +} // init + +//----------------------------------------------------------------------------- +/** Resets all ghost karts back to start position. + */ +void ReplayRecorder::reset() +{ +} // reset + +//----------------------------------------------------------------------------- +/** Saves the current replay data. + * \param dt Time step size. + */ +void ReplayRecorder::update(float dt) +{ + World *world = World::getWorld(); + unsigned int num_karts = world->getNumKarts(); + + float time = world->getTime(); + // Once we use interpolate results, we don't have to increase + // m_next by num_karts, so count how often to increase + unsigned int count = 0; + for(unsigned int i=0; im_replay_dt) + { +#ifdef DEBUG + m_count_skipped_time ++; +#endif + continue; + } + + m_count_transforms[i]++; + const Kart *kart = world->getKart(i); + if(m_count_transforms[i]>=m_transform_events[i].size()) + { + // Only print this message once. + if(m_count_transforms[i]==m_transform_events[i].size()) + printf("Can't store more events for kart %s.\n", + kart->getIdent().c_str()); + continue; + } + TransformEvent *p = &(m_transform_events[i][m_count_transforms[i]-1]); + p->m_time = World::getWorld()->getTime(); + p->m_transform = kart->getTrans(); + } // for i +} // updateRecording + +//----------------------------------------------------------------------------- +/** Saves the replay data stored in the internal data structures. + */ +void ReplayRecorder::Save() +{ + FILE *fd = openReplayFile(/*writeable*/true); + if(!fd) + { + printf("Can't open '%s' for writing - can't save replay data.\n", + getReplayFilename().c_str()); + return; + } + + printf("Replay saved in '%s'.\n", getReplayFilename().c_str()); + + World *world = World::getWorld(); + unsigned int num_karts = world->getNumKarts(); + fprintf(fd, "Version: %d\n", getReplayVersion()); + fprintf(fd, "difficulty: %d\n", race_manager->getDifficulty()); + fprintf(fd, "track: %s\n", world->getTrack()->getIdent().c_str()); + fprintf(fd, "Laps: %d\n", race_manager->getNumLaps()); + fprintf(fd, "numkarts: %d\n", num_karts); + + for(unsigned int k=0; kgetKart(k)->getIdent().c_str()); + fprintf(fd, "size: %d\n", m_count_transforms[k]); + + for(unsigned int i=0; im_time, + p->m_transform.getOrigin().getX(), + p->m_transform.getOrigin().getY(), + p->m_transform.getOrigin().getZ(), + p->m_transform.getRotation().getX(), + p->m_transform.getRotation().getY(), + p->m_transform.getRotation().getZ(), + p->m_transform.getRotation().getW() + ); + } // for k + } + fprintf(fd, "Replay file end.\n"); + fclose(fd); +} // Save + diff --git a/src/replay/replay_recorder.hpp b/src/replay/replay_recorder.hpp new file mode 100644 index 000000000..0dcf4c193 --- /dev/null +++ b/src/replay/replay_recorder.hpp @@ -0,0 +1,80 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2012 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_REPLAY_RECORDER_HPP +#define HEADER_REPLAY_RECORDER_HPP + +#include "replay/replay_base.hpp" + +#include + +/** + * \ingroup replay + */ +class ReplayRecorder : public ReplayBase +{ +private: + + /** A separate vector of Replay Events for all transforms. */ + std::vector< std::vector > m_transform_events; + + /** Time at which a transform was saved for the last time. */ + std::vector m_last_saved_time; + + /** Counts the number of transform events for each kart. */ + std::vector m_count_transforms; + + /** Static pointer to the one instance of the replay object. */ + static ReplayRecorder *m_replay_recorder; + +#ifdef DEBUG + /** Counts overall number of events stored. */ + unsigned int m_count; + + /** Counts number of events skipped due to minimum time between events. */ + unsigned int m_count_skipped_time; + + /** Counts number of events skipped due to interpolation. */ + unsigned int m_count_skipped_interpolation; +#endif + + + ReplayRecorder(); + ~ReplayRecorder(); +public: + void init(); + void update(float dt); + void reset(); + void Save(); + + // ------------------------------------------------------------------------ + /** Creates a new instance of the replay object. */ + static void create() { + assert(!m_replay_recorder); + m_replay_recorder = new ReplayRecorder(); + } + // ------------------------------------------------------------------------ + /** Returns the instance of the replay object. Returns NULL if no + * recorder is available, i.e. recording can be disabled. */ + static ReplayRecorder *get() { return m_replay_recorder; } + // ------------------------------------------------------------------------ + /** Delete the instance of the replay object. */ + static void destroy() { delete m_replay_recorder; m_replay_recorder=NULL; } +}; // ReplayRecorder + +#endif