Merge lp:~widelands-dev/widelands/remove-record into lp:widelands

Proposed by Hans Joachim Desserud
Status: Merged
Merged at revision: 6871
Proposed branch: lp:~widelands-dev/widelands/remove-record
Merge into: lp:widelands
Diff against target: 1174 lines (+42/-985)
7 files modified
src/helper.h (+0/-16)
src/journal.cc (+0/-484)
src/journal.h (+0/-137)
src/journal_exceptions.cc (+0/-59)
src/journal_exceptions.h (+0/-90)
src/wlapplication.cc (+41/-195)
src/wlapplication.h (+1/-4)
To merge this branch: bzr merge lp:~widelands-dev/widelands/remove-record
Reviewer Review Type Date Requested Status
Hans Joachim Desserud Approve
SirVer Approve
Review via email: mp+210496@code.launchpad.net

Description of the change

Like we talked about back when updating/tweaking the readme, I've removed the --record and --playback options since they weren't in use.

I started out following the methods called by the option when running Widelands, but ended up removing all of journal and journal_exception when I discovered it wasn't used for anything else. I was also able to remove a helper function which wasn't used elsewhere.

A couple of places has been marked FIXME to get some feedback on them.

To post a comment you must log in.
Revision history for this message
SirVer (sirver) wrote :

looks good to me. I added one revision adressing all the FIXMEs. hjd, if you are happy with my changes we can merge this imho.

review: Approve
Revision history for this message
Hans Joachim Desserud (hjd) wrote :

Nice, let's merge this then. :)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/helper.h'
--- src/helper.h 2013-07-26 19:16:51 +0000
+++ src/helper.h 2014-03-11 20:49:20 +0000
@@ -135,22 +135,6 @@
135 return x;135 return x;
136}136}
137137
138/* Convert any sstream-compatible type to std::string
139 *
140 * \note In a just world, this would be implemented with gnu::autosprintf. But
141 * many distributions don't carry that lib despite the fact that it is part of
142 * glibc.
143 *
144 * \see http://www.experts-exchange.com/Programming/
145 * Programming_Languages/Cplusplus/Q_20670737.html
146 * \author AssafLavie on http://www.experts-exchange.com
147 */
148template<typename T> std::string toString(const T & x) {
149 std::ostringstream oss;
150 oss << x;
151 return oss.str();
152}
153
154std::vector<std::string> split_string138std::vector<std::string> split_string
155 (const std::string &, char const * separators);139 (const std::string &, char const * separators);
156void remove_spaces(std::string &);140void remove_spaces(std::string &);
157141
=== removed file 'src/journal.cc'
--- src/journal.cc 2013-07-26 19:16:51 +0000
+++ src/journal.cc 1970-01-01 00:00:00 +0000
@@ -1,484 +0,0 @@
1/*
2 * Copyright (C) 2006-2009 by the Widelands Development Team
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20#include "journal.h"
21
22#include <cassert>
23
24#include "io/filesystem/filesystem.h"
25#include "log.h"
26#include "machdep.h"
27
28/**
29 * Write a signed 8bit value to the recording file.
30 * \param v The character to be written
31 */
32void Journal::write(int8_t const v) {
33 m_recordstream.write(reinterpret_cast<const char *>(&v), sizeof(v));
34}
35
36/// \overload
37void Journal::write(uint8_t const v) {
38 m_recordstream.write(reinterpret_cast<const char *>(&v), sizeof(v));
39}
40
41/// \overload
42void Journal::write(int16_t v) {
43 v = Little16(v);
44 m_recordstream.write(reinterpret_cast<const char *>(&v), sizeof(v));
45}
46/// \overload
47void Journal::write(uint16_t v) {
48 v = Little16(v);
49 m_recordstream.write(reinterpret_cast<const char *>(&v), sizeof(v));
50}
51
52/// \overload
53void Journal::write(int32_t v) {
54 v = Little32(v);
55 m_recordstream.write(reinterpret_cast<const char *>(&v), sizeof(v));
56}
57
58/// \overload
59void Journal::write(uint32_t v) {
60 v = Little32(v);
61 m_recordstream.write(reinterpret_cast<const char *>(&v), sizeof(v));
62}
63
64/// \overload
65/// SDLKey is an enum, and enums are implemented as int32_t. Consequently,
66/// SDLKey changes size on 64bit machines :-(
67/// So we force it to be 32bit, discarding the higher 32 bits (hopefully no-one
68/// will have so many keys).
69///
70/// On 32bit systems, it does not matter whether this method or
71/// \ref write(Uint32 v) actually gets used.
72///
73/// \sa write(SDLMod v)
74/// \sa read(SDLMod &v)
75void Journal::write(SDLKey v)
76{
77 write(static_cast<uint32_t>(v));
78}
79
80/**
81 * \overload
82 * \sa write(SDLKey v)
83 */
84void Journal::write(SDLMod v)
85{
86 write(static_cast<uint32_t>(v));
87}
88
89/**
90 * Write a signed char value to the recording file.
91 * \param v Reference where the read character will be stored.
92 */
93void Journal::read (int8_t & v)
94{
95 m_playbackstream.read(reinterpret_cast<char *>(&v), sizeof(uint8_t));
96}
97
98/**
99 * \overload
100 */
101void Journal::read(uint8_t & v)
102{
103 m_playbackstream.read(reinterpret_cast<char *>(&v), sizeof(uint8_t));
104}
105
106/**
107 * \overload
108 */
109void Journal::read (int16_t & v) {
110 m_playbackstream.read(reinterpret_cast<char *>(&v), sizeof(int16_t));
111 v = Little16(v);
112}
113
114/**
115 * \overload
116 */
117void Journal::read(uint16_t & v) {
118 m_playbackstream.read(reinterpret_cast<char *>(&v), sizeof(uint16_t));
119 v = Little16(v);
120}
121
122/**
123 * \overload
124 */
125void Journal::read (int32_t & v) {
126 m_playbackstream.read(reinterpret_cast<char *>(&v), sizeof(int32_t));
127 v = Little32(v);
128}
129
130/**
131 * \overload
132 */
133void Journal::read(uint32_t & v) {
134 m_playbackstream.read(reinterpret_cast<char *>(&v), sizeof(uint32_t));
135 v = Little32(v);
136}
137
138/**
139 * \overload
140 * \sa read(SDLKey v)
141 */
142void Journal::read(SDLKey & v)
143{
144 uint32_t x;
145 read(x);
146 v = static_cast<SDLKey>(x);
147}
148
149/**
150 * \overload
151 * \sa read(SDLKey v)
152 */
153void Journal::read(SDLMod & v)
154{
155 uint32_t x;
156 read(x);
157 v = static_cast<SDLMod>(x);
158}
159
160/**
161 * \todo Document me
162 */
163void Journal::ensure_code(uint8_t code)
164{
165 uint8_t filecode;
166
167 read(filecode);
168 if (filecode != code) {
169 throw BadRecord_error(m_playbackname, filecode, code);
170 }
171}
172
173/**
174 * Standard ctor
175 */
176Journal::Journal()
177:
178m_recordname(""), m_playbackname(""),
179m_record(false), m_playback(false)
180{
181 m_recordstream.exceptions
182 (std::ifstream::eofbit | std::ifstream::failbit | std::ifstream::badbit);
183
184 m_playbackstream.exceptions
185 (std::ifstream::eofbit | std::ifstream::failbit | std::ifstream::badbit);
186}
187
188/**
189 * Close any open journal files
190 */
191Journal::~Journal()
192{
193 stop_recording();
194 stop_playback();
195}
196
197/**
198 * Start recording events handed to us
199 * \param filename File the events should be written to
200 * \todo set the filename somewhere else
201 */
202void Journal::start_recording(const std::string & filename)
203{
204 assert(!m_recordstream.is_open());
205
206 //TODO: m_recordname = FileSystem::FS_CanonicalizeName(filename);
207 m_recordname = filename;
208 if (m_recordname.empty())
209 assert(false); //TODO: barf in a controlled way
210
211 try {
212 m_recordstream.open
213 (m_recordname.c_str(), std::ios::binary|std::ios::trunc);
214 write(RFC_MAGIC);
215 m_recordstream << std::flush;
216 m_record = true;
217 log("Recording into %s\n", m_recordname.c_str());
218 }
219 catch (std::ofstream::failure &) {
220 //TODO: use exception mask to find out what happened
221 //TODO: there should be a messagebox to tell the user.
222 log
223 ("Problem while opening record file %s for writing.\n",
224 m_recordname.c_str());
225 stop_recording();
226 throw Journalfile_error(m_recordname);
227 }
228}
229
230/**
231 * Stop recording events.
232 * It's safe to call this even if recording has not been
233 * started yet.
234 */
235void Journal::stop_recording()
236{
237 m_record = false;
238
239 if (m_recordstream.is_open()) {
240 m_recordstream<<std::flush;
241 m_recordstream.close();
242 }
243}
244
245/**
246 * Start playing back events
247 * \param filename File to get events from
248 * \todo set the filename somewhere else
249 */
250void Journal::start_playback(const std::string & filename)
251{
252 assert(!m_playbackstream.is_open());
253
254 //TODO: m_playbackname = FileSystem::FS_CanonicalizeName(filename);
255 m_playbackname = filename;
256 if (m_playbackname.empty())
257 assert(false); //TODO: barf in a controlled way
258
259 try {
260 uint32_t magic;
261
262 m_playbackstream.open(m_playbackname.c_str(), std::ios::binary);
263 read(magic);
264 if (magic != RFC_MAGIC)
265 throw BadMagic_error(m_playbackname);
266 m_playback = true;
267 log("Playing back from %s\n", m_playbackname.c_str());
268 }
269 catch (std::ifstream::failure &) {
270 //TODO: use exception mask to find out what happened
271 //TODO: there should be a messagebox to tell the user.
272 log
273 ("ERROR: problem while opening playback file for reading. Playback "
274 "deactivated.\n");
275 stop_playback();
276 throw Journalfile_error(m_recordname);
277 }
278}
279
280/**
281 * Stop playing back events.
282 * It's safe to call this even if playback has not been
283 * started yet.
284 */
285void Journal::stop_playback()
286{
287 m_playback = false;
288
289 if (m_playbackstream.is_open()) {
290 m_playbackstream.close();
291 }
292}
293
294/**
295 * Record an event into the playback file. This entails serializing the
296 * event and writing it out.
297 *
298 * \param e The event to be recorded
299 */
300void Journal::record_event(const SDL_Event & e)
301{
302 if (!m_record)
303 return;
304
305 try {
306 //Note: the following lines are *inside* the switch on purpose:
307 // write(RFC_EVENT);
308 // m_recordstream<<std::flush;
309 //If they were outside, they'd get executed on every mainloop
310 //iteration, which would yield a) huge files and b) lots of
311 //completely unnecessary overhad.
312 switch (e.type) {
313 case SDL_KEYDOWN:
314 write(static_cast<uint8_t>(RFC_EVENT));
315 write(static_cast<uint8_t>(RFC_KEYDOWN));
316 write(e.key.keysym.mod);
317 write(e.key.keysym.sym);
318 write(e.key.keysym.unicode);
319 m_recordstream << std::flush;
320 break;
321 case SDL_KEYUP:
322 write(static_cast<uint8_t>(RFC_EVENT));
323 write(static_cast<uint8_t>(RFC_KEYUP));
324 write(e.key.keysym.mod);
325 write(e.key.keysym.sym);
326 write(e.key.keysym.unicode);
327 m_recordstream << std::flush;
328 break;
329 case SDL_MOUSEBUTTONDOWN:
330 write(static_cast<uint8_t>(RFC_EVENT));
331 write(static_cast<uint8_t>(RFC_MOUSEBUTTONDOWN));
332 write(e.button.button);
333 write(e.button.x);
334 write(e.button.y);
335 write(e.button.state);
336 m_recordstream << std::flush;
337 break;
338 case SDL_MOUSEBUTTONUP:
339 write(static_cast<uint8_t>(RFC_EVENT));
340 write(static_cast<uint8_t>(RFC_MOUSEBUTTONUP));
341 write(e.button.button);
342 write(e.button.x);
343 write(e.button.y);
344 write(e.button.state);
345 m_recordstream << std::flush;
346 break;
347 case SDL_MOUSEMOTION:
348 write(static_cast<uint8_t>(RFC_EVENT));
349 write(static_cast<uint8_t>(RFC_MOUSEMOTION));
350 write(e.motion.state);
351 write(e.motion.x);
352 write(e.motion.y);
353 write(e.motion.xrel);
354 write(e.motion.yrel);
355 m_recordstream << std::flush;
356 break;
357 case SDL_QUIT:
358 write(static_cast<uint8_t>(RFC_EVENT));
359 write(static_cast<uint8_t>(RFC_QUIT));
360 m_recordstream << std::flush;
361 break;
362 default:
363 // can't really do anything useful with this event
364 break;
365 }
366 }
367 catch (const std::ofstream::failure &) {
368 //TODO: use exception mask to find out what happened
369 //TODO: there should be a messagebox to tell the user.
370 log("Failed to write to record file. Recording deactivated.\n");
371 stop_recording();
372 throw Journalfile_error(m_recordname);
373 }
374}
375
376/**
377 * Get an event from the playback file. This entails creating an empty
378 * event with sensible default values (not all parameters get recorded)
379 * and deserializing the event record.
380 *
381 * \param e The event being returned
382 */
383bool Journal::read_event(SDL_Event & e)
384{
385 if (!m_playback)
386 return false;
387
388 bool haveevent = false;
389
390 try {
391 uint8_t recordtype;
392 read(recordtype);
393 switch (recordtype) {
394 case RFC_EVENT:
395 uint8_t eventtype;
396 read(eventtype);
397 switch (eventtype) {
398 case RFC_KEYDOWN:
399 e.type = SDL_KEYDOWN;
400 read(e.key.keysym.mod);
401 read(e.key.keysym.sym);
402 read(e.key.keysym.unicode);
403 break;
404 case RFC_KEYUP:
405 e.type = SDL_KEYUP;
406 read(e.key.keysym.mod);
407 read(e.key.keysym.sym);
408 read(e.key.keysym.unicode);
409 break;
410 case RFC_MOUSEBUTTONDOWN:
411 e.type = SDL_MOUSEBUTTONDOWN;
412 read(e.button.button);
413 read(e.button.x);
414 read(e.button.y);
415 read(e.button.state);
416 break;
417 case RFC_MOUSEBUTTONUP:
418 e.type = SDL_MOUSEBUTTONUP;
419 read(e.button.button);
420 read(e.button.x);
421 read(e.button.y);
422 read(e.button.state);
423 break;
424 case RFC_MOUSEMOTION:
425 e.type = SDL_MOUSEMOTION;
426 read(e.motion.state);
427 read(e.motion.x);
428 read(e.motion.y);
429 read(e.motion.xrel);
430 read(e.motion.yrel);
431 break;
432 case RFC_QUIT:
433 e.type = SDL_QUIT;
434 break;
435 default:
436 throw BadEvent_error(m_playbackname, eventtype);
437 }
438
439 haveevent = true;
440 break;
441 case RFC_ENDEVENTS:
442 //Do nothing
443 break;
444 default:
445 throw BadRecord_error(m_playbackname, recordtype, RFC_INVALID);
446 break;
447 }
448 } catch (const std::ifstream::failure &) {
449 //TODO: use exception mask to find out what happened
450 //TODO: there should be a messagebox to tell the user.
451 log("Failed to read from journal file. Playback deactivated.\n");
452 stop_playback();
453 throw Journalfile_error(m_playbackname);
454 }
455
456 return haveevent;
457}
458
459/**
460 * Do the right thing with timestamps.
461 * All timestamps handled with \ref WLApplication::get_time() pass through here.
462 * If necessary, they will be recorded. On playback, they will be modified to
463 * show the recorded time instead of the current time.
464 */
465void Journal::timestamp_handler(uint32_t & stamp)
466{
467 if (m_record) {
468 write(static_cast<uint8_t>(RFC_GETTIME));
469 write(stamp);
470 }
471
472 if (m_playback) {
473 ensure_code(static_cast<uint8_t>(RFC_GETTIME));
474 read(stamp);
475 }
476}
477
478/**
479 * \todo document me
480 */
481void Journal::set_idle_mark()
482{
483 write(static_cast<uint8_t>(RFC_ENDEVENTS));
484}
4850
=== removed file 'src/journal.h'
--- src/journal.h 2013-07-26 19:16:51 +0000
+++ src/journal.h 1970-01-01 00:00:00 +0000
@@ -1,137 +0,0 @@
1/*
2 * Copyright (C) 2006-2009 by the Widelands Development Team
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20#ifndef JOURNAL_H
21#define JOURNAL_H
22
23#include <cstring>
24#include <fstream>
25#include <string>
26
27#include <SDL_events.h>
28
29#include "journal_exceptions.h"
30
31/**
32 * Journal encapsulates all operations that are necessary for recording and
33 * playing back a session. On it's interface, it deals with SDL_Events that
34 * might (or might not) be recorded/played back. Whether a recording / playback
35 * is actually being performed is internal to Journal.
36 *
37 * \note If you are hacking this class, throw a Journalfile_exception only
38 * and always if there is a nonrecoverable error and you have already dealt with
39 * it.
40 *
41 * \todo The idea of writing enums into a file is bad: enums are int32_t and
42 * int32_t varies in size (typ. 32/64bit). Our own codes only need 8bit, so we
43 * force IO down to this value. The same happens with keyboard events at
44 * 32 bits. Cutting off bits is not a good solution, but in this case it'll do
45 * until a better way comes along.
46 */
47struct Journal {
48 /// change this and I will ensure your death will be a most unpleasant one
49 static uint32_t const RFC_MAGIC = 0x0ACAD100;
50
51 /**
52 * Record file codes
53 * It should be possible to use record files across different platforms.
54 * However, 64 bit platforms are currently not supported.
55 */
56 enum rfccode {
57 RFC_GETTIME = 0x01,
58 RFC_EVENT = 0x02,
59 RFC_ENDEVENTS = 0x03,
60
61 RFC_KEYDOWN = 0x10,
62 RFC_KEYUP = 0x11,
63 RFC_MOUSEBUTTONDOWN = 0x12,
64 RFC_MOUSEBUTTONUP = 0x13,
65 RFC_MOUSEMOTION = 0x14,
66 RFC_QUIT = 0x15,
67 RFC_INVALID = 0xff
68 };
69
70public:
71 Journal();
72 ~Journal();
73
74 void start_recording(const std::string & filename = "widelands.jnl");
75 void stop_recording();
76 ///True if events are being recorded
77 bool is_recording() const {return m_record;}
78
79 void start_playback (const std::string & filename = "widelands.jnl");
80 void stop_playback();
81 ///True if events are being played back
82 bool is_playingback() const {return m_playback;}
83
84 void record_event(const SDL_Event &);
85 bool read_event(SDL_Event &);
86
87 void timestamp_handler(uint32_t & stamp);
88 void set_idle_mark();
89
90protected:
91 /**
92 * Returns the position in the playback file
93 * \return byte offset into the playback file, used with file reading
94 */
95 int32_t get_playback_offset() {return m_playbackstream.tellg();}
96
97 void write(int8_t);
98 void write(uint8_t);
99 void write(int16_t);
100 void write(uint16_t);
101 void write(int32_t);
102 void write(uint32_t);
103 void write(SDLKey);
104 void write(SDLMod);
105
106 void read(int8_t &);
107 void read(uint8_t &);
108 void read(int16_t &);
109 void read(uint16_t &);
110 void read(int32_t &);
111 void read(uint32_t &);
112 void read(SDLKey &);
113 void read(SDLMod &);
114 void ensure_code(uint8_t code);
115
116 ///The recording file's name.
117 ///\note This does \e not go through the layered filesystem on purpose!
118 std::string m_recordname;
119
120 ///The playback file's name.
121 ///\note This does \e not go through the layered filesystem on purpose!
122 std::string m_playbackname;
123
124 ///The file events are being recorded to
125 std::ofstream m_recordstream;
126
127 ///The file events are being played back from
128 std::ifstream m_playbackstream;
129
130 ///True if events are being recorded
131 bool m_record;
132
133 ///True if events are being played back
134 bool m_playback;
135};
136
137#endif
1380
=== removed file 'src/journal_exceptions.cc'
--- src/journal_exceptions.cc 2013-09-23 18:47:02 +0000
+++ src/journal_exceptions.cc 1970-01-01 00:00:00 +0000
@@ -1,59 +0,0 @@
1/*
2 * Copyright (C) 2006, 2008 by the Widelands Development Team
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20#include "journal_exceptions.h"
21
22#include "helper.h"
23
24Journalfile_error::Journalfile_error(const std::string & _filename)
25: std::runtime_error("Problem with journal file."), filename(_filename)
26{
27 text = "Problem with journal file " + _filename;
28}
29
30///\todo Say _which_ magic number was found and which was expected
31BadMagic_error::BadMagic_error(const std::string & _filename)
32: Journalfile_error(_filename)
33{
34 text = "Journal file " + _filename + " starts with bad magic number";
35}
36
37BadRecord_error::BadRecord_error
38 (const std::string & _filename,
39 uint8_t const _code,
40 uint8_t const _expectedcode)
41: Journalfile_error(_filename), offset(0), code(_code), expectedcode(_expectedcode)
42{
43 text = "Journal file ";
44 text += _filename;
45 text += " contains record with type ";
46 text += toString(static_cast<int>(_code));
47 text += " instead of the expected type ";
48 text += toString(static_cast<int>(_expectedcode));
49}
50
51BadEvent_error::BadEvent_error
52 (const std::string & _filename, uint8_t const _type)
53: Journalfile_error(_filename), offset(0), type(_type)
54{
55 text = "Journal file '";
56 text += _filename;
57 text += "' contains record with unknown event type ";
58 text += toString(_type);
59}
600
=== removed file 'src/journal_exceptions.h'
--- src/journal_exceptions.h 2014-02-22 18:04:02 +0000
+++ src/journal_exceptions.h 1970-01-01 00:00:00 +0000
@@ -1,90 +0,0 @@
1/*
2 * Copyright (C) 2006, 2008-2009 by the Widelands Development Team
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20#ifndef JOURNAL_EXCEPTIONS_H
21#define JOURNAL_EXCEPTIONS_H
22
23#include <stdexcept>
24#include <string>
25
26#include <stdint.h>
27
28///
29/// Thrown for IO-errors occurring with a journal file (unable to open file
30/// for any reason, out of space, etc.) that a) are unrecoverable and b)
31/// have already been dealt with.
32///
33/// This is a purely informational exception. Do not throw it unless it can
34/// safely be ignored.
35///
36/// \todo add offset into journal file if applicable
37/// \todo Rework as proposed by Erik, see filesystem_exceptions.h. Before that:
38/// Replace with File*_error where appropriate, migrate from runtime_error to
39/// logic_error (?)
40struct Journalfile_error : public std::runtime_error {
41 explicit Journalfile_error(const std::string & filename);
42 virtual ~Journalfile_error() throw () {}
43
44 virtual char const * what() const throw () override {return text.c_str();}
45
46 std::string text;
47 std::string filename;
48};
49
50/**
51 * Thrown if the journal file contains a bad magic number
52 * \todo add offset into journal file
53 */
54struct BadMagic_error : public Journalfile_error {
55 explicit BadMagic_error(const std::string & filename);
56 virtual ~BadMagic_error() throw () {}
57};
58
59/**
60 * Thrown if the journal file contains a record with an unknown type number
61 * \todo add offset into journal file
62 */
63struct BadRecord_error : public Journalfile_error {
64 explicit BadRecord_error
65 (const std::string & filename,
66 const uint8_t code,
67 const uint8_t expectedcode)
68 ;
69 virtual ~BadRecord_error() throw () {}
70
71 std::streamoff offset;
72 uint8_t code;
73 uint8_t expectedcode;
74};
75
76/**
77 * Thrown if the journal file contains an event record with an unknown
78 * event type
79 * \todo add offset into journal file
80 */
81struct BadEvent_error : public Journalfile_error {
82 explicit BadEvent_error(const std::string & filename, uint8_t const type)
83 ;
84 virtual ~BadEvent_error() throw () {}
85
86 std::streamoff offset;
87 uint8_t type;
88};
89
90#endif
910
=== modified file 'src/wlapplication.cc'
--- src/wlapplication.cc 2014-03-09 10:28:39 +0000
+++ src/wlapplication.cc 2014-03-11 20:49:20 +0000
@@ -48,7 +48,6 @@
48#include "io/dedicated_log.h"48#include "io/dedicated_log.h"
49#include "io/filesystem/disk_filesystem.h"49#include "io/filesystem/disk_filesystem.h"
50#include "io/filesystem/layered_filesystem.h"50#include "io/filesystem/layered_filesystem.h"
51#include "journal.h"
52#include "log.h"51#include "log.h"
53#include "logic/game.h"52#include "logic/game.h"
54#include "logic/game_data_error.h"53#include "logic/game_data_error.h"
@@ -248,7 +247,6 @@
248WLApplication::WLApplication(int const argc, char const * const * const argv) :247WLApplication::WLApplication(int const argc, char const * const * const argv) :
249m_commandline (std::map<std::string, std::string>()),248m_commandline (std::map<std::string, std::string>()),
250m_game_type (NONE),249m_game_type (NONE),
251journal (nullptr),
252m_mouse_swapped (false),250m_mouse_swapped (false),
253m_faking_middle_mouse_button(false),251m_faking_middle_mouse_button(false),
254m_mouse_position (0, 0),252m_mouse_position (0, 0),
@@ -480,158 +478,53 @@
480478
481/**479/**
482 * Get an event from the SDL queue, just like SDL_PollEvent.480 * Get an event from the SDL queue, just like SDL_PollEvent.
483 * Perform the meat of playback/record stuff when needed.
484 *
485 * Throttle is a hack to stop record files from getting extremely huge.
486 * If it is set to true, we will idle loop if we can't get an SDL_Event
487 * returned immediately if we're recording. If there is no user input,
488 * the actual mainloop will be throttled to 100fps.
489 *481 *
490 * \param ev the retrieved event will be put here482 * \param ev the retrieved event will be put here
491 * \param throttle Limit recording to 100fps max (not the event loop itself!)
492 *483 *
493 * \return true if an event was returned inside ev, false otherwise484 * \return true if an event was returned inside ev, false otherwise
494 *
495 * \todo Catch Journalfile_error
496 */485 */
497bool WLApplication::poll_event(SDL_Event & ev, bool const throttle) {486bool WLApplication::poll_event(SDL_Event& ev) {
498 bool haveevent = false;487 if (!SDL_PollEvent(&ev)) {
499488 return false;
500restart:489 }
501 //inject synthesized events into the event queue when playing back490
502 if (journal->is_playingback()) {491 // We edit mouse motion events in here, so that
503 try {492 // differences caused by GrabInput or mouse speed
504 haveevent = journal->read_event(ev);493 // settings are invisible to the rest of the code
505 } catch (const Journalfile_error & e) {494 switch (ev.type) {
506 // An error might occur here when playing back a file that495 case SDL_MOUSEMOTION:
507 // was not finalized due to a crash etc.496 ev.motion.xrel += m_mouse_compensate_warp.x;
508 // Since playbacks are intended precisely for debugging such497 ev.motion.yrel += m_mouse_compensate_warp.y;
509 // crashes, we must ignore the error and continue.498 m_mouse_compensate_warp = Point(0, 0);
510 log("JOURNAL: read error, continue without playback: %s\n", e.what());499
511 journal->stop_playback();500 if (m_mouse_locked) {
512 }501 warp_mouse(m_mouse_position);
513 } else {502
514 haveevent = SDL_PollEvent(&ev);503 ev.motion.x = m_mouse_position.x;
515504 ev.motion.y = m_mouse_position.y;
516 if (haveevent) {505 }
517 // We edit mouse motion events in here, so that506 break;
518 // differences caused by GrabInput or mouse speed507
519 // settings are invisible to the rest of the code508 case SDL_USEREVENT:
520 switch (ev.type) {509 if (ev.user.code == CHANGE_MUSIC)
521 case SDL_MOUSEMOTION:510 g_sound_handler.change_music();
522 ev.motion.xrel += m_mouse_compensate_warp.x;511 break;
523 ev.motion.yrel += m_mouse_compensate_warp.y;512
524 m_mouse_compensate_warp = Point(0, 0);513 case SDL_VIDEOEXPOSE:
525514 // log ("SDL Video Window expose event: %i\n", ev.expose.type);
526 if (m_mouse_locked) {515 g_gr->update_fullscreen();
527 warp_mouse(m_mouse_position);516 break;
528517 }
529 ev.motion.x = m_mouse_position.x;518 return true;
530 ev.motion.y = m_mouse_position.y;
531 }
532
533 break;
534 case SDL_USEREVENT:
535 if (ev.user.code == CHANGE_MUSIC)
536 g_sound_handler.change_music();
537
538 break;
539 case SDL_VIDEOEXPOSE:
540 //log ("SDL Video Window expose event: %i\n", ev.expose.type);
541 g_gr->update_fullscreen();
542 break;
543 default:;
544 }
545 }
546 }
547
548 // log all events into the journal file
549 if (journal->is_recording()) {
550 if (haveevent)
551 journal->record_event(ev);
552 else if (throttle && journal->is_playingback()) {
553 // Implement the throttle to avoid very quick inner mainloops when
554 // recoding a session
555 static int32_t lastthrottle = 0;
556 int32_t const time = SDL_GetTicks();
557
558 if (time - lastthrottle < 10)
559 goto restart;
560
561 lastthrottle = time;
562 }
563
564 journal->set_idle_mark();
565 } else if (haveevent) {
566 // Eliminate any unhandled events to make sure that record and playback
567 // are _really_ the same. Yes I know, it's overly paranoid but hey...
568 switch (ev.type) {
569 case SDL_KEYDOWN:
570 case SDL_KEYUP:
571 case SDL_MOUSEBUTTONDOWN:
572 case SDL_MOUSEBUTTONUP:
573 case SDL_MOUSEMOTION:
574 case SDL_QUIT:
575 break;
576 default:
577 goto restart;
578 }
579 }
580
581 return haveevent;
582}519}
583520
584
585/**521/**
586 * Pump the event queue, get packets from the network, etc...522 * Pump the event queue, get packets from the network, etc...
587 */523 */
588void WLApplication::handle_input(InputCallback const * cb)524void WLApplication::handle_input(InputCallback const * cb)
589{525{
590 bool gotevents = false;526 SDL_Event ev;
591 SDL_Event ev; // Valgrind says:527 while (poll_event(ev)) {
592 // Conditional jump or move depends on uninitialised value(s)
593 // at 0x407EEDA: (within /usr/lib/libSDL-1.2.so.0.11.0)
594 // by 0x407F78F: (within /usr/lib/libSDL-1.2.so.0.11.0)
595 // by 0x404FB12: SDL_PumpEvents (in /usr/lib/libSDL-1.2.so.0.11.0)
596 // by 0x404FFC3: SDL_PollEvent (in /usr/lib/libSDL-1.2.so.0.11.0)
597 // by 0x8252545: WLApplication::poll_event(SDL_Event*, bool)
598 // (wlapplication.cc:309)
599 // by 0x8252EB6: WLApplication::handle_input(InputCallback const*)
600 // (wlapplication.cc:459) by 0x828B56E: UI::Panel::run() (ui_panel.cc:148)
601 // by 0x8252FAB: WLApplication::run() (wlapplication.cc:212)
602 // by 0x81427A6: main (main.cc:39)
603
604 // We need to empty the SDL message queue always, even in playback mode
605 // In playback mode, only F10 for premature exiting works
606 if (journal->is_playingback()) {
607 while (SDL_PollEvent(&ev)) {
608 switch (ev.type) {
609 case SDL_KEYDOWN:
610 // get out of here quickly, overriding playback;
611 // since this is the only key event that works, we don't guard
612 // it by requiring Ctrl to be pressed.
613 if (ev.key.keysym.sym == SDLK_F10)
614 m_should_die = true;
615 break;
616 case SDL_QUIT:
617 m_should_die = true;
618 break;
619 default:;
620 }
621 }
622 }
623
624 // Usual event queue
625 while (poll_event(ev, !gotevents)) {
626
627 gotevents = true;
628
629 // CAREFUL: Record files do not save the entire SDL_Event structure.
630 // Therefore, playbacks are incomplete. When you change the following
631 // code so that it uses previously unused fields in SDL_Event,
632 // please also take a look at Journal::read_event and
633 // Journal::record_event
634
635 switch (ev.type) {528 switch (ev.type) {
636 case SDL_KEYDOWN:529 case SDL_KEYDOWN:
637 case SDL_KEYUP:530 case SDL_KEYUP:
@@ -747,9 +640,6 @@
747int32_t WLApplication::get_time() {640int32_t WLApplication::get_time() {
748 uint32_t time = SDL_GetTicks();641 uint32_t time = SDL_GetTicks();
749642
750 // might change the time when playing back!
751 journal->timestamp_handler(time);
752
753 return time;643 return time;
754}644}
755645
@@ -758,20 +648,17 @@
758/// SDL_WarpMouse() *will* create a mousemotion event, which we do not want. As648/// SDL_WarpMouse() *will* create a mousemotion event, which we do not want. As
759/// a workaround, we store the delta in m_mouse_compensate_warp and use that to649/// a workaround, we store the delta in m_mouse_compensate_warp and use that to
760/// eliminate the motion event in poll_event()650/// eliminate the motion event in poll_event()
761/// \todo Should this method have to care about playback at all???
762///651///
763/// \param position The new mouse position652/// \param position The new mouse position
764void WLApplication::warp_mouse(const Point position)653void WLApplication::warp_mouse(const Point position)
765{654{
766 m_mouse_position = position;655 m_mouse_position = position;
767656
768 if (not journal->is_playingback()) { // don't warp anything during playback657 Point cur_position;
769 Point cur_position;658 SDL_GetMouseState(&cur_position.x, &cur_position.y);
770 SDL_GetMouseState(&cur_position.x, &cur_position.y);659 if (cur_position != position) {
771 if (cur_position != position) {660 m_mouse_compensate_warp += cur_position - position;
772 m_mouse_compensate_warp += cur_position - position;661 SDL_WarpMouse(position.x, position.y);
773 SDL_WarpMouse(position.x, position.y);
774 }
775 }662 }
776}663}
777664
@@ -786,9 +673,6 @@
786 */673 */
787void WLApplication::set_input_grab(bool grab)674void WLApplication::set_input_grab(bool grab)
788{675{
789 if (journal->is_playingback())
790 return; // ignore in playback mode
791
792 if (grab) {676 if (grab) {
793 SDL_WM_GrabInput(SDL_GRAB_ON);677 SDL_WM_GrabInput(SDL_GRAB_ON);
794 } else {678 } else {
@@ -842,10 +726,6 @@
842 */726 */
843bool WLApplication::init_settings() {727bool WLApplication::init_settings() {
844728
845 //create a journal so that handle_commandline_parameters can open the
846 //journal files
847 journal = new Journal();
848
849 //read in the configuration file729 //read in the configuration file
850 g_options.read("config", "global");730 g_options.read("config", "global");
851 Section & s = g_options.pull_section("global");731 Section & s = g_options.pull_section("global");
@@ -927,10 +807,6 @@
927 } catch (...) {807 } catch (...) {
928 log("WARNING: could not save configuration");808 log("WARNING: could not save configuration");
929 }809 }
930
931 assert(journal);
932 delete journal;
933 journal = nullptr;
934}810}
935811
936/**812/**
@@ -1280,34 +1156,6 @@
1280 m_commandline.erase("script");1156 m_commandline.erase("script");
1281 }1157 }
12821158
1283 // TODO(sirver): this framework has not been useful in a long time. Kill it.
1284 if (m_commandline.count("record")) {
1285 if (m_commandline["record"].empty())
1286 throw Parameter_error("ERROR: --record needs a filename!");
1287
1288 try {
1289 journal->start_recording(m_commandline["record"]);
1290 } catch (Journalfile_error & e) {
1291 wout << "Journal file error: " << e.what() << endl;
1292 }
1293
1294 m_commandline.erase("record");
1295 }
1296
1297 if (m_commandline.count("playback")) {
1298 if (m_commandline["playback"].empty())
1299 throw Parameter_error("ERROR: --playback needs a filename!");
1300
1301 try {
1302 journal->start_playback(m_commandline["playback"]);
1303 }
1304 catch (Journalfile_error & e) {
1305 wout << "Journal file error: " << e.what() << endl;
1306 }
1307
1308 m_commandline.erase("playback");
1309 }
1310
1311 //If it hasn't been handled yet it's probably an attempt to1159 //If it hasn't been handled yet it's probably an attempt to
1312 //override a conffile setting1160 //override a conffile setting
1313 //With typos, this will create invalid config settings. They1161 //With typos, this will create invalid config settings. They
@@ -1351,9 +1199,7 @@
1351#ifdef __linux__1199#ifdef __linux__
1352 << _(" Default is ~/.widelands") << "\n"1200 << _(" Default is ~/.widelands") << "\n"
1353#endif1201#endif
1354 << _(" --record=FILENAME Record all events to the given filename for\n"1202 << "\n"
1355 " later playback") << "\n"
1356 << _(" --playback=FILENAME Playback given filename (see --record)") << "\n\n"
1357 << _(" --coredump=[yes|no] Generates a core dump on segfaults instead\n"1203 << _(" --coredump=[yes|no] Generates a core dump on segfaults instead\n"
1358 " of using the SDL") << "\n"1204 " of using the SDL") << "\n"
1359 << _(" --language=[de_DE|sv_SE|...]\n"1205 << _(" --language=[de_DE|sv_SE|...]\n"
13601206
=== modified file 'src/wlapplication.h'
--- src/wlapplication.h 2014-02-22 18:04:02 +0000
+++ src/wlapplication.h 2014-03-11 20:49:20 +0000
@@ -38,7 +38,6 @@
3838
3939
40namespace Widelands {class Game;}40namespace Widelands {class Game;}
41struct Journal;
4241
43///Thrown if a commandline parameter is faulty42///Thrown if a commandline parameter is faulty
44struct Parameter_error : public std::runtime_error {43struct Parameter_error : public std::runtime_error {
@@ -233,7 +232,7 @@
233protected:232protected:
234 WLApplication(int argc, char const * const * argv);233 WLApplication(int argc, char const * const * argv);
235234
236 bool poll_event(SDL_Event &, bool throttle);235 bool poll_event(SDL_Event &);
237236
238 bool init_settings();237 bool init_settings();
239 void init_language();238 void init_language();
@@ -271,8 +270,6 @@
271 std::string m_logfile;270 std::string m_logfile;
272271
273 GameType m_game_type;272 GameType m_game_type;
274 ///the event recorder object
275 Journal * journal;
276273
277 ///True if left and right mouse button should be swapped274 ///True if left and right mouse button should be swapped
278 bool m_mouse_swapped;275 bool m_mouse_swapped;

Subscribers

People subscribed via source and target branches

to status/vote changes: