From f95c698d82987a59e7fd7f42d69c3d3039cd3cc9 Mon Sep 17 00:00:00 2001 From: Nicolas Date: Mon, 20 Nov 2017 05:36:18 +0200 Subject: [PATCH] Update DLMAN with new EO API changes (WIP) (#110) * Update DLMAN with new EO API changes * Clean dlman a bit and first attempt at score uploading * Fix score uploads --- .../ScreenSelectMusic decorations/profile.lua | 30 +- src/DownloadManager.cpp | 362 ++++++++++++++---- src/DownloadManager.h | 19 +- src/HighScore.h | 1 + src/Player.cpp | 1 + src/PlayerStageStats.h | 1 + src/ProfileManager.cpp | 10 +- src/StageStats.cpp | 5 + 8 files changed, 347 insertions(+), 82 deletions(-) diff --git a/Themes/Til Death/BGAnimations/ScreenSelectMusic decorations/profile.lua b/Themes/Til Death/BGAnimations/ScreenSelectMusic decorations/profile.lua index fb0b454799..b8b6c2124b 100644 --- a/Themes/Til Death/BGAnimations/ScreenSelectMusic decorations/profile.lua +++ b/Themes/Til Death/BGAnimations/ScreenSelectMusic decorations/profile.lua @@ -490,19 +490,27 @@ local profilebuttons = Def.ActorFrame{ end, MouseLeftClickMessageCommand=function(self) if ButtonActive(self) and rankingSkillset == 1 then - username = function(answer) - user=answer - end - password = function(answer) - pass=answer - if PROFILEMAN:UploadProfile(PLAYER_1, user, pass) then - ms.ok("Uploaded profile") - else - ms.ok("Profile upload failed") + if not DLMAN:IsLoggedIn() then + username = function(answer) + user=answer + end + password = function(answer) + pass=answer + if PROFILEMAN:UploadProfile(PLAYER_1, user, pass) then + ms.ok("Uploaded profile") + else + ms.ok("Profile upload failed") + end end + easyInputStringWithFunction("Password:", 50, true, password) + easyInputStringWithFunction("Username:",50, false, username) + else + if PROFILEMAN:UploadProfile(PLAYER_1) then + ms.ok("Uploaded profile") + else + ms.ok("Profile upload failed") end - easyInputStringWithFunction("Password:", 50, true, password) - easyInputStringWithFunction("Username:",50, false, username) + end end end } diff --git a/src/DownloadManager.cpp b/src/DownloadManager.cpp index 008d71ea0d..8dc564885d 100644 --- a/src/DownloadManager.cpp +++ b/src/DownloadManager.cpp @@ -25,7 +25,8 @@ shared_ptr DLMAN = nullptr; static Preference maxDLPerSecond("maximumBytesDownloadedPerSecond", 0); static Preference maxDLPerSecondGameplay("maximumBytesDownloadedPerSecondDuringGameplay", 300000); static Preference packListURL("packListURL", "https://etternaonline.com/api/pack_list"); - +static Preference serverURL("UploadServerURL", "https://etternaonline.com/api"); +static Preference automaticSync("automaticScoreSync", 1); static const string TEMP_ZIP_MOUNT_POINT = "/@temp-zip/"; @@ -108,6 +109,7 @@ void DownloadManager::InstallSmzip(const string &sZipFile) +//Functions used to read/write data int progressfunc(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) { auto ptr = static_cast(clientp); @@ -123,7 +125,83 @@ size_t write_data(void *dlBuffer, size_t size, size_t nmemb, void *pnf) RFW->bytes += b; return b; } - +//A couple utility inline string functions +inline bool ends_with(std::string const & value, std::string const & ending) +{ + if (ending.size() > value.size()) return false; + return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); +} +inline bool starts_with(std::string const & value, std::string const & start) +{ + return value.rfind(start, 0) == 0; +} +inline void checkProtocol(string& url) +{ + if (!(starts_with(url, "https://") || starts_with(url, "http://"))) + url = string("http://").append(url); +} +//Utility inline functions to deal with CURL +inline CURL* initCURLHandle() { + CURL *curlHandle = curl_easy_init(); + curl_easy_setopt(curlHandle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); + curl_easy_setopt(curlHandle, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curlHandle, CURLOPT_SSL_VERIFYHOST, 0L); + return curlHandle; +} +inline bool addFileToForm(curl_httppost *&form, curl_httppost *&lastPtr, string field, string fileName, string filePath, RString &contents) +{ + RageFile rFile; + if (!rFile.Open(filePath)) + return false; + rFile.Read(contents, rFile.GetFileSize()); + rFile.Close(); + curl_formadd(&form, + &lastPtr, + CURLFORM_COPYNAME, field.c_str(), + CURLFORM_BUFFER, fileName.c_str(), + CURLFORM_BUFFERPTR, contents.c_str(), + CURLFORM_BUFFERLENGTH, 0, + CURLFORM_END); + return true; +} +inline void DownloadManager::AddSessionCookieToCURL(CURL *curlHandle) +{ + curl_easy_setopt(curlHandle, CURLOPT_COOKIEFILE, ""); /* start cookie engine */ + curl_easy_setopt(curlHandle, CURLOPT_COOKIE, ("ci_session=" + session + ";").c_str()); +} +inline void SetCURLResultsString(CURL *curlHandle, string& str) +{ + curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, &str); + curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, write_memory_buffer); +} +inline void DownloadManager::SetCURLPostToURL(CURL *curlHandle, string url) +{ + checkProtocol(url); + EncodeSpaces(url); + curl_easy_setopt(curlHandle, CURLOPT_URL, url.c_str()); + curl_easy_setopt(curlHandle, CURLOPT_POST, 1L); +} +inline void SetCURLFormPostField(CURL* curlHandle, curl_httppost *&form, curl_httppost *&lastPtr, char* field, string value) +{ + curl_formadd(&form, + &lastPtr, + CURLFORM_COPYNAME, field, + CURLFORM_COPYCONTENTS, curlHandle, value.c_str(), + CURLFORM_END); +} +inline void SetCURLFormPostField(CURL* curlHandle, curl_httppost *&form, curl_httppost *&lastPtr, string field, string value) +{ + curl_formadd(&form, + &lastPtr, + CURLFORM_COPYNAME, field.c_str(), + CURLFORM_COPYCONTENTS, value.c_str(), + CURLFORM_END); +} +template +inline void SetCURLFormPostField(CURL* curlHandle, curl_httppost *&form, curl_httppost *&lastPtr, string field, T value) +{ + SetCURLFormPostField(curlHandle, form, lastPtr, field, to_string(value)); +} DownloadManager::DownloadManager() { curl_global_init(CURL_GLOBAL_ALL); // Register with Lua. @@ -338,50 +416,190 @@ string Download::MakeTempFileName(string s) { return SpecialFiles::CACHE_DIR + "Downloads/" + Basename(s); } - -bool DownloadManager::UploadProfile(string url, string file, string user, string pass) +bool DownloadManager::LoggedIn() +{ + return !session.empty(); +} +bool DownloadManager::UploadProfile(string file, string user, string pass) { - CURL *curlForm = curl_easy_init(); + if (user != sessionUser || pass != sessionPass) + if (!StartSession(user, pass)) + return false; + return UploadProfile(file); +} - ReadThis w; - if(!w.file.Open(file)) +bool DownloadManager::UploadProfile(string file) +{ + if (!LoggedIn()) + return false; + string url = serverURL.Get() + "/upload_xml"; + CURL *curlHandle = initCURLHandle(); + curl_httppost *form = nullptr; + curl_httppost *lastPtr = nullptr; + curl_slist *headerlist = nullptr; + RString contents; + if (!addFileToForm(form, lastPtr, "xml", "etterna.xml", file, contents)) return false; + SetCURLPostToURL(curlHandle, url); + AddSessionCookieToCURL(curlHandle); + string result; + SetCURLResultsString(curlHandle, result); + curl_easy_setopt(curlHandle, CURLOPT_HTTPPOST, form); + CURLcode ret = curl_easy_perform(curlHandle); + curl_easy_cleanup(curlHandle); + if (result != "\"Success\"") { + LOG->Trace(result.c_str()); + return false; + } + return ret == 0; +} - curl_httppost *formpost = nullptr; - curl_httppost *lastptr = nullptr; +bool DownloadManager::ShouldUploadScores() +{ + return LoggedIn() && automaticSync; +} +bool DownloadManager::UploadScore(HighScore* hs) +{ + if (!LoggedIn()) + return false; + CURL *curlHandle = initCURLHandle(); + string url = serverURL.Get() + "/upload_score"; + curl_httppost *form = nullptr; + curl_httppost *lastPtr = nullptr; curl_slist *headerlist = nullptr; + SetCURLFormPostField(curlHandle, form, lastPtr, "scorekey", hs->GetScoreKey()); + FOREACH_ENUM(Skillset, ss) + SetCURLFormPostField(curlHandle, form, lastPtr, SkillsetToString(ss), hs->GetSkillsetSSR(ss)); + SetCURLFormPostField(curlHandle, form, lastPtr, "ssr_norm", hs->GetSSRNormPercent()); + SetCURLFormPostField(curlHandle, form, lastPtr, "max_combo", hs->GetMaxCombo()); + SetCURLFormPostField(curlHandle, form, lastPtr, "valid", static_cast(hs->GetEtternaValid())); + SetCURLFormPostField(curlHandle, form, lastPtr, "mods", hs->GetModifiers()); + SetCURLFormPostField(curlHandle, form, lastPtr, "miss", hs->GetTapNoteScore(TNS_Miss)); + SetCURLFormPostField(curlHandle, form, lastPtr, "bad", hs->GetTapNoteScore(TNS_W5)); + SetCURLFormPostField(curlHandle, form, lastPtr, "good", hs->GetTapNoteScore(TNS_W4)); + SetCURLFormPostField(curlHandle, form, lastPtr, "great", hs->GetTapNoteScore(TNS_W3)); + SetCURLFormPostField(curlHandle, form, lastPtr, "perfect", hs->GetTapNoteScore(TNS_W2)); + SetCURLFormPostField(curlHandle, form, lastPtr, "marv", hs->GetTapNoteScore(TNS_W1)); + SetCURLFormPostField(curlHandle, form, lastPtr, "datetime", string(hs->GetDateTime().GetString().c_str())); + SetCURLFormPostField(curlHandle, form, lastPtr, "hitmine", hs->GetTapNoteScore(TNS_HitMine)); + SetCURLFormPostField(curlHandle, form, lastPtr, "held", hs->GetHoldNoteScore(HNS_Held)); + SetCURLFormPostField(curlHandle, form, lastPtr, "letgo", hs->GetHoldNoteScore(HNS_LetGo)); + SetCURLFormPostField(curlHandle, form, lastPtr, "ng", hs->GetHoldNoteScore(HNS_Missed)); + SetCURLFormPostField(curlHandle, form, lastPtr, "chartkey", hs->GetChartKey()); + SetCURLFormPostField(curlHandle, form, lastPtr, "rate", hs->GetMusicRate()); + SetCURLFormPostField(curlHandle, form, lastPtr, "cc", static_cast(!hs->GetChordCohesion())); + SetCURLFormPostField(curlHandle, form, lastPtr, "calc_version", hs->GetSSRCalcVersion()); + SetCURLFormPostField(curlHandle, form, lastPtr, "topscore", hs->GetTopScore()); + string replayString = "["; + vector timestamps = hs->timeStamps; + vector offsets = hs->GetOffsetVector(); + for (int i = 0; i < offsets.size(); i++) { + replayString += "[" + to_string(timestamps[i]) + "," + to_string(offsets[i]) + "],"; + } + replayString = replayString.substr(0, replayString.size() - 1); //remove "," + replayString += "]"; + SetCURLFormPostField(curlHandle, form, lastPtr, "replay_data", replayString); + SetCURLPostToURL(curlHandle, url); + AddSessionCookieToCURL(curlHandle); + string result; + SetCURLResultsString(curlHandle, result); + curl_easy_setopt(curlHandle, CURLOPT_HTTPPOST, form); + CURLcode ret = curl_easy_perform(curlHandle); + curl_easy_cleanup(curlHandle); + if (result != "\"Success\"") { + LOG->Trace(result.c_str()); + return false; + } + return ret == 0; +} +void DownloadManager::EndSessionIfExists() +{ + if (!LoggedIn()) + return; + string url = serverURL.Get() +"/destroy"; + CURL *curlHandle = initCURLHandle(); - RString text; - w.file.Read(text, w.file.GetFileSize()); - w.file.Close(); + SetCURLPostToURL(curlHandle, url); - curl_formadd(&formpost, - &lastptr, - CURLFORM_COPYNAME, "xml", - CURLFORM_BUFFER, "etterna.xml", - CURLFORM_BUFFERPTR, text.c_str(), - CURLFORM_BUFFERLENGTH, 0, - CURLFORM_END); - curl_formadd(&formpost, - &lastptr, - CURLFORM_COPYNAME, "user", - CURLFORM_COPYCONTENTS, curl_easy_escape(curlForm, user.c_str(), 0), - CURLFORM_END); - curl_formadd(&formpost, - &lastptr, - CURLFORM_COPYNAME, "pass", - CURLFORM_COPYCONTENTS, curl_easy_escape(curlForm, pass.c_str(), 0) , - CURLFORM_END); + AddSessionCookieToCURL(curlHandle); - EncodeSpaces(url); - curl_easy_setopt(curlForm, CURLOPT_URL, url.c_str()); - curl_easy_setopt(curlForm, CURLOPT_POST, 1L); - curl_easy_setopt(curlForm, CURLOPT_HTTPPOST, formpost); + CURLcode ret = curl_easy_perform(curlHandle); + + curl_easy_cleanup(curlHandle); +} + +std::vector split(const std::string& s, char delimiter) +{ + std::vector tokens; + std::string token; + std::istringstream tokenStream(s); + while (std::getline(tokenStream, token, delimiter)) + { + tokens.push_back(token); + } + return tokens; +} + +bool DownloadManager::StartSession(string user, string pass) +{ + string url = serverURL.Get() + "/login"; + if (user == sessionUser && pass == sessionPass) { + return true; + } + EndSessionIfExists(); + CURL *curlHandle = initCURLHandle(); + curl_easy_setopt(curlHandle, CURLOPT_COOKIEFILE, ""); /* start cookie engine */ + + + curl_httppost *form = nullptr; + curl_httppost *lastPtr = nullptr; - CURLcode ret = curl_easy_perform(curlForm); + SetCURLFormPostField(curlHandle, form, lastPtr, "username", user); + SetCURLFormPostField(curlHandle, form, lastPtr, "password", pass); - curl_easy_cleanup(curlForm); - return ret==0; + SetCURLPostToURL(curlHandle, url); + + curl_easy_setopt(curlHandle, CURLOPT_HTTPPOST, form); + + string result; + SetCURLResultsString(curlHandle, result); + + CURLcode ret = curl_easy_perform(curlHandle); + + vector v_cookies; + if (result == "\"Success\"") { + struct curl_slist *cookies; + struct curl_slist *cookieIterator; + + printf("Cookies, curl knows:\n"); + curl_easy_getinfo(curlHandle, CURLINFO_COOKIELIST, &cookies); + + cookieIterator = cookies; + while (cookieIterator) { + v_cookies.push_back(cookieIterator->data); + cookieIterator = cookieIterator->next; + } + curl_slist_free_all(cookies); + curl_easy_cleanup(curlHandle); + for (auto& cook : v_cookies) { + vector parts = split(cook, '\t'); + for (auto x = parts.begin(); x != parts.end(); x++) { + if (*x == "ci_session") { + session = *(x + 1); + sessionCookie = cook; + break; + } + } + if (!session.empty()) + break; + } + sessionUser = user; + sessionPass = pass; + } + else { + session = sessionUser = sessionPass = sessionCookie = ""; + } + return !session.empty(); } @@ -396,35 +614,19 @@ bool DownloadManager::CachePackList(string url) return result; } -inline bool ends_with(std::string const & value, std::string const & ending) -{ - if (ending.size() > value.size()) return false; - return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); -} -inline bool starts_with(std::string const & value, std::string const & start) -{ - return value.rfind(start, 0) == 0; -} - vector* DownloadManager::GetPackList(string url, bool &result) { if (url == "") { result = false; return nullptr; } - if (!(starts_with(url, "https://") || starts_with(url, "http://"))) - url = string("http://").append(url); - CURL *curl = curl_easy_init(); - string bs; - curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + CURL *curl = initCURLHandle(); + + SetCURLPostToURL(curl, url); - curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0"); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &bs); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_memory_buffer); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "key=nick"); + string response; + SetCURLResultsString(curl, response); CURLcode res = curl_easy_perform(curl); @@ -435,7 +637,7 @@ vector* DownloadManager::GetPackList(string url, bool &result) Json::Value packs; RString error; auto packlist = new vector; - bool parsed = JsonUtil::LoadFromString(packs, bs, error); + bool parsed = JsonUtil::LoadFromString(packs, response, error); if (!parsed) { result = false; return packlist; @@ -479,7 +681,7 @@ vector* DownloadManager::GetPackList(string url, bool &result) Download::Download(string url) { m_Url = url; - handle = curl_easy_init(); + handle = initCURLHandle(); m_TempFileName = MakeTempFileName(url); p_RFWrapper.file.Open(m_TempFileName, 2); DLMAN->EncodeSpaces(m_Url); @@ -487,7 +689,6 @@ Download::Download(string url) curl_easy_setopt(handle, CURLOPT_WRITEDATA, &p_RFWrapper); curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_data); curl_easy_setopt(handle, CURLOPT_URL, m_Url.c_str()); - curl_easy_setopt(handle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); curl_easy_setopt(handle, CURLOPT_XFERINFODATA, &progress); curl_easy_setopt(handle, CURLOPT_XFERINFOFUNCTION, progressfunc); curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0); @@ -547,14 +748,40 @@ class LunaDownloadManager : public Luna static int GetDownloadingPacks(T* p, lua_State* L) { vector& packs = DLMAN->downloadablePacks; - lua_createtable(L, packs.size(), 0); + vector dling; for (unsigned i = 0; i < packs.size(); ++i) { - if (packs[i].downloading) { - packs[i].PushSelf(L); - lua_rawseti(L, -2, i + 1); - } + if (packs[i].downloading) + dling.push_back(&(packs[i])); } - + lua_createtable(L, dling.size(), 0); + for (unsigned i = 0; i < dling.size(); ++i) { + dling[i]->PushSelf(L); + lua_rawseti(L, -2, i + 1); + } + return 1; + } + static int GetDownloads(T* p, lua_State* L) + { + map& dls = DLMAN->downloads; + lua_createtable(L, dls.size(), 0); + int j = 0; + for (auto it = dls.begin(); it != dls.end(); ++it) { + it->second->PushSelf(L); + lua_rawseti(L, -2, j + 1); + j++; + } + return 1; + } + static int IsLoggedIn(T* p, lua_State* L) + { + lua_pushboolean(L, DLMAN->LoggedIn()); + return 1; + } + static int Login(T* p, lua_State* L) + { + string user = SArg(1); + string pass = SArg(2); + lua_pushboolean(L, DLMAN->StartSession(user, pass)); return 1; } static int GetFilteredAndSearchedPackList(T* p, lua_State* L) @@ -588,7 +815,10 @@ class LunaDownloadManager : public Luna { ADD_METHOD(GetPackList); ADD_METHOD(GetDownloadingPacks); + ADD_METHOD(GetDownloads); ADD_METHOD(GetFilteredAndSearchedPackList); + ADD_METHOD(IsLoggedIn); + ADD_METHOD(Login); } }; LUA_REGISTER_CLASS(DownloadManager) diff --git a/src/DownloadManager.h b/src/DownloadManager.h index 8664baa1a6..e026a2f833 100644 --- a/src/DownloadManager.h +++ b/src/DownloadManager.h @@ -11,6 +11,7 @@ #include "global.h" #include "CommandLineActions.h" #include "RageFile.h" +#include "HighScore.h" #include "ScreenManager.h" #include "RageFileManager.h" #include "curl/curl.h" @@ -88,9 +89,16 @@ class DownloadManager bool gameplay{false}; string error{""}; int lastid{0}; + string sessionCookie{ "" }; vector downloadablePacks; bool reloadPending{ false }; bool CachePackList(string url); + string session{ "" }; + string sessionUser{ "" }; + string sessionPass{ "" }; + bool LoggedIn(); + void EndSessionIfExists(); + bool StartSession(string user, string pass); vector* GetPackList(string url, bool &result); Download* DownloadAndInstallPack(const string &url); @@ -106,7 +114,16 @@ class DownloadManager bool Error() { return error == ""; } bool EncodeSpaces(string& str); - bool UploadProfile(string url, string file, string user, string pass); + bool UploadProfile(string file, string user, string pass); + bool UploadProfile(string file); + + bool UploadScore(HighScore* hs); + + bool ShouldUploadScores(); + + inline void AddSessionCookieToCURL(CURL *curlHandle); + inline void SetCURLPostToURL(CURL *curlHandle, string url); + // Lua void PushSelf(lua_State *L); diff --git a/src/HighScore.h b/src/HighScore.h index d8c2253f2f..d87d15d106 100644 --- a/src/HighScore.h +++ b/src/HighScore.h @@ -51,6 +51,7 @@ struct HighScore bool GetEtternaValid() const; vector GetOffsetVector() const; vector GetNoteRowVector() const; + vector timeStamps; string GetScoreKey() const; int GetTopScore() const; /** diff --git a/src/Player.cpp b/src/Player.cpp index 84df441fa2..631dd1d141 100644 --- a/src/Player.cpp +++ b/src/Player.cpp @@ -2941,6 +2941,7 @@ void Player::SetJudgment( int iRow, int iTrack, const TapNote &tn, TapNoteScore m_pPlayerStageStats->CurWifeScore = curwifescore; m_pPlayerStageStats->MaxWifeScore = maxwifescore; m_pPlayerStageStats->m_vOffsetVector.emplace_back(tn.result.fTapNoteOffset); + m_pPlayerStageStats->timeStamps.emplace_back(m_Timing->WhereUAtBroNoOffset(iRow)); m_pPlayerStageStats->m_vNoteRowVector.emplace_back(iRow); } else { diff --git a/src/PlayerStageStats.h b/src/PlayerStageStats.h index 9d8722afad..e5a35c8e32 100644 --- a/src/PlayerStageStats.h +++ b/src/PlayerStageStats.h @@ -33,6 +33,7 @@ class PlayerStageStats // Calculate the difficulty rating for a specific score obtained by a player - Mina Grade GetWifeGrade(); vector CalcSSR(float ssrpercent) const; + vector timeStamps; void GenerateValidationKeys(HighScore& hs) const; float GetPercentDancePoints() const; float GetWifeScore() const; diff --git a/src/ProfileManager.cpp b/src/ProfileManager.cpp index c448f7c6b3..5ab9bfc9a9 100644 --- a/src/ProfileManager.cpp +++ b/src/ProfileManager.cpp @@ -39,7 +39,6 @@ static void DefaultLocalProfileIDInit( size_t /*PlayerNumber*/ i, RString &sName } Preference1D ProfileManager::m_sDefaultLocalProfileID( DefaultLocalProfileIDInit, NUM_PLAYERS ); -Preference profileUploadURL("profileUploadURL", "https://etternaonline.com/api/upload_xml"); const RString USER_PROFILES_DIR = "/Save/LocalProfiles/"; const RString LAST_GOOD_SUBDIR = "LastGood/"; @@ -869,12 +868,15 @@ class LunaProfileManager: public Luna if (prof == nullptr) { return luaL_error(L, "UploadProfile needs a profile to be currently selected"); } - string user = SArg(2); - string pass = SArg(3); + if (!lua_isnil(L, 2) && !lua_isnil(L, 3)) { + string user = SArg(2); + string pass = SArg(3); + DLMAN->StartSession(user, pass); + } if(prof->profiledir == "") lua_pushboolean(L, false); else - lua_pushboolean(L, DLMAN->UploadProfile(profileUploadURL, prof->profiledir + "Etterna.xml", user, pass)==0); + lua_pushboolean(L, DLMAN->UploadProfile(prof->profiledir + "Etterna.xml")); return 1; } LunaProfileManager() diff --git a/src/StageStats.cpp b/src/StageStats.cpp index e69a47b7a4..38800780ea 100644 --- a/src/StageStats.cpp +++ b/src/StageStats.cpp @@ -14,6 +14,7 @@ #include #include "CryptManager.h" #include "ScoreManager.h" +#include "DownloadManager.h" #include "MinaCalc.h" /* Arcade: for the current stage (one song). @@ -218,6 +219,10 @@ static HighScore FillInHighScore(const PlayerStageStats &pss, const PlayerState FOREACH_ENUM(Skillset, ss) hs.SetSkillsetSSR(ss, 0.f); } + hs.timeStamps = pss.timeStamps; + if (DLMAN->ShouldUploadScores()) { + DLMAN->UploadScore(&hs); + } bool writesuccess = hs.WriteReplayData(); if (writesuccess) hs.UnloadReplayData();