diff options
Diffstat (limited to 'backends')
-rw-r--r-- | backends/events/default/default-events.cpp | 321 | ||||
-rw-r--r-- | backends/events/default/default-events.h | 44 | ||||
-rw-r--r-- | backends/platform/sdl/sdl.cpp | 6 |
3 files changed, 370 insertions, 1 deletions
diff --git a/backends/events/default/default-events.cpp b/backends/events/default/default-events.cpp index 7730cb7df1..7f484a73d4 100644 --- a/backends/events/default/default-events.cpp +++ b/backends/events/default/default-events.cpp @@ -27,11 +27,69 @@ #include "common/config-manager.h" #include "common/system.h" +#include "common/config-manager.h" #include "backends/events/default/default-events.h" #include "engines/engine.h" #include "gui/message.h" +#define RECORD_SIGNATURE 0x54455354 +#define RECORD_VERSION 1 + +void readRecord(Common::InSaveFile *inFile, uint32 &diff, Common::Event &event) { + diff = inFile->readUint32LE(); + + event.type = (Common::EventType)inFile->readUint32LE(); + + switch(event.type) { + case Common::EVENT_KEYDOWN: + case Common::EVENT_KEYUP: + event.kbd.keycode = (Common::KeyCode)inFile->readSint32LE(); + event.kbd.ascii = inFile->readUint16LE(); + event.kbd.flags = inFile->readByte(); + break; + case Common::EVENT_MOUSEMOVE: + case Common::EVENT_LBUTTONDOWN: + case Common::EVENT_LBUTTONUP: + case Common::EVENT_RBUTTONDOWN: + case Common::EVENT_RBUTTONUP: + case Common::EVENT_WHEELUP: + case Common::EVENT_WHEELDOWN: + event.mouse.x = inFile->readSint16LE(); + event.mouse.y = inFile->readSint16LE(); + break; + default: + break; + } +} + +void writeRecord(Common::OutSaveFile *outFile, uint32 diff, Common::Event &event) { + outFile->writeUint32LE(diff); + + outFile->writeUint32LE((uint32)event.type); + + switch(event.type) { + case Common::EVENT_KEYDOWN: + case Common::EVENT_KEYUP: + outFile->writeSint32LE(event.kbd.keycode); + outFile->writeUint16LE(event.kbd.ascii); + outFile->writeByte(event.kbd.flags); + break; + case Common::EVENT_MOUSEMOVE: + case Common::EVENT_LBUTTONDOWN: + case Common::EVENT_LBUTTONUP: + case Common::EVENT_RBUTTONDOWN: + case Common::EVENT_RBUTTONUP: + case Common::EVENT_WHEELUP: + case Common::EVENT_WHEELDOWN: + outFile->writeSint16LE(event.mouse.x); + outFile->writeSint16LE(event.mouse.y); + break; + default: + break; + } +} + DefaultEventManager::DefaultEventManager(OSystem *boss) : _boss(boss), _buttonState(0), @@ -40,8 +98,252 @@ DefaultEventManager::DefaultEventManager(OSystem *boss) : assert(_boss); + _recordFile = NULL; + _recordTimeFile = NULL; + _playbackFile = NULL; + _playbackTimeFile = NULL; + _timeMutex = _boss->createMutex(); + _recorderMutex = _boss->createMutex(); + + _eventCount = 0; + _lastEventCount = 0; + _lastMillis = 0; + + Common::String recordModeString = ConfMan.get("record_mode"); + if (recordModeString.compareToIgnoreCase("record") == 0) { + _recordMode = kRecorderRecord; + } else { + if (recordModeString.compareToIgnoreCase("playback") == 0) { + _recordMode = kRecorderPlayback; + } else { + _recordMode = kPassthrough; + } + } + + _recordFileName = ConfMan.get("record_file_name"); + if (_recordFileName.empty()) { + _recordFileName = "record.bin"; + } + _recordTempFileName = ConfMan.get("record_temp_file_name"); + if (_recordTempFileName.empty()) { + _recordTempFileName = "record.tmp"; + } + _recordTimeFileName = ConfMan.get("record_time_file_name"); + if (_recordTimeFileName.empty()) { + _recordTimeFileName = "record.time"; + } + // Reset key repeat _currentKeyDown.keycode = 0; + + // recorder stuff + if (_recordMode == kRecorderRecord) { + _recordCount = 0; + _recordTimeCount = 0; + _recordFile = _boss->getSavefileManager()->openForSaving(_recordTempFileName.c_str()); + _recordTimeFile = _boss->getSavefileManager()->openForSaving(_recordTimeFileName.c_str()); + _recordSubtitles = ConfMan.getBool("subtitles"); + } + + uint32 sign; + uint32 version; + uint32 randomSourceCount; + if (_recordMode == kRecorderPlayback) { + _playbackCount = 0; + _playbackTimeCount = 0; + _playbackFile = _boss->getSavefileManager()->openForLoading(_recordFileName.c_str()); + _playbackTimeFile = _boss->getSavefileManager()->openForLoading(_recordTimeFileName.c_str()); + + if (!_playbackFile) { + warning("Cannot open playback file %s. Playback was switched off", _recordFileName.c_str()); + _recordMode = kPassthrough; + } + + if (!_playbackTimeFile) { + warning("Cannot open playback time file %s. Playback was switched off", _recordTimeFileName.c_str()); + _recordMode = kPassthrough; + } + } + + if (_recordMode == kRecorderPlayback) { + sign = _playbackFile->readUint32LE(); + if (sign != RECORD_SIGNATURE) { + error("Unknown record file signature"); + } + version = _playbackFile->readUint32LE(); + + // conf vars + ConfMan.setBool("subtitles", _playbackFile->readByte() != 0); + + _recordCount = _playbackFile->readUint32LE(); + _recordTimeCount = _playbackFile->readUint32LE(); + randomSourceCount = _playbackFile->readUint32LE(); + for (uint i = 0; i < randomSourceCount; ++i) { + RandomSourceRecord rec; + rec.name = ""; + uint32 sLen = _playbackFile->readUint32LE(); + for (uint j = 0; j < sLen; ++j) { + char c = _playbackFile->readSByte(); + rec.name += c; + } + rec.seed = _playbackFile->readUint32LE(); + _randomSourceRecords.push_back(rec); + } + + _hasPlaybackEvent = false; + } +} + +DefaultEventManager::~DefaultEventManager() { + _boss->lockMutex(_timeMutex); + _boss->lockMutex(_recorderMutex); + _recordMode = kPassthrough; + _boss->unlockMutex(_timeMutex); + _boss->unlockMutex(_recorderMutex); + + if (_playbackFile != NULL) { + delete _playbackFile; + } + if (_playbackTimeFile != NULL) { + delete _playbackTimeFile; + } + + if (_recordFile != NULL) { + _recordFile->finalize(); + delete _recordFile; + _recordTimeFile->finalize(); + delete _recordTimeFile; + + _playbackFile = _boss->getSavefileManager()->openForLoading(_recordTempFileName.c_str()); + + _recordFile = _boss->getSavefileManager()->openForSaving(_recordFileName.c_str()); + _recordFile->writeUint32LE(RECORD_SIGNATURE); + _recordFile->writeUint32LE(RECORD_VERSION); + + // conf vars + _recordFile->writeByte(_recordSubtitles ? 1 : 0); + + _recordFile->writeUint32LE(_recordCount); + _recordFile->writeUint32LE(_recordTimeCount); + + _recordFile->writeUint32LE(_randomSourceRecords.size()); + for (uint i = 0; i < _randomSourceRecords.size(); ++i) { + _recordFile->writeUint32LE(_randomSourceRecords[i].name.size()); + _recordFile->writeString(_randomSourceRecords[i].name); + _recordFile->writeUint32LE(_randomSourceRecords[i].seed); + } + + for (uint i = 0; i < _recordCount; ++i) { + uint32 tempDiff; + Common::Event tempEvent; + readRecord(_playbackFile, tempDiff, tempEvent); + writeRecord(_recordFile, tempDiff, tempEvent); + } + + _recordFile->finalize(); + delete _recordFile; + delete _playbackFile; + + //TODO: remove recordTempFileName'ed file + } + _boss->deleteMutex(_timeMutex); + _boss->deleteMutex(_recorderMutex); +} + +bool DefaultEventManager::playback(Common::Event &event) { + + if (!_hasPlaybackEvent) { + if (_recordCount > _playbackCount) { + readRecord(_playbackFile, (uint32&)_playbackDiff, _playbackEvent); + _playbackCount++; + _hasPlaybackEvent = true; + } + } + + if (_hasPlaybackEvent) { + if (_playbackDiff <= (_eventCount - _lastEventCount)) { + switch(_playbackEvent.type) { + case Common::EVENT_MOUSEMOVE: + case Common::EVENT_LBUTTONDOWN: + case Common::EVENT_LBUTTONUP: + case Common::EVENT_RBUTTONDOWN: + case Common::EVENT_RBUTTONUP: + case Common::EVENT_WHEELUP: + case Common::EVENT_WHEELDOWN: + _boss->warpMouse(_playbackEvent.mouse.x, _playbackEvent.mouse.y); + break; + default: + break; + } + event = _playbackEvent; + _hasPlaybackEvent = false; + _lastEventCount = _eventCount; + return true; + } + } + + return false; +} + +void DefaultEventManager::record(Common::Event &event) { + writeRecord(_recordFile, _eventCount - _lastEventCount, event); + + _recordCount++; + _lastEventCount = _eventCount; +} + +void DefaultEventManager::registerRandomSource(Common::RandomSource &rnd, const char *name) { + + if (_recordMode == kRecorderRecord) { + RandomSourceRecord rec; + rec.name = name; + rec.seed = rnd.getSeed(); + _randomSourceRecords.push_back(rec); + } + + if (_recordMode == kRecorderPlayback) { + for (uint i = 0; i < _randomSourceRecords.size(); ++i) { + if (_randomSourceRecords[i].name == name) { + rnd.setSeed(_randomSourceRecords[i].seed); + _randomSourceRecords.remove_at(i); + break; + } + } + } +} + +void DefaultEventManager::processMillis(uint32 &millis) { + uint32 d; + if (_recordMode == kPassthrough) { + return; + } + + _boss->lockMutex(_timeMutex); + if (_recordMode == kRecorderRecord) { + //Simple RLE compression + d = millis - _lastMillis; + if (d >= 0xff) { + _recordTimeFile->writeByte(0xff); + _recordTimeFile->writeUint32LE(d); + } else { + _recordTimeFile->writeByte(d); + } + _recordTimeCount++; + } + + if (_recordMode == kRecorderPlayback) { + if (_recordTimeCount > _playbackTimeCount) { + d = _playbackTimeFile->readByte(); + if (d == 0xff) { + d = _playbackTimeFile->readUint32LE(); + } + millis = _lastMillis + d; + _playbackTimeCount++; + } + } + + _lastMillis = millis; + _boss->unlockMutex(_timeMutex); } bool DefaultEventManager::pollEvent(Common::Event &event) { @@ -50,6 +352,25 @@ bool DefaultEventManager::pollEvent(Common::Event &event) { result = _boss->pollEvent(event); + if (_recordMode != kPassthrough) { + + _boss->lockMutex(_recorderMutex); + _eventCount++; + + if (_recordMode == kRecorderPlayback) { + if (event.type != Common::EVENT_QUIT) { + result = playback(event); + } + } else { + if (_recordMode == kRecorderRecord) { + if (result) { + record(event); + } + } + } + _boss->unlockMutex(_recorderMutex); + } + if (result) { event.synthetic = false; switch (event.type) { diff --git a/backends/events/default/default-events.h b/backends/events/default/default-events.h index e7d70cb152..14fe775d73 100644 --- a/backends/events/default/default-events.h +++ b/backends/events/default/default-events.h @@ -27,6 +27,7 @@ #define BACKEND_EVENTS_DEFAULT_H #include "common/events.h" +#include "common/savefile.h" /* At some point we will remove pollEvent from OSystem and change @@ -47,7 +48,45 @@ class DefaultEventManager : public Common::EventManager { int _buttonState; int _modifierState; bool _shouldQuit; + + class RandomSourceRecord { + public: + Common::String name; + uint32 seed; + }; + Common::Array<RandomSourceRecord> _randomSourceRecords; + + bool _recordSubtitles; + volatile uint32 _recordCount; + volatile uint32 _lastRecordEvent; + volatile uint32 _recordTimeCount; + Common::OutSaveFile *_recordFile; + Common::OutSaveFile *_recordTimeFile; + Common::MutexRef _timeMutex; + Common::MutexRef _recorderMutex; + volatile uint32 _lastMillis; + + volatile uint32 _playbackCount; + volatile uint32 _playbackDiff; + volatile bool _hasPlaybackEvent; + volatile uint32 _playbackTimeCount; + Common::Event _playbackEvent; + Common::InSaveFile *_playbackFile; + Common::InSaveFile *_playbackTimeFile; + volatile uint32 _eventCount; + volatile uint32 _lastEventCount; + + enum RecordMode { + kPassthrough = 0, + kRecorderRecord = 1, + kRecorderPlayback = 2 + }; + volatile RecordMode _recordMode; + Common::String _recordFileName; + Common::String _recordTempFileName; + Common::String _recordTimeFileName; + // for continuous events (keyDown) enum { kKeyRepeatInitialDelay = 400, @@ -61,10 +100,15 @@ class DefaultEventManager : public Common::EventManager { } _currentKeyDown; uint32 _keyRepeatTime; + void record(Common::Event &event); + bool playback(Common::Event &event); public: DefaultEventManager(OSystem *boss); + ~DefaultEventManager(); virtual bool pollEvent(Common::Event &event); + virtual void registerRandomSource(Common::RandomSource &rnd, const char *name); + virtual void processMillis(uint32 &millis); virtual Common::Point getMousePos() const { return _mousePos; } virtual int getButtonState() const { return _buttonState; } diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp index c306f110ab..c12e4001ef 100644 --- a/backends/platform/sdl/sdl.cpp +++ b/backends/platform/sdl/sdl.cpp @@ -25,6 +25,7 @@ #include "backends/platform/sdl/sdl.h" #include "common/config-manager.h" +#include "common/events.h" #include "common/util.h" #include "backends/saves/default/default-saves.h" @@ -187,7 +188,9 @@ OSystem_SDL::~OSystem_SDL() { } uint32 OSystem_SDL::getMillis() { - return SDL_GetTicks(); + uint32 millis = SDL_GetTicks(); + getEventManager()->processMillis(millis); + return millis; } void OSystem_SDL::delayMillis(uint msecs) { @@ -268,6 +271,7 @@ void OSystem_SDL::quit() { SDL_ShowCursor(SDL_ENABLE); SDL_Quit(); + delete getEventManager(); exit(0); } |