diff --git a/config.def.h b/config.def.h index 56999e908e57..877d79542c5f 100644 --- a/config.def.h +++ b/config.def.h @@ -866,6 +866,10 @@ static const bool audio_enable_menu_bgm = false; * applied */ #define DEFAULT_NOTIFICATION_SHOW_CHEATS_APPLIED true +/* Display a notification when applying an + * IPS/BPS/UPS patch file */ +#define DEFAULT_NOTIFICATION_SHOW_PATCH_APPLIED true + /* Display a notification when loading an * input remap file */ #define DEFAULT_NOTIFICATION_SHOW_REMAP_LOAD true diff --git a/configuration.c b/configuration.c index f27376525bdd..c754ae421274 100644 --- a/configuration.c +++ b/configuration.c @@ -1502,6 +1502,7 @@ static struct config_bool_setting *populate_settings_bool( SETTING_BOOL("menu_show_load_content_animation", &settings->bools.menu_show_load_content_animation, true, DEFAULT_MENU_SHOW_LOAD_CONTENT_ANIMATION, false); SETTING_BOOL("notification_show_autoconfig", &settings->bools.notification_show_autoconfig, true, DEFAULT_NOTIFICATION_SHOW_AUTOCONFIG, false); SETTING_BOOL("notification_show_cheats_applied", &settings->bools.notification_show_cheats_applied, true, DEFAULT_NOTIFICATION_SHOW_CHEATS_APPLIED, false); + SETTING_BOOL("notification_show_patch_applied", &settings->bools.notification_show_patch_applied, true, DEFAULT_NOTIFICATION_SHOW_PATCH_APPLIED, false); SETTING_BOOL("notification_show_remap_load", &settings->bools.notification_show_remap_load, true, DEFAULT_NOTIFICATION_SHOW_REMAP_LOAD, false); SETTING_BOOL("notification_show_config_override_load", &settings->bools.notification_show_config_override_load, true, DEFAULT_NOTIFICATION_SHOW_CONFIG_OVERRIDE_LOAD, false); SETTING_BOOL("notification_show_set_initial_disk", &settings->bools.notification_show_set_initial_disk, true, DEFAULT_NOTIFICATION_SHOW_SET_INITIAL_DISK, false); diff --git a/configuration.h b/configuration.h index e03455679b71..481d71156bb6 100644 --- a/configuration.h +++ b/configuration.h @@ -552,6 +552,7 @@ typedef struct settings bool menu_show_load_content_animation; bool notification_show_autoconfig; bool notification_show_cheats_applied; + bool notification_show_patch_applied; bool notification_show_remap_load; bool notification_show_config_override_load; bool notification_show_set_initial_disk; diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index dca4d8c9ce61..49236cb99175 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -4622,6 +4622,10 @@ MSG_HASH( MENU_ENUM_LABEL_NOTIFICATION_SHOW_CHEATS_APPLIED, "notification_show_cheats_applied" ) +MSG_HASH( + MENU_ENUM_LABEL_NOTIFICATION_SHOW_PATCH_APPLIED, + "notification_show_patch_applied" + ) MSG_HASH( MENU_ENUM_LABEL_NOTIFICATION_SHOW_REMAP_LOAD, "notification_show_remap_load" diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 4c354ac29c12..54f015729f4d 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -3718,6 +3718,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_CHEATS_APPLIED, "Display an on-screen message when cheat codes are applied." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_PATCH_APPLIED, + "Patch Notifications" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_PATCH_APPLIED, + "Display an on-screen message when soft-patching ROMs." + ) MSG_HASH( MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_AUTOCONFIG, "Display an on-screen message when connecting/disconnecting input devices." @@ -10690,6 +10698,10 @@ MSG_HASH( MSG_APPLYING_CHEAT, "Applying cheat changes." ) +MSG_HASH( + MSG_APPLYING_PATCH, + "Applying patch: %s" + ) MSG_HASH( MSG_APPLYING_SHADER, "Applying shader" diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index 4193cfe8d39b..449274d7ebc3 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -414,6 +414,9 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_notification_show_autoconfig, MENU_ #ifdef HAVE_CHEATS DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_notification_show_cheats_applied, MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_CHEATS_APPLIED) #endif +#ifdef HAVE_PATCH +DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_notification_show_patch_applied, MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_PATCH_APPLIED) +#endif DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_notification_show_remap_load, MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_REMAP_LOAD) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_notification_show_config_override_load, MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_CONFIG_OVERRIDE_LOAD) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_notification_show_set_initial_disk, MENU_ENUM_SUBLABEL_NOTIFICATION_SHOW_SET_INITIAL_DISK) @@ -3252,6 +3255,11 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_NOTIFICATION_SHOW_CHEATS_APPLIED: #ifdef HAVE_CHEATS BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_notification_show_cheats_applied); +#endif + break; + case MENU_ENUM_LABEL_NOTIFICATION_SHOW_PATCH_APPLIED: +#ifdef HAVE_PATCH + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_notification_show_patch_applied); #endif break; case MENU_ENUM_LABEL_NOTIFICATION_SHOW_REMAP_LOAD: diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 6b0816ceb424..cf29c0990be8 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -8111,7 +8111,12 @@ unsigned menu_displaylist_build_list( {MENU_ENUM_LABEL_MEMORY_UPDATE_INTERVAL, PARSE_ONLY_UINT, false }, {MENU_ENUM_LABEL_MENU_SHOW_LOAD_CONTENT_ANIMATION, PARSE_ONLY_BOOL, false }, {MENU_ENUM_LABEL_NOTIFICATION_SHOW_AUTOCONFIG, PARSE_ONLY_BOOL, false }, +#ifdef HAVE_CHEATS {MENU_ENUM_LABEL_NOTIFICATION_SHOW_CHEATS_APPLIED, PARSE_ONLY_BOOL, false }, +#endif +#ifdef HAVE_PATCH + {MENU_ENUM_LABEL_NOTIFICATION_SHOW_PATCH_APPLIED, PARSE_ONLY_BOOL, true }, +#endif {MENU_ENUM_LABEL_NOTIFICATION_SHOW_REMAP_LOAD, PARSE_ONLY_BOOL, false }, {MENU_ENUM_LABEL_NOTIFICATION_SHOW_CONFIG_OVERRIDE_LOAD, PARSE_ONLY_BOOL, false }, {MENU_ENUM_LABEL_NOTIFICATION_SHOW_SET_INITIAL_DISK, PARSE_ONLY_BOOL, false }, diff --git a/menu/menu_setting.c b/menu/menu_setting.c index ec4492661b96..6cbd9b5756d3 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -13594,6 +13594,7 @@ static bool setting_append_list( general_read_handler, SD_FLAG_NONE); +#ifdef HAVE_CHEATS CONFIG_BOOL( list, list_info, &settings->bools.notification_show_cheats_applied, @@ -13608,7 +13609,23 @@ static bool setting_append_list( general_write_handler, general_read_handler, SD_FLAG_NONE); - +#endif +#ifdef HAVE_PATCH + CONFIG_BOOL( + list, list_info, + &settings->bools.notification_show_patch_applied, + MENU_ENUM_LABEL_NOTIFICATION_SHOW_PATCH_APPLIED, + MENU_ENUM_LABEL_VALUE_NOTIFICATION_SHOW_PATCH_APPLIED, + DEFAULT_NOTIFICATION_SHOW_PATCH_APPLIED, + 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); +#endif CONFIG_BOOL( list, list_info, &settings->bools.notification_show_remap_load, diff --git a/msg_hash.h b/msg_hash.h index 819411ec9120..b99585534953 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -333,6 +333,7 @@ enum msg_hash_enums MSG_REVERTING_SAVESTATE_DIRECTORY_TO, MSG_DOWNLOAD_FAILED, MSG_APPLYING_CHEAT, + MSG_APPLYING_PATCH, MSG_INPUT_CHEAT, MSG_INPUT_PRESET_FILENAME, MSG_INPUT_CHEAT_FILENAME, @@ -2760,6 +2761,7 @@ enum msg_hash_enums MENU_LABEL(NOTIFICATION_SHOW_AUTOCONFIG), MENU_LABEL(NOTIFICATION_SHOW_CHEATS_APPLIED), + MENU_LABEL(NOTIFICATION_SHOW_PATCH_APPLIED), MENU_LABEL(NOTIFICATION_SHOW_REMAP_LOAD), MENU_LABEL(NOTIFICATION_SHOW_CONFIG_OVERRIDE_LOAD), MENU_LABEL(NOTIFICATION_SHOW_SET_INITIAL_DISK), diff --git a/tasks/task_patch.c b/tasks/task_patch.c index 7aeabc35a4ce..487b12d3e7ca 100644 --- a/tasks/task_patch.c +++ b/tasks/task_patch.c @@ -31,8 +31,10 @@ #include +#include "../retroarch.h" #include "../msg_hash.h" #include "../verbosity.h" +#include "../configuration.h" enum bps_mode { @@ -613,6 +615,9 @@ static bool apply_patch_content(uint8_t **buf, ssize_t *size, const char *patch_desc, const char *patch_path, patch_func_t func, void *patch_data, int64_t patch_size) { + settings_t *settings = config_get_ptr(); + bool show_notification = settings ? + settings->bools.notification_show_patch_applied : false; enum patch_error err = PATCH_UNKNOWN; ssize_t ret_size = *size; uint8_t *ret_buf = *buf; @@ -628,6 +633,21 @@ static bool apply_patch_content(uint8_t **buf, free(ret_buf); *buf = patched_content; *size = target_size; + + /* Show an OSD message */ + if (show_notification) + { + const char *patch_filename = path_basename(patch_path); + char msg[256]; + + msg[0] = '\0'; + + snprintf(msg, sizeof(msg), msg_hash_to_str(MSG_APPLYING_PATCH), + patch_filename ? patch_filename : + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UNKNOWN)); + runloop_msg_queue_push(msg, 1, 180, false, NULL, + MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + } } else RARCH_ERR("%s %s: %s #%u\n", @@ -740,6 +760,7 @@ bool patch_content( bool allow_ups = !is_bps_pref && !is_ips_pref; bool allow_ips = !is_ups_pref && !is_bps_pref; bool allow_bps = !is_ups_pref && !is_ips_pref; + bool patch_found = false; if ( (unsigned)is_ips_pref + (unsigned)is_bps_pref @@ -750,14 +771,74 @@ bool patch_content( return false; } - if ( !try_ips_patch(allow_ips, name_ips, buf, size) - && !try_bps_patch(allow_bps, name_bps, buf, size) - && !try_ups_patch(allow_ups, name_ups, buf, size)) + /* Attempt to apply first (non-indexed) patch */ + if ( try_ips_patch(allow_ips, name_ips, buf, size) + || try_bps_patch(allow_bps, name_bps, buf, size) + || try_ups_patch(allow_ups, name_ups, buf, size)) { + /* A patch has been found. Now attempt to apply + * any additional 'indexed' patch files */ + size_t name_ips_len = strlen(name_ips); + size_t name_bps_len = strlen(name_bps); + size_t name_ups_len = strlen(name_ups); + char *name_ips_indexed = (char*)malloc((name_ips_len + 2) * sizeof(char)); + char *name_bps_indexed = (char*)malloc((name_bps_len + 2) * sizeof(char)); + char *name_ups_indexed = (char*)malloc((name_ups_len + 2) * sizeof(char)); + /* First patch already applied -> index + * for subsequent patches starts at 1 */ + size_t patch_index = 1; + + name_ips_indexed[0] = '\0'; + name_bps_indexed[0] = '\0'; + name_ups_indexed[0] = '\0'; + + strlcpy(name_ips_indexed, name_ips, (name_ips_len + 1) * sizeof(char)); + strlcpy(name_bps_indexed, name_bps, (name_bps_len + 1) * sizeof(char)); + strlcpy(name_ups_indexed, name_ups, (name_ups_len + 1) * sizeof(char)); + + /* Ensure that we NUL terminate *after* the + * index character */ + name_ips_indexed[name_ips_len + 1] = '\0'; + name_bps_indexed[name_bps_len + 1] = '\0'; + name_ups_indexed[name_ups_len + 1] = '\0'; + + /* try to patch "*.ipsX" */ + while (patch_index < 10) + { + /* Add index character to end of patch + * file path string + * > Note: This technique only works for + * index values up to 9 (i.e. single + * digit numbers) + * > If we want to support more than 10 + * patches in total, will have to replace + * this with an snprintf() implementation + * (which will have significantly higher + * performance overheads) */ + char index_char = '0' + patch_index; + + name_ips_indexed[name_ips_len] = index_char; + name_bps_indexed[name_bps_len] = index_char; + name_ups_indexed[name_ups_len] = index_char; + + if ( !try_ips_patch(allow_ips, name_ips_indexed, buf, size) + && !try_bps_patch(allow_bps, name_bps_indexed, buf, size) + && !try_ups_patch(allow_ups, name_ups_indexed, buf, size)) + break; + + patch_index++; + } + + free(name_ips_indexed); + free(name_bps_indexed); + free(name_ups_indexed); + + patch_found = true; + } + + if(!patch_found) RARCH_LOG("%s\n", msg_hash_to_str(MSG_DID_NOT_FIND_A_VALID_CONTENT_PATCH)); - return false; - } - return true; + return patch_found; }