3DS: Add experimental autosave

This commit is contained in:
Vicki Pfau 2018-01-10 00:42:09 -08:00
parent 789a84d2e2
commit 0e9ba00dbf
2 changed files with 91 additions and 0 deletions

View File

@ -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 File

@ -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();