From 7e2565ae49231013ff3c6d1e80ad4c3e7813e560 Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Tue, 29 Apr 2025 14:57:07 -0400 Subject: [PATCH 1/4] Update rcheevos submodule --- Externals/rcheevos/rcheevos | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Externals/rcheevos/rcheevos b/Externals/rcheevos/rcheevos index 022ac70cff..0115d9198f 160000 --- a/Externals/rcheevos/rcheevos +++ b/Externals/rcheevos/rcheevos @@ -1 +1 @@ -Subproject commit 022ac70cff6cf60c8957de63d6297998904a6f05 +Subproject commit 0115d9198ff7a73ff6568027dfb948ef6031818c From 999c7aed983828fd1b02609dadaf1e3c2a20cbc7 Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Thu, 1 May 2025 00:07:24 -0400 Subject: [PATCH 2/4] Don't close achievements on games that don't hash Minor bugfix necessary for future development; issue brought on by a conflict resolving wrong. --- Source/Core/Core/AchievementManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Core/Core/AchievementManager.cpp b/Source/Core/Core/AchievementManager.cpp index 2ebe12b672..7e80c9eef1 100644 --- a/Source/Core/Core/AchievementManager.cpp +++ b/Source/Core/Core/AchievementManager.cpp @@ -997,6 +997,7 @@ void AchievementManager::LoadGameCallback(int result, const char* error_message, // Allow developer tools for unidentified games rc_client_set_read_memory_function(instance.m_client, MemoryPeeker); instance.m_system.store(&Core::System::GetInstance(), std::memory_order_release); + return; } instance.CloseGame(); return; From c796691d008263f214364bbb986e3ad2c900ae94 Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Tue, 29 Apr 2025 23:56:58 -0400 Subject: [PATCH 3/4] Remove filename option from achievement manager load The only option that was currently using this was a pass-by-executable that wouldn't hash correctly anyways. --- Source/Core/Core/AchievementManager.cpp | 33 +++++++++++------------- Source/Core/Core/AchievementManager.h | 5 ++-- Source/Core/Core/Boot/Boot.cpp | 2 -- Source/Core/Core/HW/DVD/DVDInterface.cpp | 2 +- 4 files changed, 18 insertions(+), 24 deletions(-) diff --git a/Source/Core/Core/AchievementManager.cpp b/Source/Core/Core/AchievementManager.cpp index 7e80c9eef1..05aff49822 100644 --- a/Source/Core/Core/AchievementManager.cpp +++ b/Source/Core/Core/AchievementManager.cpp @@ -161,13 +161,13 @@ bool AchievementManager::HasAPIToken() const return !Config::Get(Config::RA_API_TOKEN).empty(); } -void AchievementManager::LoadGame(const std::string& file_path, const DiscIO::Volume* volume) +void AchievementManager::LoadGame(const DiscIO::Volume* volume) { if (!Config::Get(Config::RA_ENABLED) || !HasAPIToken()) { return; } - if (file_path.empty() && volume == nullptr) + if (volume == nullptr) { WARN_LOG_FMT(ACHIEVEMENTS, "Called Load Game without a game."); return; @@ -184,7 +184,13 @@ void AchievementManager::LoadGame(const std::string& file_path, const DiscIO::Vo { std::lock_guard lg{m_lock}; #ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION - SplitPath(file_path, nullptr, &m_title_estimate, nullptr); + const auto& names = volume->GetLongNames(); + if (names.contains(DiscIO::Language::English)) + m_title_estimate = names.at(DiscIO::Language::English); + else if (!names.empty()) + m_title_estimate = names.begin()->second; + else + m_title_estimate = ""; #endif // RC_CLIENT_SUPPORTS_RAINTEGRATION if (volume) { @@ -196,8 +202,7 @@ void AchievementManager::LoadGame(const std::string& file_path, const DiscIO::Vo } std::lock_guard lg{m_filereader_lock}; rc_hash_filereader volume_reader{ - .open = (volume) ? &AchievementManager::FilereaderOpenByVolume : - &AchievementManager::FilereaderOpenByFilepath, + .open = &AchievementManager::FilereaderOpen, .seek = &AchievementManager::FilereaderSeek, .tell = &AchievementManager::FilereaderTell, .read = &AchievementManager::FilereaderRead, @@ -206,12 +211,12 @@ void AchievementManager::LoadGame(const std::string& file_path, const DiscIO::Vo rc_hash_init_custom_filereader(&volume_reader); if (rc_client_get_game_info(m_client)) { - rc_client_begin_change_media(m_client, file_path.c_str(), NULL, 0, ChangeMediaCallback, NULL); + rc_client_begin_change_media(m_client, "", NULL, 0, ChangeMediaCallback, NULL); } else { rc_client_set_read_memory_function(m_client, MemoryVerifier); - rc_client_begin_identify_and_load_game(m_client, RC_CONSOLE_GAMECUBE, file_path.c_str(), NULL, + rc_client_begin_identify_and_load_game(m_client, RC_CONSOLE_GAMECUBE, "", NULL, 0, LoadGameCallback, NULL); } } @@ -237,8 +242,9 @@ void AchievementManager::SetBackgroundExecutionAllowed(bool allowed) std::string AchievementManager::CalculateHash(const std::string& file_path) { char hash_result[33] = "0"; + GetInstance().m_loading_volume = std::move(DiscIO::CreateVolume(file_path)); rc_hash_filereader volume_reader{ - .open = &AchievementManager::FilereaderOpenByFilepath, + .open = &AchievementManager::FilereaderOpen, .seek = &AchievementManager::FilereaderSeek, .tell = &AchievementManager::FilereaderTell, .read = &AchievementManager::FilereaderRead, @@ -774,16 +780,7 @@ void AchievementManager::Shutdown() } } -void* AchievementManager::FilereaderOpenByFilepath(const char* path_utf8) -{ - auto state = std::make_unique(); - state->volume = DiscIO::CreateVolume(path_utf8); - if (!state->volume) - return nullptr; - return state.release(); -} - -void* AchievementManager::FilereaderOpenByVolume(const char* path_utf8) +void* AchievementManager::FilereaderOpen(const char* path_utf8) { auto state = std::make_unique(); { diff --git a/Source/Core/Core/AchievementManager.h b/Source/Core/Core/AchievementManager.h index 012800c1b7..4efbfe829f 100644 --- a/Source/Core/Core/AchievementManager.h +++ b/Source/Core/Core/AchievementManager.h @@ -122,7 +122,7 @@ public: void SetUpdateCallback(UpdateCallback callback); void Login(const std::string& password); bool HasAPIToken() const; - void LoadGame(const std::string& file_path, const DiscIO::Volume* volume); + void LoadGame(const DiscIO::Volume* volume); bool IsGameLoaded() const; void SetBackgroundExecutionAllowed(bool allowed); @@ -193,8 +193,7 @@ private: static picojson::value LoadApprovedList(); - static void* FilereaderOpenByFilepath(const char* path_utf8); - static void* FilereaderOpenByVolume(const char* path_utf8); + static void* FilereaderOpen(const char* path_utf8); static void FilereaderSeek(void* file_handle, int64_t offset, int origin); static int64_t FilereaderTell(void* file_handle); static size_t FilereaderRead(void* file_handle, void* buffer, size_t requested_bytes); diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index a23d605a53..373f446dee 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -597,8 +597,6 @@ bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard, SetupGCMemory(system, guard); } - AchievementManager::GetInstance().LoadGame(executable.path, nullptr); - if (!executable.reader->LoadIntoMemory(system)) { PanicAlertFmtT("Failed to load the executable to memory."); diff --git a/Source/Core/Core/HW/DVD/DVDInterface.cpp b/Source/Core/Core/HW/DVD/DVDInterface.cpp index 6e60ef7772..1c6ea07aa0 100644 --- a/Source/Core/Core/HW/DVD/DVDInterface.cpp +++ b/Source/Core/Core/HW/DVD/DVDInterface.cpp @@ -398,7 +398,7 @@ void DVDInterface::SetDisc(std::unique_ptr disc, m_auto_disc_change_index = 0; } - AchievementManager::GetInstance().LoadGame("", disc.get()); + AchievementManager::GetInstance().LoadGame(disc.get()); // Assume that inserting a disc requires having an empty disc before if (had_disc != has_disc) From 1633011d2a1ae14f72be7655d38618b0e58b2e7f Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Fri, 18 Apr 2025 07:59:47 -0400 Subject: [PATCH 4/4] Add achievement support for Wii and WiiWare Add a method to detect console ID from an input file and instruct rcheevos to load as Gamecube or Wii accordingly. Also, hash .wads upon loading, to support achievements on WiiWare titles. --- Source/Core/Core/AchievementManager.cpp | 30 +++++++++++++++++-------- Source/Core/Core/AchievementManager.h | 3 +++ Source/Core/Core/Boot/Boot.cpp | 2 ++ 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/Source/Core/Core/AchievementManager.cpp b/Source/Core/Core/AchievementManager.cpp index 05aff49822..f5067f5d6e 100644 --- a/Source/Core/Core/AchievementManager.cpp +++ b/Source/Core/Core/AchievementManager.cpp @@ -11,7 +11,6 @@ #include #include -#include #include "Common/Assert.h" #include "Common/BitUtils.h" @@ -192,12 +191,9 @@ void AchievementManager::LoadGame(const DiscIO::Volume* volume) else m_title_estimate = ""; #endif // RC_CLIENT_SUPPORTS_RAINTEGRATION - if (volume) + if (!m_loading_volume) { - if (!m_loading_volume) - { - m_loading_volume = DiscIO::CreateVolume(volume->GetBlobReader().CopyReader()); - } + m_loading_volume = DiscIO::CreateVolume(volume->GetBlobReader().CopyReader()); } } std::lock_guard lg{m_filereader_lock}; @@ -215,9 +211,10 @@ void AchievementManager::LoadGame(const DiscIO::Volume* volume) } else { + u32 console_id = FindConsoleID(volume->GetVolumeType()); rc_client_set_read_memory_function(m_client, MemoryVerifier); - rc_client_begin_identify_and_load_game(m_client, RC_CONSOLE_GAMECUBE, "", NULL, - 0, LoadGameCallback, NULL); + rc_client_begin_identify_and_load_game(m_client, console_id, "", NULL, 0, LoadGameCallback, + NULL); } } @@ -251,7 +248,8 @@ std::string AchievementManager::CalculateHash(const std::string& file_path) .close = &AchievementManager::FilereaderClose, }; rc_hash_init_custom_filereader(&volume_reader); - rc_hash_generate_from_file(hash_result, RC_CONSOLE_GAMECUBE, file_path.c_str()); + u32 console_id = FindConsoleID(GetInstance().m_loading_volume->GetVolumeType()); + rc_hash_generate_from_file(hash_result, console_id, file_path.c_str()); return std::string(hash_result); } @@ -835,6 +833,20 @@ void AchievementManager::FilereaderClose(void* file_handle) delete static_cast(file_handle); } +u32 AchievementManager::FindConsoleID(const DiscIO::Platform& platform) +{ + switch (platform) + { + case DiscIO::Platform::GameCubeDisc: + return RC_CONSOLE_GAMECUBE; + case DiscIO::Platform::WiiDisc: + case DiscIO::Platform::WiiWAD: + return RC_CONSOLE_WII; + default: + return RC_CONSOLE_UNKNOWN; + } +} + void AchievementManager::LoadDefaultBadges() { std::lock_guard lg{m_lock}; diff --git a/Source/Core/Core/AchievementManager.h b/Source/Core/Core/AchievementManager.h index 4efbfe829f..3edb561979 100644 --- a/Source/Core/Core/AchievementManager.h +++ b/Source/Core/Core/AchievementManager.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "Common/CommonTypes.h" @@ -199,6 +200,8 @@ private: static size_t FilereaderRead(void* file_handle, void* buffer, size_t requested_bytes); static void FilereaderClose(void* file_handle); + static u32 FindConsoleID(const DiscIO::Platform& platform); + void LoadDefaultBadges(); static void LoginCallback(int result, const char* error_message, rc_client_t* client, void* userdata); diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index 373f446dee..2ad7eb270a 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -623,6 +623,8 @@ bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard, if (!Boot_WiiWAD(system, wad)) return false; + AchievementManager::GetInstance().LoadGame(&wad); + SConfig::OnTitleDirectlyBooted(guard); return true; }