Add autosave possibility.

This commit is contained in:
Themaister 2011-02-10 21:16:59 +01:00
parent ad9a08aea6
commit 719e4942ce
9 changed files with 203 additions and 1100 deletions

View File

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

View File

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

View File

@ -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];

File diff suppressed because it is too large Load Diff

View File

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

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

View File

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