diff --git a/cheevos/cheevos.c b/cheevos/cheevos.c index b9ad73a486..0875906f0b 100644 --- a/cheevos/cheevos.c +++ b/cheevos/cheevos.c @@ -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) diff --git a/cheevos/cheevos_client.c b/cheevos/cheevos_client.c index 985cde3e33..04aaecf6f0 100644 --- a/cheevos/cheevos_client.c +++ b/cheevos/cheevos_client.c @@ -99,6 +99,29 @@ 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; +} rcheevos_fetch_badge_data; + /**************************** * forward declarations * @@ -111,6 +134,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 +920,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; + + request->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 +1058,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 +1361,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) diff --git a/cheevos/cheevos_locals.h b/cheevos/cheevos_locals.h index 15a4d0d59c..bd726afa34 100644 --- a/cheevos/cheevos_locals.h +++ b/cheevos/cheevos_locals.h @@ -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; diff --git a/gfx/gfx_widgets.h b/gfx/gfx_widgets.h index bd409e4b76..1d0d92bf3b 100644 --- a/gfx/gfx_widgets.h +++ b/gfx/gfx_widgets.h @@ -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 diff --git a/gfx/widgets/gfx_widget_achievement_popup.c b/gfx/widgets/gfx_widget_achievement_popup.c index 02d4fe4dfc..537b5859c8 100644 --- a/gfx/widgets/gfx_widget_achievement_popup.c +++ b/gfx/widgets/gfx_widget_achievement_popup.c @@ -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); @@ -370,10 +383,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 +404,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 +442,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);