mirror of
https://github.com/stenzek/duckstation.git
synced 2025-06-06 03:25:36 +00:00
dep/rcheevos: Sync with branch
This commit is contained in:
parent
4ec372cd4e
commit
481fba357c
@ -224,6 +224,39 @@ typedef struct rc_client_user_game_summary_t {
|
|||||||
*/
|
*/
|
||||||
RC_EXPORT void RC_CCONV rc_client_get_user_game_summary(const rc_client_t* client, rc_client_user_game_summary_t* summary);
|
RC_EXPORT void RC_CCONV rc_client_get_user_game_summary(const rc_client_t* client, rc_client_user_game_summary_t* summary);
|
||||||
|
|
||||||
|
typedef struct rc_client_all_user_progress_entry_t {
|
||||||
|
uint32_t game_id;
|
||||||
|
uint32_t num_achievements;
|
||||||
|
uint32_t num_unlocked_achievements;
|
||||||
|
uint32_t num_unlocked_achievements_hardcore;
|
||||||
|
} rc_client_all_user_progress_entry_t;
|
||||||
|
|
||||||
|
typedef struct rc_client_all_user_progress_t {
|
||||||
|
rc_client_all_user_progress_entry_t* entries;
|
||||||
|
uint32_t num_entries;
|
||||||
|
} rc_client_all_user_progress_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback that is fired when an all progress query completes. list may be null if the query failed.
|
||||||
|
*/
|
||||||
|
typedef void(RC_CCONV* rc_client_fetch_all_user_progress_callback_t)(int result, const char* error_message,
|
||||||
|
rc_client_all_user_progress_t* list,
|
||||||
|
rc_client_t* client, void* callback_userdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts an asynchronous request for all progress for the given console.
|
||||||
|
* This query returns the total number of achievements for all games tracked by this console, as well as
|
||||||
|
* the user's achievement unlock count for both softcore and hardcore modes.
|
||||||
|
*/
|
||||||
|
RC_EXPORT rc_client_async_handle_t* RC_CCONV
|
||||||
|
rc_client_begin_fetch_all_user_progress(rc_client_t* client, uint32_t console_id,
|
||||||
|
rc_client_fetch_all_user_progress_callback_t callback, void* callback_userdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys a previously-allocated result from the rc_client_begin_fetch_all_progress_list() callback.
|
||||||
|
*/
|
||||||
|
RC_EXPORT void RC_CCONV rc_client_destroy_all_user_progress(rc_client_all_user_progress_t* list);
|
||||||
|
|
||||||
/*****************************************************************************\
|
/*****************************************************************************\
|
||||||
| Game |
|
| Game |
|
||||||
\*****************************************************************************/
|
\*****************************************************************************/
|
||||||
@ -326,19 +359,13 @@ RC_EXPORT const rc_client_subset_t* RC_CCONV rc_client_get_subset_info(rc_client
|
|||||||
| Fetch Game Hashes |
|
| Fetch Game Hashes |
|
||||||
\*****************************************************************************/
|
\*****************************************************************************/
|
||||||
|
|
||||||
typedef struct rc_client_hash_library_entry_t
|
typedef struct rc_client_hash_library_entry_t {
|
||||||
{
|
char hash[33];
|
||||||
/* The hash for the game */
|
|
||||||
const char* hash;
|
|
||||||
/* The unique identifier of the game */
|
|
||||||
uint32_t game_id;
|
uint32_t game_id;
|
||||||
} rc_client_hash_library_entry_t;
|
} rc_client_hash_library_entry_t;
|
||||||
|
|
||||||
typedef struct rc_client_hash_library_t
|
typedef struct rc_client_hash_library_t {
|
||||||
{
|
|
||||||
/* An array of entries, one per game */
|
|
||||||
rc_client_hash_library_entry_t* entries;
|
rc_client_hash_library_entry_t* entries;
|
||||||
/* The number of items in the entries array */
|
|
||||||
uint32_t num_entries;
|
uint32_t num_entries;
|
||||||
} rc_client_hash_library_t;
|
} rc_client_hash_library_t;
|
||||||
|
|
||||||
@ -362,51 +389,6 @@ RC_EXPORT rc_client_async_handle_t* RC_CCONV rc_client_begin_fetch_hash_library(
|
|||||||
*/
|
*/
|
||||||
RC_EXPORT void RC_CCONV rc_client_destroy_hash_library(rc_client_hash_library_t* list);
|
RC_EXPORT void RC_CCONV rc_client_destroy_hash_library(rc_client_hash_library_t* list);
|
||||||
|
|
||||||
/*****************************************************************************\
|
|
||||||
| Game Info |
|
|
||||||
\*****************************************************************************/
|
|
||||||
|
|
||||||
typedef struct rc_client_all_user_progress_entry_t
|
|
||||||
{
|
|
||||||
/* The unique identifier of the game */
|
|
||||||
uint32_t game_id;
|
|
||||||
/* The total number of achievements for this game */
|
|
||||||
uint32_t num_achievements;
|
|
||||||
/* The total number of unlocked achievements for this game in softcore mode */
|
|
||||||
uint32_t num_unlocked_achievements;
|
|
||||||
/* The total number of unlocked achievements for this game in hardcore mode */
|
|
||||||
uint32_t num_unlocked_achievements_hardcore;
|
|
||||||
} rc_client_all_user_progress_entry_t;
|
|
||||||
|
|
||||||
typedef struct rc_client_all_user_progress_t
|
|
||||||
{
|
|
||||||
/* An array of entries, one per game */
|
|
||||||
rc_client_all_user_progress_entry_t* entries;
|
|
||||||
/* The number of items in the entries array */
|
|
||||||
uint32_t num_entries;
|
|
||||||
} rc_client_all_user_progress_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback that is fired when an all progress query completes. list may be null if the query failed.
|
|
||||||
*/
|
|
||||||
typedef void(RC_CCONV* rc_client_fetch_all_user_progress_callback_t)(int result, const char* error_message,
|
|
||||||
rc_client_all_user_progress_t* list,
|
|
||||||
rc_client_t* client, void* callback_userdata);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts an asynchronous request for all progress for the given console.
|
|
||||||
* This query returns the total number of achievements for all games tracked by this console, as well as
|
|
||||||
* the user's achievement unlock count for both softcore and hardcore modes.
|
|
||||||
*/
|
|
||||||
RC_EXPORT rc_client_async_handle_t* RC_CCONV
|
|
||||||
rc_client_begin_fetch_all_user_progress(rc_client_t* client, uint32_t console_id,
|
|
||||||
rc_client_fetch_all_user_progress_callback_t callback, void* callback_userdata);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroys a previously-allocated result from the rc_client_begin_fetch_all_progress_list() callback.
|
|
||||||
*/
|
|
||||||
RC_EXPORT void RC_CCONV rc_client_destroy_all_user_progress(rc_client_all_user_progress_t* list);
|
|
||||||
|
|
||||||
/*****************************************************************************\
|
/*****************************************************************************\
|
||||||
| Achievements |
|
| Achievements |
|
||||||
\*****************************************************************************/
|
\*****************************************************************************/
|
||||||
|
@ -511,7 +511,8 @@ int rc_api_init_fetch_hash_library_request_hosted(rc_api_request_t* request,
|
|||||||
/* note: unauthenticated request */
|
/* note: unauthenticated request */
|
||||||
rc_url_builder_init(&builder, &request->buffer, 48);
|
rc_url_builder_init(&builder, &request->buffer, 48);
|
||||||
rc_url_builder_append_str_param(&builder, "r", "hashlibrary");
|
rc_url_builder_append_str_param(&builder, "r", "hashlibrary");
|
||||||
rc_url_builder_append_unum_param(&builder, "c", api_params->console_id);
|
if (api_params->console_id != 0)
|
||||||
|
rc_url_builder_append_unum_param(&builder, "c", api_params->console_id);
|
||||||
|
|
||||||
request->post_data = rc_url_builder_finalize(&builder);
|
request->post_data = rc_url_builder_finalize(&builder);
|
||||||
request->content_type = RC_CONTENT_TYPE_URLENCODED;
|
request->content_type = RC_CONTENT_TYPE_URLENCODED;
|
||||||
|
@ -978,6 +978,126 @@ void rc_client_get_user_game_summary(const rc_client_t* client, rc_client_user_g
|
|||||||
rc_mutex_unlock((rc_mutex_t*)&client->state.mutex); /* remove const cast for mutex access */
|
rc_mutex_unlock((rc_mutex_t*)&client->state.mutex); /* remove const cast for mutex access */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct rc_client_fetch_all_user_progress_callback_data_t {
|
||||||
|
rc_client_t* client;
|
||||||
|
rc_client_fetch_all_user_progress_callback_t callback;
|
||||||
|
void* callback_userdata;
|
||||||
|
uint32_t console_id;
|
||||||
|
rc_client_async_handle_t async_handle;
|
||||||
|
} rc_client_fetch_all_user_progress_callback_data_t;
|
||||||
|
|
||||||
|
static void rc_client_fetch_all_user_progress_callback(const rc_api_server_response_t* server_response,
|
||||||
|
void* callback_data)
|
||||||
|
{
|
||||||
|
rc_client_fetch_all_user_progress_callback_data_t* ap_callback_data =
|
||||||
|
(rc_client_fetch_all_user_progress_callback_data_t*)callback_data;
|
||||||
|
rc_client_t* client = ap_callback_data->client;
|
||||||
|
rc_api_fetch_all_user_progress_response_t ap_response;
|
||||||
|
const char* error_message;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
result = rc_client_end_async(client, &ap_callback_data->async_handle);
|
||||||
|
if (result) {
|
||||||
|
if (result != RC_CLIENT_ASYNC_DESTROYED)
|
||||||
|
RC_CLIENT_LOG_VERBOSE(client, "Fetch all progress aborted");
|
||||||
|
|
||||||
|
free(ap_callback_data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = rc_api_process_fetch_all_user_progress_server_response(&ap_response, server_response);
|
||||||
|
error_message = rc_client_server_error_message(&result, server_response->http_status_code, &ap_response.response);
|
||||||
|
if (error_message) {
|
||||||
|
RC_CLIENT_LOG_ERR_FORMATTED(client, "Fetch all progress for console %u failed: %s", ap_callback_data->console_id,
|
||||||
|
error_message);
|
||||||
|
ap_callback_data->callback(result, error_message, NULL, client, ap_callback_data->callback_userdata);
|
||||||
|
} else {
|
||||||
|
rc_client_all_user_progress_t* list;
|
||||||
|
const size_t list_size = sizeof(*list) + sizeof(rc_client_all_user_progress_entry_t) * ap_response.num_entries;
|
||||||
|
|
||||||
|
list = (rc_client_all_user_progress_t*)malloc(list_size);
|
||||||
|
if (!list) {
|
||||||
|
ap_callback_data->callback(RC_OUT_OF_MEMORY, rc_error_str(RC_OUT_OF_MEMORY), NULL, client,
|
||||||
|
ap_callback_data->callback_userdata);
|
||||||
|
} else {
|
||||||
|
rc_client_all_user_progress_entry_t* entry = list->entries =
|
||||||
|
(rc_client_all_user_progress_entry_t*)((uint8_t*)list + sizeof(*list));
|
||||||
|
const rc_api_all_user_progress_entry_t* hlentry = ap_response.entries;
|
||||||
|
const rc_api_all_user_progress_entry_t* stop = hlentry + ap_response.num_entries;
|
||||||
|
|
||||||
|
for (; hlentry < stop; ++hlentry, ++entry)
|
||||||
|
{
|
||||||
|
entry->game_id = hlentry->game_id;
|
||||||
|
entry->num_achievements = hlentry->num_achievements;
|
||||||
|
entry->num_unlocked_achievements = hlentry->num_unlocked_achievements;
|
||||||
|
entry->num_unlocked_achievements_hardcore = hlentry->num_unlocked_achievements_hardcore;
|
||||||
|
}
|
||||||
|
|
||||||
|
list->num_entries = ap_response.num_entries;
|
||||||
|
|
||||||
|
ap_callback_data->callback(RC_OK, NULL, list, client, ap_callback_data->callback_userdata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_api_destroy_fetch_all_user_progress_response(&ap_response);
|
||||||
|
free(ap_callback_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_client_async_handle_t* rc_client_begin_fetch_all_user_progress(rc_client_t* client, uint32_t console_id,
|
||||||
|
rc_client_fetch_all_user_progress_callback_t callback,
|
||||||
|
void* callback_userdata)
|
||||||
|
{
|
||||||
|
rc_api_fetch_all_user_progress_request_t api_params;
|
||||||
|
rc_client_fetch_all_user_progress_callback_data_t* callback_data;
|
||||||
|
rc_client_async_handle_t* async_handle;
|
||||||
|
rc_api_request_t request;
|
||||||
|
int result;
|
||||||
|
const char* error_message;
|
||||||
|
|
||||||
|
if (!client) {
|
||||||
|
callback(RC_INVALID_STATE, "client is required", NULL, client, callback_userdata);
|
||||||
|
return NULL;
|
||||||
|
} else if (client->state.user != RC_CLIENT_USER_STATE_LOGGED_IN) {
|
||||||
|
callback(RC_INVALID_STATE, "client must be logged in", NULL, client, callback_userdata);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
api_params.username = client->user.username;
|
||||||
|
api_params.api_token = client->user.token;
|
||||||
|
api_params.console_id = console_id;
|
||||||
|
|
||||||
|
result = rc_api_init_fetch_all_user_progress_request_hosted(&request, &api_params, &client->state.host);
|
||||||
|
|
||||||
|
if (result != RC_OK) {
|
||||||
|
error_message = rc_error_str(result);
|
||||||
|
callback(result, error_message, NULL, client, callback_userdata);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback_data = (rc_client_fetch_all_user_progress_callback_data_t*)calloc(1, sizeof(*callback_data));
|
||||||
|
if (!callback_data) {
|
||||||
|
callback(RC_OUT_OF_MEMORY, rc_error_str(RC_OUT_OF_MEMORY), NULL, client, callback_userdata);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback_data->client = client;
|
||||||
|
callback_data->callback = callback;
|
||||||
|
callback_data->callback_userdata = callback_userdata;
|
||||||
|
callback_data->console_id = console_id;
|
||||||
|
|
||||||
|
async_handle = &callback_data->async_handle;
|
||||||
|
rc_client_begin_async(client, async_handle);
|
||||||
|
client->callbacks.server_call(&request, rc_client_fetch_all_user_progress_callback, callback_data, client);
|
||||||
|
rc_api_destroy_request(&request);
|
||||||
|
|
||||||
|
return rc_client_async_handle_valid(client, async_handle) ? async_handle : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rc_client_destroy_all_user_progress(rc_client_all_user_progress_t* list)
|
||||||
|
{
|
||||||
|
free(list);
|
||||||
|
}
|
||||||
|
|
||||||
/* ===== Game ===== */
|
/* ===== Game ===== */
|
||||||
|
|
||||||
static void rc_client_free_game(rc_client_game_info_t* game)
|
static void rc_client_free_game(rc_client_game_info_t* game)
|
||||||
@ -3253,10 +3373,9 @@ const rc_client_subset_t* rc_client_get_subset_info(rc_client_t* client, uint32_
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== Game Info ===== */
|
/* ===== Fetch Game Hashes ===== */
|
||||||
|
|
||||||
typedef struct rc_client_fetch_hash_library_callback_data_t
|
typedef struct rc_client_fetch_hash_library_callback_data_t {
|
||||||
{
|
|
||||||
rc_client_t* client;
|
rc_client_t* client;
|
||||||
rc_client_fetch_hash_library_callback_t callback;
|
rc_client_fetch_hash_library_callback_t callback;
|
||||||
void* callback_userdata;
|
void* callback_userdata;
|
||||||
@ -3274,8 +3393,7 @@ static void rc_client_fetch_hash_library_callback(const rc_api_server_response_t
|
|||||||
int result;
|
int result;
|
||||||
|
|
||||||
result = rc_client_end_async(client, &hashlib_callback_data->async_handle);
|
result = rc_client_end_async(client, &hashlib_callback_data->async_handle);
|
||||||
if (result)
|
if (result) {
|
||||||
{
|
|
||||||
if (result != RC_CLIENT_ASYNC_DESTROYED)
|
if (result != RC_CLIENT_ASYNC_DESTROYED)
|
||||||
RC_CLIENT_LOG_VERBOSE(client, "Fetch hash library aborted");
|
RC_CLIENT_LOG_VERBOSE(client, "Fetch hash library aborted");
|
||||||
|
|
||||||
@ -3286,43 +3404,26 @@ static void rc_client_fetch_hash_library_callback(const rc_api_server_response_t
|
|||||||
result = rc_api_process_fetch_hash_library_server_response(&hashlib_response, server_response);
|
result = rc_api_process_fetch_hash_library_server_response(&hashlib_response, server_response);
|
||||||
error_message =
|
error_message =
|
||||||
rc_client_server_error_message(&result, server_response->http_status_code, &hashlib_response.response);
|
rc_client_server_error_message(&result, server_response->http_status_code, &hashlib_response.response);
|
||||||
if (error_message)
|
if (error_message) {
|
||||||
{
|
|
||||||
RC_CLIENT_LOG_ERR_FORMATTED(client, "Fetch hash library for console %u failed: %s",
|
RC_CLIENT_LOG_ERR_FORMATTED(client, "Fetch hash library for console %u failed: %s",
|
||||||
hashlib_callback_data->console_id, error_message);
|
hashlib_callback_data->console_id, error_message);
|
||||||
hashlib_callback_data->callback(result, error_message, NULL, client, hashlib_callback_data->callback_userdata);
|
hashlib_callback_data->callback(result, error_message, NULL, client, hashlib_callback_data->callback_userdata);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
rc_client_hash_library_t* list;
|
rc_client_hash_library_t* list;
|
||||||
const size_t list_size = sizeof(*list) + sizeof(rc_client_hash_library_entry_t) * hashlib_response.num_entries;
|
const size_t list_size = sizeof(*list) + sizeof(rc_client_hash_library_entry_t) * hashlib_response.num_entries;
|
||||||
size_t needed_size = list_size;
|
list = (rc_client_hash_library_t*)malloc(list_size);
|
||||||
uint32_t i;
|
if (!list) {
|
||||||
|
|
||||||
for (i = 0; i < hashlib_response.num_entries; i++)
|
|
||||||
needed_size += strlen(hashlib_response.entries[i].hash) + 1;
|
|
||||||
|
|
||||||
list = (rc_client_hash_library_t*)malloc(needed_size);
|
|
||||||
if (!list)
|
|
||||||
{
|
|
||||||
hashlib_callback_data->callback(RC_OUT_OF_MEMORY, rc_error_str(RC_OUT_OF_MEMORY), NULL, client,
|
hashlib_callback_data->callback(RC_OUT_OF_MEMORY, rc_error_str(RC_OUT_OF_MEMORY), NULL, client,
|
||||||
hashlib_callback_data->callback_userdata);
|
hashlib_callback_data->callback_userdata);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
rc_client_hash_library_entry_t* entry = list->entries =
|
rc_client_hash_library_entry_t* entry = list->entries =
|
||||||
(rc_client_hash_library_entry_t*)((uint8_t*)list + sizeof(*list));
|
(rc_client_hash_library_entry_t*)((uint8_t*)list + sizeof(*list));
|
||||||
char* hash = (char*)((uint8_t*)list + list_size);
|
|
||||||
const rc_api_hash_library_entry_t* hlentry = hashlib_response.entries;
|
const rc_api_hash_library_entry_t* hlentry = hashlib_response.entries;
|
||||||
const rc_api_hash_library_entry_t* stop = hlentry + hashlib_response.num_entries;
|
const rc_api_hash_library_entry_t* stop = hlentry + hashlib_response.num_entries;
|
||||||
|
|
||||||
for (; hlentry < stop; ++hlentry, ++entry)
|
for (; hlentry < stop; ++hlentry, ++entry) {
|
||||||
{
|
snprintf(entry->hash, sizeof(entry->hash), "%s", hlentry->hash);
|
||||||
const size_t len = strlen(hlentry->hash) + 1;
|
|
||||||
entry->hash = hash;
|
|
||||||
entry->game_id = hlentry->game_id;
|
entry->game_id = hlentry->game_id;
|
||||||
memcpy(hash, hlentry->hash, len);
|
|
||||||
hash += len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
list->num_entries = hashlib_response.num_entries;
|
list->num_entries = hashlib_response.num_entries;
|
||||||
@ -3346,8 +3447,7 @@ rc_client_async_handle_t* rc_client_begin_fetch_hash_library(rc_client_t* client
|
|||||||
int result;
|
int result;
|
||||||
const char* error_message;
|
const char* error_message;
|
||||||
|
|
||||||
if (!client)
|
if (!client) {
|
||||||
{
|
|
||||||
callback(RC_INVALID_STATE, "client is required", NULL, client, callback_userdata);
|
callback(RC_INVALID_STATE, "client is required", NULL, client, callback_userdata);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -3355,16 +3455,14 @@ rc_client_async_handle_t* rc_client_begin_fetch_hash_library(rc_client_t* client
|
|||||||
api_params.console_id = console_id;
|
api_params.console_id = console_id;
|
||||||
result = rc_api_init_fetch_hash_library_request_hosted(&request, &api_params, &client->state.host);
|
result = rc_api_init_fetch_hash_library_request_hosted(&request, &api_params, &client->state.host);
|
||||||
|
|
||||||
if (result != RC_OK)
|
if (result != RC_OK) {
|
||||||
{
|
|
||||||
error_message = rc_error_str(result);
|
error_message = rc_error_str(result);
|
||||||
callback(result, error_message, NULL, client, callback_userdata);
|
callback(result, error_message, NULL, client, callback_userdata);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
callback_data = (rc_client_fetch_hash_library_callback_data_t*)calloc(1, sizeof(*callback_data));
|
callback_data = (rc_client_fetch_hash_library_callback_data_t*)calloc(1, sizeof(*callback_data));
|
||||||
if (!callback_data)
|
if (!callback_data) {
|
||||||
{
|
|
||||||
callback(RC_OUT_OF_MEMORY, rc_error_str(RC_OUT_OF_MEMORY), NULL, client, callback_userdata);
|
callback(RC_OUT_OF_MEMORY, rc_error_str(RC_OUT_OF_MEMORY), NULL, client, callback_userdata);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -3387,141 +3485,6 @@ void rc_client_destroy_hash_library(rc_client_hash_library_t* list)
|
|||||||
free(list);
|
free(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== Fetch Game Hashes ===== */
|
|
||||||
|
|
||||||
typedef struct rc_client_fetch_all_user_progress_callback_data_t
|
|
||||||
{
|
|
||||||
rc_client_t* client;
|
|
||||||
rc_client_fetch_all_user_progress_callback_t callback;
|
|
||||||
void* callback_userdata;
|
|
||||||
uint32_t console_id;
|
|
||||||
rc_client_async_handle_t async_handle;
|
|
||||||
} rc_client_fetch_all_user_progress_callback_data_t;
|
|
||||||
|
|
||||||
static void rc_client_fetch_all_user_progress_callback(const rc_api_server_response_t* server_response,
|
|
||||||
void* callback_data)
|
|
||||||
{
|
|
||||||
rc_client_fetch_all_user_progress_callback_data_t* ap_callback_data =
|
|
||||||
(rc_client_fetch_all_user_progress_callback_data_t*)callback_data;
|
|
||||||
rc_client_t* client = ap_callback_data->client;
|
|
||||||
rc_api_fetch_all_user_progress_response_t ap_response;
|
|
||||||
const char* error_message;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
result = rc_client_end_async(client, &ap_callback_data->async_handle);
|
|
||||||
if (result)
|
|
||||||
{
|
|
||||||
if (result != RC_CLIENT_ASYNC_DESTROYED)
|
|
||||||
RC_CLIENT_LOG_VERBOSE(client, "Fetch all progress aborted");
|
|
||||||
|
|
||||||
free(ap_callback_data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = rc_api_process_fetch_all_user_progress_server_response(&ap_response, server_response);
|
|
||||||
error_message = rc_client_server_error_message(&result, server_response->http_status_code, &ap_response.response);
|
|
||||||
if (error_message)
|
|
||||||
{
|
|
||||||
RC_CLIENT_LOG_ERR_FORMATTED(client, "Fetch all progress for console %u failed: %s", ap_callback_data->console_id,
|
|
||||||
error_message);
|
|
||||||
ap_callback_data->callback(result, error_message, NULL, client, ap_callback_data->callback_userdata);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rc_client_all_user_progress_t* list;
|
|
||||||
const size_t list_size = sizeof(*list) + sizeof(rc_client_all_user_progress_entry_t) * ap_response.num_entries;
|
|
||||||
|
|
||||||
list = (rc_client_all_user_progress_t*)malloc(list_size);
|
|
||||||
if (!list)
|
|
||||||
{
|
|
||||||
ap_callback_data->callback(RC_OUT_OF_MEMORY, rc_error_str(RC_OUT_OF_MEMORY), NULL, client,
|
|
||||||
ap_callback_data->callback_userdata);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rc_client_all_user_progress_entry_t* entry = list->entries =
|
|
||||||
(rc_client_all_user_progress_entry_t*)((uint8_t*)list + sizeof(*list));
|
|
||||||
const rc_api_all_user_progress_entry_t* hlentry = ap_response.entries;
|
|
||||||
const rc_api_all_user_progress_entry_t* stop = hlentry + ap_response.num_entries;
|
|
||||||
|
|
||||||
for (; hlentry < stop; ++hlentry, ++entry)
|
|
||||||
{
|
|
||||||
entry->game_id = hlentry->game_id;
|
|
||||||
entry->num_achievements = hlentry->num_achievements;
|
|
||||||
entry->num_unlocked_achievements = hlentry->num_unlocked_achievements;
|
|
||||||
entry->num_unlocked_achievements_hardcore = hlentry->num_unlocked_achievements_hardcore;
|
|
||||||
}
|
|
||||||
|
|
||||||
list->num_entries = ap_response.num_entries;
|
|
||||||
|
|
||||||
ap_callback_data->callback(RC_OK, NULL, list, client, ap_callback_data->callback_userdata);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rc_api_destroy_fetch_all_user_progress_response(&ap_response);
|
|
||||||
free(ap_callback_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
rc_client_async_handle_t* rc_client_begin_fetch_all_user_progress(rc_client_t* client, uint32_t console_id,
|
|
||||||
rc_client_fetch_all_user_progress_callback_t callback,
|
|
||||||
void* callback_userdata)
|
|
||||||
{
|
|
||||||
rc_api_fetch_all_user_progress_request_t api_params;
|
|
||||||
rc_client_fetch_all_user_progress_callback_data_t* callback_data;
|
|
||||||
rc_client_async_handle_t* async_handle;
|
|
||||||
rc_api_request_t request;
|
|
||||||
int result;
|
|
||||||
const char* error_message;
|
|
||||||
|
|
||||||
if (!client)
|
|
||||||
{
|
|
||||||
callback(RC_INVALID_STATE, "client is required", NULL, client, callback_userdata);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
else if (client->state.user != RC_CLIENT_USER_STATE_LOGGED_IN)
|
|
||||||
{
|
|
||||||
callback(RC_INVALID_STATE, "client must be logged in", NULL, client, callback_userdata);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
api_params.username = client->user.username;
|
|
||||||
api_params.api_token = client->user.token;
|
|
||||||
api_params.console_id = console_id;
|
|
||||||
|
|
||||||
result = rc_api_init_fetch_all_user_progress_request_hosted(&request, &api_params, &client->state.host);
|
|
||||||
|
|
||||||
if (result != RC_OK)
|
|
||||||
{
|
|
||||||
error_message = rc_error_str(result);
|
|
||||||
callback(result, error_message, NULL, client, callback_userdata);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
callback_data = (rc_client_fetch_all_user_progress_callback_data_t*)calloc(1, sizeof(*callback_data));
|
|
||||||
if (!callback_data)
|
|
||||||
{
|
|
||||||
callback(RC_OUT_OF_MEMORY, rc_error_str(RC_OUT_OF_MEMORY), NULL, client, callback_userdata);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
callback_data->client = client;
|
|
||||||
callback_data->callback = callback;
|
|
||||||
callback_data->callback_userdata = callback_userdata;
|
|
||||||
callback_data->console_id = console_id;
|
|
||||||
|
|
||||||
async_handle = &callback_data->async_handle;
|
|
||||||
rc_client_begin_async(client, async_handle);
|
|
||||||
client->callbacks.server_call(&request, rc_client_fetch_all_user_progress_callback, callback_data, client);
|
|
||||||
rc_api_destroy_request(&request);
|
|
||||||
|
|
||||||
return rc_client_async_handle_valid(client, async_handle) ? async_handle : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rc_client_destroy_all_user_progress(rc_client_all_user_progress_t* list)
|
|
||||||
{
|
|
||||||
free(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ===== Achievements ===== */
|
/* ===== Achievements ===== */
|
||||||
|
|
||||||
static void rc_client_update_achievement_display_information(rc_client_t* client, rc_client_achievement_info_t* achievement, time_t recent_unlock_time)
|
static void rc_client_update_achievement_display_information(rc_client_t* client, rc_client_achievement_info_t* achievement, time_t recent_unlock_time)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user