diff --git a/Assets/dll/librcheevos.dll b/Assets/dll/librcheevos.dll index c58c7183e7..fd85a84e60 100644 Binary files a/Assets/dll/librcheevos.dll and b/Assets/dll/librcheevos.dll differ diff --git a/ExternalProjects/librcheevos/CMakeLists.txt b/ExternalProjects/librcheevos/CMakeLists.txt index 7d6f39e7e9..7d121ed8f5 100644 --- a/ExternalProjects/librcheevos/CMakeLists.txt +++ b/ExternalProjects/librcheevos/CMakeLists.txt @@ -10,6 +10,9 @@ set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS ON) +# ensure lib shared library prefix is used +set(CMAKE_SHARED_LIBRARY_PREFIX "lib") + if(MSVC) # max warnings, treat as errors add_compile_options(/W4) @@ -30,9 +33,6 @@ if(MSVC) add_compile_options(/permissive-) add_compile_options(/volatile:iso) add_compile_options(/fp:precise) - - # cmake will not insert a lib prefix for libraries on MSVC targets - set(RC_TARGET librcheevos) else() # max warnings, treat as errors add_compile_options(-Wall -Wextra) @@ -46,16 +46,13 @@ else() if(CMAKE_C_COMPILER_ID MATCHES "Clang") add_link_options(-fuse-ld=lld) endif() - - # cmake will insert a lib prefix for libraries on non-MSVC targets - set(RC_TARGET rcheevos) endif() set(RC_SRC_DIR ${CMAKE_SOURCE_DIR}/rcheevos/src) set(RC_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/rcheevos/include) add_library( - ${RC_TARGET} + rcheevos SHARED ${RC_SRC_DIR}/rc_compat.c ${RC_SRC_DIR}/rc_compat.h @@ -105,16 +102,16 @@ add_library( ${RC_INCLUDE_DIR}/rcheevos.h ) -target_compile_definitions(${RC_TARGET} PRIVATE RC_DISABLE_LUA RC_NO_THREADS RC_SHARED) -target_include_directories(${RC_TARGET} PRIVATE ${RC_INCLUDE_DIR}) +target_compile_definitions(rcheevos PRIVATE RC_DISABLE_LUA RC_NO_THREADS RC_SHARED) +target_include_directories(rcheevos PRIVATE ${RC_INCLUDE_DIR}) add_custom_command( - TARGET ${RC_TARGET} + TARGET rcheevos POST_BUILD COMMAND ${CMAKE_COMMAND} - ARGS -E copy $ ${CMAKE_SOURCE_DIR}/../../Assets/dll + ARGS -E copy $ ${CMAKE_SOURCE_DIR}/../../Assets/dll COMMAND ${CMAKE_COMMAND} - ARGS -E copy $ ${CMAKE_SOURCE_DIR}/../../output/dll + ARGS -E copy $ ${CMAKE_SOURCE_DIR}/../../output/dll ) if(MSVC) diff --git a/ExternalProjects/librcheevos/rcheevos b/ExternalProjects/librcheevos/rcheevos index e7989c3002..3106e6d3d2 160000 --- a/ExternalProjects/librcheevos/rcheevos +++ b/ExternalProjects/librcheevos/rcheevos @@ -1 +1 @@ -Subproject commit e7989c300280ba06d7621ae5b4e00ac7fe28d97a +Subproject commit 3106e6d3d274b63c59976cb07dda94a292ab45ca diff --git a/src/BizHawk.Client.EmuHawk/RetroAchievements/LibRCheevos.cs b/src/BizHawk.Client.EmuHawk/RetroAchievements/LibRCheevos.cs index fc60ce2384..783b006b7f 100644 --- a/src/BizHawk.Client.EmuHawk/RetroAchievements/LibRCheevos.cs +++ b/src/BizHawk.Client.EmuHawk/RetroAchievements/LibRCheevos.cs @@ -62,7 +62,10 @@ namespace BizHawk.Client.EmuHawk 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_INVALID_VARIABLE_NAME = -37, + RC_UNKNOWN_VARIABLE_NAME = -38 } public enum rc_runtime_event_type_t : byte @@ -154,7 +157,7 @@ namespace BizHawk.Client.EmuHawk IntPtr hardcore_unlocks, IntPtr unlocks, uint num_hardcore_unlocks, uint num_unlocks, long server_now, rc_api_response_t response); [StructLayout(LayoutKind.Sequential)] - public readonly record struct rc_api_fetch_user_unlocks_request_t(string username, string api_token, uint game_id, bool hardcore) + public readonly struct rc_api_fetch_user_unlocks_request_t(string username, string api_token, uint game_id, bool hardcore) { [MarshalAs(STR_MARSHAL_HINT)] public readonly string username = username; @@ -166,7 +169,7 @@ namespace BizHawk.Client.EmuHawk } [StructLayout(LayoutKind.Sequential)] - public readonly record struct rc_api_login_request_t(string username, string api_token, string password) + public readonly struct rc_api_login_request_t(string username, string api_token, string password) { [MarshalAs(STR_MARSHAL_HINT)] public readonly string username = username; @@ -177,7 +180,7 @@ namespace BizHawk.Client.EmuHawk } [StructLayout(LayoutKind.Sequential)] - public readonly record struct rc_api_start_session_request_t(string username, string api_token, uint game_id, string game_hash, bool hardcore) + public readonly struct rc_api_start_session_request_t(string username, string api_token, uint game_id, string game_hash, bool hardcore) { [MarshalAs(STR_MARSHAL_HINT)] public readonly string username = username; @@ -239,7 +242,7 @@ namespace BizHawk.Client.EmuHawk int submitted_score, int best_score, uint new_rank, uint num_entries, IntPtr top_entries, uint num_top_entries, rc_api_response_t response); [StructLayout(LayoutKind.Sequential)] - public readonly record struct rc_api_award_achievement_request_t(string username, string api_token, uint achievement_id, bool hardcore, string game_hash) + public readonly struct rc_api_award_achievement_request_t(string username, string api_token, uint achievement_id, bool hardcore, string game_hash, uint seconds_since_unlock) { [MarshalAs(STR_MARSHAL_HINT)] public readonly string username = username; @@ -250,10 +253,11 @@ namespace BizHawk.Client.EmuHawk public readonly bool hardcore = hardcore; [MarshalAs(STR_MARSHAL_HINT)] public readonly string game_hash = game_hash; + public readonly uint seconds_since_unlock = seconds_since_unlock; } [StructLayout(LayoutKind.Sequential)] - public readonly record struct rc_api_fetch_game_data_request_t(string username, string api_token, uint game_id) + public readonly struct rc_api_fetch_game_data_request_t(string username, string api_token, uint game_id) { [MarshalAs(STR_MARSHAL_HINT)] public readonly string username = username; @@ -263,7 +267,7 @@ namespace BizHawk.Client.EmuHawk } [StructLayout(LayoutKind.Sequential)] - public readonly record struct rc_api_fetch_image_request_t(string image_name, rc_api_image_type_t image_type) + public readonly struct rc_api_fetch_image_request_t(string image_name, rc_api_image_type_t image_type) { [MarshalAs(STR_MARSHAL_HINT)] public readonly string image_name = image_name; @@ -271,7 +275,7 @@ namespace BizHawk.Client.EmuHawk } [StructLayout(LayoutKind.Sequential)] - public readonly record struct rc_api_ping_request_t(string username, string api_token, uint game_id, string rich_presence, string game_hash, bool hardcore) + public readonly struct rc_api_ping_request_t(string username, string api_token, uint game_id, string rich_presence, string game_hash, bool hardcore) { [MarshalAs(STR_MARSHAL_HINT)] public readonly string username = username; @@ -287,7 +291,7 @@ namespace BizHawk.Client.EmuHawk } [StructLayout(LayoutKind.Sequential)] - public readonly record struct rc_api_resolve_hash_request_t(string username, string api_token, string game_hash) + public readonly struct rc_api_resolve_hash_request_t(string username, string api_token, string game_hash) { [MarshalAs(STR_MARSHAL_HINT)] public readonly string username = username; // note: not actually used @@ -298,7 +302,7 @@ namespace BizHawk.Client.EmuHawk } [StructLayout(LayoutKind.Sequential)] - public readonly record struct rc_api_submit_lboard_entry_request_t(string username, string api_token, uint leaderboard_id, int score, string game_hash) + public readonly struct rc_api_submit_lboard_entry_request_t(string username, string api_token, uint leaderboard_id, int score, string game_hash, uint seconds_since_completion) { [MarshalAs(STR_MARSHAL_HINT)] public readonly string username = username; @@ -308,6 +312,7 @@ namespace BizHawk.Client.EmuHawk public readonly int score = score; [MarshalAs(STR_MARSHAL_HINT)] public readonly string game_hash = game_hash; + public readonly uint seconds_since_completion = seconds_since_completion; } [StructLayout(LayoutKind.Sequential)] @@ -397,10 +402,10 @@ namespace BizHawk.Client.EmuHawk public abstract rc_error_t rc_runtime_progress_size(IntPtr runtime, IntPtr unused); [BizImport(cc)] - public abstract void rc_runtime_serialize_progress(byte[] buffer, IntPtr runtime, IntPtr unused); + public abstract void rc_runtime_serialize_progress_sized(byte[] buffer, uint buffer_size, IntPtr runtime, IntPtr unused); [BizImport(cc)] - public abstract rc_error_t rc_runtime_deserialize_progress(IntPtr runtime, byte[] serialized, IntPtr unused); + public abstract rc_error_t rc_runtime_deserialize_progress_sized(IntPtr runtime, byte[] serialized, uint serialized_size, IntPtr unused); [BizImport(cc)] public abstract void rc_runtime_validate_addresses(IntPtr runtime, rc_runtime_event_handler_t event_handler, rc_runtime_validate_address_t validate_handler); diff --git a/src/BizHawk.Client.EmuHawk/RetroAchievements/RCheevos.Achievements.cs b/src/BizHawk.Client.EmuHawk/RetroAchievements/RCheevos.Achievements.cs index bd4fe51082..4886789cab 100644 --- a/src/BizHawk.Client.EmuHawk/RetroAchievements/RCheevos.Achievements.cs +++ b/src/BizHawk.Client.EmuHawk/RetroAchievements/RCheevos.Achievements.cs @@ -11,6 +11,7 @@ namespace BizHawk.Client.EmuHawk private sealed class CheevoUnlockRequest : RCheevoHttpRequest { private readonly LibRCheevos.rc_api_award_achievement_request_t _apiParams; + private readonly DateTime _unlockTime; protected override void ResponseCallback(byte[] serv_resp) { @@ -24,13 +25,17 @@ namespace BizHawk.Client.EmuHawk public override void DoRequest() { - var apiParamsResult = _lib.rc_api_init_award_achievement_request(out var api_req, in _apiParams); + var secondsSinceUnlock = (DateTime.UtcNow - _unlockTime).TotalSeconds; + var apiParams = new LibRCheevos.rc_api_award_achievement_request_t(_apiParams.username, _apiParams.api_token, + _apiParams.achievement_id, _apiParams.hardcore, _apiParams.game_hash, (uint)secondsSinceUnlock); + var apiParamsResult = _lib.rc_api_init_award_achievement_request(out var api_req, in apiParams); InternalDoRequest(apiParamsResult, ref api_req); } public CheevoUnlockRequest(string username, string api_token, uint achievement_id, bool hardcore, string game_hash) { - _apiParams = new(username, api_token, achievement_id, hardcore, game_hash); + _apiParams = new(username, api_token, achievement_id, hardcore, game_hash, seconds_since_unlock: 0); + _unlockTime = DateTime.UtcNow; } } diff --git a/src/BizHawk.Client.EmuHawk/RetroAchievements/RCheevos.Leaderboards.cs b/src/BizHawk.Client.EmuHawk/RetroAchievements/RCheevos.Leaderboards.cs index 3128d2c9f1..b12e2e3bda 100644 --- a/src/BizHawk.Client.EmuHawk/RetroAchievements/RCheevos.Leaderboards.cs +++ b/src/BizHawk.Client.EmuHawk/RetroAchievements/RCheevos.Leaderboards.cs @@ -11,6 +11,7 @@ namespace BizHawk.Client.EmuHawk private sealed class LboardTriggerRequest : RCheevoHttpRequest { private readonly LibRCheevos.rc_api_submit_lboard_entry_request_t _apiParams; + private readonly DateTime _completionTime; protected override void ResponseCallback(byte[] serv_resp) { @@ -24,13 +25,17 @@ namespace BizHawk.Client.EmuHawk public override void DoRequest() { - var apiParamsResult = _lib.rc_api_init_submit_lboard_entry_request(out var api_req, in _apiParams); + var secondsSinceCompletion = (DateTime.UtcNow - _completionTime).TotalSeconds; + var apiParams = new LibRCheevos.rc_api_submit_lboard_entry_request_t(_apiParams.username, _apiParams.api_token, + _apiParams.leaderboard_id, _apiParams.score, _apiParams.game_hash, (uint)secondsSinceCompletion); + var apiParamsResult = _lib.rc_api_init_submit_lboard_entry_request(out var api_req, in apiParams); InternalDoRequest(apiParamsResult, ref api_req); } public LboardTriggerRequest(string username, string api_token, uint id, int value, string hash) { - _apiParams = new(username, api_token, id, value, hash); + _apiParams = new(username, api_token, id, value, hash, seconds_since_completion: 0); + _completionTime = DateTime.UtcNow; } } diff --git a/src/BizHawk.Client.EmuHawk/RetroAchievements/RCheevos.cs b/src/BizHawk.Client.EmuHawk/RetroAchievements/RCheevos.cs index cf9c59ee6d..0f5ee7d699 100644 --- a/src/BizHawk.Client.EmuHawk/RetroAchievements/RCheevos.cs +++ b/src/BizHawk.Client.EmuHawk/RetroAchievements/RCheevos.cs @@ -286,7 +286,7 @@ namespace BizHawk.Client.EmuHawk if (size > 0) { var buffer = new byte[(int)size]; - _lib.rc_runtime_serialize_progress(buffer, _runtime, IntPtr.Zero); + _lib.rc_runtime_serialize_progress_sized(buffer, (uint)buffer.Length, _runtime, IntPtr.Zero); using var file = File.Create(path + ".rap"); file.Write(buffer, 0, buffer.Length); } @@ -312,7 +312,7 @@ namespace BizHawk.Client.EmuHawk using var file = File.OpenRead(path + ".rap"); var buffer = file.ReadAllBytes(); - _lib.rc_runtime_deserialize_progress(_runtime, buffer, IntPtr.Zero); + _lib.rc_runtime_deserialize_progress_sized(_runtime, buffer, (uint)buffer.Length, IntPtr.Zero); } private void QuickLoadCallback(object _, BeforeQuickLoadEventArgs e) @@ -537,7 +537,7 @@ namespace BizHawk.Client.EmuHawk if (!lboard.Hidden) { CurrentLboard = lboard; - _dialogParent.AddOnScreenMessage($"Leaderboard Attempt Started!"); + _dialogParent.AddOnScreenMessage("Leaderboard Attempt Started!"); _dialogParent.AddOnScreenMessage(lboard.Description); PlaySound(_lboardStartSound); }