From f04e70ac0caa5be91b2a760a41c7a66bf6fe0e41 Mon Sep 17 00:00:00 2001 From: Chris Danford Date: Sun, 23 May 2004 21:08:03 +0000 Subject: [PATCH] update Course stats file format --- stepmania/src/Profile.cpp | 586 +++++++------------------------------- 1 file changed, 97 insertions(+), 489 deletions(-) diff --git a/stepmania/src/Profile.cpp b/stepmania/src/Profile.cpp index a9cb3c5d9a..61b2b5727e 100644 --- a/stepmania/src/Profile.cpp +++ b/stepmania/src/Profile.cpp @@ -33,6 +33,7 @@ #include "UnlockSystem.h" #include "CatalogXml.h" #include "XmlFile.h" +#include "Foreach.h" // // Old file versions for backward compatibility @@ -338,11 +339,27 @@ int Profile::GetActualCourseDancePointsForStepsType( StepsType st ) const if( !pCourse->AllSongsAreFixed() ) continue; - const HighScoresForACourse& h = i->second; - FOREACH_ShownCourseDifficulty( cd ) + const HighScoresForACourse &hsfac = i->second; + + for( std::map::const_iterator j = hsfac.m_TrailHighScores.begin(); + j != hsfac.m_TrailHighScores.end(); + ++j ) { - const HighScoreList& hs = h.hs[st][cd]; - const RadarValues& fRadars = pCourse->GetTrail(st,cd)->GetRadarValues(); + const TrailID &id = j->first; + Trail* pTrail = id.ToTrail( pCourse, true ); + + // If the Steps isn't loaded on the current machine, then we can't + // get radar values to compute dance points. + if( pTrail == NULL ) + continue; + + if( pTrail->m_StepsType != st ) + continue; + + const HighScoresForATrail& h = j->second; + const HighScoreList& hs = h.hs; + + const RadarValues& fRadars = pTrail->GetRadarValues(); int iPossibleDP = ScoreKeeperMAX2::GetPossibleDancePoints( fRadars ); iTotal += (int)truncf( hs.GetTopScore().fPercentDP * iPossibleDP ); } @@ -463,33 +480,28 @@ void Profile::GetGrades( const Song* pSong, StepsType st, int iCounts[NUM_GRADES // // Course high scores // -void Profile::AddCourseHighScore( const Course* pCourse, StepsType st, CourseDifficulty cd, HighScore hs, int &iIndexOut ) +void Profile::AddCourseHighScore( const Course* pCourse, const Trail* pTrail, HighScore hs, int &iIndexOut ) +{ + GetCourseHighScoreList(pCourse,pTrail).AddHighScore( hs, iIndexOut ); +} + +const HighScoreList& Profile::GetCourseHighScoreList( const Course* pCourse, const Trail* pTrail ) const +{ + return ((Profile *)this)->GetCourseHighScoreList( pCourse, pTrail ); +} + +HighScoreList& Profile::GetCourseHighScoreList( const Course* pCourse, const Trail* pTrail ) { CourseID courseID; courseID.FromCourse( pCourse ); - std::map::iterator iter = m_CourseHighScores.find( courseID ); - if( iter == m_CourseHighScores.end() ) - m_CourseHighScores[courseID].hs[st][cd].AddHighScore( hs, iIndexOut ); // operator[] inserts into map - else - iter->second.hs[st][cd].AddHighScore( hs, iIndexOut ); -} + TrailID trailID; + trailID.FromTrail( pTrail ); -const HighScoreList& Profile::GetCourseHighScoreList( const Course* pCourse, StepsType st, CourseDifficulty cd ) const -{ - return ((Profile *)this)->GetCourseHighScoreList( pCourse, st, cd ); -} + HighScoresForACourse &hsCourse = m_CourseHighScores[courseID]; // operator[] inserts into map + HighScoresForATrail &hsTrail = hsCourse.m_TrailHighScores[trailID]; // operator[] inserts into map -HighScoreList& Profile::GetCourseHighScoreList( const Course* pCourse, StepsType st, CourseDifficulty cd ) -{ - CourseID courseID; - courseID.FromCourse( pCourse ); - - std::map::iterator iter = m_CourseHighScores.find( courseID ); - if( iter == m_CourseHighScores.end() ) - return m_CourseHighScores[courseID].hs[st][cd]; // operator[] inserts into map - else - return iter->second.hs[st][cd]; + return hsTrail.hs; } int Profile::GetCourseNumTimesPlayed( const Course* pCourse ) const @@ -502,24 +514,25 @@ int Profile::GetCourseNumTimesPlayed( const Course* pCourse ) const int Profile::GetCourseNumTimesPlayed( const CourseID &courseID ) const { - std::map::const_iterator iter = m_CourseHighScores.find( courseID ); - if( iter == m_CourseHighScores.end() ) - { + const HighScoresForACourse *hsCourse = GetHighScoresForACourse( courseID ); + if( hsCourse == NULL ) return 0; - } - else + + int iTotalNumTimesPlayed = 0; + for( std::map::const_iterator j = hsCourse->m_TrailHighScores.begin(); + j != hsCourse->m_TrailHighScores.end(); + j++ ) { - int iTotalNumTimesPlayed = 0; - for( unsigned st = 0; st < NUM_STEPS_TYPES; ++st ) - FOREACH_CourseDifficulty( cd ) - iTotalNumTimesPlayed += iter->second.hs[st][cd].iNumTimesPlayed; - return iTotalNumTimesPlayed; + const HighScoresForATrail &hsTrail = j->second; + + iTotalNumTimesPlayed += hsTrail.hs.iNumTimesPlayed; } + return iTotalNumTimesPlayed; } -void Profile::IncrementCoursePlayCount( const Course* pCourse, StepsType st, CourseDifficulty cd ) +void Profile::IncrementCoursePlayCount( const Course* pCourse, const Trail* pTrail ) { - GetCourseHighScoreList(pCourse,st,cd).iNumTimesPlayed++; + GetCourseHighScoreList(pCourse,pTrail).iNumTimesPlayed++; } // @@ -576,17 +589,7 @@ bool Profile::LoadAllFromDir( CString sDir, bool bRequireSignature ) InitAll(); - // Only try to load old score formats if we're allowing unsigned data. - if( !PREFSMAN->m_bSignProfileData ) - { - LoadProfileDataFromDirSM390a12( sDir ); - LoadSongScoresFromDirSM390a12( sDir ); - LoadCourseScoresFromDirSM390a12( sDir ); - LoadCategoryScoresFromDirSM390a12( sDir ); - } - LoadEditableDataFromDir( sDir ); - // Read stats.xml FOR_ONCE @@ -690,17 +693,6 @@ bool Profile::SaveAllToDir( CString sDir, bool bSignData ) const } } - - // Delete old files after saving new ones so we don't try to load old - // files the next time and make duplicate records. - if( !PREFSMAN->m_bSignProfileData ) // we tried to read the older formats - { - DeleteProfileDataFromDirSM390a12( sDir ); - DeleteSongScoresFromDirSM390a12( sDir ); - DeleteCourseScoresFromDirSM390a12( sDir ); - DeleteCategoryScoresFromDirSM390a12( sDir ); - } - const bool bThisIsMachineProfile = (this == PROFILEMAN->GetMachineProfile()); // XXX if( (bThisIsMachineProfile && PREFSMAN->m_bWriteMachineStatsHtml) || (!bThisIsMachineProfile && PREFSMAN->m_bWriteProfileStatsHtml) ) @@ -721,43 +713,6 @@ bool Profile::SaveAllToDir( CString sDir, bool bSignData ) const return true; } - -void Profile::LoadProfileDataFromDirSM390a12( CString sDir ) -{ - CString fn = sDir + SM_390A12_PROFILE_INI; - InitEditableData(); - InitGeneralData(); - - // - // read ini - // - IniFile ini; - if( !ini.ReadFile( fn ) ) - return; - - ini.GetValue( "Profile", "DisplayName", m_sDisplayName ); - ini.GetValue( "Profile", "LastUsedHighScoreName", m_sLastUsedHighScoreName ); - ini.GetValue( "Profile", "UsingProfileDefaultModifiers", m_bUsingProfileDefaultModifiers ); - ini.GetValue( "Profile", "DefaultModifiers", m_sDefaultModifiers ); - ini.GetValue( "Profile", "TotalPlays", m_iTotalPlays ); - ini.GetValue( "Profile", "TotalPlaySeconds", m_iTotalPlaySeconds ); - ini.GetValue( "Profile", "TotalGameplaySeconds", m_iTotalGameplaySeconds ); - ini.GetValue( "Profile", "CurrentCombo", m_iCurrentCombo ); - ini.GetValue( "Profile", "WeightPounds", m_iWeightPounds ); - ini.GetValue( "Profile", "CaloriesBurned", m_fTotalCaloriesBurned ); - ini.GetValue( "Profile", "LastPlayedMachineGuid", m_sLastPlayedMachineGuid ); - - unsigned i; - for( i=0; iGetGameDefForGame(GAMEMAN->GetStyleDefForStyle((Style)i)->m_Game)->m_szName)+Capitalize(GAMEMAN->GetStyleDefForStyle((Style)i)->m_szName), m_iNumSongsPlayedByStyle[i] ); - for( i=0; iGetSongNumTimesPlayed(songID) == 0 ) continue; - - LPXNode pSongNode = pNode->AppendChild( songID.CreateNode() ); + XNode* pSongNode = pNode->AppendChild( songID.CreateNode() ); for( std::map::const_iterator j = hsSong.m_StepsHighScores.begin(); j != hsSong.m_StepsHighScores.end(); @@ -1082,7 +1036,7 @@ XNode* Profile::SaveSongScoresCreateNode() const if( hsl.iNumTimesPlayed == 0 ) continue; - LPXNode pStepsNode = pSongNode->AppendChild( stepsID.CreateNode() ); + XNode* pStepsNode = pSongNode->AppendChild( stepsID.CreateNode() ); pStepsNode->AppendChild( hsl.CreateNode() ); } @@ -1093,11 +1047,11 @@ XNode* Profile::SaveSongScoresCreateNode() const void Profile::LoadSongScoresFromNode( const XNode* pNode ) { + CHECKPOINT; + ASSERT( pNode->name == "SongScores" ); - for( XNodes::const_iterator song = pNode->childs.begin(); - song != pNode->childs.end(); - song++ ) + FOREACH_CONST( XNode*, pNode->childs, song ) { if( (*song)->name != "Song" ) continue; @@ -1107,9 +1061,7 @@ void Profile::LoadSongScoresFromNode( const XNode* pNode ) if( !songID.IsValid() ) WARN_AND_CONTINUE; - for( XNodes::iterator steps = (*song)->childs.begin(); - steps != (*song)->childs.end(); - steps++ ) + FOREACH_CONST( XNode*, (*song)->childs, steps ) { if( (*steps)->name != "Steps" ) continue; @@ -1129,309 +1081,6 @@ void Profile::LoadSongScoresFromNode( const XNode* pNode ) } } -static Grade ConvertA12Grade( Grade g ) -{ - /* - * Map - * GRADE_NO_DATA=0, GRADE_E, GRADE_D, GRADE_C, GRADE_B, GRADE_A, - * GRADE_AA,GRADE_AAA,GRADE_AAAA, NUM_GRADES - * - * to GRADE_TIER_1 (AAAA) ... GRADE_TIER_7 (D), GRADE_FAILED (E), GRADE_NO_DATA. - */ - switch( g ) - { - case 0: return GRADE_NO_DATA; - case 1: return GRADE_FAILED; /* E */ - case 2: return GRADE_TIER_7; /* D */ - case 3: return GRADE_TIER_6; /* C */ - case 4: return GRADE_TIER_5; /* B */ - case 5: return GRADE_TIER_4; /* A */ - case 6: return GRADE_TIER_3; /* AA */ - case 7: return GRADE_TIER_2; /* AAA */ - case 8: return GRADE_TIER_1; /* AAAA */ - default: return GRADE_NO_DATA; - } -} - -void Profile::LoadSongScoresFromDirSM390a12( CString sDir ) -{ - Profile* pProfile = this; - ASSERT( pProfile ); - - CString fn = sDir + SM_390A12_SONG_SCORES_DAT; - if( !IsAFile(fn) ) - return; - - RageFile f; - if( !f.Open(fn, RageFile::READ) ) - { - LOG->Warn( "Couldn't open file \"%s\": %s", fn.c_str(), f.GetError().c_str() ); - return; - } - - int version; - if( !FileRead(f, version) ) - WARN_AND_RETURN; - if( version != SM_390A12_SONG_SCORES_VERSION ) - WARN_AND_RETURN; - - int iNumSongs; - if( !FileRead(f, iNumSongs) ) - WARN_AND_RETURN; - - for( int s=0; sGetSongFromDir( sSongDir ); - - int iNumNotes; - if( !FileRead(f, iNumNotes) ) - WARN_AND_RETURN; - - for( int n=0; nGetStepsByDescription( st, sDescription ); - else - pSteps = pSong->GetStepsByDifficulty( st, dc ); - } - - int iNumTimesPlayed; - if( !FileRead(f, iNumTimesPlayed) ) - WARN_AND_RETURN; - - HighScoreList &hsl = pProfile->GetStepsHighScoreList(pSong,pSteps); - - if( pSteps ) - hsl.iNumTimesPlayed = iNumTimesPlayed; - - int iNumHighScores; - if( !FileRead(f, iNumHighScores) ) - WARN_AND_RETURN; - - if( pSteps ) - hsl.vHighScores.resize( iNumHighScores ); - - int l; - for( l=0; lWarn( "Couldn't open file \"%s\": %s", fn.c_str(), f.GetError().c_str() ); - return; - } - - int version; - if( !FileRead(f, version) ) - WARN_AND_RETURN; - if( version != SM_390A12_CATEGORY_RANKING_VERSION ) - WARN_AND_RETURN; - - /* NUM_STEPS_TYPES changed after A12. Only read up to the last unchanged type. We - * can probably drop all of this compatibility code before the final release, anyway ... */ - for( int st=0; st<=STEPS_TYPE_DS3DDX_SINGLE; st++ ) - { - for( int rc=0; rcGetCategoryHighScoreList( (StepsType)st, (RankingCategory)rc ); - hsl.vHighScores.resize( iNumHighScores ); - - for( int l=0; lWarn( "Couldn't open file \"%s\": %s", fn.c_str(), f.GetError().c_str() ); - return; - } - - int version; - if( !FileRead(f, version) ) - WARN_AND_RETURN; - if( version != SM_390A12_COURSE_SCORES_VERSION ) - WARN_AND_RETURN; - - int iNumCourses; - if( !FileRead(f, iNumCourses) ) - WARN_AND_RETURN; - - for( int c=0; cGetCourseFromPath( sPath ); - if( pCourse == NULL ) - pCourse = SONGMAN->GetCourseFromName( sPath ); - - // even if we don't find the Course*, we still have to read past the input - - int NumStepsTypesPlayed = 0; - if( !FileRead(f, NumStepsTypesPlayed) ) - WARN_AND_RETURN; - - while( NumStepsTypesPlayed-- ) - { - int st; - if( !FileRead(f, st) ) - WARN_AND_RETURN; - - int iNumTimesPlayed; - if( !FileRead(f, iNumTimesPlayed) ) - WARN_AND_RETURN; - - HighScoreList &hsl = pProfile->GetCourseHighScoreList( pCourse, (StepsType)st, COURSE_DIFFICULTY_REGULAR ); - - if( pCourse ) - hsl.iNumTimesPlayed = iNumTimesPlayed; - - int iNumHighScores; - if( !FileRead(f, iNumHighScores) ) - WARN_AND_RETURN; - - if( pCourse ) - hsl.vHighScores.resize(iNumHighScores); - - for( int l=0; lfirst; + const CourseID &courseID = i->first; const HighScoresForACourse &hsCourse = i->second; // skip courses that have never been played - if( pProfile->GetCourseNumTimesPlayed(id) == 0 ) + if( pProfile->GetCourseNumTimesPlayed(courseID) == 0 ) continue; - XNode* pCourseNode = pNode->AppendChild( id.CreateNode() ); + XNode* pCourseNode = pNode->AppendChild( courseID.CreateNode() ); - for( StepsType st=(StepsType)0; st::const_iterator j = hsCourse.m_TrailHighScores.begin(); + j != hsCourse.m_TrailHighScores.end(); + j++ ) { - // TRICKY: Only append this node if one we have at least one child. - // There's no point to saving a bunch of empty StepsType nodes. - LPXNode pStepsTypeNode = new XNode; - pStepsTypeNode->name = "StepsType"; - pStepsTypeNode->AppendAttr( "Type", GameManager::NotesTypeToString(st) ); - - FOREACH_CourseDifficulty( cd ) - { - const HighScoreList &hsl = hsCourse.hs[st][cd]; + const TrailID &trailID = j->first; + const HighScoresForATrail &hsTrail = j->second; - // skip course/steps types that have never been played - if( hsl.iNumTimesPlayed == 0 ) - continue; + const HighScoreList &hsl = hsTrail.hs; - LPXNode pCourseDifficultyNode = pStepsTypeNode->AppendChild( "CourseDifficulty" ); - pCourseDifficultyNode->AppendAttr( "Type", CourseDifficultyToString(cd) ); - - pCourseDifficultyNode->AppendChild( hsl.CreateNode() ); - } + // skip steps that have never been played + if( hsl.iNumTimesPlayed == 0 ) + continue; - if( !pStepsTypeNode->childs.empty() ) - pCourseNode->AppendChild( pStepsTypeNode ); + XNode* pTrailNode = pCourseNode->AppendChild( trailID.CreateNode() ); + + pTrailNode->AppendChild( hsl.CreateNode() ); } } @@ -1493,51 +1134,32 @@ void Profile::LoadCourseScoresFromNode( const XNode* pNode ) ASSERT( pNode->name == "CourseScores" ); - for( XNodes::const_iterator course = pNode->childs.begin(); - course != pNode->childs.end(); - course++ ) + FOREACH_CONST( XNode*, pNode->childs, course ) { if( (*course)->name != "Course" ) continue; - CourseID id; - id.LoadFromNode( *course ); - if( !id.IsValid() ) + CourseID courseID; + courseID.LoadFromNode( *course ); + if( !courseID.IsValid() ) WARN_AND_CONTINUE; - for( XNodes::iterator stepsType = (*course)->childs.begin(); - stepsType != (*course)->childs.end(); - stepsType++ ) + FOREACH_CONST( XNode*, (*course)->childs, trail ) { - if( (*stepsType)->name != "StepsType" ) + if( (*trail)->name != "Trail" ) continue; - CString str; - if( !(*stepsType)->GetAttrValue( "Type", str ) ) - WARN_AND_CONTINUE; - StepsType st = GameManager::StringToNotesType( str ); - if( st == STEPS_TYPE_INVALID ) + TrailID trailID; + trailID.LoadFromNode( *trail ); + if( !trailID.IsValid() ) WARN_AND_CONTINUE; - for( XNodes::iterator courseDifficulty = (*stepsType)->childs.begin(); - courseDifficulty != (*stepsType)->childs.end(); - courseDifficulty++ ) - { - - const LPXAttr TypeAttr = (*courseDifficulty)->GetAttr( "Type" ); - if( TypeAttr == NULL ) - WARN_AND_CONTINUE; - CourseDifficulty cd = StringToCourseDifficulty( TypeAttr->value ); - if( cd == COURSE_DIFFICULTY_INVALID ) - WARN_AND_CONTINUE; - - XNode *pHighScoreListNode = (*courseDifficulty)->GetChild("HighScoreList"); - if( pHighScoreListNode == NULL ) - WARN_AND_CONTINUE; - - HighScoreList &hsl = m_CourseHighScores[id].hs[st][cd]; - hsl.LoadFromNode( pHighScoreListNode ); - } + XNode *pHighScoreListNode = (*trail)->GetChild("HighScoreList"); + if( pHighScoreListNode == NULL ) + WARN_AND_CONTINUE; + + HighScoreList &hsl = m_CourseHighScores[courseID].m_TrailHighScores[trailID].hs; + hsl.LoadFromNode( pHighScoreListNode ); } } } @@ -1622,30 +1244,6 @@ void Profile::LoadCategoryScoresFromNode( const XNode* pNode ) } } -void Profile::DeleteProfileDataFromDirSM390a12( CString sDir ) const -{ - CString fn = sDir + SM_390A12_PROFILE_INI; - FILEMAN->Remove( fn ); -} - -void Profile::DeleteSongScoresFromDirSM390a12( CString sDir ) const -{ - CString fn = sDir + SM_390A12_SONG_SCORES_DAT; - FILEMAN->Remove( fn ); -} - -void Profile::DeleteCourseScoresFromDirSM390a12( CString sDir ) const -{ - CString fn = sDir + SM_390A12_COURSE_SCORES_DAT; - FILEMAN->Remove( fn ); -} - -void Profile::DeleteCategoryScoresFromDirSM390a12( CString sDir ) const -{ - CString fn = sDir + SM_390A12_CATEGORY_SCORES_DAT; - FILEMAN->Remove( fn ); -} - void Profile::SaveStatsWebPageToDir( CString sDir ) const { ASSERT( PROFILEMAN ); @@ -2084,10 +1682,11 @@ XNode* Profile::SaveRecentCourseScoresCreateNode() const return pNode; } -void Profile::AddCourseRecentScore( const Course* pCourse, StepsType st, CourseDifficulty cd, HighScore hs ) +void Profile::AddCourseRecentScore( const Course* pCourse, const Trail* pTrail, HighScore hs ) { HighScoreForACourse h; h.courseID.FromCourse( pCourse ); + h.trailID.FromTrail( pTrail ); h.hs = hs; m_vRecentCourseScores.push_back( h ); } @@ -2100,3 +1699,12 @@ const Profile::HighScoresForASong *Profile::GetHighScoresForASong( const SongID& return NULL; return &it->second; } + +const Profile::HighScoresForACourse *Profile::GetHighScoresForACourse( const CourseID& courseID ) const +{ + std::map::const_iterator it; + it = m_CourseHighScores.find( courseID ); + if( it == m_CourseHighScores.end() ) + return NULL; + return &it->second; +}