(cheevos) inform user when server is unreachable (#15970)

* ensure game placard is loaded on main thread

* show on-screen indicator while disconnected

* show server unreachable message in achievements menu

* remove comment
This commit is contained in:
Jamiras 2023-12-02 06:33:13 -07:00 committed by GitHub
parent 12b6b68132
commit 93e5566b9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 154 additions and 8 deletions

View File

@ -92,6 +92,7 @@ static rcheevos_locals_t rcheevos_locals =
{{0}},/* memory */ {{0}},/* memory */
#ifdef HAVE_THREADS #ifdef HAVE_THREADS
CMD_EVENT_NONE, /* queued_command */ CMD_EVENT_NONE, /* queued_command */
false, /* game_placard_requested */
#endif #endif
#ifndef HAVE_RC_CLIENT #ifndef HAVE_RC_CLIENT
"", /* displayname */ "", /* displayname */
@ -134,6 +135,9 @@ rcheevos_locals_t* get_rcheevos_locals(void)
Supporting functions. Supporting functions.
*****************************************************************************/ *****************************************************************************/
#define CMD_CHEEVOS_NON_COMMAND -1
static void rcheevos_show_game_placard(void);
#ifndef CHEEVOS_VERBOSE #ifndef CHEEVOS_VERBOSE
void rcheevos_log(const char* fmt, ...) void rcheevos_log(const char* fmt, ...)
{ {
@ -602,6 +606,39 @@ static void rcheevos_server_error(const char* api_name, const char* message)
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_ERROR); MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_ERROR);
} }
static void rcheevos_server_disconnected()
{
CHEEVOS_LOG(RCHEEVOS_TAG "Unable to communicate with RetroAchievements server\n");
/* always show message - even with widget. it helps the user understand what the widget is for */
{
const char* message = msg_hash_to_str(MENU_ENUM_LABEL_CHEEVOS_SERVER_DISCONNECTED);
runloop_msg_queue_push(message, 0, 3 * 60, false, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_WARNING);
}
#if defined(HAVE_GFX_WIDGETS)
if (gfx_widgets_ready())
gfx_widget_set_cheevos_disconnect(true);
#endif
}
static void rcheevos_server_reconnected()
{
CHEEVOS_LOG(RCHEEVOS_TAG "All pending requests synced to RetroAchievements server\n");
{
const char* message = msg_hash_to_str(MENU_ENUM_LABEL_CHEEVOS_SERVER_RECONNECTED);
runloop_msg_queue_push(message, 0, 3 * 60, false, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_SUCCESS);
}
#if defined(HAVE_GFX_WIDGETS)
if (gfx_widgets_ready())
gfx_widget_set_cheevos_disconnect(false);
#endif
}
static void rcheevos_client_event_handler(const rc_client_event_t* event, rc_client_t* client) static void rcheevos_client_event_handler(const rc_client_event_t* event, rc_client_t* client)
{ {
switch (event->type) switch (event->type)
@ -657,10 +694,10 @@ static void rcheevos_client_event_handler(const rc_client_event_t* event, rc_cli
rcheevos_server_error(event->server_error->api, event->server_error->error_message); rcheevos_server_error(event->server_error->api, event->server_error->error_message);
break; break;
case RC_CLIENT_EVENT_DISCONNECTED: case RC_CLIENT_EVENT_DISCONNECTED:
CHEEVOS_LOG(RCHEEVOS_TAG "Unable to communicate with RetroAchievements server"); rcheevos_server_disconnected();
break; break;
case RC_CLIENT_EVENT_RECONNECTED: case RC_CLIENT_EVENT_RECONNECTED:
CHEEVOS_LOG(RCHEEVOS_TAG "All pending requests synced to RetroAchievements server"); rcheevos_server_reconnected();
break; break;
default: default:
#ifndef NDEBUG #ifndef NDEBUG
@ -1202,11 +1239,14 @@ bool rcheevos_unload(void)
/* Clean up after completed tasks */ /* Clean up after completed tasks */
task_queue_check(); task_queue_check();
} }
rcheevos_locals.queued_command = CMD_EVENT_NONE;
#endif #endif
#endif #endif
#ifdef HAVE_THREADS
rcheevos_locals.queued_command = CMD_EVENT_NONE;
rcheevos_locals.game_placard_requested = false;
#endif
if (rcheevos_locals.memory.count > 0) if (rcheevos_locals.memory.count > 0)
rc_libretro_memory_destroy(&rcheevos_locals.memory); rc_libretro_memory_destroy(&rcheevos_locals.memory);
@ -1866,8 +1906,16 @@ void rcheevos_test(void)
#ifdef HAVE_THREADS #ifdef HAVE_THREADS
if (rcheevos_locals.queued_command != CMD_EVENT_NONE) if (rcheevos_locals.queued_command != CMD_EVENT_NONE)
{ {
command_event(rcheevos_locals.queued_command, NULL); if (rcheevos_locals.queued_command != CMD_CHEEVOS_NON_COMMAND)
command_event(rcheevos_locals.queued_command, NULL);
rcheevos_locals.queued_command = CMD_EVENT_NONE; rcheevos_locals.queued_command = CMD_EVENT_NONE;
if (rcheevos_locals.game_placard_requested)
{
rcheevos_locals.game_placard_requested = false;
rcheevos_show_game_placard();
}
} }
#endif #endif
@ -2414,7 +2462,16 @@ static void rcheevos_client_load_game_callback(int result,
rc_client_set_read_memory_function(client, rcheevos_client_read_memory); rc_client_set_read_memory_function(client, rcheevos_client_read_memory);
} }
rcheevos_show_game_placard(); #ifdef HAVE_THREADS
if (!task_is_on_main_thread())
{
/* have to "schedule" this. game image should not be loaded on background thread */
rcheevos_locals.queued_command = CMD_CHEEVOS_NON_COMMAND;
rcheevos_locals.game_placard_requested = true;
}
else
rcheevos_show_game_placard();
#endif
rcheevos_finalize_game_load(client); rcheevos_finalize_game_load(client);

View File

@ -201,6 +201,7 @@ typedef struct rcheevos_locals_t
#ifdef HAVE_THREADS #ifdef HAVE_THREADS
enum event_command queued_command; /* action queued by background thread to be run on main thread */ enum event_command queued_command; /* action queued by background thread to be run on main thread */
bool game_placard_requested; /* request to display game placard */
#endif #endif
#ifndef HAVE_RC_CLIENT #ifndef HAVE_RC_CLIENT

View File

@ -28,6 +28,7 @@
#include "../deps/rcheevos/include/rc_runtime_types.h" #include "../deps/rcheevos/include/rc_runtime_types.h"
#include "../deps/rcheevos/include/rc_api_runtime.h" #include "../deps/rcheevos/include/rc_api_runtime.h"
#include "../deps/rcheevos/src/rc_client_internal.h"
#include "../menu/menu_driver.h" #include "../menu/menu_driver.h"
#include "../menu/menu_entries.h" #include "../menu/menu_entries.h"
@ -295,6 +296,15 @@ void rcheevos_menu_populate(void* data)
rcheevos_menu_reset_badges(); rcheevos_menu_reset_badges();
rcheevos_locals->menuitem_count = 0; rcheevos_locals->menuitem_count = 0;
if (rcheevos_locals->client->state.disconnect)
{
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_SERVER_UNREACHABLE),
msg_hash_to_str(MENU_ENUM_SUBLABEL_ACHIEVEMENT_SERVER_UNREACHABLE),
MENU_ENUM_LABEL_ACHIEVEMENT_SERVER_UNREACHABLE,
MENU_INFO_ACHIEVEMENTS_SERVER_UNREACHABLE, 0, 0, NULL);
}
if (game && game->id != 0) if (game && game->id != 0)
{ {
/* first menu item is the Pause/Resume Hardcore option (unless hardcore is completely disabled) */ /* first menu item is the Pause/Resume Hardcore option (unless hardcore is completely disabled) */
@ -466,7 +476,11 @@ uintptr_t rcheevos_get_badge_texture(const char* badge, bool locked, bool downlo
return 0; return 0;
/* OpenGL driver crashes if gfx_display_reset_textures_list is called on a background thread */ /* OpenGL driver crashes if gfx_display_reset_textures_list is called on a background thread */
retro_assert(task_is_on_main_thread()); if (!task_is_on_main_thread())
{
CHEEVOS_ERR(RCHEEVOS_TAG "attempt to load badge %s from background thread", badge);
retro_assert(task_is_on_main_thread());
}
snprintf(badge_file, sizeof(badge_file), "%s%s%s", badge, snprintf(badge_file, sizeof(badge_file), "%s%s%s", badge,
locked ? "_lock" : "", FILE_PATH_PNG_EXTENSION); locked ? "_lock" : "", FILE_PATH_PNG_EXTENSION);

View File

@ -384,6 +384,7 @@ void gfx_widgets_clear_leaderboard_displays(void);
void gfx_widgets_set_challenge_display(unsigned id, const char* badge); void gfx_widgets_set_challenge_display(unsigned id, const char* badge);
void gfx_widgets_clear_challenge_displays(void); void gfx_widgets_clear_challenge_displays(void);
void gfx_widget_set_achievement_progress(const char* badge, const char* progress); void gfx_widget_set_achievement_progress(const char* badge, const char* progress);
void gfx_widget_set_cheevos_disconnect(bool visible);
#endif #endif
/* TODO/FIXME/WARNING: Not thread safe! */ /* TODO/FIXME/WARNING: Not thread safe! */

View File

@ -51,6 +51,8 @@ struct progress_tracker_info
#define CHEEVO_LBOARD_FIRST_FIXED_CHAR 0x2D /* -./0123456789: */ #define CHEEVO_LBOARD_FIRST_FIXED_CHAR 0x2D /* -./0123456789: */
#define CHEEVO_LBOARD_LAST_FIXED_CHAR 0x3A #define CHEEVO_LBOARD_LAST_FIXED_CHAR 0x3A
/* TODO: rename; this file handles all achievement tracker information, not just leaderboards */
struct gfx_widget_leaderboard_display_state struct gfx_widget_leaderboard_display_state
{ {
#ifdef HAVE_THREADS #ifdef HAVE_THREADS
@ -64,6 +66,7 @@ struct gfx_widget_leaderboard_display_state
unsigned challenge_count; unsigned challenge_count;
uint16_t char_width[CHEEVO_LBOARD_LAST_FIXED_CHAR - CHEEVO_LBOARD_FIRST_FIXED_CHAR + 1]; uint16_t char_width[CHEEVO_LBOARD_LAST_FIXED_CHAR - CHEEVO_LBOARD_FIRST_FIXED_CHAR + 1];
uint16_t fixed_char_width; uint16_t fixed_char_width;
bool disconnected;
}; };
typedef struct gfx_widget_leaderboard_display_state gfx_widget_leaderboard_display_state_t; typedef struct gfx_widget_leaderboard_display_state gfx_widget_leaderboard_display_state_t;
@ -109,7 +112,10 @@ static void gfx_widget_leaderboard_display_frame(void* data, void* userdata)
gfx_widget_leaderboard_display_state_t *state = &p_w_leaderboard_display_st; gfx_widget_leaderboard_display_state_t *state = &p_w_leaderboard_display_st;
/* if there's nothing to display, just bail */ /* if there's nothing to display, just bail */
if (state->tracker_count == 0 && state->challenge_count == 0 && state->progress_tracker.show_until == 0) if (state->tracker_count == 0 &&
state->challenge_count == 0 &&
state->progress_tracker.show_until == 0 &&
!state->disconnected)
return; return;
#ifdef HAVE_THREADS #ifdef HAVE_THREADS
@ -335,6 +341,38 @@ static void gfx_widget_leaderboard_display_frame(void* data, void* userdata)
TEXT_COLOR_INFO, TEXT_ALIGN_LEFT, true); TEXT_COLOR_INFO, TEXT_ALIGN_LEFT, true);
} }
} }
if (state->disconnected)
{
const char* disconnected_text = "! RA !";
const unsigned disconnect_widget_width = font_driver_get_message_width(
state->dispwidget_ptr->gfx_widget_fonts.msg_queue.font,
disconnected_text, 0, 1) + CHEEVO_LBOARD_DISPLAY_PADDING * 2;
const unsigned disconnect_widget_height =
p_dispwidget->gfx_widget_fonts.msg_queue.line_height + (CHEEVO_LBOARD_DISPLAY_PADDING - 1) * 2;
x = video_width - disconnect_widget_width - spacing;
y -= disconnect_widget_height + spacing;
/* Backdrop */
gfx_display_draw_quad(
p_disp,
video_info->userdata,
video_width, video_height,
(int)x, (int)y, disconnect_widget_width, disconnect_widget_height,
video_width, video_height,
p_dispwidget->backdrop_orig,
NULL);
/* Text */
char_x = (float)(x + CHEEVO_LBOARD_DISPLAY_PADDING);
char_y = (float)(y + disconnect_widget_height - (CHEEVO_LBOARD_DISPLAY_PADDING - 1)
- p_dispwidget->gfx_widget_fonts.msg_queue.line_descender);
gfx_widgets_draw_text(&p_dispwidget->gfx_widget_fonts.msg_queue,
disconnected_text, char_x, char_y,
video_width, video_height,
TEXT_COLOR_INFO, TEXT_ALIGN_LEFT, true);
}
} }
#ifdef HAVE_THREADS #ifdef HAVE_THREADS
@ -542,6 +580,13 @@ void gfx_widget_set_achievement_progress(const char* badge, const char* progress
video_driver_texture_unload(&old_badge_id); video_driver_texture_unload(&old_badge_id);
} }
void gfx_widget_set_cheevos_disconnect(bool value)
{
gfx_widget_leaderboard_display_state_t* state = &p_w_leaderboard_display_st;
state->disconnected = value;
}
const gfx_widget_t gfx_widget_leaderboard_display = { const gfx_widget_t gfx_widget_leaderboard_display = {
&gfx_widget_leaderboard_display_init, &gfx_widget_leaderboard_display_init,
&gfx_widget_leaderboard_display_free, &gfx_widget_leaderboard_display_free,

View File

@ -9691,6 +9691,22 @@ MSG_HASH(
MENU_ENUM_SUBLABEL_ACHIEVEMENT_RESUME, MENU_ENUM_SUBLABEL_ACHIEVEMENT_RESUME,
"Resume achievements hardcore mode for the current session. This action will disable cheats, rewind, slow-motion, and loading save states and reset the current game." "Resume achievements hardcore mode for the current session. This action will disable cheats, rewind, slow-motion, and loading save states and reset the current game."
) )
MSG_HASH(
MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_SERVER_UNREACHABLE,
"RetroAchievements server is unreachable"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_ACHIEVEMENT_SERVER_UNREACHABLE,
"One or more achievement unlocks did not make it to the server. The unlocks will be retried as long as you leave the app open."
)
MSG_HASH(
MENU_ENUM_LABEL_CHEEVOS_SERVER_DISCONNECTED,
"RetroAchievements server is unreachable. Will retry until successful or the app is closed."
)
MSG_HASH(
MENU_ENUM_LABEL_CHEEVOS_SERVER_RECONNECTED,
"All pending requests have succesfully been synced to the RetroAchievements server."
)
MSG_HASH( MSG_HASH(
MENU_ENUM_LABEL_VALUE_NOT_LOGGED_IN, MENU_ENUM_LABEL_VALUE_NOT_LOGGED_IN,
"Not logged in" "Not logged in"

View File

@ -301,6 +301,7 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_information_list_list, MENU_
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_achievement_list, MENU_ENUM_SUBLABEL_ACHIEVEMENT_LIST) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_achievement_list, MENU_ENUM_SUBLABEL_ACHIEVEMENT_LIST)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_achievement_pause_cancel, MENU_ENUM_SUBLABEL_ACHIEVEMENT_PAUSE_CANCEL) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_achievement_pause_cancel, MENU_ENUM_SUBLABEL_ACHIEVEMENT_PAUSE_CANCEL)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_achievement_resume_cancel, MENU_ENUM_SUBLABEL_ACHIEVEMENT_RESUME_CANCEL) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_achievement_resume_cancel, MENU_ENUM_SUBLABEL_ACHIEVEMENT_RESUME_CANCEL)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_achievement_server_unreachable,MENU_ENUM_SUBLABEL_ACHIEVEMENT_SERVER_UNREACHABLE)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_cheevos_enable, MENU_ENUM_SUBLABEL_CHEEVOS_ENABLE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_cheevos_enable, MENU_ENUM_SUBLABEL_CHEEVOS_ENABLE)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_cheevos_test_unofficial, MENU_ENUM_SUBLABEL_CHEEVOS_TEST_UNOFFICIAL) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_cheevos_test_unofficial, MENU_ENUM_SUBLABEL_CHEEVOS_TEST_UNOFFICIAL)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_cheevos_hardcore_mode_enable, MENU_ENUM_SUBLABEL_CHEEVOS_HARDCORE_MODE_ENABLE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_cheevos_hardcore_mode_enable, MENU_ENUM_SUBLABEL_CHEEVOS_HARDCORE_MODE_ENABLE)
@ -4564,6 +4565,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs,
case MENU_ENUM_LABEL_ACHIEVEMENT_RESUME_CANCEL: case MENU_ENUM_LABEL_ACHIEVEMENT_RESUME_CANCEL:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_achievement_resume_cancel); BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_achievement_resume_cancel);
break; break;
case MENU_ENUM_LABEL_ACHIEVEMENT_SERVER_UNREACHABLE:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_achievement_server_unreachable);
break;
case MENU_ENUM_LABEL_CHEEVOS_UNLOCKED_ENTRY: case MENU_ENUM_LABEL_CHEEVOS_UNLOCKED_ENTRY:
case MENU_ENUM_LABEL_CHEEVOS_UNLOCKED_ENTRY_HARDCORE: case MENU_ENUM_LABEL_CHEEVOS_UNLOCKED_ENTRY_HARDCORE:
case MENU_ENUM_LABEL_CHEEVOS_LOCKED_ENTRY: case MENU_ENUM_LABEL_CHEEVOS_LOCKED_ENTRY:

View File

@ -2290,6 +2290,8 @@ static uintptr_t ozone_entries_icon_get_texture(
return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_RELOAD]; return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_RELOAD];
case MENU_SETTING_ACTION_PAUSE_ACHIEVEMENTS: case MENU_SETTING_ACTION_PAUSE_ACHIEVEMENTS:
return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_PAUSE]; return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_PAUSE];
case MENU_INFO_ACHIEVEMENTS_SERVER_UNREACHABLE:
return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_NETWORK];
case MENU_SETTING_GROUP: case MENU_SETTING_GROUP:
return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_SETTING]; return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_SETTING];
case MENU_SET_SCREEN_BRIGHTNESS: case MENU_SET_SCREEN_BRIGHTNESS:

View File

@ -3465,6 +3465,8 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb,
return xmb->textures.list[XMB_TEXTURE_RELOAD]; return xmb->textures.list[XMB_TEXTURE_RELOAD];
case MENU_SETTING_ACTION_PAUSE_ACHIEVEMENTS: case MENU_SETTING_ACTION_PAUSE_ACHIEVEMENTS:
return xmb->textures.list[XMB_TEXTURE_PAUSE]; return xmb->textures.list[XMB_TEXTURE_PAUSE];
case MENU_ENUM_LABEL_ACHIEVEMENT_SERVER_UNREACHABLE:
return xmb->textures.list[XMB_TEXTURE_NETWORK];
case MENU_SET_SCREEN_BRIGHTNESS: case MENU_SET_SCREEN_BRIGHTNESS:
return xmb->textures.list[XMB_TEXTURE_BRIGHTNESS]; return xmb->textures.list[XMB_TEXTURE_BRIGHTNESS];
case MENU_SETTING_GROUP: case MENU_SETTING_GROUP:

View File

@ -169,6 +169,7 @@ enum menu_settings_type
MENU_SETTING_HORIZONTAL_MENU, MENU_SETTING_HORIZONTAL_MENU,
MENU_SETTING_ACTION_PAUSE_ACHIEVEMENTS, MENU_SETTING_ACTION_PAUSE_ACHIEVEMENTS,
MENU_SETTING_ACTION_RESUME_ACHIEVEMENTS, MENU_SETTING_ACTION_RESUME_ACHIEVEMENTS,
MENU_INFO_ACHIEVEMENTS_SERVER_UNREACHABLE,
MENU_SETTING_PLAYLIST_MANAGER_DEFAULT_CORE, MENU_SETTING_PLAYLIST_MANAGER_DEFAULT_CORE,
MENU_SETTING_PLAYLIST_MANAGER_LABEL_DISPLAY_MODE, MENU_SETTING_PLAYLIST_MANAGER_LABEL_DISPLAY_MODE,
MENU_SETTING_PLAYLIST_MANAGER_RIGHT_THUMBNAIL_MODE, MENU_SETTING_PLAYLIST_MANAGER_RIGHT_THUMBNAIL_MODE,

View File

@ -2926,6 +2926,9 @@ enum msg_hash_enums
MENU_LABEL(ACHIEVEMENT_RESUME_CANCEL), MENU_LABEL(ACHIEVEMENT_RESUME_CANCEL),
MENU_LABEL(ACHIEVEMENT_PAUSE), MENU_LABEL(ACHIEVEMENT_PAUSE),
MENU_LABEL(ACHIEVEMENT_RESUME), MENU_LABEL(ACHIEVEMENT_RESUME),
MENU_LABEL(ACHIEVEMENT_SERVER_UNREACHABLE),
MENU_LABEL(CHEEVOS_SERVER_DISCONNECTED),
MENU_LABEL(CHEEVOS_SERVER_RECONNECTED),
MENU_LABEL(CORE_INFORMATION), MENU_LABEL(CORE_INFORMATION),
MENU_LABEL(DISC_INFORMATION), MENU_LABEL(DISC_INFORMATION),
MENU_LABEL(CORE_LOCK), MENU_LABEL(CORE_LOCK),