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.
This commit is contained in:
LillyJadeKatrin
2025-05-30 20:47:29 -04:00
parent fd285f6348
commit c68549e9ef
3 changed files with 37 additions and 29 deletions

View File

@ -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});

View File

@ -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);
}

View File

@ -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);