Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/src/core/achievements.h
4208 views
1
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <[email protected]>
2
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
3
4
#pragma once
5
6
#include "common/small_string.h"
7
#include "common/types.h"
8
9
#include <array>
10
#include <functional>
11
#include <mutex>
12
#include <optional>
13
#include <span>
14
#include <string>
15
#include <utility>
16
#include <vector>
17
18
class Error;
19
class StateWrapper;
20
class CDImage;
21
22
struct Settings;
23
24
namespace Achievements {
25
26
enum class LoginRequestReason
27
{
28
UserInitiated,
29
TokenInvalid,
30
};
31
32
inline constexpr size_t GAME_HASH_LENGTH = 16;
33
using GameHash = std::array<u8, GAME_HASH_LENGTH>;
34
35
struct HashDatabaseEntry
36
{
37
GameHash hash;
38
u32 game_id;
39
u32 num_achievements;
40
};
41
42
class ProgressDatabase
43
{
44
public:
45
struct Entry
46
{
47
u32 game_id;
48
u16 num_achievements_unlocked;
49
u16 num_hc_achievements_unlocked;
50
};
51
52
ProgressDatabase();
53
~ProgressDatabase();
54
55
bool Load(Error* error);
56
57
const Entry* LookupGame(u32 game_id) const;
58
59
private:
60
std::vector<Entry> m_entries;
61
};
62
63
/// Acquires the achievements lock. Must be held when accessing any achievement state from another thread.
64
std::unique_lock<std::recursive_mutex> GetLock();
65
66
/// Returns the achievements game hash for a given disc.
67
std::optional<GameHash> GetGameHash(CDImage* image, u32* bytes_hashed = nullptr);
68
std::optional<GameHash> GetGameHash(const std::string_view executable_name, std::span<const u8> executable_data,
69
u32* bytes_hashed = nullptr);
70
71
/// Returns the number of achievements for a given hash.
72
const HashDatabaseEntry* LookupGameHash(const GameHash& hash);
73
74
/// Initializes the RetroAchievments client.
75
bool Initialize();
76
77
/// Updates achievements settings.
78
void UpdateSettings(const Settings& old_config);
79
80
/// Shuts down the RetroAchievements client.
81
void Shutdown();
82
83
/// Call to refresh the all-progress database.
84
bool RefreshAllProgressDatabase(Error* error);
85
86
/// Called when the system is start. Engages hardcore mode if enabled.
87
void OnSystemStarting(CDImage* image, bool disable_hardcore_mode);
88
89
/// Called when the system is shutting down. If this returns false, the shutdown should be aborted.
90
void OnSystemDestroyed();
91
92
/// Called when the system is being reset. Resets the internal state of all achievement tracking.
93
void OnSystemReset();
94
95
/// Called when the system changes game.
96
void GameChanged(CDImage* image);
97
98
/// Called once a frame at vsync time on the CPU thread.
99
void FrameUpdate();
100
101
/// Called when the system is paused, because FrameUpdate() won't be getting called.
102
void IdleUpdate();
103
104
/// Returns true if idle updates are necessary (e.g. outstanding requests).
105
bool NeedsIdleUpdate();
106
107
/// Saves/loads state.
108
bool DoState(StateWrapper& sw);
109
110
/// Attempts to log in to RetroAchievements using the specified credentials.
111
/// If the login is successful, the token returned by the server will be saved.
112
bool Login(const char* username, const char* password, Error* error);
113
114
/// Logs out of RetroAchievements, clearing any credentials.
115
void Logout();
116
117
/// Forces hardcore mode off until next reset.
118
void DisableHardcoreMode(bool show_message, bool display_game_summary);
119
120
/// Prompts the user to disable hardcore mode, if they agree, returns true.
121
bool ConfirmHardcoreModeDisable(const char* trigger);
122
void ConfirmHardcoreModeDisableAsync(const char* trigger, std::function<void(bool)> callback);
123
124
/// Returns true if hardcore mode is active, and functionality should be restricted.
125
bool IsHardcoreModeActive();
126
127
/// RAIntegration only exists for Windows, so no point checking it on other platforms.
128
bool IsUsingRAIntegration();
129
bool IsRAIntegrationAvailable();
130
131
/// Returns true if the achievement system is active. Achievements can be active without a valid client.
132
bool IsActive();
133
134
/// Returns true if RetroAchievements game data has been loaded.
135
bool HasActiveGame();
136
137
/// Returns the RetroAchievements ID for the current game.
138
u32 GetGameID();
139
140
/// Returns true if the current game has any achievements or leaderboards.
141
bool HasAchievementsOrLeaderboards();
142
143
/// Returns true if the current game has any leaderboards.
144
bool HasAchievements();
145
146
/// Returns true if the current game has any leaderboards.
147
bool HasLeaderboards();
148
149
/// Returns true if the game supports rich presence.
150
bool HasRichPresence();
151
152
/// Returns the current rich presence string.
153
/// Should be called with the lock held.
154
const std::string& GetRichPresenceString();
155
156
/// Returns the URL for the current icon of the game
157
const std::string& GetGameIconURL();
158
159
/// Returns the path for the current icon of the game
160
const std::string& GetGameIconPath();
161
162
/// Returns the RetroAchievements title for the current game.
163
/// Should be called with the lock held.
164
const std::string& GetGameTitle();
165
166
/// Returns the path for the game that is current hashed/running.
167
const std::string& GetGamePath();
168
169
/// Returns true if the user has been successfully logged in.
170
bool IsLoggedIn();
171
172
/// Returns true if the user has been successfully logged in, or the request is in progress.
173
bool IsLoggedInOrLoggingIn();
174
175
/// Returns the logged-in user name.
176
const char* GetLoggedInUserName();
177
178
/// Returns the path to the user's profile avatar.
179
/// Should be called with the lock held.
180
std::string GetLoggedInUserBadgePath();
181
182
/// Returns a summary of the user's points.
183
/// Should be called with the lock held.
184
SmallString GetLoggedInUserPointsSummary();
185
186
/// Returns 0 if pausing is allowed, otherwise the number of frames until pausing is allowed.
187
u32 GetPauseThrottleFrames();
188
189
/// Clears all cached state used to render the UI.
190
void ClearUIState();
191
192
/// Draws ImGui overlays when not paused.
193
void DrawGameOverlays();
194
195
/// Draws ImGui overlays when paused.
196
void DrawPauseMenuOverlays(float start_pos_y);
197
198
/// Updates the stored most-recent and closest-to-completion achievements.
199
/// Call before calling DrawPauseMenuOverlays() for the first time.
200
void UpdateRecentUnlockAndAlmostThere();
201
202
#ifndef __ANDROID__
203
204
/// Queries the achievement list, and if no achievements are available, returns false.
205
bool PrepareAchievementsWindow();
206
207
/// Renders the achievement list.
208
void DrawAchievementsWindow();
209
210
/// Queries the leaderboard list, and if no leaderboards are available, returns false.
211
bool PrepareLeaderboardsWindow();
212
213
/// Renders the leaderboard list.
214
void DrawLeaderboardsWindow();
215
216
#endif // __ANDROID__
217
218
} // namespace Achievements
219
220
/// Functions implemented in the frontend.
221
namespace Host {
222
223
/// Called if the big picture UI requests achievements login, or token login fails.
224
void OnAchievementsLoginRequested(Achievements::LoginRequestReason reason);
225
226
/// Called when achievements login completes.
227
void OnAchievementsLoginSuccess(const char* display_name, u32 points, u32 sc_points, u32 unread_messages);
228
229
/// Called whenever game details or rich presence information is updated.
230
/// Implementers can assume the lock is held when this is called.
231
void OnAchievementsRefreshed();
232
233
/// Called when achievements login completes or they are disabled.
234
void OnAchievementsActiveChanged(bool active);
235
236
/// Called whenever hardcore mode is toggled.
237
void OnAchievementsHardcoreModeChanged(bool enabled);
238
239
/// Called whenever all progress is manually refreshed and completed.
240
void OnAchievementsAllProgressRefreshed();
241
242
#ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION
243
244
/// Called when the RAIntegration menu changes.
245
void OnRAIntegrationMenuChanged();
246
247
#endif
248
249
} // namespace Host
250
251