diff --git a/gfx/gfx_thumbnail.c b/gfx/gfx_thumbnail.c index e2562592dcf..37ff7d93f4b 100644 --- a/gfx/gfx_thumbnail.c +++ b/gfx/gfx_thumbnail.c @@ -38,6 +38,10 @@ #include "../paths.h" #include "../file_path_special.h" +#ifdef HAVE_MENU +#include "../menu/menu_driver.h" +#endif + #include "../tasks/tasks_internal.h" #define DEFAULT_GFX_THUMBNAIL_STREAM_DELAY 16.66667f * 3 @@ -1987,6 +1991,7 @@ void gfx_savestate_thumbnail_get_path( int state_slot) { size_t _len; + playlist_t *playlist = playlist_get_cached(); if (!s || !len) return; @@ -1996,6 +2001,36 @@ void gfx_savestate_thumbnail_get_path( if (!state_name || !*state_name) return; +#ifdef HAVE_MENU + if (playlist) + { + struct menu_state *menu_st = menu_state_get_ptr(); + runloop_state_t *runloop_st = runloop_state_get_ptr(); + const struct playlist_entry *entry = NULL; + + if (menu_st && menu_st->driver_data) + playlist_get_index(playlist, menu_st->driver_data->rpl_entry_selection_ptr, &entry); + + if (*entry->path) + { + size_t _len; + char new_path[PATH_MAX_LENGTH]; + char entry_basename[PATH_MAX_LENGTH]; + + strlcpy(new_path, entry->path, sizeof(new_path)); + path_remove_extension(new_path); + + _len = strlcpy(entry_basename, path_basename(new_path), sizeof(entry_basename)); + + strlcpy(entry_basename + _len, ".state", sizeof(entry_basename) - _len); + fill_pathname_join_special(new_path, + runloop_st->savestate_dir, entry_basename, sizeof(new_path)); + + state_name = strdup(new_path); + } + } +#endif /* HAVE_MENU */ + _len = strlcpy(s, state_name, len); /* The historical implementation accumulated _len from diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index a4419efd186..1e3d0100691 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -826,6 +826,10 @@ MSG_HASH( MENU_ENUM_LABEL_SAVESTATE_LIST, MENU_ENUM_LABEL_SAVESTATE_LIST_STR ) +MSG_HASH( + MENU_ENUM_LABEL_STATE_SLOT_RUN, + MENU_ENUM_LABEL_STATE_SLOT_RUN_STR + ) MSG_HASH( MENU_ENUM_LABEL_CORE_OPTIONS, MENU_ENUM_LABEL_CORE_OPTIONS_STR diff --git a/menu/cbs/menu_cbs_cancel.c b/menu/cbs/menu_cbs_cancel.c index f85c6ce865b..c04be57051b 100644 --- a/menu/cbs/menu_cbs_cancel.c +++ b/menu/cbs/menu_cbs_cancel.c @@ -89,15 +89,32 @@ static int action_cancel_contentless_core(const char *path, { menu_state_get_ptr()->contentless_core_ptr = 0; menu_contentless_cores_flush_runtime(); - return action_cancel_pop_default(path, label, type, idx) ; + return action_cancel_pop_default(path, label, type, idx); +} + +static int action_cancel_state_slot_run(const char *path, + const char *label, unsigned type, size_t idx) +{ + struct menu_state *menu_st = menu_state_get_ptr(); + runloop_state_t *runloop_st = runloop_state_get_ptr(); + + if (!(runloop_st->flags & RUNLOOP_FLAG_CORE_RUNNING)) + command_event(CMD_EVENT_UNLOAD_CORE, NULL); + + menu_st->driver_data->state_slot_run = 0; + + menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH; + menu_st->flags &= ~MENU_ST_FLAG_PREVENT_POPULATE; + + return action_cancel_pop_default(path, label, type, idx); } #ifdef HAVE_CHEATS static int action_cancel_cheat_details(const char *path, const char *label, unsigned type, size_t idx) { - cheat_manager_copy_working_to_idx(cheat_manager_state.working_cheat.idx) ; - return action_cancel_pop_default(path, label, type, idx) ; + cheat_manager_copy_working_to_idx(cheat_manager_state.working_cheat.idx); + return action_cancel_pop_default(path, label, type, idx); } #endif @@ -165,6 +182,9 @@ static int menu_cbs_init_bind_cancel_compare_type( case MENU_SETTING_ACTION_CONTENTLESS_CORE_RUN: BIND_ACTION_CANCEL(cbs, action_cancel_contentless_core); return 0; + case MENU_SETTING_ACTION_STATE_SLOT_RUN: + BIND_ACTION_CANCEL(cbs, action_cancel_state_slot_run); + return 0; default: break; } diff --git a/menu/cbs/menu_cbs_deferred_push.c b/menu/cbs/menu_cbs_deferred_push.c index b0da7034784..51ca3b601da 100644 --- a/menu/cbs/menu_cbs_deferred_push.c +++ b/menu/cbs/menu_cbs_deferred_push.c @@ -121,6 +121,7 @@ GENERIC_DEFERRED_PUSH(deferred_push_core_cheat_options, DISPLAYLIST_ GENERIC_DEFERRED_PUSH(deferred_push_core_input_remapping_options, DISPLAYLIST_OPTIONS_REMAPPINGS) GENERIC_DEFERRED_PUSH(deferred_push_remap_file_manager, DISPLAYLIST_REMAP_FILE_MANAGER) GENERIC_DEFERRED_PUSH(deferred_push_savestate_list, DISPLAYLIST_SAVESTATE_LIST) +GENERIC_DEFERRED_PUSH(deferred_push_state_slot_run, DISPLAYLIST_STATE_SLOT_RUN) GENERIC_DEFERRED_PUSH(deferred_push_core_options, DISPLAYLIST_CORE_OPTIONS) GENERIC_DEFERRED_PUSH(deferred_push_core_option_override_list, DISPLAYLIST_CORE_OPTION_OVERRIDE_LIST) GENERIC_DEFERRED_PUSH(deferred_push_disk_options, DISPLAYLIST_OPTIONS_DISK) @@ -669,6 +670,7 @@ static int menu_cbs_init_bind_deferred_push_compare_label( {MENU_ENUM_LABEL_CORE_LIST, deferred_push_core_list}, {MENU_ENUM_LABEL_LOAD_CONTENT_HISTORY, deferred_push_history_list}, {MENU_ENUM_LABEL_SAVESTATE_LIST, deferred_push_savestate_list}, + {MENU_ENUM_LABEL_STATE_SLOT_RUN, deferred_push_state_slot_run}, {MENU_ENUM_LABEL_CORE_OPTIONS, deferred_push_core_options}, {MENU_ENUM_LABEL_DEFERRED_CORE_OPTION_OVERRIDE_LIST, deferred_push_core_option_override_list}, {MENU_ENUM_LABEL_NETWORK_INFORMATION, deferred_push_network_information}, @@ -951,6 +953,9 @@ static int menu_cbs_init_bind_deferred_push_compare_label( case MENU_ENUM_LABEL_SAVESTATE_LIST: BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_savestate_list); break; + case MENU_ENUM_LABEL_STATE_SLOT_RUN: + BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_state_slot_run); + break; case MENU_ENUM_LABEL_CORE_OPTIONS: BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_core_options); break; diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index 7aff9b5ce80..916878b4198 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -6742,6 +6742,7 @@ STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_core_manager_steam_list, ACTION_OK_ STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_core_option_override_list, ACTION_OK_DL_CORE_OPTION_OVERRIDE_LIST) STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_remap_file_manager_list, ACTION_OK_DL_REMAP_FILE_MANAGER_LIST) STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_savestate_list, ACTION_OK_DL_SAVESTATE_LIST) +STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_state_slot_run, ACTION_OK_DL_SAVESTATE_LIST) STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_core_options_list, ACTION_OK_DL_CORE_OPTIONS_LIST) STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_add_to_playlist_list, ACTION_OK_DL_ADD_TO_PLAYLIST) STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_add_to_playlist_quickmenu, ACTION_OK_DL_ADD_TO_PLAYLIST_QUICKMENU) @@ -8043,6 +8044,27 @@ static int action_ok_contentless_core_run(const char *path, return 0; } +static int action_ok_state_slot_run(const char *path, + const char *label, unsigned type, size_t idx, size_t entry_idx) +{ + settings_t *settings = config_get_ptr(); + struct menu_state *menu_st = menu_state_get_ptr(); + int slot = idx - 1; + size_t new_selection_ptr = 0; + + menu_entries_pop_stack(&new_selection_ptr, 0, 0); + menu_st->selection_ptr = 0; + + menu_st->driver_data->state_slot_run = slot; + + menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH; + menu_st->flags &= ~MENU_ST_FLAG_PREVENT_POPULATE; + + action_ok_playlist_entry_collection(path, label, type, idx, + menu_st->driver_data->rpl_entry_selection_ptr); + return 0; +} + static int action_ok_load_archive(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) { @@ -9380,6 +9402,7 @@ static int menu_cbs_init_bind_ok_compare_label(menu_file_list_cbs_t *cbs, {MENU_ENUM_LABEL_LOAD_DISC, action_ok_push_load_disc_list}, {MENU_ENUM_LABEL_SHADER_OPTIONS, action_ok_push_default}, {MENU_ENUM_LABEL_SAVESTATE_LIST, action_ok_push_savestate_list}, + {MENU_ENUM_LABEL_STATE_SLOT_RUN, action_ok_push_state_slot_run}, {MENU_ENUM_LABEL_CORE_OPTIONS, action_ok_push_core_options_list}, {MENU_ENUM_LABEL_CORE_OPTION_OVERRIDE_LIST, action_ok_push_core_option_override_list}, {MENU_ENUM_LABEL_REMAP_FILE_MANAGER_LIST, action_ok_push_remap_file_manager_list}, @@ -10181,6 +10204,9 @@ static int menu_cbs_init_bind_ok_compare_type(menu_file_list_cbs_t *cbs, case MENU_SETTING_ACTION_CONTENTLESS_CORE_RUN: BIND_ACTION_OK(cbs, action_ok_contentless_core_run); break; + case MENU_SETTING_ACTION_STATE_SLOT_RUN: + BIND_ACTION_OK(cbs, action_ok_state_slot_run); + break; default: return -1; } diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index 832ab1de721..760d4f95182 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -1955,16 +1955,6 @@ static int action_bind_sublabel_playlist_entry( unsigned playlist_sublabel_runtime_type = settings->uints.playlist_sublabel_runtime_type; bool content_runtime_log = settings->bools.content_runtime_log; bool content_runtime_log_aggregate = settings->bools.content_runtime_log_aggregate; - const char *directory_runtime_log = settings->paths.directory_runtime_log; - const char *directory_playlist = settings->paths.directory_playlist; - enum playlist_sublabel_last_played_style_type - playlist_sublabel_last_played_style = - (enum playlist_sublabel_last_played_style_type) - settings->uints.playlist_sublabel_last_played_style; - enum playlist_sublabel_last_played_date_separator_type - menu_timedate_date_separator = - (enum playlist_sublabel_last_played_date_separator_type) - settings->uints.menu_timedate_date_separator; if (!playlist_show_sublabels) return 0; @@ -2027,13 +2017,7 @@ static int action_bind_sublabel_playlist_entry( /* Check whether runtime info should be loaded from log file */ if (entry->runtime_status == PLAYLIST_RUNTIME_UNKNOWN) - runtime_update_playlist( - playlist, playlist_index, - directory_runtime_log, - directory_playlist, - (playlist_sublabel_runtime_type == PLAYLIST_RUNTIME_PER_CORE), - playlist_sublabel_last_played_style, - menu_timedate_date_separator); + runtime_update_playlist(playlist, playlist_index); /* Check whether runtime info is valid */ if (entry->runtime_status == PLAYLIST_RUNTIME_VALID) @@ -3368,6 +3352,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_SAVESTATE_LIST: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_savestate_list); break; + case MENU_ENUM_LABEL_STATE_SLOT_RUN: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_load_state); + break; case MENU_ENUM_LABEL_CORE_OPTIONS: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_options); break; diff --git a/menu/cbs/menu_cbs_title.c b/menu/cbs/menu_cbs_title.c index d063d7cf04c..f9365d9d177 100644 --- a/menu/cbs/menu_cbs_title.c +++ b/menu/cbs/menu_cbs_title.c @@ -591,6 +591,7 @@ DEFAULT_TITLE_MACRO(action_get_configurations_list, MENU_ENUM_LABEL_ DEFAULT_TITLE_MACRO(action_get_core_option_override_list, MENU_ENUM_LABEL_VALUE_CORE_OPTION_OVERRIDE_LIST) DEFAULT_TITLE_MACRO(action_get_quick_menu_list, MENU_ENUM_LABEL_VALUE_CONTENT_SETTINGS) DEFAULT_TITLE_MACRO(action_get_savestate_list, MENU_ENUM_LABEL_VALUE_SAVESTATE_LIST) +DEFAULT_TITLE_MACRO(action_get_state_slot_run, MENU_ENUM_LABEL_VALUE_LOAD_STATE) DEFAULT_TITLE_MACRO(action_get_input_remapping_options_list, MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS) DEFAULT_TITLE_MACRO(action_get_remap_file_manager_list, MENU_ENUM_LABEL_VALUE_REMAP_FILE_MANAGER_LIST) DEFAULT_TITLE_MACRO(action_get_shader_options_list, MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS) @@ -1179,6 +1180,8 @@ static int menu_cbs_init_bind_title_compare_label(menu_file_list_cbs_t *cbs, action_get_add_content_list}, {MENU_ENUM_LABEL_SAVESTATE_LIST, action_get_savestate_list}, + {MENU_ENUM_LABEL_STATE_SLOT_RUN, + action_get_state_slot_run}, {MENU_ENUM_LABEL_CORE_OPTIONS, action_get_title_core_options_list}, {MENU_ENUM_LABEL_DEFERRED_CORE_OPTION_OVERRIDE_LIST, diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index 3621b497ead..be7c552b47c 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -2524,6 +2524,7 @@ static void materialui_update_savestate_thumbnail_path(void *data, unsigned i) { unsigned _state_slot = string_to_unsigned(entry.label); if ( _state_slot == MENU_ENUM_LABEL_STATE_SLOT + || string_is_equal(entry.label, MENU_ENUM_LABEL_STATE_SLOT_RUN_STR) || string_is_equal(entry.label, MENU_ENUM_LABEL_STATE_SLOT_STR) || string_is_equal(entry.label, MENU_ENUM_LABEL_LOAD_STATE_STR) || string_is_equal(entry.label, MENU_ENUM_LABEL_SAVE_STATE_STR)) @@ -2533,7 +2534,8 @@ static void materialui_update_savestate_thumbnail_path(void *data, unsigned i) int state_slot = settings->ints.state_slot; /* State slot dropdown */ - if (_state_slot == MENU_ENUM_LABEL_STATE_SLOT) + if ( _state_slot == MENU_ENUM_LABEL_STATE_SLOT + || string_is_equal(entry.label, MENU_ENUM_LABEL_STATE_SLOT_RUN_STR)) state_slot = i - 1; gfx_savestate_thumbnail_get_path(path, sizeof(path), @@ -3685,17 +3687,6 @@ static bool materialui_render_process_entry_playlist_desktop( settings_t *settings = config_get_ptr(); bool content_runtime_log = settings->bools.content_runtime_log; bool content_runtime_log_aggregate = settings->bools.content_runtime_log_aggregate; - const char *directory_runtime_log = settings->paths.directory_runtime_log; - const char *directory_playlist = settings->paths.directory_playlist; - unsigned runtime_type = settings->uints.playlist_sublabel_runtime_type; - enum playlist_sublabel_last_played_style_type - runtime_last_played_style = - (enum playlist_sublabel_last_played_style_type) - settings->uints.playlist_sublabel_last_played_style; - enum playlist_sublabel_last_played_date_separator_type - runtime_date_separator = - (enum playlist_sublabel_last_played_date_separator_type) - settings->uints.menu_timedate_date_separator; float fade_duration = gfx_thumb_get_ptr()->fade_duration; const struct playlist_entry *entry = NULL; const char *core_name = NULL; @@ -3729,13 +3720,7 @@ static bool materialui_render_process_entry_playlist_desktop( if (content_runtime_log || content_runtime_log_aggregate) { if (entry->runtime_status == PLAYLIST_RUNTIME_UNKNOWN) - runtime_update_playlist( - mui->playlist, playlist_idx, - directory_runtime_log, - directory_playlist, - (runtime_type == PLAYLIST_RUNTIME_PER_CORE), - runtime_last_played_style, - runtime_date_separator); + runtime_update_playlist(mui->playlist, playlist_idx); if (entry->runtime_str && *entry->runtime_str) runtime_str = entry->runtime_str; @@ -5901,7 +5886,6 @@ static bool materialui_is_savestate_list(materialui_handle_t *mui) MENU_ENTRY_INITIALIZE(entry); entry.flags |= MENU_ENTRY_FLAG_LABEL_ENABLED; menu_entry_get(&entry, 0, menu_st->selection_ptr, NULL, true); - return ( string_is_equal(entry.label, MENU_ENUM_LABEL_STATE_SLOT_STR) || string_is_equal(entry.label, MENU_ENUM_LABEL_LOAD_STATE_STR) @@ -5916,7 +5900,10 @@ static bool materialui_is_savestate_slot(materialui_handle_t *mui) MENU_ENTRY_INITIALIZE(entry); entry.flags |= MENU_ENTRY_FLAG_LABEL_ENABLED; menu_entry_get(&entry, 0, menu_st->selection_ptr, NULL, true); - return string_to_unsigned(entry.label) == MENU_ENUM_LABEL_STATE_SLOT; + return + ( string_to_unsigned(entry.label) == MENU_ENUM_LABEL_STATE_SLOT + || string_is_equal(entry.label, MENU_ENUM_LABEL_STATE_SLOT_RUN_STR) + ); } /* Used for savestate layout list displays. @@ -9877,6 +9864,7 @@ static void materialui_populate_entries(void *data, const char *path, if ( settings->bools.savestate_thumbnail_enable && ( string_is_equal(label, MENU_ENUM_LABEL_SAVESTATE_LIST_STR) + || string_is_equal(label, MENU_ENUM_LABEL_STATE_SLOT_RUN_STR) || string_to_unsigned(path) == MENU_ENUM_LABEL_STATE_SLOT)) { mui->flags |= MUI_FLAG_IS_SAVESTATE_LIST; @@ -11780,6 +11768,7 @@ static void materialui_list_insert(void *userdata, node->icon_type = MUI_ICON_TYPE_INTERNAL; } else if ( string_is_equal(label, MENU_ENUM_LABEL_LOAD_STATE_STR) + || (string_is_equal(label, MENU_ENUM_LABEL_STATE_SLOT_RUN_STR) && type != MENU_SETTING_ACTION_STATE_SLOT_RUN) || string_is_equal(label, MENU_ENUM_LABEL_OVERRIDE_FILE_LOAD_STR) || string_is_equal(label, MENU_ENUM_LABEL_CHEAT_FILE_LOAD_STR) || string_is_equal(label, MENU_ENUM_LABEL_CHEAT_FILE_LOAD_APPEND_STR) diff --git a/menu/drivers/ozone.c b/menu/drivers/ozone.c index 4bbf0f69291..0ca69a31ba3 100644 --- a/menu/drivers/ozone.c +++ b/menu/drivers/ozone.c @@ -1987,6 +1987,7 @@ static uintptr_t ozone_entries_icon_get_texture( case MENU_ENUM_LABEL_NETWORK_ON_DEMAND_THUMBNAILS: return icons_tex[OZONE_ENTRIES_ICONS_TEXTURE_SAVESTATE]; case MENU_ENUM_LABEL_LOAD_STATE: + case MENU_ENUM_LABEL_STATE_SLOT_RUN: case MENU_ENUM_LABEL_CORE_RESTORE_BACKUP_LIST: return icons_tex[OZONE_ENTRIES_ICONS_TEXTURE_LOADSTATE]; case MENU_ENUM_LABEL_TAKE_SCREENSHOT: @@ -3955,6 +3956,7 @@ static void ozone_update_savestate_thumbnail_path(void *data, unsigned i) { unsigned _state_slot = string_to_unsigned(entry.label); if ( _state_slot == MENU_ENUM_LABEL_STATE_SLOT + || string_is_equal(entry.label, MENU_ENUM_LABEL_STATE_SLOT_RUN_STR) || string_is_equal(entry.label, MENU_ENUM_LABEL_STATE_SLOT_STR) || string_is_equal(entry.label, MENU_ENUM_LABEL_LOAD_STATE_STR) || string_is_equal(entry.label, MENU_ENUM_LABEL_SAVE_STATE_STR)) @@ -3964,7 +3966,8 @@ static void ozone_update_savestate_thumbnail_path(void *data, unsigned i) int state_slot = settings->ints.state_slot; /* State slot dropdown */ - if (_state_slot == MENU_ENUM_LABEL_STATE_SLOT) + if ( _state_slot == MENU_ENUM_LABEL_STATE_SLOT + || string_is_equal(entry.label, MENU_ENUM_LABEL_STATE_SLOT_RUN_STR)) { state_slot = i - 1; ozone->flags |= OZONE_FLAG_IS_STATE_SLOT; @@ -4315,17 +4318,6 @@ static void ozone_update_content_metadata(ozone_handle_t *ozone) settings_t *settings = config_get_ptr(); bool scroll_content_metadata = settings->bools.ozone_scroll_content_metadata; bool show_entry_idx = settings->bools.playlist_show_entry_idx; - const char *directory_runtime_log = settings->paths.directory_runtime_log; - const char *directory_playlist = settings->paths.directory_playlist; - unsigned runtime_type = settings->uints.playlist_sublabel_runtime_type; - enum playlist_sublabel_last_played_style_type - runtime_last_played_style = - (enum playlist_sublabel_last_played_style_type) - settings->uints.playlist_sublabel_last_played_style; - enum playlist_sublabel_last_played_date_separator_type - runtime_date_separator = - (enum playlist_sublabel_last_played_date_separator_type) - settings->uints.menu_timedate_date_separator; /* Must check whether core corresponds to 'viewer' * content even when not using a playlist, otherwise @@ -4482,13 +4474,7 @@ static void ozone_update_content_metadata(ozone_handle_t *ozone) { if ( (entry->runtime_status == PLAYLIST_RUNTIME_UNKNOWN) || (ozone->flags2 & OZONE_FLAG2_IS_QUICK_MENU)) - runtime_update_playlist( - playlist, playlist_index, - directory_runtime_log, - directory_playlist, - (runtime_type == PLAYLIST_RUNTIME_PER_CORE), - runtime_last_played_style, - runtime_date_separator); + runtime_update_playlist(playlist, playlist_index); if (entry->runtime_str && *entry->runtime_str) strlcpy(ozone->selection_playtime, entry->runtime_str, sizeof(ozone->selection_playtime)); @@ -12823,7 +12809,8 @@ static void ozone_populate_entries( else ozone->flags &= ~OZONE_FLAG_IS_CONTENTLESS_CORES; - if (string_to_unsigned(path) == MENU_ENUM_LABEL_STATE_SLOT) + if ( string_to_unsigned(path) == MENU_ENUM_LABEL_STATE_SLOT + || string_is_equal(label, MENU_ENUM_LABEL_STATE_SLOT_RUN_STR)) ozone->flags |= OZONE_FLAG_IS_STATE_SLOT; else ozone->flags &= ~OZONE_FLAG_IS_STATE_SLOT; diff --git a/menu/drivers/rgui.c b/menu/drivers/rgui.c index d478109b6da..9ef81add8be 100644 --- a/menu/drivers/rgui.c +++ b/menu/drivers/rgui.c @@ -7012,6 +7012,7 @@ static void rgui_update_savestate_thumbnail_path(void *data, unsigned i) { unsigned _state_slot = string_to_unsigned(entry.label); if ( _state_slot == MENU_ENUM_LABEL_STATE_SLOT + || string_is_equal(entry.label, MENU_ENUM_LABEL_STATE_SLOT_RUN_STR) || string_is_equal(entry.label, MENU_ENUM_LABEL_STATE_SLOT_STR) || string_is_equal(entry.label, MENU_ENUM_LABEL_LOAD_STATE_STR) || string_is_equal(entry.label, MENU_ENUM_LABEL_SAVE_STATE_STR)) @@ -7021,7 +7022,8 @@ static void rgui_update_savestate_thumbnail_path(void *data, unsigned i) int state_slot = settings->ints.state_slot; /* State slot dropdown */ - if (_state_slot == MENU_ENUM_LABEL_STATE_SLOT) + if ( _state_slot == MENU_ENUM_LABEL_STATE_SLOT + || string_is_equal(entry.label, MENU_ENUM_LABEL_STATE_SLOT_RUN_STR)) { state_slot = i - 1; rgui->flags |= RGUI_FLAG_IS_STATE_SLOT; @@ -7524,7 +7526,8 @@ static void rgui_populate_entries( else rgui->flags &= ~RGUI_FLAG_IS_QUICK_MENU; - if (string_to_unsigned(path) == MENU_ENUM_LABEL_STATE_SLOT) + if ( string_to_unsigned(path) == MENU_ENUM_LABEL_STATE_SLOT + || string_is_equal(label, MENU_ENUM_LABEL_STATE_SLOT_RUN_STR)) rgui->flags |= RGUI_FLAG_IS_STATE_SLOT; else rgui->flags &= ~RGUI_FLAG_IS_STATE_SLOT; diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index aa007eb73f9..b80c1f3e33a 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -1404,6 +1404,7 @@ static void xmb_update_savestate_thumbnail_path(void *data, unsigned i) { unsigned _state_slot = string_to_unsigned(entry.label); if ( _state_slot == MENU_ENUM_LABEL_STATE_SLOT + || string_is_equal(entry.label, MENU_ENUM_LABEL_STATE_SLOT_RUN_STR) || string_is_equal(entry.label, MENU_ENUM_LABEL_STATE_SLOT_STR) || string_is_equal(entry.label, MENU_ENUM_LABEL_LOAD_STATE_STR) || string_is_equal(entry.label, MENU_ENUM_LABEL_SAVE_STATE_STR)) @@ -1413,7 +1414,8 @@ static void xmb_update_savestate_thumbnail_path(void *data, unsigned i) int state_slot = settings->ints.state_slot; /* State slot dropdown */ - if (_state_slot == MENU_ENUM_LABEL_STATE_SLOT) + if ( _state_slot == MENU_ENUM_LABEL_STATE_SLOT + || string_is_equal(entry.label, MENU_ENUM_LABEL_STATE_SLOT_RUN_STR)) { state_slot = i - 1; xmb->is_state_slot = true; @@ -3447,7 +3449,9 @@ static void xmb_populate_entries(void *data, || string_is_equal(label, MENU_ENUM_LABEL_SAVESTATE_LIST_STR); - xmb->is_state_slot = string_to_unsigned(path) == MENU_ENUM_LABEL_STATE_SLOT; + xmb->is_state_slot = + string_to_unsigned(path) == MENU_ENUM_LABEL_STATE_SLOT + || string_is_equal(label, MENU_ENUM_LABEL_STATE_SLOT_RUN_STR); #if defined(HAVE_LIBRETRODB) /* Explore list */ @@ -3729,6 +3733,7 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, case MENU_ENUM_LABEL_NETWORK_ON_DEMAND_THUMBNAILS: return xmb->textures.list[XMB_TEXTURE_SAVESTATE]; case MENU_ENUM_LABEL_LOAD_STATE: + case MENU_ENUM_LABEL_STATE_SLOT_RUN: case MENU_ENUM_LABEL_CONFIGURATIONS: case MENU_ENUM_LABEL_GAME_SPECIFIC_OPTIONS: case MENU_ENUM_LABEL_REMAP_FILE_LOAD: diff --git a/menu/menu_defines.h b/menu/menu_defines.h index 24286846695..9fe4ab298c0 100644 --- a/menu/menu_defines.h +++ b/menu/menu_defines.h @@ -51,7 +51,8 @@ enum menu_state_flags MENU_ST_FLAG_SCREENSAVER_ACTIVE = (1 << 11), MENU_ST_FLAG_PENDING_RELOAD_CORE = (1 << 12), MENU_ST_FLAG_PENDING_STARTUP_PAGE = (1 << 13), - MENU_ST_FLAG_BLOCK_ALL_INPUT = (1 << 14) + MENU_ST_FLAG_BLOCK_ALL_INPUT = (1 << 14), + MENU_ST_FLAG_PRETEND_CORE_INIT = (1 << 15) }; enum menu_scroll_mode diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 1ae8c6496fd..c94883aae92 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -3888,6 +3888,7 @@ static int menu_displaylist_parse_horizontal_content_actions( } else { + bool savestates_enabled = core_info_current_supports_savestate(); const char *playlist_path = NULL; const char *playlist_file = NULL; #ifdef HAVE_AUDIOMIXER @@ -3919,7 +3920,18 @@ static int menu_displaylist_parse_horizontal_content_actions( menu_entries_append(list, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RUN), MENU_ENUM_LABEL_RUN_STR, - MENU_ENUM_LABEL_RUN, FILE_TYPE_PLAYLIST_ENTRY, 0, idx, NULL); + MENU_ENUM_LABEL_RUN, + FILE_TYPE_PLAYLIST_ENTRY, 0, idx, NULL); + + if ( savestates_enabled + && settings->bools.quick_menu_show_save_load_state) + { + menu_entries_append(list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_LOAD_STATE), + MENU_ENUM_LABEL_STATE_SLOT_RUN_STR, + MENU_ENUM_LABEL_STATE_SLOT_RUN, + MENU_SETTING_ACTION, 0, idx, NULL); + } if (!settings->bools.kiosk_mode_enable) { @@ -14374,6 +14386,89 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, info->flags |= MD_FLAG_NEED_PUSH; } break; + case DISPLAYLIST_STATE_SLOT_RUN: + { + bool savestates_enabled = true; + playlist_t *playlist = playlist_get_cached(); + runloop_state_t *runloop_st = runloop_state_get_ptr(); + + /* Core must be initialized at least partly to set + * savestate sorting paths accordingly. */ + if (playlist && !(runloop_st->flags & RUNLOOP_FLAG_CORE_RUNNING)) + { + struct menu_state *menu_st = menu_state_get_ptr(); + const struct playlist_entry *entry = NULL; + + if (menu_st && menu_st->driver_data) + playlist_get_index(playlist, menu_st->driver_data->rpl_entry_selection_ptr, &entry); + + if (*entry->path) + { + path_set(RARCH_PATH_CORE, entry->core_path); + command_event(CMD_EVENT_LOAD_CORE, NULL); + runloop_set_current_core_type(CORE_TYPE_PLAIN, true); + + savestates_enabled = core_info_current_supports_savestate(); + + menu_st->flags |= MENU_ST_FLAG_PRETEND_CORE_INIT; + + if (runloop_st->flags & RUNLOOP_FLAG_HAS_SET_CORE) + { + runloop_st->flags &= ~RUNLOOP_FLAG_HAS_SET_CORE; + + if (savestates_enabled) + command_event(CMD_EVENT_CORE_INIT, + &runloop_st->explicit_current_core_type); + + menu_st->flags &= ~MENU_ST_FLAG_PRETEND_CORE_INIT; + + /* Reinit runtime log and read current state slot */ + runtime_update_playlist(playlist, + menu_st->driver_data->rpl_entry_selection_ptr); + } + } + } + + menu_entries_clear(info->list); + + /* Build the dropdown selector */ + if ( savestates_enabled + && settings->bools.quick_menu_show_save_load_state) + { + int i; + int i_max = count = 1000; + + for (i = -1; i < i_max; i++) + { + char val[8]; + + if (i < 0) + strlcpy(val, "Auto", sizeof(val)); + else + snprintf(val, sizeof(val), "%u", i); + + menu_entries_append(info->list, + val, + MENU_ENUM_LABEL_STATE_SLOT_RUN_STR, + MSG_UNKNOWN, + MENU_SETTING_ACTION_STATE_SLOT_RUN, + 0, 0, NULL); + } + + /* Pre-select last slot from the runtime log */ + menu_st->selection_ptr = runloop_st->entry_state_slot + 1; + } + + if (count == 0) + menu_entries_append(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY), + MENU_ENUM_LABEL_NO_ENTRIES_TO_DISPLAY_STR, + MENU_ENUM_LABEL_NO_ENTRIES_TO_DISPLAY, + FILE_TYPE_NONE, 0, 0, NULL); + + info->flags |= MD_FLAG_NEED_PUSH; + } + break; case DISPLAYLIST_CORE_OPTIONS: { /* Number of displayed options is dynamic. If user opens diff --git a/menu/menu_displaylist.h b/menu/menu_displaylist.h index 5fe3b2a27ba..1f65c6b8abc 100644 --- a/menu/menu_displaylist.h +++ b/menu/menu_displaylist.h @@ -130,6 +130,7 @@ enum menu_displaylist_ctl_state DISPLAYLIST_LAKKA, DISPLAYLIST_CORES_DETECTED, DISPLAYLIST_SAVESTATE_LIST, + DISPLAYLIST_STATE_SLOT_RUN, DISPLAYLIST_CORE_OPTIONS, DISPLAYLIST_CORE_OPTION_OVERRIDE_LIST, DISPLAYLIST_CORE_INFO, diff --git a/menu/menu_driver.h b/menu/menu_driver.h index 24bc63e259a..9ec0f5d33fa 100644 --- a/menu/menu_driver.h +++ b/menu/menu_driver.h @@ -320,6 +320,7 @@ enum menu_settings_type MENU_SETTING_ACTION_REMAP_FILE_FLUSH, MENU_SETTING_ACTION_CONTENTLESS_CORE_RUN, + MENU_SETTING_ACTION_STATE_SLOT_RUN, MENU_SETTINGS_LAST }; @@ -438,6 +439,7 @@ typedef struct unsigned unsigned_var; } scratchpad; unsigned rpl_entry_selection_ptr; + int16_t state_slot_run; #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL) /* Used to cache the type and directory diff --git a/msg_hash.h b/msg_hash.h index 1bfe9e830f0..cdb7cfd80f2 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -2254,6 +2254,7 @@ enum msg_hash_enums MENU_LBL_H(USE_THIS_DIRECTORY), MENU_LABEL(SAVESTATE_LIST), + MENU_LABEL(STATE_SLOT_RUN), MENU_LABEL(CORE_OPTIONS), MENU_LABEL(SHADER_OPTIONS), MENU_LABEL(NO_SHADER_PARAMETERS), diff --git a/msg_hash_lbl_str.h b/msg_hash_lbl_str.h index 304770c572b..462572def09 100644 --- a/msg_hash_lbl_str.h +++ b/msg_hash_lbl_str.h @@ -214,6 +214,7 @@ #define MENU_ENUM_LABEL_CORE_LIST_UNLOAD_STR "unload_core" #define MENU_ENUM_LABEL_SIDELOAD_CORE_LIST_STR "sideload_core" #define MENU_ENUM_LABEL_SAVESTATE_LIST_STR "savestate_list" +#define MENU_ENUM_LABEL_STATE_SLOT_RUN_STR "state_slot_run" #define MENU_ENUM_LABEL_CORE_OPTIONS_STR "core_options" #define MENU_ENUM_LABEL_CORE_OPTION_ENTRY_STR "core_option_entry" #define MENU_ENUM_LABEL_CORE_SETTINGS_STR "core_settings" diff --git a/runloop.c b/runloop.c index 3f83d36a6dc..5e63dde936d 100644 --- a/runloop.c +++ b/runloop.c @@ -4263,6 +4263,7 @@ static bool event_init_content( #endif const enum rarch_core_type current_core_type = runloop_st->current_core_type; uint8_t flags = content_get_flags(); + bool entry_state_load = runloop_st->entry_state_slot > -1; if (current_core_type == CORE_TYPE_PLAIN) runloop_st->flags |= RUNLOOP_FLAG_USE_SRAM; @@ -4318,6 +4319,22 @@ static bool event_init_content( if (entry && entry->entry_slot > 0) runloop_st->entry_state_slot = entry->entry_slot; + + entry_state_load = runloop_st->entry_state_slot > -1; + + /* Override entry slot in savestate run list */ + { + menu_entry_t menu_entry; + MENU_ENTRY_INITIALIZE(menu_entry); + menu_entry.flags |= MENU_ENTRY_FLAG_LABEL_ENABLED; + menu_entry_get(&menu_entry, 0, 0, NULL, true); + + if (string_is_equal(menu_entry.label, MENU_ENUM_LABEL_STATE_SLOT_RUN_STR)) + { + runloop_st->entry_state_slot = menu_st->driver_data->state_slot_run; + entry_state_load = true; + } + } } #endif @@ -4344,7 +4361,7 @@ static bool event_init_content( if (!(input_st->bsv_movie_state.flags & BSV_FLAG_MOVIE_START_PLAYBACK)) #endif { - if ( runloop_st->entry_state_slot > -1 + if ( entry_state_load && !command_event_load_entry_state(settings)) { /* Loading the state failed, reset entry slot */ @@ -4775,6 +4792,15 @@ bool runloop_event_init_core( /* Set core environment */ runloop_st->current_core.retro_set_environment(runloop_environment_cb); +#ifdef HAVE_MENU + /* Early return for playlist entry savestate menu paths */ + { + struct menu_state *menu_st = menu_state_get_ptr(); + if (menu_st && menu_st->flags & MENU_ST_FLAG_PRETEND_CORE_INIT) + return false; + } +#endif + /* Load any input remap files * > Note that we always cache the current global * input settings when initialising a core diff --git a/runtime_file.c b/runtime_file.c index ab85e4ed955..d610e3dbb3e 100644 --- a/runtime_file.c +++ b/runtime_file.c @@ -286,7 +286,7 @@ static void runtime_log_read_file(runtime_log_t *runtime_log) state_slot = (unsigned)val; } - if ( state_slot > 0 + if ( state_slot >= 0 && state_slot < 1000) { runloop_state_t *runloop_st = runloop_state_get_ptr(); @@ -1312,18 +1312,22 @@ void runtime_log_convert_usec2hms(retro_time_t usec, /* Updates specified playlist entry runtime values with * contents of associated log file */ void runtime_update_playlist( - playlist_t *playlist, size_t idx, - const char *dir_runtime_log, - const char *dir_playlist, - bool log_per_core, - enum playlist_sublabel_last_played_style_type timedate_style, - enum playlist_sublabel_last_played_date_separator_type date_separator) + playlist_t *playlist, size_t idx) { char runtime_str[64]; char last_played_str[64]; runtime_log_t *runtime_log = NULL; const struct playlist_entry *entry = NULL; struct playlist_entry update_entry = {0}; + settings_t *settings = config_get_ptr(); + const char *dir_runtime_log = settings->paths.directory_runtime_log; + const char *dir_playlist = settings->paths.directory_playlist; + unsigned runtime_type = settings->uints.playlist_sublabel_runtime_type; + bool log_per_core = (runtime_type == PLAYLIST_RUNTIME_PER_CORE); + enum playlist_sublabel_last_played_style_type + timedate_style = settings->uints.playlist_sublabel_last_played_style; + enum playlist_sublabel_last_played_date_separator_type + date_separator = settings->uints.menu_timedate_date_separator; /* Sanity check */ if (!playlist) diff --git a/runtime_file.h b/runtime_file.h index c26c31eef8c..96feb024b04 100644 --- a/runtime_file.h +++ b/runtime_file.h @@ -130,13 +130,7 @@ void runtime_log_convert_usec2hms(retro_time_t usec, unsigned *hours, unsigned * /* Updates specified playlist entry runtime values with * contents of associated log file */ -void runtime_update_playlist( - playlist_t *playlist, size_t idx, - const char *dir_runtime_log, - const char *dir_playlist, - bool log_per_core, - enum playlist_sublabel_last_played_style_type timedate_style, - enum playlist_sublabel_last_played_date_separator_type date_separator); +void runtime_update_playlist(playlist_t *playlist, size_t idx); #if defined(HAVE_MENU) /* Contentless cores manipulation */