default rich presence on; better handling of special characters

This commit is contained in:
Jamiras 2020-02-14 20:12:49 -07:00
parent b030f044f4
commit 4b8f3ec5b5
7 changed files with 179 additions and 123 deletions

View File

@ -27,7 +27,6 @@
#include <retro_miscellaneous.h>
#include <retro_math.h>
#include <net/net_http.h>
#include <encodings/utf.h>
#include <libretro.h>
#ifdef HAVE_CONFIG_H
@ -572,94 +571,31 @@ static int rcheevos_parse(const char* json)
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')
int buffer_size = rc_richpresence_size(rcheevos_locals.patchdata.richpresence_script);
if (buffer_size <= 0)
{
if (*script_it == '\\')
{
char escaped_char = *(script_it + 1);
snprintf(buffer, sizeof(buffer), "Error in rich presence: %s", rcheevos_rc_error(buffer_size));
switch (escaped_char)
{
/* Ignore carriage return */
case 'r':
script_it += 2;
break;
if (settings->bools.cheevos_verbose_enable)
runloop_msg_queue_push(buffer, 0, 4 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
/* 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)
{
CHEEVOS_ERR(RCHEEVOS_TAG "%s\n", buffer);
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.richpresence = rc_parse_richpresence(buffer, rcheevos_locals.patchdata.richpresence_script, NULL, 0);
rcheevos_locals.richpresence.last_update = cpu_features_get_time_usec();
}
rcheevos_locals.richpresence.evaluation[0] = '\0';
}
if (!rcheevos_locals.richpresence.richpresence && rcheevos_locals.patchdata.title)
{
snprintf(rcheevos_locals.richpresence.evaluation, sizeof(rcheevos_locals.richpresence.evaluation),
"Playing %s", rcheevos_locals.patchdata.title);
}
return 0;
@ -1055,37 +991,56 @@ const char* rcheevos_get_richpresence(void)
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;
settings_t* settings = config_get_ptr();
retro_time_t now = cpu_features_get_time_usec();
{
settings_t* settings = config_get_ptr();
char url[256], post_data[1024];
if (settings->bools.cheevos_richpresence_enable)
{
/* update rich presence every two minutes */
if (now < rcheevos_locals.richpresence.last_update + CHEEVOS_PING_FREQUENCY)
return;
rcheevos_locals.richpresence.last_update = cpu_features_get_time_usec();
if (rcheevos_locals.richpresence.richpresence)
{
rc_evaluate_richpresence(rcheevos_locals.richpresence.richpresence,
rcheevos_locals.richpresence.evaluation,
sizeof(rcheevos_locals.richpresence.evaluation), rcheevos_peek, NULL, NULL);
}
}
else
{
/* send ping every four minutes */
if (now < rcheevos_locals.richpresence.last_update + CHEEVOS_PING_FREQUENCY * 2)
return;
}
rc_evaluate_richpresence(rcheevos_locals.richpresence.richpresence,
rcheevos_locals.richpresence.evaluation,
sizeof(rcheevos_locals.richpresence.evaluation), rcheevos_peek, NULL, NULL);
rcheevos_locals.richpresence.last_update = now;
/* Form URL */
snprintf(url, 256, "http://retroachievements.org/dorequest.php?r=ping&u=%s&t=%s",
settings->arrays.cheevos_username,
rcheevos_locals.token);
{
char user_agent[256], url[256], post_data[1024];
/* Form POST data */
snprintf(post_data, 1024, "g=%u&m=%s",
rcheevos_locals.patchdata.game_id,
rcheevos_get_richpresence());
snprintf(url, sizeof(url), "http://retroachievements.org/dorequest.php?r=ping&u=%s&t=%s",
settings->arrays.cheevos_username, rcheevos_locals.token);
if (rcheevos_locals.richpresence.evaluation[0])
{
char* tmp = NULL;
net_http_urlencode(&tmp, rcheevos_locals.richpresence.evaluation);
snprintf(post_data, sizeof(post_data), "g=%u&m=%s", rcheevos_locals.patchdata.game_id, tmp);
CHEEVOS_FREE(tmp);
#ifdef HAVE_DISCORD
if (settings->bools.discord_enable)
discord_update(DISCORD_PRESENCE_RETROACHIEVEMENTS,
false);
if (settings->bools.discord_enable)
discord_update(DISCORD_PRESENCE_RETROACHIEVEMENTS, false);
#endif
}
else
{
snprintf(post_data, sizeof(post_data), "g=%u", rcheevos_locals.patchdata.game_id);
}
task_push_http_post_transfer(url, post_data, true, "POST", NULL, NULL);
rcheevos_get_user_agent(user_agent);
task_push_http_post_transfer_with_user_agent(url, post_data, true, "POST", user_agent, NULL, NULL);
}
}
@ -1370,8 +1325,7 @@ void rcheevos_test(void)
!rcheevos_hardcore_paused)
rcheevos_test_leaderboards();
if (settings->bools.cheevos_richpresence_enable)
rcheevos_test_richpresence();
rcheevos_test_richpresence();
}
}
@ -2525,6 +2479,10 @@ found:
if (!path_is_directory(coro->badge_fullpath))
path_mkdir(coro->badge_fullpath);
CORO_YIELD();
if (!coro->cheevo->info->badge || !coro->cheevo->info->badge[0])
continue;
if (coro->j == 0)
snprintf(coro->badge_name,
sizeof(coro->badge_name),

View File

@ -3,6 +3,7 @@
#include "hash.h"
#include "util.h"
#include <encodings/utf.h>
#include <formats/jsonsax.h>
#include <string/stdstring.h>
#include <compat/strl.h>
@ -263,6 +264,7 @@ typedef struct
int in_cheevos;
int in_lboards;
int is_game_id;
int is_title;
int is_console_id;
int is_richpresence;
unsigned core_count;
@ -276,16 +278,77 @@ typedef struct
rcheevos_rapatchdata_t* patchdata;
} rcheevos_readud_t;
static const char* rcheevos_dupstr(const rcheevos_field_t* field)
static char* rcheevos_unescape_string(const char* string, size_t length)
{
char* string = (char*)malloc(field->length + 1);
const char* end = string + length;
char* buffer = (char*)malloc(length + 1);
char* buffer_it = buffer;
if (!string)
if (buffer == NULL)
return NULL;
memcpy((void*)string, (void*)field->string, field->length);
string[field->length] = 0;
return string;
while (string < end)
{
if (*string == '\\')
{
char escaped_char = string[1];
switch (escaped_char)
{
case 'r': /* Ignore carriage return */
string += 2;
break;
case 'n': /* Accept newlines */
*buffer_it++ = '\n';
string += 2;
break;
case 'u': /* Accept UTF-16 unicode characters */
{
#define MAX_SEQUENCES 16
uint16_t utf16[MAX_SEQUENCES];
char utf8[MAX_SEQUENCES * 4];
uint8_t i, j;
for (i = 1; i < MAX_SEQUENCES - 1; i++)
if (strncmp((string + 6 * i), "\\u", 2))
break;
/* Get escaped hex values and add them to the string */
for (j = 0; j < i; j++)
{
char temp[5];
string += 2;
memcpy(temp, string, 4);
temp[4] = '\0';
utf16[j] = string_hex_to_unsigned(temp);
string += 4;
}
utf16[j] = 0;
if (utf16_to_char_string(utf16, utf8, sizeof(utf8)))
{
memcpy(buffer_it, utf8, strlen(utf8));
buffer_it += strlen(utf8);
}
}
break;
default:
*buffer_it++ = escaped_char;
string += 2;
break;
};
}
else
{
*buffer_it++ = *string++;
}
}
*buffer_it = '\0';
return buffer;
}
static int rcheevos_new_cheevo(rcheevos_readud_t* ud)
@ -300,10 +363,10 @@ static int rcheevos_new_cheevo(rcheevos_readud_t* ud)
else
return 0;
cheevo->title = rcheevos_dupstr(&ud->title);
cheevo->description = rcheevos_dupstr(&ud->desc);
cheevo->badge = rcheevos_dupstr(&ud->badge);
cheevo->memaddr = rcheevos_dupstr(&ud->memaddr);
cheevo->title = rcheevos_unescape_string(ud->title.string, ud->title.length);
cheevo->description = rcheevos_unescape_string(ud->desc.string, ud->desc.length);
cheevo->badge = rcheevos_unescape_string(ud->badge.string, ud->badge.length);
cheevo->memaddr = rcheevos_unescape_string(ud->memaddr.string, ud->memaddr.length);
cheevo->points = (unsigned)strtol(ud->points.string, NULL, 10);
cheevo->id = (unsigned)strtol(ud->id.string, NULL, 10);
@ -326,11 +389,11 @@ static int rcheevos_new_lboard(rcheevos_readud_t* ud)
{
rcheevos_ralboard_t* lboard = ud->patchdata->lboards + ud->lboard_count++;
lboard->title = rcheevos_dupstr(&ud->title);
lboard->description = rcheevos_dupstr(&ud->desc);
lboard->format = rcheevos_dupstr(&ud->format);
lboard->mem = rcheevos_dupstr(&ud->memaddr);
lboard->id = (unsigned)strtol(ud->id.string, NULL, 10);
lboard->title = rcheevos_unescape_string(ud->title.string, ud->title.length);
lboard->description = rcheevos_unescape_string(ud->desc.string, ud->desc.length);
lboard->format = rcheevos_unescape_string(ud->format.string, ud->format.length);
lboard->mem = rcheevos_unescape_string(ud->memaddr.string, ud->memaddr.length);
lboard->id = (unsigned)strtol(ud->id.string, NULL, 10);
if ( !lboard->title
|| !lboard->description
@ -409,6 +472,8 @@ static int rcheevos_read_key(void* userdata,
case CHEEVOS_JSON_KEY_TITLE:
if (common)
ud->field = &ud->title;
else
ud->is_title = 1;
break;
case CHEEVOS_JSON_KEY_DESCRIPTION:
if (common)
@ -459,11 +524,14 @@ static int rcheevos_read_string(void* userdata,
ud->field->string = string;
ud->field->length = length;
}
else if (ud->is_title)
{
ud->patchdata->title = rcheevos_unescape_string(string, length);
ud->is_title = 0;
}
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->patchdata->richpresence_script = rcheevos_unescape_string(string, length);
ud->is_richpresence = 0;
}
@ -544,10 +612,14 @@ int rcheevos_get_patchdata(const char* json, rcheevos_rapatchdata_t* patchdata)
return -1;
}
patchdata->richpresence_script = NULL;
patchdata->title = NULL;
/* Load the achievements. */
ud.in_cheevos = 0;
ud.in_lboards = 0;
ud.is_game_id = 0;
ud.is_title = 0;
ud.is_console_id = 0;
ud.is_richpresence = 0;
ud.field = NULL;
@ -609,6 +681,7 @@ void rcheevos_free_patchdata(rcheevos_rapatchdata_t* patchdata)
CHEEVOS_FREE(patchdata->unofficial);
CHEEVOS_FREE(patchdata->lboards);
CHEEVOS_FREE(patchdata->richpresence_script);
CHEEVOS_FREE(patchdata->title);
patchdata->game_id = 0;
patchdata->console_id = 0;

View File

@ -44,6 +44,7 @@ typedef struct {
typedef struct {
unsigned game_id;
unsigned console_id;
char* title;
rcheevos_racheevo_t* core;
rcheevos_racheevo_t* unofficial;

View File

@ -1583,7 +1583,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_richpresence_enable", &settings->bools.cheevos_richpresence_enable, true, true, 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

View File

@ -15419,7 +15419,7 @@ static bool setting_append_list(
&settings->bools.cheevos_richpresence_enable,
MENU_ENUM_LABEL_CHEEVOS_RICHPRESENCE_ENABLE,
MENU_ENUM_LABEL_VALUE_CHEEVOS_RICHPRESENCE_ENABLE,
false,
true,
MENU_ENUM_LABEL_VALUE_OFF,
MENU_ENUM_LABEL_VALUE_ON,
&group_info,

View File

@ -393,6 +393,27 @@ void* task_push_http_post_transfer(const char *url,
url, mute, type, cb, user_data);
}
void* task_push_http_post_transfer_with_user_agent(const char *url,
const char *post_data, bool mute,
const char *type, const char* user_agent,
retro_task_callback_t cb, void *user_data)
{
struct http_connection_t* conn;
if (string_is_empty(url))
return NULL;
conn = net_http_connection_new(url, "POST", post_data);
if (!conn)
return NULL;
if (user_agent != NULL)
net_http_connection_set_user_agent(conn, user_agent);
/* assert: task_push_http_transfer_generic will free conn on failure */
return task_push_http_transfer_generic(conn, url, mute, type, cb, user_data);
}
task_retriever_info_t *http_task_get_transfer_list(void)
{
task_retriever_data_t retrieve_data;

View File

@ -76,6 +76,9 @@ void *task_push_http_transfer_with_user_agent(const char *url, bool mute, const
void *task_push_http_post_transfer(const char *url, const char *post_data, bool mute, const char *type,
retro_task_callback_t cb, void *userdata);
void *task_push_http_post_transfer_with_user_agent(const char* url, const char* post_data, bool mute,
const char* type, const char* user_agent, retro_task_callback_t cb, void* user_data);
task_retriever_info_t *http_task_get_transfer_list(void);
bool task_push_wifi_scan(retro_task_callback_t cb);