From a86cf6b99db08227267e8c53518d2ed819abe1c6 Mon Sep 17 00:00:00 2001 From: radius Date: Thu, 2 Jun 2016 23:33:52 -0500 Subject: [PATCH 1/8] initial implementation of undo save state --- Makefile | 3 --- command.c | 31 +++++++++++++++++++++++++++++-- command.h | 1 + content.h | 3 +++ menu/cbs/menu_cbs_ok.c | 13 ++++++++++++- menu/intl/menu_hash_us.c | 4 ++++ menu/menu_displaylist.c | 5 +++++ menu/menu_hash.h | 3 +++ 8 files changed, 57 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 33d4fc6b10..9a445a1720 100644 --- a/Makefile +++ b/Makefile @@ -54,9 +54,6 @@ ifeq ($(DEBUG), 1) OPTIMIZE_FLAG = -O0 -g else OPTIMIZE_FLAG = -O3 -ffast-math -ifneq ($(findstring Win32,$(OS)),) - LDFLAGS += -mwindows -endif endif CFLAGS += -Wall $(OPTIMIZE_FLAG) $(INCLUDE_DIRS) $(DEBUG_FLAG) -I. diff --git a/command.c b/command.c index 5e366a3211..de9ef8f512 100644 --- a/command.c +++ b/command.c @@ -1494,9 +1494,26 @@ static void command_event_save_state(const char *path, * * Loads a state with path being @path. **/ -static void command_event_load_state(const char *path, char *s, size_t len) +static void command_event_load_state(const char *path, char *s, size_t len, bool undo) { settings_t *settings = config_get_ptr(); + char buf[PATH_MAX_LENGTH] = {0}; + + if (!undo) { + /* TODO: Fence with a setting */ + 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\".", + "Failed to save undo information\n", + buf); + return; + } + } if (!content_load_state(path)) { @@ -1518,6 +1535,7 @@ static void command_event_main_state(unsigned cmd) { retro_ctx_size_info_t info; char path[PATH_MAX_LENGTH] = {0}; + char buf[PATH_MAX_LENGTH] = {0}; char msg[128] = {0}; global_t *global = global_get_ptr(); settings_t *settings = config_get_ptr(); @@ -1541,7 +1559,13 @@ static void command_event_main_state(unsigned cmd) command_event_save_state(path, msg, sizeof(msg)); break; case CMD_EVENT_LOAD_STATE: - command_event_load_state(path, msg, sizeof(msg)); + command_event_load_state(path, msg, sizeof(msg), false); + break; + case CMD_EVENT_UNDO_LOAD_STATE: + strlcpy(buf, path, sizeof(buf)); + path_remove_extension(buf); + snprintf(buf, sizeof(buf), "%s.undo", buf); + command_event_load_state(buf, msg, sizeof(msg), true); break; } } @@ -1661,6 +1685,9 @@ bool command_event(enum event_command cmd, void *data) return false; #endif + command_event_main_state(cmd); + break; + case CMD_EVENT_UNDO_LOAD_STATE: command_event_main_state(cmd); break; case CMD_EVENT_RESIZE_WINDOWED_SCALE: diff --git a/command.h b/command.h index 59e6b4dfbc..1d6c76e8a0 100644 --- a/command.h +++ b/command.h @@ -48,6 +48,7 @@ enum event_command CMD_EVENT_LOAD_CORE_PERSIST, CMD_EVENT_UNLOAD_CORE, CMD_EVENT_LOAD_STATE, + CMD_EVENT_UNDO_LOAD_STATE, CMD_EVENT_SAVE_STATE, CMD_EVENT_SAVE_STATE_DECREMENT, CMD_EVENT_SAVE_STATE_INCREMENT, diff --git a/content.h b/content.h index 1bf0282447..d3dc23b098 100644 --- a/content.h +++ b/content.h @@ -51,6 +51,9 @@ bool content_load_state(const char *path); /* Save a state from memory to disk. */ bool content_save_state(const char *path); +/* Load a state backup from disk to memory. */ +bool content_undo_load_state(const char *path); + bool content_does_not_need_content(void); void content_set_does_not_need_content(void); diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index 6eec2723eb..91f35b3618 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -1272,8 +1272,15 @@ static int action_ok_load_state(const char *path, if (generic_action_ok_command(CMD_EVENT_LOAD_STATE) == -1) return menu_cbs_exit(); return generic_action_ok_command(CMD_EVENT_RESUME); - } +} +static int action_ok_undo_load_state(const char *path, + const char *label, unsigned type, size_t idx, size_t entry_idx) +{ + if (generic_action_ok_command(CMD_EVENT_UNDO_LOAD_STATE) == -1) + return menu_cbs_exit(); + return generic_action_ok_command(CMD_EVENT_RESUME); +} static int action_ok_save_state(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) @@ -2373,6 +2380,10 @@ static int menu_cbs_init_bind_ok_compare_label(menu_file_list_cbs_t *cbs, case MENU_LABEL_LOADSTATE: BIND_ACTION_OK(cbs, action_ok_load_state); break; + case MENU_LABEL_UNDOLOADSTATE: + printf ("first test\n"); + BIND_ACTION_OK(cbs, action_ok_undo_load_state); + break; case MENU_LABEL_RESUME_CONTENT: BIND_ACTION_OK(cbs, action_ok_resume_content); break; diff --git a/menu/intl/menu_hash_us.c b/menu/intl/menu_hash_us.c index 96872e2bfd..9b506333eb 100644 --- a/menu/intl/menu_hash_us.c +++ b/menu/intl/menu_hash_us.c @@ -658,6 +658,8 @@ static const char *menu_hash_to_str_us_label(uint32_t hash) return "savestate"; case MENU_LABEL_LOAD_STATE: return "loadstate"; + case MENU_LABEL_UNDO_LOAD_STATE: + return "undoloadstate"; case MENU_LABEL_RESUME_CONTENT: return "resume_content"; case MENU_LABEL_INPUT_DRIVER: @@ -1374,6 +1376,8 @@ const char *menu_hash_to_str_us(uint32_t hash) return "Save State"; case MENU_LABEL_VALUE_LOAD_STATE: return "Load State"; + case MENU_LABEL_VALUE_UNDO_LOAD_STATE: + return "Undo Load State"; case MENU_LABEL_VALUE_RESUME_CONTENT: return "Resume"; case MENU_LABEL_VALUE_INPUT_DRIVER: diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 2ddabd5018..ac3ca1a4da 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -2276,6 +2276,11 @@ static int menu_displaylist_parse_load_content_settings( menu_hash_to_str(MENU_LABEL_LOAD_STATE), MENU_SETTING_ACTION_LOADSTATE, 0, 0); + menu_entries_add(info->list, + menu_hash_to_str(MENU_LABEL_VALUE_UNDO_LOAD_STATE), + menu_hash_to_str(MENU_LABEL_UNDO_LOAD_STATE), + MENU_SETTING_ACTION_LOADSTATE, 0, 0); + menu_entries_add(info->list, menu_hash_to_str(MENU_LABEL_VALUE_CORE_OPTIONS), menu_hash_to_str(MENU_LABEL_CORE_OPTIONS), diff --git a/menu/menu_hash.h b/menu/menu_hash.h index 32d11e8491..64224ea6e2 100644 --- a/menu/menu_hash.h +++ b/menu/menu_hash.h @@ -298,8 +298,10 @@ extern "C" { #define MENU_LABEL_VALUE_NO_CORES_AVAILABLE 0xe16bfd0dU #define MENU_LABEL_SAVE_STATE 0x3a4849b5U #define MENU_LABEL_VALUE_LOAD_STATE 0xd23ba706U +#define MENU_LABEL_VALUE_UNDO_LOAD_STATE 0xc83f09fcU #define MENU_LABEL_VALUE_SAVE_STATE 0x3e182415U #define MENU_LABEL_LOAD_STATE 0xa39eb286U +#define MENU_LABEL_UNDO_LOAD_STATE 0x464aaf5cU #define MENU_LABEL_REWIND 0x1931d5aeU #define MENU_LABEL_NETPLAY_FLIP_PLAYERS 0x801425abU #define MENU_LABEL_CHEAT_INDEX_MINUS 0x57f58b6cU @@ -955,6 +957,7 @@ extern "C" { #define MENU_LABEL_CUSTOM_BIND_DEFAULTS 0xe88f7b13U #define MENU_LABEL_SAVESTATE 0x3a4849b5U #define MENU_LABEL_LOADSTATE 0xa39eb286U +#define MENU_LABEL_UNDOLOADSTATE 0x464aaf5cU #define MENU_LABEL_RESUME_CONTENT 0xd9f088b0U #define MENU_LABEL_VALUE_RESUME_CONTENT 0xae6e5911U #define MENU_LABEL_VALUE_RESUME 0xce8ac2f6U From 7fb9ec52238fcf64585431844093fa4fa9630673 Mon Sep 17 00:00:00 2001 From: radius Date: Thu, 2 Jun 2016 23:34:21 -0500 Subject: [PATCH 2/8] remove stray comment --- menu/cbs/menu_cbs_ok.c | 1 - 1 file changed, 1 deletion(-) diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index 91f35b3618..04069bef13 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -2381,7 +2381,6 @@ static int menu_cbs_init_bind_ok_compare_label(menu_file_list_cbs_t *cbs, BIND_ACTION_OK(cbs, action_ok_load_state); break; case MENU_LABEL_UNDOLOADSTATE: - printf ("first test\n"); BIND_ACTION_OK(cbs, action_ok_undo_load_state); break; case MENU_LABEL_RESUME_CONTENT: From 04fc5d042fb598389a6f6a5cfe81310dc9de7ac0 Mon Sep 17 00:00:00 2001 From: radius Date: Thu, 2 Jun 2016 23:35:57 -0500 Subject: [PATCH 3/8] fix osd message --- command.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/command.c b/command.c index de9ef8f512..eea1fd5ddd 100644 --- a/command.c +++ b/command.c @@ -1526,9 +1526,11 @@ static void command_event_load_state(const char *path, char *s, size_t len, bool if (settings->state_slot < 0) snprintf(s, len, "%s #-1 (auto).", msg_hash_to_str(MSG_LOADED_STATE_FROM_SLOT)); - else + else if (!undo) snprintf(s, len, "%s #%d.", msg_hash_to_str(MSG_LOADED_STATE_FROM_SLOT), settings->state_slot); + else + snprintf(s, len, "%s #-1 (undo).", msg_hash_to_str(MSG_LOADED_STATE_FROM_SLOT)); } static void command_event_main_state(unsigned cmd) From cd615b3e795c2cc40772b20026ff8068fa1a993c Mon Sep 17 00:00:00 2001 From: radius Date: Thu, 2 Jun 2016 23:38:04 -0500 Subject: [PATCH 4/8] fix mwindows flag on the makefile --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 9a445a1720..082939d858 100644 --- a/Makefile +++ b/Makefile @@ -54,6 +54,9 @@ ifeq ($(DEBUG), 1) OPTIMIZE_FLAG = -O0 -g else OPTIMIZE_FLAG = -O3 -ffast-math + ifneq ($(findstring Win32,$(OS)),) + LDFLAGS += -mwindows + endif endif CFLAGS += -Wall $(OPTIMIZE_FLAG) $(INCLUDE_DIRS) $(DEBUG_FLAG) -I. From aa81de0ca033c4a84e08bf171daed706dbf20f8c Mon Sep 17 00:00:00 2001 From: radius Date: Sat, 4 Jun 2016 12:07:11 -0500 Subject: [PATCH 5/8] fix nit --- command.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/command.c b/command.c index eea1fd5ddd..14c0612ad0 100644 --- a/command.c +++ b/command.c @@ -1499,7 +1499,8 @@ static void command_event_load_state(const char *path, char *s, size_t len, bool settings_t *settings = config_get_ptr(); char buf[PATH_MAX_LENGTH] = {0}; - if (!undo) { + if (!undo) + { /* TODO: Fence with a setting */ strlcpy(buf, path, sizeof(buf)); snprintf(buf, sizeof(buf), "%s", path); From 28aafddd91facba8bf418bddbfb594fc811c272d Mon Sep 17 00:00:00 2001 From: radius Date: Sat, 4 Jun 2016 12:38:55 -0500 Subject: [PATCH 6/8] copy the old save state before making a new savestate --- command.c | 12 ++++++++++++ content.h | 3 +++ tasks/task_save_state.c | 18 ++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/command.c b/command.c index 14c0612ad0..e6757b1928 100644 --- a/command.c +++ b/command.c @@ -1469,6 +1469,18 @@ static void command_event_save_state(const char *path, char *s, size_t len) { settings_t *settings = config_get_ptr(); + char buf[PATH_MAX_LENGTH] = {0}; + + if (path_file_exists(path)) + { + /* TODO: Fence with a setting */ + strlcpy(buf, path, sizeof(buf)); + snprintf(buf, sizeof(buf), "%s", path); + path_remove_extension(buf); + snprintf(buf, sizeof(buf), "%s.last", buf); + + content_rename_state(path, buf); + } if (!content_save_state(path)) { diff --git a/content.h b/content.h index d3dc23b098..432fbbd36e 100644 --- a/content.h +++ b/content.h @@ -51,6 +51,9 @@ bool content_load_state(const char *path); /* Save a state from memory to disk. */ bool content_save_state(const char *path); +/* 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); diff --git a/tasks/task_save_state.c b/tasks/task_save_state.c index e732f667de..21bda19e52 100644 --- a/tasks/task_save_state.c +++ b/tasks/task_save_state.c @@ -18,10 +18,12 @@ #include #include #include +#include #include #include #include +#include #include "../core.h" #include "../msg_hash.h" @@ -210,3 +212,19 @@ error: free(buf); return false; } + +bool content_rename_state(const char *origin, const char *dest) +{ + int ret = 0; + if (path_file_exists(dest)) + unlink(dest); + + ret = rename (origin, dest); + if (!ret) + return true; + else + { + RARCH_LOG ("Error %d renaming file %s", ret, origin); + return false; + } +} From 93acf0caa9bfbd079c5720a8ee0bd33f5b804fbd Mon Sep 17 00:00:00 2001 From: radius Date: Sat, 4 Jun 2016 12:42:45 -0500 Subject: [PATCH 7/8] check if saving undo data was successful --- command.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/command.c b/command.c index e6757b1928..2f145803ad 100644 --- a/command.c +++ b/command.c @@ -1479,7 +1479,13 @@ static void command_event_save_state(const char *path, path_remove_extension(buf); snprintf(buf, sizeof(buf), "%s.last", buf); - content_rename_state(path, buf); + if (!content_rename_state(path, buf)) + { + snprintf(s, len, "%s \"%s\".", + "Failed to save undo information\n", + buf); + return; + } } if (!content_save_state(path)) @@ -1519,7 +1525,7 @@ static void command_event_load_state(const char *path, char *s, size_t len, bool path_remove_extension(buf); snprintf(buf, sizeof(buf), "%s.undo", buf); - if(!content_save_state(buf)) + if (!content_save_state(buf)) { snprintf(s, len, "%s \"%s\".", "Failed to save undo information\n", From 20540a8f421f2aacc67b35072b5a001af270f6fd Mon Sep 17 00:00:00 2001 From: radius Date: Sat, 4 Jun 2016 14:34:06 -0500 Subject: [PATCH 8/8] add menu entry for undo save state --- command.c | 9 +++++++++ command.h | 1 + menu/cbs/menu_cbs_ok.c | 15 +++++++++++++-- menu/intl/menu_hash_us.c | 4 ++++ menu/menu_displaylist.c | 5 +++++ menu/menu_hash.h | 3 +++ 6 files changed, 35 insertions(+), 2 deletions(-) diff --git a/command.c b/command.c index 2f145803ad..b3f482472b 100644 --- a/command.c +++ b/command.c @@ -1588,6 +1588,12 @@ static void command_event_main_state(unsigned cmd) snprintf(buf, sizeof(buf), "%s.undo", buf); command_event_load_state(buf, msg, sizeof(msg), true); break; + case CMD_EVENT_UNDO_SAVE_STATE: + strlcpy(buf, path, sizeof(buf)); + path_remove_extension(buf); + snprintf(buf, sizeof(buf), "%s.last", buf); + command_event_load_state(buf, msg, sizeof(msg), true); + break; } } else @@ -1711,6 +1717,9 @@ bool command_event(enum event_command cmd, void *data) case CMD_EVENT_UNDO_LOAD_STATE: command_event_main_state(cmd); break; + case CMD_EVENT_UNDO_SAVE_STATE: + command_event_main_state(cmd); + break; case CMD_EVENT_RESIZE_WINDOWED_SCALE: { unsigned idx = 0; diff --git a/command.h b/command.h index 1d6c76e8a0..205728fde4 100644 --- a/command.h +++ b/command.h @@ -49,6 +49,7 @@ enum event_command CMD_EVENT_UNLOAD_CORE, CMD_EVENT_LOAD_STATE, CMD_EVENT_UNDO_LOAD_STATE, + CMD_EVENT_UNDO_SAVE_STATE, CMD_EVENT_SAVE_STATE, CMD_EVENT_SAVE_STATE_DECREMENT, CMD_EVENT_SAVE_STATE_INCREMENT, diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index 04069bef13..3f3f8726e5 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -1274,6 +1274,14 @@ static int action_ok_load_state(const char *path, return generic_action_ok_command(CMD_EVENT_RESUME); } +static int action_ok_save_state(const char *path, + const char *label, unsigned type, size_t idx, size_t entry_idx) +{ + if (generic_action_ok_command(CMD_EVENT_SAVE_STATE) == -1) + return menu_cbs_exit(); + return generic_action_ok_command(CMD_EVENT_RESUME); +} + static int action_ok_undo_load_state(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) { @@ -1282,10 +1290,10 @@ static int action_ok_undo_load_state(const char *path, return generic_action_ok_command(CMD_EVENT_RESUME); } -static int action_ok_save_state(const char *path, +static int action_ok_undo_save_state(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) { - if (generic_action_ok_command(CMD_EVENT_SAVE_STATE) == -1) + if (generic_action_ok_command(CMD_EVENT_UNDO_SAVE_STATE) == -1) return menu_cbs_exit(); return generic_action_ok_command(CMD_EVENT_RESUME); } @@ -2383,6 +2391,9 @@ static int menu_cbs_init_bind_ok_compare_label(menu_file_list_cbs_t *cbs, case MENU_LABEL_UNDOLOADSTATE: BIND_ACTION_OK(cbs, action_ok_undo_load_state); break; + case MENU_LABEL_UNDOSAVESTATE: + BIND_ACTION_OK(cbs, action_ok_undo_save_state); + break; case MENU_LABEL_RESUME_CONTENT: BIND_ACTION_OK(cbs, action_ok_resume_content); break; diff --git a/menu/intl/menu_hash_us.c b/menu/intl/menu_hash_us.c index 9b506333eb..b9b79900bd 100644 --- a/menu/intl/menu_hash_us.c +++ b/menu/intl/menu_hash_us.c @@ -660,6 +660,8 @@ static const char *menu_hash_to_str_us_label(uint32_t hash) return "loadstate"; case MENU_LABEL_UNDO_LOAD_STATE: return "undoloadstate"; + case MENU_LABEL_UNDO_SAVE_STATE: + return "undosavestate"; case MENU_LABEL_RESUME_CONTENT: return "resume_content"; case MENU_LABEL_INPUT_DRIVER: @@ -1378,6 +1380,8 @@ const char *menu_hash_to_str_us(uint32_t hash) return "Load State"; case MENU_LABEL_VALUE_UNDO_LOAD_STATE: return "Undo Load State"; + case MENU_LABEL_VALUE_UNDO_SAVE_STATE: + return "Undo Save State"; case MENU_LABEL_VALUE_RESUME_CONTENT: return "Resume"; case MENU_LABEL_VALUE_INPUT_DRIVER: diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index ac3ca1a4da..18edcdc60c 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -2281,6 +2281,11 @@ static int menu_displaylist_parse_load_content_settings( menu_hash_to_str(MENU_LABEL_UNDO_LOAD_STATE), MENU_SETTING_ACTION_LOADSTATE, 0, 0); + menu_entries_add(info->list, + menu_hash_to_str(MENU_LABEL_VALUE_UNDO_SAVE_STATE), + menu_hash_to_str(MENU_LABEL_UNDO_SAVE_STATE), + MENU_SETTING_ACTION_LOADSTATE, 0, 0); + menu_entries_add(info->list, menu_hash_to_str(MENU_LABEL_VALUE_CORE_OPTIONS), menu_hash_to_str(MENU_LABEL_CORE_OPTIONS), diff --git a/menu/menu_hash.h b/menu/menu_hash.h index 64224ea6e2..a3f4c3f183 100644 --- a/menu/menu_hash.h +++ b/menu/menu_hash.h @@ -299,9 +299,11 @@ extern "C" { #define MENU_LABEL_SAVE_STATE 0x3a4849b5U #define MENU_LABEL_VALUE_LOAD_STATE 0xd23ba706U #define MENU_LABEL_VALUE_UNDO_LOAD_STATE 0xc83f09fcU +#define MENU_LABEL_VALUE_UNDO_SAVE_STATE 0x341b870bU #define MENU_LABEL_VALUE_SAVE_STATE 0x3e182415U #define MENU_LABEL_LOAD_STATE 0xa39eb286U #define MENU_LABEL_UNDO_LOAD_STATE 0x464aaf5cU +#define MENU_LABEL_UNDO_SAVE_STATE 0xdcf4468bU #define MENU_LABEL_REWIND 0x1931d5aeU #define MENU_LABEL_NETPLAY_FLIP_PLAYERS 0x801425abU #define MENU_LABEL_CHEAT_INDEX_MINUS 0x57f58b6cU @@ -958,6 +960,7 @@ extern "C" { #define MENU_LABEL_SAVESTATE 0x3a4849b5U #define MENU_LABEL_LOADSTATE 0xa39eb286U #define MENU_LABEL_UNDOLOADSTATE 0x464aaf5cU +#define MENU_LABEL_UNDOSAVESTATE 0xdcf4468bU #define MENU_LABEL_RESUME_CONTENT 0xd9f088b0U #define MENU_LABEL_VALUE_RESUME_CONTENT 0xae6e5911U #define MENU_LABEL_VALUE_RESUME 0xce8ac2f6U