all repos — mgba @ 0389237fc6a43382aa1fce96af2d6a031d7e2ff9

mGBA Game Boy Advance Emulator

Loading savestates now changes the active branch
Jeffrey Pfau jeffrey@endrift.com
Tue, 05 Aug 2014 23:52:08 -0700
commit

0389237fc6a43382aa1fce96af2d6a031d7e2ff9

parent

5ee336d274fd481c9eb4eb0ee9b49d598aa4340a

3 files changed, 92 insertions(+), 33 deletions(-)

jump to
M src/gba/gba-rr.csrc/gba/gba-rr.c

@@ -13,7 +13,11 @@ static bool _verifyMagic(struct GBARRContext* rr, struct VFile* vf);

static enum GBARRTag _readTag(struct GBARRContext* rr, struct VFile* vf); static bool _seekTag(struct GBARRContext* rr, struct VFile* vf, enum GBARRTag tag); static bool _emitTag(struct GBARRContext* rr, struct VFile* vf, uint8_t tag); +static bool _emitEnd(struct GBARRContext* rr, struct VFile* vf); + static bool _parseMetadata(struct GBARRContext* rr, struct VFile* vf); + +static bool _markStreamNext(struct GBARRContext* rr, uint32_t newStreamId, bool recursive); static struct VFile* _openSavedata(struct GBARRContext* rr, int flags); static struct VFile* _openSavestate(struct GBARRContext* rr, int flags);

@@ -113,7 +117,7 @@ rr->metadataFile = rr->streamDir->openFile(rr->streamDir, METADATA_FILENAME, O_CREAT | O_RDWR);

if (!_parseMetadata(rr, rr->metadataFile)) { rr->metadataFile->close(rr->metadataFile); rr->metadataFile = 0; - rr->maxStreamId = 1; + rr->maxStreamId = 0; } rr->streamId = 1; rr->movieStream = 0;

@@ -136,8 +140,8 @@ rr->initFrom = initFrom;

rr->initFromOffset = rr->metadataFile->seek(rr->metadataFile, 0, SEEK_CUR); _emitTag(rr, rr->metadataFile, TAG_INIT | initFrom); - rr->streamId = 1; - rr->maxStreamId = 1; + rr->streamId = 0; + rr->maxStreamId = 0; rr->maxStreamIdOffset = rr->metadataFile->seek(rr->metadataFile, 0, SEEK_CUR); _emitTag(rr, rr->metadataFile, 1); return true;

@@ -152,11 +156,9 @@ rr->streamId = streamId;

char buffer[14]; snprintf(buffer, sizeof(buffer), "%u" BINARY_EXT, streamId); if (GBARRIsRecording(rr)) { - int flags = O_CREAT | O_WRONLY; + int flags = O_CREAT | O_RDWR; if (streamId > rr->maxStreamId) { flags |= O_TRUNC; - } else { - flags |= O_APPEND; } rr->movieStream = rr->streamDir->openFile(rr->streamDir, buffer, flags); } else if (GBARRIsPlaying(rr)) {

@@ -171,17 +173,13 @@ rr->lagFrames = 0;

return true; } -bool GBARRIncrementStream(struct GBARRContext* rr) { +bool GBARRIncrementStream(struct GBARRContext* rr, bool recursive) { uint32_t newStreamId = rr->maxStreamId + 1; uint32_t oldStreamId = rr->streamId; if (GBARRIsRecording(rr) && rr->movieStream) { - _emitTag(rr, rr->movieStream, TAG_END); - _emitTag(rr, rr->movieStream, TAG_FRAME_COUNT); - rr->movieStream->write(rr->movieStream, &rr->frames, sizeof(rr->frames)); - _emitTag(rr, rr->movieStream, TAG_LAG_COUNT); - rr->movieStream->write(rr->movieStream, &rr->lagFrames, sizeof(rr->lagFrames)); - _emitTag(rr, rr->movieStream, TAG_NEXT_TIME); - rr->movieStream->write(rr->movieStream, &newStreamId, sizeof(newStreamId)); + if (!_markStreamNext(rr, newStreamId, recursive)) { + return false; + } } if (!GBARRLoadStream(rr, newStreamId)) { return false;

@@ -194,6 +192,7 @@ _emitTag(rr, rr->movieStream, TAG_BEGIN);

rr->metadataFile->seek(rr->metadataFile, rr->maxStreamIdOffset, SEEK_SET); rr->metadataFile->write(rr->movieStream, &rr->maxStreamId, sizeof(rr->maxStreamId)); + rr->previously = oldStreamId; return true; }

@@ -216,6 +215,12 @@ }

rr->peekedTag = TAG_INVALID; _readTag(rr, rr->movieStream); // Discard the buffer enum GBARRTag tag = _readTag(rr, rr->movieStream); + if (tag == TAG_PREVIOUSLY) { + if (rr->previously != 0) { + return false; + } + tag = _readTag(rr, rr->movieStream); + } if (tag != TAG_BEGIN) { rr->movieStream->close(rr->movieStream); rr->movieStream = 0;

@@ -242,19 +247,6 @@ if (GBARRIsRecording(rr) || GBARRIsPlaying(rr)) {

return false; } - char buffer[14]; - snprintf(buffer, sizeof(buffer), "%u" BINARY_EXT, rr->streamId); - rr->movieStream = rr->streamDir->openFile(rr->streamDir, buffer, O_TRUNC | O_CREAT | O_WRONLY); - if (!rr->movieStream) { - return false; - } - _emitMagic(rr, rr->movieStream); - if (!_emitTag(rr, rr->movieStream, TAG_BEGIN)) { - rr->movieStream->close(rr->movieStream); - rr->movieStream = 0; - return false; - } - if (!rr->maxStreamIdOffset) { _emitTag(rr, rr->metadataFile, TAG_MAX_STREAM); rr->maxStreamIdOffset = rr->metadataFile->seek(rr->metadataFile, 0, SEEK_CUR);

@@ -262,7 +254,7 @@ rr->metadataFile->write(rr->metadataFile, &rr->maxStreamId, sizeof(rr->maxStreamId));

} rr->isRecording = true; - return true; + return GBARRIncrementStream(rr, false); } void GBARRStopRecording(struct GBARRContext* rr) {

@@ -312,7 +304,7 @@ GBARRStopPlaying(rr);

if (rr->autorecord) { rr->isRecording = true; GBARRLoadStream(rr, endStreamId); - GBARRIncrementStream(rr); + GBARRIncrementStream(rr, false); } } }

@@ -342,6 +334,15 @@ }

return rr->currentInput; } +bool GBARRFinishSegment(struct GBARRContext* rr) { + if (rr->movieStream) { + if (!_emitEnd(rr, rr->movieStream)) { + return false; + } + } + return GBARRIncrementStream(rr, false); +} + bool GBARRSkipSegment(struct GBARRContext* rr) { rr->nextTime = 0; while (_readTag(rr, rr->movieStream) != TAG_EOF);

@@ -472,6 +473,59 @@ }

} rr->maxStreamIdOffset = vf->seek(vf, 0, SEEK_SET); return true; +} + +bool _emitEnd(struct GBARRContext* rr, struct VFile* vf) { + // TODO: Error check + _emitTag(rr, vf, TAG_END); + _emitTag(rr, vf, TAG_FRAME_COUNT); + vf->write(vf, &rr->frames, sizeof(rr->frames)); + _emitTag(rr, vf, TAG_LAG_COUNT); + vf->write(vf, &rr->lagFrames, sizeof(rr->lagFrames)); + _emitTag(rr, vf, TAG_NEXT_TIME); + + uint32_t newStreamId = 0; + vf->write(vf, &newStreamId, sizeof(newStreamId)); + return true; +} + +bool _markStreamNext(struct GBARRContext* rr, uint32_t newStreamId, bool recursive) { + if (rr->movieStream->seek(rr->movieStream, -sizeof(newStreamId) - 1, SEEK_END) < 0) { + return false; + } + + uint8_t tagBuffer; + if (rr->movieStream->read(rr->movieStream, &tagBuffer, 1) != 1) { + return false; + } + if (tagBuffer != TAG_NEXT_TIME) { + return false; + } + if (rr->movieStream->write(rr->movieStream, &newStreamId, sizeof(newStreamId)) != sizeof(newStreamId)) { + return false; + } + if (recursive) { + if (rr->movieStream->seek(rr->movieStream, 0, SEEK_SET) < 0) { + return false; + } + if (!_verifyMagic(rr, rr->movieStream)) { + return false; + } + _readTag(rr, rr->movieStream); + if (_readTag(rr, rr->movieStream) != TAG_PREVIOUSLY) { + return false; + } + if (rr->previously == 0) { + return true; + } + uint32_t currentStreamId = rr->streamId; + if (!GBARRLoadStream(rr, rr->previously)) { + return false; + } + return _markStreamNext(rr, currentStreamId, rr->previously); + } + return true; + } struct VFile* _openSavedata(struct GBARRContext* rr, int flags) {
M src/gba/gba-rr.hsrc/gba/gba-rr.h

@@ -85,7 +85,8 @@

bool GBARRInitStream(struct GBARRContext*, struct VDir*); bool GBARRReinitStream(struct GBARRContext*, enum GBARRInitFrom); bool GBARRLoadStream(struct GBARRContext*, uint32_t streamId); -bool GBARRIncrementStream(struct GBARRContext*); +bool GBARRIncrementStream(struct GBARRContext*, bool recursive); +bool GBARRFinishSegment(struct GBARRContext*); bool GBARRSkipSegment(struct GBARRContext*); bool GBARRStartPlaying(struct GBARRContext*, bool autorecord);
M src/gba/gba-serialize.csrc/gba/gba-serialize.c

@@ -39,7 +39,7 @@ GBAAudioSerialize(&gba->audio, state);

if (GBARRIsRecording(gba->rr)) { state->associatedStreamId = gba->rr->streamId; - GBARRIncrementStream(gba->rr); + GBARRFinishSegment(gba->rr); } else { state->associatedStreamId = 0; }

@@ -80,8 +80,12 @@ GBAVideoDeserialize(&gba->video, state);

GBAAudioDeserialize(&gba->audio, state); if (GBARRIsRecording(gba->rr)) { - GBARRLoadStream(gba->rr, state->associatedStreamId); - GBARRIncrementStream(gba->rr); + if (state->associatedStreamId != gba->rr->streamId) { + GBARRLoadStream(gba->rr, state->associatedStreamId); + GBARRIncrementStream(gba->rr, true); + } else { + GBARRFinishSegment(gba->rr); + } } else if (GBARRIsPlaying(gba->rr)) { GBARRLoadStream(gba->rr, state->associatedStreamId); GBARRSkipSegment(gba->rr);