|
|
|
|
@ -3493,6 +3493,58 @@ const rc_client_subset_t* rc_client_get_subset_info(rc_client_t* client, uint32_
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc_client_subset_list_t* rc_client_create_subset_list(rc_client_t* client)
|
|
|
|
|
{
|
|
|
|
|
rc_client_subset_list_info_t* list;
|
|
|
|
|
const rc_client_subset_info_t* subset;
|
|
|
|
|
const rc_client_subset_t** subset_ptr;
|
|
|
|
|
const uint32_t list_size = RC_ALIGN(sizeof(*list));
|
|
|
|
|
uint32_t num_subsets = 0;
|
|
|
|
|
|
|
|
|
|
if (!client)
|
|
|
|
|
return (rc_client_subset_list_t*)calloc(1, list_size);
|
|
|
|
|
|
|
|
|
|
#ifdef RC_CLIENT_SUPPORTS_EXTERNAL
|
|
|
|
|
if (client->state.external_client && client->state.external_client->create_subset_list)
|
|
|
|
|
return (rc_client_subset_list_t*)client->state.external_client->create_subset_list();
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (!client->game)
|
|
|
|
|
return (rc_client_subset_list_t*)calloc(1, list_size);
|
|
|
|
|
|
|
|
|
|
rc_mutex_lock(&client->state.mutex);
|
|
|
|
|
|
|
|
|
|
subset = client->game->subsets;
|
|
|
|
|
for (; subset; subset = subset->next) {
|
|
|
|
|
if (subset->active)
|
|
|
|
|
num_subsets++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
list = (rc_client_subset_list_info_t*)malloc(list_size + num_subsets * sizeof(rc_client_subset_t*));
|
|
|
|
|
list->public_.subsets = subset_ptr = (const rc_client_subset_t**)((uint8_t*)list + list_size);
|
|
|
|
|
|
|
|
|
|
subset = client->game->subsets;
|
|
|
|
|
for (; subset; subset = subset->next) {
|
|
|
|
|
if (subset->active)
|
|
|
|
|
*subset_ptr++ = &subset->public_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc_mutex_unlock(&client->state.mutex);
|
|
|
|
|
|
|
|
|
|
list->destroy_func = NULL;
|
|
|
|
|
list->public_.num_subsets = (uint32_t)(subset_ptr - list->public_.subsets);
|
|
|
|
|
return &list->public_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void rc_client_destroy_subset_list(rc_client_subset_list_t* list)
|
|
|
|
|
{
|
|
|
|
|
rc_client_subset_list_info_t* info = (rc_client_subset_list_info_t*)list;
|
|
|
|
|
if (info->destroy_func)
|
|
|
|
|
info->destroy_func(info);
|
|
|
|
|
else
|
|
|
|
|
free(list);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ===== Fetch Game Hashes ===== */
|
|
|
|
|
|
|
|
|
|
typedef struct rc_client_fetch_hash_library_callback_data_t {
|
|
|
|
|
@ -3649,6 +3701,8 @@ static void rc_client_fetch_game_titles_callback(const rc_api_server_response_t*
|
|
|
|
|
for (src = titles_response.entries, stop = src + titles_response.num_entries; src < stop; ++src) {
|
|
|
|
|
if (src->title)
|
|
|
|
|
strings_size += strlen(src->title) + 1;
|
|
|
|
|
if (src->image_url)
|
|
|
|
|
strings_size += strlen(src->image_url) + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
list_size = sizeof(*list) + sizeof(rc_client_game_title_entry_t) * titles_response.num_entries + strings_size;
|
|
|
|
|
@ -3678,6 +3732,16 @@ static void rc_client_fetch_game_titles_callback(const rc_api_server_response_t*
|
|
|
|
|
snprintf(entry->badge_name, sizeof(entry->badge_name), "%s", src->image_name);
|
|
|
|
|
else
|
|
|
|
|
entry->badge_name[0] = '\0';
|
|
|
|
|
|
|
|
|
|
if (src->image_url) {
|
|
|
|
|
const size_t len = strlen(src->image_url) + 1;
|
|
|
|
|
entry->badge_url = strings;
|
|
|
|
|
memcpy(strings, src->image_url, len);
|
|
|
|
|
strings += len;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
entry->badge_url = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
list->num_entries = titles_response.num_entries;
|
|
|
|
|
|