diff --git a/src/gba/gba-rr.c b/src/gba/gba-rr.c index 9d5ae058c..49c3e7aa8 100644 --- a/src/gba/gba-rr.c +++ b/src/gba/gba-rr.c @@ -7,6 +7,8 @@ enum { GBA_RR_BLOCK_SIZE = 1018 }; +#define FILE_INPUTS "input.log" + struct GBARRBlock { union GBARRInput { struct { @@ -42,6 +44,69 @@ void GBARRContextDestroy(struct GBA* gba) { gba->rr->currentBlock = 0; gba->rr->playbackBlock = 0; free(gba->rr); + gba->rr = 0; +} + +bool GBARRSave(struct GBARRContext* rr, struct VDir* vdir) { + if (!rr) { + return false; + } + + struct VFile* inputs = vdir->openFile(vdir, FILE_INPUTS, O_WRONLY | O_CREAT | O_TRUNC); + if (!inputs) { + return false; + } + + ssize_t written = 0; + struct GBARRBlock* inputBlock; + for (inputBlock = rr->rootBlock; inputBlock; inputBlock = inputBlock->next) { + ssize_t thisWrite = inputs->write(inputs, inputBlock->inputs, sizeof(*inputBlock->inputs) * inputBlock->numInputs); + if (!thisWrite) { + written = -1; + break; + } + written += thisWrite; + } + + if (!inputs->close(inputs)) { + return false; + } + + return written >= 0; +} + +bool GBARRLoad(struct GBARRContext* rr, struct VDir* vdir) { + if (!rr) { + return false; + } + + struct VFile* inputs = vdir->openFile(vdir, FILE_INPUTS, O_RDONLY); + if (!inputs) { + return false; + } + + struct GBARRBlock block; + ssize_t read; + do { + read = inputs->read(inputs, block.inputs, sizeof(block.inputs)); + if (read) { + struct GBARRBlock* newBlock = calloc(1, sizeof(*rr->currentBlock)); + memcpy(newBlock, &block, sizeof(*newBlock)); + if (!rr->rootBlock) { + rr->rootBlock = newBlock; + } + if (rr->currentBlock) { + rr->currentBlock->next = newBlock; + } + rr->currentBlock = newBlock; + } + } while (read > 0); + + if (!inputs->close(inputs)) { + return false; + } + + return read >= 0; } bool GBARRStartPlaying(struct GBA* gba) { diff --git a/src/gba/gba-rr.h b/src/gba/gba-rr.h index 4f1e11edf..41baa6cd0 100644 --- a/src/gba/gba-rr.h +++ b/src/gba/gba-rr.h @@ -4,6 +4,7 @@ #include "common.h" struct GBA; +struct VDir; struct VFile; struct GBARRContext { @@ -24,6 +25,9 @@ struct GBARRContext { void GBARRContextCreate(struct GBA*); void GBARRContextDestroy(struct GBA*); +bool GBARRSave(struct GBARRContext*, struct VDir*); +bool GBARRLoad(struct GBARRContext*, struct VDir*); + bool GBARRStartPlaying(struct GBA*); void GBARRStopPlaying(struct GBA*); bool GBARRStartRecording(struct GBA*); diff --git a/src/platform/sdl/sdl-events.c b/src/platform/sdl/sdl-events.c index ed4920c67..d0844a6b5 100644 --- a/src/platform/sdl/sdl-events.c +++ b/src/platform/sdl/sdl-events.c @@ -128,20 +128,6 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents case SDLK_r: GBAThreadReset(context); break; - case SDLK_t: - GBAThreadReset(context); - GBAThreadInterrupt(context); - GBARRStopPlaying(context->gba); - GBARRStartRecording(context->gba); - GBAThreadContinue(context); - break; - case SDLK_y: - GBAThreadReset(context); - GBAThreadInterrupt(context); - GBARRStopRecording(context->gba); - GBARRStartPlaying(context->gba); - GBAThreadContinue(context); - break; default: break; } @@ -162,6 +148,27 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents GBASaveState(context->gba, event->keysym.sym - SDLK_F1); GBAThreadContinue(context); break; + case SDLK_t: + if (context->gamedir) { + GBAThreadInterrupt(context); + GBARRStopPlaying(context->gba); + GBARRSave(context->gba->rr, context->gamedir); + GBAThreadContinue(context); + } + break; + case SDLK_y: + if (context->gamedir) { + GBAThreadReset(context); + GBAThreadInterrupt(context); + GBARRStopRecording(context->gba); + GBARRContextDestroy(context->gba); + GBARRContextCreate(context->gba); + if (GBARRLoad(context->gba->rr, context->gamedir)) { + GBARRStartPlaying(context->gba); + } + GBAThreadContinue(context); + } + break; default: break; } @@ -181,6 +188,20 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents GBALoadState(context->gba, event->keysym.sym - SDLK_F1); GBAThreadContinue(context); break; + case SDLK_t: + GBAThreadReset(context); + GBAThreadInterrupt(context); + GBARRStopPlaying(context->gba); + GBARRStartRecording(context->gba); + GBAThreadContinue(context); + break; + case SDLK_y: + GBAThreadReset(context); + GBAThreadInterrupt(context); + GBARRStopRecording(context->gba); + GBARRStartPlaying(context->gba); + GBAThreadContinue(context); + break; default: break; }