From 2125770236c75dc262462300eea44a0515443de1 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 2 Mar 2023 15:52:22 -0800 Subject: [PATCH] Replay UI support (#15048) * Add bsv replay controls (not yet fully implemented), remove toggle see notes in task_movie.c, make sure command.c calls the right functions, check retroarch.c and other todos. bsv files are also now stored with states, not saves. * Compilation fixes * Added command impls for play and record replay, and some code in load state to do the right thing there * Guard some parts of the new code with HAVE_BSV_MOVIE * wip, menu fixes * more menu fixes, osd for movie errors, halt recording properly * Menu and label fixes * move bsvs to own file suffix series under savestates, fix recording and playback command validity checks * Fix replay autoincrement * fix endif placement, whoops --------- Co-authored-by: Joseph C. Osborn --- command.c | 191 ++++++++++++++++++++++++++++++++++- command.h | 26 ++++- config.def.h | 16 +++ config.def.keybinds.h | 126 +++++++++++++++++++---- configuration.c | 17 +++- configuration.h | 4 + input/input_defines.h | 7 +- input/input_driver.h | 1 - intl/msg_hash_ar.h | 8 -- intl/msg_hash_ca.h | 8 -- intl/msg_hash_chs.c | 8 -- intl/msg_hash_chs.h | 8 -- intl/msg_hash_cht.h | 8 -- intl/msg_hash_cs.h | 8 -- intl/msg_hash_de.h | 8 -- intl/msg_hash_el.c | 4 - intl/msg_hash_es.h | 8 -- intl/msg_hash_fi.h | 8 -- intl/msg_hash_fr.h | 8 -- intl/msg_hash_hu.h | 8 -- intl/msg_hash_id.h | 4 - intl/msg_hash_it.h | 9 -- intl/msg_hash_ja.h | 8 -- intl/msg_hash_ko.h | 8 -- intl/msg_hash_lbl.h | 20 ++++ intl/msg_hash_nl.h | 8 -- intl/msg_hash_pl.h | 8 -- intl/msg_hash_pt_br.c | 8 -- intl/msg_hash_pt_br.h | 8 -- intl/msg_hash_pt_pt.c | 4 - intl/msg_hash_ru.h | 8 -- intl/msg_hash_sk.h | 8 -- intl/msg_hash_tr.c | 8 -- intl/msg_hash_tr.h | 8 -- intl/msg_hash_us.h | 105 ++++++++++++++++++- intl/msg_hash_vn.c | 4 - menu/cbs/menu_cbs_left.c | 19 ++++ menu/cbs/menu_cbs_ok.c | 48 +++++++++ menu/cbs/menu_cbs_right.c | 20 ++++ menu/cbs/menu_cbs_start.c | 22 ++++ menu/cbs/menu_cbs_sublabel.c | 46 ++++++++- menu/drivers/materialui.c | 30 ++++++ menu/drivers/ozone.c | 18 ++++ menu/drivers/xmb.c | 16 +++ menu/menu_displaylist.c | 64 +++++++++++- menu/menu_driver.c | 12 +++ menu/menu_driver.h | 3 + menu/menu_setting.c | 68 +++++++++++++ msg_hash.h | 27 ++++- retroarch.c | 119 ++++++++++++++++++---- runloop.c | 136 ++++++++++++++++++++++++- runloop.h | 5 + tasks/task_movie.c | 24 ++--- 53 files changed, 1106 insertions(+), 277 deletions(-) diff --git a/command.c b/command.c index ddec005f33..94b202e661 100644 --- a/command.c +++ b/command.c @@ -1492,6 +1492,152 @@ void command_event_set_savestate_garbage_collect( dir_list_free(dir_list); } +void command_event_set_replay_auto_index(settings_t *settings) +{ + size_t i; + char state_base[128]; + char state_dir[PATH_MAX_LENGTH]; + + struct string_list *dir_list = NULL; + unsigned max_idx = 0; + runloop_state_t *runloop_st = runloop_state_get_ptr(); + bool replay_auto_index = settings->bools.replay_auto_index; + bool show_hidden_files = settings->bools.show_hidden_files; + + if (!replay_auto_index) + return; + /* Find the file in the same directory as runloop_st->names.replay + * with the largest numeral suffix. + * + * E.g. /foo/path/content.bsv, will try to find + * /foo/path/content.bsv%d, where %d is the largest number available. + */ + fill_pathname_basedir(state_dir, runloop_st->name.replay, + sizeof(state_dir)); + + dir_list = dir_list_new_special(state_dir, DIR_LIST_PLAIN, NULL, + show_hidden_files); + + if (!dir_list) + return; + + fill_pathname_base(state_base, runloop_st->name.replay, + sizeof(state_base)); + + for (i = 0; i < dir_list->size; i++) + { + unsigned idx; + char elem_base[128] = {0}; + const char *end = NULL; + const char *dir_elem = dir_list->elems[i].data; + + fill_pathname_base(elem_base, dir_elem, sizeof(elem_base)); + + if (strstr(elem_base, state_base) != elem_base) + continue; + + end = dir_elem + strlen(dir_elem); + + while ((end > dir_elem) && ISDIGIT((int)end[-1])) + end--; + + idx = (unsigned)strtoul(end, NULL, 0); + if (idx > max_idx) + max_idx = idx; + } + + dir_list_free(dir_list); + + configuration_set_int(settings, settings->ints.replay_slot, max_idx); + + RARCH_LOG("[Replay]: %s: #%d\n", + msg_hash_to_str(MSG_FOUND_LAST_REPLAY_SLOT), + max_idx); +} + +void command_event_set_replay_garbage_collect( + unsigned max_to_keep, + bool show_hidden_files + ) +{ + /* TODO: debugme */ + size_t i, cnt = 0; + char state_dir[PATH_MAX_LENGTH]; + char state_base[128]; + runloop_state_t *runloop_st = runloop_state_get_ptr(); + + struct string_list *dir_list = NULL; + unsigned min_idx = UINT_MAX; + const char *oldest_save = NULL; + + /* Similar to command_event_set_replay_auto_index(), + * this will find the lowest numbered replay */ + fill_pathname_basedir(state_dir, runloop_st->name.replay, + sizeof(state_dir)); + + dir_list = dir_list_new_special(state_dir, DIR_LIST_PLAIN, NULL, + show_hidden_files); + + if (!dir_list) + return; + + fill_pathname_base(state_base, runloop_st->name.replay, + sizeof(state_base)); + + for (i = 0; i < dir_list->size; i++) + { + unsigned idx; + char elem_base[128]; + const char *ext = NULL; + const char *end = NULL; + const char *dir_elem = dir_list->elems[i].data; + + if (string_is_empty(dir_elem)) + continue; + + fill_pathname_base(elem_base, dir_elem, sizeof(elem_base)); + + /* Only consider files with a '.bsvXX' extension + * > i.e. Ignore '.bsv.auto', '.bsv.bak', etc. */ + ext = path_get_extension(elem_base); + if (string_is_empty(ext) || + !string_starts_with_size(ext, "bsv", STRLEN_CONST("BSV"))) + continue; + + /* Check whether this file is associated with + * the current content */ + if (!string_starts_with(elem_base, state_base)) + continue; + + /* This looks like a valid save */ + cnt++; + + /* > Get index */ + end = dir_elem + strlen(dir_elem); + + while ((end > dir_elem) && ISDIGIT((int)end[-1])) + end--; + + idx = string_to_unsigned(end); + + /* > Check if this is the lowest index so far */ + if (idx < min_idx) + { + min_idx = idx; + oldest_save = dir_elem; + } + } + + /* Only delete one save state per save action + * > Conservative behaviour, designed to minimise + * the risk of deleting multiple incorrect files + * in case of accident */ + if (!string_is_empty(oldest_save) && (cnt > max_to_keep)) + filestream_delete(oldest_save); + + dir_list_free(dir_list); +} + #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL) bool command_set_shader(command_t *cmd, const char *arg) { @@ -1742,6 +1888,13 @@ bool command_event_main_state(unsigned cmd) savestates_enabled = (info.size > 0); } + /* TODO: Load state should act in one of three ways: + - [X] Not during recording or playback: normally + - [-] During playback: If the state is part of this replay, go back to that state and rewind the replay (not yet implemented); otherwise halt playback and go to that state normally. + - [-] During recording: If the state is part of this replay, go back to that state and rewind the replay, clobbering the stuff in between then and now (not yet implemented); if the state is not part of the replay, do nothing and log a warning. + */ + + if (savestates_enabled) { switch (cmd) @@ -1749,6 +1902,7 @@ bool command_event_main_state(unsigned cmd) case CMD_EVENT_SAVE_STATE: case CMD_EVENT_SAVE_STATE_TO_RAM: { + /* TODO: Saving state during recording should associate the state with the replay. */ video_driver_state_t *video_st = video_state_get_ptr(); bool savestate_auto_index = @@ -1781,6 +1935,19 @@ bool command_event_main_state(unsigned cmd) case CMD_EVENT_LOAD_STATE_FROM_RAM: { bool res = false; +#ifdef HAVE_BSV_MOVIE + input_driver_state_t *input_st = input_state_get_ptr(); + if (input_st->bsv_movie_state.flags & BSV_FLAG_MOVIE_RECORDING) + { + RARCH_ERR("[Load] [Movie] Can't load state during movie record\n"); + return false; + } + if (input_st->bsv_movie_state.flags & BSV_FLAG_MOVIE_PLAYBACK) + { + RARCH_LOG("[Load] [Movie] Loaded state during movie playback, halting playback\n"); + movie_stop(input_st); + } +#endif if (cmd == CMD_EVENT_LOAD_STATE) res = content_load_state(state_path, false, false); else @@ -1794,10 +1961,26 @@ bool command_event_main_state(unsigned cmd) } push_msg = false; break; - case CMD_EVENT_UNDO_LOAD_STATE: - command_event_undo_load_state(msg, sizeof(msg)); - ret = true; - break; + case CMD_EVENT_UNDO_LOAD_STATE: + { + /* TODO: To support this through re-recording would take some care around moving the replay recording forward to the time when the undo happened, which would need undo support for replays. For now, forbid it during recording and halt playback. */ +#ifdef HAVE_BSV_MOVIE + input_driver_state_t *input_st = input_state_get_ptr(); + if (input_st->bsv_movie_state.flags & BSV_FLAG_MOVIE_RECORDING) + { + RARCH_ERR("[Load] [Movie] Can't undo load state during movie record\n"); + return false; + } + if (input_st->bsv_movie_state.flags & BSV_FLAG_MOVIE_PLAYBACK) + { + RARCH_LOG("[Load] [Movie] Undo load state during movie playback, halting playback\n"); + movie_stop(input_st); + } +#endif + command_event_undo_load_state(msg, sizeof(msg)); + ret = true; + break; + } case CMD_EVENT_UNDO_SAVE_STATE: command_event_undo_save_state(msg, sizeof(msg)); ret = true; diff --git a/command.h b/command.h index 9a25a61b27..b38b439e41 100644 --- a/command.h +++ b/command.h @@ -92,6 +92,12 @@ enum event_command CMD_EVENT_SAVE_STATE, CMD_EVENT_SAVE_STATE_DECREMENT, CMD_EVENT_SAVE_STATE_INCREMENT, + /* Replay hotkeys. */ + CMD_EVENT_PLAY_REPLAY, + CMD_EVENT_RECORD_REPLAY, + CMD_EVENT_HALT_REPLAY, + CMD_EVENT_REPLAY_DECREMENT, + CMD_EVENT_REPLAY_INCREMENT, /* Save state actions. */ CMD_EVENT_SAVE_STATE_TO_RAM, CMD_EVENT_LOAD_STATE_FROM_RAM, @@ -260,8 +266,6 @@ enum event_command CMD_EVENT_RECORDING_TOGGLE, /* Toggle streaming. */ CMD_EVENT_STREAMING_TOGGLE, - /* Toggle BSV recording. */ - CMD_EVENT_BSV_RECORDING_TOGGLE, /* Toggle Run-Ahead. */ CMD_EVENT_RUNAHEAD_TOGGLE, /* Toggle Preemtive Frames. */ @@ -373,6 +377,14 @@ void command_event_set_savestate_garbage_collect( bool show_hidden_files ); +void command_event_set_replay_auto_index( + settings_t *settings); + +void command_event_set_replay_garbage_collect( + unsigned max_to_keep, + bool show_hidden_files + ); + #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL) bool command_set_shader(command_t *cmd, const char *arg); #endif @@ -428,7 +440,8 @@ static const struct cmd_action_map action_map[] = { { "READ_CORE_MEMORY", command_read_memory, "
" }, { "WRITE_CORE_MEMORY",command_write_memory, "
..." }, - {"LOAD_STATE_SLOT",command_load_state_slot, ""} + { "LOAD_STATE_SLOT",command_load_state_slot, ""}, + /*{ "PLAY_REPLAY_SLOT",command_play_replay_slot, ""},*/ }; static const struct cmd_map map[] = { @@ -454,6 +467,12 @@ static const struct cmd_map map[] = { { "STATE_SLOT_PLUS", RARCH_STATE_SLOT_PLUS }, { "STATE_SLOT_MINUS", RARCH_STATE_SLOT_MINUS }, + { "PLAY_REPLAY", RARCH_PLAY_REPLAY_KEY }, + { "RECORD_REPLAY", RARCH_RECORD_REPLAY_KEY }, + { "HALT_REPLAY", RARCH_HALT_REPLAY_KEY }, + { "REPLAY_SLOT_PLUS", RARCH_REPLAY_SLOT_PLUS }, + { "REPLAY_SLOT_MINUS", RARCH_REPLAY_SLOT_MINUS }, + { "DISK_EJECT_TOGGLE", RARCH_DISK_EJECT_TOGGLE }, { "DISK_NEXT", RARCH_DISK_NEXT }, { "DISK_PREV", RARCH_DISK_PREV }, @@ -469,7 +488,6 @@ static const struct cmd_map map[] = { { "SCREENSHOT", RARCH_SCREENSHOT }, { "RECORDING_TOGGLE", RARCH_RECORDING_TOGGLE }, { "STREAMING_TOGGLE", RARCH_STREAMING_TOGGLE }, - { "BSV_RECORD_TOGGLE", RARCH_BSV_RECORD_TOGGLE }, { "GRAB_MOUSE_TOGGLE", RARCH_GRAB_MOUSE_TOGGLE }, { "GAME_FOCUS_TOGGLE", RARCH_GAME_FOCUS_TOGGLE }, diff --git a/config.def.h b/config.def.h index fc9ff578ba..7aacc45094 100644 --- a/config.def.h +++ b/config.def.h @@ -627,6 +627,7 @@ #define DEFAULT_QUICK_MENU_SHOW_TAKE_SCREENSHOT true #define DEFAULT_QUICK_MENU_SHOW_SAVESTATE_SUBMENU false #define DEFAULT_QUICK_MENU_SHOW_SAVE_LOAD_STATE true +#define DEFAULT_QUICK_MENU_SHOW_REPLAY true #define DEFAULT_QUICK_MENU_SHOW_UNDO_SAVE_LOAD_STATE true #define DEFAULT_QUICK_MENU_SHOW_ADD_TO_FAVORITES true #define DEFAULT_QUICK_MENU_SHOW_START_RECORDING true @@ -1263,6 +1264,21 @@ * savestates will be deleted in this case) */ #define DEFAULT_SAVESTATE_MAX_KEEP 0 +/* When recording replays, replay index is automatically + * incremented before recording starts. + * When the content is loaded, replay index will be set + * to the highest existing value. */ +#define DEFAULT_REPLAY_AUTO_INDEX true + +/* Specifies the maximum number of replays to keep + * when replay auto index is enabled + * > When limit is exceeded, replay with the lowest + * index will be deleted automatically when creating + * a new replay + * > Setting value to zero disables the limit (no + * replays will be deleted in this case) */ +#define DEFAULT_REPLAY_MAX_KEEP 0 + /* Automatically saves a savestate at the end of RetroArch's lifetime. * The path is $SRAM_PATH.auto. * RetroArch will automatically load any savestate with this path on diff --git a/config.def.keybinds.h b/config.def.keybinds.h index eaa274a549..4ccf9029cb 100644 --- a/config.def.keybinds.h +++ b/config.def.keybinds.h @@ -410,6 +410,41 @@ static const struct retro_keybind retro_keybinds_1[] = { RARCH_STATE_SLOT_MINUS, NO_BTN, NO_BTN, 0, true }, + { + NULL, NULL, + AXIS_NONE, AXIS_NONE, AXIS_NONE, + MENU_ENUM_LABEL_VALUE_INPUT_META_PLAY_REPLAY_KEY, RETROK_UNKNOWN, + RARCH_PLAY_REPLAY_KEY, NO_BTN, NO_BTN, 0, + true + }, + { + NULL, NULL, + AXIS_NONE, AXIS_NONE, AXIS_NONE, + MENU_ENUM_LABEL_VALUE_INPUT_META_RECORD_REPLAY_KEY, RETROK_UNKNOWN, + RARCH_RECORD_REPLAY_KEY, NO_BTN, NO_BTN, 0, + true + }, + { + NULL, NULL, + AXIS_NONE, AXIS_NONE, AXIS_NONE, + MENU_ENUM_LABEL_VALUE_INPUT_META_HALT_REPLAY_KEY, RETROK_UNKNOWN, + RARCH_HALT_REPLAY_KEY, NO_BTN, NO_BTN, 0, + true + }, + { + NULL, NULL, + AXIS_NONE, AXIS_NONE, AXIS_NONE, + MENU_ENUM_LABEL_VALUE_INPUT_META_REPLAY_SLOT_PLUS, RETROK_UNKNOWN, + RARCH_REPLAY_SLOT_PLUS, NO_BTN, NO_BTN, 0, + true + }, + { + NULL, NULL, + AXIS_NONE, AXIS_NONE, AXIS_NONE, + MENU_ENUM_LABEL_VALUE_INPUT_META_REPLAY_SLOT_MINUS, RETROK_UNKNOWN, + RARCH_REPLAY_SLOT_MINUS, NO_BTN, NO_BTN, 0, + true + }, { NULL, NULL, AXIS_NONE, AXIS_NONE, AXIS_NONE, @@ -494,13 +529,6 @@ static const struct retro_keybind retro_keybinds_1[] = { RARCH_STREAMING_TOGGLE, NO_BTN, NO_BTN, 0, true }, - { - NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, - MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE, RETROK_UNKNOWN, - RARCH_BSV_RECORD_TOGGLE, NO_BTN, NO_BTN, 0, - true - }, { NULL, NULL, AXIS_NONE, AXIS_NONE, AXIS_NONE, @@ -1017,6 +1045,41 @@ static const struct retro_keybind retro_keybinds_1[] = { RARCH_STATE_SLOT_MINUS, NO_BTN, NO_BTN, 0, true }, + { + NULL, NULL, + AXIS_NONE, AXIS_NONE, AXIS_NONE, + MENU_ENUM_LABEL_VALUE_INPUT_META_PLAY_REPLAY_KEY, RETROK_UNKNOWN, + RARCH_PLAY_REPLAY_KEY, NO_BTN, NO_BTN, 0, + true + }, + { + NULL, NULL, + AXIS_NONE, AXIS_NONE, AXIS_NONE, + MENU_ENUM_LABEL_VALUE_INPUT_META_RECORD_REPLAY_KEY, RETROK_UNKNOWN, + RARCH_RECORD_REPLAY_KEY, NO_BTN, NO_BTN, 0, + true + }, + { + NULL, NULL, + AXIS_NONE, AXIS_NONE, AXIS_NONE, + MENU_ENUM_LABEL_VALUE_INPUT_META_HALT_REPLAY_KEY, RETROK_UNKNOWN, + RARCH_HALT_REPLAY_KEY, NO_BTN, NO_BTN, 0, + true + }, + { + NULL, NULL, + AXIS_NONE, AXIS_NONE, AXIS_NONE, + MENU_ENUM_LABEL_VALUE_INPUT_META_REPLAY_SLOT_PLUS, RETROK_UNKNOWN, + RARCH_REPLAY_SLOT_PLUS, NO_BTN, NO_BTN, 0, + true + }, + { + NULL, NULL, + AXIS_NONE, AXIS_NONE, AXIS_NONE, + MENU_ENUM_LABEL_VALUE_INPUT_META_REPLAY_SLOT_MINUS, RETROK_UNKNOWN, + RARCH_REPLAY_SLOT_MINUS, NO_BTN, NO_BTN, 0, + true + }, { NULL, NULL, AXIS_NONE, AXIS_NONE, AXIS_NONE, @@ -1101,13 +1164,6 @@ static const struct retro_keybind retro_keybinds_1[] = { RARCH_STREAMING_TOGGLE, NO_BTN, NO_BTN, 0, true }, - { - NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, - MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE, RETROK_UNKNOWN, - RARCH_BSV_RECORD_TOGGLE, NO_BTN, NO_BTN, 0, - true - }, { NULL, NULL, AXIS_NONE, AXIS_NONE, AXIS_NONE, @@ -1634,6 +1690,41 @@ static const struct retro_keybind retro_keybinds_1[] = { RARCH_STATE_SLOT_MINUS, NO_BTN, NO_BTN, 0, true }, + { + NULL, NULL, + AXIS_NONE, AXIS_NONE, AXIS_NONE, + MENU_ENUM_LABEL_VALUE_INPUT_META_PLAY_REPLAY_KEY, RETROK_UNKNOWN, + RARCH_PLAY_REPLAY_KEY, NO_BTN, NO_BTN, 0, + true + }, + { + NULL, NULL, + AXIS_NONE, AXIS_NONE, AXIS_NONE, + MENU_ENUM_LABEL_VALUE_INPUT_META_RECORD_REPLAY_KEY, RETROK_UNKNOWN, + RARCH_RECORD_REPLAY_KEY, NO_BTN, NO_BTN, 0, + true + }, + { + NULL, NULL, + AXIS_NONE, AXIS_NONE, AXIS_NONE, + MENU_ENUM_LABEL_VALUE_INPUT_META_HALT_REPLAY_KEY, RETROK_UNKNOWN, + RARCH_HALT_REPLAY_KEY, NO_BTN, NO_BTN, 0, + true + }, + { + NULL, NULL, + AXIS_NONE, AXIS_NONE, AXIS_NONE, + MENU_ENUM_LABEL_VALUE_INPUT_META_REPLAY_SLOT_PLUS, RETROK_UNKNOWN, + RARCH_REPLAY_SLOT_PLUS, NO_BTN, NO_BTN, 0, + true + }, + { + NULL, NULL, + AXIS_NONE, AXIS_NONE, AXIS_NONE, + MENU_ENUM_LABEL_VALUE_INPUT_META_REPLAY_SLOT_MINUS, RETROK_UNKNOWN, + RARCH_REPLAY_SLOT_MINUS, NO_BTN, NO_BTN, 0, + true + }, { NULL, NULL, AXIS_NONE, AXIS_NONE, AXIS_NONE, @@ -1718,13 +1809,6 @@ static const struct retro_keybind retro_keybinds_1[] = { RARCH_STREAMING_TOGGLE, NO_BTN, NO_BTN, 0, true }, - { - NULL, NULL, - AXIS_NONE, AXIS_NONE, AXIS_NONE, - MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE, RETROK_o, - RARCH_BSV_RECORD_TOGGLE, NO_BTN, NO_BTN, 0, - true - }, { NULL, NULL, AXIS_NONE, AXIS_NONE, AXIS_NONE, diff --git a/configuration.c b/configuration.c index 2e63adac91..8fbb9993e3 100644 --- a/configuration.c +++ b/configuration.c @@ -333,6 +333,12 @@ const struct input_bind_map input_config_bind_map[RARCH_BIND_LIST_END_NULL] = { DECLARE_META_BIND(2, state_slot_increase, RARCH_STATE_SLOT_PLUS, MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_PLUS), DECLARE_META_BIND(2, state_slot_decrease, RARCH_STATE_SLOT_MINUS, MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_MINUS), + DECLARE_META_BIND(1, play_replay, RARCH_PLAY_REPLAY_KEY, MENU_ENUM_LABEL_VALUE_INPUT_META_PLAY_REPLAY_KEY), + DECLARE_META_BIND(1, record_replay, RARCH_RECORD_REPLAY_KEY, MENU_ENUM_LABEL_VALUE_INPUT_META_RECORD_REPLAY_KEY), + DECLARE_META_BIND(1, halt_replay, RARCH_HALT_REPLAY_KEY, MENU_ENUM_LABEL_VALUE_INPUT_META_HALT_REPLAY_KEY), + DECLARE_META_BIND(2, replay_slot_increase, RARCH_REPLAY_SLOT_PLUS, MENU_ENUM_LABEL_VALUE_INPUT_META_REPLAY_SLOT_PLUS), + DECLARE_META_BIND(2, replay_slot_decrease, RARCH_REPLAY_SLOT_MINUS, MENU_ENUM_LABEL_VALUE_INPUT_META_REPLAY_SLOT_MINUS), + DECLARE_META_BIND(2, disk_eject_toggle, RARCH_DISK_EJECT_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_EJECT_TOGGLE), DECLARE_META_BIND(2, disk_next, RARCH_DISK_NEXT, MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_NEXT), DECLARE_META_BIND(2, disk_prev, RARCH_DISK_PREV, MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_PREV), @@ -348,7 +354,6 @@ const struct input_bind_map input_config_bind_map[RARCH_BIND_LIST_END_NULL] = { DECLARE_META_BIND(2, screenshot, RARCH_SCREENSHOT, MENU_ENUM_LABEL_VALUE_INPUT_META_SCREENSHOT), DECLARE_META_BIND(2, recording_toggle, RARCH_RECORDING_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_RECORDING_TOGGLE), DECLARE_META_BIND(2, streaming_toggle, RARCH_STREAMING_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_STREAMING_TOGGLE), - DECLARE_META_BIND(2, movie_record_toggle, RARCH_BSV_RECORD_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE), DECLARE_META_BIND(2, grab_mouse_toggle, RARCH_GRAB_MOUSE_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE), DECLARE_META_BIND(2, game_focus_toggle, RARCH_GAME_FOCUS_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_GAME_FOCUS_TOGGLE), @@ -1836,6 +1841,7 @@ static struct config_bool_setting *populate_settings_bool( SETTING_BOOL("quick_menu_show_close_content", &settings->bools.quick_menu_show_close_content, true, DEFAULT_QUICK_MENU_SHOW_CLOSE_CONTENT, false); SETTING_BOOL("quick_menu_show_savestate_submenu", &settings->bools.quick_menu_show_savestate_submenu, true, DEFAULT_QUICK_MENU_SHOW_SAVESTATE_SUBMENU, false); SETTING_BOOL("quick_menu_show_save_load_state", &settings->bools.quick_menu_show_save_load_state, true, DEFAULT_QUICK_MENU_SHOW_SAVE_LOAD_STATE, false); + SETTING_BOOL("quick_menu_show_replay", &settings->bools.quick_menu_show_replay, true, DEFAULT_QUICK_MENU_SHOW_REPLAY, false); SETTING_BOOL("quick_menu_show_take_screenshot", &settings->bools.quick_menu_show_take_screenshot, true, DEFAULT_QUICK_MENU_SHOW_TAKE_SCREENSHOT, false); SETTING_BOOL("quick_menu_show_undo_save_load_state", &settings->bools.quick_menu_show_undo_save_load_state, true, DEFAULT_QUICK_MENU_SHOW_UNDO_SAVE_LOAD_STATE, false); SETTING_BOOL("quick_menu_show_add_to_favorites", &settings->bools.quick_menu_show_add_to_favorites, true, DEFAULT_QUICK_MENU_SHOW_ADD_TO_FAVORITES, false); @@ -1975,6 +1981,7 @@ static struct config_bool_setting *populate_settings_bool( SETTING_BOOL("netplay_nat_traversal", &settings->bools.netplay_nat_traversal, true, true, false); #endif SETTING_BOOL("block_sram_overwrite", &settings->bools.block_sram_overwrite, true, DEFAULT_BLOCK_SRAM_OVERWRITE, false); + SETTING_BOOL("replay_auto_index", &settings->bools.replay_auto_index, true, DEFAULT_REPLAY_AUTO_INDEX, false); SETTING_BOOL("savestate_auto_index", &settings->bools.savestate_auto_index, true, DEFAULT_SAVESTATE_AUTO_INDEX, false); SETTING_BOOL("savestate_auto_save", &settings->bools.savestate_auto_save, true, DEFAULT_SAVESTATE_AUTO_SAVE, false); SETTING_BOOL("savestate_auto_load", &settings->bools.savestate_auto_load, true, DEFAULT_SAVESTATE_AUTO_LOAD, false); @@ -2194,6 +2201,7 @@ static struct config_uint_setting *populate_settings_uint( SETTING_UINT("rewind_granularity", &settings->uints.rewind_granularity, true, DEFAULT_REWIND_GRANULARITY, false); SETTING_UINT("rewind_buffer_size_step", &settings->uints.rewind_buffer_size_step, true, DEFAULT_REWIND_BUFFER_SIZE_STEP, false); SETTING_UINT("autosave_interval", &settings->uints.autosave_interval, true, DEFAULT_AUTOSAVE_INTERVAL, false); + SETTING_UINT("replay_max_keep", &settings->uints.replay_max_keep, true, DEFAULT_REPLAY_MAX_KEEP, false); SETTING_UINT("savestate_max_keep", &settings->uints.savestate_max_keep, true, DEFAULT_SAVESTATE_MAX_KEEP, false); SETTING_UINT("frontend_log_level", &settings->uints.frontend_log_level, true, DEFAULT_FRONTEND_LOG_LEVEL, false); SETTING_UINT("libretro_log_level", &settings->uints.libretro_log_level, true, DEFAULT_LIBRETRO_LOG_LEVEL, false); @@ -2428,6 +2436,7 @@ static struct config_int_setting *populate_settings_int( return NULL; SETTING_INT("state_slot", &settings->ints.state_slot, false, 0 /* TODO */, false); + SETTING_INT("replay_slot", &settings->ints.replay_slot, false, 0 /* TODO */, false); #ifdef HAVE_NETWORKING SETTING_INT("netplay_check_frames", &settings->ints.netplay_check_frames, true, DEFAULT_NETPLAY_CHECK_FRAMES, false); SETTING_OVERRIDE(RARCH_OVERRIDE_SETTING_NETPLAY_CHECK_FRAMES); @@ -3847,6 +3856,12 @@ static bool config_load_file(global_t *global, path_get(RARCH_PATH_BASENAME), ".state", sizeof(runloop_st->name.savestate)); + strlcpy(runloop_st->name.replay, tmp_str, + sizeof(runloop_st->name.replay)); + fill_pathname_dir(runloop_st->name.replay, + path_get(RARCH_PATH_BASENAME), + ".bsv", + sizeof(runloop_st->name.replay)); } else RARCH_WARN("[Config]: 'savestate_directory' is not a directory, ignoring..\n"); diff --git a/configuration.h b/configuration.h index 741d8dbe89..0e2b215048 100644 --- a/configuration.h +++ b/configuration.h @@ -104,6 +104,7 @@ typedef struct settings int location_update_interval_ms; int location_update_interval_distance; int state_slot; + int replay_slot; int audio_wasapi_sh_buffer_length; int crt_switch_center_adjust; int crt_switch_porch_adjust; @@ -203,6 +204,7 @@ typedef struct settings unsigned rewind_granularity; unsigned rewind_buffer_size_step; unsigned autosave_interval; + unsigned replay_max_keep; unsigned savestate_max_keep; unsigned network_cmd_port; unsigned network_remote_base_port; @@ -758,6 +760,7 @@ typedef struct settings bool quick_menu_show_take_screenshot; bool quick_menu_show_savestate_submenu; bool quick_menu_show_save_load_state; + bool quick_menu_show_replay; bool quick_menu_show_undo_save_load_state; bool quick_menu_show_add_to_favorites; bool quick_menu_show_start_recording; @@ -875,6 +878,7 @@ typedef struct settings bool pause_nonactive; bool pause_on_disconnect; bool block_sram_overwrite; + bool replay_auto_index; bool savestate_auto_index; bool savestate_auto_save; bool savestate_auto_load; diff --git a/input/input_defines.h b/input/input_defines.h index a97996c4e2..75e6768215 100644 --- a/input/input_defines.h +++ b/input/input_defines.h @@ -96,6 +96,12 @@ enum RARCH_STATE_SLOT_PLUS, RARCH_STATE_SLOT_MINUS, + RARCH_PLAY_REPLAY_KEY, + RARCH_RECORD_REPLAY_KEY, + RARCH_HALT_REPLAY_KEY, + RARCH_REPLAY_SLOT_PLUS, + RARCH_REPLAY_SLOT_MINUS, + RARCH_DISK_EJECT_TOGGLE, RARCH_DISK_NEXT, RARCH_DISK_PREV, @@ -111,7 +117,6 @@ enum RARCH_SCREENSHOT, RARCH_RECORDING_TOGGLE, RARCH_STREAMING_TOGGLE, - RARCH_BSV_RECORD_TOGGLE, RARCH_GRAB_MOUSE_TOGGLE, RARCH_GAME_FOCUS_TOGGLE, diff --git a/input/input_driver.h b/input/input_driver.h index f3c060e1c6..a783070a13 100644 --- a/input/input_driver.h +++ b/input/input_driver.h @@ -1013,7 +1013,6 @@ bool movie_start_playback(input_driver_state_t *input_st, char *path); bool movie_start_record(input_driver_state_t *input_st, char *path); bool movie_stop_playback(input_driver_state_t *input_st); bool movie_stop_record(input_driver_state_t *input_st); -bool movie_toggle_record(input_driver_state_t *input_st, settings_t *settings); bool movie_stop(input_driver_state_t *input_st); #endif diff --git a/intl/msg_hash_ar.h b/intl/msg_hash_ar.h index b2763efb08..ca15fa4a15 100644 --- a/intl/msg_hash_ar.h +++ b/intl/msg_hash_ar.h @@ -2357,14 +2357,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE, "بدء/إيقاف تشغيل الجلسة الحالية إلى منصة فيديو عبر الإنترنت." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE, - "تبديل سجل إعادة عرض الفيلم" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_BSV_RECORD_TOGGLE, - "تبديل تسجيل مدخلات اللعبة في تنسيق .bsv تشغيل/إيقافه." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, diff --git a/intl/msg_hash_ca.h b/intl/msg_hash_ca.h index 0e2ed826b5..2114c5fc26 100644 --- a/intl/msg_hash_ca.h +++ b/intl/msg_hash_ca.h @@ -2849,14 +2849,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE, "Inicia/Atura la transmissió de la sessió actual a una plataforma de vídeo en línia." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE, - "Enregistra la repetició d'entrades (commuta)" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_BSV_RECORD_TOGGLE, - "Canvia a activat/desactivat l'enregistrament d'entrades del joc en format .bsv." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, diff --git a/intl/msg_hash_chs.c b/intl/msg_hash_chs.c index c4929d0ff4..a3879b9161 100644 --- a/intl/msg_hash_chs.c +++ b/intl/msg_hash_chs.c @@ -190,10 +190,6 @@ int msg_hash_get_help_chs_enum(enum msg_hash_enums msg, char *s, size_t len) " \n" "必须先启用回溯倒带功能。"); break; - case RARCH_BSV_RECORD_TOGGLE: - snprintf(s, len, - "在录制和非录制模式切换。"); - break; default: if (string_is_empty(s)) strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE), len); @@ -1721,10 +1717,6 @@ int msg_hash_get_help_chs_enum(enum msg_hash_enums msg, char *s, size_t len) snprintf(s, len, "游戏暂停时,运行一帧。"); break; - case MENU_ENUM_LABEL_BSV_RECORD_TOGGLE: - snprintf(s, len, - "切换是否处于录像状态。"); - break; case MENU_ENUM_LABEL_L_X_PLUS: case MENU_ENUM_LABEL_L_X_MINUS: case MENU_ENUM_LABEL_L_Y_PLUS: diff --git a/intl/msg_hash_chs.h b/intl/msg_hash_chs.h index 41ff2b9a9f..6935c86528 100644 --- a/intl/msg_hash_chs.h +++ b/intl/msg_hash_chs.h @@ -2965,14 +2965,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE, "开始/停止在线视频直播。" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE, - "记录输入回放 (开关)" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_BSV_RECORD_TOGGLE, - "打开或关闭 .bsv 格式的游戏操作录制。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, diff --git a/intl/msg_hash_cht.h b/intl/msg_hash_cht.h index f1cab3ac64..9ed26e81cd 100644 --- a/intl/msg_hash_cht.h +++ b/intl/msg_hash_cht.h @@ -3429,14 +3429,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE, "將目前執行的內容, 直播到指定網路的開關。" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE, - "錄製操作重播 (開關)" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_BSV_RECORD_TOGGLE, - "錄製遊戲操作重播檔(BSV格式)的開關。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, diff --git a/intl/msg_hash_cs.h b/intl/msg_hash_cs.h index 98f41660d2..1ab113f735 100644 --- a/intl/msg_hash_cs.h +++ b/intl/msg_hash_cs.h @@ -3317,14 +3317,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE, "Spustí/zastaví streamování aktuální relace na online video platformu." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE, - "Přehrávání Vstupního Záznamu (Přepínání)" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_BSV_RECORD_TOGGLE, - "Zapnutí/vypnutí záznamu herních vstupů ve formátu .bsv." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, diff --git a/intl/msg_hash_de.h b/intl/msg_hash_de.h index 1e7aaa1535..679ad343f0 100644 --- a/intl/msg_hash_de.h +++ b/intl/msg_hash_de.h @@ -3293,14 +3293,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE, "Startet/stoppt das Streaming der aktuellen Sitzung zu einer Online-Video-Plattform." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE, - "Eingaben-Aufnahme (Umschalten)" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_BSV_RECORD_TOGGLE, - "Schaltet die Aufnahme von Gameplay-Eingaben im .bsv-Format ein/aus." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, diff --git a/intl/msg_hash_el.c b/intl/msg_hash_el.c index a268c59848..aff6dcc3df 100644 --- a/intl/msg_hash_el.c +++ b/intl/msg_hash_el.c @@ -207,10 +207,6 @@ int msg_hash_get_help_el_enum(enum msg_hash_enums msg, char *s, size_t len) " \n" "Η επιστροφή προς τα πίσω πρέπει να είναι ενεργοποιημένη."); break; - case RARCH_BSV_RECORD_TOGGLE: - snprintf(s, len, - "Αλλαγή ανάμεσα σε εγγραφή ή όχι."); - break; default: if (string_is_empty(s)) strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE), len); diff --git a/intl/msg_hash_es.h b/intl/msg_hash_es.h index 957993758b..c27a8b6eb9 100644 --- a/intl/msg_hash_es.h +++ b/intl/msg_hash_es.h @@ -3393,14 +3393,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE, "Inicia o detiene la transmisión por streaming de la sesión actual a una plataforma de vídeo online." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE, - "Grabar repetición de entrada (alternar)" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_BSV_RECORD_TOGGLE, - "Activa o desactiva el uso del formato .bsv para guardar las grabaciones de entrada de las partidas." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, diff --git a/intl/msg_hash_fi.h b/intl/msg_hash_fi.h index 2719bf7352..d1a681ccbf 100644 --- a/intl/msg_hash_fi.h +++ b/intl/msg_hash_fi.h @@ -2957,14 +2957,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE, "Aloittaa/pysäyttää nykyisen istunnon suoratoiston verkossa toimivalle videoalustalle." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE, - "Nauhoita syötteiden toistoa (päälle/pois)" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_BSV_RECORD_TOGGLE, - "Vaihtaa pelin näppäinkomentojen nauhoituksen .bsv-muotoon päälle/pois." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, diff --git a/intl/msg_hash_fr.h b/intl/msg_hash_fr.h index c4dc227be3..0a50dd82b5 100644 --- a/intl/msg_hash_fr.h +++ b/intl/msg_hash_fr.h @@ -3365,14 +3365,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE, "Lance/arrête le streaming de la session en cours vers une plateforme vidéo en ligne." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE, - "Enregistrement de la relecture (activer/désactiver)" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_BSV_RECORD_TOGGLE, - "Active/désactive l'enregistrement des touches pressées au format .bsv." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, diff --git a/intl/msg_hash_hu.h b/intl/msg_hash_hu.h index 1b045c256e..24535766b5 100644 --- a/intl/msg_hash_hu.h +++ b/intl/msg_hash_hu.h @@ -3385,14 +3385,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE, "A tartalom közvetítése egy online videó platform felé." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE, - "Bemenetek rögzítése újrajátszáshoz (váltógomb)" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_BSV_RECORD_TOGGLE, - "Ki-be kapcsolja a játék bemeneteinek rögzítését .bsv formátumban." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, diff --git a/intl/msg_hash_id.h b/intl/msg_hash_id.h index cc358560d2..34fbae15c7 100644 --- a/intl/msg_hash_id.h +++ b/intl/msg_hash_id.h @@ -2477,10 +2477,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE, "Memulai/hentikan siaran alir dari sesi saat ini ke pelantar video daring." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE, - "Putar Ulang Masukan Rekaman (Mati/Nyala)" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_FULLSCREEN_TOGGLE_KEY, diff --git a/intl/msg_hash_it.h b/intl/msg_hash_it.h index 076dc51eec..b94e4d7cee 100644 --- a/intl/msg_hash_it.h +++ b/intl/msg_hash_it.h @@ -3337,15 +3337,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE, "Avvia/ferma lo streaming della sessione attuale su una piattaforma video online." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE, - "Registra Sequenza degli Input (Attiva / Disattiva)" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_BSV_RECORD_TOGGLE, - "Attiva o disattiva la registrazione in formato .bsv degli input utilizzati." - ) - MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, "Prendi il Mouse (Abilita / Disabilita)" diff --git a/intl/msg_hash_ja.h b/intl/msg_hash_ja.h index 7213f57c2b..2e0aa6124b 100644 --- a/intl/msg_hash_ja.h +++ b/intl/msg_hash_ja.h @@ -2717,14 +2717,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE, "オンライン動画プラットフォームへの配信を開始/停止します." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE, - "入力リプレイを録画 (切り替え)" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_BSV_RECORD_TOGGLE, - "ゲームプレイ入力記録(.bsv形式)のオン/オフを切り替えます." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, diff --git a/intl/msg_hash_ko.h b/intl/msg_hash_ko.h index e84f2acde9..9e657df77b 100644 --- a/intl/msg_hash_ko.h +++ b/intl/msg_hash_ko.h @@ -3413,14 +3413,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE, "현재 세션 영상을 온라인상으로 스트리밍을 시작/종료 합니다." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE, - "입력 기록 (시작/중지)" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_BSV_RECORD_TOGGLE, - "사용자 입력을 .bsv 파일로 기록하는 것을 시작/중지합니다." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index 4befe929b8..e89289e93b 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -3317,6 +3317,22 @@ MSG_HASH( MENU_ENUM_LABEL_SAVE_STATE, "savestate" ) +MSG_HASH( + MENU_ENUM_LABEL_RECORD_REPLAY, + "record_replay" + ) +MSG_HASH( + MENU_ENUM_LABEL_REPLAY_SLOT, + "replay_slot" + ) +MSG_HASH( + MENU_ENUM_LABEL_PLAY_REPLAY, + "play_replay" + ) +MSG_HASH( + MENU_ENUM_LABEL_HALT_REPLAY, + "halt_replay" + ) MSG_HASH( MENU_ENUM_LABEL_SAVING_SETTINGS, "saving_settings" @@ -4859,6 +4875,10 @@ MSG_HASH( MENU_ENUM_LABEL_QUICK_MENU_SHOW_SAVE_LOAD_STATE, "quick_menu_show_save_load_state" ) +MSG_HASH( + MENU_ENUM_LABEL_QUICK_MENU_SHOW_REPLAY, + "quick_menu_show_replay" + ) MSG_HASH( MENU_ENUM_LABEL_QUICK_MENU_SHOW_UNDO_SAVE_LOAD_STATE, "quick_menu_show_undo_save_load_state" diff --git a/intl/msg_hash_nl.h b/intl/msg_hash_nl.h index 9813f5e08a..7fbab33ba2 100644 --- a/intl/msg_hash_nl.h +++ b/intl/msg_hash_nl.h @@ -2761,14 +2761,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE, "Start/stopt het streamen van de huidige sessie naar een online videoplatform." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE, - "Neem de Ingedruktte Knoppen op (Omschakelen)" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_BSV_RECORD_TOGGLE, - "Schakelt de opname van gameplay-invoers in de .bsv formaat aan/uit." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, diff --git a/intl/msg_hash_pl.h b/intl/msg_hash_pl.h index b4c7369d4d..8df3996db3 100644 --- a/intl/msg_hash_pl.h +++ b/intl/msg_hash_pl.h @@ -2877,14 +2877,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE, "Uruchamia / zatrzymuje przesyłanie strumieniowe bieżącej sesji na platformę wideo online." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE, - "Nagrywanie powtórki wejścia (przełącznik)" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_BSV_RECORD_TOGGLE, - "Włącza/wyłącza nagrywanie danych wejściowych rozgrywki w formacie .bsv." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, diff --git a/intl/msg_hash_pt_br.c b/intl/msg_hash_pt_br.c index 5fdc102f84..6e5e676fbb 100644 --- a/intl/msg_hash_pt_br.c +++ b/intl/msg_hash_pt_br.c @@ -223,10 +223,6 @@ int msg_hash_get_help_pt_br_enum(enum msg_hash_enums msg, char *s, size_t len) " \n" "Rebobinar precisa estar habilitado."); break; - case RARCH_BSV_RECORD_TOGGLE: - snprintf(s, len, - "Alternar entre gravando ou não."); - break; default: if (string_is_empty(s)) strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE), len); @@ -2210,10 +2206,6 @@ int msg_hash_get_help_pt_br_enum(enum msg_hash_enums msg, char *s, size_t len) "Avanço de quadro quando o conteúdo \n" "estiver pausado."); break; - case MENU_ENUM_LABEL_BSV_RECORD_TOGGLE: - snprintf(s, len, - "Alternar entre gravando ou não."); - break; case MENU_ENUM_LABEL_L_X_PLUS: case MENU_ENUM_LABEL_L_X_MINUS: case MENU_ENUM_LABEL_L_Y_PLUS: diff --git a/intl/msg_hash_pt_br.h b/intl/msg_hash_pt_br.h index 1de8670c0a..f1f4275e15 100644 --- a/intl/msg_hash_pt_br.h +++ b/intl/msg_hash_pt_br.h @@ -2885,14 +2885,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE, "Inicia ou interrompe o transmissão da sessão atual para uma plataforma de vídeo online." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE, - "Gravar replay de entrada (alternar)" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_BSV_RECORD_TOGGLE, - "Ativa ou não a gravação de comandos do jogo no formato .bsv." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, diff --git a/intl/msg_hash_pt_pt.c b/intl/msg_hash_pt_pt.c index f3346f9f0d..4a47c8683f 100644 --- a/intl/msg_hash_pt_pt.c +++ b/intl/msg_hash_pt_pt.c @@ -905,10 +905,6 @@ int msg_hash_get_help_pt_pt_enum(enum msg_hash_enums msg, char *s, size_t len) snprintf(s, len, "O fotograma avança enquanto o conteúdo está em pausa."); break; - case MENU_ENUM_LABEL_BSV_RECORD_TOGGLE: - snprintf(s, len, - "Ativa ou desativa a gravação."); - break; case MENU_ENUM_LABEL_L_X_PLUS: case MENU_ENUM_LABEL_L_X_MINUS: case MENU_ENUM_LABEL_L_Y_PLUS: diff --git a/intl/msg_hash_ru.h b/intl/msg_hash_ru.h index 9acb866680..57b9a92fc5 100644 --- a/intl/msg_hash_ru.h +++ b/intl/msg_hash_ru.h @@ -3405,14 +3405,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE, "Включает/останавливает трансляцию текущего сеанса на онлайн-платформе." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE, - "Повтор записи нажатий (переключение)" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_BSV_RECORD_TOGGLE, - "Включает/отключает запись нажатий в формате .bsv." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, diff --git a/intl/msg_hash_sk.h b/intl/msg_hash_sk.h index c41ea371a3..a52eb5cbdd 100644 --- a/intl/msg_hash_sk.h +++ b/intl/msg_hash_sk.h @@ -2493,14 +2493,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_STREAMING_TOGGLE, "Streamovanie (prepnúť)" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE, - "Zaznamenanie vstupov (prepínanie)" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_BSV_RECORD_TOGGLE, - "Zapína/vypína zaznamenávanie vstupov hrania v .bsv formáte." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_FULLSCREEN_TOGGLE_KEY, diff --git a/intl/msg_hash_tr.c b/intl/msg_hash_tr.c index 5ac0029bf0..0930fd981c 100644 --- a/intl/msg_hash_tr.c +++ b/intl/msg_hash_tr.c @@ -213,10 +213,6 @@ int msg_hash_get_help_tr_enum(enum msg_hash_enums msg, char *s, size_t len) " \n" "Geri sarma etkin olmalı."); break; - case RARCH_BSV_RECORD_TOGGLE: - snprintf(s, len, - "Kayıt yapmak ve yapmamak arasında geçiş yapar."); - break; default: if (string_is_empty(s)) strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE), len); @@ -1785,10 +1781,6 @@ int msg_hash_get_help_tr_enum(enum msg_hash_enums msg, char *s, size_t len) snprintf(s, len, "İçerik duraklatıldığında kare ilerlemesi."); break; - case MENU_ENUM_LABEL_BSV_RECORD_TOGGLE: - snprintf(s, len, - "Kayıt yapma arasında geçiş yapmak için"); - break; case MENU_ENUM_LABEL_VALUE_WHAT_IS_A_CORE_DESC: snprintf(s, len, "RetroArch kendi başına hiçbir şey yapmaz. \n" diff --git a/intl/msg_hash_tr.h b/intl/msg_hash_tr.h index 750cb38902..9fbe632333 100644 --- a/intl/msg_hash_tr.h +++ b/intl/msg_hash_tr.h @@ -3077,14 +3077,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE, "Mevcut oturumun çevrimiçi bir video platformuna akışını başlatır/durdurur." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE, - "Kayıt Girişi Tekrarı (Değiştir)" - ) -MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_BSV_RECORD_TOGGLE, - "Oynanış girişlerinin .bsv biçiminde kaydedilmesini açar/kapatır." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index ce4f2543bc..422b8e3411 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -3458,14 +3458,45 @@ MSG_HASH( "Starts/stops streaming of the current session to an online video platform." ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE, - "Record Input Replay (Toggle)" + MENU_ENUM_LABEL_VALUE_INPUT_META_PLAY_REPLAY_KEY, + "Play Replay" ) MSG_HASH( - MENU_ENUM_SUBLABEL_INPUT_META_BSV_RECORD_TOGGLE, - "Switches recording of gameplay inputs in .bsv format on/off." + MENU_ENUM_SUBLABEL_INPUT_META_PLAY_REPLAY_KEY, + "Play replay file from the currently selected slot." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_RECORD_REPLAY_KEY, + "Record Replay" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_RECORD_REPLAY_KEY, + "Record replay file to the currently selected slot." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_HALT_REPLAY_KEY, + "Halt Record/Replay" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_HALT_REPLAY_KEY, + "Stops recording/playback of current replay." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_REPLAY_SLOT_PLUS, + "Next Replay Slot" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_REPLAY_SLOT_PLUS, + "Increments the currently selected replay slot index." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_META_REPLAY_SLOT_MINUS, + "Previous Replay Slot" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_REPLAY_SLOT_MINUS, + "Decrements the currently selected replay slot index." ) - MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, "Grab Mouse (Toggle)" @@ -4147,6 +4178,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_INDEX, "Before making a save state, the save state index is automatically increased. When loading content, the index will be set to the highest existing index." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REPLAY_AUTO_INDEX, + "Increment Replay Index Automatically" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REPLAY_AUTO_INDEX, + "Before making a replay, the replay index is automatically increased. When loading content, the index will be set to the highest existing index." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_MAX_KEEP, "Maximum Auto-Increment Save States to Keep" @@ -4155,6 +4194,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_MAX_KEEP, "Limit the number of save states that will be created when 'Increment Save State Index Automatically' is enabled. If limit is exceeded when saving a new state, the existing state with the lowest index will be deleted. A value of '0' means unlimited states will be recorded." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REPLAY_MAX_KEEP, + "Maximum Auto-Increment Replays to Keep" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REPLAY_MAX_KEEP, + "Limit the number of replays that will be created when 'Increment Replay Index Automatically' is enabled. If limit is exceeded when recording a new replay, the existing replay with the lowest index will be deleted. A value of '0' means unlimited replays will be recorded." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, "Auto Save State" @@ -5761,6 +5808,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_LOAD_STATE, "Show the options for saving/loading a state." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_REPLAY, + "Show 'Replay Controls'" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_REPLAY, + "Show the options for recording/playing back replay files." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_UNDO_SAVE_LOAD_STATE, "Show 'Undo Save/Load State'" @@ -8146,6 +8201,38 @@ MSG_HASH( MENU_ENUM_SUBLABEL_UNDO_SAVE_STATE, "If a state was overwritten, it will roll back to the previous save state." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_REPLAY_SLOT, + "Replay Slot" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REPLAY_SLOT, + "Change the currently selected state slot." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAY_REPLAY, + "Play Replay" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAY_REPLAY, + "Play replay file from the currently selected slot." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RECORD_REPLAY, + "Record Replay" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RECORD_REPLAY, + "Record replay file to the currently selected slot." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HALT_REPLAY, + "Halt Record/Replay" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_HALT_REPLAY, + "Stops recording/playback of current replay" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ADD_TO_FAVORITES, "Add to Favorites" @@ -13522,6 +13609,10 @@ MSG_HASH( MSG_FOUND_LAST_STATE_SLOT, "Found last state slot" ) +MSG_HASH( + MSG_FOUND_LAST_REPLAY_SLOT, + "Found last replay slot" + ) MSG_HASH( MSG_FOUND_SHADER, "Found shader" @@ -13902,6 +13993,10 @@ MSG_HASH( MSG_STATE_SLOT, "State slot" ) +MSG_HASH( + MSG_REPLAY_SLOT, + "Replay slot" + ) MSG_HASH( MSG_TAKING_SCREENSHOT, "Taking screenshot." diff --git a/intl/msg_hash_vn.c b/intl/msg_hash_vn.c index 0d1e08f19f..1dba3b7ef5 100644 --- a/intl/msg_hash_vn.c +++ b/intl/msg_hash_vn.c @@ -153,10 +153,6 @@ int msg_hash_get_help_vn_enum(enum msg_hash_enums msg, char *s, size_t len) " \n" "Cần phải bật chức năng quay lại."); break; - case RARCH_BSV_RECORD_TOGGLE: - snprintf(s, len, - "Bật/tắt ghi chép video."); - break; default: if (string_is_empty(s)) strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE), len); diff --git a/menu/cbs/menu_cbs_left.c b/menu/cbs/menu_cbs_left.c index cfa23a4bf5..ad7d4eb853 100644 --- a/menu/cbs/menu_cbs_left.c +++ b/menu/cbs/menu_cbs_left.c @@ -970,6 +970,20 @@ static int action_left_state_slot(unsigned type, const char *label, return 0; } +static int action_left_replay_slot(unsigned type, const char *label, + bool wraparound) +{ + settings_t *settings = config_get_ptr(); + + settings->ints.replay_slot--; + if (settings->ints.replay_slot < -1) + settings->ints.replay_slot = 999; + + menu_driver_ctl(RARCH_MENU_CTL_UPDATE_SAVESTATE_THUMBNAIL_PATH, NULL); + menu_driver_ctl(RARCH_MENU_CTL_UPDATE_SAVESTATE_THUMBNAIL_IMAGE, NULL); + + return 0; +} static int bind_left_generic(unsigned type, const char *label, bool wraparound) @@ -1270,6 +1284,11 @@ static int menu_cbs_init_bind_left_compare_type(menu_file_list_cbs_t *cbs, case MENU_SETTING_ACTION_LOADSTATE: BIND_ACTION_LEFT(cbs, action_left_state_slot); break; + case MENU_SETTING_ACTION_RECORDREPLAY: + case MENU_SETTING_ACTION_PLAYREPLAY: + case MENU_SETTING_ACTION_HALTREPLAY: + BIND_ACTION_LEFT(cbs, action_left_replay_slot); + break; default: return -1; } diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index d7b2495751..0748baed6e 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -4498,6 +4498,51 @@ static int action_ok_save_state(const char *path, return 0; } +static int action_ok_play_replay(const char *path, + const char *label, unsigned type, size_t idx, size_t entry_idx) +{ + settings_t *settings = config_get_ptr(); + bool resume = settings->bools.menu_savestate_resume; + + if (generic_action_ok_command(CMD_EVENT_PLAY_REPLAY) == -1) + return -1; + + if (resume) + return generic_action_ok_command(CMD_EVENT_RESUME); + + return 0; +} + +static int action_ok_record_replay(const char *path, + const char *label, unsigned type, size_t idx, size_t entry_idx) +{ + settings_t *settings = config_get_ptr(); + bool resume = settings->bools.menu_savestate_resume; + + if (generic_action_ok_command(CMD_EVENT_RECORD_REPLAY) == -1) + return -1; + + if (resume) + return generic_action_ok_command(CMD_EVENT_RESUME); + + return 0; +} + +static int action_ok_halt_replay(const char *path, + const char *label, unsigned type, size_t idx, size_t entry_idx) +{ + settings_t *settings = config_get_ptr(); + bool resume = settings->bools.menu_savestate_resume; + + if (generic_action_ok_command(CMD_EVENT_HALT_REPLAY) == -1) + return -1; + + if (resume) + return generic_action_ok_command(CMD_EVENT_RESUME); + + return 0; +} + static int action_ok_close_submenu(const char* path, const char* label, unsigned type, size_t idx, size_t entry_idx) { @@ -8251,6 +8296,9 @@ static int menu_cbs_init_bind_ok_compare_label(menu_file_list_cbs_t *cbs, {MENU_ENUM_LABEL_LOAD_STATE, action_ok_load_state}, {MENU_ENUM_LABEL_UNDO_LOAD_STATE, action_ok_undo_load_state}, {MENU_ENUM_LABEL_UNDO_SAVE_STATE, action_ok_undo_save_state}, + {MENU_ENUM_LABEL_RECORD_REPLAY, action_ok_record_replay}, + {MENU_ENUM_LABEL_PLAY_REPLAY, action_ok_play_replay}, + {MENU_ENUM_LABEL_HALT_REPLAY, action_ok_halt_replay}, {MENU_ENUM_LABEL_RESUME_CONTENT, action_ok_resume_content}, {MENU_ENUM_LABEL_ADD_TO_FAVORITES_PLAYLIST, action_ok_add_to_favorites_playlist}, {MENU_ENUM_LABEL_SET_CORE_ASSOCIATION, action_ok_set_core_association}, diff --git a/menu/cbs/menu_cbs_right.c b/menu/cbs/menu_cbs_right.c index d302ab8f2f..6e2cedae66 100644 --- a/menu/cbs/menu_cbs_right.c +++ b/menu/cbs/menu_cbs_right.c @@ -963,6 +963,21 @@ static int action_right_state_slot(unsigned type, const char *label, return 0; } +static int action_right_replay_slot(unsigned type, const char *label, + bool wraparound) +{ + settings_t *settings = config_get_ptr(); + + settings->ints.replay_slot++; + if (settings->ints.replay_slot > 999) + settings->ints.replay_slot = -1; + + menu_driver_ctl(RARCH_MENU_CTL_UPDATE_SAVESTATE_THUMBNAIL_PATH, NULL); + menu_driver_ctl(RARCH_MENU_CTL_UPDATE_SAVESTATE_THUMBNAIL_IMAGE, NULL); + + return 0; +} + int bind_right_generic(unsigned type, const char *label, bool wraparound) { @@ -1092,6 +1107,11 @@ static int menu_cbs_init_bind_right_compare_type(menu_file_list_cbs_t *cbs, case MENU_SETTING_ACTION_LOADSTATE: BIND_ACTION_RIGHT(cbs, action_right_state_slot); break; + case MENU_SETTING_ACTION_RECORDREPLAY: + case MENU_SETTING_ACTION_PLAYREPLAY: + case MENU_SETTING_ACTION_HALTREPLAY: + BIND_ACTION_RIGHT(cbs, action_right_replay_slot); + break; default: return -1; } diff --git a/menu/cbs/menu_cbs_start.c b/menu/cbs/menu_cbs_start.c index dcb08d81da..2b48015d9b 100644 --- a/menu/cbs/menu_cbs_start.c +++ b/menu/cbs/menu_cbs_start.c @@ -519,6 +519,20 @@ static int action_start_state_slot( return 0; } +static int action_start_replay_slot( + const char *path, const char *label, + unsigned type, size_t idx, size_t entry_idx) +{ + settings_t *settings = config_get_ptr(); + + settings->ints.replay_slot = 0; + + menu_driver_ctl(RARCH_MENU_CTL_UPDATE_SAVESTATE_THUMBNAIL_PATH, NULL); + menu_driver_ctl(RARCH_MENU_CTL_UPDATE_SAVESTATE_THUMBNAIL_IMAGE, NULL); + + return 0; +} + static int action_start_menu_wallpaper( const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) @@ -888,6 +902,9 @@ static int menu_cbs_init_bind_start_compare_label(menu_file_list_cbs_t *cbs) case MENU_ENUM_LABEL_STATE_SLOT: BIND_ACTION_START(cbs, action_start_state_slot); break; + case MENU_ENUM_LABEL_REPLAY_SLOT: + BIND_ACTION_START(cbs, action_start_replay_slot); + break; case MENU_ENUM_LABEL_MENU_WALLPAPER: BIND_ACTION_START(cbs, action_start_menu_wallpaper); break; @@ -964,6 +981,11 @@ static int menu_cbs_init_bind_start_compare_type(menu_file_list_cbs_t *cbs, case MENU_SETTING_ACTION_LOADSTATE: BIND_ACTION_START(cbs, action_start_state_slot); break; + case MENU_SETTING_ACTION_PLAYREPLAY: + case MENU_SETTING_ACTION_RECORDREPLAY: + case MENU_SETTING_ACTION_HALTREPLAY: + BIND_ACTION_START(cbs, action_start_replay_slot); + break; default: return -1; } diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index 0f6f3dd2e2..99c6e3e263 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -409,6 +409,12 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_save_state_key, ME DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_state_slot_plus, MENU_ENUM_SUBLABEL_INPUT_META_STATE_SLOT_PLUS) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_state_slot_minus, MENU_ENUM_SUBLABEL_INPUT_META_STATE_SLOT_MINUS) +DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_play_replay_key, MENU_ENUM_SUBLABEL_INPUT_META_PLAY_REPLAY_KEY) +DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_record_replay_key, MENU_ENUM_SUBLABEL_INPUT_META_RECORD_REPLAY_KEY) +DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_halt_replay_key, MENU_ENUM_SUBLABEL_INPUT_META_HALT_REPLAY_KEY) +DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_replay_slot_plus, MENU_ENUM_SUBLABEL_INPUT_META_REPLAY_SLOT_PLUS) +DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_replay_slot_minus, MENU_ENUM_SUBLABEL_INPUT_META_REPLAY_SLOT_MINUS) + DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_disk_eject_toggle, MENU_ENUM_SUBLABEL_INPUT_META_DISK_EJECT_TOGGLE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_disk_next, MENU_ENUM_SUBLABEL_INPUT_META_DISK_NEXT) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_disk_prev, MENU_ENUM_SUBLABEL_INPUT_META_DISK_PREV) @@ -424,7 +430,6 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_cheat_index_minus, ME DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_screenshot, MENU_ENUM_SUBLABEL_INPUT_META_SCREENSHOT) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_recording_toggle, MENU_ENUM_SUBLABEL_INPUT_META_RECORDING_TOGGLE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_streaming_toggle, MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE) -DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_bsv_record_toggle, MENU_ENUM_SUBLABEL_INPUT_META_BSV_RECORD_TOGGLE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_grab_mouse_toggle, MENU_ENUM_SUBLABEL_INPUT_META_GRAB_MOUSE_TOGGLE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_game_focus_toggle, MENU_ENUM_SUBLABEL_INPUT_META_GAME_FOCUS_TOGGLE) @@ -895,6 +900,10 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_load_state, DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_save_state, MENU_ENUM_SUBLABEL_SAVE_STATE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_undo_load_state, MENU_ENUM_SUBLABEL_UNDO_LOAD_STATE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_undo_save_state, MENU_ENUM_SUBLABEL_UNDO_SAVE_STATE) +DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_record_replay, MENU_ENUM_SUBLABEL_RECORD_REPLAY) +DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_play_replay, MENU_ENUM_SUBLABEL_PLAY_REPLAY) +DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_halt_replay, MENU_ENUM_SUBLABEL_HALT_REPLAY) +DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_replay_slot, MENU_ENUM_SUBLABEL_REPLAY_SLOT) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_accounts_retro_achievements, MENU_ENUM_SUBLABEL_ACCOUNTS_RETRO_ACHIEVEMENTS) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_accounts_list, MENU_ENUM_SUBLABEL_ACCOUNTS_LIST) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_rewind, MENU_ENUM_SUBLABEL_INPUT_META_REWIND) @@ -998,6 +1007,7 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_quick_menu_show_restart_content, DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_quick_menu_show_close_content, MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_CLOSE_CONTENT) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_quick_menu_show_savestate_submenu, MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVESTATE_SUBMENU) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_quick_menu_show_save_load_state, MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_LOAD_STATE) +DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_quick_menu_show_replay, MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_REPLAY) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_quick_menu_show_undo_save_load_state, MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_UNDO_SAVE_LOAD_STATE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_quick_menu_show_add_to_favorites, MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_ADD_TO_FAVORITES) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_quick_menu_show_start_recording, MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_START_RECORDING) @@ -2189,6 +2199,22 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_meta_state_slot_minus); return 0; + case RARCH_PLAY_REPLAY_KEY: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_meta_play_replay_key); + return 0; + case RARCH_RECORD_REPLAY_KEY: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_meta_record_replay_key); + return 0; + case RARCH_HALT_REPLAY_KEY: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_meta_halt_replay_key); + return 0; + case RARCH_REPLAY_SLOT_PLUS: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_meta_replay_slot_plus); + return 0; + case RARCH_REPLAY_SLOT_MINUS: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_meta_replay_slot_minus); + return 0; + case RARCH_DISK_EJECT_TOGGLE: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_meta_disk_eject_toggle); return 0; @@ -2234,9 +2260,6 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case RARCH_STREAMING_TOGGLE: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_meta_streaming_toggle); return 0; - case RARCH_BSV_RECORD_TOGGLE: - BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_meta_bsv_record_toggle); - return 0; case RARCH_GRAB_MOUSE_TOGGLE: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_meta_grab_mouse_toggle); @@ -2778,6 +2801,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_QUICK_MENU_SHOW_SAVE_LOAD_STATE: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_quick_menu_show_save_load_state); break; + case MENU_ENUM_LABEL_QUICK_MENU_SHOW_REPLAY: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_quick_menu_show_replay); + break; case MENU_ENUM_LABEL_QUICK_MENU_SHOW_UNDO_SAVE_LOAD_STATE: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_quick_menu_show_undo_save_load_state); break; @@ -3221,6 +3247,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_STATE_SLOT: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_state_slot); break; + case MENU_ENUM_LABEL_REPLAY_SLOT: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_replay_slot); + break; case MENU_ENUM_LABEL_RESUME: case MENU_ENUM_LABEL_RESUME_CONTENT: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_resume_content); @@ -3231,6 +3260,15 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_LOAD_STATE: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_load_state); break; + case MENU_ENUM_LABEL_HALT_REPLAY: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_halt_replay); + break; + case MENU_ENUM_LABEL_RECORD_REPLAY: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_record_replay); + break; + case MENU_ENUM_LABEL_PLAY_REPLAY: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_play_replay); + break; case MENU_ENUM_LABEL_CLOSE_CONTENT: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_close_content); break; diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index ad420e8eef..52b210c0b3 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -231,6 +231,10 @@ enum MUI_TEXTURE_UNDO_LOAD_STATE, MUI_TEXTURE_UNDO_SAVE_STATE, MUI_TEXTURE_STATE_SLOT, + MUI_TEXTURE_PLAY_REPLAY, + MUI_TEXTURE_RECORD_REPLAY, + MUI_TEXTURE_HALT_REPLAY, + MUI_TEXTURE_REPLAY_SLOT, MUI_TEXTURE_TAKE_SCREENSHOT, MUI_TEXTURE_CONFIGURATIONS, MUI_TEXTURE_LOAD_CONTENT, @@ -2122,6 +2126,12 @@ static const char *materialui_texture_path(unsigned id) return "load_state.png"; case MUI_TEXTURE_SAVE_STATE: return "save_state.png"; + case MUI_TEXTURE_PLAY_REPLAY: + return "load_state.png"; + case MUI_TEXTURE_RECORD_REPLAY: + return "save_state.png"; + case MUI_TEXTURE_HALT_REPLAY: + return "remove.png"; case MUI_TEXTURE_DISK: return "disk.png"; case MUI_TEXTURE_EJECT: @@ -10621,6 +10631,21 @@ static void materialui_list_insert( node->icon_texture_index = MUI_TEXTURE_LOAD_STATE; node->icon_type = MUI_ICON_TYPE_INTERNAL; } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_PLAY_REPLAY))) + { + node->icon_texture_index = MUI_TEXTURE_PLAY_REPLAY; + node->icon_type = MUI_ICON_TYPE_INTERNAL; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_RECORD_REPLAY))) + { + node->icon_texture_index = MUI_TEXTURE_RECORD_REPLAY; + node->icon_type = MUI_ICON_TYPE_INTERNAL; + } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HALT_REPLAY))) + { + node->icon_texture_index = MUI_TEXTURE_HALT_REPLAY; + node->icon_type = MUI_ICON_TYPE_INTERNAL; + } else if ( string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DISK_TRAY_EJECT)) || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DISK_TRAY_INSERT)) @@ -10675,6 +10700,11 @@ static void materialui_list_insert( node->icon_texture_index = MUI_TEXTURE_STATE_SLOT; node->icon_type = MUI_ICON_TYPE_INTERNAL; } + else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_REPLAY_SLOT))) + { + node->icon_texture_index = MUI_TEXTURE_REPLAY_SLOT; + node->icon_type = MUI_ICON_TYPE_INTERNAL; + } else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_TAKE_SCREENSHOT))) { node->icon_texture_index = MUI_TEXTURE_TAKE_SCREENSHOT; diff --git a/menu/drivers/ozone.c b/menu/drivers/ozone.c index 9cf7f92cf0..7448f36d8b 100644 --- a/menu/drivers/ozone.c +++ b/menu/drivers/ozone.c @@ -220,6 +220,9 @@ enum OZONE_ENTRIES_ICONS_TEXTURE_RESUME, OZONE_ENTRIES_ICONS_TEXTURE_SAVESTATE, OZONE_ENTRIES_ICONS_TEXTURE_LOADSTATE, + OZONE_ENTRIES_ICONS_TEXTURE_RECORDREPLAY, + OZONE_ENTRIES_ICONS_TEXTURE_PLAYREPLAY, + OZONE_ENTRIES_ICONS_TEXTURE_HALTREPLAY, OZONE_ENTRIES_ICONS_TEXTURE_UNDO, OZONE_ENTRIES_ICONS_TEXTURE_CORE_INFO, OZONE_ENTRIES_ICONS_TEXTURE_BLUETOOTH, @@ -1795,6 +1798,8 @@ static uintptr_t ozone_entries_icon_get_texture( return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_ACHIEVEMENT_LIST]; case MENU_ENUM_LABEL_STATE_SLOT: return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_SETTING]; + case MENU_ENUM_LABEL_REPLAY_SLOT: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_SETTING]; case MENU_ENUM_LABEL_SAVESTATE_LIST: case MENU_ENUM_LABEL_SAVE_STATE: case MENU_ENUM_LABEL_CORE_CREATE_BACKUP: @@ -1990,6 +1995,7 @@ static uintptr_t ozone_entries_icon_get_texture( case MENU_ENUM_LABEL_CHEAT_FILE_SAVE_AS: case MENU_ENUM_LABEL_QUICK_MENU_SHOW_SAVESTATE_SUBMENU: case MENU_ENUM_LABEL_QUICK_MENU_SHOW_SAVE_LOAD_STATE: + case MENU_ENUM_LABEL_QUICK_MENU_SHOW_REPLAY: return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_SAVING]; case MENU_ENUM_LABEL_LOGGING_SETTINGS: case MENU_ENUM_LABEL_SETTINGS_SHOW_LOGGING: @@ -2235,6 +2241,12 @@ static uintptr_t ozone_entries_icon_get_texture( return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_SAVESTATE]; case MENU_SETTING_ACTION_LOADSTATE: return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_LOADSTATE]; + case MENU_SETTING_ACTION_PLAYREPLAY: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_PLAYREPLAY]; + case MENU_SETTING_ACTION_RECORDREPLAY: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_RECORDREPLAY]; + case MENU_SETTING_ACTION_HALTREPLAY: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_HALTREPLAY]; case MENU_SETTING_ACTION_CORE_OPTIONS: if (string_starts_with(enum_path, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SETTINGS))) return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_VIDEO]; @@ -2506,6 +2518,12 @@ static const char *ozone_entries_icon_texture_path(unsigned id) return "savestate.png"; case OZONE_ENTRIES_ICONS_TEXTURE_LOADSTATE: return "loadstate.png"; + case OZONE_ENTRIES_ICONS_TEXTURE_RECORDREPLAY: + return "savestate.png"; + case OZONE_ENTRIES_ICONS_TEXTURE_PLAYREPLAY: + return "loadstate.png"; + case OZONE_ENTRIES_ICONS_TEXTURE_HALTREPLAY: + return "close.png"; case OZONE_ENTRIES_ICONS_TEXTURE_UNDO: return "undo.png"; case OZONE_ENTRIES_ICONS_TEXTURE_CORE_INFO: diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index dd9004453b..a4b51044f7 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -126,6 +126,9 @@ enum XMB_TEXTURE_RESUME, XMB_TEXTURE_SAVESTATE, XMB_TEXTURE_LOADSTATE, + XMB_TEXTURE_RECORDREPLAY, + XMB_TEXTURE_PLAYREPLAY, + XMB_TEXTURE_HALTREPLAY, XMB_TEXTURE_UNDO, XMB_TEXTURE_CORE_INFO, XMB_TEXTURE_BLUETOOTH, @@ -3124,6 +3127,7 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, case MENU_ENUM_LABEL_CHEAT_FILE_SAVE_AS: case MENU_ENUM_LABEL_QUICK_MENU_SHOW_SAVESTATE_SUBMENU: case MENU_ENUM_LABEL_QUICK_MENU_SHOW_SAVE_LOAD_STATE: + case MENU_ENUM_LABEL_QUICK_MENU_SHOW_REPLAY: return xmb->textures.list[XMB_TEXTURE_SAVING]; case MENU_ENUM_LABEL_LOGGING_SETTINGS: case MENU_ENUM_LABEL_SETTINGS_SHOW_LOGGING: @@ -3372,6 +3376,12 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, return xmb->textures.list[XMB_TEXTURE_SAVESTATE]; case MENU_SETTING_ACTION_LOADSTATE: return xmb->textures.list[XMB_TEXTURE_LOADSTATE]; + case MENU_SETTING_ACTION_PLAYREPLAY: + return xmb->textures.list[XMB_TEXTURE_PLAYREPLAY]; + case MENU_SETTING_ACTION_RECORDREPLAY: + return xmb->textures.list[XMB_TEXTURE_RECORDREPLAY]; + case MENU_SETTING_ACTION_HALTREPLAY: + return xmb->textures.list[XMB_TEXTURE_HALTREPLAY]; case MENU_SETTING_ACTION_CORE_OPTIONS: if (string_starts_with(enum_path, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SETTINGS))) return xmb->textures.list[XMB_TEXTURE_VIDEO]; @@ -6942,6 +6952,12 @@ static const char *xmb_texture_path(unsigned id) return "savestate.png"; case XMB_TEXTURE_LOADSTATE: return "loadstate.png"; + case XMB_TEXTURE_RECORDREPLAY: + return "savestate.png"; + case XMB_TEXTURE_PLAYREPLAY: + return "loadstate.png"; + case XMB_TEXTURE_HALTREPLAY: + return "close.png"; case XMB_TEXTURE_UNDO: return "undo.png"; case XMB_TEXTURE_CORE_INFO: diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 716cef84b0..bb96775b06 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -3504,8 +3504,37 @@ static int menu_displaylist_parse_load_content_settings( MENU_SETTING_ACTION_LOADSTATE, 0, 0, NULL)) count++; } - } +#ifdef HAVE_BSV_MOVIE + if (savestates_enabled && + settings->bools.quick_menu_show_replay) + { + if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list, + MENU_ENUM_LABEL_REPLAY_SLOT, PARSE_ONLY_INT, true) == 0) + count++; + if (menu_entries_append(list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RECORD_REPLAY), + msg_hash_to_str(MENU_ENUM_LABEL_RECORD_REPLAY), + MENU_ENUM_LABEL_RECORD_REPLAY, + MENU_SETTING_ACTION_RECORDREPLAY, 0, 0, NULL)) + count++; + + if (menu_entries_append(list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PLAY_REPLAY), + msg_hash_to_str(MENU_ENUM_LABEL_PLAY_REPLAY), + MENU_ENUM_LABEL_PLAY_REPLAY, + MENU_SETTING_ACTION_PLAYREPLAY, 0, 0, NULL)) + count++; + + if (menu_entries_append(list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_HALT_REPLAY), + msg_hash_to_str(MENU_ENUM_LABEL_HALT_REPLAY), + MENU_ENUM_LABEL_HALT_REPLAY, + MENU_SETTING_ACTION_HALTREPLAY, 0, 0, NULL)) + count++; + } +#endif + } if (settings->bools.quick_menu_show_options && !settings->bools.kiosk_mode_enable) { /* Empty 'path' string signifies top level @@ -9720,6 +9749,8 @@ unsigned menu_displaylist_build_list( {MENU_ENUM_LABEL_SAVESTATE_AUTO_SAVE, PARSE_ONLY_BOOL, true}, {MENU_ENUM_LABEL_SAVESTATE_AUTO_LOAD, PARSE_ONLY_BOOL, true}, {MENU_ENUM_LABEL_SAVESTATE_THUMBNAIL_ENABLE, PARSE_ONLY_BOOL, true}, + {MENU_ENUM_LABEL_REPLAY_AUTO_INDEX, PARSE_ONLY_BOOL, true}, + {MENU_ENUM_LABEL_REPLAY_MAX_KEEP, PARSE_ONLY_UINT, false}, {MENU_ENUM_LABEL_SAVE_FILE_COMPRESSION, PARSE_ONLY_BOOL, true}, {MENU_ENUM_LABEL_SAVESTATE_FILE_COMPRESSION, PARSE_ONLY_BOOL, true}, {MENU_ENUM_LABEL_SORT_SCREENSHOTS_BY_CONTENT_ENABLE, PARSE_ONLY_BOOL, true}, @@ -10081,6 +10112,7 @@ unsigned menu_displaylist_build_list( {MENU_ENUM_LABEL_QUICK_MENU_SHOW_SAVESTATE_SUBMENU, PARSE_ONLY_BOOL}, {MENU_ENUM_LABEL_QUICK_MENU_SHOW_SAVE_LOAD_STATE, PARSE_ONLY_BOOL}, {MENU_ENUM_LABEL_QUICK_MENU_SHOW_UNDO_SAVE_LOAD_STATE, PARSE_ONLY_BOOL}, + {MENU_ENUM_LABEL_QUICK_MENU_SHOW_REPLAY, PARSE_ONLY_BOOL}, {MENU_ENUM_LABEL_QUICK_MENU_SHOW_OPTIONS, PARSE_ONLY_BOOL}, {MENU_ENUM_LABEL_QUICK_MENU_SHOW_CORE_OPTIONS_FLUSH, PARSE_ONLY_BOOL}, {MENU_ENUM_LABEL_QUICK_MENU_SHOW_CONTROLS, PARSE_ONLY_BOOL}, @@ -12946,6 +12978,36 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, MENU_SETTING_ACTION_LOADSTATE, 0, 0, NULL)) count++; } +#ifdef HAVE_BSV_MOVIE + if (savestates_enabled && + settings->bools.quick_menu_show_replay) + { + if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list, + MENU_ENUM_LABEL_REPLAY_SLOT, PARSE_ONLY_INT, true) == 0) + count++; + + if (menu_entries_append(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RECORD_REPLAY), + msg_hash_to_str(MENU_ENUM_LABEL_RECORD_REPLAY), + MENU_ENUM_LABEL_RECORD_REPLAY, + MENU_SETTING_ACTION_RECORDREPLAY, 0, 0, NULL)) + count++; + + if (menu_entries_append(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PLAY_REPLAY), + msg_hash_to_str(MENU_ENUM_LABEL_PLAY_REPLAY), + MENU_ENUM_LABEL_PLAY_REPLAY, + MENU_SETTING_ACTION_PLAYREPLAY, 0, 0, NULL)) + count++; + + if (menu_entries_append(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_HALT_REPLAY), + msg_hash_to_str(MENU_ENUM_LABEL_HALT_REPLAY), + MENU_ENUM_LABEL_HALT_REPLAY, + MENU_SETTING_ACTION_HALTREPLAY, 0, 0, NULL)) + count++; + } +#endif if (count == 0) menu_entries_append(info->list, diff --git a/menu/menu_driver.c b/menu/menu_driver.c index 7fbca319eb..77d799f132 100644 --- a/menu/menu_driver.c +++ b/menu/menu_driver.c @@ -8510,6 +8510,18 @@ size_t menu_update_fullscreen_thumbnail_label( config_get_ptr()->ints.state_slot); thumbnail_label = tmpstr; } + else if (is_quick_menu && ( + string_is_equal(selected_entry.label, "replay_slot") || + string_is_equal(selected_entry.label, "record_replay") || + string_is_equal(selected_entry.label, "play_replay") || + string_is_equal(selected_entry.label, "halt_replay") + )) + { + snprintf(tmpstr, sizeof(tmpstr), "%s %d", + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_REPLAY_SLOT), + config_get_ptr()->ints.replay_slot); + thumbnail_label = tmpstr; + } else if (string_to_unsigned(selected_entry.label) == MENU_ENUM_LABEL_STATE_SLOT) { snprintf(tmpstr, sizeof(tmpstr), "%s %d", diff --git a/menu/menu_driver.h b/menu/menu_driver.h index e7fe155a99..f49964afa6 100644 --- a/menu/menu_driver.h +++ b/menu/menu_driver.h @@ -148,6 +148,9 @@ enum menu_settings_type MENU_SETTING_ACTION_CORE_SHADER_OPTIONS, MENU_SETTING_ACTION_SAVESTATE, MENU_SETTING_ACTION_LOADSTATE, + MENU_SETTING_ACTION_PLAYREPLAY, + MENU_SETTING_ACTION_RECORDREPLAY, + MENU_SETTING_ACTION_HALTREPLAY, MENU_SETTING_ACTION_SCREENSHOT, MENU_SETTING_ACTION_DELETE_ENTRY, MENU_SETTING_ACTION_RESET, diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 5fa8adbae0..97757f7a9f 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -9590,6 +9590,25 @@ static bool setting_append_list( &setting_get_string_representation_state_slot; menu_settings_list_current_add_range(list, list_info, -1, 999, 1, true, true); +#ifdef HAVE_BSV_MOVIE + CONFIG_INT( + list, list_info, + &settings->ints.replay_slot, + MENU_ENUM_LABEL_REPLAY_SLOT, + MENU_ENUM_LABEL_VALUE_REPLAY_SLOT, + 0, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler); + (*list)[list_info->index - 1].action_ok = &setting_action_ok_uint; + (*list)[list_info->index - 1].offset_by = -1; + (*list)[list_info->index - 1].get_string_representation = + &setting_get_string_representation_state_slot; + menu_settings_list_current_add_range(list, list_info, -1, 999, 1, true, true); +#endif + CONFIG_ACTION( list, list_info, MENU_ENUM_LABEL_START_CORE, @@ -11109,6 +11128,40 @@ static bool setting_append_list( (*list)[list_info->index - 1].action_ok = &setting_action_ok_uint; menu_settings_list_current_add_range(list, list_info, 0, 999, 1, true, true); +#ifdef HAVE_BSV_MOVIE + CONFIG_BOOL( + list, list_info, + &settings->bools.replay_auto_index, + MENU_ENUM_LABEL_REPLAY_AUTO_INDEX, + MENU_ENUM_LABEL_VALUE_REPLAY_AUTO_INDEX, + DEFAULT_REPLAY_AUTO_INDEX, + MENU_ENUM_LABEL_VALUE_OFF, + MENU_ENUM_LABEL_VALUE_ON, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler, + SD_FLAG_NONE); + (*list)[list_info->index - 1].action_ok = &setting_bool_action_left_with_refresh; + (*list)[list_info->index - 1].action_left = &setting_bool_action_left_with_refresh; + (*list)[list_info->index - 1].action_right = &setting_bool_action_right_with_refresh; + + CONFIG_UINT( + list, list_info, + &settings->uints.replay_max_keep, + MENU_ENUM_LABEL_REPLAY_MAX_KEEP, + MENU_ENUM_LABEL_VALUE_REPLAY_MAX_KEEP, + DEFAULT_REPLAY_MAX_KEEP, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler); + (*list)[list_info->index - 1].action_ok = &setting_action_ok_uint; + menu_settings_list_current_add_range(list, list_info, 0, 999, 1, true, true); +#endif + CONFIG_BOOL( list, list_info, &settings->bools.content_runtime_log, @@ -19351,6 +19404,21 @@ static bool setting_append_list( general_read_handler, SD_FLAG_NONE); + CONFIG_BOOL( + list, list_info, + &settings->bools.quick_menu_show_replay, + MENU_ENUM_LABEL_QUICK_MENU_SHOW_REPLAY, + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_REPLAY, + DEFAULT_QUICK_MENU_SHOW_REPLAY, + MENU_ENUM_LABEL_VALUE_OFF, + MENU_ENUM_LABEL_VALUE_ON, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler, + SD_FLAG_NONE); + CONFIG_BOOL( list, list_info, &settings->bools.quick_menu_show_undo_save_load_state, diff --git a/msg_hash.h b/msg_hash.h index 868e76b499..0d1ef3935c 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -280,6 +280,7 @@ enum msg_hash_enums MSG_VALUE_REBOOTING, MSG_FAILED_TO_START_AUDIO_DRIVER, MSG_FOUND_LAST_STATE_SLOT, + MSG_FOUND_LAST_REPLAY_SLOT, MSG_RESTORED_OLD_SAVE_STATE, MSG_NO_STATE_HAS_BEEN_LOADED_YET, MSG_GOT_CONNECTION_FROM, @@ -460,6 +461,7 @@ enum msg_hash_enums MSG_FAILED_TO_START_MOVIE_RECORD, MSG_CHEEVOS_HARDCORE_MODE_ENABLE, MSG_STATE_SLOT, + MSG_REPLAY_SLOT, MSG_STARTING_MOVIE_RECORD_TO, MSG_FAILED_TO_APPLY_SHADER, MSG_FAILED_TO_APPLY_SHADER_PRESET, @@ -1025,6 +1027,12 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_PLUS, MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_MINUS, + MENU_ENUM_LABEL_VALUE_INPUT_META_PLAY_REPLAY_KEY, + MENU_ENUM_LABEL_VALUE_INPUT_META_RECORD_REPLAY_KEY, + MENU_ENUM_LABEL_VALUE_INPUT_META_HALT_REPLAY_KEY, + MENU_ENUM_LABEL_VALUE_INPUT_META_REPLAY_SLOT_PLUS, + MENU_ENUM_LABEL_VALUE_INPUT_META_REPLAY_SLOT_MINUS, + MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_EJECT_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_NEXT, MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_PREV, @@ -1040,7 +1048,6 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_INPUT_META_SCREENSHOT, MENU_ENUM_LABEL_VALUE_INPUT_META_RECORDING_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_STREAMING_TOGGLE, - MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_GAME_FOCUS_TOGGLE, @@ -1102,6 +1109,12 @@ enum msg_hash_enums MENU_ENUM_SUBLABEL_INPUT_META_STATE_SLOT_PLUS, MENU_ENUM_SUBLABEL_INPUT_META_STATE_SLOT_MINUS, + MENU_ENUM_SUBLABEL_INPUT_META_PLAY_REPLAY_KEY, + MENU_ENUM_SUBLABEL_INPUT_META_RECORD_REPLAY_KEY, + MENU_ENUM_SUBLABEL_INPUT_META_HALT_REPLAY_KEY, + MENU_ENUM_SUBLABEL_INPUT_META_REPLAY_SLOT_PLUS, + MENU_ENUM_SUBLABEL_INPUT_META_REPLAY_SLOT_MINUS, + MENU_ENUM_SUBLABEL_INPUT_META_DISK_EJECT_TOGGLE, MENU_ENUM_SUBLABEL_INPUT_META_DISK_NEXT, MENU_ENUM_SUBLABEL_INPUT_META_DISK_PREV, @@ -1117,7 +1130,6 @@ enum msg_hash_enums MENU_ENUM_SUBLABEL_INPUT_META_SCREENSHOT, MENU_ENUM_SUBLABEL_INPUT_META_RECORDING_TOGGLE, MENU_ENUM_SUBLABEL_INPUT_META_STREAMING_TOGGLE, - MENU_ENUM_SUBLABEL_INPUT_META_BSV_RECORD_TOGGLE, MENU_ENUM_SUBLABEL_INPUT_META_GRAB_MOUSE_TOGGLE, MENU_ENUM_SUBLABEL_INPUT_META_GAME_FOCUS_TOGGLE, @@ -1500,6 +1512,7 @@ enum msg_hash_enums MENU_LABEL(QUICK_MENU_SHOW_SAVESTATE_SUBMENU), MENU_LABEL(QUICK_MENU_SHOW_SAVE_LOAD_STATE), MENU_LABEL(QUICK_MENU_SHOW_UNDO_SAVE_LOAD_STATE), + MENU_LABEL(QUICK_MENU_SHOW_REPLAY), MENU_LABEL(QUICK_MENU_SHOW_ADD_TO_FAVORITES), MENU_LABEL(QUICK_MENU_SHOW_START_RECORDING), MENU_LABEL(QUICK_MENU_SHOW_START_STREAMING), @@ -2087,6 +2100,11 @@ enum msg_hash_enums MENU_LABEL(UNDO_LOAD_STATE), MENU_LABEL(UNDO_SAVE_STATE), + MENU_LABEL(PLAY_REPLAY), + MENU_LABEL(RECORD_REPLAY), + MENU_LABEL(HALT_REPLAY), + MENU_LABEL(REPLAY_SLOT), + MENU_LABEL(NETPLAY_GAME_WATCH), MENU_LABEL(CHEAT_INDEX_MINUS), MENU_LABEL(CHEAT_INDEX_PLUS), @@ -2100,7 +2118,6 @@ enum msg_hash_enums MENU_LABEL(MEMORY_UPDATE_INTERVAL), MENU_LABEL(STATISTICS_SHOW), MENU_LABEL(FRAMECOUNT_SHOW), - MENU_LABEL(BSV_RECORD_TOGGLE), MENU_ENUM_LABEL_L_X_PLUS, MENU_ENUM_LABEL_L_X_MINUS, MENU_ENUM_LABEL_L_Y_PLUS, @@ -2220,6 +2237,8 @@ enum msg_hash_enums MENU_LABEL(SAVESTATE_AUTO_INDEX), MENU_LABEL(SAVESTATE_MAX_KEEP), + MENU_LABEL(REPLAY_AUTO_INDEX), + MENU_LABEL(REPLAY_MAX_KEEP), MENU_LABEL(SAVESTATE_AUTO_SAVE), MENU_LABEL(SAVESTATE_AUTO_LOAD), MENU_LABEL(SAVESTATE_THUMBNAIL_ENABLE), @@ -2331,6 +2350,8 @@ enum msg_hash_enums MENU_ENUM_LABEL_GAME_FOCUS_TOGGLE, MENU_LABEL(STATE_SLOT_DECREASE), MENU_LABEL(STATE_SLOT_INCREASE), + MENU_LABEL(REPLAY_SLOT_DECREASE), + MENU_LABEL(REPLAY_SLOT_INCREASE), MENU_LABEL(FRONTEND_LOG_LEVEL), MENU_LBL_H(LIBRETRO_LOG_LEVEL), diff --git a/retroarch.c b/retroarch.c index 5f18c27ab1..dbbc05e830 100644 --- a/retroarch.c +++ b/retroarch.c @@ -2172,14 +2172,6 @@ bool command_event(enum event_command cmd, void *data) video_shader_toggle(settings); #endif break; - case CMD_EVENT_BSV_RECORDING_TOGGLE: - { -#ifdef HAVE_BSV_MOVIE - input_driver_state_t *input_st = input_state_get_ptr(); - movie_toggle_record(input_st, settings); -#endif - } - break; case CMD_EVENT_AI_SERVICE_TOGGLE: { #ifdef HAVE_TRANSLATE @@ -2441,17 +2433,6 @@ bool command_event(enum event_command cmd, void *data) #endif case CMD_EVENT_LOAD_STATE: { -#ifdef HAVE_BSV_MOVIE - /* Immutable - disallow savestate load when - * we absolutely cannot change game state. */ - input_driver_state_t *input_st = input_state_get_ptr(); - if (input_st->bsv_movie_state_handle) - { - RARCH_LOG("[Load] [Movie] Can't load state during movie playback or record\n"); - return false; - } -#endif - #ifdef HAVE_CHEEVOS if (rcheevos_hardcore_active()) { @@ -2528,6 +2509,81 @@ bool command_event(enum event_command cmd, void *data) command_event(CMD_EVENT_PREEMPT_RESET_BUFFER, NULL); #endif return false; + case CMD_EVENT_PLAY_REPLAY: + { + bool res = false; +#ifdef HAVE_BSV_MOVIE + input_driver_state_t *input_st = input_state_get_ptr(); + char replay_path[PATH_MAX_LENGTH]; + res = true; + /* TODO: Consider extending the current replay if we start recording during a playback */ + if (input_st->bsv_movie_state.flags & BSV_FLAG_MOVIE_RECORDING) + res = false; + else if (input_st->bsv_movie_state.flags & BSV_FLAG_MOVIE_PLAYBACK) + res = movie_stop(input_st); + if (!runloop_get_current_replay_path(replay_path, sizeof(replay_path))) + res = false; + if (res) + res = movie_start_playback(input_st, replay_path); + if(!res) + { + const char *movie_fail_str = + msg_hash_to_str(MSG_FAILED_TO_LOAD_MOVIE_FILE); + runloop_msg_queue_push(movie_fail_str, + 1, 180, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + RARCH_ERR("%s.\n", movie_fail_str); + } + return res; +#else + return false; +#endif + } + case CMD_EVENT_RECORD_REPLAY: + { + bool res = false; +#ifdef HAVE_BSV_MOVIE + input_driver_state_t *input_st = input_state_get_ptr(); + char replay_path[PATH_MAX_LENGTH]; + res = true; + /* TODO: Consider cloning and extending the current replay if we start recording during a recording */ + if (input_st->bsv_movie_state.flags & BSV_FLAG_MOVIE_RECORDING) + res = false; + else if (input_st->bsv_movie_state.flags & BSV_FLAG_MOVIE_PLAYBACK) + res = movie_stop(input_st); + RARCH_ERR("[Movie] res after stop check: %d\n",res); + if (!runloop_get_current_replay_path(replay_path, sizeof(replay_path))) + res = false; + RARCH_ERR("[Movie] res after path get: %d\n",res); + if(res) + res = movie_start_record(input_st, replay_path); + RARCH_ERR("[Movie] res after start record: %d\n",res); + + if(res && settings->bools.replay_auto_index) + { + int new_replay_slot = settings->ints.replay_slot + 1; + configuration_set_int(settings, settings->ints.replay_slot, new_replay_slot); + } + if(!res) + { + const char *movie_rec_fail_str = + msg_hash_to_str(MSG_FAILED_TO_START_MOVIE_RECORD); + runloop_msg_queue_push(movie_rec_fail_str, + 1, 180, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + RARCH_ERR("%s.\n", movie_rec_fail_str); + } +#endif + return res; + } + case CMD_EVENT_HALT_REPLAY: + { +#ifdef HAVE_BSV_MOVIE + input_driver_state_t *input_st = input_state_get_ptr(); + movie_stop(input_st); +#endif + return true; + } case CMD_EVENT_SAVE_STATE: case CMD_EVENT_SAVE_STATE_TO_RAM: { @@ -2560,6 +2616,28 @@ bool command_event(enum event_command cmd, void *data) configuration_set_int(settings, settings->ints.state_slot, new_state_slot); } break; + case CMD_EVENT_REPLAY_DECREMENT: +#ifdef HAVE_BSV_MOVIE + { + int slot = settings->ints.replay_slot; + + /* Slot -1 is (auto) slot. */ + if (slot >= 0) + { + int new_slot = slot - 1; + configuration_set_int(settings, settings->ints.replay_slot, new_slot); + } + } +#endif + break; + case CMD_EVENT_REPLAY_INCREMENT: +#ifdef HAVE_BSV_MOVIE + { + int new_slot = settings->ints.replay_slot + 1; + configuration_set_int(settings, settings->ints.replay_slot, new_slot); + } +#endif + break; case CMD_EVENT_TAKE_SCREENSHOT: #ifdef HAVE_SCREENSHOTS { @@ -4391,6 +4469,7 @@ static void global_free(struct rarch_state *p_rarch) *runloop_st->name.ips = '\0'; *runloop_st->name.savefile = '\0'; *runloop_st->name.savestate = '\0'; + *runloop_st->name.replay = '\0'; *runloop_st->name.cheatfile = '\0'; *runloop_st->name.label = '\0'; @@ -5449,6 +5528,8 @@ static bool retroarch_parse_input_and_config( case 'S': strlcpy(runloop_st->name.savestate, optarg, sizeof(runloop_st->name.savestate)); + strlcpy(runloop_st->name.replay, optarg, + sizeof(runloop_st->name.replay)); retroarch_override_setting_set( RARCH_OVERRIDE_SETTING_STATE_PATH, NULL); break; diff --git a/runloop.c b/runloop.c index 8e94e4db28..ac37daaaae 100644 --- a/runloop.c +++ b/runloop.c @@ -4067,6 +4067,7 @@ static bool event_init_content( return false; command_event_set_savestate_auto_index(settings); + command_event_set_replay_auto_index(settings); runloop_path_init_savefile(runloop_st); @@ -4627,7 +4628,7 @@ void runloop_path_fill_names(void) #ifdef HAVE_BSV_MOVIE strlcpy(input_st->bsv_movie_state.movie_auto_path, - runloop_st->name.savefile, + runloop_st->name.replay, sizeof(input_st->bsv_movie_state.movie_auto_path)); #endif @@ -6388,6 +6389,69 @@ static enum runloop_state_enum runloop_check_state( old_should_slot_increase = should_slot_increase; old_should_slot_decrease = should_slot_decrease; } + /* Check replay slot hotkeys */ + { + static bool old_should_replay_slot_increase = false; + static bool old_should_replay_slot_decrease = false; + bool should_slot_increase = BIT256_GET( + current_bits, RARCH_REPLAY_SLOT_PLUS); + bool should_slot_decrease = BIT256_GET( + current_bits, RARCH_REPLAY_SLOT_MINUS); + bool check1 = true; + bool check2 = should_slot_increase && !old_should_replay_slot_increase; + int addition = 1; + int replay_slot = settings->ints.replay_slot; + + if (!check2) + { + check2 = should_slot_decrease && !old_should_replay_slot_decrease; + check1 = replay_slot > -1; + addition = -1; + + /* Wrap-around to 999 */ + if (check2 && !check1 && replay_slot + addition < -1) + { + replay_slot = 1000; + check1 = true; + } + } + /* Wrap-around to -1 (Auto) */ + else if (replay_slot + addition > 999) + replay_slot = -2; + + if (check2) + { + size_t _len; + char msg[128]; + int cur_replay_slot = replay_slot + addition; + + if (check1) + configuration_set_int(settings, settings->ints.replay_slot, + cur_replay_slot); + _len = strlcpy(msg, msg_hash_to_str(MSG_REPLAY_SLOT), sizeof(msg)); + + snprintf(msg + _len, + sizeof(msg) - _len, + ": %d", + settings->ints.replay_slot); + + if (cur_replay_slot < 0) + strlcat(msg, " (Auto)", sizeof(msg)); + +#ifdef HAVE_GFX_WIDGETS + if (dispwidget_get_ptr()->active) + gfx_widget_set_generic_message(msg, 1000); + else +#endif + runloop_msg_queue_push(msg, 2, 60, true, NULL, + MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + + RARCH_LOG("[Replay]: %s\n", msg); + } + + old_should_replay_slot_increase = should_slot_increase; + old_should_replay_slot_decrease = should_slot_decrease; + } /* Check save state hotkeys */ HOTKEY_CHECK(RARCH_SAVE_STATE_KEY, CMD_EVENT_SAVE_STATE, true, NULL); @@ -6399,8 +6463,10 @@ static enum runloop_state_enum runloop_check_state( /* Check VRR runloop hotkey */ HOTKEY_CHECK(RARCH_VRR_RUNLOOP_TOGGLE, CMD_EVENT_VRR_RUNLOOP_TOGGLE, true, NULL); - /* Check movie record hotkey */ - HOTKEY_CHECK(RARCH_BSV_RECORD_TOGGLE, CMD_EVENT_BSV_RECORDING_TOGGLE, true, NULL); + /* Check bsv movie hotkeys */ + HOTKEY_CHECK(RARCH_PLAY_REPLAY_KEY, CMD_EVENT_PLAY_REPLAY, true, NULL); + HOTKEY_CHECK(RARCH_RECORD_REPLAY_KEY, CMD_EVENT_RECORD_REPLAY, true, NULL); + HOTKEY_CHECK(RARCH_HALT_REPLAY_KEY, CMD_EVENT_HALT_REPLAY, true, NULL); /* Check Disc Control hotkeys */ HOTKEY_CHECK3( @@ -7133,6 +7199,32 @@ bool runloop_get_savestate_path(char *path, size_t len, unsigned state_slot) return true; } +bool runloop_get_current_replay_path(char *path, size_t len) +{ + settings_t *settings = config_get_ptr(); + int slot = settings ? settings->ints.replay_slot : 0; + return runloop_get_replay_path(path, len, slot); +} +bool runloop_get_replay_path(char *path, size_t len, unsigned slot) +{ + runloop_state_t *runloop_st = &runloop_state; + const char *name_replay = NULL; + + if (!path) + return false; + + name_replay = runloop_st->name.replay; + if (string_is_empty(name_replay)) + return false; + + if (slot >= 0) + snprintf(path, len, "%s%d", name_replay, slot); + else + strlcpy(path, name_replay, len); + + return true; +} + bool runloop_get_entry_state_path(char *path, size_t len, unsigned slot) { @@ -7621,6 +7713,22 @@ void runloop_path_set_names(void) runloop_st->name.savestate[len+6] = '\0'; } +#ifdef HAVE_BSV_MOVIE + if (!retroarch_override_setting_is_set( + RARCH_OVERRIDE_SETTING_STATE_PATH, NULL)) + { + size_t len = strlcpy( + runloop_st->name.replay, + runloop_st->runtime_content_path_basename, + sizeof(runloop_st->name.replay)); + runloop_st->name.replay[len ] = '.'; + runloop_st->name.replay[len+1] = 'b'; + runloop_st->name.replay[len+2] = 's'; + runloop_st->name.replay[len+3] = 'v'; + runloop_st->name.replay[len+4] = '\0'; + } +#endif + #ifdef HAVE_CHEATS if (!string_is_empty(runloop_st->runtime_content_path_basename)) { @@ -7800,8 +7908,12 @@ void runloop_path_set_redirect(settings_t *settings, savefile_is_dir = path_is_directory(runloop_st->name.savefile); if (savestate_is_dir) + { strlcpy(runloop_st->name.savestate, new_savestate_dir, - sizeof(runloop_st->name.savestate)); + sizeof(runloop_st->name.savestate)); + strlcpy(runloop_st->name.replay, new_savestate_dir, + sizeof(runloop_st->name.replay)); + } else savestate_is_dir = path_is_directory(runloop_st->name.savestate); @@ -7826,6 +7938,12 @@ void runloop_path_set_redirect(settings_t *settings, : system->library_name, FILE_PATH_STATE_EXTENSION, sizeof(runloop_st->name.savestate)); + fill_pathname_dir(runloop_st->name.replay, + !string_is_empty(runloop_st->runtime_content_path_basename) + ? runloop_st->runtime_content_path_basename + : system->library_name, + FILE_PATH_BSV_EXTENSION, + sizeof(runloop_st->name.replay)); RARCH_LOG("[Overrides]: %s \"%s\".\n", msg_hash_to_str(MSG_REDIRECTING_SAVESTATE_TO), runloop_st->name.savestate); @@ -7895,8 +8013,12 @@ void runloop_path_set_special(char **argv, unsigned num_content) is_dir = path_is_directory(savestate_dir); if (is_dir) + { strlcpy(runloop_st->name.savestate, savestate_dir, - sizeof(runloop_st->name.savestate)); /* TODO/FIXME - why are we setting this string here but then later overwriting it later with fil_pathname_dir? */ + sizeof(runloop_st->name.savestate)); /* TODO/FIXME - why are we setting this string here but then later overwriting it later with fil_pathname_dir? */ + strlcpy(runloop_st->name.replay, savestate_dir, + sizeof(runloop_st->name.replay)); /* TODO/FIXME - as above */ + } else is_dir = path_is_directory(runloop_st->name.savestate); @@ -7906,6 +8028,10 @@ void runloop_path_set_special(char **argv, unsigned num_content) str, ".state", sizeof(runloop_st->name.savestate)); + fill_pathname_dir(runloop_st->name.replay, + str, + ".bsv", + sizeof(runloop_st->name.replay)); RARCH_LOG("%s \"%s\".\n", msg_hash_to_str(MSG_REDIRECTING_SAVESTATE_TO), runloop_st->name.savestate); diff --git a/runloop.h b/runloop.h index b7d75e9b2b..976b32f051 100644 --- a/runloop.h +++ b/runloop.h @@ -290,6 +290,7 @@ struct runloop char *remapfile; char savefile[8192]; char savestate[8192]; + char replay[8192]; char cheatfile[8192]; char ups[8192]; char bps[8192]; @@ -427,6 +428,10 @@ bool runloop_get_current_savestate_path(char *path, size_t len); bool runloop_get_savestate_path(char *path, size_t len, unsigned slot); +bool runloop_get_current_replay_path(char *path, size_t len); + +bool runloop_get_replay_path(char *path, size_t len, unsigned slot); + void runloop_state_free(runloop_state_t *runloop_st); void runloop_path_set_redirect(settings_t *settings, const char *a, const char *b); diff --git a/tasks/task_movie.c b/tasks/task_movie.c index de71353f19..e6cbfc88e1 100644 --- a/tasks/task_movie.c +++ b/tasks/task_movie.c @@ -22,6 +22,7 @@ #include #include #include +#include #ifdef _WIN32 #include @@ -348,19 +349,6 @@ static void moviectl_start_record_cb(retro_task_t *task, /* Public functions */ -bool movie_toggle_record(input_driver_state_t *input_st, settings_t *settings) -{ - if (!input_st->bsv_movie_state_handle) - { - char path[8192]; - configuration_set_uint(settings, settings->uints.rewind_granularity, 1); - fill_str_dated_filename(path, input_st->bsv_movie_state.movie_auto_path, "bsv", sizeof(path)); - return movie_start_record(input_st, path); - } - - return movie_stop(input_st); -} - /* In the future this should probably be a deferred task as well */ bool movie_stop_playback(input_driver_state_t *input_st) { @@ -392,6 +380,9 @@ bool movie_stop_record(input_driver_state_t *input_st) NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); RARCH_LOG("%s\n", movie_rec_stopped_str); bsv_movie_deinit(input_st); + input_st->bsv_movie_state.flags &= ~( + BSV_FLAG_MOVIE_END + | BSV_FLAG_MOVIE_RECORDING); return true; } @@ -400,8 +391,10 @@ bool movie_stop(input_driver_state_t *input_st) { if (input_st->bsv_movie_state.flags & BSV_FLAG_MOVIE_PLAYBACK) return movie_stop_playback(input_st); - else if (input_st->bsv_movie_state_handle) + else if (input_st->bsv_movie_state.flags & BSV_FLAG_MOVIE_RECORDING) return movie_stop_record(input_st); + if(input_st->bsv_movie_state_handle) + RARCH_ERR("Didn't really stop movie!\n"); return true; } @@ -409,7 +402,8 @@ bool movie_start_playback(input_driver_state_t *input_st, char *path) { retro_task_t *task = task_init(); moviectl_task_state_t *state = (moviectl_task_state_t *) calloc(1, sizeof(*state)); - if (!task || !state) + bool file_exists = filestream_exists(path); + if (!task || !state || !file_exists) goto error; *state = input_st->bsv_movie_state; strlcpy(state->movie_start_path, path, sizeof(state->movie_start_path));