Etterna 0.74.4
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 auto GetTopSSRHighScore(unsigned int rank, int ss) -> HighScore*;
201 auto GetTopSSRHighScoreForGame(unsigned int rank, int ss) -> HighScore*;
202 auto GetRecentScore(int rank) -> HighScore*;
203 auto GetRecentScoreForGame(int rank) -> HighScore*;
204 void SortRecentScores(const std::string& profileID =
205 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID);
206 void SortRecentScoresForGame(
207 const std::string& profileID =
208 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID);
209
210 [[nodiscard]] auto KeyHasScores(
211 const std::string& ck,
212 const std::string& profileID =
213 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID) const -> bool
214 {
215 return pscores.count(profileID) == 1 && pscores.at(profileID).count(ck) == 1;
216 }
217 [[nodiscard]] auto HasAnyScores() const -> bool
218 {
219 return !AllScores.empty();
220 }
221
222 [[nodiscard]] auto CreateNode(
223 const std::string& profileID =
224 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID) const -> XNode*;
225 void LoadFromNode(const XNode* node,
226 const std::string& profileID =
227 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID);
228
229 auto GetScoresForChart(const std::string& ck,
230 const std::string& profileID =
231 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID)
232 -> ScoresForChart*;
233 auto GetSortedKeys() -> const std::vector<std::string>;
234
235 void PushSelf(lua_State* L);
236 auto GetMostRecentScore() -> HighScore*
237 {
238 if (camefromreplay) {
239 ASSERT_M(tempscoreforonlinereplayviewing != nullptr,
240 "Temp score for Replay & Practice viewing was empty.");
241 return tempscoreforonlinereplayviewing;
242 }
243 // Allow Lua to receive null HS here
244 if (AllScores.empty())
245 return nullptr;
246 return AllScores.back();
247 }
248 void PutScoreAtTheTop(const std::string& scorekey)
249 {
250 auto score = ScoresByKey[scorekey];
251 std::swap(score, AllScores.back());
252 }
253 auto GetAllScores() -> const std::vector<HighScore*>& { return AllScores; }
254 auto GetScoresByKey() -> const std::unordered_map<std::string, HighScore*>&
255 {
256 return ScoresByKey;
257 }
258 auto GetAllProfileScores(const std::string& profileID =
259 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID)
260 -> const std::vector<HighScore*>&
261 {
262 return AllProfileScores[profileID];
263 }
264 void RegisterScore(HighScore* hs) { AllScores.emplace_back(hs); }
265 void AddToKeyedIndex(HighScore* hs)
266 {
267 ScoresByKey.emplace(hs->GetScoreKey(), hs);
268 }
269 void RegisterScoreInProfile(HighScore* hs_, const std::string& profileID);
270
271 // return all skillsets ordered by number of plays
272 std::vector<Skillset> GetTopPlayedSkillsets(
273 const std::string& profileID = PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID);
274
275 std::vector<int> GetPlaycountPerSkillset(
276 const std::string& profileID = PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID);
277
278 void SetAllTopScores(const std::string& profileID =
279 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID);
280 void PurgeScores();
281 auto GetProfileScores(const std::string& profileID =
282 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID)
283 -> std::unordered_map<std::string, ScoresForChart>*
284 {
285 return &(pscores[profileID]);
286 };
287
288 void PurgeProfileScores(const std::string& profileID =
289 PROFILEMAN->GetProfile(PLAYER_1)->m_sProfileID);
290 void UnloadAllReplayData()
291 {
292 for (auto& s : AllScores) {
293 if (s->replay != nullptr &&
294 s->replay->GetReplayType() != ReplayType_Invalid)
295 s->UnloadReplayData();
296 }
297 }
298 bool camefromreplay = false;
299 HighScore* tempscoreforonlinereplayviewing;
300 std::vector<HighScore*> scorestorecalc;
301
302 // probably can avoid copying strings if we're sure it's safe
303 std::set<HighScore*> rescores;
304
305 auto GetNumScoresThisSession() -> int
306 {
307 return scoresThisSession.size();
308 }
309 auto GetScoresThisSession() -> std::vector<HighScore*>
310 {
311 return scoresThisSession;
312 }
313 void RegisterScoreThisSession(HighScore* hs)
314 {
315 scoresThisSession.push_back(hs);
316 }
317
318 private:
319 std::unordered_map<std::string,
320 std::unordered_map<std::string, ScoresForChart>>
321 pscores; // Profile scores
322
323 // Instead of storing pointers for each skillset just reshuffle the same set
324 // of pointers it's inexpensive and not called often
325 std::vector<HighScore*> TopSSRs;
326 std::vector<HighScore*> TopSSRsForGame;
327 std::vector<HighScore*> AllScores;
328 std::unordered_map<std::string, std::vector<HighScore*>> AllProfileScores;
329
330 // pointers in a keyed index (by scorekey, in case it's not immediately
331 // obvious)
332 std::unordered_map<std::string, HighScore*> ScoresByKey;
333
334 // a more thought out (not really) replacement for STATSMAN played stage stats
335 // note: scoresThisSession is NOT meant to reset on profile load
336 // (design choice)
337 std::vector<HighScore*> scoresThisSession;
338};
339
340extern ScoreManager* SCOREMAN;
341
342#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