Achievements: Switch to rc_client

This commit is contained in:
Stenzek
2023-09-07 20:13:48 +10:00
parent f8c5e4982c
commit c773c763ef
28 changed files with 3327 additions and 3187 deletions

View File

@@ -1,4 +1,5 @@
add_library(core
achievements.cpp
achievements.h
analog_controller.cpp
analog_controller.h
@@ -123,7 +124,7 @@ target_precompile_headers(core PRIVATE "pch.h")
target_include_directories(core PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/..")
target_include_directories(core PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..")
target_link_libraries(core PUBLIC Threads::Threads common util zlib)
target_link_libraries(core PRIVATE stb xxhash imgui rapidjson)
target_link_libraries(core PRIVATE stb xxhash imgui rapidjson rcheevos)
if(${CPU_ARCH} STREQUAL "x64")
target_include_directories(core PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../../dep/xbyak/xbyak")
@@ -154,14 +155,6 @@ else()
message("Not building recompiler")
endif()
if(ENABLE_CHEEVOS)
target_sources(core PRIVATE
achievements.cpp
)
target_compile_definitions(core PUBLIC -DWITH_CHEEVOS=1)
target_link_libraries(core PRIVATE rcheevos rapidjson)
endif()
if(ENABLE_DISCORD_PRESENCE)
target_compile_definitions(core PUBLIC -DWITH_DISCORD_PRESENCE=1)
target_link_libraries(core PRIVATE discord-rpc)

File diff suppressed because it is too large Load Diff

View File

@@ -3,105 +3,44 @@
#pragma once
#include "settings.h"
#include "types.h"
#include "common/string.h"
#include "common/types.h"
#include <functional>
#include <optional>
#include <string>
#include <utility>
#include <vector>
class Error;
class StateWrapper;
class CDImage;
struct Settings;
namespace Achievements {
#ifdef WITH_CHEEVOS
enum class AchievementCategory : u8
enum class LoginRequestReason
{
Local = 0,
Core = 3,
Unofficial = 5
UserInitiated,
TokenInvalid,
};
struct Achievement
{
u32 id;
std::string title;
std::string description;
std::string memaddr;
std::string badge_name;
// badge paths are mutable because they're resolved when they're needed.
mutable std::string locked_badge_path;
mutable std::string unlocked_badge_path;
u32 points;
AchievementCategory category;
bool locked;
bool active;
bool primed;
};
struct Leaderboard
{
u32 id;
std::string title;
std::string description;
int format;
};
struct LeaderboardEntry
{
std::string user;
std::string formatted_score;
time_t submitted;
u32 rank;
bool is_self;
};
// RAIntegration only exists for Windows, so no point checking it on other platforms.
#ifdef WITH_RAINTEGRATION
bool IsUsingRAIntegration();
#else
static ALWAYS_INLINE bool IsUsingRAIntegration()
{
return false;
}
#endif
bool IsActive();
bool IsLoggedIn();
bool ChallengeModeActive();
bool LeaderboardsActive();
bool IsTestModeActive();
bool IsUnofficialTestModeActive();
bool IsRichPresenceEnabled();
bool HasActiveGame();
u32 GetGameID();
/// Acquires the achievements lock. Must be held when accessing any achievement state from another thread.
std::unique_lock<std::recursive_mutex> GetLock();
void Initialize();
/// Initializes the RetroAchievments client.
bool Initialize();
/// Updates achievements settings.
void UpdateSettings(const Settings& old_config);
void ResetRuntime();
/// Resets the internal state of all achievement tracking. Call on system reset.
void ResetClient();
/// Called when the system is being reset. If it returns false, the reset should be aborted.
bool ConfirmSystemReset();
/// Called when the system is being shut down. If Shutdown() returns false, the shutdown should be aborted.
bool Shutdown();
bool Shutdown(bool allow_cancel);
/// Called when the system is being paused and resumed.
void OnSystemPaused(bool paused);
@@ -110,60 +49,86 @@ void OnSystemPaused(bool paused);
void FrameUpdate();
/// Called when the system is paused, because FrameUpdate() won't be getting called.
void ProcessPendingHTTPRequests();
void IdleUpdate();
/// Saves/loads state.
bool DoState(StateWrapper& sw);
/// Returns true if the current game has any achievements or leaderboards.
/// Does not need to have the lock held.
bool SafeHasAchievementsOrLeaderboards();
/// Attempts to log in to RetroAchievements using the specified credentials.
/// If the login is successful, the token returned by the server will be saved.
bool Login(const char* username, const char* password, Error* error);
const std::string& GetUsername();
const std::string& GetRichPresenceString();
bool LoginAsync(const char* username, const char* password);
bool Login(const char* username, const char* password);
/// Logs out of RetroAchievements, clearing any credentials.
void Logout();
/// Called when the system changes game, or is booting.
void GameChanged(const std::string& path, CDImage* image);
/// Re-enables hardcode mode if it is enabled in the settings.
bool ResetChallengeMode();
bool ResetHardcoreMode();
/// Forces hardcore mode off until next reset.
void DisableChallengeMode();
void DisableHardcoreMode();
/// Prompts the user to disable hardcore mode, if they agree, returns true.
bool ConfirmChallengeModeDisable(const char* trigger);
bool ConfirmHardcoreModeDisable(const char* trigger);
/// Returns true if features such as save states should be disabled.
bool ChallengeModeActive();
/// Returns true if hardcore mode is active, and functionality should be restricted.
bool IsHardcoreModeActive();
/// RAIntegration only exists for Windows, so no point checking it on other platforms.
bool IsUsingRAIntegration();
/// Returns true if the achievement system is active. Achievements can be active without a valid client.
bool IsActive();
/// Returns true if RetroAchievements game data has been loaded.
bool HasActiveGame();
/// Returns the RetroAchievements ID for the current game.
u32 GetGameID();
/// Returns true if the current game has any achievements or leaderboards.
bool HasAchievementsOrLeaderboards();
/// Returns true if the current game has any leaderboards.
bool HasLeaderboards();
/// Returns true if the game supports rich presence.
bool HasRichPresence();
/// Returns the current rich presence string.
/// Should be called with the lock held.
const std::string& GetRichPresenceString();
/// Returns the RetroAchievements title for the current game.
/// Should be called with the lock held.
const std::string& GetGameTitle();
const std::string& GetGameIcon();
bool EnumerateAchievements(std::function<bool(const Achievement&)> callback);
u32 GetUnlockedAchiementCount();
u32 GetAchievementCount();
u32 GetMaximumPointsForGame();
u32 GetCurrentPointsForGame();
/// Clears all cached state used to render the UI.
void ClearUIState();
bool EnumerateLeaderboards(std::function<bool(const Leaderboard&)> callback);
std::optional<bool> TryEnumerateLeaderboardEntries(u32 id, std::function<bool(const LeaderboardEntry&)> callback);
const Leaderboard* GetLeaderboardByID(u32 id);
u32 GetLeaderboardCount();
bool IsLeaderboardTimeType(const Leaderboard& leaderboard);
u32 GetPrimedAchievementCount();
/// Draws ImGui overlays when not paused.
void DrawGameOverlays();
const Achievement* GetAchievementByID(u32 id);
std::pair<u32, u32> GetAchievementProgress(const Achievement& achievement);
TinyString GetAchievementProgressText(const Achievement& achievement);
const std::string& GetAchievementBadgePath(const Achievement& achievement, bool download_if_missing = true,
bool force_unlocked_icon = false);
std::string GetAchievementBadgeURL(const Achievement& achievement);
/// Draws ImGui overlays when paused.
void DrawPauseMenuOverlays();
/// Queries the achievement list, and if no achievements are available, returns false.
bool PrepareAchievementsWindow();
/// Renders the achievement list.
void DrawAchievementsWindow();
/// Queries the leaderboard list, and if no leaderboards are available, returns false.
bool PrepareLeaderboardsWindow();
/// Renders the leaderboard list.
void DrawLeaderboardsWindow();
#ifdef WITH_RAINTEGRATION
/// Prevents the internal implementation from being used. Instead, RAIntegration will be
/// called into when achievement-related events occur.
void SwitchToRAIntegration();
namespace RAIntegration {
@@ -173,46 +138,20 @@ std::vector<std::tuple<int, std::string, bool>> GetMenuItems();
void ActivateMenuItem(int item);
} // namespace RAIntegration
#endif
#else
// Make noops when compiling without cheevos.
static inline bool ConfirmSystemReset()
{
return true;
}
static inline void ResetRuntime()
{
}
static inline bool DoState(StateWrapper& sw)
{
return true;
}
static constexpr inline bool ChallengeModeActive()
{
return false;
}
static inline bool ResetChallengeMode()
{
return false;
}
static inline void DisableChallengeMode()
{
}
static inline bool ConfirmChallengeModeDisable(const char* trigger)
{
return true;
}
#endif
} // namespace Achievements
/// Functions implemented in the frontend.
namespace Host {
/// Called if the big picture UI requests achievements login, or token login fails.
void OnAchievementsLoginRequested(Achievements::LoginRequestReason reason);
/// Called when achievements login completes.
void OnAchievementsLoginSuccess(const char* display_name, u32 points, u32 sc_points, u32 unread_messages);
/// Called whenever game details or rich presence information is updated.
/// Implementers can assume the lock is held when this is called.
void OnAchievementsRefreshed();
void OnAchievementsChallengeModeChanged();
/// Called whenever hardcore mode is toggled.
void OnAchievementsHardcoreModeChanged();
} // namespace Host

View File

@@ -4,7 +4,7 @@
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>WITH_CHEEVOS=1;WITH_DISCORD_PRESENCE=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WITH_DISCORD_PRESENCE=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="('$(Platform)'!='ARM64')">WITH_RAINTEGRATION=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="('$(Platform)'=='x64' Or '$(Platform)'=='ARM' Or '$(Platform)'=='ARM64')">WITH_RECOMPILER=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="('$(Platform)'=='x64' Or '$(Platform)'=='ARM64')">WITH_MMAP_FASTMEM=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@
#include <memory>
#include <string>
class GPUTexture;
class String;
struct Settings;
@@ -23,11 +23,15 @@ void OnSystemDestroyed();
void OnRunningGameChanged();
void OpenPauseMenu();
bool OpenAchievementsWindow();
bool IsAchievementsWindowOpen();
bool OpenLeaderboardsWindow();
bool IsLeaderboardsWindowOpen();
void ReturnToMainWindow();
void Shutdown();
void Render();
void InvalidateCoverCache();
void TimeToPrintableString(String* str, time_t t);
// Returns true if the message has been dismissed.
bool DrawErrorWindow(const char* message);

View File

@@ -160,7 +160,7 @@ DEFINE_HOTKEY("Screenshot", TRANSLATE_NOOP("Hotkeys", "General"), TRANSLATE_NOOP
System::SaveScreenshot();
})
#if !defined(__ANDROID__) && defined(WITH_CHEEVOS)
#if !defined(__ANDROID__)
DEFINE_HOTKEY("OpenAchievements", TRANSLATE_NOOP("Hotkeys", "General"),
TRANSLATE_NOOP("Hotkeys", "Open Achievement List"), [](s32 pressed) {
if (!pressed)
@@ -184,7 +184,7 @@ DEFINE_HOTKEY("OpenLeaderboards", TRANSLATE_NOOP("Hotkeys", "General"),
}
}
})
#endif // !defined(__ANDROID__) && defined(WITH_CHEEVOS)
#endif // !defined(__ANDROID__)
DEFINE_HOTKEY("Reset", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Reset System"), [](s32 pressed) {
if (!pressed)

View File

@@ -365,16 +365,20 @@ void Settings::Load(SettingsInterface& si)
memory_card_use_playlist_title = si.GetBoolValue("MemoryCards", "UsePlaylistTitle", true);
achievements_enabled = si.GetBoolValue("Cheevos", "Enabled", false);
achievements_test_mode = si.GetBoolValue("Cheevos", "TestMode", false);
achievements_hardcore_mode = si.GetBoolValue("Cheevos", "ChallengeMode", false);
achievements_notifications = si.GetBoolValue("Cheevos", "Notifications", true);
achievements_leaderboard_notifications = si.GetBoolValue("Cheevos", "LeaderboardNotifications", true);
achievements_sound_effects = si.GetBoolValue("Cheevos", "SoundEffects", true);
achievements_overlays = si.GetBoolValue("Cheevos", "Overlays", true);
achievements_encore_mode = si.GetBoolValue("Cheevos", "EncoreMode", false);
achievements_spectator_mode = si.GetBoolValue("Cheevos", "SpectatorMode", false);
achievements_unofficial_test_mode = si.GetBoolValue("Cheevos", "UnofficialTestMode", false);
achievements_use_first_disc_from_playlist = si.GetBoolValue("Cheevos", "UseFirstDiscFromPlaylist", true);
achievements_rich_presence = si.GetBoolValue("Cheevos", "RichPresence", true);
achievements_challenge_mode = si.GetBoolValue("Cheevos", "ChallengeMode", false);
achievements_leaderboards = si.GetBoolValue("Cheevos", "Leaderboards", true);
achievements_notifications = si.GetBoolValue("Cheevos", "Notifications", true);
achievements_sound_effects = si.GetBoolValue("Cheevos", "SoundEffects", true);
achievements_primed_indicators = si.GetBoolValue("Cheevos", "PrimedIndicators", true);
achievements_use_raintegration = si.GetBoolValue("Cheevos", "UseRAIntegration", false);
achievements_notification_duration =
si.GetFloatValue("Cheevos", "NotificationsDuration", DEFAULT_ACHIEVEMENT_NOTIFICATION_TIME);
achievements_leaderboard_duration =
si.GetFloatValue("Cheevos", "LeaderboardsDuration", DEFAULT_LEADERBOARD_NOTIFICATION_TIME);
log_level = ParseLogLevelName(si.GetStringValue("Logging", "LogLevel", GetLogLevelName(DEFAULT_LOG_LEVEL)).c_str())
.value_or(DEFAULT_LOG_LEVEL);
@@ -564,16 +568,18 @@ void Settings::Save(SettingsInterface& si) const
si.SetStringValue("ControllerPorts", "MultitapMode", GetMultitapModeName(multitap_mode));
si.SetBoolValue("Cheevos", "Enabled", achievements_enabled);
si.SetBoolValue("Cheevos", "TestMode", achievements_test_mode);
si.SetBoolValue("Cheevos", "ChallengeMode", achievements_hardcore_mode);
si.SetBoolValue("Cheevos", "Notifications", achievements_notifications);
si.SetBoolValue("Cheevos", "LeaderboardNotifications", achievements_leaderboard_notifications);
si.SetBoolValue("Cheevos", "SoundEffects", achievements_sound_effects);
si.SetBoolValue("Cheevos", "Overlays", achievements_overlays);
si.SetBoolValue("Cheevos", "EncoreMode", achievements_encore_mode);
si.SetBoolValue("Cheevos", "SpectatorMode", achievements_spectator_mode);
si.SetBoolValue("Cheevos", "UnofficialTestMode", achievements_unofficial_test_mode);
si.SetBoolValue("Cheevos", "UseFirstDiscFromPlaylist", achievements_use_first_disc_from_playlist);
si.SetBoolValue("Cheevos", "RichPresence", achievements_rich_presence);
si.SetBoolValue("Cheevos", "ChallengeMode", achievements_challenge_mode);
si.SetBoolValue("Cheevos", "Leaderboards", achievements_leaderboards);
si.SetBoolValue("Cheevos", "Notifications", achievements_notifications);
si.SetBoolValue("Cheevos", "SoundEffects", achievements_sound_effects);
si.SetBoolValue("Cheevos", "PrimedIndicators", achievements_primed_indicators);
si.SetBoolValue("Cheevos", "UseRAIntegration", achievements_use_raintegration);
si.SetFloatValue("Cheevos", "NotificationsDuration", achievements_notification_duration);
si.SetFloatValue("Cheevos", "LeaderboardsDuration", achievements_leaderboard_duration);
si.SetStringValue("Logging", "LogLevel", GetLogLevelName(log_level));
si.SetStringValue("Logging", "LogFilter", log_filter.c_str());
@@ -696,7 +702,7 @@ void Settings::FixIncompatibleSettings(bool display_osd_messages)
}
// if challenge mode is enabled, disable things like rewind since they use save states
if (Achievements::ChallengeModeActive())
if (Achievements::IsHardcoreModeActive())
{
g_settings.emulation_speed =
(g_settings.emulation_speed != 0.0f) ? std::max(g_settings.emulation_speed, 1.0f) : 0.0f;

View File

@@ -180,16 +180,18 @@ struct Settings
// achievements
bool achievements_enabled = false;
bool achievements_test_mode = false;
bool achievements_hardcore_mode = false;
bool achievements_notifications = true;
bool achievements_leaderboard_notifications = true;
bool achievements_sound_effects = true;
bool achievements_overlays = true;
bool achievements_encore_mode = false;
bool achievements_spectator_mode = false;
bool achievements_unofficial_test_mode = false;
bool achievements_use_first_disc_from_playlist = true;
bool achievements_rich_presence = true;
bool achievements_challenge_mode = false;
bool achievements_leaderboards = true;
bool achievements_notifications = true;
bool achievements_sound_effects = true;
bool achievements_primed_indicators = true;
bool achievements_use_raintegration = false;
float achievements_notification_duration = DEFAULT_ACHIEVEMENT_NOTIFICATION_TIME;
float achievements_leaderboard_duration = DEFAULT_LEADERBOARD_NOTIFICATION_TIME;
struct DebugSettings
{
@@ -473,6 +475,9 @@ struct Settings
static constexpr MemoryCardType DEFAULT_MEMORY_CARD_2_TYPE = MemoryCardType::None;
static constexpr MultitapMode DEFAULT_MULTITAP_MODE = MultitapMode::Disabled;
static constexpr float DEFAULT_ACHIEVEMENT_NOTIFICATION_TIME = 10.0f;
static constexpr float DEFAULT_LEADERBOARD_NOTIFICATION_TIME = 10.0f;
static constexpr LOGLEVEL DEFAULT_LOG_LEVEL = LOGLEVEL_INFO;
#ifndef __ANDROID__

View File

@@ -135,7 +135,6 @@ static void SetTimerResolutionIncreased(bool enabled);
#ifdef WITH_DISCORD_PRESENCE
static void InitializeDiscordPresence();
static void ShutdownDiscordPresence();
static void UpdateDiscordPresence(bool rich_presence_only);
static void PollDiscordPresence();
#endif
} // namespace System
@@ -233,11 +232,7 @@ static u32 s_runahead_replay_frames = 0;
static u64 s_session_start_time = 0;
#ifdef WITH_DISCORD_PRESENCE
// discord rich presence
static bool s_discord_presence_active = false;
#ifdef WITH_CHEEVOS
static std::string s_discord_presence_cheevos_string;
#endif
#endif
static TinyString GetTimestampStringForFileName()
@@ -250,14 +245,12 @@ void System::Internal::ProcessStartup()
// This will call back to Host::LoadSettings() -> ReloadSources().
LoadSettings(false);
#ifdef WITH_CHEEVOS
#ifdef WITH_RAINTEGRATION
if (Host::GetBaseBoolSettingValue("Cheevos", "UseRAIntegration", false))
Achievements::SwitchToRAIntegration();
#endif
if (g_settings.achievements_enabled)
Achievements::Initialize();
#endif
}
void System::Internal::ProcessShutdown()
@@ -266,9 +259,7 @@ void System::Internal::ProcessShutdown()
ShutdownDiscordPresence();
#endif
#ifdef WITH_CHEEVOS
Achievements::Shutdown();
#endif
Achievements::Shutdown(false);
InputManager::CloseSources();
}
@@ -281,9 +272,7 @@ void System::Internal::IdlePollUpdate()
PollDiscordPresence();
#endif
#ifdef WITH_CHEEVOS
Achievements::ProcessPendingHTTPRequests();
#endif
Achievements::IdleUpdate();
}
System::State System::GetState()
@@ -1068,13 +1057,11 @@ void System::ResetSystem()
if (!IsValid())
return;
#ifdef WITH_CHEEVOS
if (!Achievements::ConfirmSystemReset())
return;
if (Achievements::ResetChallengeMode())
if (Achievements::ResetHardcoreMode())
ApplySettings(false);
#endif
InternalReset();
ResetPerformanceCounters();
@@ -1096,9 +1083,7 @@ void System::PauseSystem(bool paused)
InputManager::PauseVibration();
#ifdef WITH_CHEEVOS
Achievements::OnSystemPaused(true);
#endif
if (g_settings.inhibit_screensaver)
PlatformMisc::ResumeScreensaver();
@@ -1110,9 +1095,7 @@ void System::PauseSystem(bool paused)
{
FullscreenUI::OnSystemResumed();
#ifdef WITH_CHEEVOS
Achievements::OnSystemPaused(false);
#endif
if (g_settings.inhibit_screensaver)
PlatformMisc::SuspendScreensaver();
@@ -1131,13 +1114,11 @@ bool System::LoadState(const char* filename)
if (!IsValid())
return false;
#ifdef WITH_CHEEVOS
if (Achievements::ChallengeModeActive() &&
!Achievements::ConfirmChallengeModeDisable(TRANSLATE("Achievements", "Loading state")))
if (Achievements::IsHardcoreModeActive() &&
!Achievements::ConfirmHardcoreModeDisable(TRANSLATE("Achievements", "Loading state")))
{
return false;
}
#endif
Common::Timer load_timer;
@@ -1265,11 +1246,11 @@ bool System::BootSystem(SystemBootParameters parameters)
(do_exe_boot ? GetRegionForExe(parameters.filename.c_str()) : GetRegionForPsf(parameters.filename.c_str()));
Log_InfoPrintf("EXE/PSF Region: %s", Settings::GetDiscRegionDisplayName(file_region));
s_region = GetConsoleRegionForDiscRegion(file_region);
if (do_psf_boot)
psf_boot = std::move(parameters.filename);
else
exe_boot = std::move(parameters.filename);
}
if (do_psf_boot)
psf_boot = std::move(parameters.filename);
else
exe_boot = std::move(parameters.filename);
}
else
{
@@ -1350,17 +1331,15 @@ bool System::BootSystem(SystemBootParameters parameters)
return false;
}
#ifdef WITH_CHEEVOS
// Check for resuming with hardcore mode.
if (!parameters.save_state.empty() && Achievements::ChallengeModeActive() &&
!Achievements::ConfirmChallengeModeDisable(TRANSLATE("Achievements", "Resuming state")))
if (!parameters.save_state.empty() && Achievements::IsHardcoreModeActive() &&
!Achievements::ConfirmHardcoreModeDisable(TRANSLATE("Achievements", "Resuming state")))
{
s_state = State::Shutdown;
ClearRunningGame();
Host::OnSystemDestroyed();
return false;
}
#endif
// Load BIOS image.
if (!LoadBIOS(parameters.override_bios))
@@ -1683,12 +1662,10 @@ void System::ClearRunningGame()
Host::OnGameChanged(s_running_game_path, s_running_game_serial, s_running_game_title);
#ifdef WITH_CHEEVOS
Achievements::GameChanged(s_running_game_path, nullptr);
#endif
#ifdef WITH_DISCORD_PRESENCE
UpdateDiscordPresence(false);
UpdateDiscordPresence();
#endif
}
@@ -1760,10 +1737,8 @@ void System::FrameDone()
if (s_cheat_list)
s_cheat_list->Apply();
#ifdef WITH_CHEEVOS
if (Achievements::IsActive())
Achievements::FrameUpdate();
#endif
#ifdef WITH_DISCORD_PRESENCE
PollDiscordPresence();
@@ -2131,23 +2106,13 @@ bool System::DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_di
if (!sw.DoMarker("Cheevos"))
return false;
#ifdef WITH_CHEEVOS
if (!Achievements::DoState(sw))
return false;
#else
// if we compiled without cheevos, we need to toss out the data from states which were
u32 data_size = 0;
sw.Do(&data_size);
if (data_size > 0)
sw.SkipBytes(data_size);
#endif
}
else
{
#ifdef WITH_CHEEVOS
// loading an old state without cheevos, so reset the runtime
Achievements::ResetRuntime();
#endif
Achievements::ResetClient();
}
}
@@ -2208,9 +2173,7 @@ void System::InternalReset()
TimingEvents::Reset();
ResetPerformanceCounters();
#ifdef WITH_CHEEVOS
Achievements::ResetRuntime();
#endif
Achievements::ResetClient();
}
std::string System::GetMediaPathFromSaveState(const char* path)
@@ -2352,15 +2315,13 @@ bool System::LoadStateFromStream(ByteStream* state, bool update_display, bool ig
ClearMemorySaveStates();
#ifdef WITH_CHEEVOS
// Updating game/loading settings can turn on hardcore mode. Catch this.
if (Achievements::ChallengeModeActive())
if (Achievements::IsHardcoreModeActive())
{
Host::AddKeyedOSDMessage("challenge_mode_reset",
TRANSLATE_STR("Achievements", "Hardcore mode disabled by state switch."), 10.0f);
Achievements::DisableChallengeMode();
Achievements::DisableHardcoreMode();
}
#endif
if (!state->SeekAbsolute(header.offset_to_data))
return false;
@@ -2720,10 +2681,8 @@ void System::SetRewindState(bool enabled)
return;
}
#ifdef WITH_CHEEVOS
if (Achievements::ChallengeModeActive() && !Achievements::ConfirmChallengeModeDisable("Rewinding"))
if (Achievements::IsHardcoreModeActive() && !Achievements::ConfirmHardcoreModeDisable("Rewinding"))
return;
#endif
System::SetRewinding(enabled);
UpdateSpeedLimiterState();
@@ -2734,10 +2693,8 @@ void System::DoFrameStep()
if (!IsValid())
return;
#ifdef WITH_CHEEVOS
if (Achievements::ChallengeModeActive() && !Achievements::ConfirmChallengeModeDisable("Frame stepping"))
if (Achievements::IsHardcoreModeActive() && !Achievements::ConfirmHardcoreModeDisable("Frame stepping"))
return;
#endif
s_frame_step_request = true;
PauseSystem(false);
@@ -2748,10 +2705,8 @@ void System::DoToggleCheats()
if (!System::IsValid())
return;
#ifdef WITH_CHEEVOS
if (Achievements::ChallengeModeActive() && !Achievements::ConfirmChallengeModeDisable("Toggling cheats"))
if (Achievements::IsHardcoreModeActive() && !Achievements::ConfirmHardcoreModeDisable("Toggling cheats"))
return;
#endif
CheatList* cl = GetCheatList();
if (!cl)
@@ -3341,18 +3296,16 @@ void System::UpdateRunningGame(const char* path, CDImage* image, bool booting)
g_texture_replacements.SetGameID(s_running_game_serial);
#ifdef WITH_CHEEVOS
if (booting)
Achievements::ResetChallengeMode();
Achievements::ResetHardcoreMode();
Achievements::GameChanged(s_running_game_path, image);
#endif
UpdateGameSettingsLayer();
ApplySettings(true);
s_cheat_list.reset();
if (g_settings.auto_load_cheats && !Achievements::ChallengeModeActive())
if (g_settings.auto_load_cheats && !Achievements::IsHardcoreModeActive())
LoadCheatListFromGameTitle();
if (s_running_game_serial != prev_serial)
@@ -3361,7 +3314,7 @@ void System::UpdateRunningGame(const char* path, CDImage* image, bool booting)
SaveStateSelectorUI::RefreshList();
#ifdef WITH_DISCORD_PRESENCE
UpdateDiscordPresence(false);
UpdateDiscordPresence();
#endif
Host::OnGameChanged(s_running_game_path, s_running_game_serial, s_running_game_title);
@@ -3732,9 +3685,7 @@ void System::CheckForSettingsChanges(const Settings& old_settings)
if (g_settings.multitap_mode != old_settings.multitap_mode)
UpdateMultitaps();
#ifdef WITH_CHEEVOS
Achievements::UpdateSettings(old_settings);
#endif
FullscreenUI::CheckForConfigChanges(old_settings);
@@ -4417,7 +4368,7 @@ bool System::LoadCheatList(const char* filename)
bool System::LoadCheatListFromGameTitle()
{
// Called when booting, needs to test for shutdown.
if (IsShutdown() || Achievements::ChallengeModeActive())
if (IsShutdown() || Achievements::IsHardcoreModeActive())
return false;
const std::string filename(GetCheatFileName());
@@ -4429,7 +4380,7 @@ bool System::LoadCheatListFromGameTitle()
bool System::LoadCheatListFromDatabase()
{
if (IsShutdown() || s_running_game_serial.empty() || Achievements::ChallengeModeActive())
if (IsShutdown() || s_running_game_serial.empty() || Achievements::IsHardcoreModeActive())
return false;
std::unique_ptr<CheatList> cl = std::make_unique<CheatList>();
@@ -4775,7 +4726,7 @@ void System::InitializeDiscordPresence()
Discord_Initialize("705325712680288296", &handlers, 0, nullptr);
s_discord_presence_active = true;
UpdateDiscordPresence(false);
UpdateDiscordPresence();
}
void System::ShutdownDiscordPresence()
@@ -4786,31 +4737,13 @@ void System::ShutdownDiscordPresence()
Discord_ClearPresence();
Discord_Shutdown();
s_discord_presence_active = false;
#ifdef WITH_CHEEVOS
s_discord_presence_cheevos_string.clear();
#endif
}
void System::UpdateDiscordPresence(bool rich_presence_only)
void System::UpdateDiscordPresence()
{
if (!s_discord_presence_active)
return;
#ifdef WITH_CHEEVOS
// Update only if RetroAchievements rich presence has changed
const std::string& new_rich_presence = Achievements::GetRichPresenceString();
if (new_rich_presence == s_discord_presence_cheevos_string && rich_presence_only)
{
return;
}
s_discord_presence_cheevos_string = new_rich_presence;
#else
if (rich_presence_only)
{
return;
}
#endif
// https://discord.com/developers/docs/rich-presence/how-to#updating-presence-update-presence-payload-fields
DiscordRichPresence rp = {};
rp.largeImageKey = "duckstation_logo";
@@ -4827,22 +4760,19 @@ void System::UpdateDiscordPresence(bool rich_presence_only)
details_string.AppendString("No Game Running");
}
#ifdef WITH_CHEEVOS
SmallString state_string;
// Trim to 128 bytes as per Discord-RPC requirements
if (s_discord_presence_cheevos_string.length() >= 128)
{
// 124 characters + 3 dots + null terminator
state_string = s_discord_presence_cheevos_string.substr(0, 124);
state_string.AppendString("...");
}
else
{
state_string = s_discord_presence_cheevos_string;
}
rp.state = state_string;
#endif
if (Achievements::HasRichPresence())
{
const auto lock = Achievements::GetLock();
const std::string_view richp = Achievements::GetRichPresenceString();
if (richp.length() >= 128)
state_string.AppendFmtString("{}...", richp.substr(0, 124));
else
state_string.Assign(richp);
rp.state = state_string;
}
rp.details = details_string;
Discord_UpdatePresence(&rp);
@@ -4853,8 +4783,6 @@ void System::PollDiscordPresence()
if (!s_discord_presence_active)
return;
UpdateDiscordPresence(true);
Discord_RunCallbacks();
}

View File

@@ -479,6 +479,11 @@ void UpdateMemorySaveStateSettings();
bool LoadRewindState(u32 skip_saves = 0, bool consume_state = true);
void SetRunaheadReplayFlag();
#ifdef WITH_DISCORD_PRESENCE
/// Called when rich presence changes.
void UpdateDiscordPresence();
#endif
namespace Internal {
/// Called on process startup.
void ProcessStartup();