Achievements: Tidy up API calls

This commit is contained in:
Stenzek 2025-05-11 14:07:31 +10:00
parent aee66edd6e
commit 6cde51b7b5
No known key found for this signature in database
7 changed files with 142 additions and 129 deletions

View File

@ -239,7 +239,10 @@ RC_EXPORT void RC_CCONV rc_api_destroy_fetch_game_titles_response(rc_api_fetch_g
* API parameters for a fetch games list request. * API parameters for a fetch games list request.
*/ */
typedef struct rc_api_fetch_hash_library_request_t { typedef struct rc_api_fetch_hash_library_request_t {
/* The unique identifier of the console to query */ /**
* The unique identifier of the console to query.
* Passing RC_CONSOLE_UNKNOWN will return hashes for all consoles.
*/
uint32_t console_id; uint32_t console_id;
} rc_api_fetch_hash_library_request_t; } rc_api_fetch_hash_library_request_t;

View File

@ -216,19 +216,19 @@ RC_EXPORT void RC_CCONV rc_api_destroy_fetch_followed_users_response(rc_api_fetc
/* --- Fetch All Progress --- */ /* --- Fetch All Progress --- */
/** /**
* API parameters for a fetch all progress request. * API parameters for a fetch all user progress request.
*/ */
typedef struct rc_api_fetch_all_progress_request_t { typedef struct rc_api_fetch_all_user_progress_request_t {
/* The username of the player */ /* The username of the player */
const char* username; const char* username;
/* The API token from the login request */ /* The API token from the login request */
const char* api_token; const char* api_token;
/* The unique identifier of the console to query */ /* The unique identifier of the console to query */
uint32_t console_id; uint32_t console_id;
} rc_api_fetch_all_progress_request_t; } rc_api_fetch_all_user_progress_request_t;
/* An all-progress entry */ /* An all-user-progress entry */
typedef struct rc_api_all_progress_entry_t { typedef struct rc_api_all_user_progress_entry_t {
/* The unique identifier of the game */ /* The unique identifier of the game */
uint32_t game_id; uint32_t game_id;
/* The total number of achievements for this game */ /* The total number of achievements for this game */
@ -237,25 +237,25 @@ typedef struct rc_api_all_progress_entry_t {
uint32_t num_unlocked_achievements; uint32_t num_unlocked_achievements;
/* The total number of unlocked achievements for this game in hardcore mode */ /* The total number of unlocked achievements for this game in hardcore mode */
uint32_t num_unlocked_achievements_hardcore; uint32_t num_unlocked_achievements_hardcore;
} rc_api_all_progress_entry_t; } rc_api_all_user_progress_entry_t;
/** /**
* Response data for a fetch all progress request. * Response data for a fetch all user progress request.
*/ */
typedef struct rc_api_fetch_all_progress_response_t { typedef struct rc_api_fetch_all_user_progress_response_t {
/* An array of entries, one per game */ /* An array of entries, one per game */
rc_api_all_progress_entry_t* entries; rc_api_all_user_progress_entry_t* entries;
/* The number of items in the entries array */ /* The number of items in the entries array */
uint32_t num_entries; uint32_t num_entries;
/* Common server-provided response information */ /* Common server-provided response information */
rc_api_response_t response; rc_api_response_t response;
} rc_api_fetch_all_progress_response_t; } rc_api_fetch_all_user_progress_response_t;
RC_EXPORT int RC_CCONV rc_api_init_fetch_all_progress_request(rc_api_request_t* request, const rc_api_fetch_all_progress_request_t* api_params); RC_EXPORT int RC_CCONV rc_api_init_fetch_all_user_progress_request(rc_api_request_t* request, const rc_api_fetch_all_user_progress_request_t* api_params);
RC_EXPORT int RC_CCONV rc_api_init_fetch_all_progress_request_hosted(rc_api_request_t* request, const rc_api_fetch_all_progress_request_t* api_params, const rc_api_host_t* host); RC_EXPORT int RC_CCONV rc_api_init_fetch_all_user_progress_request_hosted(rc_api_request_t* request, const rc_api_fetch_all_user_progress_request_t* api_params, const rc_api_host_t* host);
RC_EXPORT int RC_CCONV rc_api_process_fetch_all_progress_server_response(rc_api_fetch_all_progress_response_t* response, const rc_api_server_response_t* server_response); RC_EXPORT int RC_CCONV rc_api_process_fetch_all_user_progress_server_response(rc_api_fetch_all_user_progress_response_t* response, const rc_api_server_response_t* server_response);
RC_EXPORT void RC_CCONV rc_api_destroy_fetch_all_progress_response(rc_api_fetch_all_progress_response_t* response); RC_EXPORT void RC_CCONV rc_api_destroy_fetch_all_user_progress_response(rc_api_fetch_all_user_progress_response_t* response);
RC_END_C_DECLS RC_END_C_DECLS

View File

@ -323,7 +323,7 @@ typedef struct rc_client_subset_t {
RC_EXPORT const rc_client_subset_t* RC_CCONV rc_client_get_subset_info(rc_client_t* client, uint32_t subset_id); RC_EXPORT const rc_client_subset_t* RC_CCONV rc_client_get_subset_info(rc_client_t* client, uint32_t subset_id);
/*****************************************************************************\ /*****************************************************************************\
| Game Info | | Fetch Game Hashes |
\*****************************************************************************/ \*****************************************************************************/
typedef struct rc_client_hash_library_entry_t typedef struct rc_client_hash_library_entry_t
@ -357,13 +357,16 @@ typedef void(RC_CCONV* rc_client_fetch_hash_library_callback_t)(int result, cons
RC_EXPORT rc_client_async_handle_t* RC_CCONV rc_client_begin_fetch_hash_library( RC_EXPORT rc_client_async_handle_t* RC_CCONV rc_client_begin_fetch_hash_library(
rc_client_t* client, uint32_t console_id, rc_client_fetch_hash_library_callback_t callback, void* callback_userdata); rc_client_t* client, uint32_t console_id, rc_client_fetch_hash_library_callback_t callback, void* callback_userdata);
/** /**
* Destroys a previously-allocated result from the rc_client_destroy_hash_library() callback. * Destroys a previously-allocated result from the rc_client_destroy_hash_library() callback.
*/ */
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);
typedef struct rc_client_all_progress_list_entry_t /*****************************************************************************\
| Game Info |
\*****************************************************************************/
typedef struct rc_client_all_user_progress_entry_t
{ {
/* The unique identifier of the game */ /* The unique identifier of the game */
uint32_t game_id; uint32_t game_id;
@ -373,21 +376,21 @@ typedef struct rc_client_all_progress_list_entry_t
uint32_t num_unlocked_achievements; uint32_t num_unlocked_achievements;
/* The total number of unlocked achievements for this game in hardcore mode */ /* The total number of unlocked achievements for this game in hardcore mode */
uint32_t num_unlocked_achievements_hardcore; uint32_t num_unlocked_achievements_hardcore;
} rc_client_all_progress_list_entry_t; } rc_client_all_user_progress_entry_t;
typedef struct rc_client_all_progress_list_t typedef struct rc_client_all_user_progress_t
{ {
/* An array of entries, one per game */ /* An array of entries, one per game */
rc_client_all_progress_list_entry_t* entries; rc_client_all_user_progress_entry_t* entries;
/* The number of items in the entries array */ /* The number of items in the entries array */
uint32_t num_entries; uint32_t num_entries;
} rc_client_all_progress_list_t; } rc_client_all_user_progress_t;
/** /**
* Callback that is fired when an all progress query completes. list may be null if the query failed. * 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_progress_list_callback_t)(int result, const char* error_message, typedef void(RC_CCONV* rc_client_fetch_all_user_progress_callback_t)(int result, const char* error_message,
rc_client_all_progress_list_t* list, rc_client_all_user_progress_t* list,
rc_client_t* client, void* callback_userdata); rc_client_t* client, void* callback_userdata);
/** /**
@ -396,13 +399,13 @@ typedef void(RC_CCONV* rc_client_fetch_all_progress_list_callback_t)(int result,
* the user's achievement unlock count for both softcore and hardcore modes. * the user's achievement unlock count for both softcore and hardcore modes.
*/ */
RC_EXPORT rc_client_async_handle_t* RC_CCONV RC_EXPORT rc_client_async_handle_t* RC_CCONV
rc_client_begin_fetch_all_progress_list(rc_client_t* client, uint32_t console_id, rc_client_begin_fetch_all_user_progress(rc_client_t* client, uint32_t console_id,
rc_client_fetch_all_progress_list_callback_t callback, void* callback_userdata); 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. * Destroys a previously-allocated result from the rc_client_begin_fetch_all_progress_list() callback.
*/ */
RC_EXPORT void RC_CCONV rc_client_destroy_all_progress_list(rc_client_all_progress_list_t* list); RC_EXPORT void RC_CCONV rc_client_destroy_all_user_progress(rc_client_all_user_progress_t* list);
/*****************************************************************************\ /*****************************************************************************\
| Achievements | | Achievements |

View File

@ -2,7 +2,6 @@
#include "rc_api_common.h" #include "rc_api_common.h"
#include "rc_api_runtime.h" #include "rc_api_runtime.h"
#include "rc_consoles.h"
#include "rc_runtime_types.h" #include "rc_runtime_types.h"
#include "../rc_compat.h" #include "../rc_compat.h"
@ -509,9 +508,7 @@ int rc_api_init_fetch_hash_library_request_hosted(rc_api_request_t* request,
rc_api_url_builder_t builder; rc_api_url_builder_t builder;
rc_api_url_build_dorequest_url(request, host); rc_api_url_build_dorequest_url(request, host);
if (api_params->console_id == RC_CONSOLE_UNKNOWN) /* note: unauthenticated request */
return RC_INVALID_STATE;
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); rc_url_builder_append_unum_param(&builder, "c", api_params->console_id);
@ -529,7 +526,6 @@ int rc_api_process_fetch_hash_library_server_response(rc_api_fetch_hash_library_
rc_json_iterator_t iterator; rc_json_iterator_t iterator;
rc_json_field_t field; rc_json_field_t field;
int result; int result;
char* end;
rc_json_field_t fields[] = { rc_json_field_t fields[] = {
RC_JSON_NEW_FIELD("Success"), RC_JSON_NEW_FIELD("Success"),
@ -545,36 +541,36 @@ int rc_api_process_fetch_hash_library_server_response(rc_api_fetch_hash_library_
if (result != RC_OK) if (result != RC_OK)
return result; return result;
if (!fields[2].value_start) if (!fields[2].value_start) {
{
/* call rc_json_get_required_object to generate the error message */ /* call rc_json_get_required_object to generate the error message */
rc_json_get_required_object(NULL, 0, &response->response, &fields[2], "MD5List"); rc_json_get_required_object(NULL, 0, &response->response, &fields[2], "MD5List");
return RC_MISSING_VALUE; return RC_MISSING_VALUE;
} }
response->num_entries = fields[2].array_size; response->num_entries = fields[2].array_size;
rc_buffer_reserve(&response->response.buffer, response->num_entries * (32 + sizeof(rc_api_hash_library_entry_t))); if (response->num_entries > 0) {
rc_buffer_reserve(&response->response.buffer, response->num_entries * (32 + sizeof(rc_api_hash_library_entry_t)));
response->entries = (rc_api_hash_library_entry_t*)rc_buffer_alloc( response->entries = (rc_api_hash_library_entry_t*)rc_buffer_alloc(
&response->response.buffer, response->num_entries * sizeof(rc_api_hash_library_entry_t)); &response->response.buffer, response->num_entries * sizeof(rc_api_hash_library_entry_t));
if (!response->entries) if (!response->entries)
return RC_OUT_OF_MEMORY; return RC_OUT_OF_MEMORY;
memset(&iterator, 0, sizeof(iterator)); memset(&iterator, 0, sizeof(iterator));
iterator.json = fields[2].value_start; iterator.json = fields[2].value_start;
iterator.end = fields[2].value_end; iterator.end = fields[2].value_end;
entry = response->entries; entry = response->entries;
while (rc_json_get_next_object_field(&iterator, &field)) while (rc_json_get_next_object_field(&iterator, &field)) {
{ /* TODO: This isn't handling escape characters in the key, the RC JSON parsing functions have no method for it. */
/* TODO: This isn't handling escape characters in the key, the RC JSON parsing functions have no method for it. */ entry->hash = rc_buffer_strncpy(&response->response.buffer, field.name, field.name_len);
entry->hash = rc_buffer_strncpy(&response->response.buffer, field.name, field.name_len);
field.name = ""; field.name = "";
if (!rc_json_get_unum(&entry->game_id, &field, "")) if (!rc_json_get_unum(&entry->game_id, &field, ""))
return RC_MISSING_VALUE; return RC_MISSING_VALUE;
++entry; ++entry;
}
} }
return RC_OK; return RC_OK;

View File

@ -376,15 +376,15 @@ void rc_api_destroy_fetch_followed_users_response(rc_api_fetch_followed_users_re
/* --- Fetch All Progress --- */ /* --- Fetch All Progress --- */
int rc_api_init_fetch_all_progress_request(rc_api_request_t* request, int rc_api_init_fetch_all_user_progress_request(rc_api_request_t* request,
const rc_api_fetch_all_progress_request_t* api_params) const rc_api_fetch_all_user_progress_request_t* api_params)
{ {
return rc_api_init_fetch_all_progress_request_hosted(request, api_params, &g_host); return rc_api_init_fetch_all_user_progress_request_hosted(request, api_params, &g_host);
} }
int rc_api_init_fetch_all_progress_request_hosted(rc_api_request_t* request, int rc_api_init_fetch_all_user_progress_request_hosted(rc_api_request_t* request,
const rc_api_fetch_all_progress_request_t* api_params, const rc_api_fetch_all_user_progress_request_t* api_params,
const rc_api_host_t* host) const rc_api_host_t* host)
{ {
rc_api_url_builder_t builder; rc_api_url_builder_t builder;
@ -404,14 +404,11 @@ int rc_api_init_fetch_all_progress_request_hosted(rc_api_request_t* request,
return builder.result; return builder.result;
} }
int rc_api_process_fetch_all_progress_server_response(rc_api_fetch_all_progress_response_t* response, int rc_api_process_fetch_all_user_progress_server_response(rc_api_fetch_all_user_progress_response_t* response,
const rc_api_server_response_t* server_response) const rc_api_server_response_t* server_response)
{ {
rc_api_all_progress_entry_t* entry; rc_api_all_user_progress_entry_t* entry;
rc_json_iterator_t iterator;
rc_json_field_t field;
int result; int result;
char* end;
rc_json_field_t fields[] = { rc_json_field_t fields[] = {
RC_JSON_NEW_FIELD("Success"), RC_JSON_NEW_FIELD("Success"),
@ -430,51 +427,57 @@ int rc_api_process_fetch_all_progress_server_response(rc_api_fetch_all_progress_
result = result =
rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0])); rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
if (result != RC_OK) if (result != RC_OK || !response->response.succeeded)
return result; return result;
if (!fields[2].value_start) if (!fields[2].value_start) {
{
/* call rc_json_get_required_object to generate the error message */ /* call rc_json_get_required_object to generate the error message */
rc_json_get_required_object(NULL, 0, &response->response, &fields[2], "Response"); rc_json_get_required_object(NULL, 0, &response->response, &fields[2], "Response");
return RC_MISSING_VALUE; return RC_MISSING_VALUE;
} }
response->num_entries = fields[2].array_size; response->num_entries = fields[2].array_size;
rc_buffer_reserve(&response->response.buffer, response->num_entries * sizeof(rc_api_all_progress_entry_t));
response->entries = (rc_api_all_progress_entry_t*)rc_buffer_alloc( if (response->num_entries > 0) {
&response->response.buffer, response->num_entries * sizeof(rc_api_all_progress_entry_t)); rc_json_iterator_t iterator;
if (!response->entries) rc_json_field_t field;
return RC_OUT_OF_MEMORY; char* end;
memset(&iterator, 0, sizeof(iterator)); rc_buffer_reserve(&response->response.buffer, response->num_entries * sizeof(rc_api_all_user_progress_entry_t));
iterator.json = fields[2].value_start;
iterator.end = fields[2].value_end;
entry = response->entries; response->entries = (rc_api_all_user_progress_entry_t*)rc_buffer_alloc(
while (rc_json_get_next_object_field(&iterator, &field)) &response->response.buffer, response->num_entries * sizeof(rc_api_all_user_progress_entry_t));
{ if (!response->entries)
entry->game_id = strtol(field.name, &end, 10); return RC_OUT_OF_MEMORY;
field.name = ""; memset(&iterator, 0, sizeof(iterator));
if (!rc_json_get_required_object(entry_fields, sizeof(entry_fields) / sizeof(entry_fields[0]), response, &field, iterator.json = fields[2].value_start;
"")) iterator.end = fields[2].value_end;
entry = response->entries;
while (rc_json_get_next_object_field(&iterator, &field))
{ {
return RC_MISSING_VALUE; entry->game_id = strtol(field.name, &end, 10);
field.name = "";
if (!rc_json_get_required_object(entry_fields, sizeof(entry_fields) / sizeof(entry_fields[0]),
&response->response, &field, ""))
{
return RC_MISSING_VALUE;
}
rc_json_get_optional_unum(&entry->num_achievements, &entry_fields[0], "Achievements", 0);
rc_json_get_optional_unum(&entry->num_unlocked_achievements, &entry_fields[1], "Unlocked", 0);
rc_json_get_optional_unum(&entry->num_unlocked_achievements_hardcore, &entry_fields[2], "UnlockedHardcore", 0);
++entry;
} }
rc_json_get_optional_unum(&entry->num_achievements, &entry_fields[0], "Achievements", 0);
rc_json_get_optional_unum(&entry->num_unlocked_achievements, &entry_fields[1], "Unlocked", 0);
rc_json_get_optional_unum(&entry->num_unlocked_achievements_hardcore, &entry_fields[2], "UnlockedHardcore", 0);
++entry;
} }
return RC_OK; return RC_OK;
} }
void rc_api_destroy_fetch_all_progress_response(rc_api_fetch_all_progress_response_t* response) void rc_api_destroy_fetch_all_user_progress_response(rc_api_fetch_all_user_progress_response_t* response)
{ {
rc_buffer_destroy(&response->response.buffer); rc_buffer_destroy(&response->response.buffer);
} }

View File

@ -3247,7 +3247,7 @@ static void rc_client_fetch_hash_library_callback(const rc_api_server_response_t
else else
{ {
rc_client_hash_library_t* list; rc_client_hash_library_t* list;
const size_t list_size = sizeof(*list) + sizeof(rc_client_leaderboard_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; size_t needed_size = list_size;
uint32_t i; uint32_t i;
@ -3339,21 +3339,24 @@ void rc_client_destroy_hash_library(rc_client_hash_library_t* list)
free(list); free(list);
} }
typedef struct rc_client_fetch_all_progress_callback_data_t /* ===== Fetch Game Hashes ===== */
typedef struct rc_client_fetch_all_user_progress_callback_data_t
{ {
rc_client_t* client; rc_client_t* client;
rc_client_fetch_all_progress_list_callback_t callback; rc_client_fetch_all_user_progress_callback_t callback;
void* callback_userdata; void* callback_userdata;
uint32_t console_id; uint32_t console_id;
rc_client_async_handle_t async_handle; rc_client_async_handle_t async_handle;
} rc_client_fetch_all_progress_callback_data_t; } rc_client_fetch_all_user_progress_callback_data_t;
static void rc_client_fetch_all_progress_callback(const rc_api_server_response_t* server_response, void* callback_data) static void rc_client_fetch_all_user_progress_callback(const rc_api_server_response_t* server_response,
void* callback_data)
{ {
rc_client_fetch_all_progress_callback_data_t* ap_callback_data = rc_client_fetch_all_user_progress_callback_data_t* ap_callback_data =
(rc_client_fetch_all_progress_callback_data_t*)callback_data; (rc_client_fetch_all_user_progress_callback_data_t*)callback_data;
rc_client_t* client = ap_callback_data->client; rc_client_t* client = ap_callback_data->client;
rc_api_fetch_all_progress_response_t ap_response; rc_api_fetch_all_user_progress_response_t ap_response;
const char* error_message; const char* error_message;
int result; int result;
@ -3367,7 +3370,7 @@ static void rc_client_fetch_all_progress_callback(const rc_api_server_response_t
return; return;
} }
result = rc_api_process_fetch_all_progress_server_response(&ap_response, server_response); 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); error_message = rc_client_server_error_message(&result, server_response->http_status_code, &ap_response.response);
if (error_message) if (error_message)
{ {
@ -3377,10 +3380,10 @@ static void rc_client_fetch_all_progress_callback(const rc_api_server_response_t
} }
else else
{ {
rc_client_all_progress_list_t* list; rc_client_all_user_progress_t* list;
const size_t list_size = sizeof(*list) + sizeof(rc_client_all_progress_list_entry_t) * ap_response.num_entries; const size_t list_size = sizeof(*list) + sizeof(rc_client_all_user_progress_entry_t) * ap_response.num_entries;
list = (rc_client_all_progress_list_t*)malloc(list_size); list = (rc_client_all_user_progress_t*)malloc(list_size);
if (!list) if (!list)
{ {
ap_callback_data->callback(RC_OUT_OF_MEMORY, rc_error_str(RC_OUT_OF_MEMORY), NULL, client, ap_callback_data->callback(RC_OUT_OF_MEMORY, rc_error_str(RC_OUT_OF_MEMORY), NULL, client,
@ -3388,10 +3391,10 @@ static void rc_client_fetch_all_progress_callback(const rc_api_server_response_t
} }
else else
{ {
rc_client_all_progress_list_entry_t* entry = list->entries = rc_client_all_user_progress_entry_t* entry = list->entries =
(rc_client_all_progress_list_entry_t*)((uint8_t*)list + sizeof(*list)); (rc_client_all_user_progress_entry_t*)((uint8_t*)list + sizeof(*list));
const rc_api_all_progress_entry_t* hlentry = ap_response.entries; const rc_api_all_user_progress_entry_t* hlentry = ap_response.entries;
const rc_api_all_progress_entry_t* stop = hlentry + ap_response.num_entries; const rc_api_all_user_progress_entry_t* stop = hlentry + ap_response.num_entries;
for (; hlentry < stop; ++hlentry, ++entry) for (; hlentry < stop; ++hlentry, ++entry)
{ {
@ -3407,16 +3410,16 @@ static void rc_client_fetch_all_progress_callback(const rc_api_server_response_t
} }
} }
rc_api_destroy_fetch_all_progress_response(&ap_response); rc_api_destroy_fetch_all_user_progress_response(&ap_response);
free(ap_callback_data); free(ap_callback_data);
} }
rc_client_async_handle_t* rc_client_begin_fetch_all_progress_list(rc_client_t* client, uint32_t console_id, rc_client_async_handle_t* rc_client_begin_fetch_all_user_progress(rc_client_t* client, uint32_t console_id,
rc_client_fetch_all_progress_list_callback_t callback, rc_client_fetch_all_user_progress_callback_t callback,
void* callback_userdata) void* callback_userdata)
{ {
rc_api_fetch_all_progress_request_t api_params; rc_api_fetch_all_user_progress_request_t api_params;
rc_client_fetch_all_progress_callback_data_t* callback_data; rc_client_fetch_all_user_progress_callback_data_t* callback_data;
rc_client_async_handle_t* async_handle; rc_client_async_handle_t* async_handle;
rc_api_request_t request; rc_api_request_t request;
int result; int result;
@ -3437,7 +3440,7 @@ rc_client_async_handle_t* rc_client_begin_fetch_all_progress_list(rc_client_t* c
api_params.api_token = client->user.token; api_params.api_token = client->user.token;
api_params.console_id = console_id; api_params.console_id = console_id;
result = rc_api_init_fetch_all_progress_request_hosted(&request, &api_params, &client->state.host); result = rc_api_init_fetch_all_user_progress_request_hosted(&request, &api_params, &client->state.host);
if (result != RC_OK) if (result != RC_OK)
{ {
@ -3446,7 +3449,7 @@ rc_client_async_handle_t* rc_client_begin_fetch_all_progress_list(rc_client_t* c
return NULL; return NULL;
} }
callback_data = (rc_client_fetch_all_progress_callback_data_t*)calloc(1, sizeof(*callback_data)); callback_data = (rc_client_fetch_all_user_progress_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);
@ -3460,13 +3463,13 @@ rc_client_async_handle_t* rc_client_begin_fetch_all_progress_list(rc_client_t* c
async_handle = &callback_data->async_handle; async_handle = &callback_data->async_handle;
rc_client_begin_async(client, async_handle); rc_client_begin_async(client, async_handle);
client->callbacks.server_call(&request, rc_client_fetch_all_progress_callback, callback_data, client); client->callbacks.server_call(&request, rc_client_fetch_all_user_progress_callback, callback_data, client);
rc_api_destroy_request(&request); rc_api_destroy_request(&request);
return rc_client_async_handle_valid(client, async_handle) ? async_handle : NULL; return rc_client_async_handle_valid(client, async_handle) ? async_handle : NULL;
} }
void rc_client_destroy_all_progress_list(rc_client_all_progress_list_t* list) void rc_client_destroy_all_user_progress(rc_client_all_user_progress_t* list)
{ {
free(list); free(list);
} }

View File

@ -218,14 +218,14 @@ static void CancelHashDatabaseRequests();
static void FetchHashLibraryCallback(int result, const char* error_message, rc_client_hash_library_t* list, static void FetchHashLibraryCallback(int result, const char* error_message, rc_client_hash_library_t* list,
rc_client_t* client, void* callback_userdata); rc_client_t* client, void* callback_userdata);
static void FetchAllProgressCallback(int result, const char* error_message, rc_client_all_progress_list_t* list, static void FetchAllProgressCallback(int result, const char* error_message, rc_client_all_user_progress_t* list,
rc_client_t* client, void* callback_userdata); rc_client_t* client, void* callback_userdata);
static void BuildHashDatabase(const rc_client_hash_library_t* hashlib, const rc_client_all_progress_list_t* allprog); static void BuildHashDatabase(const rc_client_hash_library_t* hashlib, const rc_client_all_user_progress_t* allprog);
static bool SortAndSaveHashDatabase(Error* error); static bool SortAndSaveHashDatabase(Error* error);
static FileSystem::ManagedCFilePtr OpenProgressDatabase(bool for_write, bool truncate, Error* error); static FileSystem::ManagedCFilePtr OpenProgressDatabase(bool for_write, bool truncate, Error* error);
static void BuildProgressDatabase(const rc_client_all_progress_list_t* allprog); static void BuildProgressDatabase(const rc_client_all_user_progress_t* allprog);
static void UpdateProgressDatabase(bool force); static void UpdateProgressDatabase(bool force);
static void ClearProgressDatabase(); static void ClearProgressDatabase();
@ -295,7 +295,7 @@ struct State
rc_client_async_handle_t* fetch_hash_library_request = nullptr; rc_client_async_handle_t* fetch_hash_library_request = nullptr;
rc_client_hash_library_t* fetch_hash_library_result = nullptr; rc_client_hash_library_t* fetch_hash_library_result = nullptr;
rc_client_async_handle_t* fetch_all_progress_request = nullptr; rc_client_async_handle_t* fetch_all_progress_request = nullptr;
rc_client_all_progress_list_t* fetch_all_progress_result = nullptr; rc_client_all_user_progress_t* fetch_all_progress_result = nullptr;
#ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION #ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION
rc_client_async_handle_t* load_raintegration_request = nullptr; rc_client_async_handle_t* load_raintegration_request = nullptr;
@ -1588,7 +1588,7 @@ void Achievements::HandleSubsetCompleteEvent(const rc_client_event_t* event)
INFO_LOG("Subset {} ({}) complete", event->subset->title, event->subset->id); INFO_LOG("Subset {} ({}) complete", event->subset->title, event->subset->id);
UpdateGameSummary(false, false); UpdateGameSummary(false, false);
if (g_settings.achievements_notifications && event->subset->badge_name) if (g_settings.achievements_notifications && event->subset->badge_name[0] != '\0')
{ {
// Need to grab the icon for the subset. // Need to grab the icon for the subset.
std::string badge_path = GetLocalImagePath(event->subset->badge_name, RC_IMAGE_TYPE_GAME); std::string badge_path = GetLocalImagePath(event->subset->badge_name, RC_IMAGE_TYPE_GAME);
@ -3960,7 +3960,7 @@ void Achievements::BeginRefreshHashDatabase()
s_state.fetch_hash_library_request = s_state.fetch_hash_library_request =
rc_client_begin_fetch_hash_library(s_state.client, RC_CONSOLE_PLAYSTATION, FetchHashLibraryCallback, nullptr); rc_client_begin_fetch_hash_library(s_state.client, RC_CONSOLE_PLAYSTATION, FetchHashLibraryCallback, nullptr);
s_state.fetch_all_progress_request = s_state.fetch_all_progress_request =
rc_client_begin_fetch_all_progress_list(s_state.client, RC_CONSOLE_PLAYSTATION, FetchAllProgressCallback, nullptr); rc_client_begin_fetch_all_user_progress(s_state.client, RC_CONSOLE_PLAYSTATION, FetchAllProgressCallback, nullptr);
if (!s_state.fetch_hash_library_request || !s_state.fetch_hash_library_request) if (!s_state.fetch_hash_library_request || !s_state.fetch_hash_library_request)
{ {
ERROR_LOG("Failed to create hash database refresh requests."); ERROR_LOG("Failed to create hash database refresh requests.");
@ -3984,7 +3984,7 @@ void Achievements::FetchHashLibraryCallback(int result, const char* error_messag
FinishRefreshHashDatabase(); FinishRefreshHashDatabase();
} }
void Achievements::FetchAllProgressCallback(int result, const char* error_message, rc_client_all_progress_list_t* list, void Achievements::FetchAllProgressCallback(int result, const char* error_message, rc_client_all_user_progress_t* list,
rc_client_t* client, void* callback_userdata) rc_client_t* client, void* callback_userdata)
{ {
s_state.fetch_all_progress_request = nullptr; s_state.fetch_all_progress_request = nullptr;
@ -4004,7 +4004,7 @@ void Achievements::CancelHashDatabaseRequests()
{ {
if (s_state.fetch_all_progress_result) if (s_state.fetch_all_progress_result)
{ {
rc_client_destroy_all_progress_list(s_state.fetch_all_progress_result); rc_client_destroy_all_user_progress(s_state.fetch_all_progress_result);
s_state.fetch_all_progress_result = nullptr; s_state.fetch_all_progress_result = nullptr;
} }
if (s_state.fetch_all_progress_request) if (s_state.fetch_all_progress_request)
@ -4040,7 +4040,7 @@ void Achievements::FinishRefreshHashDatabase()
BuildProgressDatabase(s_state.fetch_all_progress_result); BuildProgressDatabase(s_state.fetch_all_progress_result);
// tidy up // tidy up
rc_client_destroy_all_progress_list(s_state.fetch_all_progress_result); rc_client_destroy_all_user_progress(s_state.fetch_all_progress_result);
s_state.fetch_all_progress_result = nullptr; s_state.fetch_all_progress_result = nullptr;
rc_client_destroy_hash_library(s_state.fetch_hash_library_result); rc_client_destroy_hash_library(s_state.fetch_hash_library_result);
s_state.fetch_hash_library_result = nullptr; s_state.fetch_hash_library_result = nullptr;
@ -4050,7 +4050,7 @@ void Achievements::FinishRefreshHashDatabase()
} }
void Achievements::BuildHashDatabase(const rc_client_hash_library_t* hashlib, void Achievements::BuildHashDatabase(const rc_client_hash_library_t* hashlib,
const rc_client_all_progress_list_t* allprog) const rc_client_all_user_progress_t* allprog)
{ {
std::vector<HashDatabaseEntry> dbentries; std::vector<HashDatabaseEntry> dbentries;
dbentries.reserve(hashlib->num_entries); dbentries.reserve(hashlib->num_entries);
@ -4079,8 +4079,8 @@ void Achievements::BuildHashDatabase(const rc_client_hash_library_t* hashlib,
} }
// fill in achievement counts // fill in achievement counts
for (const rc_client_all_progress_list_entry_t& entry : for (const rc_client_all_user_progress_entry_t& entry :
std::span<const rc_client_all_progress_list_entry_t>(allprog->entries, allprog->num_entries)) std::span<const rc_client_all_user_progress_entry_t>(allprog->entries, allprog->num_entries))
{ {
// can have multiple hashes with the same game id, update count on all of them // can have multiple hashes with the same game id, update count on all of them
bool found_one = false; bool found_one = false;
@ -4108,6 +4108,11 @@ void Achievements::BuildHashDatabase(const rc_client_hash_library_t* hashlib,
bool Achievements::CreateHashDatabaseFromSeedDatabase(const std::string& path, Error* error) bool Achievements::CreateHashDatabaseFromSeedDatabase(const std::string& path, Error* error)
{ {
std::optional<std::string> yaml_data = Host::ReadResourceFileToString("achievement_hashlib.yaml", false, error); std::optional<std::string> yaml_data = Host::ReadResourceFileToString("achievement_hashlib.yaml", false, error);
if (!yaml_data.has_value())
{
Error::SetStringView(error, "Seed database is missing.");
return false;
}
const ryml::Tree yaml = const ryml::Tree yaml =
ryml::parse_in_place(to_csubstr(path), c4::substr(reinterpret_cast<char*>(yaml_data->data()), yaml_data->size())); ryml::parse_in_place(to_csubstr(path), c4::substr(reinterpret_cast<char*>(yaml_data->data()), yaml_data->size()));
@ -4374,7 +4379,7 @@ FileSystem::ManagedCFilePtr Achievements::OpenProgressDatabase(bool for_write, b
return nullptr; return nullptr;
} }
void Achievements::BuildProgressDatabase(const rc_client_all_progress_list_t* allprog) void Achievements::BuildProgressDatabase(const rc_client_all_user_progress_t* allprog)
{ {
// no point storing it in memory, just write directly to the file // no point storing it in memory, just write directly to the file
Error error; Error error;
@ -4401,8 +4406,8 @@ void Achievements::BuildProgressDatabase(const rc_client_all_progress_list_t* al
writer.WriteU32(games_with_unlocks); writer.WriteU32(games_with_unlocks);
if (games_with_unlocks > 0) if (games_with_unlocks > 0)
{ {
for (const rc_client_all_progress_list_entry_t& entry : for (const rc_client_all_user_progress_entry_t& entry :
std::span<const rc_client_all_progress_list_entry_t>(allprog->entries, allprog->num_entries)) std::span<const rc_client_all_user_progress_entry_t>(allprog->entries, allprog->num_entries))
{ {
if ((entry.num_unlocked_achievements + entry.num_unlocked_achievements_hardcore) == 0) if ((entry.num_unlocked_achievements + entry.num_unlocked_achievements_hardcore) == 0)
continue; continue;