Change task_save_state so we save a single state and a single savestate

file in memory, allowing to undo a loadstate/savestate once.
This commit is contained in:
Arzed Five 2016-06-07 18:33:01 +01:00
parent 14fce400ce
commit 70b1f385e8
3 changed files with 212 additions and 6 deletions

View file

@ -1580,6 +1580,7 @@ static void command_event_save_state(const char *path,
settings_t *settings = config_get_ptr();
char buf[PATH_MAX_LENGTH] = {0};
#if 0
/* if a save state already exists rename it to .last before saving
* so it can be recovered */
if (path_file_exists(path))
@ -1597,6 +1598,7 @@ static void command_event_save_state(const char *path,
return;
}
}
#endif
if (!content_save_state(path))
{

View file

@ -46,16 +46,20 @@ bool content_load_ram_file(unsigned slot);
bool content_save_ram_file(unsigned slot);
/* Load a state from disk to memory. */
bool content_load_state(const char *path);
bool content_load_state(const char* path);
bool content_load_state_with_backup(const char* path, bool save_to_backup_buffer)
/* Save a state from memory to disk. */
bool content_save_state(const char *path);
bool content_save_state_with_backup(const char *path, bool save_to_disk)
/* Copy a save state. */
bool content_rename_state(const char *origin, const char *dest);
/* Load a state backup from disk to memory. */
bool content_undo_load_state(const char *path);
bool content_undo_load_state();
bool content_undo_save_state();
bool content_does_not_need_content(void);

View file

@ -30,6 +30,26 @@
#include "../verbosity.h"
#include "tasks_internal.h"
struct save_state_buf
{
void* data;
char path[PATH_MAX_LENGTH];
size_t size;
};
/*
Holds a savestate which was stored on disk and was lost when
content_save_state() wrote over it.
Can be restored to disk with undo_save_state().
*/
static struct save_state_buf old_save_file;
/*
Represents the state which was lost when load_state() was called.
Can be restored with undo_load_state().
*/
static struct save_state_buf old_state_buf;
struct sram_block
{
unsigned type;
@ -37,6 +57,141 @@ struct sram_block
size_t size;
};
bool content_undo_load_state()
{
unsigned i;
//ssize_t size;
retro_ctx_serialize_info_t serial_info;
unsigned num_blocks = 0;
//void *buf = NULL;
struct sram_block *blocks = NULL;
settings_t *settings = config_get_ptr();
global_t *global = global_get_ptr();
//bool ret = filestream_read_file(path, &buf, &size);
RARCH_LOG("%s: \"%s\".\n",
msg_hash_to_str(MSG_LOADING_STATE),
"from internal buffer");
if (old_state_buf.size == 0)
return true;
RARCH_LOG("%s: %u %s.\n",
msg_hash_to_str(MSG_STATE_SIZE),
old_state_buf.size,
msg_hash_to_str(MSG_BYTES));
/* TODO/FIXME - This checking of SRAM overwrite, the backing up of it and
its flushing could all be in their own functions... */
if (settings->block_sram_overwrite && global->savefiles
&& global->savefiles->size)
{
RARCH_LOG("%s.\n",
msg_hash_to_str(MSG_BLOCKING_SRAM_OVERWRITE));
blocks = (struct sram_block*)
calloc(global->savefiles->size, sizeof(*blocks));
if (blocks)
{
num_blocks = global->savefiles->size;
for (i = 0; i < num_blocks; i++)
blocks[i].type = global->savefiles->elems[i].attr.i;
}
}
for (i = 0; i < num_blocks; i++)
{
retro_ctx_memory_info_t mem_info;
mem_info.id = blocks[i].type;
core_get_memory(&mem_info);
blocks[i].size = mem_info.size;
}
for (i = 0; i < num_blocks; i++)
if (blocks[i].size)
blocks[i].data = malloc(blocks[i].size);
/* Backup current SRAM which is overwritten by unserialize. */
for (i = 0; i < num_blocks; i++)
{
if (blocks[i].data)
{
retro_ctx_memory_info_t mem_info;
const void *ptr = NULL;
mem_info.id = blocks[i].type;
core_get_memory(&mem_info);
ptr = mem_info.data;
if (ptr)
memcpy(blocks[i].data, ptr, blocks[i].size);
}
}
serial_info.data_const = old_state_buf.data;
serial_info.size = old_state_buf.size;
bool ret = core_unserialize(&serial_info);
/* Flush back. */
for (i = 0; i < num_blocks; i++)
{
if (blocks[i].data)
{
retro_ctx_memory_info_t mem_info;
void *ptr = NULL;
mem_info.id = blocks[i].type;
core_get_memory(&mem_info);
ptr = mem_info.data;
if (ptr)
memcpy(ptr, blocks[i].data, blocks[i].size);
}
}
for (i = 0; i < num_blocks; i++)
free(blocks[i].data);
free(blocks);
if (!ret)
RARCH_ERR("%s \"%s\".\n",
msg_hash_to_str(MSG_FAILED_TO_LOAD_STATE),
"from internal buffer");
/* Wipe the old state buffer, it's meant to be one use only */
old_state_buf.path[0] = '\0';
if (old_state_buf.data) {
free(old_state_buf.data);
old_state_buf.data = NULL;
}
old_state_buf.data = 0;
return ret;
}
bool content_undo_save_state()
{
filestream_write_file(old_save_file.path, old_save_file.data, old_save_file.size);
/* Wipe the save file buffer as it's intended to be one use only */
old_save_file.path[0] = '\0';
if (old_save_file.data) {
free(old_save_file.data);
old_save_file.data = NULL;
}
old_save_file.data = 0;
return true;
}
/* TODO/FIXME - turn this into actual task */
/**
@ -47,7 +202,8 @@ struct sram_block
*
* Returns: true if successful, false otherwise.
**/
bool content_save_state(const char *path)
bool content_save_state(const char *path) { content_save_state_with_backup(path, true);}
bool content_save_state_with_backup(const char *path, bool save_to_disk)
{
retro_ctx_serialize_info_t serial_info;
retro_ctx_size_info_t info;
@ -77,8 +233,30 @@ bool content_save_state(const char *path)
serial_info.size = info.size;
ret = core_serialize(&serial_info);
if (ret)
ret = filestream_write_file(path, data, info.size);
if (ret) {
if (save_to_disk) {
if (path_file_exists(path)) {
content_load_state(path, true);
}
ret = filestream_write_file(path, data, info.size);
}
/* save_to_disk is false, which means we are saving the state
in old_state_buf to allow content_undo_load_state() to restore it */
else
{
old_state_buf.path = NULL;
/* If we were holding onto an old state already, clean it up first */
if (old_state_buf.data) {
free(old_state_buf.data);
old_state_buf.data = NULL;
}
old_state_buf.data = malloc(info.size);
memcpy(old_state_buf.data, data);
}
}
else
{
RARCH_ERR("%s \"%s\".\n",
@ -99,7 +277,8 @@ bool content_save_state(const char *path)
*
* Returns: true if successful, false otherwise.
**/
bool content_load_state(const char *path)
bool content_load_state(const char* path) { content_load_state_with_backup(path, false); }
bool content_load_state_with_backup(const char *path, bool save_to_backup_buffer)
{
unsigned i;
ssize_t size;
@ -123,6 +302,24 @@ bool content_load_state(const char *path)
(unsigned)size,
msg_hash_to_str(MSG_BYTES));
/* This means we're backing up the file in memory, so content_undo_save_state()
can restore it */
if (save_to_backup_buffer) {
strcpy(old_save_file.path, path);
/* If we were previously backing up a file, let go of it first */
if (old_save_file.data) {
free(old_save_file.data);
old_save_file.data = NULL;
}
old_save_file.data = malloc(size);
memcpy(old_save_file.data, buf);
free(buf);
return true;
}
if (settings->block_sram_overwrite && global->savefiles
&& global->savefiles->size)
{
@ -174,6 +371,9 @@ bool content_load_state(const char *path)
serial_info.data_const = buf;
serial_info.size = size;
/* Backup the current state so we can undo this load */
content_save_state(NULL, true);
ret = core_unserialize(&serial_info);
/* Flush back. */