(Cheevos) Style nits:

* single line code blocks - remove brackets
* Try to fit lines into 80 chars
* Etc
This commit is contained in:
twinaphex 2021-11-01 18:38:56 +01:00
parent b9df71b9d5
commit 05ca465aab
3 changed files with 526 additions and 408 deletions

View File

@ -119,25 +119,29 @@ void rcheevos_log(const char *fmt, ...)
#endif
static void rcheevos_achievement_disabled(rcheevos_racheevo_t* cheevo, unsigned address)
static void rcheevos_achievement_disabled(
rcheevos_racheevo_t* cheevo, unsigned address)
{
if (!cheevo)
return;
CHEEVOS_ERR(RCHEEVOS_TAG "Achievement %u disabled (invalid address %06X): %s\n",
cheevo->id, address, cheevo->title);
CHEEVOS_ERR(RCHEEVOS_TAG
"Achievement %u disabled (invalid address %06X): %s\n",
cheevo->id, address, cheevo->title);
CHEEVOS_FREE(cheevo->memaddr);
cheevo->memaddr = NULL;
cheevo->active |= RCHEEVOS_ACTIVE_UNSUPPORTED;
}
static void rcheevos_lboard_disabled(rcheevos_ralboard_t* lboard, unsigned address)
static void rcheevos_lboard_disabled(
rcheevos_ralboard_t* lboard, unsigned address)
{
if (!lboard)
return;
CHEEVOS_ERR(RCHEEVOS_TAG "Leaderboard %u disabled (invalid address %06X): %s\n",
lboard->id, address, lboard->title);
CHEEVOS_ERR(RCHEEVOS_TAG
"Leaderboard %u disabled (invalid address %06X): %s\n",
lboard->id, address, lboard->title);
CHEEVOS_FREE(lboard->mem);
lboard->mem = NULL;
}
@ -147,7 +151,8 @@ static void rcheevos_handle_log_message(const char* message)
CHEEVOS_LOG(RCHEEVOS_TAG "%s\n", message);
}
static void rcheevos_get_core_memory_info(unsigned id, rc_libretro_core_memory_info_t* info)
static void rcheevos_get_core_memory_info(unsigned id,
rc_libretro_core_memory_info_t* info)
{
retro_ctx_memory_info_t ctx_info;
if (!info)
@ -180,9 +185,11 @@ static int rcheevos_init_memory(rcheevos_locals_t* locals)
mmap.descriptors = &descriptors[0];
mmap.num_descriptors = mmaps->num_descriptors;
/* RetroArch wraps the retro_memory_descriptor's in rarch_memory_descriptor_t's, pull them back out */
/* RetroArch wraps the retro_memory_descriptor's
* in rarch_memory_descriptor_t's, pull them back out */
for (i = 0; i < mmap.num_descriptors; ++i)
memcpy(&descriptors[i], &mmaps->descriptors[i].core, sizeof(descriptors[0]));
memcpy(&descriptors[i], &mmaps->descriptors[i].core,
sizeof(descriptors[0]));
rc_libretro_init_verbose_message_callback(rcheevos_handle_log_message);
result = rc_libretro_memory_init(&locals->memory, &mmap,
@ -194,18 +201,19 @@ static int rcheevos_init_memory(rcheevos_locals_t* locals)
uint8_t* rcheevos_patch_address(unsigned address)
{
/* Memory map was not previously initialized
* (no achievements for this game?), try now */
if (rcheevos_locals.memory.count == 0)
{
/* memory map was not previously initialized (no achievements for this game?) try now */
rcheevos_init_memory(&rcheevos_locals);
}
return rc_libretro_memory_find(&rcheevos_locals.memory, address);
}
static unsigned rcheevos_peek(unsigned address, unsigned num_bytes, void* ud)
static unsigned rcheevos_peek(unsigned address,
unsigned num_bytes, void* ud)
{
uint8_t* data = rc_libretro_memory_find(&rcheevos_locals.memory, address);
uint8_t* data = rc_libretro_memory_find(
&rcheevos_locals.memory, address);
if (data)
{
switch (num_bytes)
@ -227,12 +235,13 @@ static unsigned rcheevos_peek(unsigned address, unsigned num_bytes, void* ud)
static void rcheevos_activate_achievements(void)
{
unsigned i;
int result;
rcheevos_racheevo_t* achievement = rcheevos_locals.game.achievements;
settings_t* settings = config_get_ptr();
int result;
unsigned i;
for (i = 0; i < rcheevos_locals.game.achievement_count; i++, achievement++)
for (i = 0; i < rcheevos_locals.game.achievement_count;
i++, achievement++)
{
if ((achievement->active & (RCHEEVOS_ACTIVE_HARDCORE | RCHEEVOS_ACTIVE_SOFTCORE)) != 0)
{
@ -265,7 +274,8 @@ static void rcheevos_activate_achievements(void)
static rcheevos_racheevo_t* rcheevos_find_cheevo(unsigned id)
{
rcheevos_racheevo_t* cheevo = rcheevos_locals.game.achievements;
rcheevos_racheevo_t* stop = cheevo + rcheevos_locals.game.achievement_count;
rcheevos_racheevo_t* stop = cheevo
+ rcheevos_locals.game.achievement_count;
for(; cheevo < stop; ++cheevo)
{
@ -299,9 +309,7 @@ void rcheevos_award_achievement(rcheevos_locals_t* locals,
/* Show the on screen message. */
#if defined(HAVE_GFX_WIDGETS)
if (widgets_ready)
{
gfx_widgets_push_achievement(cheevo->title, cheevo->badge);
}
else
#endif
{
@ -314,19 +322,20 @@ void rcheevos_award_achievement(rcheevos_locals_t* locals,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
/* Start the award task (unofficial achievement unlocks are not submitted). */
/* Start the award task (unofficial achievement
* unlocks are not submitted). */
if (!(cheevo->active & RCHEEVOS_ACTIVE_UNOFFICIAL))
rcheevos_client_award_achievement(cheevo->id);
/* play the unlock sound */
#ifdef HAVE_AUDIOMIXER
/* Play the unlock sound */
if (settings->bools.cheevos_unlock_sound_enable)
audio_driver_mixer_play_menu_sound(
AUDIO_MIXER_SYSTEM_SLOT_ACHIEVEMENT_UNLOCK);
#endif
/* Take a screenshot of the achievement. */
#ifdef HAVE_SCREENSHOTS
/* Take a screenshot of the achievement. */
if (settings->bools.cheevos_auto_screenshot)
{
size_t shotname_len = sizeof(char) * 8192;
@ -344,10 +353,12 @@ void rcheevos_award_achievement(rcheevos_locals_t* locals,
shotname, true,
video_driver_cached_frame_has_valid_framebuffer(),
false, true))
CHEEVOS_LOG(RCHEEVOS_TAG "Captured screenshot for achievement %u\n",
CHEEVOS_LOG(RCHEEVOS_TAG
"Captured screenshot for achievement %u\n",
cheevo->id);
else
CHEEVOS_LOG(RCHEEVOS_TAG "Failed to capture screenshot for achievement %u\n",
CHEEVOS_LOG(RCHEEVOS_TAG
"Failed to capture screenshot for achievement %u\n",
cheevo->id);
free(shotname);
@ -359,7 +370,8 @@ void rcheevos_award_achievement(rcheevos_locals_t* locals,
static rcheevos_ralboard_t* rcheevos_find_lboard(unsigned id)
{
rcheevos_ralboard_t* lboard = rcheevos_locals.game.leaderboards;
rcheevos_ralboard_t* stop = lboard + rcheevos_locals.game.leaderboard_count;
rcheevos_ralboard_t* stop = lboard
+ rcheevos_locals.game.leaderboard_count;
for (; lboard < stop; ++lboard)
{
@ -376,7 +388,8 @@ static void rcheevos_lboard_submit(rcheevos_locals_t* locals,
char buffer[256];
char formatted_value[16];
rc_runtime_format_lboard_value(formatted_value, sizeof(formatted_value),
rc_runtime_format_lboard_value(formatted_value,
sizeof(formatted_value),
value, lboard->format);
CHEEVOS_LOG(RCHEEVOS_TAG "Submitting %s for leaderboard %u\n",
formatted_value, lboard->id);
@ -417,11 +430,12 @@ static void rcheevos_lboard_canceled(rcheevos_ralboard_t * lboard,
snprintf(buffer, sizeof(buffer),
"Leaderboard attempt failed: %s", lboard->title);
runloop_msg_queue_push(buffer, 0, 2 * 60, false, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
}
static void rcheevos_lboard_started(rcheevos_ralboard_t * lboard, int value,
static void rcheevos_lboard_started(
rcheevos_ralboard_t * lboard, int value,
bool widgets_ready)
{
char buffer[256];
@ -434,7 +448,8 @@ static void rcheevos_lboard_started(rcheevos_ralboard_t * lboard, int value,
#if defined(HAVE_GFX_WIDGETS)
if (widgets_ready && rcheevos_locals.leaderboard_trackers)
{
rc_runtime_format_lboard_value(buffer, sizeof(buffer), value, lboard->format);
rc_runtime_format_lboard_value(buffer,
sizeof(buffer), value, lboard->format);
gfx_widgets_set_leaderboard_display(lboard->id, buffer);
}
#endif
@ -451,13 +466,13 @@ static void rcheevos_lboard_started(rcheevos_ralboard_t * lboard, int value,
lboard->title);
runloop_msg_queue_push(buffer, 0, 2 * 60, false, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
}
#if defined(HAVE_GFX_WIDGETS)
static void rcheevos_lboard_updated(rcheevos_ralboard_t* lboard, int value,
static void rcheevos_lboard_updated(
rcheevos_ralboard_t* lboard, int value,
bool widgets_ready)
{
if (!lboard)
@ -466,20 +481,25 @@ static void rcheevos_lboard_updated(rcheevos_ralboard_t* lboard, int value,
if (widgets_ready && rcheevos_locals.leaderboard_trackers)
{
char buffer[32];
rc_runtime_format_lboard_value(buffer, sizeof(buffer), value, lboard->format);
rc_runtime_format_lboard_value(buffer,
sizeof(buffer), value, lboard->format);
gfx_widgets_set_leaderboard_display(lboard->id, buffer);
}
}
static void rcheevos_challenge_started(rcheevos_racheevo_t* cheevo, int value,
static void rcheevos_challenge_started(
rcheevos_racheevo_t* cheevo, int value,
bool widgets_ready)
{
settings_t* settings = config_get_ptr();
if (cheevo && widgets_ready && settings->bools.cheevos_challenge_indicators)
if ( cheevo
&& widgets_ready
&& settings->bools.cheevos_challenge_indicators)
gfx_widgets_set_challenge_display(cheevo->id, cheevo->badge);
}
static void rcheevos_challenge_ended(rcheevos_racheevo_t* cheevo, int value,
static void rcheevos_challenge_ended(
rcheevos_racheevo_t* cheevo, int value,
bool widgets_ready)
{
if (cheevo && widgets_ready)
@ -490,11 +510,12 @@ static void rcheevos_challenge_ended(rcheevos_racheevo_t* cheevo, int value,
int rcheevos_get_richpresence(char buffer[], int buffer_size)
{
int ret = rc_runtime_get_richpresence(&rcheevos_locals.runtime, buffer, buffer_size, &rcheevos_peek, NULL, NULL);
int ret = rc_runtime_get_richpresence(
&rcheevos_locals.runtime, buffer, buffer_size,
&rcheevos_peek, NULL, NULL);
if (ret <= 0 && rcheevos_locals.game.title)
ret = snprintf(buffer, buffer_size, "Playing %s", rcheevos_locals.game.title);
return snprintf(buffer, buffer_size, "Playing %s", rcheevos_locals.game.title);
return ret;
}
@ -504,16 +525,15 @@ void rcheevos_reset_game(bool widgets_ready)
/* Hide any visible trackers */
if (widgets_ready)
{
rcheevos_ralboard_t* lboard;
rcheevos_racheevo_t* cheevo;
unsigned i;
lboard = rcheevos_locals.game.leaderboards;
for (i = 0; i < rcheevos_locals.game.leaderboard_count; ++i, ++lboard)
rcheevos_racheevo_t* cheevo;
rcheevos_ralboard_t* lboard = rcheevos_locals.game.leaderboards;
for (i = 0; i < rcheevos_locals.game.leaderboard_count;
++i, ++lboard)
gfx_widgets_set_leaderboard_display(lboard->id, NULL);
cheevo = rcheevos_locals.game.achievements;
for (i = 0; i < rcheevos_locals.game.achievement_count; ++i, ++cheevo)
for (i = 0; i < rcheevos_locals.game.achievement_count;
++i, ++cheevo)
gfx_widgets_set_challenge_display(cheevo->id, NULL);
}
#endif
@ -541,8 +561,7 @@ void rcheevos_pause_hardcore(void)
static bool rcheevos_timer_check(void* userdata)
{
retro_time_t stop_time = *(retro_time_t*)userdata;
retro_time_t now = cpu_features_get_time_usec();
retro_time_t now = cpu_features_get_time_usec();
return (now < stop_time);
}
#endif
@ -561,8 +580,10 @@ bool rcheevos_unload(void)
rcheevos_locals.load_info.state = RCHEEVOS_LOAD_STATE_ABORTED;
CHEEVOS_LOG(RCHEEVOS_TAG "Asked the load tasks to terminate\n");
task_queue_wait(rcheevos_timer_check, &stop_time); /* wait for pending tasks to run */
task_queue_check(); /* clean up after completed tasks */
/* Wait for pending tasks to run */
task_queue_wait(rcheevos_timer_check, &stop_time);
/* Clean up after completed tasks */
task_queue_check();
}
rcheevos_locals.queued_command = CMD_EVENT_NONE;
@ -579,15 +600,16 @@ bool rcheevos_unload(void)
if (rcheevos_locals.menuitems)
{
CHEEVOS_FREE(rcheevos_locals.menuitems);
rcheevos_locals.menuitems = NULL;
rcheevos_locals.menuitem_capacity = rcheevos_locals.menuitem_count = 0;
rcheevos_locals.menuitems = NULL;
rcheevos_locals.menuitem_capacity =
rcheevos_locals.menuitem_count = 0;
}
#endif
if (rcheevos_locals.game.title)
{
CHEEVOS_FREE(rcheevos_locals.game.title);
rcheevos_locals.game.title = NULL;
rcheevos_locals.game.title = NULL;
}
rcheevos_locals.loaded = false;
@ -609,12 +631,13 @@ bool rcheevos_unload(void)
return true;
}
static void rcheevos_toggle_hardcore_achievements(rcheevos_locals_t *locals)
static void rcheevos_toggle_hardcore_achievements(
rcheevos_locals_t *locals)
{
const unsigned active_mask =
const unsigned active_mask =
RCHEEVOS_ACTIVE_SOFTCORE | RCHEEVOS_ACTIVE_HARDCORE | RCHEEVOS_ACTIVE_UNSUPPORTED;
rcheevos_racheevo_t* cheevo = locals->game.achievements;
rcheevos_racheevo_t* stop = cheevo + locals->game.achievement_count;
rcheevos_racheevo_t* stop = cheevo + locals->game.achievement_count;
while (cheevo < stop)
{
@ -640,17 +663,20 @@ static void rcheevos_toggle_hardcore_achievements(rcheevos_locals_t *locals)
static void rcheevos_activate_leaderboards(void)
{
rcheevos_ralboard_t* leaderboard = rcheevos_locals.game.leaderboards;
const settings_t* settings = config_get_ptr();
unsigned i;
int result;
rcheevos_ralboard_t* leaderboard = rcheevos_locals.game.leaderboards;
const settings_t *settings = config_get_ptr();
for (i = 0; i < rcheevos_locals.game.leaderboard_count; ++i, ++leaderboard)
for (i = 0; i < rcheevos_locals.game.leaderboard_count;
++i, ++leaderboard)
{
if (!leaderboard->mem)
continue;
result = rc_runtime_activate_lboard(&rcheevos_locals.runtime, leaderboard->id, leaderboard->mem, NULL, 0);
result = rc_runtime_activate_lboard(
&rcheevos_locals.runtime, leaderboard->id,
leaderboard->mem, NULL, 0);
if (result != RC_OK)
{
char buffer[256];
@ -673,13 +699,15 @@ static void rcheevos_activate_leaderboards(void)
static void rcheevos_deactivate_leaderboards()
{
rcheevos_ralboard_t* lboard = rcheevos_locals.game.leaderboards;
rcheevos_ralboard_t* stop = lboard + rcheevos_locals.game.leaderboard_count;
rcheevos_ralboard_t* stop = lboard +
rcheevos_locals.game.leaderboard_count;
for (; lboard < stop; ++lboard)
{
if (lboard->mem)
{
rc_runtime_deactivate_lboard(&rcheevos_locals.runtime, lboard->id);
rc_runtime_deactivate_lboard(&rcheevos_locals.runtime,
lboard->id);
#if defined(HAVE_GFX_WIDGETS)
/* Hide any visible trackers */
@ -774,7 +802,8 @@ static void rcheevos_toggle_hardcore_active(rcheevos_locals_t* locals)
if (locals->loaded)
{
const char* msg = msg_hash_to_str(MSG_CHEEVOS_HARDCORE_MODE_ENABLE);
const char* msg = msg_hash_to_str(
MSG_CHEEVOS_HARDCORE_MODE_ENABLE);
CHEEVOS_LOG("%s\n", msg);
runloop_msg_queue_push(msg, 0, 3 * 60, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
@ -867,7 +896,8 @@ void rcheevos_validate_config_settings(void)
if (!system->library_name || !rcheevos_locals.hardcore_active)
return;
if (!(disallowed_settings = rc_libretro_get_disallowed_settings(system->library_name)))
if (!(disallowed_settings
= rc_libretro_get_disallowed_settings(system->library_name)))
return;
if (!retroarch_ctl(RARCH_CTL_CORE_OPTIONS_LIST_GET, &coreopts))
@ -880,7 +910,8 @@ void rcheevos_validate_config_settings(void)
if (!rc_libretro_is_setting_allowed(disallowed_settings, key, val))
{
char buffer[256];
snprintf(buffer, sizeof(buffer), "Hardcore paused. Setting not allowed: %s=%s", key, val);
snprintf(buffer, sizeof(buffer),
"Hardcore paused. Setting not allowed: %s=%s", key, val);
CHEEVOS_LOG(RCHEEVOS_TAG "%s\n", buffer);
rcheevos_pause_hardcore();
@ -892,7 +923,8 @@ void rcheevos_validate_config_settings(void)
}
}
static void rcheevos_runtime_event_handler(const rc_runtime_event_t* runtime_event)
static void rcheevos_runtime_event_handler(
const rc_runtime_event_t* runtime_event)
{
#if defined(HAVE_GFX_WIDGETS)
bool widgets_ready = gfx_widgets_ready();
@ -904,41 +936,59 @@ static void rcheevos_runtime_event_handler(const rc_runtime_event_t* runtime_eve
{
#if defined(HAVE_GFX_WIDGETS)
case RC_RUNTIME_EVENT_LBOARD_UPDATED:
rcheevos_lboard_updated(rcheevos_find_lboard(runtime_event->id), runtime_event->value, widgets_ready);
rcheevos_lboard_updated(
rcheevos_find_lboard(runtime_event->id),
runtime_event->value, widgets_ready);
break;
case RC_RUNTIME_EVENT_ACHIEVEMENT_PRIMED:
rcheevos_challenge_started(rcheevos_find_cheevo(runtime_event->id), runtime_event->value, widgets_ready);
rcheevos_challenge_started(
rcheevos_find_cheevo(runtime_event->id),
runtime_event->value, widgets_ready);
break;
case RC_RUNTIME_EVENT_ACHIEVEMENT_UNPRIMED:
rcheevos_challenge_ended(rcheevos_find_cheevo(runtime_event->id), runtime_event->value, widgets_ready);
rcheevos_challenge_ended(
rcheevos_find_cheevo(runtime_event->id),
runtime_event->value, widgets_ready);
break;
#endif
case RC_RUNTIME_EVENT_ACHIEVEMENT_TRIGGERED:
rcheevos_award_achievement(&rcheevos_locals, rcheevos_find_cheevo(runtime_event->id), widgets_ready);
rcheevos_award_achievement(
&rcheevos_locals,
rcheevos_find_cheevo(runtime_event->id), widgets_ready);
break;
case RC_RUNTIME_EVENT_LBOARD_STARTED:
rcheevos_lboard_started(rcheevos_find_lboard(runtime_event->id), runtime_event->value, widgets_ready);
rcheevos_lboard_started(
rcheevos_find_lboard(runtime_event->id),
runtime_event->value, widgets_ready);
break;
case RC_RUNTIME_EVENT_LBOARD_CANCELED:
rcheevos_lboard_canceled(rcheevos_find_lboard(runtime_event->id),
rcheevos_lboard_canceled(
rcheevos_find_lboard(runtime_event->id),
widgets_ready);
break;
case RC_RUNTIME_EVENT_LBOARD_TRIGGERED:
rcheevos_lboard_submit(&rcheevos_locals, rcheevos_find_lboard(runtime_event->id), runtime_event->value, widgets_ready);
rcheevos_lboard_submit(
&rcheevos_locals,
rcheevos_find_lboard(runtime_event->id),
runtime_event->value, widgets_ready);
break;
case RC_RUNTIME_EVENT_ACHIEVEMENT_DISABLED:
rcheevos_achievement_disabled(rcheevos_find_cheevo(runtime_event->id), runtime_event->value);
rcheevos_achievement_disabled(
rcheevos_find_cheevo(runtime_event->id),
runtime_event->value);
break;
case RC_RUNTIME_EVENT_LBOARD_DISABLED:
rcheevos_lboard_disabled(rcheevos_find_lboard(runtime_event->id), runtime_event->value);
rcheevos_lboard_disabled(
rcheevos_find_lboard(runtime_event->id),
runtime_event->value);
break;
default:
@ -948,7 +998,8 @@ static void rcheevos_runtime_event_handler(const rc_runtime_event_t* runtime_eve
static int rcheevos_runtime_address_validator(unsigned address)
{
return (rc_libretro_memory_find(&rcheevos_locals.memory, address) != NULL);
return rc_libretro_memory_find(
&rcheevos_locals.memory, address) != NULL;
}
static void rcheevos_validate_memrefs(rcheevos_locals_t* locals)
@ -959,11 +1010,13 @@ static void rcheevos_validate_memrefs(rcheevos_locals_t* locals)
* first call to retro_run. in that case, there will be a total_size
* of memory reported by the core, but init will return false, as
* all of the pointers were null. if we're still loading the game,
* just reset the memory count and we'll re-evaluate in rcheevos_test()
* just reset the memory count and we'll re-evaluate in
* rcheevos_test()
*/
if (!locals->loaded)
{
/* if no memory was exposed, report the error now instead of waiting */
/* If no memory was exposed, report the error now
* instead of waiting */
if (locals->memory.total_size != 0)
{
locals->memory.count = 0;
@ -977,10 +1030,9 @@ static void rcheevos_validate_memrefs(rcheevos_locals_t* locals)
CHEEVOS_ERR(RCHEEVOS_TAG "No memory exposed by core\n");
if (settings && settings->bools.cheevos_verbose_enable)
{
runloop_msg_queue_push(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CANNOT_ACTIVATE_ACHIEVEMENTS_WITH_THIS_CORE),
0, 4 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_WARNING);
}
0, 4 * 60, false, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_WARNING);
rcheevos_unload();
rcheevos_pause_hardcore();
@ -988,7 +1040,8 @@ static void rcheevos_validate_memrefs(rcheevos_locals_t* locals)
}
rc_runtime_validate_addresses(&locals->runtime,
rcheevos_runtime_event_handler, rcheevos_runtime_address_validator);
rcheevos_runtime_event_handler,
rcheevos_runtime_address_validator);
}
/*****************************************************************************
@ -1007,13 +1060,12 @@ void rcheevos_test(void)
if (!rcheevos_locals.loaded)
return;
/* We were unable to initialize memory earlier, try now */
if (rcheevos_locals.memory.count == 0)
{
/* we were unable to initialize memory earlier, try now */
rcheevos_validate_memrefs(&rcheevos_locals);
}
rc_runtime_do_frame(&rcheevos_locals.runtime, &rcheevos_runtime_event_handler, rcheevos_peek, NULL, 0);
rc_runtime_do_frame(&rcheevos_locals.runtime,
&rcheevos_runtime_event_handler, rcheevos_peek, NULL, 0);
}
size_t rcheevos_get_serialize_size(void)
@ -1027,14 +1079,17 @@ bool rcheevos_get_serialized_data(void* buffer)
{
if (!rcheevos_locals.loaded)
return false;
return (rc_runtime_serialize_progress(buffer, &rcheevos_locals.runtime, NULL) == RC_OK);
return (rc_runtime_serialize_progress(
buffer, &rcheevos_locals.runtime, NULL) == RC_OK);
}
bool rcheevos_set_serialized_data(void* buffer)
{
if (rcheevos_locals.loaded)
{
if (buffer && rc_runtime_deserialize_progress(&rcheevos_locals.runtime, (const unsigned char*)buffer, NULL) == RC_OK)
if (buffer && rc_runtime_deserialize_progress(
&rcheevos_locals.runtime,
(const unsigned char*)buffer, NULL) == RC_OK)
return true;
rc_runtime_reset(&rcheevos_locals.runtime);
@ -1062,10 +1117,12 @@ const char* rcheevos_get_hash(void)
static void* rc_hash_handle_file_open(const char* path)
{
return intfstream_open_file(path, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);
return intfstream_open_file(path,
RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);
}
static void rc_hash_handle_file_seek(void* file_handle, int64_t offset, int origin)
static void rc_hash_handle_file_seek(
void* file_handle, int64_t offset, int origin)
{
intfstream_seek((intfstream_t*)file_handle, offset, origin);
}
@ -1075,9 +1132,11 @@ static int64_t rc_hash_handle_file_tell(void* file_handle)
return intfstream_tell((intfstream_t*)file_handle);
}
static size_t rc_hash_handle_file_read(void* file_handle, void* buffer, size_t requested_bytes)
static size_t rc_hash_handle_file_read(
void* file_handle, void* buffer, size_t requested_bytes)
{
return intfstream_read((intfstream_t*)file_handle, buffer, requested_bytes);
return intfstream_read((intfstream_t*)file_handle,
buffer, requested_bytes);
}
static void rc_hash_handle_file_close(void* file_handle)
@ -1086,7 +1145,8 @@ static void rc_hash_handle_file_close(void* file_handle)
CHEEVOS_FREE(file_handle);
}
static void* rc_hash_handle_cd_open_track(const char* path, uint32_t track)
static void* rc_hash_handle_cd_open_track(
const char* path, uint32_t track)
{
cdfs_track_t* cdfs_track;
@ -1138,7 +1198,9 @@ static void* rc_hash_handle_cd_open_track(const char* path, uint32_t track)
return NULL;
}
static size_t rc_hash_handle_cd_read_sector(void* track_handle, uint32_t sector, void* buffer, size_t requested_bytes)
static size_t rc_hash_handle_cd_read_sector(
void* track_handle, uint32_t sector,
void* buffer, size_t requested_bytes)
{
cdfs_file_t* file = (cdfs_file_t*)track_handle;
@ -1161,14 +1223,15 @@ static void rc_hash_handle_cd_close_track(void* track_handle)
static void rcheevos_show_game_placard()
{
const settings_t* settings = config_get_ptr();
const rcheevos_racheevo_t* cheevo = rcheevos_locals.game.achievements;
const rcheevos_racheevo_t* end = cheevo + rcheevos_locals.game.achievement_count;
int number_of_active = 0;
int number_of_unsupported = 0;
int number_of_core = 0;
int mode = RCHEEVOS_ACTIVE_SOFTCORE;
char msg[256];
const settings_t* settings = config_get_ptr();
const rcheevos_racheevo_t* cheevo = rcheevos_locals.game.achievements;
const rcheevos_racheevo_t* end = cheevo
+ rcheevos_locals.game.achievement_count;
int number_of_active = 0;
int number_of_unsupported = 0;
int number_of_core = 0;
int mode = RCHEEVOS_ACTIVE_SOFTCORE;
if (rcheevos_locals.hardcore_active)
mode = RCHEEVOS_ACTIVE_HARDCORE;
@ -1186,39 +1249,29 @@ static void rcheevos_show_game_placard()
}
if (number_of_core == 0)
{
snprintf(msg, sizeof(msg), "This game has no achievements.");
}
else if (!number_of_unsupported)
{
if (settings->bools.cheevos_start_active)
{
snprintf(msg, sizeof(msg),
"All %d achievements activated for this session.",
number_of_core);
}
else
{
snprintf(msg, sizeof(msg),
"You have %d of %d achievements unlocked.",
number_of_core - number_of_active, number_of_core);
}
}
else
{
if (settings->bools.cheevos_start_active)
{
snprintf(msg, sizeof(msg),
"All %d achievements activated for this session (%d unsupported).",
number_of_core, number_of_unsupported);
}
else
{
snprintf(msg, sizeof(msg),
"You have %d of %d achievements unlocked (%d unsupported).",
number_of_core - number_of_active - number_of_unsupported,
number_of_core, number_of_unsupported);
}
}
msg[sizeof(msg) - 1] = 0;
@ -1241,7 +1294,8 @@ static void rcheevos_fetch_badges_callback(void* userdata)
static void rcheevos_fetch_badges(void)
{
/* this function manages the RCHEEVOS_LOAD_STATE_FETCHING_BADGES state */
/* this function manages the
* RCHEEVOS_LOAD_STATE_FETCHING_BADGES state */
rcheevos_client_fetch_badges(rcheevos_fetch_badges_callback, NULL);
}
@ -1253,12 +1307,13 @@ static void rcheevos_start_session(void)
return;
}
if (rcheevos_locals.game.achievement_count == 0 &&
rcheevos_locals.game.leaderboard_count == 0)
if ( rcheevos_locals.game.achievement_count == 0
&& rcheevos_locals.game.leaderboard_count == 0)
{
if (!rcheevos_locals.runtime.richpresence)
{
/* nothing for the runtime to process, disable hardcore and bail */
/* nothing for the runtime to process,
* disable hardcore and bail */
rcheevos_show_game_placard();
rcheevos_pause_hardcore();
return;
@ -1267,22 +1322,26 @@ static void rcheevos_start_session(void)
rcheevos_begin_load_state(RCHEEVOS_LOAD_STATE_STARTING_SESSION);
/* activate the achievements and leaderboards (rich presence has already been activated) */
/* activate the achievements and leaderboards
* (rich presence has already been activated) */
rcheevos_activate_achievements();
if (rcheevos_locals.leaderboards_enabled && rcheevos_locals.hardcore_active)
if ( rcheevos_locals.leaderboards_enabled
&& rcheevos_locals.hardcore_active)
rcheevos_activate_leaderboards();
#if HAVE_REWIND
if (!rcheevos_locals.hardcore_active)
{
/* re-enable rewind. if rcheevos_locals.loaded is true, additional space will be allocated
* for the achievement state data */
/* Re-enable rewind. If rcheevos_locals.loaded is true,
* additional space will be allocated for the achievement
* state data */
const settings_t* settings = config_get_ptr();
if (settings->bools.rewind_enable)
{
#ifdef HAVE_THREADS
/* have to "schedule" this. CMD_EVENT_REWIND_INIT should only be called on the main thread */
/* Have to "schedule" this. CMD_EVENT_REWIND_INIT should
* only be called on the main thread */
rcheevos_locals.queued_command = CMD_EVENT_REWIND_INIT;
#else
command_event(CMD_EVENT_REWIND_INIT, NULL);
@ -1291,12 +1350,13 @@ static void rcheevos_start_session(void)
}
#endif
/* we don't have to wait for this to complete to proceed to the next loading state */
/* We don't have to wait for this to complete
* to proceed to the next loading state */
rcheevos_client_start_session(rcheevos_locals.game.id);
rcheevos_validate_memrefs(&rcheevos_locals);
/* let the runtime start processing the achievements */
/* Let the runtime start processing the achievements */
rcheevos_locals.loaded = true;
rcheevos_show_game_placard();
@ -1312,7 +1372,8 @@ static void rcheevos_initialize_runtime_callback(void* userdata)
static void rcheevos_fetch_game_data(void)
{
if (rcheevos_locals.load_info.state == RCHEEVOS_LOAD_STATE_NETWORK_ERROR)
if ( rcheevos_locals.load_info.state
== RCHEEVOS_LOAD_STATE_NETWORK_ERROR)
{
strlcpy(rcheevos_locals.game.hash,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE),
@ -1325,19 +1386,15 @@ static void rcheevos_fetch_game_data(void)
{
const settings_t* settings = config_get_ptr();
if (settings->bools.cheevos_verbose_enable)
{
runloop_msg_queue_push(
"This game has no achievements.",
0, 3 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
CHEEVOS_LOG(RCHEEVOS_TAG "Game could not be identified\n");
if (rcheevos_locals.load_info.hashes_tried > 1)
{
strlcpy(rcheevos_locals.game.hash,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE),
sizeof(rcheevos_locals.game.hash));
}
rcheevos_locals.load_info.state = RCHEEVOS_LOAD_STATE_UNKNOWN_GAME;
rcheevos_pause_hardcore();
@ -1367,9 +1424,7 @@ static void rcheevos_fetch_game_data(void)
/* wait for rewind to be disabled */
while (rcheevos_locals.queued_command != CMD_EVENT_NONE)
{
retro_sleep(1);
}
#else
command_event(CMD_EVENT_REWIND_DEINIT, NULL);
#endif
@ -1391,14 +1446,18 @@ struct rcheevos_identify_game_data
static void rcheevos_identify_game_callback(void* userdata)
{
struct rcheevos_identify_game_data* data = (struct rcheevos_identify_game_data*)userdata;
struct rcheevos_identify_game_data* data =
(struct rcheevos_identify_game_data*)userdata;
if (data)
{
/* previous hash didn't match, try the next one */
char hash[33];
if (rcheevos_locals.game.id == 0 && rc_hash_iterate(hash, &data->iterator))
if ( rcheevos_locals.game.id == 0
&& rc_hash_iterate(hash, &data->iterator))
{
rcheevos_client_identify_game(hash, rcheevos_identify_game_callback, data);
rcheevos_client_identify_game(hash,
rcheevos_identify_game_callback, data);
return;
}
@ -1420,25 +1479,29 @@ static bool rcheevos_identify_game(const struct retro_game_info* info)
size_t len;
char hash[33];
rc_hash_initialize_iterator(&iterator, info->path, (uint8_t*)info->data, info->size);
rc_hash_initialize_iterator(&iterator,
info->path, (uint8_t*)info->data, info->size);
if (!rc_hash_iterate(hash, &iterator))
{
CHEEVOS_LOG(RCHEEVOS_TAG "no hashes generated\n");
return false;
}
strlcpy(rcheevos_locals.game.hash, hash, sizeof(rcheevos_locals.game.hash));
strlcpy(rcheevos_locals.game.hash, hash,
sizeof(rcheevos_locals.game.hash));
rcheevos_locals.load_info.hashes_tried++;
if (iterator.consoles[iterator.index] == 0)
{
/* no more potential matches, just try the one hash */
rcheevos_client_identify_game(hash, rcheevos_identify_game_callback, NULL);
rcheevos_client_identify_game(hash,
rcheevos_identify_game_callback, NULL);
return true;
}
/* multiple potential matches, clone the data for the next attempt */
data = (struct rcheevos_identify_game_data*)calloc(1, sizeof(struct rcheevos_identify_game_data));
data = (struct rcheevos_identify_game_data*)
calloc(1, sizeof(struct rcheevos_identify_game_data));
if (!data)
{
CHEEVOS_LOG(RCHEEVOS_TAG "allocation failed\n");
@ -1463,7 +1526,8 @@ static bool rcheevos_identify_game(const struct retro_game_info* info)
}
memcpy(&data->iterator, &iterator, sizeof(iterator));
rcheevos_client_identify_game(hash, rcheevos_identify_game_callback, data);
rcheevos_client_identify_game(hash,
rcheevos_identify_game_callback, data);
return true;
}
@ -1478,7 +1542,8 @@ static void rcheevos_login_callback(void* userdata)
snprintf(msg, sizeof(msg),
"RetroAchievements: Logged in as \"%s\".",
rcheevos_locals.username);
runloop_msg_queue_push(msg, 0, 2 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
runloop_msg_queue_push(msg, 0, 2 * 60, false, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
}
@ -1486,7 +1551,7 @@ static void rcheevos_login_callback(void* userdata)
rcheevos_fetch_game_data();
}
/* increment the outstanding requests counter and set the load state */
/* Increment the outstanding requests counter and set the load state */
void rcheevos_begin_load_state(enum rcheevos_load_state state)
{
CHEEVOS_LOCK(rcheevos_locals.load_info.request_lock);
@ -1495,7 +1560,8 @@ void rcheevos_begin_load_state(enum rcheevos_load_state state)
CHEEVOS_UNLOCK(rcheevos_locals.load_info.request_lock);
}
/* decrement and return the outstanding requests counter. if non-zero, requests are still outstanding */
/* Decrement and return the outstanding requests counter.
* If non-zero, requests are still outstanding */
int rcheevos_end_load_state(void)
{
int requests = 0;
@ -1513,25 +1579,32 @@ bool rcheevos_load_aborted(void)
{
switch (rcheevos_locals.load_info.state)
{
case RCHEEVOS_LOAD_STATE_ABORTED: /* unload has been called */
case RCHEEVOS_LOAD_STATE_NONE: /* unload quit waiting and ran to completion */
case RCHEEVOS_LOAD_STATE_NETWORK_ERROR: /* login/resolve hash failed after several attempts */
/* Unload has been called */
case RCHEEVOS_LOAD_STATE_ABORTED:
/* Unload quit waiting and ran to completion */
case RCHEEVOS_LOAD_STATE_NONE:
/* Login/resolve hash failed after several attempts */
case RCHEEVOS_LOAD_STATE_NETWORK_ERROR:
return true;
default:
return false;
break;
}
return false;
}
bool rcheevos_load(const void *data)
{
const struct retro_game_info *info = (const struct retro_game_info*)data;
settings_t *settings = config_get_ptr();
bool cheevos_enable = settings && settings->bools.cheevos_enable;
struct rc_hash_filereader filereader;
struct rc_hash_cdreader cdreader;
struct rc_hash_filereader filereader;
const struct retro_game_info *info = (const struct retro_game_info*)
data;
settings_t *settings = config_get_ptr();
bool cheevos_enable = settings
&& settings->bools.cheevos_enable;
memset(&rcheevos_locals.load_info, 0,
sizeof(rcheevos_locals.load_info));
memset(&rcheevos_locals.load_info, 0, sizeof(rcheevos_locals.load_info));
rcheevos_locals.loaded = false;
rcheevos_locals.game.id = -1;
#ifdef HAVE_THREADS
@ -1539,8 +1612,8 @@ bool rcheevos_load(const void *data)
#endif
rc_runtime_init(&rcheevos_locals.runtime);
/* if achievements are not enabled, or the core doesn't support achievements,
* disable hardcore and bail */
/* If achievements are not enabled, or the core doesn't
* support achievements, disable hardcore and bail */
if (!cheevos_enable || !rcheevos_locals.core_supports || !data)
{
rcheevos_pause_hardcore();
@ -1575,14 +1648,15 @@ bool rcheevos_load(const void *data)
rc_hash_init_error_message_callback(rcheevos_handle_log_message);
#ifndef DEBUG /* in DEBUG mode, always initialize the verbose message handler */
#ifndef DEBUG
/* in DEBUG mode, always initialize the verbose message handler */
if (settings->bools.cheevos_verbose_enable)
#endif
{
rc_hash_init_verbose_message_callback(rcheevos_handle_log_message);
}
/* refresh the user agent in case it's not set or has changed */
/* Refresh the user agent in case it's not set or has changed */
rcheevos_client_initialize();
rcheevos_get_user_agent(&rcheevos_locals,
rcheevos_locals.user_agent_core,
@ -1614,10 +1688,12 @@ bool rcheevos_load(const void *data)
*/
/* identify the game and log the user in. these will run asynchronously. */
/* Identify the game and log the user in.
* These will run asynchronously. */
if (!rcheevos_identify_game(info))
{
/* no hashes could be generated for the game, disable hardcore and bail */
/* No hashes could be generated for the game,
* disable hardcore and bail */
rcheevos_end_load_state();
rcheevos_pause_hardcore();
return false;
@ -1630,15 +1706,19 @@ bool rcheevos_load(const void *data)
{
CHEEVOS_LOG(RCHEEVOS_TAG "Attempting to login %s (with password)\n",
settings->arrays.cheevos_username);
rcheevos_client_login_with_password(settings->arrays.cheevos_username,
settings->arrays.cheevos_password, rcheevos_login_callback, NULL);
rcheevos_client_login_with_password(
settings->arrays.cheevos_username,
settings->arrays.cheevos_password,
rcheevos_login_callback, NULL);
}
else
{
CHEEVOS_LOG(RCHEEVOS_TAG "Attempting to login %s (with token)\n",
settings->arrays.cheevos_username);
rcheevos_client_login_with_token(settings->arrays.cheevos_username,
settings->arrays.cheevos_token, rcheevos_login_callback, NULL);
rcheevos_client_login_with_token(
settings->arrays.cheevos_username,
settings->arrays.cheevos_token,
rcheevos_login_callback, NULL);
}
}

View File

@ -126,9 +126,7 @@ static int append_no_spaces(char* buffer, char* stop, const char* text)
++text;
}
else
{
*ptr++ = *text++;
}
}
*ptr = '\0';
@ -156,10 +154,8 @@ void rcheevos_get_user_agent(rcheevos_locals_t *locals,
"RetroArch/%s (%s %d.%d)", PACKAGE_VERSION, tmp, major, minor);
}
else
{
snprintf(locals->user_agent_prefix, sizeof(locals->user_agent_prefix),
"RetroArch/%s", PACKAGE_VERSION);
}
}
/* append the non-changing portion */
@ -179,9 +175,7 @@ void rcheevos_get_user_agent(rcheevos_locals_t *locals,
ptr += strlen(ptr);
}
else
{
ptr += append_no_spaces(ptr, stop, system->library_name);
}
if (system->library_version)
{
@ -287,18 +281,14 @@ static void rcheevos_log_post_url(const char* url, const char* post)
static void rcheevos_async_begin_http_request(rcheevos_async_io_request* request)
{
if (request->request.post_data == NULL)
{
task_push_http_transfer_with_user_agent(request->request.url,
true, "GET", request->user_agent,
rcheevos_async_http_task_callback, request);
}
else
{
if (request->request.post_data)
task_push_http_post_transfer_with_user_agent(request->request.url,
request->request.post_data, true, "POST", request->user_agent,
rcheevos_async_http_task_callback, request);
}
else
task_push_http_transfer_with_user_agent(request->request.url,
true, "GET", request->user_agent,
rcheevos_async_http_task_callback, request);
}
static void rcheevos_async_retry_request(retro_task_t* task)
@ -315,8 +305,7 @@ static void rcheevos_async_retry_request(retro_task_t* task)
static void rcheevos_async_retry_request_after_delay(rcheevos_async_io_request* request, const char* error)
{
retro_task_t* task = task_init();
retro_task_t* task = task_init();
/* Double the wait between each attempt until we hit
* a maximum delay of two minutes.
* 250ms -> 500ms -> 1s -> 2s -> 4s -> 8s -> 16s -> 32s -> 64s -> 120s -> 120s... */
@ -344,13 +333,16 @@ static bool rcheevos_async_request_failed(rcheevos_async_io_request* request, co
/* retry failed, don't retry these requests */
switch (request->type)
{
case CHEEVOS_ASYNC_RICHPRESENCE: /* timer will ping again */
case CHEEVOS_ASYNC_FETCH_BADGE: /* fallback to the placeholder image */
/* timer will ping again */
case CHEEVOS_ASYNC_RICHPRESENCE:
/* fallback to the placeholder image */
case CHEEVOS_ASYNC_FETCH_BADGE:
return false;
case CHEEVOS_ASYNC_RESOLVE_HASH:
case CHEEVOS_ASYNC_LOGIN:
/* make a maximum of four attempts (0ms -> 250ms -> 500ms -> 1s) */
/* make a maximum of four attempts
(0ms -> 250ms -> 500ms -> 1s) */
if (request->attempt_count == 3)
return false;
break;
@ -366,7 +358,8 @@ static bool rcheevos_async_request_failed(rcheevos_async_io_request* request, co
}
static void rcheevos_async_http_task_callback(
retro_task_t* task, void* task_data, void* user_data, const char* error)
retro_task_t* task, void* task_data, void* user_data,
const char* error)
{
rcheevos_async_io_request *request = (rcheevos_async_io_request*)user_data;
http_transfer_data_t *data = (http_transfer_data_t*)task_data;
@ -383,19 +376,14 @@ static void rcheevos_async_http_task_callback(
if (error)
{
/* there was a communication error */
/* automatically requeued, don't process any further */
if (rcheevos_async_request_failed(request, error))
{
/* automatically requeued, don't process any further */
return;
}
strlcpy(buffer, error, sizeof(buffer));
}
else if (!data)
{
/* Server did not return HTTP headers */
else if (!data) /* Server did not return HTTP headers */
strlcpy(buffer, "Server communication error", sizeof(buffer));
}
else if (!data->data || !data->len)
{
if (data->status <= 0)
@ -407,29 +395,22 @@ static void rcheevos_async_http_task_callback(
return;
}
if (data->status != 200)
{
/* Server returned an error via status code. */
if (data->status != 200) /* Server returned error via status code. */
snprintf(buffer, sizeof(buffer), "HTTP error code %d", data->status);
}
else
{
/* Server sent an empty response without an error status code */
else /* Server sent empty response without error status code */
strlcpy(buffer, "No response from server", sizeof(buffer));
}
}
else
{
buffer[0] = '\0'; /* indicate success unless handler provides error */
/* indicate success unless handler provides error */
buffer[0] = '\0';
/* Call appropriate handler to process the response */
/* NOTE: data->data is not null-terminated. Most handlers assume the
* response is properly formatted or will encounter a parse failure
* before reading past the end of the data */
if (request->handler)
{
/* NOTE: data->data is not null-terminated. Most handlers assume the
* response is properly formatted or will encounter a parse failure
* before reading past the end of the data */
request->handler(request, data, buffer, sizeof(buffer));
}
}
if (!buffer[0])
@ -469,19 +450,22 @@ static void rcheevos_async_http_task_callback(
size_t len = 0;
char* ptr;
if (rcheevos_locals->load_info.state == RCHEEVOS_LOAD_STATE_NETWORK_ERROR)
if ( rcheevos_locals->load_info.state
== RCHEEVOS_LOAD_STATE_NETWORK_ERROR)
break;
rcheevos_locals->load_info.state = RCHEEVOS_LOAD_STATE_NETWORK_ERROR;
rcheevos_locals->load_info.state =
RCHEEVOS_LOAD_STATE_NETWORK_ERROR;
while (request->request.url[len] != '/' || /* find the first single slash */
request->request.url[len + 1] == '/' ||
request->request.url[len - 1] == '/')
{
while (
/* find the first single slash */
request->request.url[len] != '/'
|| request->request.url[len + 1] == '/'
|| request->request.url[len - 1] == '/')
++len;
}
ptr = errbuf + snprintf(errbuf, sizeof(errbuf), "Could not communicate with ");
ptr = errbuf + snprintf(errbuf, sizeof(errbuf),
"Could not communicate with ");
memcpy(ptr, request->request.url, len);
ptr[len] = '\0';
}
@ -509,7 +493,8 @@ static void rcheevos_async_http_task_callback(
free(request);
}
static void rcheevos_async_begin_request(rcheevos_async_io_request* request,
static void rcheevos_async_begin_request(
rcheevos_async_io_request* request,
rcheevos_async_handler handler, char type, int id,
const char* success_message, const char* failure_message)
{
@ -528,7 +513,8 @@ static void rcheevos_async_begin_request(rcheevos_async_io_request* request,
}
static bool rcheevos_async_succeeded(int result,
const rc_api_response_t* response, char buffer[], size_t buffer_size)
const rc_api_response_t* response, char buffer[],
size_t buffer_size)
{
if (result != RC_OK)
{
@ -555,28 +541,32 @@ void rcheevos_client_initialize(void)
* login *
****************************/
static void rcheevos_async_login_callback(struct rcheevos_async_io_request* request,
http_transfer_data_t* data, char buffer[], size_t buffer_size)
static void rcheevos_async_login_callback(
struct rcheevos_async_io_request* request,
http_transfer_data_t* data, char buffer[], size_t buffer_size)
{
rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
rc_api_login_response_t api_response;
int result = rc_api_process_login_response(&api_response, data->data);
if (rcheevos_async_succeeded(result, &api_response.response, buffer, buffer_size))
if (rcheevos_async_succeeded(result, &api_response.response,
buffer, buffer_size))
{
CHEEVOS_LOG(RCHEEVOS_TAG "%s logged in successfully\n", api_response.username);
strlcpy(rcheevos_locals->username, api_response.username, sizeof(rcheevos_locals->username));
strlcpy(rcheevos_locals->token, api_response.api_token, sizeof(rcheevos_locals->token));
CHEEVOS_LOG(RCHEEVOS_TAG "%s logged in successfully\n",
api_response.username);
strlcpy(rcheevos_locals->username, api_response.username,
sizeof(rcheevos_locals->username));
strlcpy(rcheevos_locals->token, api_response.api_token,
sizeof(rcheevos_locals->token));
}
else
{
rcheevos_locals->token[0] = '\0';
}
rc_api_destroy_login_response(&api_response);
}
static void rcheevos_client_login(const char* username, const char* password, const char* token,
static void rcheevos_client_login(const char* username,
const char* password, const char* token,
rcheevos_client_callback callback, void* userdata)
{
rcheevos_async_io_request* request = (rcheevos_async_io_request*)
@ -607,14 +597,16 @@ static void rcheevos_client_login(const char* username, const char* password, co
}
}
void rcheevos_client_login_with_password(const char* username, const char* password,
rcheevos_client_callback callback, void* userdata)
void rcheevos_client_login_with_password(const char* username,
const char* password,
rcheevos_client_callback callback, void* userdata)
{
rcheevos_client_login(username, password, NULL, callback, userdata);
}
void rcheevos_client_login_with_token(const char* username, const char* token,
rcheevos_client_callback callback, void* userdata)
void rcheevos_client_login_with_token(const char* username,
const char* token,
rcheevos_client_callback callback, void* userdata)
{
rcheevos_client_login(username, NULL, token, callback, userdata);
}
@ -623,13 +615,16 @@ void rcheevos_client_login_with_token(const char* username, const char* token,
* identify game *
****************************/
static void rcheevos_async_resolve_hash_callback(struct rcheevos_async_io_request* request,
http_transfer_data_t* data, char buffer[], size_t buffer_size)
static void rcheevos_async_resolve_hash_callback(
struct rcheevos_async_io_request* request,
http_transfer_data_t* data, char buffer[], size_t buffer_size)
{
rc_api_resolve_hash_response_t api_response;
int result = rc_api_process_resolve_hash_response(&api_response,
data->data);
int result = rc_api_process_resolve_hash_response(&api_response, data->data);
if (rcheevos_async_succeeded(result, &api_response.response, buffer, buffer_size))
if (rcheevos_async_succeeded(result, &api_response.response,
buffer, buffer_size))
{
rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
rcheevos_locals->game.id = api_response.game_id;
@ -638,7 +633,8 @@ static void rcheevos_async_resolve_hash_callback(struct rcheevos_async_io_reques
rc_api_destroy_resolve_hash_response(&api_response);
}
void rcheevos_client_identify_game(const char* hash, rcheevos_client_callback callback, void* userdata)
void rcheevos_client_identify_game(const char* hash,
rcheevos_client_callback callback, void* userdata)
{
rcheevos_async_io_request* request = (rcheevos_async_io_request*)
calloc(1, sizeof(rcheevos_async_io_request));
@ -651,13 +647,13 @@ void rcheevos_client_identify_game(const char* hash, rcheevos_client_callback ca
rc_api_resolve_hash_request_t api_params;
memset(&api_params, 0, sizeof(api_params));
api_params.username = "unused"; /* TODO: don't set this after upgrading to rcheevos 10.2 */
api_params.username = "unused"; /* TODO: don't set this after upgrading to rcheevos 10.2 */
api_params.api_token = "unused"; /* TODO: don't set this after upgrading to rcheevos 10.2 */
api_params.game_hash = hash;
rc_api_init_resolve_hash_request(&request->request, &api_params);
request->callback = callback;
request->callback = callback;
request->callback_data = userdata;
rcheevos_begin_load_state(RCHEEVOS_LOAD_STATE_IDENTIFYING_GAME);
@ -683,16 +679,18 @@ typedef struct rcheevos_async_initialize_runtime_data_t
void* callback_data;
} rcheevos_async_initialize_runtime_data_t;
static void rcheevos_client_copy_achievements(rcheevos_async_initialize_runtime_data_t* runtime_data)
static void rcheevos_client_copy_achievements(
rcheevos_async_initialize_runtime_data_t* runtime_data)
{
const rc_api_achievement_definition_t* definition;
rcheevos_racheevo_t* achievement;
rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
const settings_t* settings = config_get_ptr();
unsigned i, j;
const rc_api_achievement_definition_t* definition;
rcheevos_racheevo_t *achievement;
rcheevos_locals_t *rcheevos_locals = get_rcheevos_locals();
const settings_t *settings = config_get_ptr();
rcheevos_locals->game.achievements = (rcheevos_racheevo_t*)
calloc(runtime_data->game_data.num_achievements, sizeof(rcheevos_racheevo_t));
rcheevos_locals->game.achievements = (rcheevos_racheevo_t*)
calloc(runtime_data->game_data.num_achievements,
sizeof(rcheevos_racheevo_t));
achievement = rcheevos_locals->game.achievements;
if (!achievement)
@ -702,40 +700,50 @@ static void rcheevos_client_copy_achievements(rcheevos_async_initialize_runtime_
}
definition = runtime_data->game_data.achievements;
for (i = 0; i < runtime_data->game_data.num_achievements; ++i, ++definition)
for (i = 0; i < runtime_data->game_data.num_achievements;
++i, ++definition)
{
if (definition->category == 0 ||
!definition->definition || !definition->definition[0] ||
!definition->title || !definition->title[0] ||
!definition->description || !definition->description[0])
{
/* invalid definition, ignore */
/* invalid definition, ignore */
if (
definition->category == 0
|| !definition->definition
|| !definition->definition[0]
|| !definition->title
|| !definition->title[0]
|| !definition->description
|| !definition->description[0])
continue;
}
if (definition->category != 3)
{
achievement->active = RCHEEVOS_ACTIVE_UNOFFICIAL;
if (settings->bools.cheevos_test_unofficial)
achievement->active |= RCHEEVOS_ACTIVE_SOFTCORE | RCHEEVOS_ACTIVE_HARDCORE;
achievement->active |= RCHEEVOS_ACTIVE_SOFTCORE
| RCHEEVOS_ACTIVE_HARDCORE;
}
else
{
achievement->active = RCHEEVOS_ACTIVE_SOFTCORE | RCHEEVOS_ACTIVE_HARDCORE;
achievement->active = RCHEEVOS_ACTIVE_SOFTCORE
| RCHEEVOS_ACTIVE_HARDCORE;
for (j = 0; j < runtime_data->hardcore_unlocks.num_achievement_ids; ++j)
for (j = 0; j <
runtime_data->hardcore_unlocks.num_achievement_ids; ++j)
{
if (runtime_data->hardcore_unlocks.achievement_ids[j] == definition->id)
if (runtime_data->hardcore_unlocks.achievement_ids[j]
== definition->id)
{
achievement->active &= ~(RCHEEVOS_ACTIVE_HARDCORE | RCHEEVOS_ACTIVE_SOFTCORE);
achievement->active &= ~(RCHEEVOS_ACTIVE_HARDCORE
| RCHEEVOS_ACTIVE_SOFTCORE);
break;
}
}
if ((achievement->active & RCHEEVOS_ACTIVE_SOFTCORE) != 0)
{
for (j = 0; j < runtime_data->non_hardcore_unlocks.num_achievement_ids; ++j)
for (j = 0; j <
runtime_data->non_hardcore_unlocks.num_achievement_ids;
++j)
{
if (runtime_data->non_hardcore_unlocks.achievement_ids[j] == definition->id)
{
@ -746,33 +754,40 @@ static void rcheevos_client_copy_achievements(rcheevos_async_initialize_runtime_
}
}
achievement->id = definition->id;
achievement->title = strdup(definition->title);
achievement->id = definition->id;
achievement->title = strdup(definition->title);
achievement->description = strdup(definition->description);
achievement->badge = strdup(definition->badge_name);
achievement->points = definition->points;
achievement->badge = strdup(definition->badge_name);
achievement->points = definition->points;
/* if an achievement has been fully unlocked, we don't need to keep the definition around
* as it won't be reactivated. otherwise, we do have to keep a copy of it. */
if ((achievement->active & (RCHEEVOS_ACTIVE_HARDCORE | RCHEEVOS_ACTIVE_SOFTCORE)) != 0)
/* If an achievement has been fully unlocked,
* we don't need to keep the definition around
* as it won't be reactivated. Otherwise,
* we do have to keep a copy of it. */
if ((achievement->active & (RCHEEVOS_ACTIVE_HARDCORE
| RCHEEVOS_ACTIVE_SOFTCORE)) != 0)
achievement->memaddr = strdup(definition->definition);
++achievement;
}
rcheevos_locals->game.achievement_count = achievement - rcheevos_locals->game.achievements;
rcheevos_locals->game.achievement_count = achievement
- rcheevos_locals->game.achievements;
}
static void rcheevos_client_copy_leaderboards(rcheevos_async_initialize_runtime_data_t* runtime_data)
static void rcheevos_client_copy_leaderboards(
rcheevos_async_initialize_runtime_data_t* runtime_data)
{
const rc_api_leaderboard_definition_t* definition;
rcheevos_ralboard_t* leaderboard;
rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
unsigned i;
rcheevos_ralboard_t *leaderboard;
const rc_api_leaderboard_definition_t *definition;
rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
rcheevos_locals->game.leaderboards = (rcheevos_ralboard_t*)
calloc(runtime_data->game_data.num_leaderboards, sizeof(rcheevos_ralboard_t));
rcheevos_locals->game.leaderboard_count = runtime_data->game_data.num_leaderboards;
calloc(runtime_data->game_data.num_leaderboards,
sizeof(rcheevos_ralboard_t));
rcheevos_locals->game.leaderboard_count =
runtime_data->game_data.num_leaderboards;
leaderboard = rcheevos_locals->game.leaderboards;
if (!leaderboard)
@ -784,24 +799,28 @@ static void rcheevos_client_copy_leaderboards(rcheevos_async_initialize_runtime_
definition = runtime_data->game_data.leaderboards;
for (i = 0; i < runtime_data->game_data.num_leaderboards; ++i, ++definition, ++leaderboard)
{
leaderboard->id = definition->id;
leaderboard->title = strdup(definition->title);
leaderboard->id = definition->id;
leaderboard->title = strdup(definition->title);
leaderboard->description = strdup(definition->description);
leaderboard->mem = strdup(definition->definition);
leaderboard->format = definition->format;
leaderboard->mem = strdup(definition->definition);
leaderboard->format = definition->format;
}
}
static void rcheevos_client_initialize_runtime_rich_presence(rcheevos_async_initialize_runtime_data_t* runtime_data)
static void rcheevos_client_initialize_runtime_rich_presence(
rcheevos_async_initialize_runtime_data_t* runtime_data)
{
if (runtime_data->game_data.rich_presence_script && *runtime_data->game_data.rich_presence_script)
{
rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
/* just activate the rich presence script now. it can't be toggled on or off,
* so there's no reason to keep the unparsed version around any longer than
* necessary, and we can avoid making a copy in the process. */
int result = rc_runtime_activate_richpresence(&rcheevos_locals->runtime,
/* Just activate the rich presence script now.
* It can't be toggled on or off,
* so there's no reason to keep the unparsed version
* around any longer than necessary, and we can avoid
* making a copy in the process. */
int result = rc_runtime_activate_richpresence(
&rcheevos_locals->runtime,
runtime_data->game_data.rich_presence_script, NULL, 0);
if (result != RC_OK)
@ -809,11 +828,12 @@ static void rcheevos_client_initialize_runtime_rich_presence(rcheevos_async_init
const settings_t* settings = config_get_ptr();
char buffer[256];
snprintf(buffer, sizeof(buffer),
"Could not activate rich presence: %s", rc_error_str(result));
"Could not activate rich presence: %s",
rc_error_str(result));
if (settings->bools.cheevos_verbose_enable)
runloop_msg_queue_push(buffer, 0, 4 * 60, false, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
CHEEVOS_ERR(RCHEEVOS_TAG "%s\n", buffer);
}
@ -844,60 +864,76 @@ static void rcheevos_client_initialize_runtime_callback(void* userdata)
free(runtime_data);
}
static void rcheevos_async_fetch_user_unlocks_callback(struct rcheevos_async_io_request* request,
http_transfer_data_t* data, char buffer[], size_t buffer_size)
static void rcheevos_async_fetch_user_unlocks_callback(
struct rcheevos_async_io_request* request,
http_transfer_data_t* data, char buffer[], size_t buffer_size)
{
rcheevos_async_initialize_runtime_data_t* runtime_data = (rcheevos_async_initialize_runtime_data_t*)request->callback_data;
rcheevos_async_initialize_runtime_data_t* runtime_data =
(rcheevos_async_initialize_runtime_data_t*)request->callback_data;
int result;
if (request->type == CHEEVOS_ASYNC_FETCH_HARDCORE_USER_UNLOCKS)
{
result = rc_api_process_fetch_user_unlocks_response(&runtime_data->hardcore_unlocks, data->data);
rcheevos_async_succeeded(result, &runtime_data->hardcore_unlocks.response, buffer, buffer_size);
result = rc_api_process_fetch_user_unlocks_response(
&runtime_data->hardcore_unlocks, data->data);
rcheevos_async_succeeded(result,
&runtime_data->hardcore_unlocks.response,
buffer, buffer_size);
}
else
{
result = rc_api_process_fetch_user_unlocks_response(&runtime_data->non_hardcore_unlocks, data->data);
rcheevos_async_succeeded(result, &runtime_data->non_hardcore_unlocks.response, buffer, buffer_size);
result = rc_api_process_fetch_user_unlocks_response(
&runtime_data->non_hardcore_unlocks, data->data);
rcheevos_async_succeeded(result,
&runtime_data->non_hardcore_unlocks.response,
buffer, buffer_size);
}
}
static void rcheevos_async_fetch_game_data_callback(struct rcheevos_async_io_request* request,
static void rcheevos_async_fetch_game_data_callback(
struct rcheevos_async_io_request* request,
http_transfer_data_t* data, char buffer[], size_t buffer_size)
{
rcheevos_async_initialize_runtime_data_t* runtime_data = (rcheevos_async_initialize_runtime_data_t*)request->callback_data;
rcheevos_async_initialize_runtime_data_t* runtime_data =
(rcheevos_async_initialize_runtime_data_t*)request->callback_data;
#ifdef CHEEVOS_SAVE_JSON
filestream_write_file(CHEEVOS_SAVE_JSON, data->data, data->len);
#endif
int result = rc_api_process_fetch_game_data_response(&runtime_data->game_data, data->data);
int result = rc_api_process_fetch_game_data_response(
&runtime_data->game_data, data->data);
if (rcheevos_async_succeeded(result, &runtime_data->game_data.response, buffer, buffer_size))
{
rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
rcheevos_locals->game.title = strdup(runtime_data->game_data.title);
rcheevos_locals->game.console_id = runtime_data->game_data.console_id;
rcheevos_locals->game.title = strdup(
runtime_data->game_data.title);
rcheevos_locals->game.console_id =
runtime_data->game_data.console_id;
}
}
void rcheevos_client_initialize_runtime(unsigned game_id, rcheevos_client_callback callback, void* userdata)
void rcheevos_client_initialize_runtime(unsigned game_id,
rcheevos_client_callback callback, void* userdata)
{
rcheevos_async_io_request* request;
const settings_t* settings = config_get_ptr();
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
rcheevos_async_initialize_runtime_data_t* data = (rcheevos_async_initialize_runtime_data_t*)
const settings_t *settings = config_get_ptr();
const rcheevos_locals_t *rcheevos_locals = get_rcheevos_locals();
rcheevos_async_initialize_runtime_data_t *data =
(rcheevos_async_initialize_runtime_data_t*)
malloc(sizeof(rcheevos_async_initialize_runtime_data_t));
if (!data)
{
CHEEVOS_LOG(RCHEEVOS_TAG "Failed to allocate runtime initalization data\n");
return;
}
data->callback = callback;
data->callback = callback;
data->callback_data = userdata;
request = (rcheevos_async_io_request*)
calloc(1, sizeof(rcheevos_async_io_request));
request = (rcheevos_async_io_request*)calloc(1, sizeof(rcheevos_async_io_request));
if (!request)
{
CHEEVOS_LOG(RCHEEVOS_TAG "Failed to allocate game data fetch request\n");
@ -1012,14 +1048,15 @@ void rcheevos_client_initialize_runtime(unsigned game_id, rcheevos_client_callba
* ping *
****************************/
static retro_time_t rcheevos_client_prepare_ping(rcheevos_async_io_request* request)
static retro_time_t rcheevos_client_prepare_ping(
rcheevos_async_io_request* request)
{
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
const settings_t *settings = config_get_ptr();
const bool cheevos_richpresence_enable =
settings->bools.cheevos_richpresence_enable;
rc_api_ping_request_t api_params;
char buffer[256] = "";
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
const settings_t *settings = config_get_ptr();
const bool cheevos_richpresence_enable =
settings->bools.cheevos_richpresence_enable;
char buffer[256] = "";
memset(&api_params, 0, sizeof(api_params));
api_params.username = rcheevos_locals->username;
@ -1034,7 +1071,8 @@ static retro_time_t rcheevos_client_prepare_ping(rcheevos_async_io_request* requ
rc_api_init_ping_request(&request->request, &api_params);
rcheevos_log_post_url(request->request.url, request->request.post_data);
rcheevos_log_post_url(request->request.url,
request->request.post_data);
#ifdef HAVE_DISCORD
if (settings->bools.discord_enable && discord_is_ready())
@ -1060,7 +1098,8 @@ static void rcheevos_async_ping_handler(retro_task_t* task)
/* game changed; stop the recurring task - a new one will
* be scheduled if a new game is loaded */
task_set_finished(task, 1);
/* request->request was destroyed in rcheevos_async_http_task_callback */
/* request->request was destroyed
* in rcheevos_async_http_task_callback */
free(request);
return;
}
@ -1075,18 +1114,20 @@ static void rcheevos_async_ping_handler(retro_task_t* task)
rcheevos_async_http_task_callback, request);
}
/****************************
* start session *
****************************/
static void rcheevos_async_start_session_callback(struct rcheevos_async_io_request* request,
http_transfer_data_t* data, char buffer[], size_t buffer_size)
static void rcheevos_async_start_session_callback(
struct rcheevos_async_io_request* request,
http_transfer_data_t* data, char buffer[], size_t buffer_size)
{
rc_api_start_session_response_t api_response;
int result = rc_api_process_start_session_response(&api_response, data->data);
rcheevos_async_succeeded(result, &api_response.response, buffer, buffer_size);
int result = rc_api_process_start_session_response(
&api_response, data->data);
rcheevos_async_succeeded(result,
&api_response.response, buffer, buffer_size);
rc_api_destroy_start_session_response(&api_response);
}
@ -1106,7 +1147,8 @@ void rcheevos_client_start_session(unsigned game_id)
calloc(1, sizeof(rcheevos_async_io_request));
if (!request)
{
CHEEVOS_LOG(RCHEEVOS_TAG "Failed to allocate rich presence request\n");
CHEEVOS_LOG(RCHEEVOS_TAG
"Failed to allocate rich presence request\n");
}
else
{
@ -1133,7 +1175,8 @@ void rcheevos_client_start_session(unsigned game_id)
calloc(1, sizeof(rcheevos_async_io_request));
if (!request)
{
CHEEVOS_LOG(RCHEEVOS_TAG "Failed to allocate new session request\n");
CHEEVOS_LOG(RCHEEVOS_TAG
"Failed to allocate new session request\n");
}
else
{
@ -1144,7 +1187,8 @@ void rcheevos_client_start_session(unsigned game_id)
api_params.api_token = rcheevos_locals->token;
api_params.game_id = game_id;
rc_api_init_start_session_request(&request->request, &api_params);
rc_api_init_start_session_request(
&request->request, &api_params);
rcheevos_async_begin_request(request,
rcheevos_async_start_session_callback,
@ -1173,7 +1217,8 @@ typedef struct rcheevos_fetch_badge_state
const char* badge_directory;
rcheevos_client_callback callback;
void* callback_data;
char requested_badges[RCHEEVOS_CONCURRENT_BADGE_DOWNLOADS][32];
char requested_badges[
RCHEEVOS_CONCURRENT_BADGE_DOWNLOADS][32];
} rcheevos_fetch_badge_state;
typedef struct rcheevos_fetch_badge_data
@ -1196,7 +1241,8 @@ static void rcheevos_end_fetch_badges(rcheevos_fetch_badge_state* state)
static void rcheevos_async_download_next_badge(void* userdata)
{
rcheevos_fetch_badge_data* badge_data = (rcheevos_fetch_badge_data*)userdata;
rcheevos_fetch_badge_data* badge_data =
(rcheevos_fetch_badge_data*)userdata;
rcheevos_fetch_next_badge(badge_data->state);
if (rcheevos_end_load_state() == 0)
@ -1205,40 +1251,49 @@ static void rcheevos_async_download_next_badge(void* userdata)
free(badge_data);
}
static void rcheevos_async_fetch_badge_callback(struct rcheevos_async_io_request* request,
http_transfer_data_t* data, char buffer[], size_t buffer_size)
static void rcheevos_async_fetch_badge_callback(
struct rcheevos_async_io_request* request,
http_transfer_data_t* data, char buffer[], size_t buffer_size)
{
rcheevos_fetch_badge_data* badge_data = (rcheevos_fetch_badge_data*)request->callback_data;
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
char badge_fullpath[PATH_MAX_LENGTH];
rcheevos_fetch_badge_data* badge_data =
(rcheevos_fetch_badge_data*)request->callback_data;
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
fill_pathname_join(badge_fullpath, badge_data->state->badge_directory,
badge_data->state->requested_badges[badge_data->request_index], sizeof(badge_fullpath));
badge_data->state->requested_badges[badge_data->request_index],
sizeof(badge_fullpath));
if (!filestream_write_file(badge_fullpath, data->data, data->len))
CHEEVOS_ERR(RCHEEVOS_TAG "Error writing badge %s\n", badge_fullpath);
CHEEVOS_ERR(RCHEEVOS_TAG "Error writing badge %s\n",
badge_fullpath);
CHEEVOS_LOCK(rcheevos_locals->load_info.request_lock);
badge_data->state->requested_badges[badge_data->request_index][0] = '\0';
CHEEVOS_UNLOCK(rcheevos_locals->load_info.request_lock);
}
static bool rcheevos_client_fetch_badge(const char* badge_name, int locked, rcheevos_fetch_badge_state* state)
static bool rcheevos_client_fetch_badge(
const char* badge_name, int locked,
rcheevos_fetch_badge_state* state)
{
char badge_fullpath[PATH_MAX_LENGTH];
char* badge_fullname = NULL;
char* badge_fullname = NULL;
size_t badge_fullname_size = 0;
int request_index = -1;
int request_index = -1;
if (!badge_name || !badge_name[0])
return false;
strlcpy(badge_fullpath, state->badge_directory, sizeof(badge_fullpath));
strlcpy(badge_fullpath,
state->badge_directory, sizeof(badge_fullpath));
fill_pathname_slash(badge_fullpath, sizeof(badge_fullpath));
badge_fullname = badge_fullpath + strlen(state->badge_directory);
badge_fullname_size = sizeof(badge_fullpath) - (badge_fullname - badge_fullpath);
badge_fullname = badge_fullpath + strlen(state->badge_directory);
badge_fullname_size = sizeof(badge_fullpath) -
(badge_fullname - badge_fullpath);
snprintf(badge_fullname, badge_fullname_size, "%s%s" FILE_PATH_PNG_EXTENSION,
snprintf(badge_fullname,
badge_fullname_size, "%s%s" FILE_PATH_PNG_EXTENSION,
badge_name, locked ? "_lock" : "");
/* check if it's already available */
@ -1255,10 +1310,9 @@ static bool rcheevos_client_fetch_badge(const char* badge_name, int locked, rche
for (i = RCHEEVOS_CONCURRENT_BADGE_DOWNLOADS - 1; i >= 0; --i)
{
if (!state->requested_badges[i][0])
{
request_index = i;
}
else if (string_is_equal(badge_fullname, state->requested_badges[i]))
else if (string_is_equal(badge_fullname,
state->requested_badges[i]))
{
found_index = i;
break;
@ -1267,15 +1321,15 @@ static bool rcheevos_client_fetch_badge(const char* badge_name, int locked, rche
if (found_index == -1)
{
/* unexpected - but if it happens,
* the queue is full. Pretend we found
* a match to prevent an exception */
if (request_index == -1)
{
/* unexpected - but if it happens, the queue is full. pretend we found a match to prevent an exception */
found_index = 0;
}
else
{
strlcpy(state->requested_badges[request_index], badge_fullname, sizeof(state->requested_badges[request_index]));
}
strlcpy(state->requested_badges[request_index],
badge_fullname,
sizeof(state->requested_badges[request_index]));
}
CHEEVOS_UNLOCK(rcheevos_locals->load_info.request_lock);
@ -1296,7 +1350,8 @@ static bool rcheevos_client_fetch_badge(const char* badge_name, int locked, rche
if (!request || !data)
{
CHEEVOS_LOG(RCHEEVOS_TAG "Failed to allocate fetch badge request\n");
CHEEVOS_LOG(RCHEEVOS_TAG
"Failed to allocate fetch badge request\n");
}
else
{
@ -1304,14 +1359,16 @@ static bool rcheevos_client_fetch_badge(const char* badge_name, int locked, rche
memset(&api_params, 0, sizeof(api_params));
api_params.image_name = badge_name;
api_params.image_type = locked ? RC_IMAGE_TYPE_ACHIEVEMENT_LOCKED : RC_IMAGE_TYPE_ACHIEVEMENT;
api_params.image_type = locked
? RC_IMAGE_TYPE_ACHIEVEMENT_LOCKED
: RC_IMAGE_TYPE_ACHIEVEMENT;
rc_api_init_fetch_image_request(&request->request, &api_params);
data->state = state;
data->request_index = request_index;
data->state = state;
data->request_index = request_index;
request->callback = rcheevos_async_download_next_badge;
request->callback = rcheevos_async_download_next_badge;
request->callback_data = data;
rcheevos_begin_load_state(RCHEEVOS_LOAD_STATE_FETCHING_BADGES);
@ -1341,7 +1398,8 @@ static bool rcheevos_fetch_next_badge(rcheevos_fetch_badge_state* state)
do
{
CHEEVOS_LOCK(rcheevos_locals->load_info.request_lock);
if (state->locked_badge_fetch_index < rcheevos_locals->game.achievement_count)
if ( state->locked_badge_fetch_index
< rcheevos_locals->game.achievement_count)
cheevo = &rcheevos_locals->game.achievements[state->locked_badge_fetch_index++];
else
cheevo = NULL;
@ -1350,7 +1408,8 @@ static bool rcheevos_fetch_next_badge(rcheevos_fetch_badge_state* state)
if (!cheevo)
break;
active = (cheevo->active & (RCHEEVOS_ACTIVE_HARDCORE | RCHEEVOS_ACTIVE_SOFTCORE));
active = (cheevo->active
& (RCHEEVOS_ACTIVE_HARDCORE | RCHEEVOS_ACTIVE_SOFTCORE));
if (rcheevos_client_fetch_badge(cheevo->badge, active, state))
return true;
@ -1364,6 +1423,7 @@ static bool rcheevos_fetch_next_badge(rcheevos_fetch_badge_state* state)
cheevo = &rcheevos_locals->game.achievements[state->badge_fetch_index++];
else
cheevo = NULL;
CHEEVOS_UNLOCK(rcheevos_locals->load_info.request_lock);
if (!cheevo)
@ -1381,21 +1441,24 @@ static bool rcheevos_fetch_next_badge(rcheevos_fetch_badge_state* state)
void rcheevos_client_fetch_badges(rcheevos_client_callback callback, void* userdata)
{
#if defined(HAVE_MENU) || defined(HAVE_GFX_WIDGETS) /* don't need badges unless menu or widgets are enabled */
rcheevos_fetch_badge_state* state = NULL;
char badge_fullpath[PATH_MAX_LENGTH] = "";
#if !defined(HAVE_GFX_WIDGETS) /* we always want badges if widgets are enabled */
settings_t* settings = config_get_ptr();
if (!settings->bools.cheevos_badges_enable) /* user has explicitly disabled badges */
#if !defined(HAVE_GFX_WIDGETS) /* we always want badges if widgets are enabled */
settings_t* settings = config_get_ptr();
/* User has explicitly disabled badges */
if (!settings->bools.cheevos_badges_enable)
return;
/* badges are only needed for xmb and ozone menus */
if (!string_is_equal(settings->arrays.menu_driver, "xmb") &&
!string_is_equal(settings->arrays.menu_driver, "ozone"))
!string_is_equal(settings->arrays.menu_driver, "ozone"))
return;
#endif /* !defined(HAVE_GFX_WIDGETS) */
#endif /* !defined(HAVE_GFX_WIDGETS) */
/* make sure the directory exists */
fill_pathname_application_special(badge_fullpath, sizeof(badge_fullpath),
APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_CHEEVOS_BADGES);
fill_pathname_application_special(badge_fullpath,
sizeof(badge_fullpath),
APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_CHEEVOS_BADGES);
if (!path_is_directory(badge_fullpath))
{
@ -1404,8 +1467,9 @@ void rcheevos_client_fetch_badges(rcheevos_client_callback callback, void* userd
}
/* start the download task */
rcheevos_fetch_badge_state* state = (rcheevos_fetch_badge_state*)
state = (rcheevos_fetch_badge_state*)
calloc(1, sizeof(rcheevos_fetch_badge_state));
if (!state)
{
CHEEVOS_LOG(RCHEEVOS_TAG "Failed to allocate fetch badge state\n");
@ -1446,19 +1510,20 @@ void rcheevos_client_fetch_badges(rcheevos_client_callback callback, void* userd
* award achievement *
****************************/
static void rcheevos_async_award_achievement_callback(struct rcheevos_async_io_request* request,
static void rcheevos_async_award_achievement_callback(
struct rcheevos_async_io_request* request,
http_transfer_data_t *data, char buffer[], size_t buffer_size)
{
rc_api_award_achievement_response_t api_response;
int result = rc_api_process_award_achievement_response(&api_response, data->data);
if (rcheevos_async_succeeded(result, &api_response.response, buffer, buffer_size))
int result = rc_api_process_award_achievement_response(
&api_response, data->data);
if (rcheevos_async_succeeded(result, &api_response.response,
buffer, buffer_size))
{
if (api_response.awarded_achievement_id != request->id)
{
snprintf(buffer, buffer_size, "Achievement %u awarded instead",
api_response.awarded_achievement_id);
}
else if (api_response.response.error_message)
{
/* previously unlocked achievements are returned as a "successful" error */
@ -1481,8 +1546,8 @@ void rcheevos_client_award_achievement(unsigned achievement_id)
}
else
{
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
rc_api_award_achievement_request_t api_params;
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
memset(&api_params, 0, sizeof(api_params));
api_params.username = rcheevos_locals->username;
@ -1491,7 +1556,8 @@ void rcheevos_client_award_achievement(unsigned achievement_id)
api_params.hardcore = rcheevos_locals->hardcore_active ? 1 : 0;
api_params.game_hash = rcheevos_locals->game.hash;
rc_api_init_award_achievement_request(&request->request, &api_params);
rc_api_init_award_achievement_request(&request->request,
&api_params);
rcheevos_async_begin_request(request,
rcheevos_async_award_achievement_callback,
@ -1506,28 +1572,30 @@ void rcheevos_client_award_achievement(unsigned achievement_id)
* submit leaderboard *
****************************/
static void rcheevos_async_submit_lboard_entry_callback(struct rcheevos_async_io_request* request,
static void rcheevos_async_submit_lboard_entry_callback(
struct rcheevos_async_io_request* request,
http_transfer_data_t* data, char buffer[], size_t buffer_size)
{
rc_api_submit_lboard_entry_response_t api_response;
int result = rc_api_process_submit_lboard_entry_response(
&api_response, data->data);
int result = rc_api_process_submit_lboard_entry_response(&api_response, data->data);
if (rcheevos_async_succeeded(result, &api_response.response, buffer, buffer_size))
{
/* not currently doing anything with the response */
}
/* not currently doing anything with the response */
if (rcheevos_async_succeeded(result, &api_response.response, buffer,
buffer_size)) { }
rc_api_destroy_submit_lboard_entry_response(&api_response);
}
void rcheevos_client_submit_lboard_entry(unsigned leaderboard_id, int value)
void rcheevos_client_submit_lboard_entry(unsigned leaderboard_id,
int value)
{
rcheevos_async_io_request *request = (rcheevos_async_io_request*)
calloc(1, sizeof(rcheevos_async_io_request));
if (!request)
{
CHEEVOS_LOG(RCHEEVOS_TAG "Failed to allocate request for lboard %u submit\n",
CHEEVOS_LOG(RCHEEVOS_TAG
"Failed to allocate request for lboard %u submit\n",
leaderboard_id);
}
else
@ -1542,7 +1610,8 @@ void rcheevos_client_submit_lboard_entry(unsigned leaderboard_id, int value)
api_params.score = value;
api_params.game_hash = rcheevos_locals->game.hash;
rc_api_init_submit_lboard_entry_request(&request->request, &api_params);
rc_api_init_submit_lboard_entry_request(&request->request,
&api_params);
rcheevos_async_begin_request(request,
rcheevos_async_submit_lboard_entry_callback,
@ -1551,4 +1620,3 @@ void rcheevos_client_submit_lboard_entry(unsigned leaderboard_id, int value)
"Error submitting leaderboard");
}
}

View File

@ -115,15 +115,11 @@ bool rcheevos_menu_get_state(unsigned menu_offset, char *buffer, size_t len)
if (cheevo)
{
if (cheevo->menu_progress)
{
snprintf(buffer, len, "%s - %d%%",
msg_hash_to_str(menuitem->state_label_idx),
cheevo->menu_progress);
}
else
{
strlcpy(buffer, msg_hash_to_str(menuitem->state_label_idx), len);
}
return true;
}
@ -183,9 +179,7 @@ static rcheevos_menuitem_t* rcheevos_menu_allocate(
rcheevos_locals->menuitem_capacity * sizeof(rcheevos_menuitem_t));
if (new_menuitems)
{
rcheevos_locals->menuitems = new_menuitems;
}
else
{
/* realloc failed */
@ -353,9 +347,7 @@ static void rcheevos_menu_append_items(rcheevos_locals_t* rcheevos_locals,
if (cheevo->badge && cheevo->badge[0] && settings &&
settings->bools.cheevos_badges_enable)
{
rcheevos_menu_update_badge(cheevo);
}
}
++cheevo;
@ -467,7 +459,7 @@ void rcheevos_menu_populate(void* data)
/* count items in each bucket */
cheevo = rcheevos_locals->game.achievements;
stop = cheevo + rcheevos_locals->game.achievement_count;
stop = cheevo + rcheevos_locals->game.achievement_count;
while (cheevo < stop)
{
@ -480,9 +472,7 @@ void rcheevos_menu_populate(void* data)
++num_recently_unlocked;
}
else
{
++num_unlocked;
}
break;
case RCHEEVOS_MENUITEM_BUCKET_LOCKED:
@ -555,10 +545,8 @@ void rcheevos_menu_populate(void* data)
if (num_locked)
{
if (rcheevos_locals->menuitem_count > 0)
{
rcheevos_menu_append_header(rcheevos_locals,
MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ENTRY);
}
rcheevos_menu_append_items(rcheevos_locals,
RCHEEVOS_MENUITEM_BUCKET_LOCKED);
@ -570,10 +558,8 @@ void rcheevos_menu_populate(void* data)
if (num_unsupported)
{
if (rcheevos_locals->menuitem_count > 0)
{
rcheevos_menu_append_header(rcheevos_locals,
MENU_ENUM_LABEL_VALUE_CHEEVOS_UNSUPPORTED_ENTRY);
}
rcheevos_menu_append_items(rcheevos_locals,
RCHEEVOS_MENUITEM_BUCKET_UNSUPPORTED);
@ -583,10 +569,8 @@ void rcheevos_menu_populate(void* data)
if (num_unlocked)
{
if (rcheevos_locals->menuitem_count > 0)
{
rcheevos_menu_append_header(rcheevos_locals,
MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY);
}
rcheevos_menu_append_items(rcheevos_locals,
RCHEEVOS_MENUITEM_BUCKET_UNLOCKED);
@ -594,21 +578,20 @@ void rcheevos_menu_populate(void* data)
if (rcheevos_locals->menuitem_count > 0)
{
/* convert to menu entries */
rcheevos_menuitem_t* menuitem = rcheevos_locals->menuitems;
rcheevos_menuitem_t* stop = menuitem + rcheevos_locals->menuitem_count;
char buffer[128];
unsigned idx = 0;
/* convert to menu entries */
rcheevos_menuitem_t* menuitem = rcheevos_locals->menuitems;
rcheevos_menuitem_t* stop = menuitem +
rcheevos_locals->menuitem_count;
do
{
if (menuitem->cheevo)
{
menu_entries_append_enum(info->list, menuitem->cheevo->title,
menuitem->cheevo->description,
MENU_ENUM_LABEL_CHEEVOS_LOCKED_ENTRY,
MENU_SETTINGS_CHEEVOS_START + idx, 0, 0);
}
else
{
snprintf(buffer, sizeof(buffer), "----- %s -----",
@ -627,45 +610,35 @@ void rcheevos_menu_populate(void* data)
{
/* no achievements found */
if (!rcheevos_locals->core_supports)
{
menu_entries_append_enum(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CANNOT_ACTIVATE_ACHIEVEMENTS_WITH_THIS_CORE),
msg_hash_to_str(MENU_ENUM_LABEL_CANNOT_ACTIVATE_ACHIEVEMENTS_WITH_THIS_CORE),
MENU_ENUM_LABEL_CANNOT_ACTIVATE_ACHIEVEMENTS_WITH_THIS_CORE,
FILE_TYPE_NONE, 0, 0);
}
else if (rcheevos_locals->load_info.state == RCHEEVOS_LOAD_STATE_NETWORK_ERROR)
{
menu_entries_append_enum(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETWORK_ERROR),
msg_hash_to_str(MENU_ENUM_LABEL_NETWORK_ERROR),
MENU_ENUM_LABEL_NETWORK_ERROR,
FILE_TYPE_NONE, 0, 0);
}
else if (!rcheevos_locals->game.id)
{
menu_entries_append_enum(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UNKNOWN_GAME),
msg_hash_to_str(MENU_ENUM_LABEL_UNKNOWN_GAME),
MENU_ENUM_LABEL_UNKNOWN_GAME,
FILE_TYPE_NONE, 0, 0);
}
else if (!rcheevos_locals->token[0])
{
menu_entries_append_enum(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_LOGGED_IN),
msg_hash_to_str(MENU_ENUM_LABEL_NOT_LOGGED_IN),
MENU_ENUM_LABEL_NOT_LOGGED_IN,
FILE_TYPE_NONE, 0, 0);
}
else
{
menu_entries_append_enum(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ACHIEVEMENTS_TO_DISPLAY),
msg_hash_to_str(MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY),
MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY,
FILE_TYPE_NONE, 0, 0);
}
}
}
@ -688,10 +661,7 @@ uintptr_t rcheevos_get_badge_texture(const char *badge, bool locked)
if (!gfx_display_reset_textures_list(badge_file, fullpath,
&tex, TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL))
{
tex = 0;
}
return 0;
return tex;
}