Fix several annoying edit mode bugs, mostly by fixing the Song copy
operator and the various uses of it. - revert file from disk: keeps old BPM. The BPMS on disk are added to the existing BPM information! - edit mode turns X stepcharts into 2X when reverting - sometimes edit mode loses an entire stepchart: open a stepchart, change to a new stepchart, exit without going back, original chart gone - edit a chart, make a change in a different chart, exit from the first chart: change made in different chart doesn't revert - normally, when you create a stepchart and don't save it after editting it, it is deleted. however, if you create a stepchart, don't save it, and exit edit mode while looking at a different chart, the chart isn't deleted. Some existing bugs are not fixed, though: - delete the last stepchart for a step type. CTD. - Edit one of the fake doubles stepcharts for a song that doesn't have real doubles stepcharts. Exit without doing anything. CTD. This is probably the same problem as the previous bug. - delete a song or a steps that happens to be part of a trail. Trail is now broken. Some other edits should affect a trail as well, but don't.
This commit is contained in:
+98
-24
@@ -42,9 +42,8 @@ static Preference<float> g_fMarathonVerSongSeconds( "MarathonVerSongSeconds", 60
|
||||
Song::Song()
|
||||
{
|
||||
FOREACH_BackgroundLayer( i )
|
||||
m_BackgroundChanges[i] = AutoPtrCopyOnWrite<VBackgroundChange>(new VBackgroundChange);
|
||||
m_ForegroundChanges = AutoPtrCopyOnWrite<VBackgroundChange>(new VBackgroundChange);
|
||||
|
||||
m_BackgroundChanges[i] = new VBackgroundChange;
|
||||
m_ForegroundChanges = new VBackgroundChange;
|
||||
|
||||
m_LoadedFromProfile = ProfileSlot_Invalid;
|
||||
m_fMusicSampleStartSeconds = -1;
|
||||
@@ -68,34 +67,96 @@ 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.
|
||||
}
|
||||
|
||||
void Song::DetachSteps()
|
||||
{
|
||||
m_vpSteps.clear();
|
||||
FOREACH_StepsType( st )
|
||||
m_vpStepsByType[st].clear();
|
||||
}
|
||||
|
||||
/* Reset to an empty song. */
|
||||
// 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 = empty;
|
||||
|
||||
this->DeepCopy(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.
|
||||
@@ -173,7 +234,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 Song::LoadFromSongDir( RString sDir, bool bIgnoreCache )
|
||||
{
|
||||
// LOG->Trace( "Song::LoadFromSongDir(%s)", sDir.c_str() );
|
||||
ASSERT( sDir != "" );
|
||||
@@ -196,7 +257,7 @@ bool Song::LoadFromSongDir( RString sDir )
|
||||
// First look in the cache for this song (without loading NoteData)
|
||||
//
|
||||
unsigned uCacheHash = SONGINDEX->GetCacheHash(m_sSongDir);
|
||||
bool bUseCache = true;
|
||||
bool bUseCache = !bIgnoreCache;
|
||||
if( !DoesFileExist(GetCacheFilePath()) )
|
||||
bUseCache = false;
|
||||
if( !PREFSMAN->m_bFastLoad && GetHashForDirectory(m_sSongDir) != uCacheHash )
|
||||
@@ -283,6 +344,14 @@ bool Song::LoadFromSongDir( RString sDir )
|
||||
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 );
|
||||
@@ -743,6 +812,12 @@ 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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -963,7 +1038,7 @@ const vector<BackgroundChange> &Song::GetBackgroundChanges( BackgroundLayer bl )
|
||||
}
|
||||
vector<BackgroundChange> &Song::GetBackgroundChanges( BackgroundLayer bl )
|
||||
{
|
||||
return *(m_BackgroundChanges[bl].Get());
|
||||
return *(m_BackgroundChanges[bl]);
|
||||
}
|
||||
|
||||
const vector<BackgroundChange> &Song::GetForegroundChanges() const
|
||||
@@ -972,7 +1047,7 @@ const vector<BackgroundChange> &Song::GetForegroundChanges() const
|
||||
}
|
||||
vector<BackgroundChange> &Song::GetForegroundChanges()
|
||||
{
|
||||
return *m_ForegroundChanges.Get();
|
||||
return *m_ForegroundChanges;
|
||||
}
|
||||
|
||||
|
||||
@@ -1083,7 +1158,6 @@ 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-- )
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user