Just about all that can be done before Loading.

This next commit will be the big one it seems.
This commit is contained in:
Jason Felds
2011-07-17 13:27:47 -04:00
parent 186200d3c6
commit bafcea2a6b
3 changed files with 121 additions and 110 deletions
+97 -106
View File
@@ -258,7 +258,7 @@ static set<RString> BlacklistedImages;
bool Song::LoadFromSongDir( RString sDir )
{
// LOG->Trace( "Song::LoadFromSongDir(%s)", sDir.c_str() );
ASSERT( sDir != "" );
ASSERT_M( sDir != "", "Songs can't be loaded from an empty directory!" );
// make sure there is a trailing slash at the end of sDir
if( sDir.Right(1) != "/" )
@@ -321,10 +321,14 @@ bool Song::LoadFromSongDir( RString sDir )
LOG->UserLog( "Song", sDir, "has no music file either. Ignoring this song directory." );
return false;
}
// Make sure we have a future filename figured out.
vector<RString> folders;
split(sDir, "/", folders);
RString songName = folders[2] + ".ssc";
this->m_sSongFileName = sDir + songName;
// Continue on with a blank Song so that people can make adjustments using the editor.
}
TidyUpData();
TidyUpData(false, true);
// save a cache file so we don't have to parse it all over again next time
if( !SaveToCacheFile() )
@@ -333,8 +337,6 @@ bool Song::LoadFromSongDir( RString sDir )
FOREACH( Steps*, m_vpSteps, s )
{
(*s)->SetFilename( sCacheFilePath );
/* Compress all Steps. During initial caching, this will remove cached
* NoteData; during cached loads, this will just remove cached SMData. */
(*s)->Compress();
@@ -446,7 +448,7 @@ void FixupPath( RString &path, const RString &sSongPath )
}
// Songs in BlacklistImages will never be autodetected as song images.
void Song::TidyUpData( bool bFromCache )
void Song::TidyUpData( bool fromCache, bool duringCache )
{
// We need to do this before calling any of HasMusic, HasHasCDTitle, etc.
ASSERT_M( m_sSongDir.Left(3) != "../", m_sSongDir ); // meaningless
@@ -543,7 +545,7 @@ void Song::TidyUpData( bool bFromCache )
/* Generate these before we autogen notes, so the new notes can inherit
* their source's values. */
ReCalculateRadarValuesAndLastSecond( bFromCache );
ReCalculateRadarValuesAndLastSecond( fromCache, true );
Trim( m_sMainTitle );
Trim( m_sSubTitle );
@@ -779,11 +781,11 @@ void Song::TidyUpData( bool bFromCache )
* music starts. */
if( arrayPossibleMovies.size() == 1 )
this->AddBackgroundChange(BACKGROUND_LAYER_1,
BackgroundChange(0,
arrayPossibleMovies[0],
"",
1.f,
SBE_StretchNoLoop));
BackgroundChange(0,
arrayPossibleMovies[0],
"",
1.f,
SBE_StretchNoLoop));
}
@@ -791,64 +793,6 @@ void Song::TidyUpData( bool bFromCache )
* for edits). We should be able to use difficulty names as unique
* identifiers for steps. */
SongUtil::AdjustDuplicateSteps( this );
{
/* Generated filename; this doesn't always point to a loadable file,
* but instead points to the file we should write changed files to,
* and will always be a .SSC.
*
* This is a little tricky. We can't always use the song title directly,
* since it might contain characters we can't store in filenames. Two
* easy options: we could manually filter out invalid characters, or we
* could use the name of the directory, which is always a valid filename
* and should always be the same as the song. The former might not catch
* everything--filename restrictions are platform-specific; we might even
* be on an 8.3 filesystem, so let's do the latter.
*
* We can't rely on searching for other data filenames; it works for DWIs,
* but not KSFs and BMSs.
*
* So, let's do this (by priority):
* 1. If there's a .SSC file, use that filename. No reason to use anything
* else; it's the filename in use.
* 2. If there's an .SM, use it with a changed extension.
* 3. If there's a .DWI, use it with a changed extension.
* 4. Otherwise, use the name of the directory, since it's definitely a valid
* filename, and should always be the title of the song (unlike KSFs). */
m_sSongFileName = m_sSongDir;
vector<RString> asFileNames;
do
{
GetDirListing( m_sSongDir+"*.ssc", asFileNames );
if( !asFileNames.empty() )
{
m_sSongFileName += asFileNames[0];
break;
}
GetDirListing( m_sSongDir+"*.sma", asFileNames );
if (!asFileNames.empty() )
{
m_sSongFileName += SetExtension( asFileNames[0], "ssc" );
break;
}
GetDirListing( m_sSongDir+"*.sm", asFileNames );
if( !asFileNames.empty() )
{
m_sSongFileName += SetExtension( asFileNames[0], "ssc" );
break;
}
GetDirListing( m_sSongDir+"*.dwi", asFileNames );
if( !asFileNames.empty() ) {
m_sSongFileName += SetExtension( asFileNames[0], "ssc" );
break;
}
m_sSongFileName += Basename(m_sSongDir);
m_sSongFileName += ".ssc";
} while(0);
}
}
void Song::TranslateTitles()
@@ -863,9 +807,9 @@ void Song::TranslateTitles()
m_sMainTitleTranslit, m_sSubTitleTranslit, m_sArtistTranslit );
}
void Song::ReCalculateRadarValuesAndLastSecond( bool bFromCache )
void Song::ReCalculateRadarValuesAndLastSecond(bool fromCache, bool duringCache)
{
if( bFromCache && this->GetFirstSecond() >= 0 && this->GetLastSecond() > 0 )
if( fromCache && this->GetFirstSecond() >= 0 && this->GetLastSecond() > 0 )
{
// this is loaded from cache, then we just have to calculate the radar values.
for( unsigned i=0; i<m_vpSteps.size(); i++ )
@@ -883,35 +827,41 @@ void Song::ReCalculateRadarValuesAndLastSecond( bool bFromCache )
pSteps->CalculateRadarValues( m_fMusicLengthSeconds );
// Must initialize before the gotos.
NoteData tempNoteData;
pSteps->GetNoteData( tempNoteData );
// calculate lastSecond
// If it's autogen, then first/last beat will come from the parent.
if( pSteps->IsAutogen() )
continue;
goto wipe_notedata;
/* Don't calculate with edits unless the song only contains an edit
* chart, like those in Mungyodance 3. Otherwise, edits installed on
* the machine could extend the length of the song. */
if( pSteps->IsAnEdit() && m_vpSteps.size() > 1 )
continue;
goto wipe_notedata;
// Don't set first/last beat based on lights. They often start very
// early and end very late.
if( pSteps->m_StepsType == StepsType_lights_cabinet )
continue;
NoteData tempNoteData;
pSteps->GetNoteData( tempNoteData );
continue; // no need to wipe this.
/* Many songs have stray, empty song patterns. Ignore them, so they
* don't force the first beat of the whole song to 0. */
if( tempNoteData.GetLastRow() == 0 )
continue;
localFirst = min(localFirst,
if( tempNoteData.GetLastRow() != 0 )
{
localFirst = min(localFirst,
pSteps->m_Timing.GetElapsedTimeFromBeat(tempNoteData.GetFirstBeat()));
localLast = max(localLast,
localLast = max(localLast,
pSteps->m_Timing.GetElapsedTimeFromBeat(tempNoteData.GetLastBeat()));
}
wipe_notedata:
if (duringCache)
{
// update this when at that point.
}
}
this->firstSecond = localFirst;
@@ -1005,11 +955,15 @@ bool Song::SaveToSMFile()
bool Song::SaveToSSCFile( RString sPath, bool bSavingCache )
{
LOG->Trace( "Song::SaveToSSCFile('%s')", sPath.c_str() );
RString path = sPath;
if (!bSavingCache)
path = SetExtension(sPath, "ssc");
LOG->Trace( "Song::SaveToSSCFile('%s')", path.c_str() );
// If the file exists, make a backup.
if( !bSavingCache && IsAFile(sPath) )
FileCopy( sPath, sPath + ".old" );
if( !bSavingCache && IsAFile(path) )
FileCopy( path, path + ".old" );
vector<Steps*> vpStepsToSave;
FOREACH_CONST( Steps*, m_vpSteps, s )
@@ -1022,16 +976,23 @@ bool Song::SaveToSSCFile( RString sPath, bool bSavingCache )
if( pSteps->WasLoadedFromProfile() )
continue;
if (!bSavingCache)
pSteps->SetFilename(path);
vpStepsToSave.push_back( pSteps );
}
if (bSavingCache)
{
return NotesWriterSSC::Write(path, *this, vpStepsToSave, bSavingCache);
}
if( !NotesWriterSSC::Write(sPath, *this, vpStepsToSave, bSavingCache) )
if( !NotesWriterSSC::Write(path, *this, vpStepsToSave, bSavingCache) )
return false;
if( !bSavingCache && g_BackUpAllSongSaves.Get() )
if( g_BackUpAllSongSaves.Get() )
{
RString sExt = GetExtension( sPath );
RString sBackupFile = SetExtension( sPath, "" );
RString sExt = GetExtension( path );
RString sBackupFile = SetExtension( path, "" );
time_t cur_time;
time( &cur_time );
@@ -1043,18 +1004,15 @@ bool Song::SaveToSSCFile( RString sPath, bool bSavingCache )
sBackupFile = SetExtension( sBackupFile, sExt );
sBackupFile += ssprintf( ".old" );
if( FileCopy(sPath, sBackupFile) )
LOG->Trace( "Backed up %s to %s", sPath.c_str(), sBackupFile.c_str() );
if( FileCopy(path, sBackupFile) )
LOG->Trace( "Backed up %s to %s", path.c_str(), sBackupFile.c_str() );
else
LOG->Trace( "Failed to back up %s to %s", sPath.c_str(), sBackupFile.c_str() );
LOG->Trace( "Failed to back up %s to %s", path.c_str(), sBackupFile.c_str() );
}
if( !bSavingCache )
{
// Mark these steps saved to disk.
FOREACH( Steps*, vpStepsToSave, s )
(*s)->SetSavedToDisk( true );
}
// Mark these steps saved to disk.
FOREACH( Steps*, vpStepsToSave, s )
(*s)->SetSavedToDisk( true );
return true;
}
@@ -1063,13 +1021,7 @@ bool Song::SaveToCacheFile()
{
SONGINDEX->AddCacheIndex(m_sSongDir, GetHashForDirectory(m_sSongDir));
const RString sPath = GetCacheFilePath();
if( !SaveToSSCFile(sPath, true) )
return false;
FOREACH( Steps*, m_vpSteps, pSteps )
(*pSteps)->SetFilename( sPath );
return true;
return SaveToSSCFile(sPath, true);
}
bool Song::SaveToDWIFile()
@@ -1295,6 +1247,45 @@ vector<BackgroundChange> &Song::GetForegroundChanges()
return *m_ForegroundChanges.Get();
}
vector<RString> Song::GetChangesToVectorString(const vector<BackgroundChange> & changes) const
{
vector<RString> ret;
FOREACH_CONST( BackgroundChange, changes, bgc )
{
ret.push_back((*bgc).ToString());
}
return ret;
}
vector<RString> Song::GetBGChanges1ToVectorString() const
{
return this->GetChangesToVectorString(this->GetBackgroundChanges(BACKGROUND_LAYER_1));
}
vector<RString> Song::GetBGChanges2ToVectorString() const
{
return this->GetChangesToVectorString(this->GetBackgroundChanges(BACKGROUND_LAYER_2));
}
vector<RString> Song::GetFGChanges1ToVectorString() const
{
return this->GetChangesToVectorString(this->GetForegroundChanges());
}
vector<RString> Song::GetInstrumentTracksToVectorString() const
{
vector<RString> ret;
FOREACH_ENUM(InstrumentTrack, it)
{
if (this->HasInstrumentTrack(it))
{
ret.push_back(InstrumentTrackToString(it)
+ "="
+ this->m_sInstrumentTrackFile[it]);
}
}
return ret;
}
RString GetSongAssetPath( RString sPath, const RString &sSongPath )
{