Etterna 0.75.1
Loading...
Searching...
No Matches
ScoreManager.h
1#ifndef ScoreManager_H
2#define ScoreManager_H
3
4#include "Etterna/Models/Misc/GameConstantsAndTypes.h"
5#include "Etterna/Models/Misc/Grade.h"
6#include "PrefsManager.h"
7#include "SongManager.h"
8#include "ProfileManager.h"
9
10#include <map>
11#include <string>
12#include <unordered_map>
13
14// Scores for a specific rate for a specific chart
16{
17 public:
19
20 HighScore* PBptr;
21 HighScore* noccPBptr;
22
23 // -technically- your pb could be a fail grade so use "bestgrade" -mina
24 Grade bestGrade;
25 float bestWifeScore = 0.F;
26
27 auto AddScore(HighScore& hs) -> HighScore*;
28
29 [[nodiscard]] auto GetSortedKeys() const -> const std::vector<std::string>;
30 void PushSelf(lua_State* L);
31
32 auto HandleNoCCPB(HighScore& hs) -> bool;
33
34 [[nodiscard]] auto CreateNode(const int& rate) const -> XNode*;
35 void LoadFromNode(const XNode* node,
36 const std::string& ck,
37 const float& rate,
38 const std::string& profileID);
39
40 auto GetAllScores() -> const std::vector<HighScore*>;
41 std::unordered_map<std::string, HighScore> scores;
42};
43
44// All scores for a specific chart
46{
47 public:
49
50 Grade bestGrade = Grade_Invalid; // best grade for any rate
51 float bestWifeScore = 0.F;
52
53 auto GetPBAt(float rate) -> HighScore*;
54 auto GetPBUpTo(float rate) -> HighScore*;
55 auto GetAllPBPtrs() -> const std::vector<HighScore*>;
56
57 auto AddScore(HighScore& hs) -> HighScore*;
58
59 [[nodiscard]] auto GetPlayedRates() const -> const std::vector<float>;
60 [[nodiscard]] auto GetPlayedRateKeys() const -> const std::vector<int>;
61 [[nodiscard]] auto GetPlayedRateDisplayStrings() const
62 -> const std::vector<std::string>;
63
64 void PushSelf(lua_State* L);
65
66 Chart ch;
67
68 auto GetScoresAtRate(const int& rate) -> ScoresAtRate*;
69 auto GetAllScores() -> const std::vector<HighScore*>;
70 [[nodiscard]] auto CreateNode(const std::string& ck) const -> XNode*;
71 void LoadFromNode(const XNode* node,
72 const std::string& ck,
73 const std::string& profileID);
74
75 auto operator[](const int rate) -> ScoresAtRate
76 {
77 return ScoresByRate.at(rate);
78 }
79
80 // Sets rate indepdendent topscore tags inside highscores. 1 = best. 2 =
81 // 2nd. 0 = the rest. -mina
82 void SetTopScores();
83 auto GetTopScoresForUploading() -> const std::vector<HighScore*>;
84
85 [[nodiscard]] auto GetNumScores() const -> int
86 {
87 return ScoresByRate.size();
88 }
89
90 /* It makes sense internally to have the map keys sorted highest rate to
91 lowest however my experience in lua is that it tends to be more friendly
92 to approach things in the reverse -mina */
93 std::map<int, ScoresAtRate, std::greater<>> ScoresByRate;
94
95 [[nodiscard]] static auto RateToKey(float rate) -> int
96 {
97 return lround(rate * 10000.F);
98 }
99
100 [[nodiscard]] static auto KeyToRate(int key) -> float
101 {
102 return static_cast<float>(key) / 10000.F;
103 }
104};
105
107{
108 public:
109 ScoreManager();
111
112 auto GetAllPBPtrs(const std::string& profileID =
113 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID)
114 -> const std::vector<vector<HighScore*>>;
115 auto GetAllPBsPreferringReplays(
116 const std::string& profileID =
117 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID)
118 -> std::vector<HighScore*>;
119
120 auto GetChartPBAt(const std::string& ck,
121 float rate,
122 const std::string& profileID =
123 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID)
124 -> HighScore*;
125
126 // technically "up to and including rate: x" but that's a mouthful -mina
127 // HighScore* GetChartPBUpTo(const std::string& ck, float& rate);
128 auto GetChartPBUpTo(const std::string& ck,
129 float rate,
130 const std::string& profileID =
131 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID)
132 -> HighScore*;
133
134 [[nodiscard]] auto GetBestGradeFor(
135 const std::string& ck,
136 const std::string& profileID =
137 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID) const -> Grade
138 {
139 if (KeyHasScores(ck, profileID)) {
140 return pscores.at(profileID).at(ck).bestGrade;
141 }
142
143 return Grade_Invalid;
144 }
145
146 [[nodiscard]] auto GetBestWifeScoreFor(
147 const std::string& ck,
148 const std::string& profileID =
149 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID) const -> float
150 {
151 if (KeyHasScores(ck, profileID)) {
152 return pscores.at(profileID).at(ck).bestWifeScore;
153 }
154
155 return 0.F;
156 }
157
158 // for scores achieved during this session
159 // now returns top score status because i'm bad at coding --lurker
160 auto AddScore(const HighScore& hs_,
161 const std::string& profileID =
162 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID) -> int
163 {
164 HighScore hs = hs_;
165 HighScore* h = pscores[profileID][hs.GetChartKey()].AddScore(hs);
166 RegisterScoreThisSession(h);
167 RegisterScoreInProfile(h, profileID);
168 return hs.GetTopScore();
169 }
170
171 void ImportScore(const HighScore& hs_,
172 const std::string& profileID =
173 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID);
174
175 // don't save scores under this percentage
176 const float minpercent = PREFSMAN->m_fMinPercentToSaveScores;
177
178 // Player Rating and SSR functions
179 std::vector<float> SortTopSSRPtrs(
180 Skillset ss,
181 const std::string& profileID =
182 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID,
183 bool getSSRs = false);
184 std::map<DateTime, std::vector<float>> GetPlayerRatingOverTime(
185 const std::string& profileID =
186 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID);
187 void SortTopSSRPtrsForGame(
188 Skillset ss,
189 const std::string& profileID =
190 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID);
191 void RecalculateSSRs(LoadingWindow* ld);
192 void RecalculateSSRs(const std::string& profileID);
193 void UnInvalidateAllScores(const std::string& profileID);
194 void CalcPlayerRating(float& prating,
195 float* pskillsets,
196 const std::string& profileID);
197
198 auto GetTopSSRValue(unsigned int rank, int ss) -> float;
199
200 void SortTopSSRPtrsByPercent(
201 const std::string& profileID =
202 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID);
203 void SortTopSSRPtrsByPercentForGame(
204 const std::string& profileID =
205 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID);
206 auto GetTopSSRHighScore(unsigned int rank, int ss) -> HighScore*;
207 auto GetTopSSRHighScoreForGame(unsigned int rank, int ss) -> HighScore*;
208 auto GetRecentScore(int rank) -> HighScore*;
209 auto GetRecentScoreForGame(int rank) -> HighScore*;
210 void SortRecentScores(const std::string& profileID =
211 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID);
212 void SortRecentScoresForGame(
213 const std::string& profileID =
214 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID);
215
216 [[nodiscard]] auto KeyHasScores(
217 const std::string& ck,
218 const std::string& profileID =
219 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID) const -> bool
220 {
221 return pscores.count(profileID) == 1 && pscores.at(profileID).count(ck) == 1;
222 }
223 [[nodiscard]] auto HasAnyScores() const -> bool
224 {
225 return !AllScores.empty();
226 }
227
228 [[nodiscard]] auto CreateNode(
229 const std::string& profileID =
230 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID) const -> XNode*;
231 void LoadFromNode(const XNode* node,
232 const std::string& profileID =
233 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID);
234
235 auto GetScoresForChart(const std::string& ck,
236 const std::string& profileID =
237 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID)
238 -> ScoresForChart*;
239 auto GetSortedKeys() -> const std::vector<std::string>;
240
241 void PushSelf(lua_State* L);
242 auto GetMostRecentScore() -> HighScore*
243 {
244 if (camefromreplay) {
245 ASSERT_M(tempscoreforonlinereplayviewing != nullptr,
246 "Temp score for Replay & Practice viewing was empty.");
247 return tempscoreforonlinereplayviewing;
248 }
249 // Allow Lua to receive null HS here
250 if (AllScores.empty())
251 return nullptr;
252 return AllScores.back();
253 }
254 void PutScoreAtTheTop(const std::string& scorekey)
255 {
256 auto score = ScoresByKey[scorekey];
257 std::swap(score, AllScores.back());
258 }
259 auto GetAllScores() -> const std::vector<HighScore*>& { return AllScores; }
260 auto GetScoresByKey() -> const std::unordered_map<std::string, HighScore*>&
261 {
262 return ScoresByKey;
263 }
264 auto GetAllProfileScores(const std::string& profileID =
265 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID)
266 -> const std::vector<HighScore*>&
267 {
268 return AllProfileScores[profileID];
269 }
270 void RegisterScore(HighScore* hs) { AllScores.emplace_back(hs); }
271 void AddToKeyedIndex(HighScore* hs)
272 {
273 ScoresByKey.emplace(hs->GetScoreKey(), hs);
274 }
275 void RegisterScoreInProfile(HighScore* hs_, const std::string& profileID);
276
277 // return all skillsets ordered by number of plays
278 std::vector<Skillset> GetTopPlayedSkillsets(
279 const std::string& profileID = PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID);
280
281 std::vector<int> GetPlaycountPerSkillset(
282 const std::string& profileID = PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID);
283
284 void SetAllTopScores(const std::string& profileID =
285 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID);
286 void PurgeScores();
287 auto GetProfileScores(const std::string& profileID =
288 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID)
289 -> std::unordered_map<std::string, ScoresForChart>*
290 {
291 return &(pscores[profileID]);
292 };
293
294 void PurgeProfileScores(const std::string& profileID =
295 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID);
296 void UnloadAllReplayData()
297 {
298 for (auto& s : AllScores) {
299 if (s->replay != nullptr &&
300 s->replay->GetReplayType() != ReplayType_Invalid)
301 s->UnloadReplayData();
302 }
303 }
304 bool camefromreplay = false;
305 HighScore* tempscoreforonlinereplayviewing;
306 std::vector<HighScore*> scorestorecalc;
307
308 // probably can avoid copying strings if we're sure it's safe
309 std::set<HighScore*> rescores;
310
311 auto GetNumScoresThisSession() -> int
312 {
313 return scoresThisSession.size();
314 }
315 auto GetScoresThisSession() -> std::vector<HighScore*>
316 {
317 return scoresThisSession;
318 }
319 void RegisterScoreThisSession(HighScore* hs)
320 {
321 scoresThisSession.push_back(hs);
322 }
323
324 private:
325 std::unordered_map<std::string,
326 std::unordered_map<std::string, ScoresForChart>>
327 pscores; // Profile scores
328
329 // Instead of storing pointers for each skillset just reshuffle the same set
330 // of pointers it's inexpensive and not called often
331 std::vector<HighScore*> TopSSRs;
332 std::vector<HighScore*> TopSSRsForGame;
333 std::vector<HighScore*> AllScores;
334 std::unordered_map<std::string, std::vector<HighScore*>> AllProfileScores;
335
336 // pointers in a keyed index (by scorekey, in case it's not immediately
337 // obvious)
338 std::unordered_map<std::string, HighScore*> ScoresByKey;
339
340 // a more thought out (not really) replacement for STATSMAN played stage stats
341 // note: scoresThisSession is NOT meant to reset on profile load
342 // (design choice)
343 std::vector<HighScore*> scoresThisSession;
344};
345
346extern ScoreManager* SCOREMAN;
347
348#endif
Opens and displays the loading banner.
Definition LoadingWindow.h:9
Definition ScoreManager.h:107
Definition XmlFile.h:95
Definition Difficulty.h:44
The high score that is earned by a player.
Definition HighScore.h:18
Definition ScoreManager.h:16
Definition ScoreManager.h:46