1 //
2 //  SuperTuxKart - a fun racing game with go-kart
3 //  Copyright (C) 2006-2015 Joerg Henrichs
4 //
5 //  This program is free software; you can redistribute it and/or
6 //  modify it under the terms of the GNU General Public License
7 //  as published by the Free Software Foundation; either version 3
8 //  of the License, or (at your option) any later version.
9 //
10 //  This program is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //  GNU General Public License for more details.
14 //
15 //  You should have received a copy of the GNU General Public License
16 //  along with this program; if not, write to the Free Software
17 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 #include "race/history.hpp"
20 
21 #include <stdio.h>
22 
23 #include "io/file_manager.hpp"
24 #include "modes/world.hpp"
25 #include "karts/abstract_kart.hpp"
26 #include "karts/controller/controller.hpp"
27 #include "network/network_config.hpp"
28 #include "network/rewind_manager.hpp"
29 #include "physics/physics.hpp"
30 #include "race/race_manager.hpp"
31 #include "tracks/track.hpp"
32 #include "utils/constants.hpp"
33 #include "utils/file_utils.hpp"
34 
35 History* history = 0;
36 bool History::m_online_history_replay = false;
37 //-----------------------------------------------------------------------------
38 /** Initialises the history object and sets the mode to none.
39  */
History()40 History::History()
41 {
42     m_replay_history = false;
43 }   // History
44 
45 //-----------------------------------------------------------------------------
46 /** Initialise the history for a new recording. It especially allocates memory
47  *  to store the history.
48  */
initRecording()49 void History::initRecording()
50 {
51     allocateMemory();
52     m_event_index = 0;
53     m_all_input_events.clear();
54 }   // initRecording
55 
56 //-----------------------------------------------------------------------------
57 /** Allocates memory for the history. This is used when recording as well
58  *  as when replaying (since in replay the data is read into memory first).
59  *  \param number_of_frames Maximum number of frames to store.
60  */
allocateMemory(int size)61 void History::allocateMemory(int size)
62 {
63     m_all_input_events.clear();
64     if(size<0)
65         m_all_input_events.reserve(1024);
66     else
67         m_all_input_events.resize(size);
68 }   // allocateMemory
69 
70 //-----------------------------------------------------------------------------
71 /** Stores an input event (e.g. acceleration or steering event) into the
72  *  history data for physics replay.
73  *  \param kart_id The kart index which triggered the event.
74  *  \param pa      The action.
75  *  \param value   Value of the action (0=release, 32768 = pressed), in
76  *                 between in case of analog devices.
77  */
addEvent(int kart_id,PlayerAction pa,int value)78 void History::addEvent(int kart_id, PlayerAction pa, int value)
79 {
80     InputEvent ie;
81     // The event is added before m_current is increased. So in order to
82     // save the right index for this event, we need to use m_current+1.
83     ie.m_world_ticks = World::getWorld()->getTicksSinceStart();
84     ie.m_action      = pa;
85     ie.m_value       = value;
86     ie.m_kart_index  = kart_id;
87     m_all_input_events.emplace_back(ie);
88 }   // addEvent
89 
90 //-----------------------------------------------------------------------------
91 /** Sets the kart position and controls to the recorded history value.
92  *  \param world_ticks WOrld time in ticks.
93  *  \param ticks Number of time steps.
94  */
updateReplay(int world_ticks)95 void History::updateReplay(int world_ticks)
96 {
97     World *world = World::getWorld();
98 
99     while (m_event_index < m_all_input_events.size() &&
100         m_all_input_events[m_event_index].m_world_ticks <= world_ticks)
101     {
102         const InputEvent &ie = m_all_input_events[m_event_index];
103         AbstractKart *kart = world->getKart(ie.m_kart_index);
104         Log::verbose("history", "time %d event-time %d action %d %d",
105             world->getTicksSinceStart(), ie.m_world_ticks, ie.m_action,
106             ie.m_value);
107         kart->getController()->action(ie.m_action, ie.m_value);
108         m_event_index++;
109     }   // while we have events for current time step.
110 
111     // Check if we have reached the end of the buffer
112     if(m_event_index >= m_all_input_events.size())
113     {
114         Log::info("History", "Replay finished");
115         m_event_index= 0;
116         // This is useful to use a reproducable rewind problem:
117         // replay it with history, for debugging only
118 #undef DO_REWIND_AT_END_OF_HISTORY
119 #ifdef DO_REWIND_AT_END_OF_HISTORY
120         RewindManager::get()->rewindTo(5.0f);
121         exit(-1);
122 #else
123         world->reset();
124 #endif
125     }   // if m_event_index >= m_all_input_events.size()
126 
127 }   // updateReplay
128 
129 //-----------------------------------------------------------------------------
130 /** Saves the history stored in the internal data structures into a file called
131  *  history.dat.
132  */
Save()133 void History::Save()
134 {
135     FILE *fd = fopen("history.dat","w");
136     if(fd)
137         Log::info("History", "Saved in ./history.dat.");
138     else
139     {
140         std::string fn = file_manager->getUserConfigFile("history.dat");
141         fd = FileUtils::fopenU8Path(fn, "w");
142         if(fd)
143             Log::info("History", "Saved in '%s'.", fn.c_str());
144     }
145     if(!fd)
146     {
147         Log::info("History", "Can't open history.dat file for writing - can't save history.");
148         Log::info("History", "Make sure history.dat in the current directory "
149                              "or the config directory is writable.");
150         return;
151     }
152 
153     World *world   = World::getWorld();
154     const int num_karts = world->getNumKarts();
155     fprintf(fd, "STK-version:      %s\n",   STK_VERSION);
156     fprintf(fd, "History-version:  %d\n",   1);
157     fprintf(fd, "numkarts:         %d\n",   num_karts);
158     fprintf(fd, "numplayers:       %d\n", RaceManager::get()->getNumPlayers());
159     fprintf(fd, "difficulty:       %d\n", RaceManager::get()->getDifficulty());
160     fprintf(fd, "reverse: %c\n", RaceManager::get()->getReverseTrack() ? 'y' : 'n');
161 
162     fprintf(fd, "track: %s\n", Track::getCurrentTrack()->getIdent().c_str());
163 
164     assert(num_karts > 0);
165 
166     int k;
167     for(k=0; k<num_karts; k++)
168     {
169         fprintf(fd, "model %d: %s\n",k, world->getKart(k)->getIdent().c_str());
170     }
171     fprintf(fd, "count:     %zu\n", m_all_input_events.size());
172 
173     for (unsigned int i = 0; i < m_all_input_events.size(); i++)
174     {
175         fprintf(fd, "%d %d %d %d\n",
176                 m_all_input_events[i].m_world_ticks,
177                 m_all_input_events[i].m_kart_index,
178                 m_all_input_events[i].m_action,
179                 m_all_input_events[i].m_value      );
180     }   // for i
181 
182     fprintf(fd, "History file end.\n");
183     fclose(fd);
184 }   // Save
185 
186 //-----------------------------------------------------------------------------
187 /** Loads a history from history.dat in the current directory.
188  */
Load()189 void History::Load()
190 {
191     char s[1024], s1[1024];
192     int  n;
193 
194     FILE *fd = fopen("history.dat","r");
195     if(fd)
196         Log::info("History", "Reading ./history.dat");
197     else
198     {
199         std::string fn = file_manager->getUserConfigFile("history.dat");
200         fd = FileUtils::fopenU8Path(fn, "r");
201         if(fd)
202             Log::info("History", "Reading '%s'.", fn.c_str());
203     }
204     if(!fd)
205         Log::fatal("History", "Could not open history.dat");
206 
207     if (fgets(s, 1023, fd) == NULL)
208         Log::fatal("History", "Could not read history.dat.");
209 
210     // Check for unsupported hsitory file formats:
211     if (sscanf(s, "Version-2: %1023s", s1) == 1 ||
212         sscanf(s, "Version-1: %1023s", s1) == 1)
213     {
214         Log::fatal("History",
215                    "Old history file format is not supported anymore.");
216     }
217 
218     if (sscanf(s,"STK-version: %1023s",s1)!=1)
219         Log::fatal("History", "No Version information found in history "
220                               "file (bogus history file).");
221     if (strcmp(s1,STK_VERSION))
222         Log::warn("History", "History is version '%s', STK version is '%s'.",
223                   s1, STK_VERSION);
224 
225     if (fgets(s, 1023, fd) == NULL)
226         Log::fatal("History", "Could not read history.dat.");
227 
228     int version;
229     if (sscanf(s, "History-version: %1023d", &version) != 1)
230         Log::fatal("Invalid version number found: '%s'", s);
231 
232     if (version != 1)
233         Log::fatal("History",
234                    "Old-style history files are not supported anymore.");
235 
236     if (fgets(s, 1023, fd) == NULL)
237         Log::fatal("History", "Could not read history.dat.");
238 
239     unsigned int num_karts;
240     if(sscanf(s, "numkarts: %u", &num_karts)!=1)
241         Log::fatal("History", "No number of karts found in history file.");
242     RaceManager::get()->setNumKarts(num_karts);
243 
244     fgets(s, 1023, fd);
245     if(sscanf(s, "numplayers: %d",&n)!=1)
246         Log::fatal("History", "No number of players found in history file.");
247     RaceManager::get()->setNumPlayers(n);
248 
249     fgets(s, 1023, fd);
250     if(sscanf(s, "difficulty: %d",&n)!=1)
251         Log::fatal("History", "No difficulty found in history file.");
252     RaceManager::get()->setDifficulty((RaceManager::Difficulty)n);
253 
254 
255     fgets(s, 1023, fd);
256     char r;
257     if (sscanf(s, "reverse: %c", &r) != 1)
258         Log::fatal("History", "Could not read reverse information: '%s'", s);
259     RaceManager::get()->setReverseTrack(r == 'y');
260 
261     fgets(s, 1023, fd);
262     if(sscanf(s, "track: %1023s",s1)!=1)
263         Log::warn("History", "Track not found in history file.");
264     RaceManager::get()->setTrack(s1);
265     // This value doesn't really matter, but should be defined, otherwise
266     // the racing phase can switch to 'ending'
267     RaceManager::get()->setNumLaps(100);
268 
269     for(unsigned int i=0; i<num_karts; i++)
270     {
271         fgets(s, 1023, fd);
272         if(sscanf(s, "model %d: %1023s",&n, s1) != 2)
273             Log::fatal("History", "No model information for kart %d found.", i);
274         m_kart_ident.push_back(s1);
275         if(i<RaceManager::get()->getNumPlayers() && !m_online_history_replay)
276         {
277             RaceManager::get()->setPlayerKart(i, s1);
278         }
279     }   // for i<nKarts
280     // FIXME: The model information is currently ignored
281 
282     fgets(s, 1023, fd);
283     int count;
284     if(sscanf(s,"count: %d",&count)!=1)
285         Log::fatal("History", "Number of records not found in history file.");
286 
287     allocateMemory(count);
288     m_event_index = 0;
289 
290     // We need to disable the rewind manager here (otherwise setting the
291     // KartControl data would access the rewind manager).
292     bool rewind_manager_was_enabled = RewindManager::isEnabled();
293     RewindManager::setEnable(false);
294 
295     for (int i=0; i<count; i++)
296     {
297         fgets(s, 1023, fd);
298         InputEvent &ie = m_all_input_events[i];
299         int action = 0;
300         if (sscanf(s, "%d %d %d %d\n", &ie.m_world_ticks, &ie.m_kart_index,
301             &action, &ie.m_value) != 4)
302         {
303             Log::warn("History", "Problems reading event: '%s'", s);
304         }
305         ie.m_action = (PlayerAction)action;
306     }   // for i
307     RewindManager::setEnable(rewind_manager_was_enabled);
308 
309     fclose(fd);
310 }   // Load
311 
312