Merge pull request #13246 from Jamiras/cheevos_game_placard

(cheevos) use widget for game loaded achievement progress
This commit is contained in:
Autechre 2021-11-17 03:21:37 +01:00 committed by GitHub
commit b0c859557e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 228 additions and 67 deletions

View File

@ -307,7 +307,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);
gfx_widgets_push_achievement(msg_hash_to_str(MSG_ACHIEVEMENT_UNLOCKED), cheevo->title, cheevo->badge);
else
#endif
{
@ -1285,7 +1285,14 @@ static void rcheevos_show_game_placard()
CHEEVOS_LOG(RCHEEVOS_TAG "%s\n", msg);
if (settings->bools.cheevos_verbose_enable)
runloop_msg_queue_push(msg, 0, 3 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
{
#if defined (HAVE_GFX_WIDGETS)
if (gfx_widgets_ready())
gfx_widgets_push_achievement(rcheevos_locals.game.title, msg, rcheevos_locals.game.badge_name);
else
#endif
runloop_msg_queue_push(msg, 0, 3 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
}
static void rcheevos_end_load(void)
@ -1306,27 +1313,8 @@ static void rcheevos_fetch_badges(void)
rcheevos_client_fetch_badges(rcheevos_fetch_badges_callback, NULL);
}
static void rcheevos_start_session(void)
static void rcheevos_start_session_async(retro_task_t* task)
{
if (rcheevos_load_aborted())
{
CHEEVOS_LOG(RCHEEVOS_TAG "Load aborted before starting session\n");
return;
}
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 */
rcheevos_show_game_placard();
rcheevos_pause_hardcore();
return;
}
}
rcheevos_begin_load_state(RCHEEVOS_LOAD_STATE_STARTING_SESSION);
/* activate the achievements and leaderboards
@ -1371,10 +1359,41 @@ static void rcheevos_start_session(void)
rcheevos_show_game_placard();
task_set_finished(task, true);
if (rcheevos_end_load_state() == 0)
rcheevos_fetch_badges();
}
static void rcheevos_start_session(void)
{
retro_task_t* task;
if (rcheevos_load_aborted())
{
CHEEVOS_LOG(RCHEEVOS_TAG "Load aborted before starting session\n");
return;
}
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 */
rcheevos_show_game_placard();
rcheevos_pause_hardcore();
return;
}
}
/* this is called on the primary thread. use a task to do the initialization on a background thread */
task = task_init();
task->handler = rcheevos_start_session_async;
task_queue_push(task);
}
static void rcheevos_initialize_runtime_callback(void* userdata)
{
rcheevos_start_session();

View File

@ -99,6 +99,32 @@ typedef struct rcheevos_async_io_request
char type;
} rcheevos_async_io_request;
#ifdef HAVE_THREADS
#define RCHEEVOS_CONCURRENT_BADGE_DOWNLOADS 2
#else
#define RCHEEVOS_CONCURRENT_BADGE_DOWNLOADS 1
#endif
typedef struct rcheevos_fetch_badge_state
{
unsigned badge_fetch_index;
unsigned locked_badge_fetch_index;
const char* badge_directory;
rcheevos_client_callback callback;
void* callback_data;
char requested_badges[
RCHEEVOS_CONCURRENT_BADGE_DOWNLOADS][32];
} rcheevos_fetch_badge_state;
typedef struct rcheevos_fetch_badge_data
{
rcheevos_fetch_badge_state* state;
int request_index;
void* data;
size_t data_len;
rcheevos_client_callback callback;
} rcheevos_fetch_badge_data;
/****************************
* forward declarations *
@ -111,6 +137,10 @@ static void rcheevos_async_http_task_callback(
static void rcheevos_async_end_request(rcheevos_async_io_request* request);
static void rcheevos_async_fetch_badge_callback(
struct rcheevos_async_io_request* request,
http_transfer_data_t* data, char buffer[], size_t buffer_size);
/****************************
* user agent construction *
****************************/
@ -893,6 +923,98 @@ static void rcheevos_client_initialize_runtime_callback(void* userdata)
free(runtime_data);
}
static void rcheevos_client_fetch_game_badge_callback(void* userdata)
{
rcheevos_fetch_badge_data* data = (rcheevos_fetch_badge_data*)userdata;
rcheevos_async_initialize_runtime_data_t* runtime_data =
(rcheevos_async_initialize_runtime_data_t*)data->state->callback_data;
free((void*)data->state->badge_directory);
free(data->state);
free(data);
rcheevos_client_initialize_runtime_callback(runtime_data);
}
static void rcheevos_client_fetch_game_badge(const char* badge_name, rcheevos_async_initialize_runtime_data_t* runtime_data)
{
#if defined(HAVE_GFX_WIDGETS) /* don't need game badge unless widgets are enabled */
char badge_fullpath[PATH_MAX_LENGTH] = "";
char* badge_fullname = NULL;
size_t badge_fullname_size = 0;
/* make sure the directory exists */
fill_pathname_application_special(badge_fullpath,
sizeof(badge_fullpath),
APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_CHEEVOS_BADGES);
if (!path_is_directory(badge_fullpath))
{
CHEEVOS_LOG(RCHEEVOS_TAG "Creating %s\n", badge_fullpath);
path_mkdir(badge_fullpath);
}
fill_pathname_slash(badge_fullpath, sizeof(badge_fullpath));
badge_fullname = badge_fullpath + strlen(badge_fullpath);
badge_fullname_size = sizeof(badge_fullpath) -
(badge_fullname - badge_fullpath);
snprintf(badge_fullname,
badge_fullname_size, "i%s" FILE_PATH_PNG_EXTENSION, badge_name);
/* check if it's already available */
if (path_is_valid(badge_fullpath))
return;
#ifdef CHEEVOS_LOG_BADGES
CHEEVOS_LOG(RCHEEVOS_TAG "Downloading game badge %s\n", badge_name);
#endif
{
rcheevos_async_io_request* request = (rcheevos_async_io_request*)
calloc(1, sizeof(rcheevos_async_io_request));
rcheevos_fetch_badge_data* data = (rcheevos_fetch_badge_data*)
calloc(1, sizeof(rcheevos_fetch_badge_data));
rcheevos_fetch_badge_state* state = (rcheevos_fetch_badge_state*)
calloc(1, sizeof(rcheevos_fetch_badge_state));
if (!request || !data || !state)
{
CHEEVOS_LOG(RCHEEVOS_TAG
"Failed to allocate fetch badge request\n");
}
else
{
rc_api_fetch_image_request_t api_params;
int result;
memset(&api_params, 0, sizeof(api_params));
api_params.image_name = badge_name;
api_params.image_type = RC_IMAGE_TYPE_GAME;
result = rc_api_init_fetch_image_request(&request->request, &api_params);
strlcpy(state->requested_badges[0], badge_fullname, sizeof(state->requested_badges[0]));
*badge_fullname = '\0';
state->badge_directory = strdup(badge_fullpath);
state->callback_data = runtime_data;
data->state = state;
data->request_index = 0;
data->callback = rcheevos_client_fetch_game_badge_callback;
request->callback_data = data;
rcheevos_begin_load_state(RCHEEVOS_LOAD_STATE_FETCHING_GAME_DATA);
rcheevos_async_begin_request(request, result,
rcheevos_async_fetch_badge_callback,
CHEEVOS_ASYNC_FETCH_BADGE, atoi(badge_name), NULL,
"Error fetching game badge");
}
}
#endif
}
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)
@ -939,6 +1061,10 @@ static void rcheevos_async_fetch_game_data_callback(
runtime_data->game_data.title);
rcheevos_locals->game.console_id =
runtime_data->game_data.console_id;
snprintf(rcheevos_locals->game.badge_name, sizeof(rcheevos_locals->game.badge_name),
"i%s", runtime_data->game_data.image_name);
rcheevos_client_fetch_game_badge(runtime_data->game_data.image_name, runtime_data);
}
}
@ -1238,30 +1364,6 @@ void rcheevos_client_start_session(unsigned game_id)
* fetch badge *
****************************/
#ifdef HAVE_THREADS
#define RCHEEVOS_CONCURRENT_BADGE_DOWNLOADS 2
#else
#define RCHEEVOS_CONCURRENT_BADGE_DOWNLOADS 1
#endif
typedef struct rcheevos_fetch_badge_state
{
unsigned badge_fetch_index;
unsigned locked_badge_fetch_index;
const char* badge_directory;
rcheevos_client_callback callback;
void* callback_data;
char requested_badges[
RCHEEVOS_CONCURRENT_BADGE_DOWNLOADS][32];
} rcheevos_fetch_badge_state;
typedef struct rcheevos_fetch_badge_data
{
rcheevos_fetch_badge_state* state;
int request_index;
} rcheevos_fetch_badge_data;
static bool rcheevos_fetch_next_badge(rcheevos_fetch_badge_state* state);
static void rcheevos_end_fetch_badges(rcheevos_fetch_badge_state* state)
@ -1285,26 +1387,56 @@ 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_write_badge(retro_task_t* task)
{
char badge_fullpath[PATH_MAX_LENGTH];
rcheevos_fetch_badge_data* badge_data =
(rcheevos_fetch_badge_data*)request->callback_data;
rcheevos_fetch_badge_data* badge_data =
(rcheevos_fetch_badge_data*)task->user_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));
if (!filestream_write_file(badge_fullpath, data->data, data->len))
if (!filestream_write_file(badge_fullpath, badge_data->data, badge_data->data_len))
{
CHEEVOS_ERR(RCHEEVOS_TAG "Error writing badge %s\n",
badge_fullpath);
badge_fullpath);
}
free(badge_data->data);
badge_data->data = NULL;
badge_data->data_len = 0;
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);
task_set_finished(task, true);
if (badge_data->callback)
badge_data->callback(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)
{
rcheevos_fetch_badge_data* badge_data =
(rcheevos_fetch_badge_data*)request->callback_data;
retro_task_t* task;
/* take ownership of the file data */
badge_data->data = data->data;
badge_data->data_len = data->len;
data->data = NULL;
data->len = 0;
/* this is called on the primary thread. use a task to write the file from a background thread */
task = task_init();
task->handler = rcheevos_async_write_badge;
task->user_data = badge_data;
task_queue_push(task);
}
static bool rcheevos_client_fetch_badge(
@ -1402,8 +1534,8 @@ static bool rcheevos_client_fetch_badge(
data->state = state;
data->request_index = request_index;
data->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);

View File

@ -125,6 +125,7 @@ typedef struct rcheevos_game_info_t
int id;
int console_id;
char* title;
char badge_name[16];
char hash[33];
rcheevos_racheevo_t* achievements;

View File

@ -110,12 +110,6 @@ typedef struct
gfx_widget_font_data_t msg_queue;
} gfx_widget_fonts_t;
typedef struct cheevo_popup
{
char* title;
uintptr_t badge;
} cheevo_popup;
typedef struct disp_widget_msg
{
char *msg;
@ -353,7 +347,7 @@ void gfx_widgets_ai_service_overlay_unload(void);
#endif
#ifdef HAVE_CHEEVOS
void gfx_widgets_push_achievement(const char *title, const char *badge);
void gfx_widgets_push_achievement(const char *title, const char* subtitle, const char *badge);
void gfx_widgets_set_leaderboard_display(unsigned id, const char* value);
void gfx_widgets_set_challenge_display(unsigned id, const char* badge);
#endif

View File

@ -32,6 +32,13 @@
#define CHEEVO_QUEUE_SIZE 8
typedef struct cheevo_popup
{
char* title;
char* subtitle;
uintptr_t badge;
} cheevo_popup;
struct gfx_widget_achievement_popup_state
{
#ifdef HAVE_THREADS
@ -222,7 +229,7 @@ static void gfx_widget_achievement_popup_frame(void* data, void* userdata)
/* Title */
gfx_widgets_draw_text(&p_dispwidget->gfx_widget_fonts.regular,
msg_hash_to_str(MSG_ACHIEVEMENT_UNLOCKED),
state->queue[state->queue_read_index].title,
state->height + p_dispwidget->simple_widget_padding - unfold_offet,
state->y + p_dispwidget->gfx_widget_fonts.regular.line_height
+ p_dispwidget->gfx_widget_fonts.regular.line_ascender,
@ -235,7 +242,7 @@ static void gfx_widget_achievement_popup_frame(void* data, void* userdata)
/* TODO: is a ticker necessary ? */
gfx_widgets_draw_text(&p_dispwidget->gfx_widget_fonts.regular,
state->queue[state->queue_read_index].title,
state->queue[state->queue_read_index].subtitle,
state->height + p_dispwidget->simple_widget_padding - unfold_offet,
state->y + state->height
- p_dispwidget->gfx_widget_fonts.regular.line_height
@ -267,6 +274,12 @@ static void gfx_widget_achievement_popup_free_current(
state->queue[state->queue_read_index].title = NULL;
}
if (state->queue[state->queue_read_index].subtitle)
{
free(state->queue[state->queue_read_index].subtitle);
state->queue[state->queue_read_index].subtitle = NULL;
}
if (state->queue[state->queue_read_index].badge)
{
video_driver_texture_unload(&state->queue[state->queue_read_index].badge);
@ -284,7 +297,8 @@ static void gfx_widget_achievement_popup_next(void* userdata)
if (state->queue_read_index >= 0)
{
gfx_widget_achievement_popup_free_current(state);
if (state->queue[state->queue_read_index].title)
gfx_widget_achievement_popup_free_current(state);
/* start the next popup (if present) */
if (state->queue[state->queue_read_index].title)
@ -370,10 +384,10 @@ static void gfx_widget_achievement_popup_start(
state->width = MAX(
font_driver_get_message_width(
p_dispwidget->gfx_widget_fonts.regular.font,
msg_hash_to_str(MSG_ACHIEVEMENT_UNLOCKED), 0, 1),
state->queue[state->queue_read_index].title, 0, 1),
font_driver_get_message_width(
p_dispwidget->gfx_widget_fonts.regular.font,
state->queue[state->queue_read_index].title, 0, 1)
state->queue[state->queue_read_index].subtitle, 0, 1)
);
state->width += p_dispwidget->simple_widget_padding * 2;
state->y = (float)(-(int)state->height);
@ -391,7 +405,7 @@ static void gfx_widget_achievement_popup_start(
gfx_animation_push(&entry);
}
void gfx_widgets_push_achievement(const char *title, const char *badge)
void gfx_widgets_push_achievement(const char *title, const char* subtitle, const char *badge)
{
gfx_widget_achievement_popup_state_t *state = &p_w_achievement_popup_st;
int start_notification = 1;
@ -429,6 +443,7 @@ void gfx_widgets_push_achievement(const char *title, const char *badge)
state->queue[state->queue_write_index].badge = badge_id;
state->queue[state->queue_write_index].title = strdup(title);
state->queue[state->queue_write_index].subtitle = strdup(subtitle);
state->queue_write_index = (state->queue_write_index + 1) % ARRAY_SIZE(state->queue);