Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/src/core/achievements.h
4802 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);
68
std::optional<GameHash> GetGameHash(const std::string_view executable_name, std::span<const u8> executable_data);
69
70
/// Returns the number of achievements for a given hash.
71
const HashDatabaseEntry* LookupGameHash(const GameHash& hash);
72
73
/// Initializes the RetroAchievments client.
74
bool Initialize();
75
76
/// Updates achievements settings.
77
void UpdateSettings(const Settings& old_config);
78
79
/// Shuts down the RetroAchievements client.
80
void Shutdown();
81
82
/// Call to refresh the all-progress database.
83
bool RefreshAllProgressDatabase(Error* error);
84
85
/// Called when the system is start. Engages hardcore mode if enabled.
86
void OnSystemStarting(CDImage* image, bool disable_hardcore_mode);
87
88
/// Called when the system is shutting down. If this returns false, the shutdown should be aborted.
89
void OnSystemDestroyed();
90
91
/// Called when the system is being reset. Resets the internal state of all achievement tracking.
92
void OnSystemReset();
93
94
/// Called when the system changes game.
95
void GameChanged(CDImage* image);
96
97
/// Called once a frame at vsync time on the CPU thread.
98
void FrameUpdate();
99
100
/// Called when the system is paused, because FrameUpdate() won't be getting called.
101
void IdleUpdate();
102
103
/// Returns true if idle updates are necessary (e.g. outstanding requests).
104
bool NeedsIdleUpdate();
105
106
/// Saves/loads state.
107
bool DoState(StateWrapper& sw);
108
109
/// 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.
111
bool Login(const char* username, const char* password, Error* error);
112
113
/// Logs out of RetroAchievements, clearing any credentials.
114
void Logout();
115
116
/// Forces hardcore mode off until next reset.
117
void DisableHardcoreMode(bool show_message, bool display_game_summary);
118
119
/// Prompts the user to disable hardcore mode, if they agree, returns true.
120
bool ConfirmHardcoreModeDisable(const char* trigger);
121
void ConfirmHardcoreModeDisableAsync(const char* trigger, std::function<void(bool)> callback);
122
123
/// Returns true if hardcore mode is active, and functionality should be restricted.
124
bool IsHardcoreModeActive();
125
126
/// RAIntegration only exists for Windows, so no point checking it on other platforms.
127
bool IsUsingRAIntegration();
128
bool IsRAIntegrationAvailable();
129
130
/// Returns true if the achievement system is active. Achievements can be active without a valid client.
131
bool IsActive();
132
133
/// Returns true if RetroAchievements game data has been loaded.
134
bool HasActiveGame();
135
136
/// Returns the RetroAchievements ID for the current game.
137
u32 GetGameID();
138
139
/// Returns true if the current game has any achievements or leaderboards.
140
bool HasAchievementsOrLeaderboards();
141
142
/// Returns true if the current game has any leaderboards.
143
bool HasAchievements();
144
145
/// Returns true if the current game has any leaderboards.
146
bool HasLeaderboards();
147
148
/// Returns true if the game supports rich presence.
149
bool HasRichPresence();
150
151
/// Returns the current rich presence string.
152
/// Should be called with the lock held.
153
const std::string& GetRichPresenceString();
154
155
/// Returns the URL for the current icon of the game
156
const std::string& GetGameIconURL();
157
158
/// Returns the path for the current icon of the game
159
const std::string& GetGameIconPath();
160
161
/// Returns the RetroAchievements title for the current game.
162
/// Should be called with the lock held.
163
const std::string& GetGameTitle();
164
165
/// Returns the path for the game that is current hashed/running.
166
const std::string& GetGamePath();
167
168
/// Returns true if the user has been successfully logged in.
169
bool IsLoggedIn();
170
171
/// Returns true if the user has been successfully logged in, or the request is in progress.
172
bool IsLoggedInOrLoggingIn();
173
174
/// Returns the logged-in user name.
175
const char* GetLoggedInUserName();
176
177
/// Returns the path to the user's profile avatar.
178
/// Should be called with the lock held.
179
std::string GetLoggedInUserBadgePath();
180
181
/// Returns a summary of the user's points.
182
/// Should be called with the lock held.
183
SmallString GetLoggedInUserPointsSummary();
184
185
/// Returns 0 if pausing is allowed, otherwise the number of frames until pausing is allowed.
186
u32 GetPauseThrottleFrames();
187
188
/// Clears all cached state used to render the UI.
189
void ClearUIState();
190
191
/// Draws ImGui overlays when not paused.
192
void DrawGameOverlays();
193
194
/// Draws ImGui overlays when paused.
195
void DrawPauseMenuOverlays(float start_pos_y);
196
197
/// Updates the stored most-recent and closest-to-completion achievements.
198
/// Call before calling DrawPauseMenuOverlays() for the first time.
199
void UpdateRecentUnlockAndAlmostThere();
200
201
#ifndef __ANDROID__
202
203
/// Queries the achievement list, and if no achievements are available, returns false.
204
bool PrepareAchievementsWindow();
205
206
/// Renders the achievement list.
207
void DrawAchievementsWindow();
208
209
/// Queries the leaderboard list, and if no leaderboards are available, returns false.
210
bool PrepareLeaderboardsWindow();
211
212
/// Renders the leaderboard list.
213
void DrawLeaderboardsWindow();
214
215
#endif // __ANDROID__
216
217
} // namespace Achievements
218
219
/// Functions implemented in the frontend.
220
namespace Host {
221
222
/// Called if the big picture UI requests achievements login, or token login fails.
223
void OnAchievementsLoginRequested(Achievements::LoginRequestReason reason);
224
225
/// Called when achievements login completes.
226
void OnAchievementsLoginSuccess(const char* display_name, u32 points, u32 sc_points, u32 unread_messages);
227
228
/// Called whenever game details or rich presence information is updated.
229
/// Implementers can assume the lock is held when this is called.
230
void OnAchievementsRefreshed();
231
232
/// Called when achievements login completes or they are disabled.
233
void OnAchievementsActiveChanged(bool active);
234
235
/// Called whenever hardcore mode is toggled.
236
void OnAchievementsHardcoreModeChanged(bool enabled);
237
238
/// Called whenever all progress is manually refreshed and completed.
239
void OnAchievementsAllProgressRefreshed();
240
241
#ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION
242
243
/// Called when the RAIntegration menu changes.
244
void OnRAIntegrationMenuChanged();
245
246
#endif
247
248
} // namespace Host
249
250