// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <[email protected]>1// SPDX-License-Identifier: CC-BY-NC-ND-4.023#pragma once45#include "common/small_string.h"6#include "common/types.h"78#include <array>9#include <functional>10#include <mutex>11#include <optional>12#include <span>13#include <string>14#include <utility>15#include <vector>1617class Error;18class StateWrapper;19class CDImage;2021struct Settings;2223namespace Achievements {2425enum class LoginRequestReason26{27UserInitiated,28TokenInvalid,29};3031inline constexpr size_t GAME_HASH_LENGTH = 16;32using GameHash = std::array<u8, GAME_HASH_LENGTH>;3334struct HashDatabaseEntry35{36GameHash hash;37u32 game_id;38u32 num_achievements;39};4041class ProgressDatabase42{43public:44struct Entry45{46u32 game_id;47u16 num_achievements_unlocked;48u16 num_hc_achievements_unlocked;49};5051ProgressDatabase();52~ProgressDatabase();5354bool Load(Error* error);5556const Entry* LookupGame(u32 game_id) const;5758private:59std::vector<Entry> m_entries;60};6162/// Acquires the achievements lock. Must be held when accessing any achievement state from another thread.63std::unique_lock<std::recursive_mutex> GetLock();6465/// Returns the achievements game hash for a given disc.66std::optional<GameHash> GetGameHash(CDImage* image, u32* bytes_hashed = nullptr);67std::optional<GameHash> GetGameHash(const std::string_view executable_name, std::span<const u8> executable_data,68u32* bytes_hashed = nullptr);6970/// Returns the number of achievements for a given hash.71const HashDatabaseEntry* LookupGameHash(const GameHash& hash);7273/// Initializes the RetroAchievments client.74bool Initialize();7576/// Updates achievements settings.77void UpdateSettings(const Settings& old_config);7879/// Shuts down the RetroAchievements client.80void Shutdown();8182/// Call to refresh the all-progress database.83bool RefreshAllProgressDatabase(Error* error);8485/// Called when the system is start. Engages hardcore mode if enabled.86void OnSystemStarting(CDImage* image, bool disable_hardcore_mode);8788/// Called when the system is shutting down. If this returns false, the shutdown should be aborted.89void OnSystemDestroyed();9091/// Called when the system is being reset. Resets the internal state of all achievement tracking.92void OnSystemReset();9394/// Called when the system changes game.95void GameChanged(CDImage* image);9697/// Called once a frame at vsync time on the CPU thread.98void FrameUpdate();99100/// Called when the system is paused, because FrameUpdate() won't be getting called.101void IdleUpdate();102103/// Returns true if idle updates are necessary (e.g. outstanding requests).104bool NeedsIdleUpdate();105106/// Saves/loads state.107bool DoState(StateWrapper& sw);108109/// Attempts to log in to RetroAchievements using the specified credentials.110/// If the login is successful, the token returned by the server will be saved.111bool Login(const char* username, const char* password, Error* error);112113/// Logs out of RetroAchievements, clearing any credentials.114void Logout();115116/// Forces hardcore mode off until next reset.117void DisableHardcoreMode(bool show_message, bool display_game_summary);118119/// Prompts the user to disable hardcore mode, if they agree, returns true.120bool ConfirmHardcoreModeDisable(const char* trigger);121void ConfirmHardcoreModeDisableAsync(const char* trigger, std::function<void(bool)> callback);122123/// Returns true if hardcore mode is active, and functionality should be restricted.124bool IsHardcoreModeActive();125126/// RAIntegration only exists for Windows, so no point checking it on other platforms.127bool IsUsingRAIntegration();128bool IsRAIntegrationAvailable();129130/// Returns true if the achievement system is active. Achievements can be active without a valid client.131bool IsActive();132133/// Returns true if RetroAchievements game data has been loaded.134bool HasActiveGame();135136/// Returns the RetroAchievements ID for the current game.137u32 GetGameID();138139/// Returns true if the current game has any achievements or leaderboards.140bool HasAchievementsOrLeaderboards();141142/// Returns true if the current game has any leaderboards.143bool HasAchievements();144145/// Returns true if the current game has any leaderboards.146bool HasLeaderboards();147148/// Returns true if the game supports rich presence.149bool HasRichPresence();150151/// Returns the current rich presence string.152/// Should be called with the lock held.153const std::string& GetRichPresenceString();154155/// Returns the URL for the current icon of the game156const std::string& GetGameIconURL();157158/// Returns the path for the current icon of the game159const std::string& GetGameIconPath();160161/// Returns the RetroAchievements title for the current game.162/// Should be called with the lock held.163const std::string& GetGameTitle();164165/// Returns the path for the game that is current hashed/running.166const std::string& GetGamePath();167168/// Returns true if the user has been successfully logged in.169bool IsLoggedIn();170171/// Returns true if the user has been successfully logged in, or the request is in progress.172bool IsLoggedInOrLoggingIn();173174/// Returns the logged-in user name.175const char* GetLoggedInUserName();176177/// Returns the path to the user's profile avatar.178/// Should be called with the lock held.179std::string GetLoggedInUserBadgePath();180181/// Returns a summary of the user's points.182/// Should be called with the lock held.183SmallString GetLoggedInUserPointsSummary();184185/// Returns 0 if pausing is allowed, otherwise the number of frames until pausing is allowed.186u32 GetPauseThrottleFrames();187188/// Clears all cached state used to render the UI.189void ClearUIState();190191/// Draws ImGui overlays when not paused.192void DrawGameOverlays();193194/// Draws ImGui overlays when paused.195void DrawPauseMenuOverlays(float start_pos_y);196197/// Updates the stored most-recent and closest-to-completion achievements.198/// Call before calling DrawPauseMenuOverlays() for the first time.199void UpdateRecentUnlockAndAlmostThere();200201#ifndef __ANDROID__202203/// Queries the achievement list, and if no achievements are available, returns false.204bool PrepareAchievementsWindow();205206/// Renders the achievement list.207void DrawAchievementsWindow();208209/// Queries the leaderboard list, and if no leaderboards are available, returns false.210bool PrepareLeaderboardsWindow();211212/// Renders the leaderboard list.213void DrawLeaderboardsWindow();214215#endif // __ANDROID__216217} // namespace Achievements218219/// Functions implemented in the frontend.220namespace Host {221222/// Called if the big picture UI requests achievements login, or token login fails.223void OnAchievementsLoginRequested(Achievements::LoginRequestReason reason);224225/// Called when achievements login completes.226void OnAchievementsLoginSuccess(const char* display_name, u32 points, u32 sc_points, u32 unread_messages);227228/// Called whenever game details or rich presence information is updated.229/// Implementers can assume the lock is held when this is called.230void OnAchievementsRefreshed();231232/// Called when achievements login completes or they are disabled.233void OnAchievementsActiveChanged(bool active);234235/// Called whenever hardcore mode is toggled.236void OnAchievementsHardcoreModeChanged(bool enabled);237238/// Called whenever all progress is manually refreshed and completed.239void OnAchievementsAllProgressRefreshed();240241#ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION242243/// Called when the RAIntegration menu changes.244void OnRAIntegrationMenuChanged();245246#endif247248} // namespace Host249250251