revert. Need a better approach.

This commit is contained in:
Glenn Maynard
2006-11-12 03:26:25 +00:00
parent 34ebb84f63
commit c6e62ae92d
13 changed files with 239 additions and 210 deletions
+2 -2
View File
@@ -349,7 +349,7 @@ bool Course::GetTrailSorted( StepsType st, CourseDifficulty cd, Trail &trail ) c
{
SortTrailEntry ste;
ste.entry = trail.m_vEntries[i];
ste.SortMeter = SortTrail.m_vEntries[i].GetSteps()->GetMeter();
ste.SortMeter = SortTrail.m_vEntries[i].pSteps->GetMeter();
entries.push_back( ste );
}
@@ -567,7 +567,7 @@ bool Course::GetTrailUnsorted( StepsType st, CourseDifficulty cd, Trail &trail )
TrailEntry te;
te.pSong = resolved.pSong;
te.SetSteps(resolved.pSteps);
te.pSteps = resolved.pSteps;
te.Modifiers = e->sModifiers;
te.Attacks = e->attacks;
te.bSecret = e->bSecret;
+1 -1
View File
@@ -173,7 +173,7 @@ void CourseEntryDisplay::SetFromGameState( int iCourseEntryIndex )
const TrailEntry *te = tes[pn];
if( te == NULL )
continue;
SetDifficulty( pn, ssprintf("%d", te->GetSteps()->GetMeter()), te->GetSteps()->GetDifficulty() );
SetDifficulty( pn, ssprintf("%d", te->pSteps->GetMeter()), te->pSteps->GetDifficulty() );
}
m_TextBanner.LoadFromSong( te->pSong );
+1 -1
View File
@@ -630,7 +630,7 @@ bool PlayerOptions::IsEasierForCourseAndTrail( Course* pCourse, Trail* pTrail )
FOREACH_CONST( TrailEntry, pTrail->m_vEntries, e )
{
if( e->pSong && IsEasierForSongAndSteps(e->pSong, e->GetSteps(), PLAYER_1) )
if( e->pSong && IsEasierForSongAndSteps(e->pSong, e->pSteps, PLAYER_1) )
return true;
}
return false;
+25 -46
View File
@@ -769,6 +769,9 @@ void ScreenEdit::Init()
ScreenEdit::~ScreenEdit()
{
// UGLY: Don't delete the Song's steps.
m_songLastSave.DetachSteps();
LOG->Trace( "ScreenEdit::~ScreenEdit()" );
m_soundMusic.StopPlaying();
}
@@ -2577,6 +2580,7 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM )
else if( SM == SM_SaveSuccessful )
{
LOG->Trace( "Save successful." );
m_pSteps->SetSavedToDisk( true );
CopyToLastSave();
SetDirty( false );
@@ -2598,24 +2602,17 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM )
// IMPORTANT: CopyFromLastSave before deleting the Steps below
CopyFromLastSave();
// We have to scroll through the entire Steps array because the user
// may have changed to a different stepchart after starting the edit.
vector<Steps*> vStepsToDelete;
for( vector<Steps*>::const_iterator it = GAMESTATE->m_pCurSong->GetAllSteps().begin();
it != GAMESTATE->m_pCurSong->GetAllSteps().end(); ++it )
// If these steps have never been saved, then we should delete them.
// If the user created them in the edit menu and never bothered
// to save them, then they aren't wanted.
Steps* pSteps = GAMESTATE->m_pCurSteps[PLAYER_1];
if( !pSteps->GetSavedToDisk() )
{
Steps *pSteps = *it;
if( !pSteps->GetSavedToDisk() && !pSteps->IsAutogen() )
{
vStepsToDelete.push_back( pSteps );
if( pSteps == GAMESTATE->m_pCurSteps[PLAYER_1] )
GAMESTATE->m_pCurSteps[PLAYER_1].Set( NULL );
if( pSteps == m_pSteps )
m_pSteps = NULL;
}
}
FOREACH( Steps*, vStepsToDelete, pSteps )
GAMESTATE->m_pCurSong->DeleteSteps( *pSteps );
Song* pSong = GAMESTATE->m_pCurSong;
pSong->DeleteSteps( pSteps );
m_pSteps = NULL;
GAMESTATE->m_pCurSteps[PLAYER_1].Set( NULL );
}
m_Out.StartTransitioning( SM_GoToNextScreen );
}
@@ -3432,23 +3429,16 @@ void ScreenEdit::SetupCourseAttacks()
void ScreenEdit::CopyToLastSave()
{
m_SongLastSave.DeepCopy( *GAMESTATE->m_pCurSong );
m_songLastSave = *GAMESTATE->m_pCurSong;
if( GAMESTATE->m_pCurSteps[PLAYER_1] )
m_stepsLastSave = *GAMESTATE->m_pCurSteps[PLAYER_1];
}
void ScreenEdit::CopyFromLastSave()
{
// We have to make sure the new m_pCurSteps pointer points to the correct Steps
// object. The Song copy destroys all of the old pointers.
StepsID id;
if( GAMESTATE->m_pCurSteps[PLAYER_1] )
id.FromSteps( GAMESTATE->m_pCurSteps[PLAYER_1] );
GAMESTATE->m_pCurSong->DeepCopy( m_SongLastSave );
if( id.IsValid() ) {
GAMESTATE->m_pCurSteps[PLAYER_1].Set( id.ToSteps( GAMESTATE->m_pCurSong, false ) );
m_pSteps = GAMESTATE->m_pCurSteps[PLAYER_1];
}
*GAMESTATE->m_pCurSong = m_songLastSave;
if( GAMESTATE->m_pCurSteps[PLAYER_1] )
*GAMESTATE->m_pCurSteps[PLAYER_1] = m_stepsLastSave;
}
void ScreenEdit::RevertFromDisk()
@@ -3458,25 +3448,14 @@ void ScreenEdit::RevertFromDisk()
id.FromSteps( GAMESTATE->m_pCurSteps[PLAYER_1] );
RString sSongDir = GAMESTATE->m_pCurSong->GetSongDir();
GAMESTATE->m_pCurSong->ReloadFromSongDir( sSongDir );
GAMESTATE->m_pCurSong->LoadFromSongDir( sSongDir );
if( id.IsValid() )
{
Steps *pChosenSteps = id.ToSteps( GAMESTATE->m_pCurSong, true );
if( pChosenSteps == NULL )
{
// This can happen in a couple ways. For example, the user might be editting a new
// stepchart and revert from disk.
pChosenSteps = new Steps();
pChosenSteps->CreateBlank( id.GetStepsType() );
pChosenSteps->SetDifficultyAndDescription( id.GetDifficulty(), id.GetDescription() );
GAMESTATE->m_pCurSong->AddSteps( pChosenSteps );
}
GAMESTATE->m_pCurSteps[PLAYER_1].Set( pChosenSteps );
m_pSteps = pChosenSteps;
}
GAMESTATE->m_pCurSteps[PLAYER_1].Set( id.ToSteps( GAMESTATE->m_pCurSong, false ) );
CopyToLastSave();
m_songLastSave = *GAMESTATE->m_pCurSong;
if( GAMESTATE->m_pCurSteps[PLAYER_1] )
m_stepsLastSave = *GAMESTATE->m_pCurSteps[PLAYER_1];
SetDirty(false);
}
+3 -2
View File
@@ -253,8 +253,9 @@ protected:
void CopyFromLastSave();
void RevertFromDisk();
Song m_SongLastSave;
Song m_songLastSave;
Steps m_stepsLastSave;
// for MODE_RECORD
+2 -7
View File
@@ -850,13 +850,8 @@ void ScreenGameplay::InitSongQueues()
pi->m_asModifiersQueue.clear();
FOREACH_CONST( TrailEntry, pTrail->m_vEntries, e )
{
// Here we assume there are never any NULL Steps in any Trails.
// This assumption can fail if we delete a Steps from a
// Song or revert a Song where the stepchart was deleted
// ouside the editor. In those cases: goodbye cruel world.
// TODO: fix that somehow
ASSERT( e->GetSteps() );
pi->m_vpStepsQueue.push_back( e->GetSteps() );
ASSERT( e->pSteps );
pi->m_vpStepsQueue.push_back( e->pSteps );
AttackArray a;
e->GetAttackArray( a );
pi->m_asModifiersQueue.push_back( a );
+24 -98
View File
@@ -42,8 +42,9 @@ static Preference<float> g_fMarathonVerSongSeconds( "MarathonVerSongSeconds", 60
Song::Song()
{
FOREACH_BackgroundLayer( i )
m_BackgroundChanges[i] = new VBackgroundChange;
m_ForegroundChanges = new VBackgroundChange;
m_BackgroundChanges[i] = AutoPtrCopyOnWrite<VBackgroundChange>(new VBackgroundChange);
m_ForegroundChanges = AutoPtrCopyOnWrite<VBackgroundChange>(new VBackgroundChange);
m_LoadedFromProfile = ProfileSlot_Invalid;
m_fMusicSampleStartSeconds = -1;
@@ -67,96 +68,34 @@ Song::~Song()
SAFE_DELETE( *s );
m_vpSteps.clear();
FOREACH_BackgroundLayer( i )
SAFE_DELETE( m_BackgroundChanges[i] );
SAFE_DELETE( m_ForegroundChanges );
// It's the responsibility of the owner of this Song to make sure
// that all pointers to this Song and its Steps are invalidated.
}
// Reset to an empty song.
void Song::DetachSteps()
{
m_vpSteps.clear();
FOREACH_StepsType( st )
m_vpStepsByType[st].clear();
}
/* Reset to an empty song. */
void Song::Reset()
{
FOREACH( Steps*, m_vpSteps, s )
SAFE_DELETE( *s );
m_vpSteps.clear();
FOREACH_StepsType( st )
m_vpStepsByType[st].clear();
Song empty;
this->DeepCopy(empty);
*this = empty;
// It's the responsibility of the owner of this Song to make sure
// that all pointers to this Song and its Steps are invalidated.
}
void Song::DeepCopy(const Song &song)
{
m_sSongFileName = song.m_sSongFileName;
m_sGroupName = song.m_sGroupName;
m_LoadedFromProfile = song.m_LoadedFromProfile;
m_bIsSymLink = song.m_bIsSymLink;
m_sMainTitle = song.m_sMainTitle;
m_sSubTitle = song.m_sSubTitle;
m_sArtist = song.m_sArtist;
m_sMainTitleTranslit = song.m_sMainTitleTranslit;
m_sSubTitleTranslit = song.m_sSubTitleTranslit;
m_sArtistTranslit = song.m_sArtistTranslit;
m_sGenre = song.m_sGenre;
m_sCredit = song.m_sCredit;
m_sMusicFile = song.m_sMusicFile;
m_fMusicLengthSeconds = song.m_fMusicLengthSeconds;
m_fFirstBeat = song.m_fFirstBeat;
m_fLastBeat = song.m_fLastBeat;
m_fSpecifiedLastBeat = song.m_fSpecifiedLastBeat;
m_fMusicSampleStartSeconds = song.m_fMusicSampleStartSeconds;
m_fMusicSampleLengthSeconds = song.m_fMusicSampleLengthSeconds;
m_DisplayBPMType = song.m_DisplayBPMType;
m_fSpecifiedBPMMin = song.m_fSpecifiedBPMMin;
m_fSpecifiedBPMMax = song.m_fSpecifiedBPMMax;
m_sBannerFile = song.m_sBannerFile;
m_sLyricsFile = song.m_sLyricsFile;
m_sBackgroundFile = song.m_sBackgroundFile;
m_sCDTitleFile = song.m_sCDTitleFile;
m_bHasMusic = song.m_bHasMusic;
m_bHasBanner = song.m_bHasBanner;
m_Timing = song.m_Timing;
FOREACH_BackgroundLayer( i )
*(m_BackgroundChanges[i]) = *(song.m_BackgroundChanges[i]);
*m_ForegroundChanges = *song.m_ForegroundChanges;
m_LyricSegments = song.m_LyricSegments;
m_vsKeysoundFile = song.m_vsKeysoundFile;
// First, get rid of all the old steps ...
FOREACH( Steps*, m_vpSteps, s )
SAFE_DELETE( *s );
m_vpSteps.clear();
FOREACH_StepsType( i )
m_vpStepsByType[i].clear();
// ... then create duplicates of the new steps, correctly arranging them in the m_vpStepsByType array
m_vpSteps.clear();
for( vector<Steps*>::const_iterator it = song.m_vpSteps.begin(); it != song.m_vpSteps.end(); ++it )
{
Steps *steps = new Steps( **it );
m_vpSteps.push_back( steps );
m_vpStepsByType[steps->m_StepsType].push_back( steps );
}
// TODO: This is horribly ugly. A much better solution is to make the Song class in charge of its
// own Steps cache. StepsID::ToSteps can simply reference the Song cache then.
StepsID::ClearCache();
// TODO: we have also ruined the pointers for GAMESTATE->m_pCurSteps, STATSMAN->m_CurStageStats.m_player[].vpPlayedSteps,
// STATSMAN->m_vPlayedStageStats->m_player[].vpPlayedSteps, and GAMESTATE->m_pEditSourceSteps. Probably we've also
// ruined other pointers aside from those. In general, we need to use StepsIDs everywhere instead of Step*s.
// FOR NOW this is not a problem, as the only place this copy is used is in the editor. The editor does not need any of
// the various GAMESTATE or STATSMAN pointers except for m_pCurSteps, which it already takes care of on its own.
// However, we have to fix this if we are going to use DeepCopy anywhere else.
}
void Song::AddBackgroundChange( BackgroundLayer iLayer, BackgroundChange seg )
{
// Delete old background change at this start beat, if any.
@@ -234,7 +173,7 @@ static set<RString> BlacklistedImages;
*
* If true, check the directory hash and reload the song from scratch if it's changed.
*/
bool Song::LoadFromSongDir( RString sDir, bool bIgnoreCache )
bool Song::LoadFromSongDir( RString sDir )
{
// LOG->Trace( "Song::LoadFromSongDir(%s)", sDir.c_str() );
ASSERT( sDir != "" );
@@ -257,7 +196,7 @@ bool Song::LoadFromSongDir( RString sDir, bool bIgnoreCache )
// First look in the cache for this song (without loading NoteData)
//
unsigned uCacheHash = SONGINDEX->GetCacheHash(m_sSongDir);
bool bUseCache = !bIgnoreCache;
bool bUseCache = true;
if( !DoesFileExist(GetCacheFilePath()) )
bUseCache = false;
if( !PREFSMAN->m_bFastLoad && GetHashForDirectory(m_sSongDir) != uCacheHash )
@@ -344,14 +283,6 @@ bool Song::LoadFromSongDir( RString sDir, bool bIgnoreCache )
return true; // do load this song
}
bool Song::ReloadFromSongDir( RString sDir )
{
// If we are loading from the song dir a second time around, the song is filled
// with all sorts of data we no longer want. Get rid of it.
Reset();
return LoadFromSongDir( sDir, true );
}
static void GetImageDirListing( RString sPath, vector<RString> &AddTo, bool bReturnPathToo=false )
{
GetDirListing( sPath + ".png", AddTo, false, bReturnPathToo );
@@ -812,12 +743,6 @@ void Song::Save()
else
FILEMAN->Remove( sOldPath );
}
// Now we need to mark all of the stepcharts as "saved to disk".
FOREACH( Steps*, m_vpSteps, steps )
{
(*steps)->SetSavedToDisk( true );
}
}
@@ -1038,7 +963,7 @@ const vector<BackgroundChange> &Song::GetBackgroundChanges( BackgroundLayer bl )
}
vector<BackgroundChange> &Song::GetBackgroundChanges( BackgroundLayer bl )
{
return *(m_BackgroundChanges[bl]);
return *(m_BackgroundChanges[bl].Get());
}
const vector<BackgroundChange> &Song::GetForegroundChanges() const
@@ -1047,7 +972,7 @@ const vector<BackgroundChange> &Song::GetForegroundChanges() const
}
vector<BackgroundChange> &Song::GetForegroundChanges()
{
return *m_ForegroundChanges;
return *m_ForegroundChanges.Get();
}
@@ -1158,6 +1083,7 @@ void Song::DeleteSteps( const Steps* pSteps, bool bReAutoGen )
if( bReAutoGen )
RemoveAutoGenNotes();
vector<Steps*> &vpSteps = m_vpStepsByType[pSteps->m_StepsType];
for( int j=vpSteps.size()-1; j>=0; j-- )
{
+166 -3
View File
@@ -235,7 +235,7 @@ void SongManager::LoadStepManiaSongDir( RString sDir, LoadingWindow *ld )
ld->Paint();
}
Song* pNewSong = new Song;
if( !pNewSong->LoadFromSongDir( sSongDirName, false ) ) // don't ignore cache
if( !pNewSong->LoadFromSongDir( sSongDirName ) )
{
/* The song failed to load. */
delete pNewSong;
@@ -277,7 +277,7 @@ void SongManager::LoadGroupSymLinks(RString sDir, RString sGroupFolder)
RString sSymDestination = msdF.GetParam(0,1); // Should only be 1 vale&param...period.
Song* pNewSong = new Song;
if( !pNewSong->LoadFromSongDir( sSymDestination, false ) ) // don't ignore cache
if( !pNewSong->LoadFromSongDir( sSymDestination ) )
{
delete pNewSong; // The song failed to load.
}
@@ -859,6 +859,169 @@ 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::Invalidate( Song *pStaleSong )
{
//
// Save list of all old Course and Trail pointers
//
map<Course*,CourseID> mapOldCourseToCourseID;
typedef pair<TrailID,Course*> TrailIDAndCourse;
map<Trail*,TrailIDAndCourse> mapOldTrailToTrailIDAndCourse;
FOREACH_CONST( Course*, this->m_pCourses, pCourse )
{
CourseID id;
id.FromCourse( *pCourse );
mapOldCourseToCourseID[*pCourse] = id;
vector<Trail *> Trails;
(*pCourse)->GetAllCachedTrails( Trails );
FOREACH_CONST( Trail*, Trails, pTrail )
{
TrailID id;
id.FromTrail( *pTrail );
mapOldTrailToTrailIDAndCourse[*pTrail] = TrailIDAndCourse(id, *pCourse);
}
}
// It's a real pain to selectively invalidate only those Courses with
// dependencies on the stale Song. So, instead, just reload all Courses.
// It doesn't take very long.
FreeCourses();
InitCoursesFromDisk( NULL );
InitAutogenCourses();
// invalidate cache
StepsID::ClearCache();
#define CONVERT_COURSE_POINTER( pCourse ) do { \
CourseID id = mapOldCourseToCourseID[pCourse]; /* this will always succeed */ \
pCourse = id.ToCourse(); \
} while(false)
/* Ugly: We need the course pointer to restore a trail pointer, and both have
* been invalidated. We need to go through our mapping, and update the course
* pointers, so we can use that to update trail pointers. */
{
map<Trail*,TrailIDAndCourse>::iterator it;
for( it = mapOldTrailToTrailIDAndCourse.begin(); it != mapOldTrailToTrailIDAndCourse.end(); ++it )
{
TrailIDAndCourse &tidc = it->second;
CONVERT_COURSE_POINTER( tidc.second );
}
}
{
CourseID id = mapOldCourseToCourseID[GAMESTATE->m_pCurCourse]; /* this will always succeed */
GAMESTATE->m_pCurCourse.Set( id.ToCourse() );
}
CONVERT_COURSE_POINTER( GAMESTATE->m_pPreferredCourse );
#define CONVERT_TRAIL_POINTER( pTrail ) do { \
if( pTrail != NULL ) { \
map<Trail*,TrailIDAndCourse>::iterator it; \
it = mapOldTrailToTrailIDAndCourse.find(pTrail); \
ASSERT_M( it != mapOldTrailToTrailIDAndCourse.end(), ssprintf("%p", pTrail.Get()) ); \
const TrailIDAndCourse &tidc = it->second; \
const TrailID &id = tidc.first; \
const Course *pCourse = tidc.second; \
pTrail.Set( id.ToTrail( pCourse, true ) ); \
} \
} while(false)
FOREACH_PlayerNumber( pn )
{
CONVERT_TRAIL_POINTER( GAMESTATE->m_pCurTrail[pn] );
}
}
/* If bAllowNotesLoss is true, any global notes pointers which no longer exist
* (or exist but couldn't be matched) will be set to NULL. This is used when
* reverting out of the editor. If false, this is unexpected and will assert.
* This is used when reverting out of gameplay, in which case we may have StageStats,
* etc. which may cause hard-to-trace crashes down the line if we set them to NULL. */
void CONVERT_STEPS_POINTER( Steps *&pSteps, const map<Steps*,StepsID> &mapOldStepsToStepsID, const Song *pSong, bool bAllowNotesLoss )
{
if( pSteps == NULL )
return;
map<Steps*,StepsID>::const_iterator it = mapOldStepsToStepsID.find(pSteps);
if( it != mapOldStepsToStepsID.end() )
pSteps = it->second.ToSteps(pSong, bAllowNotesLoss);
}
void CONVERT_STEPS_POINTER( BroadcastOnChangePtr<Steps> &pSteps, const map<Steps*,StepsID> &mapOldStepsToStepsID, const Song *pSong, bool bAllowNotesLoss )
{
if( pSteps == NULL )
return;
map<Steps*,StepsID>::const_iterator it = mapOldStepsToStepsID.find(pSteps);
if( it != mapOldStepsToStepsID.end() )
pSteps.Set( it->second.ToSteps(pSong, bAllowNotesLoss) );
}
void SongManager::RevertFromDisk( Song *pSong, bool bAllowNotesLoss )
{
/* Reverting from disk is brittle, and touches a lot of tricky and rarely-
* used code paths. If it's ever used during a game, log it. */
LOG->MapLog( "RevertFromDisk", "Reverted \"%s\" from disk", pSong->GetTranslitMainTitle().c_str() );
// Ugly: When we re-load the song, the Steps* will change.
// Fix GAMESTATE->m_CurSteps, STATSMAN->m_CurStageStats, STATSMAN->m_vPlayedStageStats[] after reloading.
/* XXX: This is very brittle. However, we must know about all globals uses of Steps*,
* so we can check to make sure we didn't lose any steps which are referenced ... */
//
// Save list of all old Steps pointers for the song
//
map<Steps*,StepsID> mapOldStepsToStepsID;
FOREACH_CONST( Steps*, pSong->GetAllSteps(), pSteps )
{
StepsID id;
id.FromSteps( *pSteps );
mapOldStepsToStepsID[*pSteps] = id;
}
//
// Reload the song
//
const RString dir = pSong->GetSongDir();
FILEMAN->FlushDirCache( dir );
/* Erase existing data and reload. */
pSong->Reset();
const bool OldVal = PREFSMAN->m_bFastLoad;
PREFSMAN->m_bFastLoad.Set( false );
pSong->LoadFromSongDir( dir );
/* XXX: reload edits? */
PREFSMAN->m_bFastLoad.Set( OldVal );
/* Courses cache Steps pointers. On the off chance that this isn't the last
* thing this screen does, clear that cache. */
/* TODO: Don't make Song depend on SongManager. This is breaking
* encapsulation and placing confusing limitation on what can be done in
* SONGMAN->Invalidate(). -Chris */
this->Invalidate( pSong );
StepsID::ClearCache();
FOREACH_PlayerNumber( p )
{
CONVERT_STEPS_POINTER( GAMESTATE->m_pCurSteps[p], mapOldStepsToStepsID, pSong, bAllowNotesLoss );
FOREACH( Steps*, STATSMAN->m_CurStageStats.m_player[p].vpPlayedSteps, pSteps )
CONVERT_STEPS_POINTER( *pSteps, mapOldStepsToStepsID, pSong, bAllowNotesLoss );
FOREACH( StageStats, STATSMAN->m_vPlayedStageStats, ss )
FOREACH( Steps*, ss->m_player[p].vpPlayedSteps, pSteps )
CONVERT_STEPS_POINTER( *pSteps, mapOldStepsToStepsID, pSong, bAllowNotesLoss );
}
CONVERT_STEPS_POINTER( GAMESTATE->m_pEditSourceSteps, mapOldStepsToStepsID, pSong, bAllowNotesLoss );
}
void SongManager::RegenerateNonFixedCourses()
{
for( unsigned i=0; i < m_pCourses.size(); i++ )
@@ -981,7 +1144,7 @@ bool SongManager::GetExtraStageInfoFromCourse( bool bExtra2, RString sPreferredG
}
pSongOut = pTrail->m_vEntries[0].pSong;
pStepsOut = pTrail->m_vEntries[0].GetSteps();
pStepsOut = pTrail->m_vEntries[0].pSteps;
return true;
}
+3
View File
@@ -33,6 +33,9 @@ public:
void FreeSongs();
void Cleanup();
void Invalidate( Song *pStaleSong );
void RevertFromDisk( Song *pSong, bool bAllowNotesLoss=false );
void RegenerateNonFixedCourses();
void SetPreferences();
-10
View File
@@ -69,7 +69,6 @@ namespace StepsUtil
class StepsID
{
private:
StepsType st;
Difficulty dc;
RString sDescription;
@@ -90,15 +89,6 @@ public:
static void ClearCache();
StepsType GetStepsType() const { return st; }
Difficulty GetDifficulty() const { return dc; }
RString GetDescription() const { return sDescription; }
bool operator==( const StepsID &other ) const
{
#define X(x) (x == other.x)
return X(st) && X(dc) && X(sDescription) && X(uHash);
#undef X
}
};
#endif
+3 -18
View File
@@ -21,7 +21,7 @@ bool TrailEntry::operator== ( const TrailEntry &rhs ) const
#define EQUAL(a) (a==rhs.a)
return
EQUAL(pSong) &&
EQUAL(m_StepsID) &&
EQUAL(pSteps) &&
EQUAL(Modifiers) &&
EQUAL(Attacks) &&
EQUAL(bSecret) &&
@@ -30,21 +30,6 @@ bool TrailEntry::operator== ( const TrailEntry &rhs ) const
EQUAL(dc);
}
Steps *TrailEntry::GetSteps() const
{
// TODO: There are a few bugs with the way we do trails right now.
// - If a steps (or an entire song) is deleted, possibly through the editor,
// this section will fail.
// - If the editor changes a stepchart's stats, that should also be reflected
// in the trail.
return m_StepsID.ToSteps( pSong, false );
}
void TrailEntry::SetSteps(Steps *steps)
{
m_StepsID.FromSteps( steps );
}
bool TrailEntry::ContainsTransformOrTurn() const
{
PlayerOptions po;
@@ -83,7 +68,7 @@ const RadarValues &Trail::GetRadarValues() const
FOREACH_CONST( TrailEntry, m_vEntries, e )
{
const Steps *pSteps = e->GetSteps();
const Steps *pSteps = e->pSteps;
ASSERT( pSteps );
/* Hack: don't calculate for autogen entries; it makes writing Catalog.xml
* take way too long. (Tournamix 4 Sample.crs takes me ~10s.) */
@@ -135,7 +120,7 @@ int Trail::GetTotalMeter() const
int iTotalMeter = 0;
FOREACH_CONST( TrailEntry, m_vEntries, e )
{
iTotalMeter += e->GetSteps()->GetMeter();
iTotalMeter += e->pSteps->GetMeter();
}
return iTotalMeter;
+5 -8
View File
@@ -4,9 +4,8 @@
#define TRAIL_H
#include "Attack.h"
#include "Difficulty.h"
#include "RadarValues.h"
#include "StepsUtil.h"
#include "Difficulty.h"
class Song;
class Steps;
@@ -14,22 +13,19 @@ struct lua_State;
struct TrailEntry
{
public:
TrailEntry():
pSong(NULL),
pSteps(NULL),
bSecret(false),
iLowMeter(-1),
iHighMeter(-1),
dc(Difficulty_Invalid)
{
}
void GetAttackArray( AttackArray &out ) const;
Steps* GetSteps() const;
void SetSteps(Steps *steps);
bool ContainsTransformOrTurn() const;
void GetAttackArray( AttackArray &out ) const;
Song* pSong;
StepsID m_StepsID;
Steps* pSteps;
RString Modifiers;
AttackArray Attacks;
bool bSecret; // show "???"
@@ -41,6 +37,7 @@ public:
Difficulty dc;
bool operator== ( const TrailEntry &rhs ) const;
bool operator!= ( const TrailEntry &rhs ) const { return !(*this==rhs); }
bool ContainsTransformOrTurn() const;
};
class Trail
+4 -14
View File
@@ -58,15 +58,7 @@ public:
void Reset();
void DetachSteps();
// WARNING: Do not use this DeepCopy in any situation with existing Steps*. Those pointers
// will all point to garbage memory after this call. The way to fix that is to change the
// pointers to StepsIDs or in some other way avoid keeping the Steps* pointers from before
// the call to DeepCopy.
void DeepCopy(const Song &song);
// LoadFromSongDir assumes the song is uninitialized. Call ReloadFromSongDir if that is not true.
bool LoadFromSongDir( RString sDir, bool bIgnoreCache );
bool ReloadFromSongDir( RString sDir );
bool LoadFromSongDir( RString sDir );
void TidyUpData(); // call after loading to clean up invalid data
void ReCalculateRadarValuesAndLastBeat(); // called by TidyUpData, and after saving
@@ -160,8 +152,9 @@ public:
typedef vector<BackgroundChange> VBackgroundChange;
private:
VBackgroundChange * m_BackgroundChanges[NUM_BackgroundLayer]; // these must be sorted before gameplay
VBackgroundChange * m_ForegroundChanges; // this must be sorted before gameplay
// AutoPtr instead of raw pointer so that the auto gen'd copy constructor works correctly.
AutoPtrCopyOnWrite<VBackgroundChange> m_BackgroundChanges[NUM_BackgroundLayer]; // these must be sorted before gameplay
AutoPtrCopyOnWrite<VBackgroundChange> m_ForegroundChanges; // this must be sorted before gameplay
public:
const vector<BackgroundChange> &GetBackgroundChanges( BackgroundLayer bl ) const;
vector<BackgroundChange> &GetBackgroundChanges( BackgroundLayer bl );
@@ -223,9 +216,6 @@ public:
void PushSelf( lua_State *L );
private:
// DISALLOW operator= and Steps(Steps&)
Song(const Song&);
void operator=(const Song&);
vector<Steps*> m_vpSteps;
vector<Steps*> m_vpStepsByType[NUM_StepsType];