diff --git a/include/mgba/internal/gba/gba.h b/include/mgba/internal/gba/gba.h index 141892b64..931ae5b64 100644 --- a/include/mgba/internal/gba/gba.h +++ b/include/mgba/internal/gba/gba.h @@ -91,7 +91,6 @@ struct GBA { struct mRTCSource* rtcSource; struct mRumble* rumble; - struct GBARRContext* rr; bool isPristine; size_t pristineRomSize; size_t yankedRomSize; diff --git a/include/mgba/internal/gba/rr/mgm.h b/include/mgba/internal/gba/rr/mgm.h deleted file mode 100644 index fd455a830..000000000 --- a/include/mgba/internal/gba/rr/mgm.h +++ /dev/null @@ -1,87 +0,0 @@ -/* Copyright (c) 2013-2015 Jeffrey Pfau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef RR_MGM_H -#define RR_MGM_H - -#include - -CXX_GUARD_START - -#include - -struct GBA; -struct VDir; -struct VFile; - -enum GBAMGMTag { - // Playback tags - TAG_INVALID = 0x00, - TAG_INPUT = 0x01, - TAG_FRAME = 0x02, - TAG_LAG = 0x03, - TAG_RESET = 0x04, - - // Stream chunking tags - TAG_BEGIN = 0x10, - TAG_END = 0x11, - TAG_PREVIOUSLY = 0x12, - TAG_NEXT_TIME = 0x13, - TAG_MAX_STREAM = 0x14, - - // Recording information tags - TAG_FRAME_COUNT = 0x20, - TAG_LAG_COUNT = 0x21, - TAG_RR_COUNT = 0x22, - TAG_INIT = 0x24, - TAG_INIT_EX_NIHILO = 0x24 | INIT_EX_NIHILO, - TAG_INIT_FROM_SAVEGAME = 0x24 | INIT_FROM_SAVEGAME, - TAG_INIT_FROM_SAVESTATE = 0x24 | INIT_FROM_SAVESTATE, - TAG_INIT_FROM_BOTH = 0x24 | INIT_FROM_BOTH, - - // User metadata tags - TAG_AUTHOR = 0x30, - TAG_COMMENT = 0x31, - - TAG_EOF = INT_MAX -}; - -struct GBAMGMContext { - struct GBARRContext d; - - // Playback state - bool isPlaying; - bool autorecord; - - // Recording state - bool isRecording; - bool inputThisFrame; - - // Metadata - uint32_t streamId; - - uint32_t maxStreamId; - off_t maxStreamIdOffset; - off_t initFromOffset; - off_t rrCountOffset; - - // Streaming state - struct VDir* streamDir; - struct VFile* metadataFile; - struct VFile* movieStream; - uint16_t currentInput; - enum GBAMGMTag peekedTag; - uint32_t nextTime; - uint32_t previously; -}; - -void GBAMGMContextCreate(struct GBAMGMContext*); - -bool GBAMGMSetStream(struct GBAMGMContext* mgm, struct VDir* stream); -bool GBAMGMCreateStream(struct GBAMGMContext* mgm, enum GBARRInitFrom initFrom); - -CXX_GUARD_END - -#endif diff --git a/include/mgba/internal/gba/rr/rr.h b/include/mgba/internal/gba/rr/rr.h deleted file mode 100644 index b4fc2e627..000000000 --- a/include/mgba/internal/gba/rr/rr.h +++ /dev/null @@ -1,65 +0,0 @@ -/* Copyright (c) 2013-2015 Jeffrey Pfau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef GBA_RR_H -#define GBA_RR_H - -#include - -CXX_GUARD_START - -#include -#include - -struct VFile; - -mLOG_DECLARE_CATEGORY(GBA_RR); - -enum GBARRInitFrom { - INIT_EX_NIHILO = 0, - INIT_FROM_SAVEGAME = 1, - INIT_FROM_SAVESTATE = 2, - INIT_FROM_BOTH = 3, -}; - -struct GBARRContext { - void (*destroy)(struct GBARRContext*); - - bool (*startPlaying)(struct GBARRContext*, bool autorecord); - void (*stopPlaying)(struct GBARRContext*); - bool (*startRecording)(struct GBARRContext*); - void (*stopRecording)(struct GBARRContext*); - - bool (*isPlaying)(const struct GBARRContext*); - bool (*isRecording)(const struct GBARRContext*); - - void (*nextFrame)(struct GBARRContext*); - void (*logInput)(struct GBARRContext*, uint16_t input); - uint16_t (*queryInput)(struct GBARRContext*); - bool (*queryReset)(struct GBARRContext*); - - void (*stateSaved)(struct GBARRContext*, struct GBASerializedState*); - void (*stateLoaded)(struct GBARRContext*, const struct GBASerializedState*); - - struct VFile* (*openSavedata)(struct GBARRContext* mgm, int flags); - struct VFile* (*openSavestate)(struct GBARRContext* mgm, int flags); - - uint32_t frames; - uint32_t lagFrames; - enum GBARRInitFrom initFrom; - - uint32_t rrCount; - - struct VFile* savedata; -}; - -void GBARRDestroy(struct GBARRContext*); - -void GBARRInitRecord(struct GBA*); -void GBARRInitPlay(struct GBA*); - -CXX_GUARD_END - -#endif diff --git a/include/mgba/internal/gba/rr/vbm.h b/include/mgba/internal/gba/rr/vbm.h deleted file mode 100644 index 66d19b76e..000000000 --- a/include/mgba/internal/gba/rr/vbm.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (c) 2013-2015 Jeffrey Pfau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef GBA_VBM_H -#define GBA_VBM_H - -#include - -CXX_GUARD_START - -#include - -struct GBAVBMContext { - struct GBARRContext d; - - bool isPlaying; - - struct VFile* vbmFile; - int32_t inputOffset; -}; - -void GBAVBMContextCreate(struct GBAVBMContext*); - -bool GBAVBMSetStream(struct GBAVBMContext*, struct VFile*); - -CXX_GUARD_END - -#endif diff --git a/include/mgba/internal/gba/serialize.h b/include/mgba/internal/gba/serialize.h index ced79f59f..672d182cf 100644 --- a/include/mgba/internal/gba/serialize.h +++ b/include/mgba/internal/gba/serialize.h @@ -193,8 +193,7 @@ mLOG_DECLARE_CATEGORY(GBA_STATE); * | 0x002F4 - 0x002F7: GBA BIOS bus prefetch * | 0x002F8 - 0x002FB: CPU prefecth (decode slot) * | 0x002FC - 0x002FF: CPU prefetch (fetch slot) - * 0x00300 - 0x00303: Associated movie stream ID for record/replay (or 0 if no stream) - * 0x00304 - 0x00317: Savestate creation time (usec since 1970) + * 0x00300 - 0x00317: Reserved (leave zero) * 0x00318 - 0x0031B: Last prefetched program counter * 0x0031C - 0x0031F: Miscellaneous flags * | bit 0: Is CPU halted? @@ -327,8 +326,7 @@ struct GBASerializedState { uint32_t biosPrefetch; uint32_t cpuPrefetch[2]; - uint32_t associatedStreamId; - uint32_t reservedRr[5]; + uint32_t reservedCpu[6]; uint32_t lastPrefetchedPc; GBASerializedMiscFlags miscFlags; diff --git a/src/gba/CMakeLists.txt b/src/gba/CMakeLists.txt index 74a79425c..94bb8f09f 100644 --- a/src/gba/CMakeLists.txt +++ b/src/gba/CMakeLists.txt @@ -39,10 +39,7 @@ set(SIO_FILES set(EXTRA_FILES extra/audio-mixer.c extra/battlechip.c - extra/proxy.c - rr/mgm.c - rr/rr.c - rr/vbm.c) + extra/proxy.c) set(DEBUGGER_FILES debugger/cli.c) diff --git a/src/gba/gba.c b/src/gba/gba.c index a2ea187fc..d145ce214 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include @@ -96,7 +95,6 @@ static void GBAInit(void* cpu, struct mCPUComponent* component) { gba->luminanceSource = 0; gba->rtcSource = 0; gba->rumble = 0; - gba->rr = 0; gba->romVf = 0; gba->biosVf = 0; @@ -170,7 +168,6 @@ void GBADestroy(struct GBA* gba) { GBAVideoDeinit(&gba->video); GBAAudioDeinit(&gba->audio); GBASIODeinit(&gba->sio); - gba->rr = 0; mTimingDeinit(&gba->timing); mCoreCallbacksListDeinit(&gba->coreCallbacks); } @@ -196,10 +193,8 @@ void GBAReset(struct ARMCore* cpu) { cpu->gprs[ARM_SP] = SP_BASE_SYSTEM; struct GBA* gba = (struct GBA*) cpu->master; - if (!gba->rr || (!gba->rr->isPlaying(gba->rr) && !gba->rr->isRecording(gba->rr))) { - gba->memory.savedata.maskWriteback = false; - GBASavedataUnmask(&gba->memory.savedata); - } + gba->memory.savedata.maskWriteback = false; + GBASavedataUnmask(&gba->memory.savedata); gba->cpuBlocked = false; gba->earlyExit = false; @@ -813,10 +808,6 @@ void GBAFrameStarted(struct GBA* gba) { void GBAFrameEnded(struct GBA* gba) { GBASavedataClean(&gba->memory.savedata, gba->video.frameCounter); - if (gba->rr) { - gba->rr->nextFrame(gba->rr); - } - if (gba->cpu->components && gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) { struct mCheatDevice* device = (struct mCheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]; size_t i; diff --git a/src/gba/io.c b/src/gba/io.c index 530f9cda2..59c74bc41 100644 --- a/src/gba/io.c +++ b/src/gba/io.c @@ -8,7 +8,6 @@ #include #include #include -#include #include mLOG_DEFINE_CATEGORY(GBA_IO, "GBA I/O", "gba.io"); @@ -734,31 +733,24 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) { } } } - if (gba->rr && gba->rr->isPlaying(gba->rr)) { - return 0x3FF ^ gba->rr->queryInput(gba->rr); - } else { - uint16_t input = 0; - if (gba->keyCallback) { - input = gba->keyCallback->readKeys(gba->keyCallback); - if (gba->keySource) { - *gba->keySource = input; - } - } else if (gba->keySource) { - input = *gba->keySource; - if (!gba->allowOpposingDirections) { - unsigned rl = input & 0x030; - unsigned ud = input & 0x0C0; - input &= 0x30F; - if (rl != 0x030) { - input |= rl; - } - if (ud != 0x0C0) { - input |= ud; - } - } + uint16_t input = 0; + if (gba->keyCallback) { + input = gba->keyCallback->readKeys(gba->keyCallback); + if (gba->keySource) { + *gba->keySource = input; } - if (gba->rr && gba->rr->isRecording(gba->rr)) { - gba->rr->logInput(gba->rr, input); + } else if (gba->keySource) { + input = *gba->keySource; + if (!gba->allowOpposingDirections) { + unsigned rl = input & 0x030; + unsigned ud = input & 0x0C0; + input &= 0x30F; + if (rl != 0x030) { + input |= rl; + } + if (ud != 0x0C0) { + input |= ud; + } } return 0x3FF ^ input; } diff --git a/src/gba/rr/mgm.c b/src/gba/rr/mgm.c deleted file mode 100644 index d56e979bb..000000000 --- a/src/gba/rr/mgm.c +++ /dev/null @@ -1,590 +0,0 @@ -/* Copyright (c) 2013-2015 Jeffrey Pfau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include - -#include -#include -#include - -#define BINARY_EXT ".mgm" -#define BINARY_MAGIC "GBAb" -#define METADATA_FILENAME "metadata" BINARY_EXT - -enum { - INVALID_INPUT = 0x8000 -}; - -static void GBAMGMContextDestroy(struct GBARRContext*); - -static bool GBAMGMStartPlaying(struct GBARRContext*, bool autorecord); -static void GBAMGMStopPlaying(struct GBARRContext*); -static bool GBAMGMStartRecording(struct GBARRContext*); -static void GBAMGMStopRecording(struct GBARRContext*); - -static bool GBAMGMIsPlaying(const struct GBARRContext*); -static bool GBAMGMIsRecording(const struct GBARRContext*); - -static void GBAMGMNextFrame(struct GBARRContext*); -static void GBAMGMLogInput(struct GBARRContext*, uint16_t input); -static uint16_t GBAMGMQueryInput(struct GBARRContext*); -static bool GBAMGMQueryReset(struct GBARRContext*); - -static void GBAMGMStateSaved(struct GBARRContext* rr, struct GBASerializedState* state); -static void GBAMGMStateLoaded(struct GBARRContext* rr, const struct GBASerializedState* state); - -static bool _loadStream(struct GBAMGMContext*, uint32_t streamId); -static bool _incrementStream(struct GBAMGMContext*, bool recursive); -static bool _finishSegment(struct GBAMGMContext*); -static bool _skipSegment(struct GBAMGMContext*); -static bool _markRerecord(struct GBAMGMContext*); - -static bool _emitMagic(struct GBAMGMContext*, struct VFile* vf); -static bool _verifyMagic(struct GBAMGMContext*, struct VFile* vf); -static enum GBAMGMTag _readTag(struct GBAMGMContext*, struct VFile* vf); -static bool _seekTag(struct GBAMGMContext*, struct VFile* vf, enum GBAMGMTag tag); -static bool _emitTag(struct GBAMGMContext*, struct VFile* vf, uint8_t tag); -static bool _emitEnd(struct GBAMGMContext*, struct VFile* vf); - -static bool _parseMetadata(struct GBAMGMContext*, struct VFile* vf); - -static bool _markStreamNext(struct GBAMGMContext*, uint32_t newStreamId, bool recursive); -static void _streamEndReached(struct GBAMGMContext*); - -static struct VFile* GBAMGMOpenSavedata(struct GBARRContext*, int flags); -static struct VFile* GBAMGMOpenSavestate(struct GBARRContext*, int flags); - -void GBAMGMContextCreate(struct GBAMGMContext* mgm) { - memset(mgm, 0, sizeof(*mgm)); - - mgm->d.destroy = GBAMGMContextDestroy; - - mgm->d.startPlaying = GBAMGMStartPlaying; - mgm->d.stopPlaying = GBAMGMStopPlaying; - mgm->d.startRecording = GBAMGMStartRecording; - mgm->d.stopRecording = GBAMGMStopRecording; - - mgm->d.isPlaying = GBAMGMIsPlaying; - mgm->d.isRecording = GBAMGMIsRecording; - - mgm->d.nextFrame = GBAMGMNextFrame; - mgm->d.logInput = GBAMGMLogInput; - mgm->d.queryInput = GBAMGMQueryInput; - mgm->d.queryReset = GBAMGMQueryReset; - - mgm->d.stateSaved = GBAMGMStateSaved; - mgm->d.stateLoaded = GBAMGMStateLoaded; - - mgm->d.openSavedata = GBAMGMOpenSavedata; - mgm->d.openSavestate = GBAMGMOpenSavestate; -} - -void GBAMGMContextDestroy(struct GBARRContext* rr) { - struct GBAMGMContext* mgm = (struct GBAMGMContext*) rr; - if (mgm->metadataFile) { - mgm->metadataFile->close(mgm->metadataFile); - } -} - -bool GBAMGMSetStream(struct GBAMGMContext* mgm, struct VDir* stream) { - if (mgm->movieStream && !mgm->movieStream->close(mgm->movieStream)) { - return false; - } - - if (mgm->metadataFile && !mgm->metadataFile->close(mgm->metadataFile)) { - return false; - } - - mgm->streamDir = stream; - mgm->metadataFile = mgm->streamDir->openFile(mgm->streamDir, METADATA_FILENAME, O_CREAT | O_RDWR); - mgm->currentInput = INVALID_INPUT; - if (!_parseMetadata(mgm, mgm->metadataFile)) { - mgm->metadataFile->close(mgm->metadataFile); - mgm->metadataFile = 0; - mgm->maxStreamId = 0; - } - mgm->streamId = 1; - mgm->movieStream = 0; - return true; -} - -bool GBAMGMCreateStream(struct GBAMGMContext* mgm, enum GBARRInitFrom initFrom) { - if (mgm->metadataFile) { - mgm->metadataFile->truncate(mgm->metadataFile, 0); - } else { - mgm->metadataFile = mgm->streamDir->openFile(mgm->streamDir, METADATA_FILENAME, O_CREAT | O_TRUNC | O_RDWR); - } - _emitMagic(mgm, mgm->metadataFile); - - mgm->d.initFrom = initFrom; - mgm->initFromOffset = mgm->metadataFile->seek(mgm->metadataFile, 0, SEEK_CUR); - _emitTag(mgm, mgm->metadataFile, TAG_INIT | initFrom); - - mgm->streamId = 0; - mgm->maxStreamId = 0; - _emitTag(mgm, mgm->metadataFile, TAG_MAX_STREAM); - mgm->maxStreamIdOffset = mgm->metadataFile->seek(mgm->metadataFile, 0, SEEK_CUR); - mgm->metadataFile->write(mgm->metadataFile, &mgm->maxStreamId, sizeof(mgm->maxStreamId)); - - mgm->d.rrCount = 0; - _emitTag(mgm, mgm->metadataFile, TAG_RR_COUNT); - mgm->rrCountOffset = mgm->metadataFile->seek(mgm->metadataFile, 0, SEEK_CUR); - mgm->metadataFile->write(mgm->metadataFile, &mgm->d.rrCount, sizeof(mgm->d.rrCount)); - return true; -} - -bool _loadStream(struct GBAMGMContext* mgm, uint32_t streamId) { - if (mgm->movieStream && !mgm->movieStream->close(mgm->movieStream)) { - return false; - } - mgm->movieStream = 0; - mgm->streamId = streamId; - mgm->currentInput = INVALID_INPUT; - char buffer[14]; - snprintf(buffer, sizeof(buffer), "%u" BINARY_EXT, streamId); - if (mgm->d.isRecording(&mgm->d)) { - int flags = O_CREAT | O_RDWR; - if (streamId > mgm->maxStreamId) { - flags |= O_TRUNC; - } - mgm->movieStream = mgm->streamDir->openFile(mgm->streamDir, buffer, flags); - } else if (mgm->d.isPlaying(&mgm->d)) { - mgm->movieStream = mgm->streamDir->openFile(mgm->streamDir, buffer, O_RDONLY); - mgm->peekedTag = TAG_INVALID; - if (!mgm->movieStream || !_verifyMagic(mgm, mgm->movieStream) || !_seekTag(mgm, mgm->movieStream, TAG_BEGIN)) { - mgm->d.stopPlaying(&mgm->d); - } - } - mLOG(GBA_RR, DEBUG, "Loading segment: %u", streamId); - mgm->d.frames = 0; - mgm->d.lagFrames = 0; - return true; -} - -bool _incrementStream(struct GBAMGMContext* mgm, bool recursive) { - uint32_t newStreamId = mgm->maxStreamId + 1; - uint32_t oldStreamId = mgm->streamId; - if (mgm->d.isRecording(&mgm->d) && mgm->movieStream) { - if (!_markStreamNext(mgm, newStreamId, recursive)) { - return false; - } - } - if (!_loadStream(mgm, newStreamId)) { - return false; - } - mLOG(GBA_RR, DEBUG, "New segment: %u", newStreamId); - _emitMagic(mgm, mgm->movieStream); - mgm->maxStreamId = newStreamId; - _emitTag(mgm, mgm->movieStream, TAG_PREVIOUSLY); - mgm->movieStream->write(mgm->movieStream, &oldStreamId, sizeof(oldStreamId)); - _emitTag(mgm, mgm->movieStream, TAG_BEGIN); - - mgm->metadataFile->seek(mgm->metadataFile, mgm->maxStreamIdOffset, SEEK_SET); - mgm->metadataFile->write(mgm->metadataFile, &mgm->maxStreamId, sizeof(mgm->maxStreamId)); - mgm->previously = oldStreamId; - return true; -} - -bool GBAMGMStartPlaying(struct GBARRContext* rr, bool autorecord) { - if (rr->isRecording(rr) || rr->isPlaying(rr)) { - return false; - } - - struct GBAMGMContext* mgm = (struct GBAMGMContext*) rr; - mgm->isPlaying = true; - if (!_loadStream(mgm, 1)) { - mgm->isPlaying = false; - return false; - } - mgm->autorecord = autorecord; - return true; -} - -void GBAMGMStopPlaying(struct GBARRContext* rr) { - if (!rr->isPlaying(rr)) { - return; - } - - struct GBAMGMContext* mgm = (struct GBAMGMContext*) rr; - mgm->isPlaying = false; - if (mgm->movieStream) { - mgm->movieStream->close(mgm->movieStream); - mgm->movieStream = 0; - } -} - -bool GBAMGMStartRecording(struct GBARRContext* rr) { - if (rr->isRecording(rr) || rr->isPlaying(rr)) { - return false; - } - - struct GBAMGMContext* mgm = (struct GBAMGMContext*) rr; - if (!mgm->maxStreamIdOffset) { - _emitTag(mgm, mgm->metadataFile, TAG_MAX_STREAM); - mgm->maxStreamIdOffset = mgm->metadataFile->seek(mgm->metadataFile, 0, SEEK_CUR); - mgm->metadataFile->write(mgm->metadataFile, &mgm->maxStreamId, sizeof(mgm->maxStreamId)); - } - - mgm->isRecording = true; - return _incrementStream(mgm, false); -} - -void GBAMGMStopRecording(struct GBARRContext* rr) { - if (!rr->isRecording(rr)) { - return; - } - - struct GBAMGMContext* mgm = (struct GBAMGMContext*) rr; - mgm->isRecording = false; - if (mgm->movieStream) { - _emitEnd(mgm, mgm->movieStream); - mgm->movieStream->close(mgm->movieStream); - mgm->movieStream = 0; - } -} - -bool GBAMGMIsPlaying(const struct GBARRContext* rr) { - const struct GBAMGMContext* mgm = (const struct GBAMGMContext*) rr; - return mgm->isPlaying; -} - -bool GBAMGMIsRecording(const struct GBARRContext* rr) { - const struct GBAMGMContext* mgm = (const struct GBAMGMContext*) rr; - return mgm->isRecording; -} - -void GBAMGMNextFrame(struct GBARRContext* rr) { - if (!rr->isRecording(rr) && !rr->isPlaying(rr)) { - return; - } - - struct GBAMGMContext* mgm = (struct GBAMGMContext*) rr; - if (rr->isPlaying(rr)) { - while (mgm->peekedTag == TAG_INPUT) { - _readTag(mgm, mgm->movieStream); - mLOG(GBA_RR, WARN, "Desync detected!"); - } - if (mgm->peekedTag == TAG_LAG) { - mLOG(GBA_RR, DEBUG, "Lag frame marked in stream"); - if (mgm->inputThisFrame) { - mLOG(GBA_RR, WARN, "Lag frame in stream does not match movie"); - } - } - } - - ++mgm->d.frames; - mLOG(GBA_RR, DEBUG, "Frame: %u", mgm->d.frames); - if (!mgm->inputThisFrame) { - ++mgm->d.lagFrames; - mLOG(GBA_RR, DEBUG, "Lag frame: %u", mgm->d.lagFrames); - } - - if (rr->isRecording(rr)) { - if (!mgm->inputThisFrame) { - _emitTag(mgm, mgm->movieStream, TAG_LAG); - } - _emitTag(mgm, mgm->movieStream, TAG_FRAME); - mgm->inputThisFrame = false; - } else { - if (!_seekTag(mgm, mgm->movieStream, TAG_FRAME)) { - _streamEndReached(mgm); - } - } -} - -void GBAMGMLogInput(struct GBARRContext* rr, uint16_t keys) { - if (!rr->isRecording(rr)) { - return; - } - - struct GBAMGMContext* mgm = (struct GBAMGMContext*) rr; - if (keys != mgm->currentInput) { - _emitTag(mgm, mgm->movieStream, TAG_INPUT); - mgm->movieStream->write(mgm->movieStream, &keys, sizeof(keys)); - mgm->currentInput = keys; - } - mLOG(GBA_RR, DEBUG, "Input log: %03X", mgm->currentInput); - mgm->inputThisFrame = true; -} - -uint16_t GBAMGMQueryInput(struct GBARRContext* rr) { - if (!rr->isPlaying(rr)) { - return 0; - } - - struct GBAMGMContext* mgm = (struct GBAMGMContext*) rr; - if (mgm->peekedTag == TAG_INPUT) { - _readTag(mgm, mgm->movieStream); - } - mgm->inputThisFrame = true; - if (mgm->currentInput == INVALID_INPUT) { - mLOG(GBA_RR, WARN, "Stream did not specify input"); - } - mLOG(GBA_RR, DEBUG, "Input replay: %03X", mgm->currentInput); - return mgm->currentInput; -} - -bool GBAMGMQueryReset(struct GBARRContext* rr) { - if (!rr->isPlaying(rr)) { - return 0; - } - - struct GBAMGMContext* mgm = (struct GBAMGMContext*) rr; - return mgm->peekedTag == TAG_RESET; -} - -void GBAMGMStateSaved(struct GBARRContext* rr, struct GBASerializedState* state) { - struct GBAMGMContext* mgm = (struct GBAMGMContext*) rr; - if (rr->isRecording(rr)) { - state->associatedStreamId = mgm->streamId; - _finishSegment(mgm); - } -} - -void GBAMGMStateLoaded(struct GBARRContext* rr, const struct GBASerializedState* state) { - struct GBAMGMContext* mgm = (struct GBAMGMContext*) rr; - if (rr->isRecording(rr)) { - if (state->associatedStreamId != mgm->streamId) { - _loadStream(mgm, state->associatedStreamId); - _incrementStream(mgm, true); - } else { - _finishSegment(mgm); - } - _markRerecord(mgm); - } else if (rr->isPlaying(rr)) { - _loadStream(mgm, state->associatedStreamId); - _skipSegment(mgm); - } -} - -bool _finishSegment(struct GBAMGMContext* mgm) { - if (mgm->movieStream) { - if (!_emitEnd(mgm, mgm->movieStream)) { - return false; - } - } - return _incrementStream(mgm, false); -} - -bool _skipSegment(struct GBAMGMContext* mgm) { - mgm->nextTime = 0; - while (_readTag(mgm, mgm->movieStream) != TAG_EOF); - if (!mgm->nextTime || !_loadStream(mgm, mgm->nextTime)) { - _streamEndReached(mgm); - return false; - } - return true; -} - -bool _markRerecord(struct GBAMGMContext* mgm) { - ++mgm->d.rrCount; - mgm->metadataFile->seek(mgm->metadataFile, mgm->rrCountOffset, SEEK_SET); - mgm->metadataFile->write(mgm->metadataFile, &mgm->d.rrCount, sizeof(mgm->d.rrCount)); - return true; -} - -bool _emitMagic(struct GBAMGMContext* mgm, struct VFile* vf) { - UNUSED(mgm); - return vf->write(vf, BINARY_MAGIC, 4) == 4; -} - -bool _verifyMagic(struct GBAMGMContext* mgm, struct VFile* vf) { - UNUSED(mgm); - char buffer[4]; - if (vf->read(vf, buffer, sizeof(buffer)) != sizeof(buffer)) { - return false; - } - if (memcmp(buffer, BINARY_MAGIC, sizeof(buffer)) != 0) { - return false; - } - return true; -} - -enum GBAMGMTag _readTag(struct GBAMGMContext* mgm, struct VFile* vf) { - if (!mgm || !vf) { - return TAG_EOF; - } - - enum GBAMGMTag tag = mgm->peekedTag; - switch (tag) { - case TAG_INPUT: - vf->read(vf, &mgm->currentInput, sizeof(uint16_t)); - break; - case TAG_PREVIOUSLY: - vf->read(vf, &mgm->previously, sizeof(mgm->previously)); - break; - case TAG_NEXT_TIME: - vf->read(vf, &mgm->nextTime, sizeof(mgm->nextTime)); - break; - case TAG_MAX_STREAM: - vf->read(vf, &mgm->maxStreamId, sizeof(mgm->maxStreamId)); - break; - case TAG_FRAME_COUNT: - vf->read(vf, &mgm->d.frames, sizeof(mgm->d.frames)); - break; - case TAG_LAG_COUNT: - vf->read(vf, &mgm->d.lagFrames, sizeof(mgm->d.lagFrames)); - break; - case TAG_RR_COUNT: - vf->read(vf, &mgm->d.rrCount, sizeof(mgm->d.rrCount)); - break; - - case TAG_INIT_EX_NIHILO: - mgm->d.initFrom = INIT_EX_NIHILO; - break; - case TAG_INIT_FROM_SAVEGAME: - mgm->d.initFrom = INIT_FROM_SAVEGAME; - break; - case TAG_INIT_FROM_SAVESTATE: - mgm->d.initFrom = INIT_FROM_SAVESTATE; - break; - case TAG_INIT_FROM_BOTH: - mgm->d.initFrom = INIT_FROM_BOTH; - break; - - // To be spec'd - case TAG_AUTHOR: - case TAG_COMMENT: - break; - - // Empty markers - case TAG_FRAME: - case TAG_LAG: - case TAG_RESET: - case TAG_BEGIN: - case TAG_END: - case TAG_INVALID: - case TAG_EOF: - break; - } - - uint8_t tagBuffer; - if (vf->read(vf, &tagBuffer, 1) != 1) { - mgm->peekedTag = TAG_EOF; - } else { - mgm->peekedTag = tagBuffer; - } - - if (mgm->peekedTag == TAG_END) { - _skipSegment(mgm); - } - return tag; -} - -bool _seekTag(struct GBAMGMContext* mgm, struct VFile* vf, enum GBAMGMTag tag) { - enum GBAMGMTag readTag; - while ((readTag = _readTag(mgm, vf)) != tag) { - if (readTag == TAG_EOF) { - return false; - } - } - return true; -} - -bool _emitTag(struct GBAMGMContext* mgm, struct VFile* vf, uint8_t tag) { - UNUSED(mgm); - return vf->write(vf, &tag, sizeof(tag)) == sizeof(tag); -} - -bool _parseMetadata(struct GBAMGMContext* mgm, struct VFile* vf) { - if (!_verifyMagic(mgm, vf)) { - return false; - } - while (_readTag(mgm, vf) != TAG_EOF) { - switch (mgm->peekedTag) { - case TAG_MAX_STREAM: - mgm->maxStreamIdOffset = vf->seek(vf, 0, SEEK_CUR); - break; - case TAG_INIT_EX_NIHILO: - case TAG_INIT_FROM_SAVEGAME: - case TAG_INIT_FROM_SAVESTATE: - case TAG_INIT_FROM_BOTH: - mgm->initFromOffset = vf->seek(vf, 0, SEEK_CUR); - break; - case TAG_RR_COUNT: - mgm->rrCountOffset = vf->seek(vf, 0, SEEK_CUR); - break; - default: - break; - } - } - return true; -} - -bool _emitEnd(struct GBAMGMContext* mgm, struct VFile* vf) { - // TODO: Error check - _emitTag(mgm, vf, TAG_END); - _emitTag(mgm, vf, TAG_FRAME_COUNT); - vf->write(vf, &mgm->d.frames, sizeof(mgm->d.frames)); - _emitTag(mgm, vf, TAG_LAG_COUNT); - vf->write(vf, &mgm->d.lagFrames, sizeof(mgm->d.lagFrames)); - _emitTag(mgm, vf, TAG_NEXT_TIME); - - uint32_t newStreamId = 0; - vf->write(vf, &newStreamId, sizeof(newStreamId)); - return true; -} - -bool _markStreamNext(struct GBAMGMContext* mgm, uint32_t newStreamId, bool recursive) { - if (mgm->movieStream->seek(mgm->movieStream, -sizeof(newStreamId) - 1, SEEK_END) < 0) { - return false; - } - - uint8_t tagBuffer; - if (mgm->movieStream->read(mgm->movieStream, &tagBuffer, 1) != 1) { - return false; - } - if (tagBuffer != TAG_NEXT_TIME) { - return false; - } - if (mgm->movieStream->write(mgm->movieStream, &newStreamId, sizeof(newStreamId)) != sizeof(newStreamId)) { - return false; - } - if (recursive) { - if (mgm->movieStream->seek(mgm->movieStream, 0, SEEK_SET) < 0) { - return false; - } - if (!_verifyMagic(mgm, mgm->movieStream)) { - return false; - } - _readTag(mgm, mgm->movieStream); - if (_readTag(mgm, mgm->movieStream) != TAG_PREVIOUSLY) { - return false; - } - if (mgm->previously == 0) { - return true; - } - uint32_t currentStreamId = mgm->streamId; - if (!_loadStream(mgm, mgm->previously)) { - return false; - } - return _markStreamNext(mgm, currentStreamId, mgm->previously); - } - return true; -} - -void _streamEndReached(struct GBAMGMContext* mgm) { - if (!mgm->d.isPlaying(&mgm->d)) { - return; - } - - uint32_t endStreamId = mgm->streamId; - mgm->d.stopPlaying(&mgm->d); - if (mgm->autorecord) { - mgm->isRecording = true; - _loadStream(mgm, endStreamId); - _incrementStream(mgm, false); - } -} - -struct VFile* GBAMGMOpenSavedata(struct GBARRContext* rr, int flags) { - struct GBAMGMContext* mgm = (struct GBAMGMContext*) rr; - return mgm->streamDir->openFile(mgm->streamDir, "movie.sav", flags); -} - -struct VFile* GBAMGMOpenSavestate(struct GBARRContext* rr, int flags) { - struct GBAMGMContext* mgm = (struct GBAMGMContext*) rr; - return mgm->streamDir->openFile(mgm->streamDir, "movie.ssm", flags); -} diff --git a/src/gba/rr/rr.c b/src/gba/rr/rr.c deleted file mode 100644 index 7ed957753..000000000 --- a/src/gba/rr/rr.c +++ /dev/null @@ -1,77 +0,0 @@ -/* Copyright (c) 2013-2015 Jeffrey Pfau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include - -#include -#include -#include - -mLOG_DEFINE_CATEGORY(GBA_RR, "GBA RR", "gba.rr"); - -void GBARRInitRecord(struct GBA* gba) { - if (!gba || !gba->rr) { - return; - } - - if (gba->rr->initFrom & INIT_FROM_SAVEGAME) { - if (gba->rr->savedata) { - gba->rr->savedata->close(gba->rr->savedata); - } - gba->rr->savedata = gba->rr->openSavedata(gba->rr, O_TRUNC | O_CREAT | O_WRONLY); - GBASavedataClone(&gba->memory.savedata, gba->rr->savedata); - gba->rr->savedata->close(gba->rr->savedata); - gba->rr->savedata = gba->rr->openSavedata(gba->rr, O_RDONLY); - GBASavedataMask(&gba->memory.savedata, gba->rr->savedata, false); - } else { - GBASavedataMask(&gba->memory.savedata, 0, false); - } - - if (gba->rr->initFrom & INIT_FROM_SAVESTATE) { - struct VFile* vf = gba->rr->openSavestate(gba->rr, O_TRUNC | O_CREAT | O_RDWR); - //GBASaveStateNamed(gba, vf, SAVESTATE_SAVEDATA); - vf->close(vf); - } else { - ARMReset(gba->cpu); - } -} - -void GBARRInitPlay(struct GBA* gba) { - if (!gba || !gba->rr) { - return; - } - - if (gba->rr->initFrom & INIT_FROM_SAVEGAME) { - if (gba->rr->savedata) { - gba->rr->savedata->close(gba->rr->savedata); - } - gba->rr->savedata = gba->rr->openSavedata(gba->rr, O_RDONLY); - GBASavedataMask(&gba->memory.savedata, gba->rr->savedata, false); - } else { - GBASavedataMask(&gba->memory.savedata, 0, false); - } - - if (gba->rr->initFrom & INIT_FROM_SAVESTATE) { - struct VFile* vf = gba->rr->openSavestate(gba->rr, O_RDONLY); - //GBALoadStateNamed(gba, vf, SAVESTATE_SCREENSHOT | SAVESTATE_SAVEDATA); - vf->close(vf); - } else { - ARMReset(gba->cpu); - } -} - -void GBARRDestroy(struct GBARRContext* rr) { - if (rr->isPlaying(rr)) { - rr->stopPlaying(rr); - } - if (rr->isRecording(rr)) { - rr->stopRecording(rr); - } - if (rr->savedata) { - rr->savedata->close(rr->savedata); - rr->savedata = 0; - } - rr->destroy(rr); -} diff --git a/src/gba/rr/vbm.c b/src/gba/rr/vbm.c deleted file mode 100644 index 2845b74bc..000000000 --- a/src/gba/rr/vbm.c +++ /dev/null @@ -1,274 +0,0 @@ -/* Copyright (c) 2013-2015 Jeffrey Pfau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include - -#include -#include -#include - -#ifdef USE_ZLIB -#include -#endif - -static const char VBM_MAGIC[] = "VBM\x1A"; - -static void GBAVBMContextDestroy(struct GBARRContext*); - -static bool GBAVBMStartPlaying(struct GBARRContext*, bool autorecord); -static void GBAVBMStopPlaying(struct GBARRContext*); -static bool GBAVBMStartRecording(struct GBARRContext*); -static void GBAVBMStopRecording(struct GBARRContext*); - -static bool GBAVBMIsPlaying(const struct GBARRContext*); -static bool GBAVBMIsRecording(const struct GBARRContext*); - -static void GBAVBMNextFrame(struct GBARRContext*); -static uint16_t GBAVBMQueryInput(struct GBARRContext*); -static bool GBAVBMQueryReset(struct GBARRContext*); - -static void GBAVBMStateSaved(struct GBARRContext* rr, struct GBASerializedState* state); -static void GBAVBMStateLoaded(struct GBARRContext* rr, const struct GBASerializedState* state); - -static struct VFile* GBAVBMOpenSavedata(struct GBARRContext*, int flags); -static struct VFile* GBAVBMOpenSavestate(struct GBARRContext*, int flags); - -void GBAVBMContextCreate(struct GBAVBMContext* vbm) { - memset(vbm, 0, sizeof(*vbm)); - - vbm->d.destroy = GBAVBMContextDestroy; - - vbm->d.startPlaying = GBAVBMStartPlaying; - vbm->d.stopPlaying = GBAVBMStopPlaying; - vbm->d.startRecording = GBAVBMStartRecording; - vbm->d.stopRecording = GBAVBMStopRecording; - - vbm->d.isPlaying = GBAVBMIsPlaying; - vbm->d.isRecording = GBAVBMIsRecording; - - vbm->d.nextFrame = GBAVBMNextFrame; - vbm->d.logInput = 0; - vbm->d.queryInput = GBAVBMQueryInput; - vbm->d.queryReset = GBAVBMQueryReset; - - vbm->d.stateSaved = GBAVBMStateSaved; - vbm->d.stateLoaded = GBAVBMStateLoaded; - - vbm->d.openSavedata = GBAVBMOpenSavedata; - vbm->d.openSavestate = GBAVBMOpenSavestate; -} - -bool GBAVBMStartPlaying(struct GBARRContext* rr, bool autorecord) { - if (rr->isRecording(rr) || rr->isPlaying(rr) || autorecord) { - return false; - } - - struct GBAVBMContext* vbm = (struct GBAVBMContext*) rr; - vbm->isPlaying = true; - vbm->vbmFile->seek(vbm->vbmFile, vbm->inputOffset, SEEK_SET); - return true; -} - -void GBAVBMStopPlaying(struct GBARRContext* rr) { - if (!rr->isPlaying(rr)) { - return; - } - - struct GBAVBMContext* vbm = (struct GBAVBMContext*) rr; - vbm->isPlaying = false; -} - -bool GBAVBMStartRecording(struct GBARRContext* rr) { - UNUSED(rr); - return false; -} - -void GBAVBMStopRecording(struct GBARRContext* rr) { - UNUSED(rr); -} - -bool GBAVBMIsPlaying(const struct GBARRContext* rr) { - struct GBAVBMContext* vbm = (struct GBAVBMContext*) rr; - return vbm->isPlaying; -} - -bool GBAVBMIsRecording(const struct GBARRContext* rr) { - UNUSED(rr); - return false; -} - -void GBAVBMNextFrame(struct GBARRContext* rr) { - if (!rr->isPlaying(rr)) { - return; - } - - struct GBAVBMContext* vbm = (struct GBAVBMContext*) rr; - vbm->vbmFile->seek(vbm->vbmFile, sizeof(uint16_t), SEEK_CUR); -} - -uint16_t GBAVBMQueryInput(struct GBARRContext* rr) { - if (!rr->isPlaying(rr)) { - return 0; - } - - struct GBAVBMContext* vbm = (struct GBAVBMContext*) rr; - uint16_t input; - vbm->vbmFile->read(vbm->vbmFile, &input, sizeof(input)); - vbm->vbmFile->seek(vbm->vbmFile, -sizeof(input), SEEK_CUR); - return input & 0x3FF; -} - -bool GBAVBMQueryReset(struct GBARRContext* rr) { - if (!rr->isPlaying(rr)) { - return false; - } - - struct GBAVBMContext* vbm = (struct GBAVBMContext*) rr; - uint16_t input; - vbm->vbmFile->read(vbm->vbmFile, &input, sizeof(input)); - vbm->vbmFile->seek(vbm->vbmFile, -sizeof(input), SEEK_CUR); - return input & 0x800; -} - -void GBAVBMStateSaved(struct GBARRContext* rr, struct GBASerializedState* state) { - UNUSED(rr); - UNUSED(state); -} - -void GBAVBMStateLoaded(struct GBARRContext* rr, const struct GBASerializedState* state) { - UNUSED(rr); - UNUSED(state); -} - -struct VFile* GBAVBMOpenSavedata(struct GBARRContext* rr, int flags) { - UNUSED(flags); -#ifndef USE_ZLIB - UNUSED(rr); - return 0; -#else - struct GBAVBMContext* vbm = (struct GBAVBMContext*) rr; - off_t pos = vbm->vbmFile->seek(vbm->vbmFile, 0, SEEK_CUR); - uint32_t saveType, flashSize, sramOffset; - vbm->vbmFile->seek(vbm->vbmFile, 0x18, SEEK_SET); - vbm->vbmFile->read(vbm->vbmFile, &saveType, sizeof(saveType)); - vbm->vbmFile->read(vbm->vbmFile, &flashSize, sizeof(flashSize)); - vbm->vbmFile->seek(vbm->vbmFile, 0x38, SEEK_SET); - vbm->vbmFile->read(vbm->vbmFile, &sramOffset, sizeof(sramOffset)); - if (!sramOffset) { - vbm->vbmFile->seek(vbm->vbmFile, pos, SEEK_SET); - return 0; - } - vbm->vbmFile->seek(vbm->vbmFile, sramOffset, SEEK_SET); - struct VFile* save = VFileMemChunk(0, 0); - size_t size; - switch (saveType) { - case 1: - size = SIZE_CART_SRAM; - break; - case 2: - size = flashSize; - if (size > SIZE_CART_FLASH1M) { - size = SIZE_CART_FLASH1M; - } - break; - case 3: - size = SIZE_CART_EEPROM; - break; - default: - size = SIZE_CART_FLASH1M; - break; - } - uLong zlen = vbm->inputOffset - sramOffset; - char buffer[8761]; - char* zbuffer = malloc(zlen); - vbm->vbmFile->read(vbm->vbmFile, zbuffer, zlen); - z_stream zstr; - zstr.zalloc = Z_NULL; - zstr.zfree = Z_NULL; - zstr.opaque = Z_NULL; - zstr.avail_in = zlen; - zstr.next_in = (Bytef*) zbuffer; - zstr.avail_out = 0; - inflateInit2(&zstr, 31); - // Skip header, we know where the save file is - zstr.avail_out = sizeof(buffer); - zstr.next_out = (Bytef*) &buffer; - int err = inflate(&zstr, 0); - while (err != Z_STREAM_END && !zstr.avail_out) { - zstr.avail_out = sizeof(buffer); - zstr.next_out = (Bytef*) &buffer; - int err = inflate(&zstr, 0); - if (err < 0) { - break; - } - save->write(save, buffer, sizeof(buffer) - zstr.avail_out); - } - inflateEnd(&zstr); - vbm->vbmFile->seek(vbm->vbmFile, pos, SEEK_SET); - return save; -#endif -} - -struct VFile* GBAVBMOpenSavestate(struct GBARRContext* rr, int flags) { - UNUSED(rr); - UNUSED(flags); - return 0; -} - -void GBAVBMContextDestroy(struct GBARRContext* rr) { - struct GBAVBMContext* vbm = (struct GBAVBMContext*) rr; - if (vbm->vbmFile) { - vbm->vbmFile->close(vbm->vbmFile); - } -} - -bool GBAVBMSetStream(struct GBAVBMContext* vbm, struct VFile* vf) { - vf->seek(vf, 0, SEEK_SET); - char magic[4]; - vf->read(vf, magic, sizeof(magic)); - if (memcmp(magic, VBM_MAGIC, sizeof(magic)) != 0) { - return false; - } - - uint32_t id; - vf->read(vf, &id, sizeof(id)); - if (id != 1) { - return false; - } - - vf->seek(vf, 4, SEEK_CUR); - vf->read(vf, &vbm->d.frames, sizeof(vbm->d.frames)); - vf->read(vf, &vbm->d.rrCount, sizeof(vbm->d.rrCount)); - - uint8_t flags; - vf->read(vf, &flags, sizeof(flags)); - if (flags & 2) { -#ifdef USE_ZLIB - vbm->d.initFrom = INIT_FROM_SAVEGAME; -#else - // zlib is needed to parse the savegame - return false; -#endif - } - if (flags & 1) { - // Incompatible savestate format - return false; - } - - vf->seek(vf, 1, SEEK_CUR); - vf->read(vf, &flags, sizeof(flags)); - if ((flags & 0x7) != 1) { - // Non-GBA movie - return false; - } - - // TODO: parse more flags - - vf->seek(vf, 0x3C, SEEK_SET); - vf->read(vf, &vbm->inputOffset, sizeof(vbm->inputOffset)); - vf->seek(vf, vbm->inputOffset, SEEK_SET); - vbm->vbmFile = vf; - return true; -} diff --git a/src/gba/serialize.c b/src/gba/serialize.c index 60b8524ca..bd543482a 100644 --- a/src/gba/serialize.c +++ b/src/gba/serialize.c @@ -7,7 +7,6 @@ #include #include -#include #include #include @@ -73,11 +72,6 @@ void GBASerialize(struct GBA* gba, struct GBASerializedState* state) { GBAVideoSerialize(&gba->video, state); GBAAudioSerialize(&gba->audio, state); GBASavedataSerialize(&gba->memory.savedata, state); - - state->associatedStreamId = 0; - if (gba->rr) { - gba->rr->stateSaved(gba->rr, state); - } } bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) { @@ -195,10 +189,6 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) { GBAAudioDeserialize(&gba->audio, state); GBASavedataDeserialize(&gba->memory.savedata, state); - if (gba->rr) { - gba->rr->stateLoaded(gba->rr, state); - } - gba->timing.reroot = gba->timing.root; gba->timing.root = NULL;