diff --git a/Themes/Til Death/BGAnimations/ScreenSelectMusic decorations/profile.lua b/Themes/Til Death/BGAnimations/ScreenSelectMusic decorations/profile.lua index 7468f70dc0..a3ea54954e 100644 --- a/Themes/Til Death/BGAnimations/ScreenSelectMusic decorations/profile.lua +++ b/Themes/Til Death/BGAnimations/ScreenSelectMusic decorations/profile.lua @@ -388,6 +388,28 @@ t[#t+1] = Def.Quad{ UpdateRankingMessageCommand=cmd(queuecommand,"Set") } +t[#t+1] = Def.Quad{ + InitCommand=cmd(xy,frameX+320,frameY+rankingY+265;zoomto,100,20;halign,0.5;valign,0;diffuse,getMainColor('frames');diffusealpha,0.35), + SetCommand=function(self) + if rankingSkillset == 0 then + self:visible(true) + else + self:visible(false) + end + end, + MouseLeftClickMessageCommand=function(self) + if isOver(self) and rankingSkillset == 0 then + local saved = PROFILEMAN:ConvertProfile(PLAYER_1) + if saved then + ms.ok("Convert") + else + ms.ok("Save failed") + end + end + end, + UpdateRankingMessageCommand=cmd(queuecommand,"Set") +} + t[#t+1] = LoadFont("Common Large") .. { InitCommand=cmd(xy,frameX+80,frameY+rankingY+275;halign,0.5;zoom,0.3;diffuse,getMainColor('positive');settext,"Save Profile"), SetCommand=function(self) diff --git a/src/Profile.cpp b/src/Profile.cpp index 2428a5cf82..049c53b4f5 100644 --- a/src/Profile.cpp +++ b/src/Profile.cpp @@ -2114,32 +2114,32 @@ void Profile::RemoveFromFavorites(RString ck) { } } -void Profile::LoadSongScoresFromNode( const XNode* pSongScores ) +void Profile::LoadSongScoresFromNode(const XNode* pSongScores) { CHECKPOINT_M("Loading the node that contains song scores."); - ASSERT( pSongScores->GetName() == "SongScores" ); + ASSERT(pSongScores->GetName() == "SongScores"); - FOREACH_CONST_Child( pSongScores, pSong ) + FOREACH_CONST_Child(pSongScores, pSong) { - if( pSong->GetName() != "Song" ) + if (pSong->GetName() != "Song") continue; SongID songID; - songID.LoadFromNode( pSong ); + songID.LoadFromNode(pSong); // Allow invalid songs so that scores aren't deleted for people that use // AdditionalSongsFolders and change it frequently. -Kyz //if( !songID.IsValid() ) // continue; - FOREACH_CONST_Child( pSong, pSteps ) + FOREACH_CONST_Child(pSong, pSteps) { - if( pSteps->GetName() != "Steps" ) + if (pSteps->GetName() != "Steps") continue; StepsID stepsID; - stepsID.LoadFromNode( pSteps ); - if( !stepsID.IsValid() ) + stepsID.LoadFromNode(pSteps); + if (!stepsID.IsValid()) WARN_AND_CONTINUE; const XNode *pHighScoreListNode = pSteps->GetChild("HighScoreList"); @@ -2148,72 +2148,52 @@ void Profile::LoadSongScoresFromNode( const XNode* pSongScores ) HighScoreList &hsl = m_SongHighScores[songID].m_StepsHighScores[stepsID].hsl; hsl.LoadFromNode(pHighScoreListNode); + } + } +} - /* This is for updating the chartkey values for pre-existing steps entries. First - we do a validity check to ensure a chartkey can and has been generated. Then we - load the chart the score is attached to and then rerun the validity test. This is - to handle scores for which the relevant.sm has been moved or deleted and chartkeys - cannot be generated or assigned. If we encounter a newly invalidated steps we reload - it so as not to alter the entry. This way if a steps entry already has a chartkey - attached to it and the .sm file is moved or deleted the chartkey and score will persist - allowing it to be accessed by any current file that shares the same key. - Mina - */ - if (songID.IsValid()) - { - Song* song = songID.ToSong(); - Steps* steps = stepsID.ToSteps(song, true); - if (stepsID.IsValid() && stepsID.GetDifficulty() != Difficulty_Edit) { - stepsID.FromSteps(steps); - if(!stepsID.IsValid()) - stepsID.LoadFromNode(pSteps); - stepsID.CreateNode(); - } +void Profile::ImportScoresToEtterna() { + //LOG->Trace("Converting scores to etterna"); + string ck; - // Create a key/rate sorted map for just internal use for now - Mina - RString ck = stepsID.GetKey(); - auto it = HighScoresByChartKey.find(ck); - if (it == HighScoresByChartKey.end()) { - HighScoreRateMap hsrm; - FOREACH(HighScore, hsl.vHighScores, hs) { - float rate = (*hs).GetMusicRate(); - auto itr = hsrm.find(rate); - if (itr == hsrm.end()) { - vector hsvec; - hsvec.emplace_back(*hs); - hsrm.emplace(rate, hsvec); - } - else { - hsrm[rate].emplace_back(*hs); - } - } - HighScoresByChartKey.emplace(ck, hsrm); - } - else { - HighScoreRateMap& hsrm = HighScoresByChartKey.at(ck); - FOREACH(HighScore, hsl.vHighScores, hs) { - float rate = (*hs).GetMusicRate(); - auto itr = hsrm.find(rate); - if (itr == hsrm.end()) { - vector hsvec; - hsvec.emplace_back(*hs); - hsrm.emplace(rate, hsvec); - } - else { - hsrm[rate].emplace_back(*hs); - } - } - } + FOREACHM(SongID, HighScoresForASong, m_SongHighScores, i) { + const SongID& id = i->first; + //LOG->Warn("songdir %s", id.ToString()); - // sort by rate - FOREACHM(RString, HighScoreRateMap, HighScoresByChartKey, keyedhsrm) { - HighScoreRateMap& hsrm = keyedhsrm->second; - FOREACHM(float, vector, hsrm, ratedhsvec) { - vector& hsvec = ratedhsvec->second; - sort(hsvec.begin(), hsvec.end()); - reverse(hsvec.begin(), hsvec.end()); - } + HighScoresForASong& hsfas = i->second; + FOREACHM(StepsID, HighScoresForASteps, hsfas.m_StepsHighScores, j) { + const StepsID& sid = j->first; + + if (sid.GetStepsType() != StepsType_dance_single) + continue; + + //LOG->Warn("steps %s", sid.ToString()); + + if (id.IsValid() && sid.IsValid()) { + //LOG->Warn("attempting conversion"); + vector& hsv = j->second.hsl.vHighScores; + + Song* song = id.ToSong(); + Steps* steps = sid.ToSteps(song, true); + + if (!steps) + continue; + + ck = steps->GetChartKey(); + + for (size_t i = 0; i < hsv.size(); ++i) { + //LOG->Warn("converting score for key %s", ck); + HighScore hs = hsv[i]; + + //LOG->Warn("score percent %f", hs.GetWifeScore()); + // ignore historic key and just load from here since the hashing function was changed anyway + hs.SetChartKey(ck); + pscores.AddScore(hs); } + } + + } } } diff --git a/src/Profile.h b/src/Profile.h index 267daa370c..05967721de 100644 --- a/src/Profile.h +++ b/src/Profile.h @@ -457,6 +457,8 @@ class Profile XNode* SaveEttScoresCreateNode() const; XNode* SaveEttXmlCreateNode() const; + // For converting to etterna from stats.xml + void ImportScoresToEtterna(); void SaveStatsWebPageToDir( const RString &sDir ) const; diff --git a/src/ProfileManager.cpp b/src/ProfileManager.cpp index bd5b5b5bad..3c46a793f2 100644 --- a/src/ProfileManager.cpp +++ b/src/ProfileManager.cpp @@ -353,6 +353,30 @@ bool ProfileManager::SaveProfile( PlayerNumber pn ) const return b; } +bool ProfileManager::ConvertProfile(PlayerNumber pn) +{ + if (m_sProfileDir[pn].empty()) + return false; + + /* + * If the profile we're writing was loaded from the primary (non-backup) + * data, then we've validated it and know it's good. Before writing our + * new data, move the old, good data to the backup. (Only do this once; + * if we save the profile more than once, we haven't re-validated the + * newly written data.) + */ + if (m_bNeedToBackUpLastLoad[pn]) + { + m_bNeedToBackUpLastLoad[pn] = false; + RString sBackupDir = m_sProfileDir[pn] + LAST_GOOD_SUBDIR; + Profile::MoveBackupToDir(m_sProfileDir[pn], sBackupDir); + } + + GetProfile(pn)->ImportScoresToEtterna(); + + return true; +} + bool ProfileManager::SaveLocalProfile( const RString &sProfileID ) { const Profile *pProfile = GetLocalProfile( sProfileID ); @@ -881,36 +905,6 @@ void ProfileManager::AddStepsScore( const Song* pSong, const Steps* pSteps, Play */ } -// gotta get a better way to do this, probably by making the score map a class - Mina -void ProfileManager::AddScoreByKey(PlayerNumber pn, const HighScore &hs_) { - HighScore hs = hs_; - Profile* pProfile = GetProfile(pn); - auto ck = hs.GetChartKey(); - auto rate = hs.GetMusicRate(); - - - auto &hsbk = pProfile->HighScoresByChartKey; - auto it = hsbk.find(ck); - if (it == hsbk.end()) { - vector hsv; - hsv.emplace_back(hs); - map> hsrm; - hsrm.emplace(rate, hsv); - hsbk.emplace(ck, hsrm); - } - else { - auto it2 = hsbk.at(ck).find(rate); - if (it2 == hsbk.at(ck).end()) { - vector hsv; - hsv.emplace_back(hs); - hsbk.at(ck).emplace(rate, hsv); - } - else { - hsbk.at(ck).at(rate).emplace_back(hs); - } - } -} - void ProfileManager::IncrementStepsPlayCount( const Song* pSong, const Steps* pSteps, PlayerNumber pn ) { if( IsPersistentProfile(pn) ) @@ -1128,6 +1122,7 @@ class LunaProfileManager: public Luna return 1; } static int SaveProfile( T* p, lua_State *L ) { lua_pushboolean( L, p->SaveProfile(Enum::Check(L, 1)) ); return 1; } + static int ConvertProfile(T* p, lua_State *L) { lua_pushboolean(L, p->ConvertProfile(Enum::Check(L, 1))); return 1; } static int SaveLocalProfile( T* p, lua_State *L ) { lua_pushboolean( L, p->SaveLocalProfile(SArg(1)) ); return 1; } static int ProfileFromMemoryCardIsNew( T* p, lua_State *L ) { lua_pushboolean( L, p->ProfileFromMemoryCardIsNew(Enum::Check(L, 1)) ); return 1; } static int GetSongNumTimesPlayed( T* p, lua_State *L ) @@ -1170,6 +1165,7 @@ class LunaProfileManager: public Luna ADD_METHOD( GetPlayerName ); // ADD_METHOD( SaveProfile ); + ADD_METHOD( ConvertProfile ); ADD_METHOD( SaveLocalProfile ); ADD_METHOD( ProfileFromMemoryCardIsNew ); ADD_METHOD( GetSongNumTimesPlayed ); diff --git a/src/ProfileManager.h b/src/ProfileManager.h index b6c1e87000..a3f0de4da2 100644 --- a/src/ProfileManager.h +++ b/src/ProfileManager.h @@ -51,6 +51,7 @@ class ProfileManager bool LoadProfileFromMemoryCard( PlayerNumber pn, bool bLoadEdits = true ); bool FastLoadProfileNameFromMemoryCard( const RString &sRootDir, RString &sName ) const; bool SaveProfile( PlayerNumber pn ) const; + bool ConvertProfile(PlayerNumber pn); bool SaveLocalProfile( const RString &sProfileID ); void UnloadProfile( PlayerNumber pn ); @@ -92,7 +93,6 @@ class ProfileManager int GetSongNumTimesPlayed( const Song* pSong, ProfileSlot card ) const; bool IsSongNew( const Song* pSong ) const { return GetSongNumTimesPlayed(pSong,ProfileSlot_Machine)==0; } void AddStepsScore( const Song* pSong, const Steps* pSteps , PlayerNumber pn, const HighScore &hs, int &iPersonalIndexOut, int &iMachineIndexOut ); - void AddScoreByKey(PlayerNumber pn, const HighScore &hs); void IncrementStepsPlayCount( const Song* pSong, const Steps* pSteps, PlayerNumber pn ); // Course stats diff --git a/src/StageStats.cpp b/src/StageStats.cpp index 66ad015f7c..df4f742adb 100644 --- a/src/StageStats.cpp +++ b/src/StageStats.cpp @@ -307,7 +307,6 @@ void StageStats::FinalizeScores( bool bSummary ) PROFILEMAN->AddStepsScore( pSong, pSteps, p, hs, m_player[p].m_iPersonalHighScoreIndex, m_player[p].m_iMachineHighScoreIndex ); // new score structure -mina - PROFILEMAN->AddScoreByKey(p, hs); Profile* zzz = PROFILEMAN->GetProfile(PLAYER_1); zzz->pscores.AddScore(hs); zzz->SetAnyAchievedGoals(GAMESTATE->m_pCurSteps[PLAYER_1]->GetChartKey(), GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate, hs);