Skip to content

Commit

Permalink
Achievements: Implement disc change without state reset
Browse files Browse the repository at this point in the history
  • Loading branch information
stenzek committed Jun 24, 2024
1 parent b9ff358 commit db30566
Showing 1 changed file with 59 additions and 9 deletions.
68 changes: 59 additions & 9 deletions src/core/achievements.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)

// TODO: Don't poll when booting the game, e.g. Crash Warped freaks out.
// TODO: rc_client_begin_change_media

#define IMGUI_DEFINE_MATH_OPERATORS

Expand Down Expand Up @@ -135,6 +134,7 @@ static void ShowLoginSuccess(const rc_client_t* client);
static void ShowLoginNotification();
static void IdentifyGame(const std::string& path, CDImage* image);
static void BeginLoadGame();
static void BeginChangeDisc();
static void UpdateGameSummary();
static void DownloadImage(std::string url, std::string cache_filename);

Expand Down Expand Up @@ -872,10 +872,35 @@ void Achievements::IdentifyGame(const std::string& path, CDImage* image)
return;
}

BeginLoadGame();
if (!rc_client_is_game_loaded(s_client))
BeginLoadGame();
else
BeginChangeDisc();
}

void Achievements::BeginLoadGame()
{
ClearGameInfo();

if (s_game_hash.empty())
{
// when we're booting the bios, this will fail
if (!s_game_path.empty())
{
Host::AddKeyedOSDMessage(
"retroachievements_disc_read_failed",
TRANSLATE_STR("Achievements", "Failed to read executable from disc. Achievements disabled."),
Host::OSD_ERROR_DURATION);
}

DisableHardcoreMode();
return;
}

s_load_game_request = rc_client_begin_load_game(s_client, s_game_hash.c_str(), ClientLoadGameCallback, nullptr);
}

void Achievements::BeginChangeDisc()
{
// cancel previous requests
if (s_load_game_request)
Expand All @@ -884,33 +909,40 @@ void Achievements::BeginLoadGame()
s_load_game_request = nullptr;
}

ClearGameInfo();

if (s_game_hash.empty())
{
// when we're booting the bios, this will fail
if (!s_game_path.empty())
{
Host::AddKeyedOSDMessage("retroachievements_disc_read_failed",
"Failed to read executable from disc. Achievements disabled.", Host::OSD_ERROR_DURATION);
Host::AddKeyedOSDMessage(
"retroachievements_disc_read_failed",
TRANSLATE_STR("Achievements", "Failed to read executable from disc. Achievements disabled."),
Host::OSD_ERROR_DURATION);
}

ClearGameInfo();
DisableHardcoreMode();
return;
}

s_load_game_request = rc_client_begin_load_game(s_client, s_game_hash.c_str(), ClientLoadGameCallback, nullptr);
s_load_game_request = rc_client_begin_change_media_from_hash(s_client, s_game_hash.c_str(), ClientLoadGameCallback,
reinterpret_cast<void*>(static_cast<uintptr_t>(1)));
}

void Achievements::ClientLoadGameCallback(int result, const char* error_message, rc_client_t* client, void* userdata)
{
const bool was_disc_change = (userdata != nullptr);

s_load_game_request = nullptr;
s_state_buffer.deallocate();

if (result == RC_NO_GAME_LOADED)
{
// Unknown game.
INFO_LOG("Unknown game '{}', disabling achievements.", s_game_hash);
if (was_disc_change)
ClearGameInfo();

DisableHardcoreMode();
return;
}
Expand All @@ -923,21 +955,37 @@ void Achievements::ClientLoadGameCallback(int result, const char* error_message,
else if (result != RC_OK)
{
ReportFmtError("Loading game failed: {}", error_message);
if (was_disc_change)
ClearGameInfo();

DisableHardcoreMode();
return;
}
else if (result == RC_HARDCORE_DISABLED)
{
if (error_message)
ReportError(error_message);

DisableHardcoreMode();
}

const rc_client_game_t* info = rc_client_get_game_info(s_client);
if (!info)
{
ReportError("rc_client_get_game_info() returned NULL");
if (was_disc_change)
ClearGameInfo();

DisableHardcoreMode();
return;
}

const bool has_achievements = rc_client_has_achievements(client);
const bool has_leaderboards = rc_client_has_leaderboards(client);

// Only display summary if the game title has changed across discs.
const bool display_summary = (s_game_id != info->id || s_game_title != info->title);

// If the game has a RetroAchievements entry but no achievements or leaderboards,
// enforcing hardcore mode is pointless.
if (!has_achievements && !has_leaderboards)
Expand All @@ -954,7 +1002,8 @@ void Achievements::ClientLoadGameCallback(int result, const char* error_message,
s_game_icon = {};

// ensure fullscreen UI is ready for notifications
FullscreenUI::Initialize();
if (display_summary)
FullscreenUI::Initialize();

if (const std::string_view badge_name = info->badge_name; !badge_name.empty())
{
Expand All @@ -974,7 +1023,8 @@ void Achievements::ClientLoadGameCallback(int result, const char* error_message,
}

UpdateGameSummary();
DisplayAchievementSummary();
if (display_summary)
DisplayAchievementSummary();

Host::OnAchievementsRefreshed();
}
Expand Down

0 comments on commit db30566

Please sign in to comment.