mirror of https://github.com/mgba-emu/mgba.git
3DS: Add experimental autosave
This commit is contained in:
parent
789a84d2e2
commit
0e9ba00dbf
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue