mirror of
https://github.com/libretro/RetroArch
synced 2025-03-29 22:20:21 +00:00
(cheevos) upgrade to rcheevos 11.2 (#16408)
* provide more information during achievement load process * update rcheevos version * do disconnected processing even when no game is loaded * make loading widget unique * only show loading indicator with verbose messages on
This commit is contained in:
parent
5426ec8d90
commit
a6beba6376
@ -2115,7 +2115,7 @@ ifeq ($(HAVE_NETWORKING), 1)
|
||||
|
||||
# RetroAchievements
|
||||
ifeq ($(HAVE_CHEEVOS), 1)
|
||||
DEFINES += -DHAVE_CHEEVOS
|
||||
DEFINES += -DHAVE_CHEEVOS -DRC_CLIENT_SUPPORTS_HASH
|
||||
INCLUDE_DIRS += -Ideps/rcheevos/include
|
||||
|
||||
ifneq ($(HAVE_THREADS), 1)
|
||||
|
@ -107,7 +107,7 @@ static rcheevos_locals_t rcheevos_locals =
|
||||
0, /* menuitem_count */
|
||||
#endif
|
||||
#ifdef HAVE_RC_CLIENT
|
||||
true,/* hardcore_allowed */
|
||||
true, /* hardcore_allowed */
|
||||
#else
|
||||
#ifdef HAVE_GFX_WIDGETS
|
||||
0, /* active_lboard_trackers */
|
||||
@ -1221,6 +1221,7 @@ bool rcheevos_unload(void)
|
||||
|
||||
#ifdef HAVE_GFX_WIDGETS
|
||||
rcheevos_hide_widgets(gfx_widgets_ready());
|
||||
gfx_widget_set_cheevos_set_loading(false);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_RC_CLIENT
|
||||
@ -2441,6 +2442,10 @@ static void rcheevos_client_load_game_callback(int result,
|
||||
const rc_client_game_t* game = rc_client_get_game_info(client);
|
||||
char msg[256];
|
||||
|
||||
#if defined(HAVE_GFX_WIDGETS)
|
||||
gfx_widget_set_cheevos_set_loading(false);
|
||||
#endif
|
||||
|
||||
if (result != RC_OK || !game)
|
||||
{
|
||||
if (result == RC_NO_GAME_LOADED)
|
||||
@ -3257,6 +3262,11 @@ bool rcheevos_load(const void *data)
|
||||
/* provide hooks for reading files */
|
||||
rc_hash_reset_cdreader_hooks();
|
||||
|
||||
#if defined(HAVE_GFX_WIDGETS)
|
||||
if (settings->bools.cheevos_verbose_enable)
|
||||
gfx_widget_set_cheevos_set_loading(true);
|
||||
#endif
|
||||
|
||||
rc_client_begin_identify_and_load_game(rcheevos_locals.client, RC_CONSOLE_UNKNOWN,
|
||||
info->path, info->data, info->size, rcheevos_client_load_game_callback, NULL);
|
||||
|
||||
|
@ -338,6 +338,12 @@ static void rcheevos_client_http_task_callback(retro_task_t* task,
|
||||
|
||||
if (!http_data)
|
||||
{
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "http_task returned null");
|
||||
callback_data->callback(&server_response, callback_data->callback_data);
|
||||
}
|
||||
else if (http_data->status < 0)
|
||||
{
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "http_task returned %d", http_data->status);
|
||||
callback_data->callback(&server_response, callback_data->callback_data);
|
||||
}
|
||||
else
|
||||
|
@ -447,29 +447,71 @@ void rcheevos_menu_populate(void* data)
|
||||
{
|
||||
/* no achievements found */
|
||||
if (!rcheevos_locals->core_supports)
|
||||
{
|
||||
menu_entries_append(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CANNOT_ACTIVATE_ACHIEVEMENTS_WITH_THIS_CORE),
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_CANNOT_ACTIVATE_ACHIEVEMENTS_WITH_THIS_CORE),
|
||||
MENU_ENUM_LABEL_CANNOT_ACTIVATE_ACHIEVEMENTS_WITH_THIS_CORE,
|
||||
FILE_TYPE_NONE, 0, 0, NULL);
|
||||
else if (!rc_client_get_game_info(rcheevos_locals->client))
|
||||
}
|
||||
else if (!game)
|
||||
{
|
||||
int state = rc_client_get_load_game_state(rcheevos_locals->client);
|
||||
enum msg_hash_enums msg = MENU_ENUM_LABEL_VALUE_UNKNOWN_GAME;
|
||||
switch (state)
|
||||
{
|
||||
case RC_CLIENT_LOAD_GAME_STATE_IDENTIFYING_GAME:
|
||||
msg = MENU_ENUM_LABEL_VALUE_CHEEVOS_IDENTIFYING_GAME;
|
||||
break;
|
||||
case RC_CLIENT_LOAD_GAME_STATE_AWAIT_LOGIN:
|
||||
msg = MENU_ENUM_LABEL_VALUE_NOT_LOGGED_IN;
|
||||
break;
|
||||
case RC_CLIENT_LOAD_GAME_STATE_FETCHING_GAME_DATA:
|
||||
msg = MENU_ENUM_LABEL_VALUE_CHEEVOS_FETCHING_GAME_DATA;
|
||||
break;
|
||||
case RC_CLIENT_LOAD_GAME_STATE_STARTING_SESSION:
|
||||
msg = MENU_ENUM_LABEL_VALUE_CHEEVOS_STARTING_SESSION;
|
||||
break;
|
||||
case RC_CLIENT_LOAD_GAME_STATE_NONE:
|
||||
if (!rc_client_get_user_info(rcheevos_locals->client))
|
||||
msg = MENU_ENUM_LABEL_VALUE_NOT_LOGGED_IN;
|
||||
break;
|
||||
}
|
||||
|
||||
menu_entries_append(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UNKNOWN_GAME),
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_UNKNOWN_GAME),
|
||||
MENU_ENUM_LABEL_UNKNOWN_GAME,
|
||||
msg_hash_to_str(msg),
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY),
|
||||
MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY,
|
||||
FILE_TYPE_NONE, 0, 0, NULL);
|
||||
}
|
||||
else if (!game->id)
|
||||
{
|
||||
char buffer[128];
|
||||
snprintf(buffer, sizeof(buffer), "%s (%s)",
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UNKNOWN_GAME), game->hash);
|
||||
|
||||
menu_entries_append(info->list,
|
||||
buffer,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY),
|
||||
MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY,
|
||||
FILE_TYPE_NONE, 0, 0, NULL);
|
||||
}
|
||||
else if (!rc_client_get_user_info(rcheevos_locals->client))
|
||||
{
|
||||
menu_entries_append(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_LOGGED_IN),
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_NOT_LOGGED_IN),
|
||||
MENU_ENUM_LABEL_NOT_LOGGED_IN,
|
||||
FILE_TYPE_NONE, 0, 0, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
menu_entries_append(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ACHIEVEMENTS_TO_DISPLAY),
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY),
|
||||
MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY,
|
||||
FILE_TYPE_NONE, 0, 0, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
12
deps/rcheevos/CHANGELOG.md
vendored
12
deps/rcheevos/CHANGELOG.md
vendored
@ -1,3 +1,15 @@
|
||||
# v11.2.0
|
||||
* add alternate methods for state serialization/deserialization that accept a buffer_size parameter
|
||||
* add RC_CLIENT_SUPPORTS_HASH compile flag
|
||||
- allows rc_client code to build without the rhash files (except md5.c)
|
||||
- must be explicitly defined to use rc_client_begin_identify_and_load_game
|
||||
* add rc_client_get_load_game_state
|
||||
* add rc_client_raintegration_set_get_game_name_function
|
||||
* add RC_MEMSIZE_DOUBLE32 and RC_MEMSIZE_DOUBLE32_BE
|
||||
* exclude directory records from ZIP hash algorithm
|
||||
* fix media host when explicitly setting host to production server
|
||||
* fix potential out-of-bounds read looking for error message in non-JSON response
|
||||
|
||||
# v11.1.0
|
||||
* add rc_client_get_user_agent_clause to generate substring to include in client User-Agents
|
||||
* add rc_client_can_pause function to control pause spam
|
||||
|
35
deps/rcheevos/include/rc_api_info.h
vendored
35
deps/rcheevos/include/rc_api_info.h
vendored
@ -6,9 +6,7 @@
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
RC_BEGIN_C_DECLS
|
||||
|
||||
/* --- Fetch Achievement Info --- */
|
||||
|
||||
@ -63,10 +61,11 @@ typedef struct rc_api_fetch_achievement_info_response_t {
|
||||
}
|
||||
rc_api_fetch_achievement_info_response_t;
|
||||
|
||||
int rc_api_init_fetch_achievement_info_request(rc_api_request_t* request, const rc_api_fetch_achievement_info_request_t* api_params);
|
||||
int rc_api_process_fetch_achievement_info_response(rc_api_fetch_achievement_info_response_t* response, const char* server_response);
|
||||
int rc_api_process_fetch_achievement_info_server_response(rc_api_fetch_achievement_info_response_t* response, const rc_api_server_response_t* server_response);
|
||||
void rc_api_destroy_fetch_achievement_info_response(rc_api_fetch_achievement_info_response_t* response);
|
||||
RC_EXPORT int RC_CCONV rc_api_init_fetch_achievement_info_request(rc_api_request_t* request, const rc_api_fetch_achievement_info_request_t* api_params);
|
||||
/* [deprecated] use rc_api_process_fetch_achievement_info_server_response instead */
|
||||
RC_EXPORT int RC_CCONV rc_api_process_fetch_achievement_info_response(rc_api_fetch_achievement_info_response_t* response, const char* server_response);
|
||||
RC_EXPORT int RC_CCONV rc_api_process_fetch_achievement_info_server_response(rc_api_fetch_achievement_info_response_t* response, const rc_api_server_response_t* server_response);
|
||||
RC_EXPORT void RC_CCONV rc_api_destroy_fetch_achievement_info_response(rc_api_fetch_achievement_info_response_t* response);
|
||||
|
||||
/* --- Fetch Leaderboard Info --- */
|
||||
|
||||
@ -135,10 +134,11 @@ typedef struct rc_api_fetch_leaderboard_info_response_t {
|
||||
}
|
||||
rc_api_fetch_leaderboard_info_response_t;
|
||||
|
||||
int rc_api_init_fetch_leaderboard_info_request(rc_api_request_t* request, const rc_api_fetch_leaderboard_info_request_t* api_params);
|
||||
int rc_api_process_fetch_leaderboard_info_response(rc_api_fetch_leaderboard_info_response_t* response, const char* server_response);
|
||||
int rc_api_process_fetch_leaderboard_info_server_response(rc_api_fetch_leaderboard_info_response_t* response, const rc_api_server_response_t* server_response);
|
||||
void rc_api_destroy_fetch_leaderboard_info_response(rc_api_fetch_leaderboard_info_response_t* response);
|
||||
RC_EXPORT int RC_CCONV rc_api_init_fetch_leaderboard_info_request(rc_api_request_t* request, const rc_api_fetch_leaderboard_info_request_t* api_params);
|
||||
/* [deprecated] use rc_api_process_fetch_leaderboard_info_server_response instead */
|
||||
RC_EXPORT int RC_CCONV rc_api_process_fetch_leaderboard_info_response(rc_api_fetch_leaderboard_info_response_t* response, const char* server_response);
|
||||
RC_EXPORT int RC_CCONV rc_api_process_fetch_leaderboard_info_server_response(rc_api_fetch_leaderboard_info_response_t* response, const rc_api_server_response_t* server_response);
|
||||
RC_EXPORT void RC_CCONV rc_api_destroy_fetch_leaderboard_info_response(rc_api_fetch_leaderboard_info_response_t* response);
|
||||
|
||||
/* --- Fetch Games List --- */
|
||||
|
||||
@ -174,13 +174,12 @@ typedef struct rc_api_fetch_games_list_response_t {
|
||||
}
|
||||
rc_api_fetch_games_list_response_t;
|
||||
|
||||
int rc_api_init_fetch_games_list_request(rc_api_request_t* request, const rc_api_fetch_games_list_request_t* api_params);
|
||||
int rc_api_process_fetch_games_list_response(rc_api_fetch_games_list_response_t* response, const char* server_response);
|
||||
int rc_api_process_fetch_games_list_server_response(rc_api_fetch_games_list_response_t* response, const rc_api_server_response_t* server_response);
|
||||
void rc_api_destroy_fetch_games_list_response(rc_api_fetch_games_list_response_t* response);
|
||||
RC_EXPORT int RC_CCONV rc_api_init_fetch_games_list_request(rc_api_request_t* request, const rc_api_fetch_games_list_request_t* api_params);
|
||||
/* [deprecated] use rc_api_process_fetch_games_list_server_response instead */
|
||||
RC_EXPORT int RC_CCONV rc_api_process_fetch_games_list_response(rc_api_fetch_games_list_response_t* response, const char* server_response);
|
||||
RC_EXPORT int RC_CCONV rc_api_process_fetch_games_list_server_response(rc_api_fetch_games_list_response_t* response, const rc_api_server_response_t* server_response);
|
||||
RC_EXPORT void RC_CCONV rc_api_destroy_fetch_games_list_response(rc_api_fetch_games_list_response_t* response);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
RC_END_C_DECLS
|
||||
|
||||
#endif /* RC_API_INFO_H */
|
||||
|
3
deps/rcheevos/include/rc_api_user.h
vendored
3
deps/rcheevos/include/rc_api_user.h
vendored
@ -47,6 +47,7 @@ typedef struct rc_api_login_response_t {
|
||||
rc_api_login_response_t;
|
||||
|
||||
RC_EXPORT int RC_CCONV rc_api_init_login_request(rc_api_request_t* request, const rc_api_login_request_t* api_params);
|
||||
/* [deprecated] use rc_api_process_login_server_response instead */
|
||||
RC_EXPORT int RC_CCONV rc_api_process_login_response(rc_api_login_response_t* response, const char* server_response);
|
||||
RC_EXPORT int RC_CCONV rc_api_process_login_server_response(rc_api_login_response_t* response, const rc_api_server_response_t* server_response);
|
||||
RC_EXPORT void RC_CCONV rc_api_destroy_login_response(rc_api_login_response_t* response);
|
||||
@ -104,6 +105,7 @@ typedef struct rc_api_start_session_response_t {
|
||||
rc_api_start_session_response_t;
|
||||
|
||||
RC_EXPORT int RC_CCONV rc_api_init_start_session_request(rc_api_request_t* request, const rc_api_start_session_request_t* api_params);
|
||||
/* [deprecated] use rc_api_process_start_session_server_response instead */
|
||||
RC_EXPORT int RC_CCONV rc_api_process_start_session_response(rc_api_start_session_response_t* response, const char* server_response);
|
||||
RC_EXPORT int RC_CCONV rc_api_process_start_session_server_response(rc_api_start_session_response_t* response, const rc_api_server_response_t* server_response);
|
||||
RC_EXPORT void RC_CCONV rc_api_destroy_start_session_response(rc_api_start_session_response_t* response);
|
||||
@ -140,6 +142,7 @@ typedef struct rc_api_fetch_user_unlocks_response_t {
|
||||
rc_api_fetch_user_unlocks_response_t;
|
||||
|
||||
RC_EXPORT int RC_CCONV rc_api_init_fetch_user_unlocks_request(rc_api_request_t* request, const rc_api_fetch_user_unlocks_request_t* api_params);
|
||||
/* [deprecated] use rc_api_process_fetch_user_unlocks_server_response instead */
|
||||
RC_EXPORT int RC_CCONV rc_api_process_fetch_user_unlocks_response(rc_api_fetch_user_unlocks_response_t* response, const char* server_response);
|
||||
RC_EXPORT int RC_CCONV rc_api_process_fetch_user_unlocks_server_response(rc_api_fetch_user_unlocks_response_t* response, const rc_api_server_response_t* server_response);
|
||||
RC_EXPORT void RC_CCONV rc_api_destroy_fetch_user_unlocks_response(rc_api_fetch_user_unlocks_response_t* response);
|
||||
|
40
deps/rcheevos/include/rc_client.h
vendored
40
deps/rcheevos/include/rc_client.h
vendored
@ -221,6 +221,7 @@ RC_EXPORT void RC_CCONV rc_client_get_user_game_summary(const rc_client_t* clien
|
||||
| Game |
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifdef RC_CLIENT_SUPPORTS_HASH
|
||||
/**
|
||||
* Start loading an unidentified game.
|
||||
*/
|
||||
@ -228,6 +229,7 @@ RC_EXPORT rc_client_async_handle_t* RC_CCONV rc_client_begin_identify_and_load_g
|
||||
uint32_t console_id, const char* file_path,
|
||||
const uint8_t* data, size_t data_size,
|
||||
rc_client_callback_t callback, void* callback_userdata);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Start loading a game.
|
||||
@ -235,6 +237,20 @@ RC_EXPORT rc_client_async_handle_t* RC_CCONV rc_client_begin_identify_and_load_g
|
||||
RC_EXPORT rc_client_async_handle_t* RC_CCONV rc_client_begin_load_game(rc_client_t* client, const char* hash,
|
||||
rc_client_callback_t callback, void* callback_userdata);
|
||||
|
||||
/**
|
||||
* Gets the current progress of the asynchronous load game process.
|
||||
*/
|
||||
RC_EXPORT int RC_CCONV rc_client_get_load_game_state(const rc_client_t* client);
|
||||
enum {
|
||||
RC_CLIENT_LOAD_GAME_STATE_NONE,
|
||||
RC_CLIENT_LOAD_GAME_STATE_IDENTIFYING_GAME,
|
||||
RC_CLIENT_LOAD_GAME_STATE_AWAIT_LOGIN,
|
||||
RC_CLIENT_LOAD_GAME_STATE_FETCHING_GAME_DATA,
|
||||
RC_CLIENT_LOAD_GAME_STATE_STARTING_SESSION,
|
||||
RC_CLIENT_LOAD_GAME_STATE_DONE,
|
||||
RC_CLIENT_LOAD_GAME_STATE_ABORTED
|
||||
};
|
||||
|
||||
/**
|
||||
* Unloads the current game.
|
||||
*/
|
||||
@ -259,11 +275,19 @@ RC_EXPORT const rc_client_game_t* RC_CCONV rc_client_get_game_info(const rc_clie
|
||||
*/
|
||||
RC_EXPORT int RC_CCONV rc_client_game_get_image_url(const rc_client_game_t* game, char buffer[], size_t buffer_size);
|
||||
|
||||
#ifdef RC_CLIENT_SUPPORTS_HASH
|
||||
/**
|
||||
* Changes the active disc in a multi-disc game.
|
||||
*/
|
||||
RC_EXPORT rc_client_async_handle_t* RC_CCONV rc_client_begin_change_media(rc_client_t* client, const char* file_path,
|
||||
const uint8_t* data, size_t data_size, rc_client_callback_t callback, void* callback_userdata);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Changes the active disc in a multi-disc game.
|
||||
*/
|
||||
RC_EXPORT rc_client_async_handle_t* RC_CCONV rc_client_begin_change_media_from_hash(rc_client_t* client, const char* hash,
|
||||
rc_client_callback_t callback, void* callback_userdata);
|
||||
|
||||
/*****************************************************************************\
|
||||
| Subsets |
|
||||
@ -663,15 +687,29 @@ RC_EXPORT size_t RC_CCONV rc_client_progress_size(rc_client_t* client);
|
||||
/**
|
||||
* Serializes the runtime state into a buffer.
|
||||
* Returns RC_OK on success, or an error indicator.
|
||||
* [deprecated] use rc_client_serialize_progress_sized instead
|
||||
*/
|
||||
RC_EXPORT int RC_CCONV rc_client_serialize_progress(rc_client_t* client, uint8_t* buffer);
|
||||
|
||||
/**
|
||||
* Deserializes the runtime state from a buffer.
|
||||
* Serializes the runtime state into a buffer.
|
||||
* Returns RC_OK on success, or an error indicator.
|
||||
*/
|
||||
RC_EXPORT int RC_CCONV rc_client_serialize_progress_sized(rc_client_t* client, uint8_t* buffer, size_t buffer_size);
|
||||
|
||||
/**
|
||||
* Deserializes the runtime state from a buffer.
|
||||
* Returns RC_OK on success, or an error indicator.
|
||||
* [deprecated] use rc_client_deserialize_progress_sized instead
|
||||
*/
|
||||
RC_EXPORT int RC_CCONV rc_client_deserialize_progress(rc_client_t* client, const uint8_t* serialized);
|
||||
|
||||
/**
|
||||
* Serializes the runtime state into a buffer.
|
||||
* Returns RC_OK on success, or an error indicator.
|
||||
*/
|
||||
RC_EXPORT int RC_CCONV rc_client_deserialize_progress_sized(rc_client_t* client, const uint8_t* serialized, size_t serialized_size);
|
||||
|
||||
RC_END_C_DECLS
|
||||
|
||||
#endif /* RC_RUNTIME_H */
|
||||
|
@ -46,6 +46,8 @@ typedef void (RC_CCONV *rc_client_raintegration_event_handler_t)(const rc_client
|
||||
typedef void (RC_CCONV *rc_client_raintegration_write_memory_func_t)(uint32_t address, uint8_t* buffer,
|
||||
uint32_t num_bytes, rc_client_t* client);
|
||||
|
||||
typedef void (RC_CCONV* rc_client_raintegration_get_game_name_func_t)(char* buffer, uint32_t buffer_size, rc_client_t* client);
|
||||
|
||||
/* types needed to integrate raintegration */
|
||||
|
||||
#ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION
|
||||
@ -71,9 +73,11 @@ RC_EXPORT const rc_client_raintegration_menu_t* RC_CCONV rc_client_raintegration
|
||||
|
||||
RC_EXPORT void RC_CCONV rc_client_raintegration_rebuild_submenu(rc_client_t* client, HMENU hMenu);
|
||||
RC_EXPORT void RC_CCONV rc_client_raintegration_update_menu_item(const rc_client_t* client, const rc_client_raintegration_menu_item_t* menu_item);
|
||||
RC_EXPORT int RC_CCONV rc_client_raintegration_activate_menu_item(const rc_client_t* client, uint32_t nMenuItemId);
|
||||
RC_EXPORT int RC_CCONV rc_client_raintegration_activate_menu_item(const rc_client_t* client, uint32_t menu_item_id);
|
||||
|
||||
RC_EXPORT void RC_CCONV rc_client_raintegration_set_write_memory_function(rc_client_t* client, rc_client_raintegration_write_memory_func_t handler);
|
||||
RC_EXPORT void RC_CCONV rc_client_raintegration_set_get_game_name_function(rc_client_t* client, rc_client_raintegration_get_game_name_func_t handler);
|
||||
RC_EXPORT int RC_CCONV rc_client_raintegration_has_modifications(const rc_client_t* client);
|
||||
|
||||
RC_EXPORT void RC_CCONV rc_client_raintegration_set_event_handler(rc_client_t* client,
|
||||
rc_client_raintegration_event_handler_t handler);
|
||||
|
3
deps/rcheevos/include/rc_error.h
vendored
3
deps/rcheevos/include/rc_error.h
vendored
@ -45,7 +45,8 @@ enum {
|
||||
RC_NO_RESPONSE = -32,
|
||||
RC_ACCESS_DENIED = -33,
|
||||
RC_INVALID_CREDENTIALS = -34,
|
||||
RC_EXPIRED_TOKEN = -35
|
||||
RC_EXPIRED_TOKEN = -35,
|
||||
RC_INSUFFICIENT_BUFFER = -36
|
||||
};
|
||||
|
||||
RC_EXPORT const char* RC_CCONV rc_error_str(int ret);
|
||||
|
8
deps/rcheevos/include/rc_runtime.h
vendored
8
deps/rcheevos/include/rc_runtime.h
vendored
@ -143,9 +143,15 @@ typedef int (RC_CCONV *rc_runtime_validate_address_t)(uint32_t address);
|
||||
RC_EXPORT void RC_CCONV rc_runtime_validate_addresses(rc_runtime_t* runtime, rc_runtime_event_handler_t event_handler, rc_runtime_validate_address_t validate_handler);
|
||||
RC_EXPORT void RC_CCONV rc_runtime_invalidate_address(rc_runtime_t* runtime, uint32_t address);
|
||||
|
||||
RC_EXPORT int RC_CCONV rc_runtime_progress_size(const rc_runtime_t* runtime, lua_State* L);
|
||||
RC_EXPORT uint32_t RC_CCONV rc_runtime_progress_size(const rc_runtime_t* runtime, lua_State* L);
|
||||
|
||||
/* [deprecated] use rc_runtime_serialize_progress_sized instead */
|
||||
RC_EXPORT int RC_CCONV rc_runtime_serialize_progress(void* buffer, const rc_runtime_t* runtime, lua_State* L);
|
||||
RC_EXPORT int RC_CCONV rc_runtime_serialize_progress_sized(uint8_t* buffer, uint32_t buffer_size, const rc_runtime_t* runtime, lua_State* L);
|
||||
|
||||
/* [deprecated] use rc_runtime_deserialize_progress_sized instead */
|
||||
RC_EXPORT int RC_CCONV rc_runtime_deserialize_progress(rc_runtime_t* runtime, const uint8_t* serialized, lua_State* L);
|
||||
RC_EXPORT int RC_CCONV rc_runtime_deserialize_progress_sized(rc_runtime_t* runtime, const uint8_t* serialized, uint32_t serialized_size, lua_State* L);
|
||||
|
||||
RC_END_C_DECLS
|
||||
|
||||
|
2
deps/rcheevos/include/rc_runtime_types.h
vendored
2
deps/rcheevos/include/rc_runtime_types.h
vendored
@ -59,6 +59,8 @@ enum {
|
||||
RC_MEMSIZE_MBF32,
|
||||
RC_MEMSIZE_MBF32_LE,
|
||||
RC_MEMSIZE_FLOAT_BE,
|
||||
RC_MEMSIZE_DOUBLE32,
|
||||
RC_MEMSIZE_DOUBLE32_BE,
|
||||
RC_MEMSIZE_VARIABLE
|
||||
};
|
||||
|
||||
|
68
deps/rcheevos/src/rapi/rc_api_common.c
vendored
68
deps/rcheevos/src/rapi/rc_api_common.c
vendored
@ -37,6 +37,24 @@ static void rc_json_skip_whitespace(rc_json_iterator_t* iterator)
|
||||
++iterator->json;
|
||||
}
|
||||
|
||||
static int rc_json_find_substring(rc_json_iterator_t* iterator, const char* substring)
|
||||
{
|
||||
const char first = *substring;
|
||||
const size_t substring_len = strlen(substring);
|
||||
const char* end = iterator->end - substring_len;
|
||||
|
||||
while (iterator->json <= end) {
|
||||
if (*iterator->json == first) {
|
||||
if (memcmp(iterator->json, substring, substring_len) == 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
++iterator->json;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rc_json_find_closing_quote(rc_json_iterator_t* iterator)
|
||||
{
|
||||
while (iterator->json < iterator->end) {
|
||||
@ -237,8 +255,6 @@ int rc_json_get_next_object_field(rc_json_iterator_t* iterator, rc_json_field_t*
|
||||
}
|
||||
|
||||
int rc_json_get_object_string_length(const char* json) {
|
||||
const char* json_start = json;
|
||||
|
||||
rc_json_iterator_t iterator;
|
||||
memset(&iterator, 0, sizeof(iterator));
|
||||
iterator.json = json;
|
||||
@ -246,34 +262,41 @@ int rc_json_get_object_string_length(const char* json) {
|
||||
|
||||
rc_json_parse_object(&iterator, NULL, 0, NULL);
|
||||
|
||||
return (int)(iterator.json - json_start);
|
||||
if (iterator.json == json) /* not JSON */
|
||||
return (int)strlen(json);
|
||||
|
||||
return (int)(iterator.json - json);
|
||||
}
|
||||
|
||||
static int rc_json_extract_html_error(rc_api_response_t* response, const rc_api_server_response_t* server_response) {
|
||||
const char* json = server_response->body;
|
||||
const char* end = json;
|
||||
rc_json_iterator_t iterator;
|
||||
memset(&iterator, 0, sizeof(iterator));
|
||||
iterator.json = server_response->body;
|
||||
iterator.end = server_response->body + server_response->body_length;
|
||||
|
||||
const char* title_start = strstr(json, "<title>");
|
||||
if (title_start) {
|
||||
title_start += 7;
|
||||
if (isdigit((int)*title_start)) {
|
||||
const char* title_end = strstr(title_start + 7, "</title>");
|
||||
if (title_end) {
|
||||
response->error_message = rc_buffer_strncpy(&response->buffer, title_start, title_end - title_start);
|
||||
response->succeeded = 0;
|
||||
return RC_INVALID_JSON;
|
||||
}
|
||||
/* if the title contains an HTTP status code(i.e "404 Not Found"), return the title */
|
||||
if (rc_json_find_substring(&iterator, "<title>")) {
|
||||
const char* title_start = iterator.json + 7;
|
||||
if (isdigit((int)*title_start) && rc_json_find_substring(&iterator, "</title>")) {
|
||||
response->error_message = rc_buffer_strncpy(&response->buffer, title_start, iterator.json - title_start);
|
||||
response->succeeded = 0;
|
||||
return RC_INVALID_JSON;
|
||||
}
|
||||
}
|
||||
|
||||
while (*end && *end != '\n' && end - json < 200)
|
||||
++end;
|
||||
/* title not found, or did not start with an error code, return the first line of the response */
|
||||
iterator.json = server_response->body;
|
||||
|
||||
if (end > json && end[-1] == '\r')
|
||||
--end;
|
||||
while (iterator.json < iterator.end && *iterator.json != '\n' &&
|
||||
iterator.json - server_response->body < 200) {
|
||||
++iterator.json;
|
||||
}
|
||||
|
||||
if (end > json)
|
||||
response->error_message = rc_buffer_strncpy(&response->buffer, json, end - json);
|
||||
if (iterator.json > server_response->body && iterator.json[-1] == '\r')
|
||||
--iterator.json;
|
||||
|
||||
if (iterator.json > server_response->body)
|
||||
response->error_message = rc_buffer_strncpy(&response->buffer, server_response->body, iterator.json - server_response->body);
|
||||
|
||||
response->succeeded = 0;
|
||||
return RC_INVALID_JSON;
|
||||
@ -1150,6 +1173,9 @@ static void rc_api_update_host(char** host, const char* hostname) {
|
||||
}
|
||||
|
||||
void rc_api_set_host(const char* hostname) {
|
||||
if (hostname && strcmp(hostname, RETROACHIEVEMENTS_HOST) == 0)
|
||||
hostname = NULL;
|
||||
|
||||
rc_api_update_host(&g_host, hostname);
|
||||
|
||||
if (!hostname) {
|
||||
|
335
deps/rcheevos/src/rc_client.c
vendored
335
deps/rcheevos/src/rc_client.c
vendored
@ -42,9 +42,12 @@ typedef struct rc_client_generic_callback_data_t {
|
||||
|
||||
typedef struct rc_client_pending_media_t
|
||||
{
|
||||
#ifdef RC_CLIENT_SUPPORTS_HASH
|
||||
const char* file_path;
|
||||
uint8_t* data;
|
||||
size_t data_size;
|
||||
#endif
|
||||
const char* hash;
|
||||
rc_client_callback_t callback;
|
||||
void* callback_userdata;
|
||||
} rc_client_pending_media_t;
|
||||
@ -59,7 +62,9 @@ typedef struct rc_client_load_state_t
|
||||
rc_client_subset_info_t* subset;
|
||||
rc_client_game_hash_t* hash;
|
||||
|
||||
#ifdef RC_CLIENT_SUPPORTS_HASH
|
||||
rc_hash_iterator_t hash_iterator;
|
||||
#endif
|
||||
rc_client_pending_media_t* pending_media;
|
||||
|
||||
rc_api_start_session_response_t *start_session_response;
|
||||
@ -68,7 +73,9 @@ typedef struct rc_client_load_state_t
|
||||
|
||||
uint8_t progress;
|
||||
uint8_t outstanding_requests;
|
||||
#ifdef RC_CLIENT_SUPPORTS_HASH
|
||||
uint8_t hash_console_id;
|
||||
#endif
|
||||
} rc_client_load_state_t;
|
||||
|
||||
static void rc_client_begin_fetch_game_data(rc_client_load_state_t* callback_data);
|
||||
@ -135,6 +142,10 @@ void rc_client_destroy(rc_client_t* client)
|
||||
|
||||
rc_client_unload_game(client);
|
||||
|
||||
#ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION
|
||||
rc_client_unload_raintegration(client);
|
||||
#endif
|
||||
|
||||
#ifdef RC_CLIENT_SUPPORTS_EXTERNAL
|
||||
if (client->state.external_client && client->state.external_client->destroy)
|
||||
client->state.external_client->destroy();
|
||||
@ -151,9 +162,11 @@ void rc_client_destroy(rc_client_t* client)
|
||||
|
||||
static rc_client_t* g_hash_client = NULL;
|
||||
|
||||
#ifdef RC_CLIENT_SUPPORTS_HASH
|
||||
static void rc_client_log_hash_message(const char* message) {
|
||||
rc_client_log_message(g_hash_client, message);
|
||||
}
|
||||
#endif
|
||||
|
||||
void rc_client_log_message(const rc_client_t* client, const char* message)
|
||||
{
|
||||
@ -612,7 +625,7 @@ static void rc_client_login_callback(const rc_api_server_response_t* server_resp
|
||||
if (login_callback_data->callback)
|
||||
login_callback_data->callback(result, error_message, client, login_callback_data->callback_userdata);
|
||||
|
||||
if (load_state && load_state->progress == RC_CLIENT_LOAD_STATE_AWAIT_LOGIN)
|
||||
if (load_state && load_state->progress == RC_CLIENT_LOAD_GAME_STATE_AWAIT_LOGIN)
|
||||
rc_client_begin_fetch_game_data(load_state);
|
||||
}
|
||||
else {
|
||||
@ -635,7 +648,7 @@ static void rc_client_login_callback(const rc_api_server_response_t* server_resp
|
||||
|
||||
RC_CLIENT_LOG_INFO_FORMATTED(client, "%s logged in successfully", login_response.display_name);
|
||||
|
||||
if (load_state && load_state->progress == RC_CLIENT_LOAD_STATE_AWAIT_LOGIN)
|
||||
if (load_state && load_state->progress == RC_CLIENT_LOAD_GAME_STATE_AWAIT_LOGIN)
|
||||
rc_client_begin_fetch_game_data(load_state);
|
||||
|
||||
if (login_callback_data->callback)
|
||||
@ -796,7 +809,7 @@ void rc_client_logout(rc_client_t* client)
|
||||
|
||||
rc_client_unload_game(client);
|
||||
|
||||
if (load_state && load_state->progress == RC_CLIENT_LOAD_STATE_AWAIT_LOGIN)
|
||||
if (load_state && load_state->progress == RC_CLIENT_LOAD_GAME_STATE_AWAIT_LOGIN)
|
||||
rc_client_load_error(load_state, RC_ABORTED, "Login aborted");
|
||||
}
|
||||
|
||||
@ -937,9 +950,9 @@ static int rc_client_end_load_state(rc_client_load_state_t* load_state)
|
||||
* the outstanding_requests count will reach zero and the memory will be free'd then. */
|
||||
if (remaining_requests == 0) {
|
||||
/* if one of the callbacks called rc_client_load_error, progress will be set to
|
||||
* RC_CLIENT_LOAD_STATE_UNKNOWN. There's no need to call the callback with RC_ABORTED
|
||||
* RC_CLIENT_LOAD_STATE_ABORTED. There's no need to call the callback with RC_ABORTED
|
||||
* in that case, as it will have already been called with something more appropriate. */
|
||||
if (load_state->progress != RC_CLIENT_LOAD_STATE_UNKNOWN_GAME && load_state->callback)
|
||||
if (load_state->progress != RC_CLIENT_LOAD_GAME_STATE_ABORTED && load_state->callback)
|
||||
load_state->callback(RC_ABORTED, "The requested game is no longer active", load_state->client, load_state->callback_userdata);
|
||||
|
||||
rc_client_free_load_state(load_state);
|
||||
@ -957,7 +970,7 @@ static void rc_client_load_error(rc_client_load_state_t* load_state, int result,
|
||||
|
||||
rc_mutex_lock(&load_state->client->state.mutex);
|
||||
|
||||
load_state->progress = RC_CLIENT_LOAD_STATE_UNKNOWN_GAME;
|
||||
load_state->progress = RC_CLIENT_LOAD_GAME_STATE_ABORTED;
|
||||
if (load_state->client->state.load == load_state)
|
||||
load_state->client->state.load = NULL;
|
||||
|
||||
@ -1401,17 +1414,29 @@ static void rc_client_apply_unlocks(rc_client_subset_info_t* subset, rc_api_unlo
|
||||
}
|
||||
}
|
||||
|
||||
static void rc_client_free_pending_media(rc_client_pending_media_t* pending_media)
|
||||
{
|
||||
if (pending_media->hash)
|
||||
free((void*)pending_media->hash);
|
||||
#ifdef RC_CLIENT_SUPPORTS_HASH
|
||||
if (pending_media->data)
|
||||
free(pending_media->data);
|
||||
free((void*)pending_media->file_path);
|
||||
#endif
|
||||
free(pending_media);
|
||||
}
|
||||
|
||||
static void rc_client_activate_game(rc_client_load_state_t* load_state, rc_api_start_session_response_t *start_session_response)
|
||||
{
|
||||
rc_client_t* client = load_state->client;
|
||||
|
||||
rc_mutex_lock(&client->state.mutex);
|
||||
load_state->progress = (client->state.load == load_state) ?
|
||||
RC_CLIENT_LOAD_STATE_DONE : RC_CLIENT_LOAD_STATE_UNKNOWN_GAME;
|
||||
RC_CLIENT_LOAD_GAME_STATE_DONE : RC_CLIENT_LOAD_GAME_STATE_ABORTED;
|
||||
client->state.load = NULL;
|
||||
rc_mutex_unlock(&client->state.mutex);
|
||||
|
||||
if (load_state->progress != RC_CLIENT_LOAD_STATE_DONE) {
|
||||
if (load_state->progress != RC_CLIENT_LOAD_GAME_STATE_DONE) {
|
||||
/* previous load state was aborted */
|
||||
if (load_state->callback)
|
||||
load_state->callback(RC_ABORTED, "The requested game is no longer active", client, load_state->callback_userdata);
|
||||
@ -1449,12 +1474,17 @@ static void rc_client_activate_game(rc_client_load_state_t* load_state, rc_api_s
|
||||
rc_mutex_unlock(&load_state->client->state.mutex);
|
||||
|
||||
if (pending_media) {
|
||||
rc_client_begin_change_media(client, pending_media->file_path,
|
||||
pending_media->data, pending_media->data_size, pending_media->callback, pending_media->callback_userdata);
|
||||
if (pending_media->data)
|
||||
free(pending_media->data);
|
||||
free((void*)pending_media->file_path);
|
||||
free(pending_media);
|
||||
if (pending_media->hash) {
|
||||
rc_client_begin_change_media_from_hash(client, pending_media->hash,
|
||||
pending_media->callback, pending_media->callback_userdata);
|
||||
} else {
|
||||
#ifdef RC_CLIENT_SUPPORTS_HASH
|
||||
rc_client_begin_change_media(client, pending_media->file_path,
|
||||
pending_media->data, pending_media->data_size,
|
||||
pending_media->callback, pending_media->callback_userdata);
|
||||
#endif
|
||||
}
|
||||
rc_client_free_pending_media(pending_media);
|
||||
}
|
||||
|
||||
/* client->game must be set before calling this function so it can query the console_id */
|
||||
@ -1561,7 +1591,7 @@ static void rc_client_begin_start_session(rc_client_load_state_t* load_state)
|
||||
rc_client_load_error(load_state, result, rc_error_str(result));
|
||||
}
|
||||
else {
|
||||
rc_client_begin_load_state(load_state, RC_CLIENT_LOAD_STATE_STARTING_SESSION, 1);
|
||||
rc_client_begin_load_state(load_state, RC_CLIENT_LOAD_GAME_STATE_STARTING_SESSION, 1);
|
||||
RC_CLIENT_LOG_VERBOSE_FORMATTED(client, "Starting session for game %u", start_session_params.game_id);
|
||||
rc_client_begin_async(client, &load_state->async_handle);
|
||||
client->callbacks.server_call(&start_session_request, rc_client_start_session_callback, load_state, client);
|
||||
@ -1876,7 +1906,7 @@ static void rc_client_fetch_game_data_callback(const rc_api_server_response_t* s
|
||||
}
|
||||
|
||||
/* kick off the start session request while we process the game data */
|
||||
rc_client_begin_load_state(load_state, RC_CLIENT_LOAD_STATE_STARTING_SESSION, 1);
|
||||
rc_client_begin_load_state(load_state, RC_CLIENT_LOAD_GAME_STATE_STARTING_SESSION, 1);
|
||||
if (load_state->client->state.spectator_mode != RC_CLIENT_SPECTATOR_MODE_OFF) {
|
||||
/* we can't unlock achievements without a session, lock spectator mode for the game */
|
||||
load_state->client->state.spectator_mode = RC_CLIENT_SPECTATOR_MODE_LOCKED;
|
||||
@ -1962,6 +1992,7 @@ static void rc_client_begin_fetch_game_data(rc_client_load_state_t* load_state)
|
||||
int result;
|
||||
|
||||
if (load_state->hash->game_id == 0) {
|
||||
#ifdef RC_CLIENT_SUPPORTS_HASH
|
||||
char hash[33];
|
||||
|
||||
if (rc_hash_iterate(hash, &load_state->hash_iterator)) {
|
||||
@ -2010,18 +2041,34 @@ static void rc_client_begin_fetch_game_data(rc_client_load_state_t* load_state)
|
||||
/* only a single hash was tried, capture it */
|
||||
load_state->game->public_.console_id = load_state->hash_console_id;
|
||||
load_state->game->public_.hash = load_state->hash->hash;
|
||||
|
||||
if (client->callbacks.identify_unknown_hash) {
|
||||
load_state->hash->game_id = client->callbacks.identify_unknown_hash(
|
||||
load_state->hash_console_id, load_state->hash->hash, client, load_state->callback_userdata);
|
||||
|
||||
if (load_state->hash->game_id != 0) {
|
||||
RC_CLIENT_LOG_INFO_FORMATTED(load_state->client, "Client says to load game %u for unidentified hash %s",
|
||||
load_state->hash->game_id, load_state->hash->hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
load_state->game->public_.console_id = RC_CONSOLE_UNKNOWN;
|
||||
load_state->game->public_.hash = load_state->hash->hash;
|
||||
#endif /* RC_CLIENT_SUPPORTS_HASH */
|
||||
|
||||
load_state->game->public_.title = "Unknown Game";
|
||||
load_state->game->public_.badge_name = "";
|
||||
client->game = load_state->game;
|
||||
load_state->game = NULL;
|
||||
if (load_state->hash->game_id == 0) {
|
||||
load_state->game->public_.title = "Unknown Game";
|
||||
load_state->game->public_.badge_name = "";
|
||||
client->game = load_state->game;
|
||||
load_state->game = NULL;
|
||||
|
||||
rc_client_load_error(load_state, RC_NO_GAME_LOADED, "Unknown game");
|
||||
return;
|
||||
rc_client_load_error(load_state, RC_NO_GAME_LOADED, "Unknown game");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (load_state->hash->hash[0] != '[') {
|
||||
if (load_state->hash->hash[0] != '[') { /* not [NO HASH] or [SUBSETxx] */
|
||||
load_state->game->public_.id = load_state->hash->game_id;
|
||||
load_state->game->public_.hash = load_state->hash->hash;
|
||||
}
|
||||
@ -2032,7 +2079,7 @@ static void rc_client_begin_fetch_game_data(rc_client_load_state_t* load_state)
|
||||
rc_mutex_lock(&client->state.mutex);
|
||||
result = client->state.user;
|
||||
if (result == RC_CLIENT_USER_STATE_LOGIN_REQUESTED)
|
||||
load_state->progress = RC_CLIENT_LOAD_STATE_AWAIT_LOGIN;
|
||||
load_state->progress = RC_CLIENT_LOAD_GAME_STATE_AWAIT_LOGIN;
|
||||
rc_mutex_unlock(&client->state.mutex);
|
||||
|
||||
switch (result) {
|
||||
@ -2059,7 +2106,7 @@ static void rc_client_begin_fetch_game_data(rc_client_load_state_t* load_state)
|
||||
return;
|
||||
}
|
||||
|
||||
rc_client_begin_load_state(load_state, RC_CLIENT_LOAD_STATE_FETCHING_GAME_DATA, 1);
|
||||
rc_client_begin_load_state(load_state, RC_CLIENT_LOAD_GAME_STATE_FETCHING_GAME_DATA, 1);
|
||||
|
||||
RC_CLIENT_LOG_VERBOSE_FORMATTED(client, "Fetching data for game %u", fetch_game_data_request.game_id);
|
||||
rc_client_begin_async(client, &load_state->async_handle);
|
||||
@ -2201,7 +2248,7 @@ static rc_client_async_handle_t* rc_client_load_game(rc_client_load_state_t* loa
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rc_client_begin_load_state(load_state, RC_CLIENT_LOAD_STATE_IDENTIFYING_GAME, 1);
|
||||
rc_client_begin_load_state(load_state, RC_CLIENT_LOAD_GAME_STATE_IDENTIFYING_GAME, 1);
|
||||
|
||||
rc_client_begin_async(client, &load_state->async_handle);
|
||||
client->callbacks.server_call(&request, rc_client_identify_game_callback, load_state, client);
|
||||
@ -2217,14 +2264,6 @@ static rc_client_async_handle_t* rc_client_load_game(rc_client_load_state_t* loa
|
||||
return (client->state.load == load_state) ? &load_state->async_handle : NULL;
|
||||
}
|
||||
|
||||
rc_hash_iterator_t* rc_client_get_load_state_hash_iterator(rc_client_t* client)
|
||||
{
|
||||
if (client && client->state.load)
|
||||
return &client->state.load->hash_iterator;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rc_client_async_handle_t* rc_client_begin_load_game(rc_client_t* client, const char* hash, rc_client_callback_t callback, void* callback_userdata)
|
||||
{
|
||||
rc_client_load_state_t* load_state;
|
||||
@ -2257,6 +2296,16 @@ rc_client_async_handle_t* rc_client_begin_load_game(rc_client_t* client, const c
|
||||
return rc_client_load_game(load_state, hash, NULL);
|
||||
}
|
||||
|
||||
#ifdef RC_CLIENT_SUPPORTS_HASH
|
||||
|
||||
rc_hash_iterator_t* rc_client_get_load_state_hash_iterator(rc_client_t* client)
|
||||
{
|
||||
if (client && client->state.load)
|
||||
return &client->state.load->hash_iterator;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rc_client_async_handle_t* rc_client_begin_identify_and_load_game(rc_client_t* client,
|
||||
uint32_t console_id, const char* file_path,
|
||||
const uint8_t* data, size_t data_size,
|
||||
@ -2340,6 +2389,22 @@ rc_client_async_handle_t* rc_client_begin_identify_and_load_game(rc_client_t* cl
|
||||
return rc_client_load_game(load_state, hash, file_path);
|
||||
}
|
||||
|
||||
#endif /* RC_CLIENT_SUPPORTS_HASH */
|
||||
|
||||
int rc_client_get_load_game_state(const rc_client_t* client)
|
||||
{
|
||||
int state = RC_CLIENT_LOAD_GAME_STATE_NONE;
|
||||
if (client) {
|
||||
const rc_client_load_state_t* load_state = client->state.load;
|
||||
if (load_state)
|
||||
state = load_state->progress;
|
||||
else if (client->game)
|
||||
state = RC_CLIENT_LOAD_GAME_STATE_DONE;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
static void rc_client_game_mark_ui_to_be_hidden(rc_client_t* client, rc_client_game_info_t* game)
|
||||
{
|
||||
rc_client_achievement_info_t* achievement;
|
||||
@ -2428,8 +2493,10 @@ void rc_client_unload_game(rc_client_t* client)
|
||||
}
|
||||
}
|
||||
|
||||
static void rc_client_change_media(rc_client_t* client, const rc_client_game_hash_t* game_hash, rc_client_callback_t callback, void* callback_userdata)
|
||||
static void rc_client_change_media_internal(rc_client_t* client, const rc_client_game_hash_t* game_hash, rc_client_callback_t callback, void* callback_userdata)
|
||||
{
|
||||
client->game->public_.hash = game_hash->hash;
|
||||
|
||||
if (game_hash->game_id == client->game->public_.id) {
|
||||
RC_CLIENT_LOG_INFO_FORMATTED(client, "Switching to valid media for game %u: %s", game_hash->game_id, game_hash->hash);
|
||||
}
|
||||
@ -2437,13 +2504,19 @@ static void rc_client_change_media(rc_client_t* client, const rc_client_game_has
|
||||
RC_CLIENT_LOG_INFO(client, "Switching to unknown media");
|
||||
}
|
||||
else if (game_hash->game_id == 0) {
|
||||
if (client->state.hardcore) {
|
||||
RC_CLIENT_LOG_WARN_FORMATTED(client, "Disabling hardcore for unidentified media: %s", game_hash->hash);
|
||||
rc_client_set_hardcore_enabled(client, 0);
|
||||
callback(RC_HARDCORE_DISABLED, "Hardcore disabled. Unidentified media inserted.", client, callback_userdata);
|
||||
return;
|
||||
}
|
||||
|
||||
RC_CLIENT_LOG_INFO_FORMATTED(client, "Switching to unrecognized media: %s", game_hash->hash);
|
||||
}
|
||||
else {
|
||||
RC_CLIENT_LOG_INFO_FORMATTED(client, "Switching to known media for game %u: %s", game_hash->game_id, game_hash->hash);
|
||||
}
|
||||
|
||||
client->game->public_.hash = game_hash->hash;
|
||||
callback(RC_OK, NULL, client, callback_userdata);
|
||||
}
|
||||
|
||||
@ -2475,22 +2548,65 @@ static void rc_client_identify_changed_media_callback(const rc_api_server_respon
|
||||
else {
|
||||
load_state->hash->game_id = resolve_hash_response.game_id;
|
||||
|
||||
if (resolve_hash_response.game_id == 0 && client->state.hardcore) {
|
||||
RC_CLIENT_LOG_WARN_FORMATTED(client, "Disabling hardcore for unidentified media: %s", load_state->hash->hash);
|
||||
rc_client_set_hardcore_enabled(client, 0);
|
||||
client->game->public_.hash = load_state->hash->hash; /* do still update the loaded hash */
|
||||
load_state->callback(RC_HARDCORE_DISABLED, "Hardcore disabled. Unidentified media inserted.", client, load_state->callback_userdata);
|
||||
}
|
||||
else {
|
||||
if (resolve_hash_response.game_id != 0) {
|
||||
RC_CLIENT_LOG_INFO_FORMATTED(client, "Identified game: %u (%s)", load_state->hash->game_id, load_state->hash->hash);
|
||||
rc_client_change_media(client, load_state->hash, load_state->callback, load_state->callback_userdata);
|
||||
}
|
||||
|
||||
rc_client_change_media_internal(client, load_state->hash, load_state->callback, load_state->callback_userdata);
|
||||
}
|
||||
|
||||
free(load_state);
|
||||
rc_api_destroy_resolve_hash_response(&resolve_hash_response);
|
||||
}
|
||||
|
||||
static rc_client_async_handle_t* rc_client_begin_change_media_internal(rc_client_t* client,
|
||||
rc_client_game_info_t* game, rc_client_game_hash_t* game_hash, rc_client_callback_t callback, void* callback_userdata)
|
||||
{
|
||||
rc_client_load_state_t* callback_data;
|
||||
rc_client_async_handle_t* async_handle;
|
||||
rc_api_resolve_hash_request_t resolve_hash_request;
|
||||
rc_api_request_t request;
|
||||
int result;
|
||||
|
||||
if (game_hash->game_id != RC_CLIENT_UNKNOWN_GAME_ID) {
|
||||
rc_client_change_media_internal(client, game_hash, callback, callback_userdata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* call the server to make sure the hash is valid for the loaded game */
|
||||
memset(&resolve_hash_request, 0, sizeof(resolve_hash_request));
|
||||
resolve_hash_request.game_hash = game_hash->hash;
|
||||
|
||||
result = rc_api_init_resolve_hash_request(&request, &resolve_hash_request);
|
||||
if (result != RC_OK) {
|
||||
callback(result, rc_error_str(result), client, callback_userdata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
callback_data = (rc_client_load_state_t*)calloc(1, sizeof(rc_client_load_state_t));
|
||||
if (!callback_data) {
|
||||
callback(RC_OUT_OF_MEMORY, rc_error_str(RC_OUT_OF_MEMORY), client, callback_userdata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
callback_data->callback = callback;
|
||||
callback_data->callback_userdata = callback_userdata;
|
||||
callback_data->client = client;
|
||||
callback_data->hash = game_hash;
|
||||
callback_data->game = game;
|
||||
|
||||
async_handle = &callback_data->async_handle;
|
||||
rc_client_begin_async(client, async_handle);
|
||||
client->callbacks.server_call(&request, rc_client_identify_changed_media_callback, callback_data, client);
|
||||
|
||||
rc_api_destroy_request(&request);
|
||||
|
||||
/* if handle is no longer valid, the async operation completed synchronously */
|
||||
return rc_client_async_handle_valid(client, async_handle) ? async_handle : NULL;
|
||||
}
|
||||
|
||||
#ifdef RC_CLIENT_SUPPORTS_HASH
|
||||
|
||||
rc_client_async_handle_t* rc_client_begin_change_media(rc_client_t* client, const char* file_path,
|
||||
const uint8_t* data, size_t data_size, rc_client_callback_t callback, void* callback_userdata)
|
||||
{
|
||||
@ -2521,12 +2637,8 @@ rc_client_async_handle_t* rc_client_begin_change_media(rc_client_t* client, cons
|
||||
if (game->public_.console_id == 0) {
|
||||
/* still waiting for game data */
|
||||
pending_media = client->state.load->pending_media;
|
||||
if (pending_media) {
|
||||
if (pending_media->data)
|
||||
free(pending_media->data);
|
||||
free((void*)pending_media->file_path);
|
||||
free(pending_media);
|
||||
}
|
||||
if (pending_media)
|
||||
rc_client_free_pending_media(pending_media);
|
||||
|
||||
pending_media = (rc_client_pending_media_t*)calloc(1, sizeof(*pending_media));
|
||||
if (!pending_media) {
|
||||
@ -2613,53 +2725,78 @@ rc_client_async_handle_t* rc_client_begin_change_media(rc_client_t* client, cons
|
||||
rc_mutex_unlock(&client->state.mutex);
|
||||
|
||||
if (!result) {
|
||||
rc_client_change_media(client, game_hash, callback, callback_userdata);
|
||||
rc_client_change_media_internal(client, game_hash, callback, callback_userdata);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (game_hash->game_id != RC_CLIENT_UNKNOWN_GAME_ID) {
|
||||
rc_client_change_media(client, game_hash, callback, callback_userdata);
|
||||
return rc_client_begin_change_media_internal(client, game, game_hash, callback, callback_userdata);
|
||||
}
|
||||
|
||||
#endif /* RC_CLIENT_SUPPORTS_HASH */
|
||||
|
||||
rc_client_async_handle_t* rc_client_begin_change_media_from_hash(rc_client_t* client, const char* hash,
|
||||
rc_client_callback_t callback, void* callback_userdata)
|
||||
{
|
||||
rc_client_game_hash_t* game_hash;
|
||||
rc_client_game_info_t* game;
|
||||
rc_client_pending_media_t* pending_media = NULL;
|
||||
|
||||
if (!client) {
|
||||
callback(RC_INVALID_STATE, "client is required", client, callback_userdata);
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
/* call the server to make sure the hash is valid for the loaded game */
|
||||
rc_client_load_state_t* callback_data;
|
||||
rc_client_async_handle_t* async_handle;
|
||||
rc_api_resolve_hash_request_t resolve_hash_request;
|
||||
rc_api_request_t request;
|
||||
int result;
|
||||
|
||||
memset(&resolve_hash_request, 0, sizeof(resolve_hash_request));
|
||||
resolve_hash_request.game_hash = game_hash->hash;
|
||||
|
||||
result = rc_api_init_resolve_hash_request(&request, &resolve_hash_request);
|
||||
if (result != RC_OK) {
|
||||
callback(result, rc_error_str(result), client, callback_userdata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
callback_data = (rc_client_load_state_t*)calloc(1, sizeof(rc_client_load_state_t));
|
||||
if (!callback_data) {
|
||||
callback(RC_OUT_OF_MEMORY, rc_error_str(RC_OUT_OF_MEMORY), client, callback_userdata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
callback_data->callback = callback;
|
||||
callback_data->callback_userdata = callback_userdata;
|
||||
callback_data->client = client;
|
||||
callback_data->hash = game_hash;
|
||||
callback_data->game = game;
|
||||
|
||||
async_handle = &callback_data->async_handle;
|
||||
rc_client_begin_async(client, async_handle);
|
||||
client->callbacks.server_call(&request, rc_client_identify_changed_media_callback, callback_data, client);
|
||||
|
||||
rc_api_destroy_request(&request);
|
||||
|
||||
/* if handle is no longer valid, the async operation completed synchronously */
|
||||
return rc_client_async_handle_valid(client, async_handle) ? async_handle : NULL;
|
||||
if (!hash || !hash[0]) {
|
||||
callback(RC_INVALID_STATE, "hash is required", client, callback_userdata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef RC_CLIENT_SUPPORTS_EXTERNAL
|
||||
if (client->state.external_client && client->state.external_client->begin_change_media_from_hash) {
|
||||
return client->state.external_client->begin_change_media_from_hash(client, hash, callback, callback_userdata);
|
||||
}
|
||||
#endif
|
||||
|
||||
rc_mutex_lock(&client->state.mutex);
|
||||
if (client->state.load) {
|
||||
game = client->state.load->game;
|
||||
if (game->public_.console_id == 0) {
|
||||
/* still waiting for game data */
|
||||
pending_media = client->state.load->pending_media;
|
||||
if (pending_media)
|
||||
rc_client_free_pending_media(pending_media);
|
||||
|
||||
pending_media = (rc_client_pending_media_t*)calloc(1, sizeof(*pending_media));
|
||||
if (!pending_media) {
|
||||
rc_mutex_unlock(&client->state.mutex);
|
||||
callback(RC_OUT_OF_MEMORY, rc_error_str(RC_OUT_OF_MEMORY), client, callback_userdata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pending_media->hash = strdup(hash);
|
||||
pending_media->callback = callback;
|
||||
pending_media->callback_userdata = callback_userdata;
|
||||
|
||||
client->state.load->pending_media = pending_media;
|
||||
}
|
||||
} else {
|
||||
game = client->game;
|
||||
}
|
||||
rc_mutex_unlock(&client->state.mutex);
|
||||
|
||||
if (!game) {
|
||||
callback(RC_NO_GAME_LOADED, rc_error_str(RC_NO_GAME_LOADED), client, callback_userdata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* still waiting for game data */
|
||||
if (pending_media)
|
||||
return NULL;
|
||||
|
||||
/* check to see if we've already hashed this file. */
|
||||
game_hash = rc_client_find_game_hash(client, hash);
|
||||
return rc_client_begin_change_media_internal(client, game, game_hash, callback, callback_userdata);
|
||||
}
|
||||
|
||||
const rc_client_game_t* rc_client_get_game_info(const rc_client_t* client)
|
||||
@ -3753,7 +3890,7 @@ int rc_client_has_leaderboards(rc_client_t* client)
|
||||
return result;
|
||||
}
|
||||
|
||||
static void rc_client_allocate_leaderboard_tracker(rc_client_game_info_t* game, rc_client_leaderboard_info_t* leaderboard)
|
||||
void rc_client_allocate_leaderboard_tracker(rc_client_game_info_t* game, rc_client_leaderboard_info_t* leaderboard)
|
||||
{
|
||||
rc_client_leaderboard_tracker_info_t* tracker;
|
||||
rc_client_leaderboard_tracker_info_t* available_tracker = NULL;
|
||||
@ -5234,6 +5371,11 @@ size_t rc_client_progress_size(rc_client_t* client)
|
||||
}
|
||||
|
||||
int rc_client_serialize_progress(rc_client_t* client, uint8_t* buffer)
|
||||
{
|
||||
return rc_client_serialize_progress_sized(client, buffer, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
int rc_client_serialize_progress_sized(rc_client_t* client, uint8_t* buffer, size_t buffer_size)
|
||||
{
|
||||
int result;
|
||||
|
||||
@ -5242,7 +5384,7 @@ int rc_client_serialize_progress(rc_client_t* client, uint8_t* buffer)
|
||||
|
||||
#ifdef RC_CLIENT_SUPPORTS_EXTERNAL
|
||||
if (client->state.external_client && client->state.external_client->serialize_progress)
|
||||
return client->state.external_client->serialize_progress(buffer);
|
||||
return client->state.external_client->serialize_progress(buffer, buffer_size);
|
||||
#endif
|
||||
|
||||
if (!client->game)
|
||||
@ -5252,7 +5394,7 @@ int rc_client_serialize_progress(rc_client_t* client, uint8_t* buffer)
|
||||
return RC_INVALID_STATE;
|
||||
|
||||
rc_mutex_lock(&client->state.mutex);
|
||||
result = rc_runtime_serialize_progress(buffer, &client->game->runtime, NULL);
|
||||
result = rc_runtime_serialize_progress_sized(buffer, (uint32_t)buffer_size, &client->game->runtime, NULL);
|
||||
rc_mutex_unlock(&client->state.mutex);
|
||||
|
||||
return result;
|
||||
@ -5352,6 +5494,11 @@ static void rc_client_subset_after_deserialize_progress(rc_client_game_info_t* g
|
||||
}
|
||||
|
||||
int rc_client_deserialize_progress(rc_client_t* client, const uint8_t* serialized)
|
||||
{
|
||||
return rc_client_deserialize_progress_sized(client, serialized, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
int rc_client_deserialize_progress_sized(rc_client_t* client, const uint8_t* serialized, size_t serialized_size)
|
||||
{
|
||||
rc_client_subset_info_t* subset;
|
||||
int result;
|
||||
@ -5361,7 +5508,7 @@ int rc_client_deserialize_progress(rc_client_t* client, const uint8_t* serialize
|
||||
|
||||
#ifdef RC_CLIENT_SUPPORTS_EXTERNAL
|
||||
if (client->state.external_client && client->state.external_client->deserialize_progress)
|
||||
return client->state.external_client->deserialize_progress(serialized);
|
||||
return client->state.external_client->deserialize_progress(serialized, serialized_size);
|
||||
#endif
|
||||
|
||||
if (!client->game)
|
||||
@ -5381,7 +5528,7 @@ int rc_client_deserialize_progress(rc_client_t* client, const uint8_t* serialize
|
||||
result = RC_OK;
|
||||
}
|
||||
else {
|
||||
result = rc_runtime_deserialize_progress(&client->game->runtime, serialized, NULL);
|
||||
result = rc_runtime_deserialize_progress_sized(&client->game->runtime, serialized, (uint32_t)serialized_size, NULL);
|
||||
}
|
||||
|
||||
for (subset = client->game->subsets; subset; subset = subset->next)
|
||||
|
5
deps/rcheevos/src/rc_client_external.h
vendored
5
deps/rcheevos/src/rc_client_external.h
vendored
@ -61,8 +61,8 @@ typedef rc_client_async_handle_t* (RC_CCONV *rc_client_external_begin_fetch_lead
|
||||
|
||||
|
||||
typedef size_t (RC_CCONV *rc_client_external_progress_size_func_t)(void);
|
||||
typedef int (RC_CCONV *rc_client_external_serialize_progress_func_t)(uint8_t* buffer);
|
||||
typedef int (RC_CCONV *rc_client_external_deserialize_progress_func_t)(const uint8_t* buffer);
|
||||
typedef int (RC_CCONV *rc_client_external_serialize_progress_func_t)(uint8_t* buffer, size_t buffer_size);
|
||||
typedef int (RC_CCONV *rc_client_external_deserialize_progress_func_t)(const uint8_t* buffer, size_t buffer_size);
|
||||
|
||||
typedef struct rc_client_external_t
|
||||
{
|
||||
@ -99,6 +99,7 @@ typedef struct rc_client_external_t
|
||||
rc_client_external_action_func_t unload_game;
|
||||
rc_client_external_get_user_game_summary_func_t get_user_game_summary;
|
||||
rc_client_external_begin_change_media_func_t begin_change_media;
|
||||
rc_client_external_begin_load_game_func_t begin_change_media_from_hash;
|
||||
|
||||
rc_client_external_create_achievement_list_func_t create_achievement_list;
|
||||
rc_client_external_get_int_func_t has_achievements;
|
||||
|
16
deps/rcheevos/src/rc_client_internal.h
vendored
16
deps/rcheevos/src/rc_client_internal.h
vendored
@ -26,6 +26,8 @@ typedef void (RC_CCONV *rc_client_post_process_game_data_response_t)(const rc_ap
|
||||
typedef int (RC_CCONV *rc_client_can_submit_achievement_unlock_t)(uint32_t achievement_id, rc_client_t* client);
|
||||
typedef int (RC_CCONV *rc_client_can_submit_leaderboard_entry_t)(uint32_t leaderboard_id, rc_client_t* client);
|
||||
typedef int (RC_CCONV *rc_client_rich_presence_override_t)(rc_client_t* client, char buffer[], size_t buffersize);
|
||||
typedef uint32_t (RC_CCONV* rc_client_identify_hash_func_t)(uint32_t console_id, const char* hash,
|
||||
rc_client_t* client, void* callback_userdata);
|
||||
|
||||
typedef struct rc_client_callbacks_t {
|
||||
rc_client_read_memory_func_t read_memory;
|
||||
@ -33,6 +35,7 @@ typedef struct rc_client_callbacks_t {
|
||||
rc_client_server_call_t server_call;
|
||||
rc_client_message_callback_t log_call;
|
||||
rc_get_time_millisecs_func_t get_time_millisecs;
|
||||
rc_client_identify_hash_func_t identify_unknown_hash;
|
||||
rc_client_post_process_game_data_response_t post_process_game_data_response;
|
||||
rc_client_can_submit_achievement_unlock_t can_submit_achievement_unlock;
|
||||
rc_client_can_submit_leaderboard_entry_t can_submit_leaderboard_entry;
|
||||
@ -265,16 +268,6 @@ void rc_client_update_active_leaderboards(rc_client_game_info_t* game);
|
||||
| Client |
|
||||
\*****************************************************************************/
|
||||
|
||||
enum {
|
||||
RC_CLIENT_LOAD_STATE_NONE,
|
||||
RC_CLIENT_LOAD_STATE_IDENTIFYING_GAME,
|
||||
RC_CLIENT_LOAD_STATE_AWAIT_LOGIN,
|
||||
RC_CLIENT_LOAD_STATE_FETCHING_GAME_DATA,
|
||||
RC_CLIENT_LOAD_STATE_STARTING_SESSION,
|
||||
RC_CLIENT_LOAD_STATE_DONE,
|
||||
RC_CLIENT_LOAD_STATE_UNKNOWN_GAME
|
||||
};
|
||||
|
||||
enum {
|
||||
RC_CLIENT_USER_STATE_NONE,
|
||||
RC_CLIENT_USER_STATE_LOGIN_REQUESTED,
|
||||
@ -375,8 +368,10 @@ int rc_value_contains_memref(const rc_value_t* value, const rc_memref_t* memref)
|
||||
/* end runtime.c internals */
|
||||
|
||||
/* helper functions for unit tests */
|
||||
#ifdef RC_CLIENT_SUPPORTS_HASH
|
||||
struct rc_hash_iterator;
|
||||
struct rc_hash_iterator* rc_client_get_load_state_hash_iterator(rc_client_t* client);
|
||||
#endif
|
||||
/* end helper functions for unit tests */
|
||||
|
||||
enum {
|
||||
@ -387,6 +382,7 @@ enum {
|
||||
|
||||
void rc_client_set_legacy_peek(rc_client_t* client, int method);
|
||||
|
||||
void rc_client_allocate_leaderboard_tracker(rc_client_game_info_t* game, rc_client_leaderboard_info_t* leaderboard);
|
||||
void rc_client_release_leaderboard_tracker(rc_client_game_info_t* game, rc_client_leaderboard_info_t* leaderboard);
|
||||
|
||||
RC_END_C_DECLS
|
||||
|
37
deps/rcheevos/src/rc_client_raintegration.c
vendored
37
deps/rcheevos/src/rc_client_raintegration.c
vendored
@ -77,7 +77,9 @@ static void rc_client_raintegration_load_dll(rc_client_t* client,
|
||||
raintegration->get_menu = (rc_client_raintegration_get_menu_func_t)GetProcAddress(hDLL, "_Rcheevos_RAIntegrationGetMenu");
|
||||
raintegration->activate_menu_item = (rc_client_raintegration_activate_menuitem_func_t)GetProcAddress(hDLL, "_Rcheevos_ActivateRAIntegrationMenuItem");
|
||||
raintegration->set_write_memory_function = (rc_client_raintegration_set_write_memory_func_t)GetProcAddress(hDLL, "_Rcheevos_SetRAIntegrationWriteMemoryFunction");
|
||||
raintegration->set_get_game_name_function = (rc_client_raintegration_set_get_game_name_func_t)GetProcAddress(hDLL, "_Rcheevos_SetRAIntegrationGetGameNameFunction");
|
||||
raintegration->set_event_handler = (rc_client_raintegration_set_event_handler_func_t)GetProcAddress(hDLL, "_Rcheevos_SetRAIntegrationEventHandler");
|
||||
raintegration->has_modifications = (rc_client_raintegration_get_int_func_t)GetProcAddress(hDLL, "_Rcheevos_HasModifications");
|
||||
|
||||
if (!raintegration->get_version ||
|
||||
!raintegration->init_client ||
|
||||
@ -147,7 +149,8 @@ static void rc_client_init_raintegration(rc_client_t* client,
|
||||
const char* host_url = client->state.raintegration->get_host_url();
|
||||
if (host_url) {
|
||||
if (strcmp(host_url, "OFFLINE") != 0) {
|
||||
rc_client_set_host(client, host_url);
|
||||
if (strcmp(host_url, "https://retroachievements.org") != 0)
|
||||
rc_client_set_host(client, host_url);
|
||||
}
|
||||
else if (client->state.raintegration->init_client_offline) {
|
||||
init_func = client->state.raintegration->init_client_offline;
|
||||
@ -363,6 +366,12 @@ void rc_client_raintegration_set_write_memory_function(rc_client_t* client, rc_c
|
||||
client->state.raintegration->set_write_memory_function(client, handler);
|
||||
}
|
||||
|
||||
void rc_client_raintegration_set_get_game_name_function(rc_client_t* client, rc_client_raintegration_get_game_name_func_t handler)
|
||||
{
|
||||
if (client && client->state.raintegration && client->state.raintegration->set_get_game_name_function)
|
||||
client->state.raintegration->set_get_game_name_function(client, handler);
|
||||
}
|
||||
|
||||
void rc_client_raintegration_set_event_handler(rc_client_t* client,
|
||||
rc_client_raintegration_event_handler_t handler)
|
||||
{
|
||||
@ -382,6 +391,18 @@ const rc_client_raintegration_menu_t* rc_client_raintegration_get_menu(const rc_
|
||||
return client->state.raintegration->get_menu();
|
||||
}
|
||||
|
||||
int rc_client_raintegration_has_modifications(const rc_client_t* client)
|
||||
{
|
||||
if (!client || !client->state.raintegration ||
|
||||
!client->state.raintegration->bIsInited ||
|
||||
!client->state.raintegration->has_modifications)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return client->state.raintegration->has_modifications();
|
||||
}
|
||||
|
||||
void rc_client_raintegration_rebuild_submenu(rc_client_t* client, HMENU hMenu)
|
||||
{
|
||||
HMENU hPopupMenu = NULL;
|
||||
@ -413,7 +434,7 @@ void rc_client_raintegration_rebuild_submenu(rc_client_t* client, HMENU hMenu)
|
||||
if (menuitem->checked)
|
||||
flags |= MF_CHECKED;
|
||||
if (!menuitem->enabled)
|
||||
flags |= MF_DISABLED | MF_GRAYED;
|
||||
flags |= MF_GRAYED;
|
||||
|
||||
AppendMenuA(hPopupMenu, flags, menuitem->id, menuitem->label);
|
||||
}
|
||||
@ -428,7 +449,7 @@ void rc_client_raintegration_rebuild_submenu(rc_client_t* client, HMENU hMenu)
|
||||
|
||||
UINT flags = MF_POPUP | MF_STRING;
|
||||
if (!menu || !menu->num_items)
|
||||
flags |= MF_DISABLED | MF_GRAYED;
|
||||
flags |= MF_GRAYED;
|
||||
|
||||
while (--nIndex >= 0)
|
||||
{
|
||||
@ -457,15 +478,18 @@ void rc_client_raintegration_update_menu_item(const rc_client_t* client, const r
|
||||
flags |= MF_CHECKED;
|
||||
|
||||
CheckMenuItem(client->state.raintegration->hPopupMenu, menuitem->id, flags | MF_BYCOMMAND);
|
||||
|
||||
flags = (menuitem->enabled) ? MF_ENABLED : MF_GRAYED;
|
||||
EnableMenuItem(client->state.raintegration->hPopupMenu, menuitem->id, flags | MF_BYCOMMAND);
|
||||
}
|
||||
}
|
||||
|
||||
int rc_client_raintegration_activate_menu_item(const rc_client_t* client, uint32_t nMenuItemId)
|
||||
int rc_client_raintegration_activate_menu_item(const rc_client_t* client, uint32_t menu_item_id)
|
||||
{
|
||||
if (!client || !client->state.raintegration || !client->state.raintegration->activate_menu_item)
|
||||
return 0;
|
||||
|
||||
return client->state.raintegration->activate_menu_item(nMenuItemId);
|
||||
return client->state.raintegration->activate_menu_item(menu_item_id);
|
||||
}
|
||||
|
||||
void rc_client_unload_raintegration(rc_client_t* client)
|
||||
@ -477,6 +501,9 @@ void rc_client_unload_raintegration(rc_client_t* client)
|
||||
|
||||
RC_CLIENT_LOG_INFO(client, "Unloading RA_Integration")
|
||||
|
||||
if (client->state.external_client && client->state.external_client->destroy)
|
||||
client->state.external_client->destroy();
|
||||
|
||||
if (client->state.raintegration->shutdown)
|
||||
client->state.raintegration->shutdown();
|
||||
|
||||
|
@ -20,7 +20,9 @@ typedef void (RC_CCONV* rc_client_raintegration_hwnd_action_func_t)(HWND hWnd);
|
||||
typedef const rc_client_raintegration_menu_t* (RC_CCONV* rc_client_raintegration_get_menu_func_t)(void);
|
||||
typedef int (RC_CCONV* rc_client_raintegration_activate_menuitem_func_t)(uint32_t nMenuItemId);
|
||||
typedef void (RC_CCONV* rc_client_raintegration_set_write_memory_func_t)(rc_client_t* pClient, rc_client_raintegration_write_memory_func_t handler);
|
||||
typedef void (RC_CCONV* rc_client_raintegration_set_get_game_name_func_t)(rc_client_t* pClient, rc_client_raintegration_get_game_name_func_t handler);
|
||||
typedef void (RC_CCONV* rc_client_raintegration_set_event_handler_func_t)(rc_client_t* pClient, rc_client_raintegration_event_handler_t handler);
|
||||
typedef int (RC_CCONV* rc_client_raintegration_get_int_func_t)(void);
|
||||
|
||||
typedef struct rc_client_raintegration_t
|
||||
{
|
||||
@ -37,9 +39,11 @@ typedef struct rc_client_raintegration_t
|
||||
rc_client_raintegration_hwnd_action_func_t update_main_window_handle;
|
||||
|
||||
rc_client_raintegration_set_write_memory_func_t set_write_memory_function;
|
||||
rc_client_raintegration_set_get_game_name_func_t set_get_game_name_function;
|
||||
rc_client_raintegration_set_event_handler_func_t set_event_handler;
|
||||
rc_client_raintegration_get_menu_func_t get_menu;
|
||||
rc_client_raintegration_activate_menuitem_func_t activate_menu_item;
|
||||
rc_client_raintegration_get_int_func_t has_modifications;
|
||||
|
||||
rc_client_raintegration_get_external_client_func_t get_external_client;
|
||||
|
||||
|
1
deps/rcheevos/src/rc_util.c
vendored
1
deps/rcheevos/src/rc_util.c
vendored
@ -183,6 +183,7 @@ const char* rc_error_str(int ret)
|
||||
case RC_ACCESS_DENIED: return "Access denied";
|
||||
case RC_INVALID_CREDENTIALS: return "Invalid credentials";
|
||||
case RC_EXPIRED_TOKEN: return "Expired token";
|
||||
case RC_INSUFFICIENT_BUFFER: return "Buffer not large enough";
|
||||
default: return "Unknown error";
|
||||
}
|
||||
}
|
||||
|
2
deps/rcheevos/src/rc_version.h
vendored
2
deps/rcheevos/src/rc_version.h
vendored
@ -8,7 +8,7 @@
|
||||
RC_BEGIN_C_DECLS
|
||||
|
||||
#define RCHEEVOS_VERSION_MAJOR 11
|
||||
#define RCHEEVOS_VERSION_MINOR 1
|
||||
#define RCHEEVOS_VERSION_MINOR 2
|
||||
#define RCHEEVOS_VERSION_PATCH 0
|
||||
|
||||
#define RCHEEVOS_MAKE_VERSION(major, minor, patch) (major * 1000000 + minor * 1000 + patch)
|
||||
|
37
deps/rcheevos/src/rcheevos/memref.c
vendored
37
deps/rcheevos/src/rcheevos/memref.c
vendored
@ -95,6 +95,8 @@ int rc_parse_memref(const char** memaddr, uint8_t* size, uint32_t* address) {
|
||||
switch (*aux++) {
|
||||
case 'f': case 'F': *size = RC_MEMSIZE_FLOAT; break;
|
||||
case 'b': case 'B': *size = RC_MEMSIZE_FLOAT_BE; break;
|
||||
case 'h': case 'H': *size = RC_MEMSIZE_DOUBLE32; break;
|
||||
case 'i': case 'I': *size = RC_MEMSIZE_DOUBLE32_BE; break;
|
||||
case 'm': case 'M': *size = RC_MEMSIZE_MBF32; break;
|
||||
case 'l': case 'L': *size = RC_MEMSIZE_MBF32_LE; break;
|
||||
|
||||
@ -198,6 +200,29 @@ static void rc_transform_memref_float_be(rc_typed_value_t* value) {
|
||||
value->type = RC_VALUE_TYPE_FLOAT;
|
||||
}
|
||||
|
||||
static void rc_transform_memref_double32(rc_typed_value_t* value)
|
||||
{
|
||||
/* decodes the four most significant bytes of an IEEE 754 double into a float */
|
||||
const uint32_t mantissa = (value->value.u32 & 0x000FFFFF) << 3;
|
||||
const int32_t exponent = (int32_t)((value->value.u32 >> 20) & 0x7FF) - 1023;
|
||||
const int sign = (value->value.u32 & 0x80000000);
|
||||
value->value.f32 = rc_build_float(mantissa, exponent, sign);
|
||||
value->type = RC_VALUE_TYPE_FLOAT;
|
||||
}
|
||||
|
||||
static void rc_transform_memref_double32_be(rc_typed_value_t* value)
|
||||
{
|
||||
/* decodes the four most significant bytes of an IEEE 754 double in big endian format into a float */
|
||||
const uint32_t mantissa = (((value->value.u32 & 0xFF000000) >> 24) |
|
||||
((value->value.u32 & 0x00FF0000) >> 8) |
|
||||
((value->value.u32 & 0x00000F00) << 8)) << 3;
|
||||
const int32_t exponent = (int32_t)(((value->value.u32 & 0x0000007F) << 4) |
|
||||
((value->value.u32 & 0x0000F000) >> 12)) - 1023;
|
||||
const int sign = (value->value.u32 & 0x00000080);
|
||||
value->value.f32 = rc_build_float(mantissa, exponent, sign);
|
||||
value->type = RC_VALUE_TYPE_FLOAT;
|
||||
}
|
||||
|
||||
static void rc_transform_memref_mbf32(rc_typed_value_t* value) {
|
||||
/* decodes a Microsoft Binary Format float */
|
||||
/* NOTE: 32-bit MBF is stored in memory as big endian (at least for Apple II) */
|
||||
@ -322,6 +347,14 @@ void rc_transform_memref_value(rc_typed_value_t* value, uint8_t size) {
|
||||
rc_transform_memref_float_be(value);
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_DOUBLE32:
|
||||
rc_transform_memref_double32(value);
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_DOUBLE32_BE:
|
||||
rc_transform_memref_double32_be(value);
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_MBF32:
|
||||
rc_transform_memref_mbf32(value);
|
||||
break;
|
||||
@ -358,6 +391,8 @@ static const uint32_t rc_memref_masks[] = {
|
||||
0xffffffff, /* RC_MEMSIZE_MBF32 */
|
||||
0xffffffff, /* RC_MEMSIZE_MBF32_LE */
|
||||
0xffffffff, /* RC_MEMSIZE_FLOAT_BE */
|
||||
0xffffffff, /* RC_MEMSIZE_DOUBLE32 */
|
||||
0xffffffff, /* RC_MEMSIZE_DOUBLE32_BE*/
|
||||
0xffffffff /* RC_MEMSIZE_VARIABLE */
|
||||
};
|
||||
|
||||
@ -395,6 +430,8 @@ static const uint8_t rc_memref_shared_sizes[] = {
|
||||
RC_MEMSIZE_32_BITS, /* RC_MEMSIZE_MBF32 */
|
||||
RC_MEMSIZE_32_BITS, /* RC_MEMSIZE_MBF32_LE */
|
||||
RC_MEMSIZE_32_BITS, /* RC_MEMSIZE_FLOAT_BE */
|
||||
RC_MEMSIZE_32_BITS, /* RC_MEMSIZE_DOUBLE32 */
|
||||
RC_MEMSIZE_32_BITS, /* RC_MEMSIZE_DOUBLE32_BE*/
|
||||
RC_MEMSIZE_32_BITS /* RC_MEMSIZE_VARIABLE */
|
||||
};
|
||||
|
||||
|
2
deps/rcheevos/src/rcheevos/operand.c
vendored
2
deps/rcheevos/src/rcheevos/operand.c
vendored
@ -297,6 +297,8 @@ int rc_operand_is_float_memref(const rc_operand_t* self) {
|
||||
switch (self->size) {
|
||||
case RC_MEMSIZE_FLOAT:
|
||||
case RC_MEMSIZE_FLOAT_BE:
|
||||
case RC_MEMSIZE_DOUBLE32:
|
||||
case RC_MEMSIZE_DOUBLE32_BE:
|
||||
case RC_MEMSIZE_MBF32:
|
||||
case RC_MEMSIZE_MBF32_LE:
|
||||
return 1;
|
||||
|
131
deps/rcheevos/src/rcheevos/runtime_progress.c
vendored
131
deps/rcheevos/src/rcheevos/runtime_progress.c
vendored
@ -4,6 +4,7 @@
|
||||
#include "rc_util.h"
|
||||
#include "../rhash/md5.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -17,17 +18,22 @@
|
||||
|
||||
#define RC_RUNTIME_CHUNK_DONE 0x454E4F44 /* DONE */
|
||||
|
||||
#define RC_RUNTIME_MIN_BUFFER_SIZE 4 + 8 + 16 /* RUNTIME_MARKER, CHUNK_DONE, MD5 */
|
||||
|
||||
typedef struct rc_runtime_progress_t {
|
||||
const rc_runtime_t* runtime;
|
||||
|
||||
uint32_t offset;
|
||||
uint8_t* buffer;
|
||||
uint32_t buffer_size;
|
||||
|
||||
uint32_t chunk_size_offset;
|
||||
|
||||
lua_State* L;
|
||||
} rc_runtime_progress_t;
|
||||
|
||||
#define assert_chunk_size(expected_size) assert((uint32_t)(progress->offset - progress->chunk_size_offset - 4) == (uint32_t)(expected_size))
|
||||
|
||||
#define RC_TRIGGER_STATE_UNUPDATED 0x7F
|
||||
|
||||
#define RC_MEMREF_FLAG_CHANGED_THIS_FRAME 0x00010000
|
||||
@ -117,21 +123,29 @@ static void rc_runtime_progress_init(rc_runtime_progress_t* progress, const rc_r
|
||||
progress->L = L;
|
||||
}
|
||||
|
||||
#define RC_RUNTIME_SERIALIZED_MEMREF_SIZE 16 /* 4x uint: address, flags, value, prior */
|
||||
|
||||
static int rc_runtime_progress_write_memrefs(rc_runtime_progress_t* progress)
|
||||
{
|
||||
rc_memref_t* memref = progress->runtime->memrefs;
|
||||
uint32_t flags = 0;
|
||||
rc_memref_t* memref;
|
||||
uint32_t count = 0;
|
||||
|
||||
for (memref = progress->runtime->memrefs; memref; memref = memref->next)
|
||||
++count;
|
||||
if (count == 0)
|
||||
return RC_OK;
|
||||
|
||||
if (progress->offset + 8 + count * RC_RUNTIME_SERIALIZED_MEMREF_SIZE > progress->buffer_size)
|
||||
return RC_INSUFFICIENT_BUFFER;
|
||||
|
||||
rc_runtime_progress_start_chunk(progress, RC_RUNTIME_CHUNK_MEMREFS);
|
||||
|
||||
if (!progress->buffer) {
|
||||
while (memref) {
|
||||
progress->offset += 16;
|
||||
memref = memref->next;
|
||||
}
|
||||
progress->offset += count * RC_RUNTIME_SERIALIZED_MEMREF_SIZE;
|
||||
}
|
||||
else {
|
||||
while (memref) {
|
||||
uint32_t flags = 0;
|
||||
for (memref = progress->runtime->memrefs; memref; memref = memref->next) {
|
||||
flags = memref->value.size;
|
||||
if (memref->value.changed)
|
||||
flags |= RC_MEMREF_FLAG_CHANGED_THIS_FRAME;
|
||||
@ -140,11 +154,10 @@ static int rc_runtime_progress_write_memrefs(rc_runtime_progress_t* progress)
|
||||
rc_runtime_progress_write_uint(progress, flags);
|
||||
rc_runtime_progress_write_uint(progress, memref->value.value);
|
||||
rc_runtime_progress_write_uint(progress, memref->value.prior);
|
||||
|
||||
memref = memref->next;
|
||||
}
|
||||
}
|
||||
|
||||
assert_chunk_size(count * RC_RUNTIME_SERIALIZED_MEMREF_SIZE);
|
||||
rc_runtime_progress_end_chunk(progress);
|
||||
return RC_OK;
|
||||
}
|
||||
@ -159,7 +172,7 @@ static int rc_runtime_progress_read_memrefs(rc_runtime_progress_t* progress)
|
||||
|
||||
/* re-read the chunk size to determine how many memrefs are present */
|
||||
progress->offset -= 4;
|
||||
entries = rc_runtime_progress_read_uint(progress) / 16;
|
||||
entries = rc_runtime_progress_read_uint(progress) / RC_RUNTIME_SERIALIZED_MEMREF_SIZE;
|
||||
|
||||
while (entries != 0) {
|
||||
address = rc_runtime_progress_read_uint(progress);
|
||||
@ -210,6 +223,9 @@ static int rc_runtime_progress_write_condset(rc_runtime_progress_t* progress, rc
|
||||
rc_condition_t* cond;
|
||||
uint32_t flags;
|
||||
|
||||
if (progress->offset + 4 > progress->buffer_size)
|
||||
return RC_INSUFFICIENT_BUFFER;
|
||||
|
||||
rc_runtime_progress_write_uint(progress, condset->is_paused);
|
||||
|
||||
cond = condset->conditions;
|
||||
@ -230,15 +246,24 @@ static int rc_runtime_progress_write_condset(rc_runtime_progress_t* progress, rc
|
||||
flags |= RC_COND_FLAG_OPERAND2_MEMREF_CHANGED_THIS_FRAME;
|
||||
}
|
||||
|
||||
if (progress->offset + 8 > progress->buffer_size)
|
||||
return RC_INSUFFICIENT_BUFFER;
|
||||
|
||||
rc_runtime_progress_write_uint(progress, cond->current_hits);
|
||||
rc_runtime_progress_write_uint(progress, flags);
|
||||
|
||||
if (flags & RC_COND_FLAG_OPERAND1_IS_INDIRECT_MEMREF) {
|
||||
if (progress->offset + 8 > progress->buffer_size)
|
||||
return RC_INSUFFICIENT_BUFFER;
|
||||
|
||||
rc_runtime_progress_write_uint(progress, cond->operand1.value.memref->value.value);
|
||||
rc_runtime_progress_write_uint(progress, cond->operand1.value.memref->value.prior);
|
||||
}
|
||||
|
||||
if (flags & RC_COND_FLAG_OPERAND2_IS_INDIRECT_MEMREF) {
|
||||
if (progress->offset + 8 > progress->buffer_size)
|
||||
return RC_INSUFFICIENT_BUFFER;
|
||||
|
||||
rc_runtime_progress_write_uint(progress, cond->operand2.value.memref->value.value);
|
||||
rc_runtime_progress_write_uint(progress, cond->operand2.value.memref->value.prior);
|
||||
}
|
||||
@ -310,6 +335,9 @@ static int rc_runtime_progress_write_variable(rc_runtime_progress_t* progress, c
|
||||
{
|
||||
uint32_t flags;
|
||||
|
||||
if (progress->offset + 12 > progress->buffer_size)
|
||||
return RC_INSUFFICIENT_BUFFER;
|
||||
|
||||
flags = rc_runtime_progress_should_serialize_variable_condset(variable->conditions);
|
||||
if (variable->value.changed)
|
||||
flags |= RC_MEMREF_FLAG_CHANGED_THIS_FRAME;
|
||||
@ -331,21 +359,30 @@ static int rc_runtime_progress_write_variables(rc_runtime_progress_t* progress)
|
||||
{
|
||||
uint32_t count = 0;
|
||||
const rc_value_t* variable;
|
||||
int result;
|
||||
|
||||
for (variable = progress->runtime->variables; variable; variable = variable->next)
|
||||
++count;
|
||||
if (count == 0)
|
||||
return RC_OK;
|
||||
|
||||
/* header + count + count(djb2,flags,value,prior,?cond) */
|
||||
if (progress->offset + 8 + 4 + count * 16 > progress->buffer_size)
|
||||
return RC_INSUFFICIENT_BUFFER;
|
||||
|
||||
rc_runtime_progress_start_chunk(progress, RC_RUNTIME_CHUNK_VARIABLES);
|
||||
rc_runtime_progress_write_uint(progress, count);
|
||||
|
||||
for (variable = progress->runtime->variables; variable; variable = variable->next)
|
||||
{
|
||||
for (variable = progress->runtime->variables; variable; variable = variable->next) {
|
||||
uint32_t djb2 = rc_djb2(variable->name);
|
||||
if (progress->offset + 16 > progress->buffer_size)
|
||||
return RC_INSUFFICIENT_BUFFER;
|
||||
|
||||
rc_runtime_progress_write_uint(progress, djb2);
|
||||
|
||||
rc_runtime_progress_write_variable(progress, variable);
|
||||
result = rc_runtime_progress_write_variable(progress, variable);
|
||||
if (result != RC_OK)
|
||||
return result;
|
||||
}
|
||||
|
||||
rc_runtime_progress_end_chunk(progress);
|
||||
@ -493,7 +530,7 @@ static int rc_runtime_progress_read_trigger(rc_runtime_progress_t* progress, rc_
|
||||
static int rc_runtime_progress_write_achievements(rc_runtime_progress_t* progress)
|
||||
{
|
||||
uint32_t i;
|
||||
int offset = 0;
|
||||
int initial_offset = 0;
|
||||
int result;
|
||||
|
||||
for (i = 0; i < progress->runtime->trigger_count; ++i) {
|
||||
@ -511,7 +548,10 @@ static int rc_runtime_progress_write_achievements(rc_runtime_progress_t* progres
|
||||
continue;
|
||||
}
|
||||
|
||||
offset = progress->offset;
|
||||
initial_offset = progress->offset;
|
||||
} else {
|
||||
if (progress->offset + runtime_trigger->serialized_size > progress->buffer_size)
|
||||
return RC_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
rc_runtime_progress_start_chunk(progress, RC_RUNTIME_CHUNK_ACHIEVEMENT);
|
||||
@ -522,10 +562,15 @@ static int rc_runtime_progress_write_achievements(rc_runtime_progress_t* progres
|
||||
if (result != RC_OK)
|
||||
return result;
|
||||
|
||||
if (runtime_trigger->serialized_size) {
|
||||
/* runtime_trigger->serialized_size includes the header */
|
||||
assert_chunk_size(runtime_trigger->serialized_size - 8);
|
||||
}
|
||||
|
||||
rc_runtime_progress_end_chunk(progress);
|
||||
|
||||
if (!progress->buffer)
|
||||
runtime_trigger->serialized_size = progress->offset - offset;
|
||||
runtime_trigger->serialized_size = progress->offset - initial_offset;
|
||||
}
|
||||
|
||||
return RC_OK;
|
||||
@ -556,7 +601,7 @@ static int rc_runtime_progress_write_leaderboards(rc_runtime_progress_t* progres
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t flags;
|
||||
int offset = 0;
|
||||
int initial_offset = 0;
|
||||
int result;
|
||||
|
||||
for (i = 0; i < progress->runtime->lboard_count; ++i) {
|
||||
@ -574,7 +619,10 @@ static int rc_runtime_progress_write_leaderboards(rc_runtime_progress_t* progres
|
||||
continue;
|
||||
}
|
||||
|
||||
offset = progress->offset;
|
||||
initial_offset = progress->offset;
|
||||
} else {
|
||||
if (progress->offset + runtime_lboard->serialized_size > progress->buffer_size)
|
||||
return RC_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
rc_runtime_progress_start_chunk(progress, RC_RUNTIME_CHUNK_LEADERBOARD);
|
||||
@ -600,10 +648,15 @@ static int rc_runtime_progress_write_leaderboards(rc_runtime_progress_t* progres
|
||||
if (result != RC_OK)
|
||||
return result;
|
||||
|
||||
if (runtime_lboard->serialized_size) {
|
||||
/* runtime_lboard->serialized_size includes the header */
|
||||
assert_chunk_size(runtime_lboard->serialized_size - 8);
|
||||
}
|
||||
|
||||
rc_runtime_progress_end_chunk(progress);
|
||||
|
||||
if (!progress->buffer)
|
||||
runtime_lboard->serialized_size = progress->offset - offset;
|
||||
runtime_lboard->serialized_size = progress->offset - initial_offset;
|
||||
}
|
||||
|
||||
return RC_OK;
|
||||
@ -663,6 +716,9 @@ static int rc_runtime_progress_write_rich_presence(rc_runtime_progress_t* progre
|
||||
if (!display->next)
|
||||
return RC_OK;
|
||||
|
||||
if (progress->offset + 8 + 16 > progress->buffer_size)
|
||||
return RC_INSUFFICIENT_BUFFER;
|
||||
|
||||
rc_runtime_progress_start_chunk(progress, RC_RUNTIME_CHUNK_RICHPRESENCE);
|
||||
rc_runtime_progress_write_md5(progress, progress->runtime->richpresence->md5);
|
||||
|
||||
@ -705,6 +761,9 @@ static int rc_runtime_progress_serialize_internal(rc_runtime_progress_t* progres
|
||||
uint8_t md5[16];
|
||||
int result;
|
||||
|
||||
if (progress->buffer_size < RC_RUNTIME_MIN_BUFFER_SIZE)
|
||||
return RC_INSUFFICIENT_BUFFER;
|
||||
|
||||
rc_runtime_progress_write_uint(progress, RC_RUNTIME_MARKER);
|
||||
|
||||
if ((result = rc_runtime_progress_write_memrefs(progress)) != RC_OK)
|
||||
@ -722,6 +781,9 @@ static int rc_runtime_progress_serialize_internal(rc_runtime_progress_t* progres
|
||||
if ((result = rc_runtime_progress_write_rich_presence(progress)) != RC_OK)
|
||||
return result;
|
||||
|
||||
if (progress->offset + 8 + 16 > progress->buffer_size)
|
||||
return RC_INSUFFICIENT_BUFFER;
|
||||
|
||||
rc_runtime_progress_write_uint(progress, RC_RUNTIME_CHUNK_DONE);
|
||||
rc_runtime_progress_write_uint(progress, 16);
|
||||
|
||||
@ -736,12 +798,13 @@ static int rc_runtime_progress_serialize_internal(rc_runtime_progress_t* progres
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
int rc_runtime_progress_size(const rc_runtime_t* runtime, lua_State* L)
|
||||
uint32_t rc_runtime_progress_size(const rc_runtime_t* runtime, lua_State* L)
|
||||
{
|
||||
rc_runtime_progress_t progress;
|
||||
int result;
|
||||
|
||||
rc_runtime_progress_init(&progress, runtime, L);
|
||||
progress.buffer_size = 0xFFFFFFFF;
|
||||
|
||||
result = rc_runtime_progress_serialize_internal(&progress);
|
||||
if (result != RC_OK)
|
||||
@ -751,6 +814,11 @@ int rc_runtime_progress_size(const rc_runtime_t* runtime, lua_State* L)
|
||||
}
|
||||
|
||||
int rc_runtime_serialize_progress(void* buffer, const rc_runtime_t* runtime, lua_State* L)
|
||||
{
|
||||
return rc_runtime_serialize_progress_sized(buffer, 0xFFFFFFFF, runtime, L);
|
||||
}
|
||||
|
||||
int rc_runtime_serialize_progress_sized(uint8_t* buffer, uint32_t buffer_size, const rc_runtime_t* runtime, lua_State* L)
|
||||
{
|
||||
rc_runtime_progress_t progress;
|
||||
|
||||
@ -759,11 +827,17 @@ int rc_runtime_serialize_progress(void* buffer, const rc_runtime_t* runtime, lua
|
||||
|
||||
rc_runtime_progress_init(&progress, runtime, L);
|
||||
progress.buffer = (uint8_t*)buffer;
|
||||
progress.buffer_size = buffer_size;
|
||||
|
||||
return rc_runtime_progress_serialize_internal(&progress);
|
||||
}
|
||||
|
||||
int rc_runtime_deserialize_progress(rc_runtime_t* runtime, const uint8_t* serialized, lua_State* L)
|
||||
{
|
||||
return rc_runtime_deserialize_progress_sized(runtime, serialized, 0xFFFFFFFF, L);
|
||||
}
|
||||
|
||||
int rc_runtime_deserialize_progress_sized(rc_runtime_t* runtime, const uint8_t* serialized, uint32_t serialized_size, lua_State* L)
|
||||
{
|
||||
rc_runtime_progress_t progress;
|
||||
md5_state_t state;
|
||||
@ -775,9 +849,9 @@ int rc_runtime_deserialize_progress(rc_runtime_t* runtime, const uint8_t* serial
|
||||
int seen_rich_presence = 0;
|
||||
int result = RC_OK;
|
||||
|
||||
if (!serialized) {
|
||||
if (!serialized || serialized_size < RC_RUNTIME_MIN_BUFFER_SIZE) {
|
||||
rc_runtime_reset(runtime);
|
||||
return RC_INVALID_STATE;
|
||||
return RC_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
rc_runtime_progress_init(&progress, runtime, L);
|
||||
@ -813,12 +887,21 @@ int rc_runtime_deserialize_progress(rc_runtime_t* runtime, const uint8_t* serial
|
||||
}
|
||||
|
||||
do {
|
||||
if (progress.offset + 8 >= serialized_size) {
|
||||
result = RC_INSUFFICIENT_BUFFER;
|
||||
break;
|
||||
}
|
||||
|
||||
chunk_id = rc_runtime_progress_read_uint(&progress);
|
||||
chunk_size = rc_runtime_progress_read_uint(&progress);
|
||||
next_chunk_offset = progress.offset + chunk_size;
|
||||
|
||||
switch (chunk_id)
|
||||
{
|
||||
if (next_chunk_offset > serialized_size) {
|
||||
result = RC_INSUFFICIENT_BUFFER;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (chunk_id) {
|
||||
case RC_RUNTIME_CHUNK_MEMREFS:
|
||||
result = rc_runtime_progress_read_memrefs(&progress);
|
||||
break;
|
||||
|
11
deps/rcheevos/src/rcheevos/value.c
vendored
11
deps/rcheevos/src/rcheevos/value.c
vendored
@ -683,9 +683,14 @@ static int rc_typed_value_compare_floats(float f1, float f2, char oper) {
|
||||
}
|
||||
|
||||
int rc_typed_value_compare(const rc_typed_value_t* value1, const rc_typed_value_t* value2, char oper) {
|
||||
rc_typed_value_t converted_value2;
|
||||
if (value2->type != value1->type)
|
||||
value2 = rc_typed_value_convert_into(&converted_value2, value2, value1->type);
|
||||
rc_typed_value_t converted_value;
|
||||
if (value2->type != value1->type) {
|
||||
/* if either side is a float, convert both sides to float. otherwise, assume the signed-ness of the left side. */
|
||||
if (value2->type == RC_VALUE_TYPE_FLOAT)
|
||||
value1 = rc_typed_value_convert_into(&converted_value, value1, value2->type);
|
||||
else
|
||||
value2 = rc_typed_value_convert_into(&converted_value, value2, value1->type);
|
||||
}
|
||||
|
||||
switch (value1->type) {
|
||||
case RC_VALUE_TYPE_UNSIGNED:
|
||||
|
12
deps/rcheevos/src/rhash/hash.c
vendored
12
deps/rcheevos/src/rhash/hash.c
vendored
@ -528,7 +528,7 @@ static int rc_hash_cd_file(md5_state_t* md5, void* track_handle, uint32_t sector
|
||||
verbose_message_callback(message);
|
||||
}
|
||||
|
||||
if (size < (unsigned)num_read)
|
||||
if (size < (unsigned)num_read) /* we read a whole sector - only hash the part containing file data */
|
||||
num_read = (size_t)size;
|
||||
|
||||
do
|
||||
@ -834,12 +834,18 @@ static int rc_hash_zip_file(md5_state_t* md5, void* file_handle)
|
||||
uint32_t filename_len = RC_ZIP_READ_LE16(cdir + 0x1C);
|
||||
int32_t extra_len = RC_ZIP_READ_LE16(cdir + 0x1E);
|
||||
int32_t comment_len = RC_ZIP_READ_LE16(cdir + 0x20);
|
||||
int32_t external_attr = RC_ZIP_READ_LE16(cdir + 0x26);
|
||||
uint64_t local_hdr_ofs = RC_ZIP_READ_LE32(cdir + 0x2A);
|
||||
cdir_entry_len = cdirhdr_size + filename_len + extra_len + comment_len;
|
||||
|
||||
if (signature != 0x02014b50) /* expected central directory entry signature */
|
||||
break;
|
||||
|
||||
/* Ignore records describing a directory (we only hash file records) */
|
||||
name = (cdir + cdirhdr_size);
|
||||
if (name[filename_len - 1] == '/' || name[filename_len - 1] == '\\' || (external_attr & 0x10))
|
||||
continue;
|
||||
|
||||
/* Handle Zip64 fields */
|
||||
if (decomp_size == 0xFFFFFFFF || comp_size == 0xFFFFFFFF || local_hdr_ofs == 0xFFFFFFFF)
|
||||
{
|
||||
@ -893,7 +899,7 @@ static int rc_hash_zip_file(md5_state_t* md5, void* file_handle)
|
||||
hashindex++;
|
||||
|
||||
/* Convert and store the file name in the hash data buffer */
|
||||
for (name = (cdir + cdirhdr_size), name_end = name + filename_len; name != name_end; name++)
|
||||
for (name_end = name + filename_len; name != name_end; name++)
|
||||
{
|
||||
*(hashdata++) =
|
||||
(*name == '\\' ? '/' : /* convert back-slashes to regular slashes */
|
||||
@ -1717,7 +1723,7 @@ static int rc_hash_nintendo_3ds_ncch(md5_state_t* md5, void* file_handle, uint8_
|
||||
}
|
||||
|
||||
AES_init_ctx(&ncch_aes, primary_key);
|
||||
AES_CTR_xcrypt_buffer(&ncch_aes, &hash_buffer[exefs_section_offset], exefs_section_size);
|
||||
AES_CTR_xcrypt_buffer(&ncch_aes, &hash_buffer[exefs_section_offset], (size_t)exefs_section_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -391,6 +391,7 @@ void gfx_widgets_set_challenge_display(unsigned id, const char* badge);
|
||||
void gfx_widgets_clear_challenge_displays(void);
|
||||
void gfx_widget_set_achievement_progress(const char* badge, const char* progress);
|
||||
void gfx_widget_set_cheevos_disconnect(bool visible);
|
||||
void gfx_widget_set_cheevos_set_loading(bool visible);
|
||||
#endif
|
||||
|
||||
/* TODO/FIXME/WARNING: Not thread safe! */
|
||||
|
@ -66,6 +66,7 @@ struct gfx_widget_leaderboard_display_state
|
||||
unsigned challenge_count;
|
||||
uint16_t char_width[CHEEVO_LBOARD_LAST_FIXED_CHAR - CHEEVO_LBOARD_FIRST_FIXED_CHAR + 1];
|
||||
uint16_t fixed_char_width;
|
||||
uint16_t loading;
|
||||
bool disconnected;
|
||||
};
|
||||
|
||||
@ -115,6 +116,7 @@ static void gfx_widget_leaderboard_display_frame(void* data, void* userdata)
|
||||
if (state->tracker_count == 0 &&
|
||||
state->challenge_count == 0 &&
|
||||
state->progress_tracker.show_until == 0 &&
|
||||
!state->loading &&
|
||||
!state->disconnected)
|
||||
return;
|
||||
|
||||
@ -342,9 +344,10 @@ static void gfx_widget_leaderboard_display_frame(void* data, void* userdata)
|
||||
}
|
||||
}
|
||||
|
||||
if (state->disconnected)
|
||||
if (state->disconnected || state->loading)
|
||||
{
|
||||
const char* disconnected_text = "! RA !";
|
||||
char loading_buffer[8] = "RA ...";
|
||||
const char* disconnected_text = state->disconnected ? "! RA !" : loading_buffer;
|
||||
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;
|
||||
@ -353,6 +356,13 @@ static void gfx_widget_leaderboard_display_frame(void* data, void* userdata)
|
||||
x = video_width - disconnect_widget_width - spacing;
|
||||
y -= disconnect_widget_height + spacing;
|
||||
|
||||
if (state->loading) {
|
||||
const uint16_t loading_shift = 5;
|
||||
loading_buffer[((state->loading - 1) >> loading_shift) + 3] = '\0';
|
||||
state->loading &= (1 << (loading_shift + 2)) - 1;
|
||||
++state->loading;
|
||||
}
|
||||
|
||||
/* Backdrop */
|
||||
gfx_display_draw_quad(
|
||||
p_disp,
|
||||
@ -586,6 +596,12 @@ void gfx_widget_set_cheevos_disconnect(bool value)
|
||||
state->disconnected = value;
|
||||
}
|
||||
|
||||
void gfx_widget_set_cheevos_set_loading(bool value)
|
||||
{
|
||||
gfx_widget_leaderboard_display_state_t* state = &p_w_leaderboard_display_st;
|
||||
state->loading = value ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
const gfx_widget_t gfx_widget_leaderboard_display = {
|
||||
&gfx_widget_leaderboard_display_init,
|
||||
|
@ -194,6 +194,7 @@ ACHIEVEMENTS
|
||||
/* Gekko (Wii) and 3DS use custom pthread wrappers (see rthreads.c) */
|
||||
#define RC_NO_THREADS 1
|
||||
#endif
|
||||
#define RC_CLIENT_SUPPORTS_HASH 1
|
||||
|
||||
#include "../libretro-common/formats/cdfs/cdfs.c"
|
||||
#include "../network/net_http_special.c"
|
||||
|
@ -10152,6 +10152,18 @@ MSG_HASH(
|
||||
MENU_ENUM_LABEL_CHEEVOS_SERVER_RECONNECTED,
|
||||
"All pending requests have succesfully been synced to the RetroAchievements server."
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_CHEEVOS_IDENTIFYING_GAME,
|
||||
"Identifying game"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_CHEEVOS_FETCHING_GAME_DATA,
|
||||
"Fetching game data"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_CHEEVOS_STARTING_SESSION,
|
||||
"Starting session"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_NOT_LOGGED_IN,
|
||||
"Not logged in"
|
||||
|
@ -3062,6 +3062,9 @@ enum msg_hash_enums
|
||||
MENU_LABEL(ACHIEVEMENT_SERVER_UNREACHABLE),
|
||||
MENU_LABEL(CHEEVOS_SERVER_DISCONNECTED),
|
||||
MENU_LABEL(CHEEVOS_SERVER_RECONNECTED),
|
||||
MENU_LABEL(CHEEVOS_IDENTIFYING_GAME),
|
||||
MENU_LABEL(CHEEVOS_FETCHING_GAME_DATA),
|
||||
MENU_LABEL(CHEEVOS_STARTING_SESSION),
|
||||
MENU_LABEL(CORE_INFORMATION),
|
||||
MENU_LABEL(DISC_INFORMATION),
|
||||
MENU_LABEL(CORE_LOCK),
|
||||
|
@ -6983,6 +6983,10 @@ int runloop_iterate(void)
|
||||
netplay_driver_ctl(RARCH_NETPLAY_CTL_PAUSE, NULL);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef HAVE_CHEEVOS
|
||||
if (cheevos_enable)
|
||||
rcheevos_idle();
|
||||
#endif
|
||||
#ifdef HAVE_MENU
|
||||
/* Rely on vsync throttling unless VRR is enabled and menu throttle is disabled. */
|
||||
if (vrr_runloop_enable && !settings->bools.menu_throttle_framerate)
|
||||
@ -6998,10 +7002,6 @@ int runloop_iterate(void)
|
||||
: settings->floats.video_refresh_rate));
|
||||
else
|
||||
runloop_set_frame_limit(&video_st->av_info, settings->floats.fastforward_ratio);
|
||||
#endif
|
||||
#ifdef HAVE_CHEEVOS
|
||||
if (cheevos_enable)
|
||||
rcheevos_idle();
|
||||
#endif
|
||||
goto end;
|
||||
case RUNLOOP_STATE_ITERATE:
|
||||
|
Loading…
x
Reference in New Issue
Block a user