diff --git a/stepmania/src/Course.cpp b/stepmania/src/Course.cpp index 4e4916beeb..e4bc66bbf2 100644 --- a/stepmania/src/Course.cpp +++ b/stepmania/src/Course.cpp @@ -256,6 +256,11 @@ void Course::LoadFromCRSFile( CString sPath ) m_sMainTitleTranslit = title.TitleTranslit; } +void Course::RevertFromDisk() +{ + LoadFromCRSFile( m_sPath ); +} + void Course::Init() { m_bIsAutogen = false; @@ -898,9 +903,9 @@ void Course::GetTrails( vector &AddTo, StepsType st ) const bool Course::HasMods() const { - for( unsigned i=0; imodifiers.empty() || !e->attacks.empty() ) return true; } @@ -909,17 +914,44 @@ bool Course::HasMods() const bool Course::AllSongsAreFixed() const { - for( unsigned i=0; itype != COURSE_ENTRY_FIXED ) return false; } return true; } -void Course::RegenTrails() +void Course::Invalidate( Song *pStaleSong ) { - ZERO( m_TrailCacheValid ); + FOREACH_CONST( CourseEntry, m_entries, e ) + { + if( e->pSong == pStaleSong ) // a fixed entry that references the stale Song + { + RevertFromDisk(); + return; + } + } + + // Invalidate any Trails that contain this song. + // If we find a Trail that contains this song, then it's part of a + // non-fixed entry. So, regenerating the Trail will force different + // songs to be chosen. + FOREACH_StepsType( st ) + FOREACH_ShownCourseDifficulty( cd ) + if( m_TrailCacheValid[st][cd] && !m_TrailCacheNull[st][cd] ) + if( GetTrail( st, cd )->ContainsSong( pStaleSong ) ) + m_TrailCacheValid[st][cd] = false; +} + +void Course::RegenerateNonFixedTrails() +{ + // Only need to regen Trails if the Course has a random entry. + // We can create these Trails on demand because we don't + // calculate RadarValues for Trails with one or more non-fixed + // entry. + if( !IsFixed() ) + ZERO( m_TrailCacheValid ); } RageColor Course::GetColor() const diff --git a/stepmania/src/Course.h b/stepmania/src/Course.h index 6fa2ea816a..574dec8b29 100644 --- a/stepmania/src/Course.h +++ b/stepmania/src/Course.h @@ -127,6 +127,7 @@ public: bool IsFixed() const; void LoadFromCRSFile( CString sPath ); + void RevertFromDisk(); void Init(); void Save(); void AutogenEndlessFromGroup( CString sGroupName, Difficulty dc ); @@ -140,8 +141,11 @@ public: void UpdateCourseStats( StepsType st ); - /* Call to generate Trails with random entries and if song or notes pointers change. */ - void RegenTrails(); + /* Call to regenerate Trails with random entries */ + void RegenerateNonFixedTrails(); + + /* Call when a Song or its Steps are deleted/changed. */ + void Invalidate( Song *pStaleSong ); private: bool GetTrailUnsorted( StepsType st, CourseDifficulty cd, Trail &trail ) const; diff --git a/stepmania/src/GameState.cpp b/stepmania/src/GameState.cpp index e2ba18cc10..1ba10b2ee6 100644 --- a/stepmania/src/GameState.cpp +++ b/stepmania/src/GameState.cpp @@ -150,7 +150,7 @@ void GameState::Reset() /* We may have cached trails from before everything was loaded (eg. from before * SongManager::UpdateBest could be called). Erase the cache. */ - SONGMAN->FlushCaches(); + SONGMAN->RegenerateNonFixedCourses(); g_vPlayedStageStats.clear(); diff --git a/stepmania/src/ScreenGameplay.cpp b/stepmania/src/ScreenGameplay.cpp index dc5f356e1e..9365a479a2 100644 --- a/stepmania/src/ScreenGameplay.cpp +++ b/stepmania/src/ScreenGameplay.cpp @@ -1815,15 +1815,14 @@ void SaveChanges( void* papSongsQueue ) void RevertChanges( void* papSongsQueue ) { vector& apSongsQueue = *(vector*)papSongsQueue; - for( unsigned i=0; iRevertFromDisk(); + FOREACH( Song*, apSongsQueue, pSong ) + { + (*pSong)->RevertFromDisk(); - // We need to regen any Courses that have any of the songs we just reloaded. - // Regen all Courses for now. - vector vpAllCourses; - SONGMAN->GetAllCourses( vpAllCourses, true ); - FOREACH( Course*, vpAllCourses, pCourse ) - (*pCourse)->RegenTrails(); + // We need to regen any Courses that have any of the songs we just reloaded. + // Regen all Courses for now. + SONGMAN->Invalidate( *pSong ); + } } void ScreenGameplay::ShowSavePrompt( ScreenMessage SM_SendWhenDone ) diff --git a/stepmania/src/Song.cpp b/stepmania/src/Song.cpp index 224af9ee41..9320fb4db2 100644 --- a/stepmania/src/Song.cpp +++ b/stepmania/src/Song.cpp @@ -86,7 +86,9 @@ Song::~Song() m_vpSteps.clear(); /* We deleted some Steps*; clear stuff that used it. */ - SONGMAN->FlushCaches(); + /* Don't make Song depend on SongManager. It's leading to some + * confusing limitation on what can be done in SONGMAN->FlushCaches(). */ + SONGMAN->Invalidate( this ); } /* Reset to an empty song. */ @@ -103,7 +105,7 @@ void Song::Reset() /* Courses cache Notes* pointers. On the off chance that this isn't the last * thing this screen does, clear that cache. */ - SONGMAN->FlushCaches(); + SONGMAN->Invalidate( this ); } @@ -348,7 +350,7 @@ void Song::RevertFromDisk( bool bAllowNotesLoss ) } } - StepsID::FlushCache(); + StepsID::Invalidate( this ); } diff --git a/stepmania/src/SongManager.cpp b/stepmania/src/SongManager.cpp index cfaa7f2403..4055b1a196 100644 --- a/stepmania/src/SongManager.cpp +++ b/stepmania/src/SongManager.cpp @@ -28,6 +28,7 @@ #include "RageFileManager.h" #include "UnlockSystem.h" #include "CatalogXml.h" +#include "Foreach.h" SongManager* SONGMAN = NULL; // global and accessable from anywhere in our program @@ -78,8 +79,8 @@ SongManager::SongManager() SongManager::~SongManager() { - FreeSongs(); FreeCourses(); + FreeSongs(); } void SongManager::InitAll( LoadingWindow *ld ) @@ -665,13 +666,19 @@ void SongManager::Cleanup() /* Flush all Song*, Steps* and Course* caches. This is called on reload, and when * any of those are removed or changed. This doesn't touch GAMESTATE and StageStats * pointers, which are updated explicitly in Song::RevertFromDisk. */ -void SongManager::FlushCaches() +void SongManager::Invalidate( Song *pStaleSong ) { /* Erase cached course info. */ - for( unsigned i=0; i < m_pCourses.size(); i++ ) - m_pCourses[i]->RegenTrails(); + FOREACH_CONST( Course*, m_pCourses, c ) + (*c)->Invalidate( pStaleSong ); - StepsID::FlushCache(); + StepsID::Invalidate( pStaleSong ); +} + +void SongManager::RegenerateNonFixedCourses() +{ + for( unsigned i=0; i < m_pCourses.size(); i++ ) + m_pCourses[i]->RegenerateNonFixedTrails(); } void SongManager::SetPreferences() diff --git a/stepmania/src/SongManager.h b/stepmania/src/SongManager.h index c5934c7966..61ea8fb812 100644 --- a/stepmania/src/SongManager.h +++ b/stepmania/src/SongManager.h @@ -25,7 +25,10 @@ public: void InitSongsFromDisk( LoadingWindow *ld ); void FreeSongs(); void Cleanup(); - void FlushCaches(); + + void Invalidate( Song *pStaleSong ); + + void RegenerateNonFixedCourses(); void SetPreferences(); void LoadAllFromProfiles(); // song, edits diff --git a/stepmania/src/StepsUtil.cpp b/stepmania/src/StepsUtil.cpp index c18bda9d08..768f64b4f6 100644 --- a/stepmania/src/StepsUtil.cpp +++ b/stepmania/src/StepsUtil.cpp @@ -184,8 +184,9 @@ XNode* StepsID::CreateNode() const } -void StepsID::FlushCache() +void StepsID::Invalidate( Song *pStaleSong ) { + // FIXME: Only flush entries with the stale song g_StepsIDCache.clear(); } diff --git a/stepmania/src/StepsUtil.h b/stepmania/src/StepsUtil.h index 2546c38fba..39a77b6af4 100644 --- a/stepmania/src/StepsUtil.h +++ b/stepmania/src/StepsUtil.h @@ -39,7 +39,7 @@ public: void LoadFromNode( const XNode* pNode ); CString ToString() const; bool IsValid() const; - static void FlushCache(); + static void Invalidate( Song *pStaleSong ); }; #endif diff --git a/stepmania/src/StyleUtil.h b/stepmania/src/StyleUtil.h index a6016d37c5..1e129cdb84 100644 --- a/stepmania/src/StyleUtil.h +++ b/stepmania/src/StyleUtil.h @@ -20,7 +20,7 @@ public: XNode* CreateNode() const; void LoadFromNode( const XNode* pNode ); bool IsValid() const; - static void FlushCache(); + static void FlushCache( Song* pStaleSong ); }; #endif diff --git a/stepmania/src/Trail.cpp b/stepmania/src/Trail.cpp index a83512cb1e..6a418e417d 100644 --- a/stepmania/src/Trail.cpp +++ b/stepmania/src/Trail.cpp @@ -51,7 +51,14 @@ bool TrailEntry::ContainsTransformOrTurn() const RadarValues Trail::GetRadarValues() const { - if( m_bRadarValuesCached ) + if( IsMystery() ) + { + // Don't calculate RadarValues for a non-fixed Course. They values are + // worthless because they'll change every time this Trail is + // regenerated. + return RadarValues(); + } + else if( m_bRadarValuesCached ) { return m_CachedRadarValues; } @@ -152,6 +159,26 @@ void Trail::GetDisplayBpms( DisplayBpms &AddTo ) } } +bool Trail::IsMystery() const +{ + FOREACH_CONST( TrailEntry, m_vEntries, e ) + { + if( e->bMystery ) + return true; + } + return false; +} + +bool Trail::ContainsSong( Song* pSong ) const +{ + FOREACH_CONST( TrailEntry, m_vEntries, e ) + { + if( e->pSong == pSong ) + return true; + } + return false; +} + /* * (c) 2001-2004 Chris Danford, Glenn Maynard * All rights reserved. diff --git a/stepmania/src/Trail.h b/stepmania/src/Trail.h index 82a1309d2d..8e76ca84c5 100644 --- a/stepmania/src/Trail.h +++ b/stepmania/src/Trail.h @@ -66,6 +66,8 @@ public: int GetTotalMeter() const; float GetLengthSeconds() const; void GetDisplayBpms( DisplayBpms &AddTo ); + bool IsMystery() const; + bool ContainsSong( Song* pSong ) const; }; #endif diff --git a/stepmania/src/TrailUtil.h b/stepmania/src/TrailUtil.h index cd5fd09e40..5131a1a34e 100644 --- a/stepmania/src/TrailUtil.h +++ b/stepmania/src/TrailUtil.h @@ -3,6 +3,7 @@ #include "GameConstantsAndTypes.h" +class Song; class Trail; class Course; struct XNode; @@ -24,7 +25,7 @@ public: void LoadFromNode( const XNode* pNode ); CString ToString() const; bool IsValid() const; - static void FlushCache(); + static void Invalidate( Song* pStaleSong ); }; #endif