Skip to content

Commit

Permalink
update rcheevos
Browse files Browse the repository at this point in the history
  • Loading branch information
Jamiras committed Aug 19, 2023
1 parent 40f4c81 commit bcbadd3
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 31 deletions.
19 changes: 14 additions & 5 deletions deps/rcheevos/include/rc_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,6 @@ typedef void (*rc_client_callback_t)(int result, const char* error_message, rc_c
*/
typedef void (*rc_client_message_callback_t)(const char* message, const rc_client_t* client);

/**
* Marks an async process as aborted. The associated callback will not be called.
*/
void rc_client_abort_async(rc_client_t* client, rc_client_async_handle_t* async_handle);

/*****************************************************************************\
| Runtime |
\*****************************************************************************/
Expand Down Expand Up @@ -130,6 +125,20 @@ void* rc_client_get_userdata(const rc_client_t* client);
*/
void rc_client_set_host(const rc_client_t* client, const char* hostname);

/* 32-bit unsigned integer can hold enough milliseconds for 49.7 days*/
typedef uint32_t rc_clock_t;
typedef rc_clock_t (*rc_get_time_millisecs_func_t)(const rc_client_t* client);

/**
* Specifies a function that returns a value that increases once per millisecond.
*/
void rc_client_set_get_time_millisecs_function(rc_client_t* client, rc_get_time_millisecs_func_t handler);

/**
* Marks an async process as aborted. The associated callback will not be called.
*/
void rc_client_abort_async(rc_client_t* client, rc_client_async_handle_t* async_handle);

/*****************************************************************************\
| Logging |
\*****************************************************************************/
Expand Down
117 changes: 93 additions & 24 deletions deps/rcheevos/src/rcheevos/rc_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,17 @@

#include <stdarg.h>

#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <profileapi.h>
#else
#include <time.h>
#endif

#define RC_CLIENT_UNKNOWN_GAME_ID (uint32_t)-1
#define RC_CLIENT_RECENT_UNLOCK_DELAY_SECONDS (10 * 60) /* ten minutes */

/* clock_t can wrap. For most cases, we won't have to worry about it because it won't
* overflow until after over a month of runtime. But some cases can overflow in as short as
* 36 minutes. Use substraction as a secondary check to ensure an overflow hasn't occurred. */
#define RC_CLIENT_CLOCK_IS_BEFORE(clk, cmp_clk) (clk < cmp_clk && (cmp_clk - clk) > 0)

struct rc_client_async_handle_t {
uint8_t aborted;
};
Expand Down Expand Up @@ -68,11 +71,11 @@ static void rc_client_begin_fetch_game_data(rc_client_load_state_t* callback_dat
static void rc_client_hide_progress_tracker(rc_client_t* client, rc_client_game_info_t* game);
static void rc_client_load_error(rc_client_load_state_t* load_state, int result, const char* error_message);
static rc_client_async_handle_t* rc_client_load_game(rc_client_load_state_t* load_state, const char* hash, const char* file_path);
static void rc_client_ping(rc_client_scheduled_callback_data_t* callback_data, rc_client_t* client, clock_t now);
static void rc_client_ping(rc_client_scheduled_callback_data_t* callback_data, rc_client_t* client, rc_clock_t now);
static void rc_client_raise_leaderboard_events(rc_client_t* client, rc_client_subset_info_t* subset);
static void rc_client_raise_pending_events(rc_client_t* client, rc_client_game_info_t* game);
static void rc_client_release_leaderboard_tracker(rc_client_game_info_t* game, rc_client_leaderboard_info_t* leaderboard);
static void rc_client_reschedule_callback(rc_client_t* client, rc_client_scheduled_callback_data_t* callback, clock_t when);
static void rc_client_reschedule_callback(rc_client_t* client, rc_client_scheduled_callback_data_t* callback, rc_clock_t when);

/* ===== Construction/Destruction ===== */

Expand All @@ -92,6 +95,7 @@ rc_client_t* rc_client_create(rc_client_read_memory_func_t read_memory_function,
client->callbacks.server_call = server_call_function;
client->callbacks.event_handler = rc_client_dummy_event_handler;
rc_client_set_legacy_peek(client, RC_CLIENT_LEGACY_PEEK_AUTO);
rc_client_set_get_time_millisecs_function(client, NULL);

rc_mutex_init(&client->state.mutex);

Expand Down Expand Up @@ -207,6 +211,68 @@ void rc_client_enable_logging(rc_client_t* client, int level, rc_client_message_

/* ===== Common ===== */

static rc_clock_t rc_client_clock_get_now_millisecs(const rc_client_t* client)
{
#if defined(CLOCK_MONOTONIC)
struct timespec now;
if (clock_gettime(CLOCK_MONOTONIC, &now) < 0)
return 0;

/* round nanoseconds to nearest millisecond and add to seconds */
return (rc_clock_t)(now.tv_sec * 1000 + (now.tv_nsec + 500000) / 1000000);
#elif defined(_WIN32)
static LARGE_INTEGER freq;
LARGE_INTEGER ticks;

/* Frequency is the number of ticks per second and is guaranteed to not change. */
if (!freq.QuadPart) {
if (!QueryPerformanceFrequency(&freq))
return 0;

/* convert to number of ticks per millisecond to simplify later calculations */
freq.QuadPart *= 1000;
}

if (!QueryPerformanceCounter(&ticks))
return 0;

return (rc_clock_t)(ticks.QuadPart / freq.QuadPart);
#else
const clock_t clock_now = clock();
if (sizeof(clock_t) == 4) {
static uint32_t clock_wraps = 0;
static clock_t last_clock = 0;
static time_t last_timet = 0;
const time_t time_now = time(NULL);

if (last_timet != 0) {
const uint32_t seconds_per_clock_t = (uint32_t)(((uint64_t)1 << 32) / CLOCKS_PER_SEC);
if (clock_now < last_clock) {
/* clock() has wrapped */
++clock_wraps;
}
else if (time_now - last_timet > seconds_per_clock_t) {
/* it's been long enough that clock() has wrapped and is higher than the last time it was read */
++clock_wraps;
}
}

last_timet = time_now;
last_clock = clock_now;

return (rc_clock_t)((((uint64_t)clock_wraps << 32) | clock_now) / (CLOCKS_PER_SEC / 1000));
}
else {
return (rc_clock_t)(clock_now / (CLOCKS_PER_SEC / 1000));
}
#endif
}

void rc_client_set_get_time_millisecs_function(rc_client_t* client, rc_get_time_millisecs_func_t handler)
{
client->callbacks.get_time_millisecs = handler ? handler : rc_client_clock_get_now_millisecs;
}

static int rc_client_async_handle_aborted(rc_client_t* client, rc_client_async_handle_t* async_handle)
{
int aborted;
Expand Down Expand Up @@ -1074,7 +1140,7 @@ static void rc_client_activate_game(rc_client_load_state_t* load_state)
memset(callback_data, 0, sizeof(*callback_data));
callback_data->callback = rc_client_ping;
callback_data->related_id = load_state->game->public_.id;
callback_data->when = clock() + 30 * CLOCKS_PER_SEC;
callback_data->when = client->callbacks.get_time_millisecs(client) + 30 * 1000;
rc_client_schedule_callback(client, callback_data);
}

Expand Down Expand Up @@ -2668,7 +2734,7 @@ typedef struct rc_client_award_achievement_callback_data_t

static void rc_client_award_achievement_server_call(rc_client_award_achievement_callback_data_t* ach_data);

static void rc_client_award_achievement_retry(rc_client_scheduled_callback_data_t* callback_data, rc_client_t* client, clock_t now)
static void rc_client_award_achievement_retry(rc_client_scheduled_callback_data_t* callback_data, rc_client_t* client, rc_clock_t now)
{
rc_client_award_achievement_callback_data_t* ach_data =
(rc_client_award_achievement_callback_data_t*)callback_data->data;
Expand Down Expand Up @@ -2700,7 +2766,7 @@ static void rc_client_award_achievement_callback(const rc_api_server_response_t*
else {
/* double wait time between each attempt until we hit a maximum delay of two minutes */
/* 1s -> 2s -> 4s -> 8s -> 16s -> 32s -> 64s -> 120s -> 120s -> 120s ...*/
const uint32_t delay = (ach_data->retry_count > 7) ? 120 : (1 << (ach_data->retry_count - 1));
const uint32_t delay = (ach_data->retry_count > 8) ? 120 : (1 << (ach_data->retry_count - 2));
RC_CLIENT_LOG_ERR_FORMATTED(ach_data->client, "Error awarding achievement %u: %s, retrying in %u seconds", ach_data->id, error_message, delay);

if (!ach_data->scheduled_callback_data) {
Expand All @@ -2715,7 +2781,8 @@ static void rc_client_award_achievement_callback(const rc_api_server_response_t*
ach_data->scheduled_callback_data->related_id = ach_data->id;
}

ach_data->scheduled_callback_data->when = clock() + delay * CLOCKS_PER_SEC;
ach_data->scheduled_callback_data->when =
ach_data->client->callbacks.get_time_millisecs(ach_data->client) + delay * 1000;

rc_client_schedule_callback(ach_data->client, ach_data->scheduled_callback_data);
return;
Expand Down Expand Up @@ -3225,7 +3292,7 @@ typedef struct rc_client_submit_leaderboard_entry_callback_data_t

static void rc_client_submit_leaderboard_entry_server_call(rc_client_submit_leaderboard_entry_callback_data_t* lboard_data);

static void rc_client_submit_leaderboard_entry_retry(rc_client_scheduled_callback_data_t* callback_data, rc_client_t* client, clock_t now)
static void rc_client_submit_leaderboard_entry_retry(rc_client_scheduled_callback_data_t* callback_data, rc_client_t* client, rc_clock_t now)
{
rc_client_submit_leaderboard_entry_callback_data_t* lboard_data =
(rc_client_submit_leaderboard_entry_callback_data_t*)callback_data->data;
Expand Down Expand Up @@ -3257,7 +3324,7 @@ static void rc_client_submit_leaderboard_entry_callback(const rc_api_server_resp
else {
/* double wait time between each attempt until we hit a maximum delay of two minutes */
/* 1s -> 2s -> 4s -> 8s -> 16s -> 32s -> 64s -> 120s -> 120s -> 120s ...*/
const uint32_t delay = (lboard_data->retry_count > 7) ? 120 : (1 << (lboard_data->retry_count - 1));
const uint32_t delay = (lboard_data->retry_count > 8) ? 120 : (1 << (lboard_data->retry_count - 2));
RC_CLIENT_LOG_ERR_FORMATTED(lboard_data->client, "Error submitting leaderboard entry %u: %s, retrying in %u seconds", lboard_data->id, error_message, delay);

if (!lboard_data->scheduled_callback_data) {
Expand All @@ -3272,7 +3339,8 @@ static void rc_client_submit_leaderboard_entry_callback(const rc_api_server_resp
lboard_data->scheduled_callback_data->related_id = lboard_data->id;
}

lboard_data->scheduled_callback_data->when = clock() + delay * CLOCKS_PER_SEC;
lboard_data->scheduled_callback_data->when =
lboard_data->client->callbacks.get_time_millisecs(lboard_data->client) + delay * 1000;

rc_client_schedule_callback(lboard_data->client, lboard_data->scheduled_callback_data);
return;
Expand Down Expand Up @@ -3548,7 +3616,7 @@ static void rc_client_ping_callback(const rc_api_server_response_t* server_respo
rc_api_destroy_ping_response(&response);
}

static void rc_client_ping(rc_client_scheduled_callback_data_t* callback_data, rc_client_t* client, clock_t now)
static void rc_client_ping(rc_client_scheduled_callback_data_t* callback_data, rc_client_t* client, rc_clock_t now)
{
rc_api_ping_request_t api_params;
rc_api_request_t request;
Expand All @@ -3572,7 +3640,7 @@ static void rc_client_ping(rc_client_scheduled_callback_data_t* callback_data, r
client->callbacks.server_call(&request, rc_client_ping_callback, client, client);
}

callback_data->when = now + 120 * CLOCKS_PER_SEC;
callback_data->when = now + 120 * 1000;
rc_client_schedule_callback(client, callback_data);
}

Expand Down Expand Up @@ -3821,7 +3889,7 @@ static void rc_client_hide_progress_tracker(rc_client_t* client, rc_client_game_
}
}

static void rc_client_progress_tracker_timer_elapsed(rc_client_scheduled_callback_data_t* callback_data, rc_client_t* client, clock_t now)
static void rc_client_progress_tracker_timer_elapsed(rc_client_scheduled_callback_data_t* callback_data, rc_client_t* client, rc_clock_t now)
{
rc_client_event_t client_event;
memset(&client_event, 0, sizeof(client_event));
Expand Down Expand Up @@ -3851,7 +3919,8 @@ static void rc_client_do_frame_update_progress_tracker(rc_client_t* client, rc_c
else
game->progress_tracker.action = RC_CLIENT_PROGRESS_TRACKER_ACTION_UPDATE;

rc_client_reschedule_callback(client, game->progress_tracker.hide_callback, clock() + 2 * CLOCKS_PER_SEC);
rc_client_reschedule_callback(client, game->progress_tracker.hide_callback,
client->callbacks.get_time_millisecs(client) + 2 * 1000);
}

static void rc_client_raise_progress_tracker_events(rc_client_t* client, rc_client_game_info_t* game)
Expand Down Expand Up @@ -4177,13 +4246,13 @@ void rc_client_idle(rc_client_t* client)

scheduled_callback = client->state.scheduled_callbacks;
if (scheduled_callback) {
const clock_t now = clock();
const rc_clock_t now = client->callbacks.get_time_millisecs(client);

do {
rc_mutex_lock(&client->state.mutex);
scheduled_callback = client->state.scheduled_callbacks;
if (scheduled_callback) {
if (RC_CLIENT_CLOCK_IS_BEFORE(now, scheduled_callback->when)) {
if (scheduled_callback->when > now) {
/* not time for next callback yet, ignore it */
scheduled_callback = NULL;
}
Expand Down Expand Up @@ -4212,7 +4281,7 @@ void rc_client_schedule_callback(rc_client_t* client, rc_client_scheduled_callba
last = &client->state.scheduled_callbacks;
do {
next = *last;
if (!next || RC_CLIENT_CLOCK_IS_BEFORE(scheduled_callback->when, next->when)) {
if (!next || scheduled_callback->when < next->when) {
scheduled_callback->next = next;
*last = scheduled_callback;
break;
Expand All @@ -4225,7 +4294,7 @@ void rc_client_schedule_callback(rc_client_t* client, rc_client_scheduled_callba
}

static void rc_client_reschedule_callback(rc_client_t* client,
rc_client_scheduled_callback_data_t* callback, clock_t when)
rc_client_scheduled_callback_data_t* callback, rc_clock_t when)
{
rc_client_scheduled_callback_data_t** last;
rc_client_scheduled_callback_data_t* next;
Expand All @@ -4251,7 +4320,7 @@ static void rc_client_reschedule_callback(rc_client_t* client,
break;
}

if (RC_CLIENT_CLOCK_IS_BEFORE(when, next->next->when)) {
if (when < next->next->when) {
/* already in the correct place */
break;
}
Expand All @@ -4262,7 +4331,7 @@ static void rc_client_reschedule_callback(rc_client_t* client,
continue;
}

if (!next || RC_CLIENT_CLOCK_IS_BEFORE(when, next->when)) {
if (!next || when < next->when) {
/* insert here */
callback->next = next;
*last = callback;
Expand Down
5 changes: 3 additions & 2 deletions deps/rcheevos/src/rcheevos/rc_client_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,17 @@ typedef struct rc_client_callbacks_t {
rc_client_event_handler_t event_handler;
rc_client_server_call_t server_call;
rc_client_message_callback_t log_call;
rc_get_time_millisecs_func_t get_time_millisecs;

void* client_data;
} rc_client_callbacks_t;

struct rc_client_scheduled_callback_data_t;
typedef void (*rc_client_scheduled_callback_t)(struct rc_client_scheduled_callback_data_t* callback_data, rc_client_t* client, clock_t now);
typedef void (*rc_client_scheduled_callback_t)(struct rc_client_scheduled_callback_data_t* callback_data, rc_client_t* client, rc_clock_t now);

typedef struct rc_client_scheduled_callback_data_t
{
clock_t when;
rc_clock_t when;
unsigned related_id;
rc_client_scheduled_callback_t callback;
void* data;
Expand Down

0 comments on commit bcbadd3

Please sign in to comment.