From 05c1f9c9aace296f23c27b5030d4c72578a37df0 Mon Sep 17 00:00:00 2001 From: "U-DESKTOP-LII42QK\\andre" Date: Sun, 5 Jan 2020 17:53:59 -0600 Subject: [PATCH] Squashed commit of the following: commit 830a69818c6a9496d950def3f68f59c7d3affcab Author: celerizer <33245078+celerizer@users.noreply.github.com> Date: Sun Jan 5 17:43:47 2020 -0600 remove unneeded pointer commit 034cc521004dd95816af69c9d02eec6b3db62d95 Author: celerizer <33245078+celerizer@users.noreply.github.com> Date: Sun Jan 5 17:39:45 2020 -0600 cleanup commit 4317b9d04d3f86f215d9df8d41ac22a6a2705420 Author: celerizer <33245078+celerizer@users.noreply.github.com> Date: Thu Jan 2 18:52:06 2020 -0600 needs a lot of cleanup --- cheevos-new/cheevos.c | 177 +++++++++++++++++++++++++++++++++-- cheevos-new/cheevos.h | 2 + cheevos-new/parser.c | 24 +++++ cheevos-new/parser.h | 2 + configuration.c | 1 + configuration.h | 1 + discord/discord.c | 6 ++ discord/discord.h | 1 + intl/msg_hash_lbl.h | 2 + intl/msg_hash_us.h | 8 ++ menu/cbs/menu_cbs_sublabel.c | 4 + menu/menu_displaylist.c | 1 + menu/menu_setting.c | 16 ++++ msg_hash.h | 1 + 14 files changed, 238 insertions(+), 8 deletions(-) diff --git a/cheevos-new/cheevos.c b/cheevos-new/cheevos.c index cf8ab35b08..49527d1f5a 100644 --- a/cheevos-new/cheevos.c +++ b/cheevos-new/cheevos.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #ifdef HAVE_CONFIG_H @@ -45,6 +46,10 @@ #include #endif +#ifdef HAVE_DISCORD +#include "../discord/discord.h" +#endif + #include "badges.h" #include "cheevos.h" #include "fixup.h" @@ -97,6 +102,10 @@ /* Define this macro to log downloaded badge images. */ #undef CHEEVOS_LOG_BADGES +/* Number of usecs to wait between posting rich presence to the site. */ +/* Keep consistent with SERVER_PING_FREQUENCY from RAIntegration. */ +#define CHEEVOS_PING_FREQUENCY 2 * 60 * 1000000 + typedef struct { rc_trigger_t* trigger; @@ -114,6 +123,13 @@ typedef struct int format; } rcheevos_lboard_t; +typedef struct +{ + rc_richpresence_t* richpresence; + char evaluation[256]; + retro_time_t last_update; +} rcheevos_richpresence_t; + typedef struct { retro_task_t* task; @@ -128,6 +144,7 @@ typedef struct rcheevos_cheevo_t* core; rcheevos_cheevo_t* unofficial; rcheevos_lboard_t* lboards; + rcheevos_richpresence_t richpresence; rcheevos_fixups_t fixups; @@ -163,6 +180,7 @@ static rcheevos_locals_t rcheevos_locals = NULL, /* core */ NULL, /* unofficial */ NULL, /* lboards */ + {0}, /* rich presence */ {0}, /* fixups */ {0}, /* token */ }; @@ -371,11 +389,11 @@ static const char* rcheevos_rc_error(int ret) static int rcheevos_parse(const char* json) { char buffer[256]; - settings_t *settings = config_get_ptr(); - int res = 0; - int i = 0; - unsigned j = 0; - unsigned count = 0; + settings_t *settings = config_get_ptr(); + int res = 0; + int i = 0; + unsigned j = 0; + unsigned count = 0; rcheevos_cheevo_t* cheevo = NULL; rcheevos_lboard_t* lboard = NULL; rcheevos_racheevo_t* rac = NULL; @@ -397,6 +415,7 @@ static int rcheevos_parse(const char* json) rcheevos_locals.core = NULL; rcheevos_locals.unofficial = NULL; rcheevos_locals.lboards = NULL; + rcheevos_locals.richpresence.richpresence = NULL; rcheevos_free_patchdata(&rcheevos_locals.patchdata); return 0; } @@ -515,6 +534,98 @@ static int rcheevos_parse(const char* json) lboard->format = rc_parse_format(lboard->info->format); } + if (rcheevos_locals.patchdata.richpresence_script) + { + char *script = rcheevos_locals.patchdata.richpresence_script; + char *buffer_it = &script[0]; + const char *script_it = &script[0]; + unsigned buffer_size; + + while (*script_it != '\0') + { + if (*script_it == '\\') + { + char escaped_char = *(script_it + 1); + + switch (escaped_char) + { + /* Ignore carriage return */ + case 'r': + script_it += 2; + break; + + /* Accept newlines */ + case 'n': + *buffer_it = '\n'; + buffer_it++; + script_it += 2; + break; + + /* Accept UTF-16 unicode characters */ + case 'u': + { + uint16_t *utf16; + char *utf8; + uint8_t i, j; + + for (i = 1; i < 16; i++) + if (strncmp((script_it + 6 * i), "\\u", 2)) + break; + + utf16 = (uint16_t*)calloc(i, sizeof(uint16_t)); + utf8 = (char*) calloc(i * 4, sizeof(char)); + + /* Get escaped hex values and add them to the string */ + for (j = 0; j < i; j++) + { + char temp[5]; + + script_it += 2; + memcpy(temp, script_it, 4); + temp[4] = '\0'; + utf16[j] = string_hex_to_unsigned(temp); + script_it += 4; + } + + if (utf16_to_char_string(utf16, utf8, i * 4)) + { + memcpy(buffer_it, utf8, strlen(utf8)); + buffer_it += strlen(utf8); + } + + free(utf16); + free(utf8); + } + break; + default: + *buffer_it = *script_it; + buffer_it++; + script_it++; + }; + } + else + { + *buffer_it = *script_it; + buffer_it++; + script_it++; + } + } + *buffer_it = '\0'; + + buffer_size = rc_richpresence_size(rcheevos_locals.patchdata.richpresence_script); + if (buffer_size == 0) + { + rcheevos_locals.richpresence.richpresence = NULL; + CHEEVOS_ERR(RCHEEVOS_TAG "Error reading rich presence"); + } + else + { + char *buffer = (char*)malloc(buffer_size); + rcheevos_locals.richpresence.richpresence = rc_parse_richpresence(buffer, script, NULL, 0); + rcheevos_locals.richpresence.last_update = cpu_features_get_time_usec(); + } + } + return 0; error: @@ -898,6 +1009,49 @@ static void rcheevos_test_leaderboards(void) } } +const char* rcheevos_get_richpresence(void) +{ + if (!rcheevos_locals.richpresence.richpresence) + return NULL; + else + return rcheevos_locals.richpresence.evaluation; +} + +static void rcheevos_test_richpresence(void) +{ + if (!rcheevos_locals.richpresence.richpresence || + cpu_features_get_time_usec() < rcheevos_locals.richpresence.last_update + CHEEVOS_PING_FREQUENCY) + return; + else + { + settings_t* settings = config_get_ptr(); + char url[256], post_data[1024]; + + rcheevos_locals.richpresence.last_update = cpu_features_get_time_usec(); + + rc_evaluate_richpresence(rcheevos_locals.richpresence.richpresence, + rcheevos_locals.richpresence.evaluation, + sizeof(rcheevos_locals.richpresence.evaluation), rcheevos_peek, NULL, NULL); + + /* Form URL */ + snprintf(url, 256, "http://retroachievements.org/dorequest.php?r=ping&u=%s&t=%s", + settings->arrays.cheevos_username, + rcheevos_locals.token); + + /* Form POST data */ + snprintf(post_data, 1024, "g=%u&m=%s", + rcheevos_locals.patchdata.game_id, + rcheevos_get_richpresence()); + +#ifdef HAVE_DISCORD + if (settings->bools.discord_enable) + discord_update(DISCORD_PRESENCE_RETROACHIEVEMENTS); +#endif + + task_push_http_post_transfer(url, post_data, true, "POST", NULL, NULL); + } +} + void rcheevos_reset_game(void) { rcheevos_cheevo_t* cheevo; @@ -935,6 +1089,8 @@ void rcheevos_reset_game(void) lboard->lboard->submitted = 1; } } + + rcheevos_locals.richpresence.last_update = cpu_features_get_time_usec(); } #ifdef HAVE_MENU @@ -1107,12 +1263,14 @@ bool rcheevos_unload(void) CHEEVOS_FREE(rcheevos_locals.core); CHEEVOS_FREE(rcheevos_locals.unofficial); CHEEVOS_FREE(rcheevos_locals.lboards); + CHEEVOS_FREE(rcheevos_locals.richpresence.richpresence); rcheevos_free_patchdata(&rcheevos_locals.patchdata); rcheevos_fixup_destroy(&rcheevos_locals.fixups); - rcheevos_locals.core = NULL; - rcheevos_locals.unofficial = NULL; - rcheevos_locals.lboards = NULL; + rcheevos_locals.core = NULL; + rcheevos_locals.unofficial = NULL; + rcheevos_locals.lboards = NULL; + rcheevos_locals.richpresence.richpresence = NULL; rcheevos_loaded = false; rcheevos_hardcore_active = false; @@ -1174,6 +1332,9 @@ void rcheevos_test(void) settings->bools.cheevos_leaderboards_enable && !rcheevos_hardcore_paused) rcheevos_test_leaderboards(); + + if (settings->bools.cheevos_richpresence_enable) + rcheevos_test_richpresence(); } } diff --git a/cheevos-new/cheevos.h b/cheevos-new/cheevos.h index fce51e482c..6a0b310029 100644 --- a/cheevos-new/cheevos.h +++ b/cheevos-new/cheevos.h @@ -64,6 +64,8 @@ bool rcheevos_get_support_cheevos(void); int rcheevos_get_console(void); +const char *rcheevos_get_richpresence(void); + extern bool rcheevos_loaded; extern bool rcheevos_hardcore_active; extern bool rcheevos_hardcore_paused; diff --git a/cheevos-new/parser.c b/cheevos-new/parser.c index eed9a88ecb..e27002991a 100644 --- a/cheevos-new/parser.c +++ b/cheevos-new/parser.c @@ -23,6 +23,7 @@ #define CHEEVOS_JSON_KEY_TOKEN 0x0e2dbd26U #define CHEEVOS_JSON_KEY_FLAGS 0x0d2e96b2U #define CHEEVOS_JSON_KEY_LEADERBOARDS 0xf1247d2dU +#define CHEEVOS_JSON_KEY_RICHPRESENCE 0xf18dd230U #define CHEEVOS_JSON_KEY_MEM 0x0b8807e4U #define CHEEVOS_JSON_KEY_FORMAT 0xb341208eU #define CHEEVOS_JSON_KEY_SUCCESS 0x110461deU @@ -261,7 +262,9 @@ typedef struct { int in_cheevos; int in_lboards; + int is_game_id; int is_console_id; + int is_richpresence; unsigned core_count; unsigned unofficial_count; unsigned lboard_count; @@ -386,9 +389,14 @@ static int rcheevos_read_key(void* userdata, case CHEEVOS_JSON_KEY_CONSOLE_ID: ud->is_console_id = 1; break; + case CHEEVOS_JSON_KEY_RICHPRESENCE: + ud->is_richpresence = 1; + break; case CHEEVOS_JSON_KEY_ID: if (common) ud->field = &ud->id; + else + ud->is_game_id = 1; break; case CHEEVOS_JSON_KEY_MEMADDR: if (ud->in_cheevos) @@ -451,6 +459,13 @@ static int rcheevos_read_string(void* userdata, ud->field->string = string; ud->field->length = length; } + else if (ud->is_richpresence) + { + ud->patchdata->richpresence_script = (char*)malloc(length + 1); + memcpy(ud->patchdata->richpresence_script, string, length); + ud->patchdata->richpresence_script[length] = '\0'; + ud->is_richpresence = 0; + } return 0; } @@ -465,6 +480,11 @@ static int rcheevos_read_number(void* userdata, ud->field->string = number; ud->field->length = length; } + else if (ud->is_game_id) + { + ud->patchdata->game_id = (unsigned)strtol(number, NULL, 10); + ud->is_game_id = 0; + } else if (ud->is_console_id) { ud->patchdata->console_id = (unsigned)strtol(number, NULL, 10); @@ -527,7 +547,9 @@ int rcheevos_get_patchdata(const char* json, rcheevos_rapatchdata_t* patchdata) /* Load the achievements. */ ud.in_cheevos = 0; ud.in_lboards = 0; + ud.is_game_id = 0; ud.is_console_id = 0; + ud.is_richpresence = 0; ud.field = NULL; ud.core_count = 0; ud.unofficial_count = 0; @@ -586,7 +608,9 @@ void rcheevos_free_patchdata(rcheevos_rapatchdata_t* patchdata) CHEEVOS_FREE(patchdata->core); CHEEVOS_FREE(patchdata->unofficial); CHEEVOS_FREE(patchdata->lboards); + CHEEVOS_FREE(patchdata->richpresence_script); + patchdata->game_id = 0; patchdata->console_id = 0; patchdata->core = NULL; patchdata->unofficial = NULL; diff --git a/cheevos-new/parser.h b/cheevos-new/parser.h index b9706f5474..2ce63d4b08 100644 --- a/cheevos-new/parser.h +++ b/cheevos-new/parser.h @@ -42,11 +42,13 @@ typedef struct { } rcheevos_ralboard_t; typedef struct { + unsigned game_id; unsigned console_id; rcheevos_racheevo_t* core; rcheevos_racheevo_t* unofficial; rcheevos_ralboard_t* lboards; + char* richpresence_script; unsigned core_count; unsigned unofficial_count; diff --git a/configuration.c b/configuration.c index 3cf434e697..43514320eb 100644 --- a/configuration.c +++ b/configuration.c @@ -1579,6 +1579,7 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings, SETTING_BOOL("cheevos_test_unofficial", &settings->bools.cheevos_test_unofficial, true, false, false); SETTING_BOOL("cheevos_hardcore_mode_enable", &settings->bools.cheevos_hardcore_mode_enable, true, false, false); SETTING_BOOL("cheevos_leaderboards_enable", &settings->bools.cheevos_leaderboards_enable, true, false, false); + SETTING_BOOL("cheevos_richpresence_enable", &settings->bools.cheevos_richpresence_enable, true, false, false); SETTING_BOOL("cheevos_verbose_enable", &settings->bools.cheevos_verbose_enable, true, false, false); SETTING_BOOL("cheevos_auto_screenshot", &settings->bools.cheevos_auto_screenshot, true, false, false); #ifdef HAVE_XMB diff --git a/configuration.h b/configuration.h index c14c307741..9c2aa6d80c 100644 --- a/configuration.h +++ b/configuration.h @@ -288,6 +288,7 @@ typedef struct settings bool cheevos_test_unofficial; bool cheevos_hardcore_mode_enable; bool cheevos_leaderboards_enable; + bool cheevos_richpresence_enable; bool cheevos_badges_enable; bool cheevos_verbose_enable; bool cheevos_auto_screenshot; diff --git a/discord/discord.c b/discord/discord.c index 777a7e6a00..72af1c904b 100644 --- a/discord/discord.c +++ b/discord/discord.c @@ -447,6 +447,12 @@ void discord_update(enum discord_presence presence) } } break; +#ifdef HAVE_CHEEVOS + case DISCORD_PRESENCE_RETROACHIEVEMENTS: + discord_presence.details = rcheevos_get_richpresence(); + presence = DISCORD_PRESENCE_GAME; + break; +#endif case DISCORD_PRESENCE_SHUTDOWN: discord_presence.partyId = NULL; discord_presence.partyMax = 0; diff --git a/discord/discord.h b/discord/discord.h index a08d9ed6b7..0e32b50103 100644 --- a/discord/discord.h +++ b/discord/discord.h @@ -33,6 +33,7 @@ enum discord_presence DISCORD_PRESENCE_NETPLAY_HOSTING, DISCORD_PRESENCE_NETPLAY_CLIENT, DISCORD_PRESENCE_NETPLAY_NETPLAY_STOPPED, + DISCORD_PRESENCE_RETROACHIEVEMENTS, DISCORD_PRESENCE_SHUTDOWN }; diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index f74217ce02..712bc4e003 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -164,6 +164,8 @@ MSG_HASH(MENU_ENUM_LABEL_CHEEVOS_HARDCORE_MODE_ENABLE, "cheevos_hardcore_mode_enable") MSG_HASH(MENU_ENUM_LABEL_CHEEVOS_LEADERBOARDS_ENABLE, "cheevos_leaderboards_enable") +MSG_HASH(MENU_ENUM_LABEL_CHEEVOS_RICHPRESENCE_ENABLE, + "cheevos_richpresence_enable") MSG_HASH(MENU_ENUM_LABEL_CHEEVOS_BADGES_ENABLE, "cheevos_badges_enable") MSG_HASH(MENU_ENUM_LABEL_CHEEVOS_LOCKED_ENTRY, diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 1e7bf3fc3c..fd61f48a74 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -540,6 +540,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_LEADERBOARDS_ENABLE, "Leaderboards" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_RICHPRESENCE_ENABLE, + "Rich Presence" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_BADGES_ENABLE, "Achievement Badges" @@ -4493,6 +4497,10 @@ MSG_HASH( "Game specific leaderboards.\n" "Has no effect if Hardcore Mode is disabled." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEEVOS_RICHPRESENCE_ENABLE, + "Sends detailed play status to the RetroAchievements website." + ) MSG_HASH( MENU_ENUM_SUBLABEL_CHEEVOS_BADGES_ENABLE, "Display badges in the Achievement List." diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index b2b961d66e..b4506243d2 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -164,6 +164,7 @@ default_sublabel_macro(action_bind_sublabel_cheevos_enable, MENU_ default_sublabel_macro(action_bind_sublabel_cheevos_test_unofficial, MENU_ENUM_SUBLABEL_CHEEVOS_TEST_UNOFFICIAL) default_sublabel_macro(action_bind_sublabel_cheevos_hardcore_mode_enable, MENU_ENUM_SUBLABEL_CHEEVOS_HARDCORE_MODE_ENABLE) default_sublabel_macro(action_bind_sublabel_cheevos_leaderboards_enable, MENU_ENUM_SUBLABEL_CHEEVOS_LEADERBOARDS_ENABLE) +default_sublabel_macro(action_bind_sublabel_cheevos_richpresence_enable, MENU_ENUM_SUBLABEL_CHEEVOS_RICHPRESENCE_ENABLE) default_sublabel_macro(action_bind_sublabel_cheevos_badges_enable, MENU_ENUM_SUBLABEL_CHEEVOS_BADGES_ENABLE) default_sublabel_macro(action_bind_sublabel_cheevos_verbose_enable, MENU_ENUM_SUBLABEL_CHEEVOS_VERBOSE_ENABLE) default_sublabel_macro(action_bind_sublabel_cheevos_auto_screenshot, MENU_ENUM_SUBLABEL_CHEEVOS_AUTO_SCREENSHOT) @@ -2582,6 +2583,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_CHEEVOS_LEADERBOARDS_ENABLE: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_cheevos_leaderboards_enable); break; + case MENU_ENUM_LABEL_CHEEVOS_RICHPRESENCE_ENABLE: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_cheevos_richpresence_enable); + break; case MENU_ENUM_LABEL_CHEEVOS_BADGES_ENABLE: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_cheevos_badges_enable); break; diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 5ac74f5745..6e2e9a929d 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -5675,6 +5675,7 @@ unsigned menu_displaylist_build_list(file_list_t *list, enum menu_displaylist_ct {MENU_ENUM_LABEL_CHEEVOS_PASSWORD, PARSE_ONLY_STRING, false }, {MENU_ENUM_LABEL_CHEEVOS_HARDCORE_MODE_ENABLE, PARSE_ONLY_BOOL, false }, {MENU_ENUM_LABEL_CHEEVOS_LEADERBOARDS_ENABLE, PARSE_ONLY_BOOL, false }, + {MENU_ENUM_LABEL_CHEEVOS_RICHPRESENCE_ENABLE, PARSE_ONLY_BOOL, false }, {MENU_ENUM_LABEL_CHEEVOS_BADGES_ENABLE, PARSE_ONLY_BOOL, false }, {MENU_ENUM_LABEL_CHEEVOS_TEST_UNOFFICIAL, PARSE_ONLY_BOOL, false }, {MENU_ENUM_LABEL_CHEEVOS_VERBOSE_ENABLE, PARSE_ONLY_BOOL, false }, diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 1e2f8989be..e730f8f993 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -15380,6 +15380,22 @@ static bool setting_append_list( SD_FLAG_NONE ); + CONFIG_BOOL( + list, list_info, + &settings->bools.cheevos_richpresence_enable, + MENU_ENUM_LABEL_CHEEVOS_RICHPRESENCE_ENABLE, + MENU_ENUM_LABEL_VALUE_CHEEVOS_RICHPRESENCE_ENABLE, + false, + 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 + ); + if (string_is_equal(settings->arrays.menu_driver, "xmb") || string_is_equal(settings->arrays.menu_driver, "ozone")) CONFIG_BOOL( list, list_info, diff --git a/msg_hash.h b/msg_hash.h index 075a7e0d55..8a9637ad74 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1212,6 +1212,7 @@ enum msg_hash_enums MENU_LABEL(ACCOUNTS_CHEEVOS_USERNAME), MENU_LABEL(CHEEVOS_HARDCORE_MODE_ENABLE), MENU_LABEL(CHEEVOS_LEADERBOARDS_ENABLE), + MENU_LABEL(CHEEVOS_RICHPRESENCE_ENABLE), MENU_LABEL(CHEEVOS_BADGES_ENABLE), MENU_LABEL(CHEEVOS_TEST_UNOFFICIAL), MENU_LABEL(CHEEVOS_VERBOSE_ENABLE),