Permalink
Browse files

3DS: Add experimental autosave

  • Loading branch information...
endrift committed Jan 10, 2018
1 parent 789a84d commit 0e9ba00dbfd3ed4586fbe79b64ebb319db5221a5
Showing with 91 additions and 0 deletions.
  1. +16 −0 src/feature/gui/gui-runner.c
  2. +75 −0 src/platform/3ds/main.c
@@ -317,6 +317,13 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
mLOG(GUI_RUNNER, DEBUG, "Reseting...");
runner->core->reset(runner->core);
mLOG(GUI_RUNNER, DEBUG, "Reset!");
+
+ if (mCoreLoadState(runner->core, 0, SAVESTATE_SCREENSHOT | SAVESTATE_RTC)) {
+ struct VFile* autosave = mCoreGetState(runner->core, 0, true);
+ autosave->truncate(autosave, 0);
+ autosave->close(autosave);
+ }
+
bool running = true;
if (runner->gameLoaded) {
runner->gameLoaded(runner);
@@ -469,6 +476,14 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
mappedMemoryFree(drawState.screenshot, w * h * 4);
}
+ struct VFile* autosave = mCoreGetState(runner->core, 0, false);
+ if (autosave) {
+ autosave->close(autosave);
+ autosave = mCoreGetState(runner->core, 0, true);
+ autosave->truncate(autosave, 0);
+ autosave->close(autosave);
+ }
+
if (runner->config.port) {
mLOG(GUI_RUNNER, DEBUG, "Saving key sources...");
if (runner->keySources) {
@@ -483,6 +498,7 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
mInputMapDeinit(&runner->core->inputMap);
mLOG(GUI_RUNNER, DEBUG, "Deinitializing core...");
runner->core->deinit(runner->core);
+ runner->core = NULL;
GUIMenuItemListDeinit(&pauseMenu.items);
GUIMenuItemListDeinit(&stateSaveMenu.items);
View
@@ -6,6 +6,7 @@
#include <mgba/core/blip_buf.h>
#include <mgba/core/core.h>
+#include <mgba/core/serialize.h>
#ifdef M_CORE_GBA
#include <mgba/internal/gba/gba.h>
#include <mgba/internal/gba/input.h>
@@ -22,6 +23,7 @@
#include <mgba-util/memory.h>
#include <mgba-util/platform/3ds/3ds-vfs.h>
+#include <mgba-util/threading.h>
#include "ctr-gpu.h"
#include <3ds.h>
@@ -104,6 +106,12 @@ static C3D_Tex upscaleBufferTex;
static aptHookCookie cookie;
+static Thread autosave;
+static struct VFile* autosaveBuffer = NULL;
+static Mutex autosaveMutex;
+static Condition autosaveCond;
+static struct mCore* autosaveCore = NULL;
+
extern bool allocateRomBuffer(void);
static bool _initGpu(void) {
@@ -193,6 +201,33 @@ static void _aptHook(APT_HookType hook, void* user) {
}
}
+static void _autosaveThread(void* context) {
+ bool* running = context;
+ MutexLock(&autosaveMutex);
+ while (*running) {
+ ConditionWait(&autosaveCond, &autosaveMutex);
+ if (*running && autosaveCore) {
+ struct VFile* vf = mCoreGetState(autosaveCore, 0, true);
+ void* mem = autosaveBuffer->map(autosaveBuffer, autosaveBuffer->size(autosaveBuffer), MAP_READ);
+ vf->write(vf, mem, autosaveBuffer->size(autosaveBuffer));
+ autosaveBuffer->unmap(autosaveBuffer, mem, autosaveBuffer->size(autosaveBuffer));
+ vf->close(vf);
+ }
+ }
+ MutexUnlock(&autosaveMutex);
+}
+
+static void _tryAutosave(struct mCore* core) {
+ if (!autosaveBuffer) {
+ autosaveBuffer = VFileMemChunk(NULL, 0);
+ }
+ MutexLock(&autosaveMutex);
+ autosaveCore = core;
+ mCoreSaveStateNamed(core, autosaveBuffer, SAVESTATE_SAVEDATA | SAVESTATE_RTC | SAVESTATE_METADATA);
+ ConditionWake(&autosaveCond);
+ MutexUnlock(&autosaveMutex);
+}
+
static void _map3DSKey(struct mInputMap* map, int ctrKey, enum GBAKey key) {
mInputBindKey(map, _3DS_INPUT, __builtin_ctz(ctrKey), key);
}
@@ -425,6 +460,10 @@ static void _gameLoaded(struct mGUIRunner* runner) {
}
}
}
+
+ MutexLock(&autosaveMutex);
+ autosaveCore = runner->core;
+ MutexUnlock(&autosaveMutex);
}
static void _gameUnloaded(struct mGUIRunner* runner) {
@@ -458,6 +497,10 @@ static void _gameUnloaded(struct mGUIRunner* runner) {
default:
break;
}
+
+ MutexLock(&autosaveMutex);
+ autosaveCore = NULL;
+ MutexUnlock(&autosaveMutex);
}
static void _drawTex(struct mCore* core, bool faded) {
@@ -679,6 +722,16 @@ static void _setFrameLimiter(struct mGUIRunner* runner, bool limit) {
}
static bool _running(struct mGUIRunner* runner) {
+ static int frame = 0;
+ if (autosaveCore) {
+ ++frame;
+ if (frame == 300) {
+ _tryAutosave(autosaveCore);
+ frame = 0;
+ }
+ } else {
+ frame = 0;
+ }
return aptMainLoop();
}
@@ -1041,7 +1094,29 @@ int main() {
_map3DSKey(&runner.params.keyMap, KEY_CSTICK_UP, mGUI_INPUT_INCREASE_BRIGHTNESS);
_map3DSKey(&runner.params.keyMap, KEY_CSTICK_DOWN, mGUI_INPUT_DECREASE_BRIGHTNESS);
+ bool autosaveActive = true;
+ MutexInit(&autosaveMutex);
+ ConditionInit(&autosaveCond);
+
+ APT_SetAppCpuTimeLimit(20);
+ autosave = threadCreate(_autosaveThread, &autosaveActive, 0x4000, 0x1F, 1, true);
+
mGUIRunloop(&runner);
+
+ MutexLock(&autosaveMutex);
+ autosaveActive = false;
+ ConditionWake(&autosaveCond);
+ MutexUnlock(&autosaveMutex);
+
+ threadJoin(autosave, U64_MAX);
+
+ if (autosaveBuffer) {
+ autosaveBuffer->close(autosaveBuffer);
+ }
+
+ ConditionDeinit(&autosaveCond);
+ MutexDeinit(&autosaveMutex);
+
mGUIDeinit(&runner);
_cleanup();

0 comments on commit 0e9ba00

Please sign in to comment.