mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-27 02:00:41 +00:00
Add autosave possibility.
This commit is contained in:
parent
ad9a08aea6
commit
719e4942ce
2
Makefile
2
Makefile
@ -2,7 +2,7 @@ include config.mk
|
||||
|
||||
TARGET = ssnes tools/ssnes-joyconfig
|
||||
|
||||
OBJ = ssnes.o file.o driver.o settings.o dynamic.o message.o rewind.o movie.o
|
||||
OBJ = ssnes.o file.o driver.o settings.o dynamic.o message.o rewind.o movie.o autosave.o
|
||||
JOYCONFIG_OBJ = tools/ssnes-joyconfig.o conf/config_file.o
|
||||
HEADERS = $(wildcard */*.h) $(wildcard *.h)
|
||||
|
||||
|
118
autosave.c
Normal file
118
autosave.c
Normal file
@ -0,0 +1,118 @@
|
||||
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
|
||||
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
|
||||
*
|
||||
* Some code herein may be based on code found in BSNES.
|
||||
*
|
||||
* SSNES is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with SSNES.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "autosave.h"
|
||||
#include "SDL.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "general.h"
|
||||
|
||||
struct autosave
|
||||
{
|
||||
volatile bool quit;
|
||||
SDL_mutex *lock;
|
||||
|
||||
SDL_mutex *cond_lock;
|
||||
SDL_cond *cond;
|
||||
SDL_Thread *thread;
|
||||
|
||||
void *buffer;
|
||||
const void *snes_buffer;
|
||||
const char *path;
|
||||
size_t bufsize;
|
||||
unsigned interval;
|
||||
};
|
||||
|
||||
static int autosave_thread(void *data)
|
||||
{
|
||||
autosave_t *save = data;
|
||||
while (!save->quit)
|
||||
{
|
||||
autosave_lock(save);
|
||||
memcpy(save->buffer, save->snes_buffer, save->bufsize);
|
||||
autosave_unlock(save);
|
||||
|
||||
// Should probably deal with this more elegantly.
|
||||
FILE *file = fopen(save->path, "wb");
|
||||
if (file)
|
||||
{
|
||||
SSNES_LOG("Autosaving SRAM to \"%s\"\n", save->path);
|
||||
fwrite(save->buffer, 1, save->bufsize, file);
|
||||
fflush(file);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
SDL_mutexP(save->cond_lock);
|
||||
SDL_CondWaitTimeout(save->cond, save->cond_lock, save->interval * 1000);
|
||||
SDL_mutexV(save->cond_lock);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
autosave_t *autosave_new(const char *path, const void *data, size_t size, unsigned interval)
|
||||
{
|
||||
autosave_t *handle = calloc(1, sizeof(*handle));
|
||||
if (!handle)
|
||||
return NULL;
|
||||
|
||||
handle->bufsize = size;
|
||||
handle->interval = interval;
|
||||
handle->path = path;
|
||||
handle->buffer = malloc(size);
|
||||
handle->snes_buffer = data;
|
||||
|
||||
if (!handle->buffer)
|
||||
{
|
||||
free(handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
handle->lock = SDL_CreateMutex();
|
||||
handle->cond_lock = SDL_CreateMutex();
|
||||
handle->cond = SDL_CreateCond();
|
||||
|
||||
handle->thread = SDL_CreateThread(autosave_thread, handle);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void autosave_lock(autosave_t *handle)
|
||||
{
|
||||
SDL_mutexP(handle->lock);
|
||||
}
|
||||
|
||||
void autosave_unlock(autosave_t *handle)
|
||||
{
|
||||
SDL_mutexV(handle->lock);
|
||||
}
|
||||
|
||||
void autosave_free(autosave_t *handle)
|
||||
{
|
||||
handle->quit = true;
|
||||
SDL_CondSignal(handle->cond);
|
||||
SDL_WaitThread(handle->thread, NULL);
|
||||
|
||||
SDL_DestroyMutex(handle->lock);
|
||||
SDL_DestroyMutex(handle->cond_lock);
|
||||
SDL_DestroyCond(handle->cond);
|
||||
|
||||
free(handle->buffer);
|
||||
free(handle);
|
||||
}
|
31
autosave.h
Normal file
31
autosave.h
Normal file
@ -0,0 +1,31 @@
|
||||
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
|
||||
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
|
||||
*
|
||||
* Some code herein may be based on code found in BSNES.
|
||||
*
|
||||
* SSNES is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with SSNES.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __SSNES_AUTOSAVE_H
|
||||
#define __SSNES_AUTOSAVE_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct autosave autosave_t;
|
||||
|
||||
autosave_t *autosave_new(const char *path, const void *data, size_t size, unsigned interval);
|
||||
void autosave_lock(autosave_t *handle);
|
||||
void autosave_unlock(autosave_t *handle);
|
||||
void autosave_free(autosave_t *handle);
|
||||
|
||||
|
||||
#endif
|
@ -159,6 +159,9 @@ static const unsigned rewind_granularity = 1;
|
||||
// Pause gameplay when gameplay loses focus.
|
||||
static const bool pause_nonactive = true;
|
||||
|
||||
// Saves non-volatile SRAM at a regular interval. It is measured in seconds. A value of 0 disables autosave.
|
||||
static const unsigned autosave_interval = 0;
|
||||
|
||||
|
||||
////////////////////
|
||||
// Keybinds, Joypad
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "message.h"
|
||||
#include "rewind.h"
|
||||
#include "movie.h"
|
||||
#include "autosave.h"
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
@ -94,6 +95,7 @@ struct settings
|
||||
unsigned rewind_granularity;
|
||||
|
||||
bool pause_nonactive;
|
||||
unsigned autosave_interval;
|
||||
};
|
||||
|
||||
enum ssnes_game_type
|
||||
@ -172,6 +174,8 @@ struct global
|
||||
|
||||
bool is_paused;
|
||||
|
||||
autosave_t *autosave;
|
||||
|
||||
#ifdef HAVE_FFMPEG
|
||||
ffemu_t *rec;
|
||||
char record_path[256];
|
||||
|
1109
libsnes.hpp
1109
libsnes.hpp
File diff suppressed because it is too large
Load Diff
@ -131,6 +131,7 @@ static void set_defaults(void)
|
||||
g_settings.rewind_buffer_size = rewind_buffer_size;
|
||||
g_settings.rewind_granularity = rewind_granularity;
|
||||
g_settings.pause_nonactive = pause_nonactive;
|
||||
g_settings.autosave_interval = autosave_interval;
|
||||
|
||||
assert(sizeof(g_settings.input.binds[0]) >= sizeof(snes_keybinds_1));
|
||||
assert(sizeof(g_settings.input.binds[1]) >= sizeof(snes_keybinds_2));
|
||||
@ -330,6 +331,7 @@ static void parse_config_file(void)
|
||||
CONFIG_GET_INT(rewind_granularity, "rewind_granularity");
|
||||
|
||||
CONFIG_GET_BOOL(pause_nonactive, "pause_nonactive");
|
||||
CONFIG_GET_INT(autosave_interval, "autosave_interval");
|
||||
|
||||
read_keybinds(conf);
|
||||
|
||||
|
30
ssnes.c
30
ssnes.c
@ -734,6 +734,25 @@ static void deinit_movie(void)
|
||||
bsv_movie_free(g_extern.bsv_movie);
|
||||
}
|
||||
|
||||
static void init_autosave(void)
|
||||
{
|
||||
if (g_settings.autosave_interval > 0)
|
||||
{
|
||||
g_extern.autosave = autosave_new(g_extern.savefile_name_srm,
|
||||
psnes_get_memory_data(SNES_MEMORY_CARTRIDGE_RAM),
|
||||
psnes_get_memory_size(SNES_MEMORY_CARTRIDGE_RAM),
|
||||
g_settings.autosave_interval);
|
||||
if (!g_extern.autosave)
|
||||
SSNES_WARN("Could not initialize autosave.\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void deinit_autosave(void)
|
||||
{
|
||||
if (g_extern.autosave)
|
||||
autosave_free(g_extern.autosave);
|
||||
}
|
||||
|
||||
static void fill_pathnames(void)
|
||||
{
|
||||
if (!g_extern.bsv_movie_playback)
|
||||
@ -1069,6 +1088,7 @@ int main(int argc, char *argv[])
|
||||
init_recording();
|
||||
#endif
|
||||
|
||||
init_autosave();
|
||||
|
||||
// Main loop
|
||||
for(;;)
|
||||
@ -1083,7 +1103,15 @@ int main(int argc, char *argv[])
|
||||
|
||||
// Run libsnes for one frame.
|
||||
if (!g_extern.is_paused)
|
||||
{
|
||||
if (g_extern.autosave)
|
||||
autosave_lock(g_extern.autosave);
|
||||
|
||||
psnes_run();
|
||||
|
||||
if (g_extern.autosave)
|
||||
autosave_unlock(g_extern.autosave);
|
||||
}
|
||||
else
|
||||
{
|
||||
input_poll();
|
||||
@ -1099,6 +1127,8 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
deinit_autosave();
|
||||
|
||||
#ifdef HAVE_FFMPEG
|
||||
deinit_recording();
|
||||
#endif
|
||||
|
@ -214,3 +214,7 @@
|
||||
|
||||
# Pause gameplay when window focus is lost.
|
||||
# pause_nonactive = true
|
||||
|
||||
# Autosaves the non-volatile SRAM at a regular interval. This is disabled by default unless set otherwise.
|
||||
# The interval is measured in seconds. A value of 0 disables autosave.
|
||||
# autosave_interval =
|
||||
|
Loading…
Reference in New Issue
Block a user