From 56bb3e8445e4605bba5c7d7f771ebd62c82f32c8 Mon Sep 17 00:00:00 2001 From: AJ Kelly Date: Tue, 8 Mar 2011 21:09:38 -0600 Subject: [PATCH] sm5svn 0dc297b [Glenn Maynard] "Previously, we didn't create MusicWheel sorts when the screen loads; it was delayed until the screen begins. This allowed preloading before the style is set. However, it caused a major skip when the screen starts, because creating the sorts is fairly expensive. Refactor this. Load the sorts when the screen is loaded, and then go through them and quickly filter out unplayable data and handle other initialization on begin. This is much faster, so we can more easily transition seamlessly from the previous menu. One known limitation: the sorts are created before we know the style, so we have to guess. This means if you're in a style like dance-solo or pump-halfdouble, sorts will still be based on regular mode. This affects the difficulty, top grade and roulette sorts." --- Docs/Changelog_sm-ssc.txt | 14 ++ src/MusicWheel.cpp | 356 +++++++++++++++++++++----------------- src/MusicWheel.h | 5 +- src/SongUtil.cpp | 61 ++++--- 4 files changed, 252 insertions(+), 184 deletions(-) diff --git a/Docs/Changelog_sm-ssc.txt b/Docs/Changelog_sm-ssc.txt index 0275ae24e7..4f9c28b3c0 100644 --- a/Docs/Changelog_sm-ssc.txt +++ b/Docs/Changelog_sm-ssc.txt @@ -21,6 +21,20 @@ sm-ssc v1.2.3 | 201103?? * [MeterDisplay] Add Lua binding. "Allow setting and changing the width dynamically. Phase out the "StreamWidth" node property; set it with SetStreamWidth instead." [Glenn Maynard] +* sm5svn r28280: "Previously, we didn't create MusicWheel sorts when the screen + loads; it was delayed until the screen begins. This allowed preloading before + the style is set. However, it caused a major skip when the screen starts, + because creating the sorts is fairly expensive. + + Refactor this. Load the sorts when the screen is loaded, and then go through + them and quickly filter out unplayable data and handle other initialization + on begin. This is much faster, so we can more easily transition seamlessly + from the previous menu. + + One known limitation: the sorts are created before we know the style, so we + have to guess. This means if you're in a style like dance-solo or + pump-halfdouble, sorts will still be based on regular mode. This affects the + difficulty, top grade and roulette sorts." [Glenn Maynard] 20110305 -------- diff --git a/src/MusicWheel.cpp b/src/MusicWheel.cpp index d08d8b3df2..1428275d37 100644 --- a/src/MusicWheel.cpp +++ b/src/MusicWheel.cpp @@ -113,25 +113,31 @@ void MusicWheel::Load( RString sType ) * stable_sort) from its output, and title will be the secondary sort, without having * to re-sort by title each time. */ SONGMAN->SortSongs(); -} -void MusicWheel::BeginScreen() -{ RageTimer timer; RString times; /* Build all of the wheel item data. Do this after selecting the extra stage, * so it knows to always display it. */ FOREACH_ENUM( SortOrder, so ) { - BuildWheelItemDatas( m_WheelItemDatas[so], so ); + BuildWheelItemDatas( m_UnfilteredWheelItemDatas[so], so ); times += ssprintf( "%i:%.3f ", so, timer.GetDeltaTime() ); } LOG->Trace( "MusicWheel sorting took: %s", times.c_str() ); +} + +void MusicWheel::BeginScreen() +{ + FOREACH_ENUM( SortOrder, so ) + { + m_UnfilteredWheelItemDatas[so] = m_UnfilteredWheelItemDatas[so]; + UpdateWheelItemDatas( so ); + } /* Set m_LastModeMenuItem to the first item that matches the current mode. (Do this * after building wheel item data.) */ { - const vector &from = m_WheelItemDatas[SORT_MODE_MENU]; + const vector &from = m_UnfilteredWheelItemDatas[SORT_MODE_MENU]; for( unsigned i=0; im_pAction ); @@ -228,7 +234,7 @@ void MusicWheel::BeginScreen() MusicWheel::~MusicWheel() { FOREACH_ENUM( SortOrder, so ) - FOREACH( MusicWheelItemData*, m_WheelItemDatas[so], i ) + FOREACH( MusicWheelItemData*, m_UnfilteredWheelItemDatas[so], i ) delete *i; } @@ -247,7 +253,7 @@ bool MusicWheel::SelectSongOrCourse() return true; // Select the first selectable song based on the sort order... - vector &wiWheelItems = m_WheelItemDatas[GAMESTATE->m_SortOrder]; + vector &wiWheelItems = m_UnfilteredWheelItemDatas[GAMESTATE->m_SortOrder]; for( unsigned i = 0; i < wiWheelItems.size(); i++ ) { if( wiWheelItems[i]->m_pSong ) @@ -280,7 +286,7 @@ bool MusicWheel::SelectSong( const Song *p ) return false; unsigned i; - vector &from = m_WheelItemDatas[GAMESTATE->m_SortOrder]; + vector &from = m_UnfilteredWheelItemDatas[GAMESTATE->m_SortOrder]; for( i=0; im_pSong == p ) @@ -308,7 +314,7 @@ bool MusicWheel::SelectCourse( const Course *p ) return false; unsigned i; - vector &from = m_WheelItemDatas[GAMESTATE->m_SortOrder]; + vector &from = m_UnfilteredWheelItemDatas[GAMESTATE->m_SortOrder]; for( i=0; im_pCourse == p ) @@ -335,7 +341,7 @@ bool MusicWheel::SelectModeMenuItem() { /* Select the last-chosen option. */ ASSERT( GAMESTATE->m_SortOrder == SORT_MODE_MENU ); - const vector &from = m_WheelItemDatas[GAMESTATE->m_SortOrder]; + const vector &from = m_UnfilteredWheelItemDatas[GAMESTATE->m_SortOrder]; unsigned i; for( i=0; i &arraySongs, SortOrder so ) -{ - vector apAllSongs; - switch( so ) - { - case SORT_PREFERRED: - SONGMAN->GetPreferredSortSongs( apAllSongs ); - break; - case SORT_POPULARITY: - SONGMAN->GetPopularSongs(); - break; - case SORT_GROUP: - // if we're not using sections with a preferred song group, and there - // is a group to load, only load those songs. -aj - if(GAMESTATE->m_sPreferredSongGroup != GROUP_ALL && !USE_SECTIONS_WITH_PREFERRED_GROUP ) - { - apAllSongs = SONGMAN->GetSongs(GAMESTATE->m_sPreferredSongGroup); - break; - } - // otherwise fall through - default: - apAllSongs = SONGMAN->GetAllSongs(); - break; - } - - // filter songs that we don't have enough stages to play - { - vector vTempSongs; - SongCriteria sc; - sc.m_iMaxStagesForSong = GAMESTATE->GetSmallestNumStagesLeftForAnyHumanPlayer(); - SongUtil::FilterSongs( sc, apAllSongs, vTempSongs ); - apAllSongs = vTempSongs; - } - - // copy only songs that have at least one Steps for the current GameMode - for( unsigned i=0; iSongIsLocked( pSong ); - if( iLocked & LOCKED_DISABLED ) - continue; - - // If we're on an extra stage, and this song is selected, ignore #SELECTABLE. - if( pSong != GAMESTATE->m_pCurSong || !GAMESTATE->IsAnExtraStage() ) - { - // Hide songs that asked to be hidden via #SELECTABLE. - if( iLocked & LOCKED_SELECTABLE ) - continue; - if( so != SORT_ROULETTE && iLocked & LOCKED_ROULETTE ) - continue; - } - - /* Hide locked songs. If RANDOM_PICKS_LOCKED_SONGS, hide in Roulette - * and Random, too. */ - if( (so!=SORT_ROULETTE || !RANDOM_PICKS_LOCKED_SONGS) && iLocked ) - continue; - - if( PREFSMAN->m_bOnlyPreferredDifficulties ) - { - // if the song has steps that fit the preferred difficulty of the default player - if( pSong->HasStepsTypeAndDifficulty( GAMESTATE->GetCurrentStyle()->m_StepsType,GAMESTATE->m_PreferredDifficulty[GAMESTATE->GetFirstHumanPlayer()] ) ) - arraySongs.push_back( pSong ); - } - else - { - if(CommonMetrics::AUTO_SET_STYLE) - { - // with AUTO_SET_STYLE on and Autogen off, some songs may get - // hidden. Search through every playable StepsType until you - // find one, then add the song. - // see Issue 147 for more information. -aj - // http://ssc.ajworld.net/sm-ssc/bugtracker/view.php?id=147 - set vStepsType; - SongUtil::GetPlayableStepsTypes( pSong, vStepsType ); - - FOREACHS( StepsType, vStepsType, st ) - { - if(pSong->HasStepsType(*st)) - { - arraySongs.push_back( pSong ); - break; - } - } - } - else - { - // If the song has at least one steps, add it. - if( pSong->HasStepsType(GAMESTATE->GetCurrentStyle()->m_StepsType) ) - arraySongs.push_back( pSong ); - } - } - } - - /* Hack: Add extra stage item if it was eliminated for any reason - * (eg. it's a long song). */ - if( GAMESTATE->IsAnExtraStage() ) - { - Song* pSong; - Steps* pSteps; - SONGMAN->GetExtraStageInfo( GAMESTATE->IsExtraStage2(), GAMESTATE->GetCurrentStyle(), pSong, pSteps ); - - if( find( arraySongs.begin(), arraySongs.end(), pSong ) == arraySongs.end() ) - arraySongs.push_back( pSong ); - } -} - void MusicWheel::BuildWheelItemDatas( vector &arrayWheelItemDatas, SortOrder so ) { switch( so ) { case SORT_MODE_MENU: { - arrayWheelItemDatas.clear(); // clear out the previous wheel items vector vsNames; split( MODE_MENU_CHOICE_NAMES, ",", vsNames ); for( unsigned i=0; i &arrayWheelIt case SORT_LENGTH: case SORT_RECENT: { - // Make an array of Song*, then sort them + // Get all songs that can be shown in this sort. Filtering songs + // that can't be played will happen later, in UpdateWheelItemDatas. vector arraySongs; - - GetSongList( arraySongs, so ); + switch( so ) + { + case SORT_PREFERRED: + SONGMAN->GetPreferredSortSongs( arraySongs ); + break; + case SORT_POPULARITY: + arraySongs = SONGMAN->GetPopularSongs(); + break; + default: + arraySongs = SONGMAN->GetAllSongs(); + break; + } bool bUseSections = true; @@ -522,11 +431,16 @@ void MusicWheel::BuildWheelItemDatas( vector &arrayWheelIt // obey order specified by the preferred sort list break; case SORT_ROULETTE: - SongUtil::SortSongPointerArrayByStepsTypeAndMeter( arraySongs, GAMESTATE->m_pCurStyle->m_StepsType, Difficulty_Easy ); + { + StepsType st; + Difficulty dc; + SongUtil::GetStepsTypeAndDifficultyFromSortOrder( SORT_EASY_METER, st, dc ); + SongUtil::SortSongPointerArrayByStepsTypeAndMeter( arraySongs, st, dc ); if( (bool)PREFSMAN->m_bPreferredSortUsesGroups ) stable_sort( arraySongs.begin(), arraySongs.end(), SongUtil::CompareSongPointersByGroup ); bUseSections = false; break; + } case SORT_GROUP: SongUtil::SortSongPointerArrayByGroupAndTitle( arraySongs ); if(USE_SECTIONS_WITH_PREFERRED_GROUP) @@ -631,15 +545,6 @@ void MusicWheel::BuildWheelItemDatas( vector &arrayWheelIt { int iSectionCount = 0; - // Count songs in this section - unsigned j; - for( j=i; j < arraySongs.size(); j++ ) - { - if( SongUtil::GetSectionNameFromSongAndSort( arraySongs[j], so ) != sThisSection ) - break; - } - iSectionCount = j-i; - // new section, make a section item // todo: preferred sort section color handling? -aj RageColor colorSection = (so==SORT_GROUP) ? SONGMAN->GetSongGroupColor(pSong->m_sGroupName) : SECTION_COLORS.GetValue(iSectionColorIndex); @@ -647,7 +552,7 @@ void MusicWheel::BuildWheelItemDatas( vector &arrayWheelIt // In certain situations (e.g. simulating Pump it Up), themes may // want to only show one group at a time. if( !HIDE_INACTIVE_SECTIONS ) - arrayWheelItemDatas.push_back( new MusicWheelItemData(TYPE_SECTION, NULL, sThisSection, NULL, colorSection, iSectionCount) ); + arrayWheelItemDatas.push_back( new MusicWheelItemData(TYPE_SECTION, NULL, sThisSection, NULL, colorSection, 0) ); sLastSection = sThisSection; } } @@ -659,16 +564,10 @@ void MusicWheel::BuildWheelItemDatas( vector &arrayWheelIt if( SHOW_ROULETTE ) arrayWheelItemDatas.push_back( new MusicWheelItemData(TYPE_ROULETTE, NULL, "", NULL, ROULETTE_COLOR, 0) ); - // Only add TYPE_PORTAL if there's at least one song on the list. - bool bFoundAnySong = false; - for( unsigned i=0; !bFoundAnySong && i < arrayWheelItemDatas.size(); i++ ) - if( arrayWheelItemDatas[i]->m_Type == TYPE_SONG ) - bFoundAnySong = true; - - if( SHOW_RANDOM && bFoundAnySong ) + if( SHOW_RANDOM ) arrayWheelItemDatas.push_back( new MusicWheelItemData(TYPE_RANDOM, NULL, "", NULL, RANDOM_COLOR, 0) ); - if( SHOW_PORTAL && bFoundAnySong ) + if( SHOW_PORTAL ) arrayWheelItemDatas.push_back( new MusicWheelItemData(TYPE_PORTAL, NULL, "", NULL, PORTAL_COLOR, 0) ); // add custom wheel items @@ -769,8 +668,6 @@ void MusicWheel::BuildWheelItemDatas( vector &arrayWheelIt if( so == SORT_ALL_COURSES ) CourseUtil::SortCoursePointerArrayByType( apCourses ); - arrayWheelItemDatas.clear(); // clear out the previous wheel items - RString sLastSection = ""; int iSectionColorIndex = 0; for( unsigned i=0; i &arrayWheelIt } } - // check that this course has at least one song playable in the current style - if( !pCourse->IsPlayableIn(GAMESTATE->GetCurrentStyle()->m_StepsType) ) - continue; - if( sThisSection != sLastSection ) // new section, make a section item { RageColor c = SECTION_COLORS.GetValue(iSectionColorIndex); @@ -817,7 +710,6 @@ void MusicWheel::BuildWheelItemDatas( vector &arrayWheelIt MusicWheelItemData& WID = *arrayWheelItemDatas[i]; if( WID.m_pSong != NULL ) { - WID.m_Flags.bHasBeginnerOr1Meter = WID.m_pSong->IsEasy( GAMESTATE->GetCurrentStyle()->m_StepsType ) && SHOW_EASY_FLAG; WID.m_Flags.bEdits = false; set vStepsType; SongUtil::GetPlayableStepsTypes( WID.m_pSong, vStepsType ); @@ -827,25 +719,171 @@ void MusicWheel::BuildWheelItemDatas( vector &arrayWheelIt } else if( WID.m_pCourse != NULL ) { - WID.m_Flags.bHasBeginnerOr1Meter = false; WID.m_Flags.bEdits = WID.m_pCourse->IsAnEdit(); WID.m_Flags.iStagesForSong = 1; } } +} - // init crowns +/* The screen is starting. Take m_UnfilteredWheelItemDatas created on load by + * BuildWheelItemDatas and update them for the current state. Output the + * results into m_WheelItemDatas. */ +void MusicWheel::UpdateWheelItemDatas( SortOrder so ) +{ + vector &aWheelItemDatas = m_UnfilteredWheelItemDatas[so]; + + // Only add TYPE_PORTAL if there's at least one song on the list. + bool bFoundAnySong = false; + for( unsigned i=0; !bFoundAnySong && i < aWheelItemDatas.size(); i++ ) + if( aWheelItemDatas[i]->m_Type == TYPE_SONG ) + bFoundAnySong = true; + + vector aiRemove; + aiRemove.insert( aiRemove.begin(), aWheelItemDatas.size(), false ); + + SongCriteria sc; + sc.m_iMaxStagesForSong = GAMESTATE->GetSmallestNumStagesLeftForAnyHumanPlayer(); + + Song *pExtraStageSong = NULL; + if( GAMESTATE->IsAnExtraStage() ) + { + Steps *pSteps; + SONGMAN->GetExtraStageInfo( GAMESTATE->IsExtraStage2(), GAMESTATE->GetCurrentStyle(), pExtraStageSong, pSteps ); + } + + // Mark any songs that aren't playable in aiRemove. + for( unsigned i=0; i< aWheelItemDatas.size(); i++ ) + { + MusicWheelItemData& WID = *aWheelItemDatas[i]; + + // If we have no songs, remove Random and Portal. + if( WID.m_Type == TYPE_RANDOM || WID.m_Type == TYPE_PORTAL ) + { + if( !bFoundAnySong ) + aiRemove[i] = true; + continue; + } + + // Filter songs that we don't have enough stages to play. + if( WID.m_Type == TYPE_SONG ) + { + Song* pSong = WID.m_pSong; + + // Never remove the extra stage song. + if( pExtraStageSong && WID.m_pSong == pExtraStageSong ) + continue; + + // Check that we have enough stages to play this song, and that it's not disabled. + if( !sc.Matches(WID.m_pSong) ) + { + aiRemove[i] = true; + continue; + } + + int iLocked = UNLOCKMAN->SongIsLocked( pSong ); + + // If we're on an extra stage, and this song is selected, ignore #SELECTABLE. + if( pSong != GAMESTATE->m_pCurSong || !GAMESTATE->IsAnExtraStage() ) + { + // Hide songs that asked to be hidden via #SELECTABLE. + if( iLocked & LOCKED_SELECTABLE ) + { + aiRemove[i] = true; + continue; + } + if( so != SORT_ROULETTE && iLocked & LOCKED_ROULETTE ) + { + aiRemove[i] = true; + continue; + } + } + + /* Hide locked songs. If RANDOM_PICKS_LOCKED_SONGS, hide in Roulette + * and Random, too. */ + if( (so!=SORT_ROULETTE || !RANDOM_PICKS_LOCKED_SONGS) && iLocked ) + { + aiRemove[i] = true; + continue; + } + + // If the song has no steps for the current style, remove it. + if( !pSong->HasStepsType(GAMESTATE->GetCurrentStyle()->m_StepsType) ) + { + aiRemove[i] = true; + continue; + } + } + + if( WID.m_Type == TYPE_COURSE ) + { + if( !WID.m_pCourse->IsPlayableIn(GAMESTATE->GetCurrentStyle()->m_StepsType) ) + aiRemove[i] = true; + } + } + + // Filter out the songs we're removing. + vector &aFilteredData = m_WheelItemDatas[so]; + aFilteredData.reserve( aWheelItemDatas.size() ); + for( unsigned i=0; i< aWheelItemDatas.size(); i++ ) + { + if( aiRemove[i] ) + continue; + aFilteredData.push_back( aWheelItemDatas[i] ); + } + + // Update the song count in each section header. + for( unsigned i=0; i < aFilteredData.size(); ) + { + MusicWheelItemData& WID = *aFilteredData[i]; + ++i; + if( WID.m_Type != TYPE_SECTION ) + continue; + + // Count songs in this section + WID.m_iSectionCount = 0; + for( ; i < aFilteredData.size() && aFilteredData[i]->m_sText == WID.m_sText; ++i ) + ++WID.m_iSectionCount; + } + + // If we have any section headers with no songs, then we filtered all of + // the songs in that group, so remove it. This isn't optimized like the + // above since this is a rare case. + for( unsigned i=0; i < aFilteredData.size(); ++i ) + { + MusicWheelItemData& WID = *aFilteredData[i]; + if( WID.m_Type != TYPE_SECTION ) + continue; + if( WID.m_iSectionCount > 0 ) + continue; + aFilteredData.erase( aFilteredData.begin()+i, aFilteredData.begin()+i+1 ); + --i; + } + + // Update the popularity. This is affected by filtering. if( so == SORT_POPULARITY ) { - // init crown icons - for( unsigned i=0; i< min(3u,arrayWheelItemDatas.size()); i++ ) + for( unsigned i=0; i< min(3u,aFilteredData.size()); i++ ) { - MusicWheelItemData& WID = *arrayWheelItemDatas[i]; + MusicWheelItemData& WID = *aFilteredData[i]; WID.m_Flags.iPlayersBestNumber = i+1; } } - if( arrayWheelItemDatas.empty() ) - arrayWheelItemDatas.push_back( new MusicWheelItemData(TYPE_SECTION, NULL, "- EMPTY -", NULL, RageColor(1,0,0,1), 0) ); + // Update the easy status. This is affected by the steps type. + if( SHOW_EASY_FLAG ) + { + for( unsigned i=0; iIsEasy( GAMESTATE->GetCurrentStyle()->m_StepsType ); + } + } + + // If we've filtered all items, insert a dummy. + if( aFilteredData.empty() ) + aFilteredData.push_back( new MusicWheelItemData(TYPE_SECTION, NULL, "- EMPTY -", NULL, RageColor(1,0,0,1), 0) ); } void MusicWheel::UpdateSwitch() @@ -973,7 +1011,7 @@ bool MusicWheel::ChangeSort( SortOrder new_so ) // return true if change success return false; // Don't change to SORT_MODE_MENU if it doesn't have at least two choices. - if( new_so == SORT_MODE_MENU && m_WheelItemDatas[new_so].size() < 2 ) + if( new_so == SORT_MODE_MENU && m_UnfilteredWheelItemDatas[new_so].size() < 2 ) return false; switch( m_WheelState ) @@ -1109,7 +1147,7 @@ void MusicWheel::StartRandom() { // Shuffle and use the roulette wheel. RandomGen rnd; - random_shuffle( m_WheelItemDatas[SORT_ROULETTE].begin(), m_WheelItemDatas[SORT_ROULETTE].end(), rnd ); + random_shuffle( m_UnfilteredWheelItemDatas[SORT_ROULETTE].begin(), m_UnfilteredWheelItemDatas[SORT_ROULETTE].end(), rnd ); GAMESTATE->m_SortOrder.Set( SORT_ROULETTE ); } else @@ -1147,7 +1185,7 @@ void MusicWheel::SetOpenSection( RString group ) GAMEMAN->GetCompatibleStyles( GAMESTATE->m_pCurGame, GAMESTATE->GetNumPlayersEnabled(), vpPossibleStyles ); m_CurWheelItemData.clear(); - vector &from = m_WheelItemDatas[GAMESTATE->m_SortOrder]; + vector &from = m_UnfilteredWheelItemDatas[GAMESTATE->m_SortOrder]; m_CurWheelItemData.reserve( from.size() ); for( unsigned i = 0; i < from.size(); ++i ) { @@ -1309,7 +1347,7 @@ void MusicWheel::PlayerJoined() // We need to rebuild the wheel item data in this situation. -aj if( !GAMESTATE->IsCourseMode() && !PREFSMAN->m_bAutogenSteps ) { - BuildWheelItemDatas( m_WheelItemDatas[GAMESTATE->m_SortOrder], GAMESTATE->m_SortOrder ); + BuildWheelItemDatas( m_UnfilteredWheelItemDatas[GAMESTATE->m_SortOrder], GAMESTATE->m_SortOrder ); } SetOpenSection( m_sExpandedSectionName ); @@ -1359,7 +1397,7 @@ Song *MusicWheel::GetPreferredSelectionForRandomOrPortal() } RString sPreferredGroup = m_sExpandedSectionName; - vector &wid = m_WheelItemDatas[GAMESTATE->m_SortOrder]; + vector &wid = m_UnfilteredWheelItemDatas[GAMESTATE->m_SortOrder]; StepsType st = GAMESTATE->GetCurrentStyle()->m_StepsType; diff --git a/src/MusicWheel.h b/src/MusicWheel.h index d282473b86..18088ff3d7 100644 --- a/src/MusicWheel.h +++ b/src/MusicWheel.h @@ -52,15 +52,16 @@ public: protected: MusicWheelItem *MakeItem(); - void GetSongList( vector &arraySongs, SortOrder so ); void BuildWheelItemDatas( vector &arrayWheelItems, SortOrder so ); + void UpdateWheelItemDatas( SortOrder so ); bool SelectSongOrCourse(); bool SelectCourse( const Course *p ); bool SelectModeMenuItem(); virtual void UpdateSwitch(); - vector m_WheelItemDatas[NUM_SortOrder]; + vector m_UnfilteredWheelItemDatas[NUM_SortOrder]; + vector m_WheelItemDatas[NUM_SortOrder]; // aliases into m_UnfilteredWheelItemDatas RString m_sLastModeMenuItem; SortOrder m_SortOrder; diff --git a/src/SongUtil.cpp b/src/SongUtil.cpp index 6e075c3334..6ea6b413c8 100644 --- a/src/SongUtil.cpp +++ b/src/SongUtil.cpp @@ -460,8 +460,12 @@ static bool CompAscending( const pair &a, const pair &vpSongsInOut, bool bDescending ) { - /* Optimize by pre-writing a string to compare, since doing GetNumNotesWithGrade - * inside the sort is too slow. */ + StepsType st; + Difficulty dc; + SongUtil::GetStepsTypeAndDifficultyFromSortOrder( SORT_EASY_METER, st, dc ); + + /* Optimize by pre-writing a string to compare, since doing + * GetNumNotesWithGrade inside the sort is too slow. */ typedef pair< Song *, RString > val; vector vals; vals.reserve( vpSongsInOut.size() ); @@ -472,10 +476,7 @@ void SongUtil::SortSongPointerArrayByGrades( vector &vpSongsInOut, bool b int iCounts[NUM_Grade]; const Profile *pProfile = PROFILEMAN->GetMachineProfile(); - ASSERT( pProfile ); // XXX: Debugging. - const Style *pStyle = GAMESTATE->GetCurrentStyle(); - ASSERT( pStyle ); // XXX: Debugging. - StepsType st = pStyle->m_StepsType; + ASSERT( pProfile ); pProfile->GetGrades( pSong, st, iCounts ); RString foo; @@ -620,8 +621,12 @@ RString SongUtil::GetSectionNameFromSongAndSort( const Song* pSong, SortOrder so return RString(); case SORT_TOP_GRADES: { + StepsType st; + Difficulty dc; + SongUtil::GetStepsTypeAndDifficultyFromSortOrder( so, st, dc ); + int iCounts[NUM_Grade]; - PROFILEMAN->GetMachineProfile()->GetGrades( pSong, GAMESTATE->GetCurrentStyle()->m_StepsType, iCounts ); + PROFILEMAN->GetMachineProfile()->GetGrades( pSong, st, iCounts ); for( int i=Grade_Tier01; iGetCurrentStyle()->m_StepsType; + bDoubles = false; break; case SORT_DOUBLE_EASY_METER: case SORT_DOUBLE_MEDIUM_METER: case SORT_DOUBLE_HARD_METER: case SORT_DOUBLE_CHALLENGE_METER: - stOut = GAMESTATE->GetCurrentStyle()->m_StepsType; // in case we don't find any matches below - vector vpStyles; - GAMEMAN->GetStylesForGame(GAMESTATE->m_pCurGame,vpStyles); - FOREACH_CONST( const Style*, vpStyles, i ) - { - if( (*i)->m_StyleType == StyleType_OnePlayerTwoSides ) - { - // Ugly hack to ignore pump's half-double. - bool bContainsHalf = ((RString)(*i)->m_szName).find("half") != RString::npos; - if( bContainsHalf ) - continue; - stOut = (*i)->m_StepsType; - break; - } - } + bDoubles = true; + break; + } + + stOut = StepsType_Invalid; + + vector vpStyles; + GAMEMAN->GetStylesForGame(GAMESTATE->m_pCurGame,vpStyles); + FOREACH_CONST( const Style*, vpStyles, i ) + { + if( !(*i)->m_bUsedForGameplay ) + continue; + + if( bDoubles && (*i)->m_StyleType != StyleType_OnePlayerTwoSides ) + continue; + if( !bDoubles && (*i)->m_StyleType != StyleType_OnePlayerOneSide && (*i)->m_StyleType != StyleType_TwoPlayersTwoSides ) + continue; + + // Ugly hack to ignore pump's half-double. + bool bContainsHalf = ((RString)(*i)->m_szName).find("half") != RString::npos; + if( bContainsHalf ) + continue; + + stOut = (*i)->m_StepsType; break; }