diff --git a/cheevos/cheevos.c b/cheevos/cheevos.c index e3c5848576b..e193b54fc30 100644 --- a/cheevos/cheevos.c +++ b/cheevos/cheevos.c @@ -31,7 +31,6 @@ #include #include #include -#include #ifdef HAVE_CONFIG_H #include "../config.h" @@ -75,7 +74,11 @@ #include "../tasks/tasks_internal.h" +#ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION #include "../deps/rcheevos/include/rc_client_raintegration.h" +#include +#endif + #include "../deps/rcheevos/include/rc_runtime.h" #include "../deps/rcheevos/include/rc_runtime_types.h" #include "../deps/rcheevos/include/rc_hash.h" @@ -3179,6 +3182,30 @@ static void rcheevos_raintegration_event_handler(const rc_client_raintegration_e } } +static uint32_t rcheevos_raintegration_write_memory(uint32_t address, + uint8_t* buffer, uint32_t num_bytes, rc_client_t* client) +{ + uint32_t avail; + uint8_t* ptr = rc_libretro_memory_find_avail(&rcheevos_locals.memory, address, &avail); + if (avail >= num_bytes) { + memcpy(ptr, buffer, num_bytes); + return num_bytes; + } + + if (avail == 0) + return 0; + + memcpy(ptr, buffer, avail); + return avail + rcheevos_raintegration_write_memory(address + avail, buffer + avail, num_bytes - avail, client); +} + +static void rc_client_raintegration_get_game_name(char* buffer, uint32_t buffer_size, rc_client_t* client) +{ + const char* content_path = path_get(RARCH_PATH_CONTENT); + snprintf(buffer, buffer_size, path_basename(content_path)); + path_remove_extension(buffer); +} + static void rcheevos_load_raintegration_callback(int result, const char* error_message, rc_client_t* client, void* userdata) { @@ -3203,6 +3230,8 @@ static void rcheevos_load_raintegration_callback(int result, #endif rc_client_raintegration_set_event_handler(client, rcheevos_raintegration_event_handler); + rc_client_raintegration_set_write_memory_function(client, rcheevos_raintegration_write_memory); + rc_client_raintegration_set_get_game_name_function(client, rc_client_raintegration_get_game_name); rcheevos_load(info); diff --git a/cheevos/cheevos_client.c b/cheevos/cheevos_client.c index 62e9fd01b2a..1e39e3c81d0 100644 --- a/cheevos/cheevos_client.c +++ b/cheevos/cheevos_client.c @@ -336,7 +336,7 @@ static void rcheevos_client_http_task_callback(retro_task_t* task, rc_api_server_response_t server_response; memset(&server_response, 0, sizeof(server_response)); - if (!http_data) + if (!http_data || http_data->status < 0) { callback_data->callback(&server_response, callback_data->callback_data); } diff --git a/deps/rcheevos/include/rc_client_raintegration.h b/deps/rcheevos/include/rc_client_raintegration.h index b2e77cdec0c..46112910457 100644 --- a/deps/rcheevos/include/rc_client_raintegration.h +++ b/deps/rcheevos/include/rc_client_raintegration.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 @@ -74,6 +76,8 @@ RC_EXPORT void RC_CCONV rc_client_raintegration_update_menu_item(const rc_client RC_EXPORT int RC_CCONV rc_client_raintegration_activate_menu_item(const rc_client_t* client, uint32_t nMenuItemId); 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); diff --git a/deps/rcheevos/src/rc_client.c b/deps/rcheevos/src/rc_client.c index 6790e1768d7..506790ee2e8 100644 --- a/deps/rcheevos/src/rc_client.c +++ b/deps/rcheevos/src/rc_client.c @@ -2006,22 +2006,36 @@ static void rc_client_begin_fetch_game_data(rc_client_load_state_t* load_state) load_state->game->public_.hash = ptr; load_state->game->public_.console_id = RC_CONSOLE_UNKNOWN; - } else { + } + else + { /* 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); + } + } } - 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] != '[') { /* [NO HASH] or [SUBSETxx] */ load_state->game->public_.id = load_state->hash->game_id; load_state->game->public_.hash = load_state->hash->hash; } @@ -3753,7 +3767,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; diff --git a/deps/rcheevos/src/rc_client_internal.h b/deps/rcheevos/src/rc_client_internal.h index 5e57091516a..db2ad583bbc 100644 --- a/deps/rcheevos/src/rc_client_internal.h +++ b/deps/rcheevos/src/rc_client_internal.h @@ -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; @@ -387,6 +390,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 diff --git a/deps/rcheevos/src/rc_client_raintegration.c b/deps/rcheevos/src/rc_client_raintegration.c index efea7e449d2..227d03a8450 100644 --- a/deps/rcheevos/src/rc_client_raintegration.c +++ b/deps/rcheevos/src/rc_client_raintegration.c @@ -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; diff --git a/deps/rcheevos/src/rc_client_raintegration_internal.h b/deps/rcheevos/src/rc_client_raintegration_internal.h index 530d98e1a82..ce7c98b03be 100644 --- a/deps/rcheevos/src/rc_client_raintegration_internal.h +++ b/deps/rcheevos/src/rc_client_raintegration_internal.h @@ -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;