mirror of https://github.com/mgba-emu/mgba.git
RR starting from savegame (currently broken) and savestate
This commit is contained in:
parent
86a2edbdf1
commit
82b31c46f1
|
@ -1,6 +1,7 @@
|
||||||
#include "gba-rr.h"
|
#include "gba-rr.h"
|
||||||
|
|
||||||
#include "gba.h"
|
#include "gba.h"
|
||||||
|
#include "gba-serialize.h"
|
||||||
#include "util/vfs.h"
|
#include "util/vfs.h"
|
||||||
|
|
||||||
#define BINARY_EXT ".dat"
|
#define BINARY_EXT ".dat"
|
||||||
|
@ -14,6 +15,9 @@ static bool _seekTag(struct GBARRContext* rr, struct VFile* vf, enum GBARRTag ta
|
||||||
static bool _emitTag(struct GBARRContext* rr, struct VFile* vf, uint8_t tag);
|
static bool _emitTag(struct GBARRContext* rr, struct VFile* vf, uint8_t tag);
|
||||||
static bool _parseMetadata(struct GBARRContext* rr, struct VFile* vf);
|
static bool _parseMetadata(struct GBARRContext* rr, struct VFile* vf);
|
||||||
|
|
||||||
|
static struct VFile* _openSavedata(struct GBARRContext* rr, int flags);
|
||||||
|
static struct VFile* _openSavestate(struct GBARRContext* rr, int flags);
|
||||||
|
|
||||||
void GBARRContextCreate(struct GBA* gba) {
|
void GBARRContextCreate(struct GBA* gba) {
|
||||||
if (gba->rr) {
|
if (gba->rr) {
|
||||||
return;
|
return;
|
||||||
|
@ -36,21 +40,63 @@ void GBARRContextDestroy(struct GBA* gba) {
|
||||||
if (gba->rr->metadataFile) {
|
if (gba->rr->metadataFile) {
|
||||||
gba->rr->metadataFile->close(gba->rr->metadataFile);
|
gba->rr->metadataFile->close(gba->rr->metadataFile);
|
||||||
}
|
}
|
||||||
|
if (gba->rr->savedata) {
|
||||||
|
gba->rr->savedata->close(gba->rr->savedata);
|
||||||
|
}
|
||||||
|
|
||||||
free(gba->rr);
|
free(gba->rr);
|
||||||
gba->rr = 0;
|
gba->rr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBARRAlterSavedata(struct GBA* gba) {
|
void GBARRSaveState(struct GBA* gba) {
|
||||||
if (!gba || !gba->rr) {
|
if (!gba || !gba->rr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gba->rr->initFrom & INIT_FROM_SAVEGAME) {
|
if (gba->rr->initFrom & INIT_FROM_SAVEGAME) {
|
||||||
// TOOD
|
if (gba->rr->savedata) {
|
||||||
|
gba->rr->savedata->close(gba->rr->savedata);
|
||||||
|
}
|
||||||
|
gba->rr->savedata = _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 = _openSavedata(gba->rr, O_RDONLY);
|
||||||
|
GBASavedataMask(&gba->memory.savedata, gba->rr->savedata);
|
||||||
} else {
|
} else {
|
||||||
GBASavedataMask(&gba->memory.savedata, 0);
|
GBASavedataMask(&gba->memory.savedata, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gba->rr->initFrom & INIT_FROM_SAVESTATE) {
|
||||||
|
struct VFile* vf = _openSavestate(gba->rr, O_TRUNC | O_CREAT | O_RDWR);
|
||||||
|
GBASaveStateNamed(gba, vf, false);
|
||||||
|
vf->close(vf);
|
||||||
|
} else {
|
||||||
|
ARMReset(gba->cpu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GBARRLoadState(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 = _openSavedata(gba->rr, O_RDONLY);
|
||||||
|
GBASavedataMask(&gba->memory.savedata, gba->rr->savedata);
|
||||||
|
} else {
|
||||||
|
GBASavedataMask(&gba->memory.savedata, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gba->rr->initFrom & INIT_FROM_SAVESTATE) {
|
||||||
|
struct VFile* vf = _openSavestate(gba->rr, O_RDONLY);
|
||||||
|
GBALoadStateNamed(gba, vf);
|
||||||
|
vf->close(vf);
|
||||||
|
} else {
|
||||||
|
ARMReset(gba->cpu);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GBARRInitStream(struct GBARRContext* rr, struct VDir* stream) {
|
bool GBARRInitStream(struct GBARRContext* rr, struct VDir* stream) {
|
||||||
|
@ -427,3 +473,11 @@ bool _parseMetadata(struct GBARRContext* rr, struct VFile* vf) {
|
||||||
rr->maxStreamIdOffset = vf->seek(vf, 0, SEEK_SET);
|
rr->maxStreamIdOffset = vf->seek(vf, 0, SEEK_SET);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct VFile* _openSavedata(struct GBARRContext* rr, int flags) {
|
||||||
|
return rr->streamDir->openFile(rr->streamDir, "movie.sav", flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct VFile* _openSavestate(struct GBARRContext* rr, int flags) {
|
||||||
|
return rr->streamDir->openFile(rr->streamDir, "movie.ssm", flags);
|
||||||
|
}
|
||||||
|
|
|
@ -65,6 +65,8 @@ struct GBARRContext {
|
||||||
enum GBARRInitFrom initFrom;
|
enum GBARRInitFrom initFrom;
|
||||||
off_t initFromOffset;
|
off_t initFromOffset;
|
||||||
|
|
||||||
|
struct VFile* savedata;
|
||||||
|
|
||||||
// Streaming state
|
// Streaming state
|
||||||
struct VDir* streamDir;
|
struct VDir* streamDir;
|
||||||
struct VFile* metadataFile;
|
struct VFile* metadataFile;
|
||||||
|
@ -77,7 +79,8 @@ struct GBARRContext {
|
||||||
|
|
||||||
void GBARRContextCreate(struct GBA*);
|
void GBARRContextCreate(struct GBA*);
|
||||||
void GBARRContextDestroy(struct GBA*);
|
void GBARRContextDestroy(struct GBA*);
|
||||||
void GBARRAlterSavedata(struct GBA*);
|
void GBARRSaveState(struct GBA*);
|
||||||
|
void GBARRLoadState(struct GBA*);
|
||||||
|
|
||||||
bool GBARRInitStream(struct GBARRContext*, struct VDir*);
|
bool GBARRInitStream(struct GBARRContext*, struct VDir*);
|
||||||
bool GBARRReinitStream(struct GBARRContext*, enum GBARRInitFrom);
|
bool GBARRReinitStream(struct GBARRContext*, enum GBARRInitFrom);
|
||||||
|
|
|
@ -72,6 +72,32 @@ void GBASavedataUnmask(struct GBASavedata* savedata) {
|
||||||
savedata->vf = savedata->realVf;
|
savedata->vf = savedata->realVf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out) {
|
||||||
|
if (savedata->data) {
|
||||||
|
switch (savedata->type) {
|
||||||
|
case SAVEDATA_SRAM:
|
||||||
|
return out->write(out, savedata->data, SIZE_CART_SRAM) == SIZE_CART_SRAM;
|
||||||
|
case SAVEDATA_FLASH512:
|
||||||
|
return out->write(out, savedata->data, SIZE_CART_FLASH512) == SIZE_CART_FLASH512;
|
||||||
|
case SAVEDATA_FLASH1M:
|
||||||
|
return out->write(out, savedata->data, SIZE_CART_FLASH1M) == SIZE_CART_FLASH1M;
|
||||||
|
case SAVEDATA_EEPROM:
|
||||||
|
return out->write(out, savedata->data, SIZE_CART_EEPROM) == SIZE_CART_EEPROM;
|
||||||
|
case SAVEDATA_NONE:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (savedata->vf) {
|
||||||
|
off_t read = 0;
|
||||||
|
uint8_t buffer[2048];
|
||||||
|
do {
|
||||||
|
read = savedata->vf->read(savedata->vf, buffer, sizeof(buffer));
|
||||||
|
out->write(out, buffer, read);
|
||||||
|
} while (read == sizeof(buffer));
|
||||||
|
return read >= 0;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void GBASavedataInitFlash(struct GBASavedata* savedata) {
|
void GBASavedataInitFlash(struct GBASavedata* savedata) {
|
||||||
if (savedata->type == SAVEDATA_NONE) {
|
if (savedata->type == SAVEDATA_NONE) {
|
||||||
savedata->type = SAVEDATA_FLASH512;
|
savedata->type = SAVEDATA_FLASH512;
|
||||||
|
|
|
@ -75,6 +75,7 @@ void GBASavedataDeinit(struct GBASavedata* savedata);
|
||||||
|
|
||||||
void GBASavedataMask(struct GBASavedata* savedata, struct VFile* vf);
|
void GBASavedataMask(struct GBASavedata* savedata, struct VFile* vf);
|
||||||
void GBASavedataUnmask(struct GBASavedata* savedata);
|
void GBASavedataUnmask(struct GBASavedata* savedata);
|
||||||
|
bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out);
|
||||||
|
|
||||||
void GBASavedataInitFlash(struct GBASavedata* savedata);
|
void GBASavedataInitFlash(struct GBASavedata* savedata);
|
||||||
void GBASavedataInitEEPROM(struct GBASavedata* savedata);
|
void GBASavedataInitEEPROM(struct GBASavedata* savedata);
|
||||||
|
|
|
@ -123,31 +123,26 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents
|
||||||
break;
|
break;
|
||||||
case SDLK_t:
|
case SDLK_t:
|
||||||
if (context->stateDir) {
|
if (context->stateDir) {
|
||||||
GBAThreadReset(context);
|
|
||||||
GBAThreadInterrupt(context);
|
GBAThreadInterrupt(context);
|
||||||
GBARRContextCreate(context->gba);
|
GBARRContextCreate(context->gba);
|
||||||
if (!GBARRIsRecording(context->gba->rr)) {
|
if (!GBARRIsRecording(context->gba->rr)) {
|
||||||
|
GBARRStopPlaying(context->gba->rr);
|
||||||
GBARRInitStream(context->gba->rr, context->stateDir);
|
GBARRInitStream(context->gba->rr, context->stateDir);
|
||||||
GBARRReinitStream(context->gba->rr, INIT_EX_NIHILO);
|
GBARRReinitStream(context->gba->rr, INIT_EX_NIHILO);
|
||||||
GBARRStopPlaying(context->gba->rr);
|
|
||||||
GBARRStartRecording(context->gba->rr);
|
GBARRStartRecording(context->gba->rr);
|
||||||
GBARRAlterSavedata(context->gba);
|
GBARRSaveState(context->gba);
|
||||||
}
|
}
|
||||||
GBAThreadContinue(context);
|
GBAThreadContinue(context);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SDLK_y:
|
case SDLK_y:
|
||||||
if (context->stateDir) {
|
if (context->stateDir) {
|
||||||
GBAThreadReset(context);
|
|
||||||
GBAThreadInterrupt(context);
|
GBAThreadInterrupt(context);
|
||||||
GBARRContextCreate(context->gba);
|
GBARRContextCreate(context->gba);
|
||||||
GBARRInitStream(context->gba->rr, context->stateDir);
|
|
||||||
GBARRStopRecording(context->gba->rr);
|
GBARRStopRecording(context->gba->rr);
|
||||||
|
GBARRInitStream(context->gba->rr, context->stateDir);
|
||||||
GBARRStartPlaying(context->gba->rr, false);
|
GBARRStartPlaying(context->gba->rr, false);
|
||||||
if (context->gba->rr->initFrom & INIT_FROM_SAVESTATE) {
|
GBARRLoadState(context->gba);
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
GBARRAlterSavedata(context->gba);
|
|
||||||
GBAThreadContinue(context);
|
GBAThreadContinue(context);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue