mirror of
https://github.com/libretro/RetroArch
synced 2025-04-07 13:23:32 +00:00
commit
11819e2d47
129
command.c
129
command.c
@ -1226,7 +1226,7 @@ static void command_event_load_auto_state(void)
|
|||||||
if (!path_file_exists(savestate_name_auto))
|
if (!path_file_exists(savestate_name_auto))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ret = content_load_state(savestate_name_auto);
|
ret = content_load_state(savestate_name_auto, false);
|
||||||
|
|
||||||
RARCH_LOG("Found auto savestate in: %s\n", savestate_name_auto);
|
RARCH_LOG("Found auto savestate in: %s\n", savestate_name_auto);
|
||||||
|
|
||||||
@ -1398,7 +1398,7 @@ static bool command_event_save_auto_state(void)
|
|||||||
fill_pathname_noext(savestate_name_auto, global->name.savestate,
|
fill_pathname_noext(savestate_name_auto, global->name.savestate,
|
||||||
".auto", sizeof(savestate_name_auto));
|
".auto", sizeof(savestate_name_auto));
|
||||||
|
|
||||||
ret = content_save_state((const char*)savestate_name_auto);
|
ret = content_save_state((const char*)savestate_name_auto, true);
|
||||||
RARCH_LOG("Auto save state to \"%s\" %s.\n", savestate_name_auto, ret ?
|
RARCH_LOG("Auto save state to \"%s\" %s.\n", savestate_name_auto, ret ?
|
||||||
"succeeded" : "failed");
|
"succeeded" : "failed");
|
||||||
|
|
||||||
@ -1568,27 +1568,8 @@ static void command_event_save_state(const char *path,
|
|||||||
char *s, size_t len)
|
char *s, size_t len)
|
||||||
{
|
{
|
||||||
settings_t *settings = config_get_ptr();
|
settings_t *settings = config_get_ptr();
|
||||||
char buf[PATH_MAX_LENGTH] = {0};
|
|
||||||
|
|
||||||
/* if a save state already exists rename it to .last before saving
|
if (!content_save_state(path, true))
|
||||||
* so it can be recovered */
|
|
||||||
if (path_file_exists(path))
|
|
||||||
{
|
|
||||||
strlcpy(buf, path, sizeof(buf));
|
|
||||||
snprintf(buf, sizeof(buf), "%s", path);
|
|
||||||
path_remove_extension(buf);
|
|
||||||
snprintf(buf, sizeof(buf), "%s.last", buf);
|
|
||||||
|
|
||||||
if (!content_rename_state(path, buf))
|
|
||||||
{
|
|
||||||
snprintf(s, len, "%s \"%s\".",
|
|
||||||
msg_hash_to_str(MSG_FAILED_TO_SAVE_UNDO),
|
|
||||||
path);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!content_save_state(path))
|
|
||||||
{
|
{
|
||||||
snprintf(s, len, "%s \"%s\".",
|
snprintf(s, len, "%s \"%s\".",
|
||||||
msg_hash_to_str(MSG_FAILED_TO_SAVE_STATE_TO),
|
msg_hash_to_str(MSG_FAILED_TO_SAVE_STATE_TO),
|
||||||
@ -1604,6 +1585,29 @@ static void command_event_save_state(const char *path,
|
|||||||
settings->state_slot);
|
settings->state_slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void command_event_undo_save_state(char *s, size_t len)
|
||||||
|
{
|
||||||
|
if (content_undo_save_buf_is_empty())
|
||||||
|
{
|
||||||
|
/* TODO/FIXME - use msg_hash_to_str here */
|
||||||
|
snprintf(s, len, "%s",
|
||||||
|
"No save state has been overwritten yet.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!content_undo_save_state())
|
||||||
|
{
|
||||||
|
snprintf(s, len, "%s \"%s\".",
|
||||||
|
msg_hash_to_str(MSG_FAILED_TO_UNDO_SAVE_STATE),
|
||||||
|
"RAM");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO/FIXME - use msg_hash_to_str here */
|
||||||
|
snprintf(s, len, "%s",
|
||||||
|
"Restored old save state.");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* event_load_state
|
* event_load_state
|
||||||
* @path : Path to state.
|
* @path : Path to state.
|
||||||
@ -1612,31 +1616,11 @@ static void command_event_save_state(const char *path,
|
|||||||
*
|
*
|
||||||
* Loads a state with path being @path.
|
* Loads a state with path being @path.
|
||||||
**/
|
**/
|
||||||
static void command_event_load_state(const char *path, char *s, size_t len, bool undo)
|
static void command_event_load_state(const char *path, char *s, size_t len)
|
||||||
{
|
{
|
||||||
settings_t *settings = config_get_ptr();
|
settings_t *settings = config_get_ptr();
|
||||||
char buf[PATH_MAX_LENGTH] = {0};
|
|
||||||
|
|
||||||
/* save a state before loading (unless it's an undo operation already)
|
if (!content_load_state(path, false))
|
||||||
* so the state can be recovered
|
|
||||||
*/
|
|
||||||
if (!undo)
|
|
||||||
{
|
|
||||||
strlcpy(buf, path, sizeof(buf));
|
|
||||||
snprintf(buf, sizeof(buf), "%s", path);
|
|
||||||
path_remove_extension(buf);
|
|
||||||
snprintf(buf, sizeof(buf), "%s.undo", buf);
|
|
||||||
|
|
||||||
if (!content_save_state(buf))
|
|
||||||
{
|
|
||||||
snprintf(s, len, "%s \"%s\".",
|
|
||||||
msg_hash_to_str(MSG_FAILED_TO_SAVE_UNDO),
|
|
||||||
path);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!content_load_state(path))
|
|
||||||
{
|
{
|
||||||
snprintf(s, len, "%s \"%s\".",
|
snprintf(s, len, "%s \"%s\".",
|
||||||
msg_hash_to_str(MSG_FAILED_TO_LOAD_STATE),
|
msg_hash_to_str(MSG_FAILED_TO_LOAD_STATE),
|
||||||
@ -1647,18 +1631,39 @@ static void command_event_load_state(const char *path, char *s, size_t len, bool
|
|||||||
if (settings->state_slot < 0)
|
if (settings->state_slot < 0)
|
||||||
snprintf(s, len, "%s #-1 (auto).",
|
snprintf(s, len, "%s #-1 (auto).",
|
||||||
msg_hash_to_str(MSG_LOADED_STATE_FROM_SLOT));
|
msg_hash_to_str(MSG_LOADED_STATE_FROM_SLOT));
|
||||||
else if (!undo)
|
else
|
||||||
snprintf(s, len, "%s #%d.", msg_hash_to_str(MSG_LOADED_STATE_FROM_SLOT),
|
snprintf(s, len, "%s #%d.", msg_hash_to_str(MSG_LOADED_STATE_FROM_SLOT),
|
||||||
settings->state_slot);
|
settings->state_slot);
|
||||||
else
|
}
|
||||||
snprintf(s, len, "%s #-1 (undo).", msg_hash_to_str(MSG_LOADED_STATE_FROM_SLOT));
|
|
||||||
|
static void command_event_undo_load_state(char *s, size_t len)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (content_undo_load_buf_is_empty())
|
||||||
|
{
|
||||||
|
/* TODO/FIXME - use msg_hash_to_str here */
|
||||||
|
snprintf(s, len, "%s",
|
||||||
|
"No state has been loaded yet.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!content_undo_load_state())
|
||||||
|
{
|
||||||
|
snprintf(s, len, "%s \"%s\".",
|
||||||
|
msg_hash_to_str(MSG_FAILED_TO_UNDO_LOAD_STATE),
|
||||||
|
"RAM");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO/FIXME - use msg_hash_to_str here */
|
||||||
|
snprintf(s, len, "%s",
|
||||||
|
"Undid load state.");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void command_event_main_state(unsigned cmd)
|
static void command_event_main_state(unsigned cmd)
|
||||||
{
|
{
|
||||||
retro_ctx_size_info_t info;
|
retro_ctx_size_info_t info;
|
||||||
char path[PATH_MAX_LENGTH] = {0};
|
char path[PATH_MAX_LENGTH] = {0};
|
||||||
char buf[PATH_MAX_LENGTH] = {0};
|
|
||||||
char msg[128] = {0};
|
char msg[128] = {0};
|
||||||
global_t *global = global_get_ptr();
|
global_t *global = global_get_ptr();
|
||||||
settings_t *settings = config_get_ptr();
|
settings_t *settings = config_get_ptr();
|
||||||
@ -1682,33 +1687,13 @@ static void command_event_main_state(unsigned cmd)
|
|||||||
command_event_save_state(path, msg, sizeof(msg));
|
command_event_save_state(path, msg, sizeof(msg));
|
||||||
break;
|
break;
|
||||||
case CMD_EVENT_LOAD_STATE:
|
case CMD_EVENT_LOAD_STATE:
|
||||||
command_event_load_state(path, msg, sizeof(msg), false);
|
command_event_load_state(path, msg, sizeof(msg));
|
||||||
break;
|
break;
|
||||||
case CMD_EVENT_UNDO_LOAD_STATE:
|
case CMD_EVENT_UNDO_LOAD_STATE:
|
||||||
strlcpy(buf, path, sizeof(buf));
|
command_event_undo_load_state(msg, sizeof(msg));
|
||||||
path_remove_extension(buf);
|
|
||||||
snprintf(buf, sizeof(buf), "%s.undo", buf);
|
|
||||||
|
|
||||||
if (path_file_exists(buf))
|
|
||||||
command_event_load_state(buf, msg, sizeof(msg), true);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
snprintf(msg, sizeof(msg), "%s.",
|
|
||||||
msg_hash_to_str(MSG_FAILED_TO_LOAD_UNDO));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case CMD_EVENT_UNDO_SAVE_STATE:
|
case CMD_EVENT_UNDO_SAVE_STATE:
|
||||||
strlcpy(buf, path, sizeof(buf));
|
command_event_undo_save_state(msg, sizeof(msg));
|
||||||
path_remove_extension(buf);
|
|
||||||
snprintf(buf, sizeof(buf), "%s.last", buf);
|
|
||||||
|
|
||||||
if (path_file_exists(buf))
|
|
||||||
command_event_load_state(buf, msg, sizeof(msg), true);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
snprintf(msg, sizeof(msg), "%s.",
|
|
||||||
msg_hash_to_str(MSG_FAILED_TO_LOAD_UNDO));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2103,6 +2088,7 @@ bool command_event(enum event_command cmd, void *data)
|
|||||||
break;
|
break;
|
||||||
case CMD_EVENT_CORE_DEINIT:
|
case CMD_EVENT_CORE_DEINIT:
|
||||||
{
|
{
|
||||||
|
content_reset_savestate_backups();
|
||||||
struct retro_hw_render_callback *hwr =
|
struct retro_hw_render_callback *hwr =
|
||||||
video_driver_get_hw_context();
|
video_driver_get_hw_context();
|
||||||
command_event_deinit_core(true);
|
command_event_deinit_core(true);
|
||||||
@ -2113,6 +2099,7 @@ bool command_event(enum event_command cmd, void *data)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CMD_EVENT_CORE_INIT:
|
case CMD_EVENT_CORE_INIT:
|
||||||
|
content_reset_savestate_backups();
|
||||||
if (!command_event_init_core((enum rarch_core_type*)data))
|
if (!command_event_init_core((enum rarch_core_type*)data))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
|
@ -48,7 +48,9 @@ enum event_command
|
|||||||
CMD_EVENT_LOAD_CORE_PERSIST,
|
CMD_EVENT_LOAD_CORE_PERSIST,
|
||||||
CMD_EVENT_UNLOAD_CORE,
|
CMD_EVENT_UNLOAD_CORE,
|
||||||
CMD_EVENT_LOAD_STATE,
|
CMD_EVENT_LOAD_STATE,
|
||||||
|
/* Swaps the current state with what's on the undo load buffer */
|
||||||
CMD_EVENT_UNDO_LOAD_STATE,
|
CMD_EVENT_UNDO_LOAD_STATE,
|
||||||
|
/* Rewrites a savestate on disk */
|
||||||
CMD_EVENT_UNDO_SAVE_STATE,
|
CMD_EVENT_UNDO_SAVE_STATE,
|
||||||
CMD_EVENT_SAVE_STATE,
|
CMD_EVENT_SAVE_STATE,
|
||||||
CMD_EVENT_SAVE_STATE_DECREMENT,
|
CMD_EVENT_SAVE_STATE_DECREMENT,
|
||||||
|
18
content.h
18
content.h
@ -46,16 +46,19 @@ bool content_load_ram_file(unsigned slot);
|
|||||||
bool content_save_ram_file(unsigned slot);
|
bool content_save_ram_file(unsigned slot);
|
||||||
|
|
||||||
/* Load a state from disk to memory. */
|
/* Load a state from disk to memory. */
|
||||||
bool content_load_state(const char *path);
|
bool content_load_state(const char* path, bool load_to_backup_buffer);
|
||||||
|
|
||||||
/* Save a state from memory to disk. */
|
/* Save a state from memory to disk. */
|
||||||
bool content_save_state(const char *path);
|
bool content_save_state(const char *path, bool save_to_disk);
|
||||||
|
|
||||||
/* Copy a save state. */
|
/* Copy a save state. */
|
||||||
bool content_rename_state(const char *origin, const char *dest);
|
bool content_rename_state(const char *origin, const char *dest);
|
||||||
|
|
||||||
/* Load a state backup from disk to memory. */
|
/* Undoes the last load state operation that was done */
|
||||||
bool content_undo_load_state(const char *path);
|
bool content_undo_load_state();
|
||||||
|
|
||||||
|
/* Restores the last savestate file which was overwritten */
|
||||||
|
bool content_undo_save_state();
|
||||||
|
|
||||||
bool content_does_not_need_content(void);
|
bool content_does_not_need_content(void);
|
||||||
|
|
||||||
@ -73,6 +76,13 @@ void content_deinit(void);
|
|||||||
* selected libretro core. */
|
* selected libretro core. */
|
||||||
bool content_init(void);
|
bool content_init(void);
|
||||||
|
|
||||||
|
/* Resets the state and savefile backup buffers */
|
||||||
|
bool content_reset_savestate_backups();
|
||||||
|
|
||||||
|
/* Checks if the buffers are empty */
|
||||||
|
bool content_undo_load_buf_is_empty();
|
||||||
|
bool content_undo_save_buf_is_empty();
|
||||||
|
|
||||||
RETRO_END_DECLS
|
RETRO_END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
BIN
internal buffer
Normal file
BIN
internal buffer
Normal file
Binary file not shown.
@ -148,9 +148,9 @@ const char *msg_hash_to_str_fr(enum msg_hash_enums msg)
|
|||||||
return "Impossible de charger la savestate à partir de";
|
return "Impossible de charger la savestate à partir de";
|
||||||
case MSG_FAILED_TO_SAVE_STATE_TO:
|
case MSG_FAILED_TO_SAVE_STATE_TO:
|
||||||
return "Impossible de sauvegarder la savestate vers";
|
return "Impossible de sauvegarder la savestate vers";
|
||||||
case MSG_FAILED_TO_LOAD_UNDO:
|
case MSG_FAILED_TO_UNDO_LOAD_STATE:
|
||||||
return "Aucun savestate de retour arrière trouvé";
|
return "Aucun savestate de retour arrière trouvé";
|
||||||
case MSG_FAILED_TO_SAVE_UNDO:
|
case MSG_FAILED_TO_UNDO_SAVE_STATE:
|
||||||
return "Impossible de sauvegarder les informations de savestate de retour arrière";
|
return "Impossible de sauvegarder les informations de savestate de retour arrière";
|
||||||
case MSG_FAILED_TO_SAVE_SRAM:
|
case MSG_FAILED_TO_SAVE_SRAM:
|
||||||
return "Impossible de sauvegarder la SRAM";
|
return "Impossible de sauvegarder la SRAM";
|
||||||
|
@ -2120,13 +2120,13 @@ const char *msg_hash_to_str_us(enum msg_hash_enums msg)
|
|||||||
case MSG_RESET:
|
case MSG_RESET:
|
||||||
return "Reset";
|
return "Reset";
|
||||||
case MSG_FAILED_TO_LOAD_STATE:
|
case MSG_FAILED_TO_LOAD_STATE:
|
||||||
return "Failed to load state from";
|
return "Nothing to undo.";
|
||||||
case MSG_FAILED_TO_SAVE_STATE_TO:
|
case MSG_FAILED_TO_SAVE_STATE_TO:
|
||||||
return "Failed to save state to";
|
return "Failed to save state to";
|
||||||
case MSG_FAILED_TO_LOAD_UNDO:
|
case MSG_FAILED_TO_UNDO_LOAD_STATE:
|
||||||
return "No undo state found";
|
return "Failed to undo load state.";
|
||||||
case MSG_FAILED_TO_SAVE_UNDO:
|
case MSG_FAILED_TO_UNDO_SAVE_STATE:
|
||||||
return "Failed to save undo information";
|
return "Failed to undo save state.";
|
||||||
case MSG_FAILED_TO_SAVE_SRAM:
|
case MSG_FAILED_TO_SAVE_SRAM:
|
||||||
return "Failed to save SRAM";
|
return "Failed to save SRAM";
|
||||||
case MSG_STATE_SIZE:
|
case MSG_STATE_SIZE:
|
||||||
|
@ -198,8 +198,8 @@ enum msg_hash_enums
|
|||||||
MSG_SAVED_STATE_TO_SLOT,
|
MSG_SAVED_STATE_TO_SLOT,
|
||||||
MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES,
|
MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES,
|
||||||
MSG_FAILED_TO_LOAD_STATE,
|
MSG_FAILED_TO_LOAD_STATE,
|
||||||
MSG_FAILED_TO_LOAD_UNDO,
|
MSG_FAILED_TO_UNDO_LOAD_STATE,
|
||||||
MSG_FAILED_TO_SAVE_UNDO,
|
MSG_FAILED_TO_UNDO_SAVE_STATE,
|
||||||
MSG_RESET,
|
MSG_RESET,
|
||||||
MSG_AUDIO_MUTED,
|
MSG_AUDIO_MUTED,
|
||||||
MSG_AUDIO_UNMUTED,
|
MSG_AUDIO_UNMUTED,
|
||||||
|
@ -37,6 +37,21 @@
|
|||||||
#include "../verbosity.h"
|
#include "../verbosity.h"
|
||||||
#include "tasks_internal.h"
|
#include "tasks_internal.h"
|
||||||
|
|
||||||
|
struct save_state_buf
|
||||||
|
{
|
||||||
|
void* data;
|
||||||
|
char path[PATH_MAX_LENGTH];
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Holds the previous saved state
|
||||||
|
* Can be restored to disk with undo_save_state(). */
|
||||||
|
static struct save_state_buf undo_save_buf;
|
||||||
|
|
||||||
|
/* Holds the data from before a load_state() operation
|
||||||
|
* Can be restored with undo_load_state(). */
|
||||||
|
static struct save_state_buf undo_load_buf;
|
||||||
|
|
||||||
struct sram_block
|
struct sram_block
|
||||||
{
|
{
|
||||||
unsigned type;
|
unsigned type;
|
||||||
@ -44,17 +59,172 @@ struct sram_block
|
|||||||
size_t size;
|
size_t size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* undo_load_state:
|
||||||
|
* Revert to the state before a state was loaded.
|
||||||
|
*
|
||||||
|
* Returns: true if successful, false otherwise.
|
||||||
|
**/
|
||||||
|
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),
|
||||||
|
undo_load_buf.path);
|
||||||
|
|
||||||
|
RARCH_LOG("%s: %u %s.\n",
|
||||||
|
msg_hash_to_str(MSG_STATE_SIZE),
|
||||||
|
undo_load_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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We need to make a temporary copy of the buffer, to allow the swap below */
|
||||||
|
void* temp_data = malloc(undo_load_buf.size);
|
||||||
|
size_t temp_data_size = undo_load_buf.size;
|
||||||
|
memcpy(temp_data, undo_load_buf.data, undo_load_buf.size);
|
||||||
|
|
||||||
|
serial_info.data_const = temp_data;
|
||||||
|
serial_info.size = temp_data_size;
|
||||||
|
|
||||||
|
/* Swap the current state with the backup state. This way, we can undo
|
||||||
|
what we're undoing */
|
||||||
|
content_save_state("RAM", false);
|
||||||
|
bool ret = core_unserialize(&serial_info);
|
||||||
|
|
||||||
|
/* Clean up the temporary copy */
|
||||||
|
free(temp_data);
|
||||||
|
temp_data = NULL;
|
||||||
|
temp_data_size = 0;
|
||||||
|
|
||||||
|
/* 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_UNDO_LOAD_STATE),
|
||||||
|
undo_load_buf.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* undo_save_state:
|
||||||
|
* Reverts the last save operation
|
||||||
|
*
|
||||||
|
* Returns: true if successful, false otherwise.
|
||||||
|
**/
|
||||||
|
bool content_undo_save_state()
|
||||||
|
{
|
||||||
|
bool ret = filestream_write_file(undo_save_buf.path, undo_save_buf.data, undo_save_buf.size);
|
||||||
|
|
||||||
|
/* Wipe the save file buffer as it's intended to be one use only */
|
||||||
|
undo_save_buf.path[0] = '\0';
|
||||||
|
undo_save_buf.size = 0;
|
||||||
|
if (undo_save_buf.data) {
|
||||||
|
free(undo_save_buf.data);
|
||||||
|
undo_save_buf.data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ret) {
|
||||||
|
RARCH_ERR("%s \"%s\".\n",
|
||||||
|
msg_hash_to_str(MSG_FAILED_TO_UNDO_SAVE_STATE),
|
||||||
|
undo_save_buf.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* TODO/FIXME - turn this into actual task */
|
/* TODO/FIXME - turn this into actual task */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* save_state:
|
* save_state:
|
||||||
* @path : path of saved state that shall be written to.
|
* @path : path of saved state that shall be written to.
|
||||||
*
|
* @save_to_disk: If false, saves the state onto undo_load_buf.
|
||||||
* Save a state from memory to disk.
|
* Save a state from memory to disk.
|
||||||
*
|
*
|
||||||
* Returns: true if successful, false otherwise.
|
* Returns: true if successful, false otherwise.
|
||||||
**/
|
**/
|
||||||
bool content_save_state(const char *path)
|
bool content_save_state(const char *path, bool save_to_disk)
|
||||||
{
|
{
|
||||||
retro_ctx_serialize_info_t serial_info;
|
retro_ctx_serialize_info_t serial_info;
|
||||||
retro_ctx_size_info_t info;
|
retro_ctx_size_info_t info;
|
||||||
@ -84,8 +254,43 @@ bool content_save_state(const char *path)
|
|||||||
serial_info.size = info.size;
|
serial_info.size = info.size;
|
||||||
ret = core_serialize(&serial_info);
|
ret = core_serialize(&serial_info);
|
||||||
|
|
||||||
if (ret)
|
if (ret) {
|
||||||
ret = filestream_write_file(path, data, info.size);
|
if (save_to_disk) {
|
||||||
|
if (path_file_exists(path)) {
|
||||||
|
/* Before overwritting the savestate file, load it into a buffer
|
||||||
|
to allow undo_save_state() to work */
|
||||||
|
/* TODO/FIXME - Use msg_hash_to_str here */
|
||||||
|
RARCH_LOG("%s\n",
|
||||||
|
"File already exists. Saving to backup buffer...");
|
||||||
|
|
||||||
|
content_load_state(path, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = filestream_write_file(path, data, info.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* save_to_disk is false, which means we are saving the state
|
||||||
|
in undo_load_buf to allow content_undo_load_state() to restore it */
|
||||||
|
|
||||||
|
/* If we were holding onto an old state already, clean it up first */
|
||||||
|
if (undo_load_buf.data) {
|
||||||
|
free(undo_load_buf.data);
|
||||||
|
undo_load_buf.data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
undo_load_buf.data = malloc(info.size);
|
||||||
|
if (!undo_load_buf.data) {
|
||||||
|
free(data);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(undo_load_buf.data, data, info.size);
|
||||||
|
undo_load_buf.size = info.size;
|
||||||
|
strcpy(undo_load_buf.path, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
RARCH_ERR("%s \"%s\".\n",
|
RARCH_ERR("%s \"%s\".\n",
|
||||||
@ -101,12 +306,14 @@ bool content_save_state(const char *path)
|
|||||||
/**
|
/**
|
||||||
* content_load_state:
|
* content_load_state:
|
||||||
* @path : path that state will be loaded from.
|
* @path : path that state will be loaded from.
|
||||||
*
|
* @load_to_backup_buffer: If true, the state will be loaded into undo_save_buf.
|
||||||
* Load a state from disk to memory.
|
* Load a state from disk to memory.
|
||||||
*
|
*
|
||||||
* Returns: true if successful, false otherwise.
|
* Returns: true if successful, false otherwise.
|
||||||
|
*
|
||||||
|
*
|
||||||
**/
|
**/
|
||||||
bool content_load_state(const char *path)
|
bool content_load_state(const char *path, bool load_to_backup_buffer)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
ssize_t size;
|
ssize_t size;
|
||||||
@ -130,6 +337,28 @@ bool content_load_state(const char *path)
|
|||||||
(unsigned)size,
|
(unsigned)size,
|
||||||
msg_hash_to_str(MSG_BYTES));
|
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 (load_to_backup_buffer) {
|
||||||
|
|
||||||
|
/* If we were previously backing up a file, let go of it first */
|
||||||
|
if (undo_save_buf.data) {
|
||||||
|
free(undo_save_buf.data);
|
||||||
|
undo_save_buf.data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
undo_save_buf.data = malloc(size);
|
||||||
|
if (!undo_save_buf.data)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
memcpy(undo_save_buf.data, buf, size);
|
||||||
|
undo_save_buf.size = size;
|
||||||
|
strcpy(undo_save_buf.path, path);
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (settings->block_sram_overwrite && global->savefiles
|
if (settings->block_sram_overwrite && global->savefiles
|
||||||
&& global->savefiles->size)
|
&& global->savefiles->size)
|
||||||
{
|
{
|
||||||
@ -181,6 +410,9 @@ bool content_load_state(const char *path)
|
|||||||
|
|
||||||
serial_info.data_const = buf;
|
serial_info.data_const = buf;
|
||||||
serial_info.size = size;
|
serial_info.size = size;
|
||||||
|
|
||||||
|
/* Backup the current state so we can undo this load */
|
||||||
|
content_save_state("RAM", false);
|
||||||
ret = core_unserialize(&serial_info);
|
ret = core_unserialize(&serial_info);
|
||||||
|
|
||||||
/* Flush back. */
|
/* Flush back. */
|
||||||
@ -233,3 +465,44 @@ bool content_rename_state(const char *origin, const char *dest)
|
|||||||
RARCH_LOG("Error %d renaming file %s\n", ret, origin);
|
RARCH_LOG("Error %d renaming file %s\n", ret, origin);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* TODO/FIXME: Figure out when and where this should be called.
|
||||||
|
* As it is, when e.g. closing Gambatte, we get the same printf message 4 times.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
bool content_reset_savestate_backups()
|
||||||
|
{
|
||||||
|
printf("Resetting undo buffers.\n");
|
||||||
|
|
||||||
|
if (undo_save_buf.data)
|
||||||
|
{
|
||||||
|
free(undo_save_buf.data);
|
||||||
|
undo_save_buf.data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
undo_save_buf.path[0] = '\0';
|
||||||
|
undo_save_buf.size = 0;
|
||||||
|
|
||||||
|
if (undo_load_buf.data)
|
||||||
|
{
|
||||||
|
free(undo_load_buf.data);
|
||||||
|
undo_load_buf.data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
undo_load_buf.path[0] = '\0';
|
||||||
|
undo_load_buf.size = 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool content_undo_load_buf_is_empty()
|
||||||
|
{
|
||||||
|
return undo_load_buf.data == NULL || undo_load_buf.size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool content_undo_save_buf_is_empty()
|
||||||
|
{
|
||||||
|
return undo_save_buf.data == NULL || undo_save_buf.size == 0;
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user