From c68549e9efcaebd5979bd254d9f746c5c3b68904 Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Fri, 30 May 2025 20:47:29 -0400 Subject: [PATCH] AchievementManager - Load unknown games Prior to this change, any game unrecognized by RetroAchievements would ultimately result in the game being "Closed" by AchievementManager. As a result, if any game was run while in this state without any other closing being done, AchievementManager would simply load it like a new game, despite memory already being accessed. However, testing and documentation determined that the rcheevos client doesn't actually complain when it fails to hash a game; it just runs this as "Unidentified Game" with RA ID = 0. As such, this change utilizes that in AchievementManager to differentiate between no software running and unidentified software running. As a result of this, now LoadGame needs to be called for every piece of runnable software, supported format or otherwise. If a supported format is not available, LoadGame can now be called with a nullptr to ensure that rcheevos still properly sets up an unidentified game. --- Source/Core/Core/AchievementManager.cpp | 55 +++++++++++++------------ Source/Core/Core/Boot/Boot.cpp | 7 ++++ Source/Core/Core/IOS/ES/ES.cpp | 4 +- 3 files changed, 37 insertions(+), 29 deletions(-) diff --git a/Source/Core/Core/AchievementManager.cpp b/Source/Core/Core/AchievementManager.cpp index baf8fa9ae9..e6cc162056 100644 --- a/Source/Core/Core/AchievementManager.cpp +++ b/Source/Core/Core/AchievementManager.cpp @@ -165,17 +165,26 @@ void AchievementManager::LoadGame(const DiscIO::Volume* volume) { return; } - if (volume == nullptr) - { - WARN_LOG_FMT(ACHIEVEMENTS, "Called Load Game without a game."); - return; - } if (!m_client) { ERROR_LOG_FMT(ACHIEVEMENTS, "Attempted to load game achievements without achievement client initialized."); return; } + if (volume == nullptr) + { + WARN_LOG_FMT(ACHIEVEMENTS, "Software format unsupported by AchievementManager."); + if (rc_client_get_game_info(m_client)) + { + rc_client_begin_change_media_from_hash(m_client, "", ChangeMediaCallback, NULL); + } + else + { + rc_client_set_read_memory_function(m_client, MemoryVerifier); + rc_client_begin_load_game(m_client, "", LoadGameCallback, NULL); + } + return; + } rc_client_set_unofficial_enabled(m_client, Config::Get(Config::RA_UNOFFICIAL_ENABLED)); rc_client_set_encore_mode_enabled(m_client, Config::Get(Config::RA_ENCORE_ENABLED)); rc_client_set_spectator_mode_enabled(m_client, Config::Get(Config::RA_SPECTATOR_ENABLED)); @@ -986,36 +995,30 @@ void AchievementManager::LoadGameCallback(int result, const char* error_message, OSD::Color::RED); return; } - if (result == RC_NO_GAME_LOADED && instance.m_dll_found) + + auto* game = rc_client_get_game_info(client); + if (result == RC_OK) { - // 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); - WARN_LOG_FMT(ACHIEVEMENTS, "Unrecognized title ready for development."); - OSD::AddMessage("Unrecognized title loaded for development.", OSD::Duration::VERY_LONG, - OSD::Color::YELLOW); + if (!game) + { + ERROR_LOG_FMT(ACHIEVEMENTS, "Failed to retrieve game information from client."); + OSD::AddMessage("Failed to load achievements for this title.", OSD::Duration::VERY_LONG, + OSD::Color::RED); + } + else + { + INFO_LOG_FMT(ACHIEVEMENTS, "Loaded data for game ID {}.", game->id); + instance.m_display_welcome_message = true; + } } - if (result != RC_OK) + else { WARN_LOG_FMT(ACHIEVEMENTS, "Failed to load data for current game."); OSD::AddMessage("Achievements are not supported for this title.", OSD::Duration::VERY_LONG, OSD::Color::RED); - return; } - auto* game = rc_client_get_game_info(client); - if (!game) - { - ERROR_LOG_FMT(ACHIEVEMENTS, "Failed to retrieve game information from client."); - OSD::AddMessage("Failed to load achievements for this title.", OSD::Duration::VERY_LONG, - OSD::Color::RED); - instance.CloseGame(); - return; - } - INFO_LOG_FMT(ACHIEVEMENTS, "Loaded data for game ID {}.", game->id); - rc_client_set_read_memory_function(instance.m_client, MemoryPeeker); - instance.m_display_welcome_message = true; instance.FetchGameBadges(); instance.m_system.store(&Core::System::GetInstance(), std::memory_order_release); instance.m_update_callback({.all = true}); diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index 2ad7eb270a..a3a984e35e 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -603,6 +603,8 @@ bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard, return false; } + AchievementManager::GetInstance().LoadGame(nullptr); + SConfig::OnTitleDirectlyBooted(guard); ppc_state.pc = executable.reader->GetEntryPoint(); @@ -635,6 +637,8 @@ bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard, if (!BootNANDTitle(system, nand_title.id)) return false; + AchievementManager::GetInstance().LoadGame(nullptr); + SConfig::OnTitleDirectlyBooted(guard); return true; } @@ -661,6 +665,8 @@ bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard, ipl.disc->auto_disc_change_paths); } + AchievementManager::GetInstance().LoadGame(nullptr); + SConfig::OnTitleDirectlyBooted(guard); return true; } @@ -668,6 +674,7 @@ bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard, bool operator()(const BootParameters::DFF& dff) const { NOTICE_LOG_FMT(BOOT, "Booting DFF: {}", dff.dff_path); + AchievementManager::GetInstance().LoadGame(nullptr); return system.GetFifoPlayer().Open(dff.dff_path); } diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index adc07d8d39..de13cf9bd1 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -479,9 +479,7 @@ bool ESDevice::LaunchPPCTitle(u64 title_id) if (!Core::IsRunning(system)) return BootstrapPPC(); - INFO_LOG_FMT(ACHIEVEMENTS, - "WAD and NAND formats not currently supported by Achievement Manager."); - AchievementManager::GetInstance().CloseGame(); + AchievementManager::GetInstance().LoadGame(nullptr); core_timing.RemoveEvent(s_bootstrap_ppc_for_launch_event); core_timing.ScheduleEvent(ticks, s_bootstrap_ppc_for_launch_event);