159 std::set<std::string>& tagFilters,
162 const std::string& sortByField,
186 return key == other.key;
192 int totalEntries = 0;
193 std::vector<DownloadablePack*> results{};
196 bool pendingRequest =
false;
199 bool noResults =
false;
201 bool initialized =
false;
203 void initialize(
LuaReference& whenDone = EMPTY_REFERENCE) {
204 setPage(0, whenDone);
208 std::vector<DownloadablePack*> get() {
209 auto it = results.begin();
210 if (results.size() > currentPageStartIndex()) {
212 it += currentPageStartIndex();
215 std::vector<DownloadablePack*> o{};
217 while (it != results.end()) {
225 std::vector<DownloadablePack*> getCache() {
return results; }
231 setPage(getNextPageNbr(), whenDone);
237 setPage(getPrevPageNbr(), whenDone);
241 int getTotalPages() {
242 return static_cast<int>(ceilf(
static_cast<float>(totalEntries) /
243 static_cast<float>(key.perPage)));
247 void PushSelf(lua_State* L);
253 std::set<int> finishedPageRequests{};
256 int currentPageStartIndex() {
257 return key.perPage * currentPage;
260 int getNextPageNbr() {
261 if (key.perPage >= totalEntries) {
264 if (currentPage == getTotalPages() - 1) {
267 return currentPage + 1;
270 int getPrevPageNbr() {
271 if (key.perPage >= totalEntries) {
274 if (currentPage == 0) {
275 return getTotalPages() - 1;
277 return currentPage - 1;
282 void setPage(
int page,
LuaReference& whenDone = EMPTY_REFERENCE);
284 bool mustRequestPage(
int page) {
285 const auto ind = key.perPage * page;
286 if (results.size() <= ind) {
291 return results.at(ind) ==
nullptr;
461 void Update(
float fDeltaSeconds);
462 void UpdatePacks(
float fDeltaSeconds);
463 void UpdateHTTP(
float fDeltaSeconds);
464 void UpdateGameplayState(
bool gameplay);
468 void PushSelf(lua_State* L);
473 bool ShouldUploadScores();
474 bool InGameplay() {
return gameplay; }
479 const std::string& username,
480 const std::string& password,
481 std::function<
void(
bool)> done = [](
bool loggedIn) {})
483 LoginRequest(username, password, done);
486 const std::string& sessionToken,
487 std::function<
void(
bool)> done = [](
bool loggedIn) {});
489 void LogoutIfLoggedIn()
495 void GetRankedChartkeys(
496 std::function<
void(
void)> callback = []() {},
497 const DateTime start = DateTime::GetFromString(
"1990-01-01 12:00:00"),
498 const DateTime end = DateTime::GetFromString(
"2100-01-01 12:00:00"))
500 GetRankedChartkeysRequest(callback, start, end);
502 void AddFavorite(
const std::string& chartKey)
504 AddFavoriteRequest(chartKey);
506 void BulkAddFavorites(
507 std::vector<std::string> chartKeys,
508 std::function<
void()> = []() {});
509 void RemoveFavorite(
const std::string& chartKey)
511 RemoveFavoriteRequest(chartKey);
513 void RefreshFavorites(
514 const DateTime start = DateTime::GetFromString(
"1990-01-01 12:00:00"),
515 const DateTime end = DateTime::GetFromString(
"2100-01-01 12:00:00"));
517 AddGoalRequest(goal);
520 std::vector<ScoreGoal*> goals,
521 std::function<
void()> callback = []() {});
523 UpdateGoalRequest(goal);
525 void RemoveGoal(
ScoreGoal* goal,
bool oldGoal =
false) {
526 RemoveGoalRequest(goal, oldGoal);
529 const DateTime start = DateTime::GetFromString(
"1990-01-01 12:00:00"),
530 const DateTime end = DateTime::GetFromString(
"2100-01-01 12:00:00"));
531 void AddPlaylist(
const std::string& name) {
532 AddPlaylistRequest(name);
534 void UpdatePlaylist(
const std::string& name)
536 UpdatePlaylistRequest(name);
538 void RemovePlaylist(
const std::string& name)
540 RemovePlaylistRequest(name);
544 const DateTime start = DateTime::GetFromString(
"1990-01-01 12:00:00"),
545 const DateTime end = DateTime::GetFromString(
"2100-01-01 12:00:00"));
546 void DownloadMissingPlaylists(
547 const DateTime start = DateTime::GetFromString(
"1990-01-01 12:00:00"),
548 const DateTime end = DateTime::GetFromString(
"2100-01-01 12:00:00"));
549 void DownloadPlaylist(
const std::string& name);
553 std::function<
void()> callback,
554 bool load_from_disk);
555 void UploadScoreWithReplayData(
HighScore* hs);
556 void UploadScoreWithReplayDataFromDisk(
558 std::function<
void()> callback = []() {});
559 void UploadBulkScores(
560 std::vector<HighScore*> hsList,
561 std::function<
void()> callback = []() {});
563 void RefreshPackTags();
565 std::function<
void(rapidjson::Document&)> packSearchParser)
567 MultiSearchRequest(searchCriteria, packSearchParser);
571 bool ForceUploadPBsForChart(
const std::string& ck,
bool startNow =
false);
572 bool ForceUploadPBsForPack(
const std::string& pack,
bool startNow =
false);
573 bool ForceUploadAllPBs();
574 bool InitialScoreSync();
576 void GetChartLeaderboard(
const std::string& chartkey,
579 GetChartLeaderboardRequest(chartkey, ref);
581 void GetReplayData(
const std::string& scorekey,
583 const std::string& username,
584 const std::string& chartkey,
587 GetReplayDataRequest(scorekey, userid, username, chartkey, callback);
593 float GetSkillsetRating(Skillset ss);
594 int GetSkillsetRank(Skillset ss);
597 const std::string& searchString,
598 std::set<std::string> tagFilters,
601 const std::string& sortBy,
603 std::shared_ptr<Download> DownloadAndInstallPack(
const std::string& url,
604 std::string filename =
"");
606 bool mirror =
false);
608 void DownloadCoreBundle(
const std::string& bundlename,
bool mirror =
false);
609 std::vector<DownloadablePack*> GetCoreBundle(
const std::string& bundlename);
611 bool OpenSitePage(
const std::string& path);
612 bool OpenProjectPage(
const std::string& path);
614 bool ShowPackPage(
int packid) {
615 return OpenSitePage(fmt::format(
"/packs/{}", packid));
617 bool ShowUserPage(
const std::string& username){
618 return OpenSitePage(fmt::format(
"/users/{}", username));
620 bool ShowScorePage(
const std::string& username,
int scoreid)
623 fmt::format(
"/users/{}/scores/{}", username, scoreid));
625 bool ShowBugReportSite();
626 bool ShowEditorSite();
627 bool ShowProjectReleases() {
628 return OpenProjectPage(
"/releases");
630 bool ShowProjectSite() {
631 return OpenProjectPage(
"");
637 std::string authToken{
"" };
639 std::string sessionUser{
"" };
641 std::map<Skillset, int> sessionRanks{};
643 std::map<Skillset, double> sessionRatings{};
647 std::deque<HighScore*> ScoreUploadSequentialQueue;
648 unsigned int sequentialScoreUploadTotalWorkload{ 0 };
652 std::deque<ScoreGoal*> GoalUploadSequentialQueue;
653 unsigned int sequentialGoalUploadTotalWorkload{ 0 };
657 std::deque<std::string> FavoriteUploadSequentialQueue;
658 unsigned int sequentialFavoriteUploadTotalWorkload{ 0 };
663 std::map<std::string, std::shared_ptr<Download>> downloads;
665 std::deque<std::pair<DownloadablePack*, bool>> DownloadQueue;
666 std::map<std::string, std::shared_ptr<Download>> finishedDownloads;
667 std::map<std::string, std::shared_ptr<Download>> pendingInstallDownloads;
668 std::map<int, DownloadablePack> downloadablePacks;
669 std::unordered_map<std::string, std::vector<std::string>> packTags;
672 downloadablePackPaginations{};
674 std::unordered_map<std::string, std::set<int>> tagPacks;
678 std::map<std::string, std::vector<OnlineScore>> chartLeaderboards{};
679 std::map<Skillset, std::vector<OnlineTopScore>> topScores{};
680 std::set<std::string> unrankedCharts{};
681 bool currentrateonly =
false;
682 bool topscoresonly =
true;
683 bool validonly =
true;
688 std::string lastVersion{
"" };
689 std::string countryCode{
"" };
700 bool HandleAuthErrorResponse(
const std::string& endpoint,
HTTPRequest& req);
702 bool HandleRatelimitResponse(
const std::string& endpoint,
HTTPRequest& req);
703 bool QueueRequestIfRatelimited(
const std::string& endpiont,
705 void QueueRatelimitedRequest(
const std::string& endpoint,
HTTPRequest& req);
709 bool Handle401And429Response(
710 const std::string& endpoint,
712 std::function<
void()> if401 = []() {},
713 std::function<void()> if429 = []() {});
717 void LoginRequest(
const std::string& username,
718 const std::string& password,
719 std::function<
void(
bool)> done);
720 void GetRankedChartkeysRequest(std::function<
void(
void)> callback,
723 void AddFavoriteRequest(
const std::string& chartKey);
724 void RemoveFavoriteRequest(
const std::string& chartKey);
725 void GetFavoritesRequest(
726 std::function<
void(std::set<std::string>)> onSuccess,
731 void RemoveGoalRequest(
ScoreGoal* goal,
bool oldGoal);
732 void GetGoalsRequest(std::function<
void(std::vector<ScoreGoal>)> onSuccess,
735 void AddPlaylistRequest(
const std::string& name);
736 void UpdatePlaylistRequest(
const std::string& name);
737 void RemovePlaylistRequest(
const std::string& name);
738 void GetPlaylistsRequest(
739 std::function<
void(std::unordered_map<std::string, Playlist>)> onSuccess,
742 void GetPlaylistRequest(std::function<
void(
Playlist)> onSuccess,
int id);
743 void GetChartLeaderboardRequest(
const std::string& chartkey,
745 void GetReplayDataRequest(
const std::string& scorekey,
747 const std::string& username,
748 const std::string& chartkey,
751 void RefreshUserData();
752 void RequestTop25(Skillset ss);
753 void RefreshLastVersion();
755 void GetPackTagsRequest();
756 void CachePacksForTag(
const std::string& tag);
759 std::function<
void(rapidjson::Document&)> whenDoneParser);
763 std::string requestName,
764 std::vector<std::pair<std::string, std::string>> params,
766 bool requireLogin =
true,
767 RequestMethod httpMethod = RequestMethod::GET,
768 bool compressed =
false,
770 bool withBearer =
true);
773 std::string requestName,
775 std::vector<std::pair<std::string, std::string>> params,
777 bool requireLogin =
true,
778 RequestMethod httpMethod = RequestMethod::GET,
779 bool compressed =
false,
781 bool withBearer =
true);
786 std::vector<std::pair<std::string, std::string>> params,
789 RequestMethod httpMethod,
795 std::vector<HTTPRequest*> HTTPRequests;
797 CURLM* pack_multi_handle =
nullptr;
798 CURLM* http_req_handle =
nullptr;
801 bool loggingIn{
false };
803 bool gameplay{
false };
804 bool initialized{
false };
806 float timeSinceLastDownload = 0.F;
808 std::unordered_map<std::string, std::chrono::steady_clock::time_point>
809 endpointRatelimitTimestamps{};
810 std::unordered_map<std::string, std::vector<HTTPRequest*>>
811 ratelimitedRequestQueue{};
812 std::unordered_set<std::string> newlyRankedChartkeys{};