all repos — mgba @ fa884d071ecaa3e05ff20b45a67bf9500dd3d6b6

mGBA Game Boy Advance Emulator

src/core/rewind.c (view raw)

 1/* Copyright (c) 2013-2016 Jeffrey Pfau
 2 *
 3 * This Source Code Form is subject to the terms of the Mozilla Public
 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 6#include <mgba/core/rewind.h>
 7
 8#include <mgba/core/core.h>
 9#include <mgba-util/patch/fast.h>
10#include <mgba-util/vfs.h>
11
12DEFINE_VECTOR(mCoreRewindPatches, struct PatchFast);
13
14void mCoreRewindContextInit(struct mCoreRewindContext* context, size_t entries) {
15	mCoreRewindPatchesInit(&context->patchMemory, entries);
16	size_t e;
17	for (e = 0; e < entries; ++e) {
18		initPatchFast(mCoreRewindPatchesAppend(&context->patchMemory));
19	}
20	context->previousState = VFileMemChunk(0, 0);
21	context->currentState = VFileMemChunk(0, 0);
22	context->size = 0;
23}
24
25void mCoreRewindContextDeinit(struct mCoreRewindContext* context) {
26	context->previousState->close(context->previousState);
27	context->currentState->close(context->currentState);
28	size_t s;
29	for (s = 0; s < mCoreRewindPatchesSize(&context->patchMemory); ++s) {
30		deinitPatchFast(mCoreRewindPatchesGetPointer(&context->patchMemory, s));
31	}
32	mCoreRewindPatchesDeinit(&context->patchMemory);
33}
34
35void mCoreRewindAppend(struct mCoreRewindContext* context, struct mCore* core) {
36	struct VFile* nextState = context->previousState;
37	++context->current;
38	if (context->size < mCoreRewindPatchesSize(&context->patchMemory)) {
39		++context->size;
40	}
41	if (context->current >= mCoreRewindPatchesSize(&context->patchMemory)) {
42		context->current = 0;
43	}
44	mCoreSaveStateNamed(core, nextState, 0);
45	struct PatchFast* patch = mCoreRewindPatchesGetPointer(&context->patchMemory, context->current);
46	size_t size2 = nextState->size(nextState);
47	size_t size = context->currentState->size(context->currentState);
48	if (size2 > size) {
49		context->currentState->truncate(context->currentState, size2);
50		size = size2;
51	}
52	void* current = context->currentState->map(context->currentState, size, MAP_READ);
53	void* next = nextState->map(nextState, size, MAP_READ);
54	diffPatchFast(patch, current, next, size);
55	context->currentState->unmap(context->currentState, current, size);
56	nextState->unmap(next, nextState, size);
57	context->previousState = context->currentState;
58	context->currentState = nextState;
59}
60
61bool mCoreRewindRestore(struct mCoreRewindContext* context, struct mCore* core) {
62	if (!context->size) {
63		return false;
64	}
65	--context->size;
66
67	struct PatchFast* patch = mCoreRewindPatchesGetPointer(&context->patchMemory, context->current);
68	size_t size2 = context->previousState->size(context->previousState);
69	size_t size = context->currentState->size(context->currentState);
70	if (size2 < size) {
71		size = size2;
72	}
73	void* current = context->currentState->map(context->currentState, size, MAP_READ);
74	void* previous = context->previousState->map(context->previousState, size, MAP_WRITE);
75	patch->d.applyPatch(&patch->d, current, size, previous, size);
76	context->currentState->unmap(context->currentState, current, size);
77	context->previousState->unmap(context->previousState, previous, size);
78	mCoreLoadStateNamed(core, context->previousState, 0);
79	struct VFile* nextState = context->previousState;
80	context->previousState = context->currentState;
81	context->currentState = nextState;
82
83	if (context->current == 0) {
84		context->current = mCoreRewindPatchesSize(&context->patchMemory);
85	} 
86	--context->current;
87	return true;
88}