Disable save states based on save state support level defined in core info files (#13562)

This commit is contained in:
jdgleaver 2022-02-02 15:49:53 +00:00 committed by GitHub
parent 6f7332c8fa
commit 42e03cae83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 316 additions and 22 deletions

View File

@ -1088,6 +1088,8 @@ bool command_event_save_auto_state(
return false;
if (current_core_type == CORE_TYPE_DUMMY)
return false;
if (!core_info_current_supports_savestate())
return false;
if (string_is_empty(path_basename(path_get(RARCH_PATH_BASENAME))))
return false;
@ -1148,6 +1150,9 @@ bool command_event_load_entry_state(void)
runloop_state_t *runloop_st = runloop_state_get_ptr();
bool ret = false;
if (!core_info_current_supports_savestate())
return false;
#ifdef HAVE_CHEEVOS
if (rcheevos_hardcore_active())
return false;
@ -1187,6 +1192,10 @@ void command_event_load_auto_state(void)
char savestate_name_auto[PATH_MAX_LENGTH];
runloop_state_t *runloop_st = runloop_state_get_ptr();
bool ret = false;
if (!core_info_current_supports_savestate())
return;
#ifdef HAVE_CHEEVOS
if (rcheevos_hardcore_active())
return;
@ -1551,16 +1560,22 @@ bool command_event_main_state(unsigned cmd)
char msg[128];
char state_path[16384];
settings_t *settings = config_get_ptr();
bool savestates_enabled = core_info_current_supports_savestate();
bool ret = false;
bool push_msg = true;
state_path[0] = msg[0] = '\0';
retroarch_get_current_savestate_path(state_path, sizeof(state_path));
if (savestates_enabled)
{
retroarch_get_current_savestate_path(state_path,
sizeof(state_path));
core_serialize_size(&info);
core_serialize_size(&info);
savestates_enabled = (info.size > 0);
}
if (info.size)
if (savestates_enabled)
{
switch (cmd)
{

View File

@ -48,6 +48,7 @@
/* Core Info Cache START */
/*************************/
#define CORE_INFO_CACHE_VERSION "1.1"
#define CORE_INFO_CACHE_DEFAULT_CAPACITY 8
/* TODO/FIXME: Apparently rzip compression is an issue on UWP */
@ -60,6 +61,7 @@ typedef struct
core_info_t *items;
size_t length;
size_t capacity;
char *version;
bool refresh;
} core_info_cache_list_t;
@ -103,7 +105,9 @@ static bool CCJSONObjectMemberHandler(void *context,
{
CCJSONContext *pCtx = (CCJSONContext *)context;
if ((pCtx->object_depth == 2) && (pCtx->array_depth == 1) && length)
if ((pCtx->object_depth == 2) &&
(pCtx->array_depth == 1) &&
length)
{
pCtx->current_string_val = NULL;
pCtx->current_string_list_val = NULL;
@ -199,26 +203,29 @@ static bool CCJSONObjectMemberHandler(void *context,
}
else if (string_is_equal(pValue, "supports_no_game"))
pCtx->current_entry_bool_val = &pCtx->core_info->supports_no_game;
else if (string_is_equal(pValue, "savestate_support_level"))
pCtx->current_entry_uint_val = &pCtx->core_info->savestate_support_level;
break;
}
}
else if ((pCtx->object_depth == 3)
&& (pCtx->array_depth == 1) && length)
else if ((pCtx->object_depth == 3) &&
(pCtx->array_depth == 1) &&
length)
{
pCtx->current_string_val = NULL;
pCtx->current_entry_uint_val = NULL;
if (pCtx->to_core_file_id)
{
if (string_is_equal(pValue, "str"))
if (string_is_equal(pValue, "str"))
pCtx->current_string_val = &pCtx->core_info->core_file_id.str;
else if (string_is_equal(pValue, "hash"))
pCtx->current_entry_uint_val = &pCtx->core_info->core_file_id.hash;
}
}
else if ((pCtx->object_depth == 3)
&& (pCtx->array_depth == 2)
&& length)
else if ((pCtx->object_depth == 3) &&
(pCtx->array_depth == 2) &&
length)
{
pCtx->current_string_val = NULL;
pCtx->current_entry_bool_val = NULL;
@ -227,7 +234,7 @@ static bool CCJSONObjectMemberHandler(void *context,
{
size_t firmware_idx = pCtx->core_info->firmware_count - 1;
if (string_is_equal(pValue, "path"))
if (string_is_equal(pValue, "path"))
pCtx->current_string_val = &pCtx->core_info->firmware[firmware_idx].path;
else if (string_is_equal(pValue, "desc"))
pCtx->current_string_val = &pCtx->core_info->firmware[firmware_idx].desc;
@ -235,6 +242,15 @@ static bool CCJSONObjectMemberHandler(void *context,
pCtx->current_entry_bool_val = &pCtx->core_info->firmware[firmware_idx].optional;
}
}
else if ((pCtx->object_depth == 1) &&
(pCtx->array_depth == 0) &&
length)
{
pCtx->current_string_val = NULL;
if (string_is_equal(pValue, "version"))
pCtx->current_string_val = &pCtx->core_info_cache_list->version;
}
return true;
}
@ -319,6 +335,11 @@ static bool CCJSONStartObjectHandler(void *context)
pCtx->core_info = (core_info_t*)calloc(1, sizeof(core_info_t));
if (!pCtx->core_info)
return false;
/* Assume all cores have 'full' savestate support
* by default */
pCtx->core_info->savestate_support_level =
CORE_INFO_SAVESTATE_DETERMINISTIC;
}
else if ((pCtx->object_depth == 3) && (pCtx->array_depth == 2))
{
@ -448,6 +469,7 @@ static void core_info_copy(core_info_t *src, core_info_t *dst)
? strdup(src->core_file_id.str) : NULL;
dst->core_file_id.hash = src->core_file_id.hash;
dst->savestate_support_level = src->savestate_support_level;
dst->has_info = src->has_info;
dst->supports_no_game = src->supports_no_game;
dst->database_match_archive_member = src->database_match_archive_member;
@ -542,6 +564,7 @@ static void core_info_transfer(core_info_t *src, core_info_t *dst)
src->core_file_id.str = NULL;
dst->core_file_id.hash = src->core_file_id.hash;
dst->savestate_support_level = src->savestate_support_level;
dst->has_info = src->has_info;
dst->supports_no_game = src->supports_no_game;
dst->database_match_archive_member = src->database_match_archive_member;
@ -565,6 +588,10 @@ static void core_info_cache_list_free(
}
free(core_info_cache_list->items);
if (core_info_cache_list->version)
free(core_info_cache_list->version);
free(core_info_cache_list);
}
@ -657,6 +684,7 @@ static core_info_cache_list_t *core_info_cache_list_new(void)
core_info_cache_list->capacity = CORE_INFO_CACHE_DEFAULT_CAPACITY;
core_info_cache_list->refresh = false;
core_info_cache_list->version = NULL;
return core_info_cache_list;
}
@ -758,6 +786,21 @@ static core_info_cache_list_t *core_info_cache_read(const char *info_dir)
free(context.core_info);
}
/* If info cache file has the wrong version
* number, discard it */
if (string_is_empty(core_info_cache_list->version) ||
!string_is_equal(core_info_cache_list->version,
CORE_INFO_CACHE_VERSION))
{
RARCH_WARN("[Core Info] Core info cache has invalid version"
" - forcing refresh (required v%s, found v%s)\n",
CORE_INFO_CACHE_VERSION,
core_info_cache_list->version);
core_info_cache_list_free(context.core_info_cache_list);
core_info_cache_list = core_info_cache_list_new();
}
end:
intfstream_close(file);
free(file);
@ -822,7 +865,7 @@ static bool core_info_cache_write(core_info_cache_list_t *list, const char *info
rjsonwriter_add_string(writer, "version");
rjsonwriter_add_colon(writer);
rjsonwriter_add_space(writer);
rjsonwriter_add_string(writer, "1.0");
rjsonwriter_add_string(writer, CORE_INFO_CACHE_VERSION);
rjsonwriter_add_comma(writer);
rjsonwriter_add_newline(writer);
rjsonwriter_add_spaces(writer, 2);
@ -1051,6 +1094,14 @@ static bool core_info_cache_write(core_info_cache_list_t *list, const char *info
rjsonwriter_add_comma(writer);
rjsonwriter_add_newline(writer);
rjsonwriter_add_spaces(writer, 6);
rjsonwriter_add_string(writer, "savestate_support_level");
rjsonwriter_add_colon(writer);
rjsonwriter_add_space(writer);
rjsonwriter_add_unsigned(writer, info->savestate_support_level);
rjsonwriter_add_comma(writer);
rjsonwriter_add_newline(writer);
rjsonwriter_add_spaces(writer, 6);
rjsonwriter_add_string(writer, "has_info");
rjsonwriter_add_colon(writer);
@ -1703,6 +1754,40 @@ static void core_info_parse_config_file(
&tmp_bool))
info->is_experimental = tmp_bool;
/* Savestate support level is slightly more complex,
* since it is a value derived from two configuration
* parameters */
/* > Assume all cores have 'full' savestate support
* by default */
info->savestate_support_level =
CORE_INFO_SAVESTATE_DETERMINISTIC;
/* > Check whether savestate functionality is defined
* in the info file */
if (config_get_bool(conf, "savestate", &tmp_bool))
{
if (tmp_bool)
{
/* Check if savestate features are defined */
entry = config_get_entry(conf, "savestate_features");
if (entry && !string_is_empty(entry->value))
{
if (string_is_equal(entry->value, "basic"))
info->savestate_support_level =
CORE_INFO_SAVESTATE_BASIC;
else if (string_is_equal(entry->value, "serialized"))
info->savestate_support_level =
CORE_INFO_SAVESTATE_SERIALIZED;
}
}
else
info->savestate_support_level =
CORE_INFO_SAVESTATE_DISABLED;
}
core_info_resolve_firmware(info, conf);
info->has_info = true;
@ -2097,6 +2182,7 @@ bool core_info_init_current_core(void)
current->is_experimental = false;
current->is_locked = false;
current->firmware_count = 0;
current->savestate_support_level = CORE_INFO_SAVESTATE_DETERMINISTIC;
current->path = NULL;
current->display_name = NULL;
current->display_version = NULL;
@ -2916,6 +3002,62 @@ bool core_info_hw_api_supported(core_info_t *info)
#endif
}
bool core_info_current_supports_savestate(void)
{
core_info_state_t *p_coreinfo = &core_info_st;
/* If no core is currently loaded, assume
* by default that all savestate functionality
* is supported */
if (!p_coreinfo->current)
return true;
return p_coreinfo->current->savestate_support_level >=
CORE_INFO_SAVESTATE_BASIC;
}
bool core_info_current_supports_rewind(void)
{
core_info_state_t *p_coreinfo = &core_info_st;
/* If no core is currently loaded, assume
* by default that all savestate functionality
* is supported */
if (!p_coreinfo->current)
return true;
return p_coreinfo->current->savestate_support_level >=
CORE_INFO_SAVESTATE_SERIALIZED;
}
bool core_info_current_supports_netplay(void)
{
core_info_state_t *p_coreinfo = &core_info_st;
/* If no core is currently loaded, assume
* by default that all savestate functionality
* is supported */
if (!p_coreinfo->current)
return true;
return p_coreinfo->current->savestate_support_level >=
CORE_INFO_SAVESTATE_DETERMINISTIC;
}
bool core_info_current_supports_runahead(void)
{
core_info_state_t *p_coreinfo = &core_info_st;
/* If no core is currently loaded, assume
* by default that all savestate functionality
* is supported */
if (!p_coreinfo->current)
return true;
return p_coreinfo->current->savestate_support_level >=
CORE_INFO_SAVESTATE_DETERMINISTIC;
}
/* Sets 'locked' status of specified core
* > Returns true if successful
* > Like all functions that access the cached

View File

@ -25,6 +25,23 @@
RETRO_BEGIN_DECLS
/* Defines the levels of savestate support
* that may be offered by a core:
* - serialized: rewind
* - deterministic: netplay/runahead
* Thus:
* (level < CORE_INFO_SAVESTATE_BASIC)
* -> no savestate support
* (level < CORE_INFO_SAVESTATE_SERIALIZED)
* -> no rewind/netplay/runahead
* (level < CORE_INFO_SAVESTATE_DETERMINISTIC)
* -> no netplay/runahead
*/
#define CORE_INFO_SAVESTATE_DISABLED 0
#define CORE_INFO_SAVESTATE_BASIC 1
#define CORE_INFO_SAVESTATE_SERIALIZED 2
#define CORE_INFO_SAVESTATE_DETERMINISTIC 3
enum core_info_list_qsort_type
{
CORE_INFO_LIST_SORT_PATH = 0,
@ -84,6 +101,7 @@ typedef struct
core_info_firmware_t *firmware;
core_file_id_t core_file_id; /* ptr alignment */
size_t firmware_count;
uint32_t savestate_support_level;
bool has_info;
bool supports_no_game;
bool database_match_archive_member;
@ -184,6 +202,16 @@ bool core_info_list_get_info(core_info_list_t *core_info_list,
bool core_info_hw_api_supported(core_info_t *info);
/* Convenience wrapper functions used to interpret
* the 'savestate_support_level' parameter of
* the currently loaded core. If no core is
* loaded, will return 'true' (since full
* savestate functionality is assumed by default) */
bool core_info_current_supports_savestate(void);
bool core_info_current_supports_rewind(void);
bool core_info_current_supports_netplay(void);
bool core_info_current_supports_runahead(void);
/* Sets 'locked' status of specified core
* > Returns true if successful
* > Like all functions that access the cached

View File

@ -467,6 +467,26 @@ MSG_HASH(
MENU_ENUM_LABEL_VALUE_CORE_INFO_REQUIRED_HW_API,
"Required Graphics API"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_SUPPORT_LEVEL,
"Save State Support"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_DISABLED,
"None"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_BASIC,
"Basic (Save/Load)"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_SERIALIZED,
"Serialized (Save/Load, Rewind)"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_DETERMINISTIC,
"Deterministic (Save/Load, Rewind, Run-Ahead, Netplay)"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE,
"Firmware"

View File

@ -460,13 +460,14 @@ static int menu_displaylist_parse_core_info(menu_displaylist_info_t *info,
settings_t *settings)
{
char tmp[PATH_MAX_LENGTH];
unsigned i, count = 0;
core_info_t *core_info = NULL;
const char *core_path = NULL;
unsigned i, count = 0;
core_info_t *core_info = NULL;
const char *core_path = NULL;
const char *savestate_support = NULL;
#if !(defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
bool kiosk_mode_enable = settings->bools.kiosk_mode_enable;
bool kiosk_mode_enable = settings->bools.kiosk_mode_enable;
#if defined(HAVE_NETWORKING) && defined(HAVE_ONLINE_UPDATER)
bool menu_show_core_updater = settings->bools.menu_show_core_updater;
bool menu_show_core_updater = settings->bools.menu_show_core_updater;
#endif
#endif
@ -615,6 +616,39 @@ static int menu_displaylist_parse_core_info(menu_displaylist_info_t *info,
count++;
}
switch (core_info->savestate_support_level)
{
case CORE_INFO_SAVESTATE_BASIC:
savestate_support = msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_BASIC);
break;
case CORE_INFO_SAVESTATE_SERIALIZED:
savestate_support = msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_SERIALIZED);
break;
case CORE_INFO_SAVESTATE_DETERMINISTIC:
savestate_support = msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_DETERMINISTIC);
break;
default:
if (core_info->savestate_support_level >
CORE_INFO_SAVESTATE_DETERMINISTIC)
savestate_support = msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_DETERMINISTIC);
else
savestate_support = msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_DISABLED);
break;
}
fill_pathname_join_concat_noext(tmp,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_SUPPORT_LEVEL),
": ",
savestate_support,
sizeof(tmp));
if (menu_entries_append_enum(info->list, tmp, "",
MENU_ENUM_LABEL_CORE_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE, 0, 0))
count++;
if (core_info->firmware_count > 0)
{
core_info_ctx_firmware_t firmware_info;
@ -2872,6 +2906,7 @@ static int menu_displaylist_parse_load_content_settings(
#endif
bool quickmenu_show_resume_content = settings->bools.quick_menu_show_resume_content;
bool quickmenu_show_restart_content = settings->bools.quick_menu_show_restart_content;
bool savestates_enabled = core_info_current_supports_savestate();
rarch_system_info_t *system = &runloop_state_get_ptr()->system;
if (quickmenu_show_resume_content)
@ -2920,7 +2955,8 @@ static int menu_displaylist_parse_load_content_settings(
}
#endif
if (settings->bools.quick_menu_show_save_load_state)
if (savestates_enabled &&
settings->bools.quick_menu_show_save_load_state)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_STATE_SLOT, PARSE_ONLY_INT, true) == 0)
@ -2941,7 +2977,8 @@ static int menu_displaylist_parse_load_content_settings(
count++;
}
if (settings->bools.quick_menu_show_save_load_state &&
if (savestates_enabled &&
settings->bools.quick_menu_show_save_load_state &&
settings->bools.quick_menu_show_undo_save_load_state)
{
#ifdef HAVE_CHEEVOS

View File

@ -2594,6 +2594,12 @@ enum msg_hash_enums
MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE,
MENU_ENUM_LABEL_VALUE_CORE_INFO_REQUIRED_HW_API,
MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_SUPPORT_LEVEL,
MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_DISABLED,
MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_BASIC,
MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_SERIALIZED,
MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_DETERMINISTIC,
/* System information */
MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LAKKA_VERSION,

View File

@ -39,7 +39,7 @@
#include <time/rtime.h>
#ifdef HAVE_CONFIG_H
#include "../core.h"
#include "../config.h"
#endif
#ifdef HAVE_NETWORKING
@ -52,6 +52,7 @@
#include "../content.h"
#include "../core.h"
#include "../core_info.h"
#include "../file_path_special.h"
#include "../configuration.h"
#include "../msg_hash.h"
@ -440,6 +441,13 @@ bool content_undo_load_state(void)
settings_t *settings = config_get_ptr();
bool block_sram_overwrite = settings->bools.block_sram_overwrite;
if (!core_info_current_supports_savestate())
{
RARCH_LOG("[State]: %s\n",
msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES));
return false;
}
RARCH_LOG("[State]: %s \"%s\", %u %s.\n",
msg_hash_to_str(MSG_LOADING_STATE),
undo_load_buf.path,
@ -886,6 +894,13 @@ error:
**/
bool content_undo_save_state(void)
{
if (!core_info_current_supports_savestate())
{
RARCH_LOG("[State]: %s\n",
msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES));
return false;
}
return task_push_undo_save_state(undo_save_buf.path,
undo_save_buf.data,
undo_save_buf.size);
@ -1474,6 +1489,13 @@ bool content_save_state(const char *path, bool save_to_disk, bool autosave)
void *data = NULL;
size_t serial_size;
if (!core_info_current_supports_savestate())
{
RARCH_LOG("[State]: %s\n",
msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES));
return false;
}
core_serialize_size(&info);
if (info.size == 0)
@ -1606,8 +1628,8 @@ void content_wait_for_save_state_task(void)
bool content_load_state(const char *path,
bool load_to_backup_buffer, bool autoload)
{
retro_task_t *task = task_init();
save_task_state_t *state = (save_task_state_t*)calloc(1, sizeof(*state));
retro_task_t *task = NULL;
save_task_state_t *state = NULL;
settings_t *settings = config_get_ptr();
int state_slot = settings->ints.state_slot;
#if defined(HAVE_ZLIB)
@ -1616,6 +1638,16 @@ bool content_load_state(const char *path,
bool compress_files = false;
#endif
if (!core_info_current_supports_savestate())
{
RARCH_LOG("[State]: %s\n",
msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES));
goto error;
}
task = task_init();
state = (save_task_state_t*)calloc(1, sizeof(*state));
if (!task || !state)
goto error;
@ -1847,6 +1879,13 @@ bool content_load_state_from_ram(void)
bool ret = false;
void* temp_data = NULL;
if (!core_info_current_supports_savestate())
{
RARCH_LOG("[State]: %s\n",
msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES));
return false;
}
if (!ram_buf.state_buf.data)
return false;
@ -1891,6 +1930,13 @@ bool content_save_state_to_ram(void)
void *data = NULL;
size_t serial_size;
if (!core_info_current_supports_savestate())
{
RARCH_LOG("[State]: %s\n",
msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES));
return false;
}
core_serialize_size(&info);
if (info.size == 0)