[notesloader -> default] Mission accomplished.
This commit is contained in:
@@ -142,8 +142,10 @@ static void StartMusic( MusicToPlay &ToPlay )
|
|||||||
{
|
{
|
||||||
LOG->Trace( "Found '%s'", ToPlay.m_sTimingFile.c_str() );
|
LOG->Trace( "Found '%s'", ToPlay.m_sTimingFile.c_str() );
|
||||||
Song song;
|
Song song;
|
||||||
|
SSCLoader loaderSSC;
|
||||||
|
SMLoader loaderSM;
|
||||||
if(GetExtension(ToPlay.m_sTimingFile) == ".ssc" &&
|
if(GetExtension(ToPlay.m_sTimingFile) == ".ssc" &&
|
||||||
SSCLoader::LoadFromSSCFile(ToPlay.m_sTimingFile, song) )
|
loaderSSC.LoadFromSimfile(ToPlay.m_sTimingFile, song) )
|
||||||
{
|
{
|
||||||
ToPlay.HasTiming = true;
|
ToPlay.HasTiming = true;
|
||||||
ToPlay.m_TimingData = song.m_SongTiming;
|
ToPlay.m_TimingData = song.m_SongTiming;
|
||||||
@@ -153,7 +155,7 @@ static void StartMusic( MusicToPlay &ToPlay )
|
|||||||
pStepsCabinetLights->GetNoteData( ToPlay.m_LightsData );
|
pStepsCabinetLights->GetNoteData( ToPlay.m_LightsData );
|
||||||
}
|
}
|
||||||
else if(GetExtension(ToPlay.m_sTimingFile) == ".sm" &&
|
else if(GetExtension(ToPlay.m_sTimingFile) == ".sm" &&
|
||||||
SMLoader::LoadFromSMFile(ToPlay.m_sTimingFile, song) )
|
loaderSM.LoadFromSimfile(ToPlay.m_sTimingFile, song) )
|
||||||
{
|
{
|
||||||
ToPlay.HasTiming = true;
|
ToPlay.HasTiming = true;
|
||||||
ToPlay.m_TimingData = song.m_SongTiming;
|
ToPlay.m_TimingData = song.m_SongTiming;
|
||||||
|
|||||||
+10
-7
@@ -32,20 +32,23 @@ bool NotesLoader::LoadFromDir( const RString &sPath, Song &out, set<RString> &Bl
|
|||||||
vector<RString> list;
|
vector<RString> list;
|
||||||
|
|
||||||
BlacklistedImages.clear();
|
BlacklistedImages.clear();
|
||||||
SSCLoader::GetApplicableFiles( sPath, list );
|
SSCLoader loaderSSC;
|
||||||
|
loaderSSC.GetApplicableFiles( sPath, list );
|
||||||
if( !list.empty() )
|
if( !list.empty() )
|
||||||
{
|
{
|
||||||
if( !SSCLoader::LoadFromDir( sPath, out ) )
|
if( !loaderSSC.LoadFromDir( sPath, out ) )
|
||||||
return false;
|
return false;
|
||||||
SSCLoader::TidyUpData( out, false );
|
loaderSSC.TidyUpData( out, false );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
SMALoader::GetApplicableFiles( sPath, list );
|
SMALoader loaderSMA;
|
||||||
|
loaderSMA.GetApplicableFiles( sPath, list );
|
||||||
if (!list.empty() )
|
if (!list.empty() )
|
||||||
return SMALoader::LoadFromDir( sPath, out );
|
return loaderSMA.LoadFromDir( sPath, out );
|
||||||
SMLoader::GetApplicableFiles( sPath, list );
|
SMLoader loaderSM;
|
||||||
|
loaderSM.GetApplicableFiles( sPath, list );
|
||||||
if (!list.empty() )
|
if (!list.empty() )
|
||||||
return SMLoader::LoadFromDir( sPath, out );
|
return loaderSM.LoadFromDir( sPath, out );
|
||||||
DWILoader::GetApplicableFiles( sPath, list );
|
DWILoader::GetApplicableFiles( sPath, list );
|
||||||
if( !list.empty() )
|
if( !list.empty() )
|
||||||
return DWILoader::LoadFromDir( sPath, out, BlacklistedImages );
|
return DWILoader::LoadFromDir( sPath, out, BlacklistedImages );
|
||||||
|
|||||||
+134
-56
@@ -13,10 +13,39 @@
|
|||||||
#include "Attack.h"
|
#include "Attack.h"
|
||||||
#include "PrefsManager.h"
|
#include "PrefsManager.h"
|
||||||
|
|
||||||
/** @brief The maximum file size for edits. */
|
bool SMLoader::LoadFromDir( const RString &sPath, Song &out )
|
||||||
const int MAX_EDIT_STEPS_SIZE_BYTES = 60*1024; // 60KB
|
{
|
||||||
|
vector<RString> aFileNames;
|
||||||
|
GetApplicableFiles( sPath, aFileNames );
|
||||||
|
|
||||||
void SMLoader::LoadFromSMTokens(
|
if( aFileNames.size() > 1 )
|
||||||
|
{
|
||||||
|
// Need to break this up first.
|
||||||
|
RString tmp = "Song " + sPath + " has more than one";
|
||||||
|
LOG->UserLog(tmp, this->GetFileExtension(), "file. There can only be one!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT( aFileNames.size() == 1 );
|
||||||
|
return LoadFromSimfile( sPath + aFileNames[0], out );
|
||||||
|
}
|
||||||
|
|
||||||
|
float SMLoader::RowToBeat( RString line, const int rowsPerBeat )
|
||||||
|
{
|
||||||
|
RString backup = line;
|
||||||
|
Trim(line, "r");
|
||||||
|
Trim(line, "R");
|
||||||
|
if( backup != line )
|
||||||
|
{
|
||||||
|
return StringToFloat( line ) / rowsPerBeat;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return StringToFloat( line );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SMLoader::LoadFromTokens(
|
||||||
RString sStepsType,
|
RString sStepsType,
|
||||||
RString sDescription,
|
RString sDescription,
|
||||||
RString sDifficulty,
|
RString sDifficulty,
|
||||||
@@ -34,7 +63,7 @@ void SMLoader::LoadFromSMTokens(
|
|||||||
Trim( sDifficulty );
|
Trim( sDifficulty );
|
||||||
Trim( sNoteData );
|
Trim( sNoteData );
|
||||||
|
|
||||||
// LOG->Trace( "Steps::LoadFromSMTokens()" );
|
// LOG->Trace( "Steps::LoadFromTokens()" );
|
||||||
|
|
||||||
// insert stepstype hacks from GameManager.cpp here? -aj
|
// insert stepstype hacks from GameManager.cpp here? -aj
|
||||||
out.m_StepsType = GAMEMAN->StringToStepsType( sStepsType );
|
out.m_StepsType = GAMEMAN->StringToStepsType( sStepsType );
|
||||||
@@ -79,11 +108,6 @@ void SMLoader::LoadFromSMTokens(
|
|||||||
out.TidyUpData();
|
out.TidyUpData();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMLoader::GetApplicableFiles( const RString &sPath, vector<RString> &out )
|
|
||||||
{
|
|
||||||
GetDirListing( sPath + RString("*.sm"), out );
|
|
||||||
}
|
|
||||||
|
|
||||||
void SMLoader::ProcessBGChanges( Song &out, const RString &sValueName, const RString &sPath, const RString &sParam )
|
void SMLoader::ProcessBGChanges( Song &out, const RString &sValueName, const RString &sPath, const RString &sParam )
|
||||||
{
|
{
|
||||||
BackgroundLayer iLayer = BACKGROUND_LAYER_1;
|
BackgroundLayer iLayer = BACKGROUND_LAYER_1;
|
||||||
@@ -171,10 +195,10 @@ void SMLoader::ProcessInstrumentTracks( Song &out, const RString &sParam )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SMLoader::ProcessBPMs( TimingData &out, const RString sParam )
|
bool SMLoader::ProcessBPMs( TimingData &out, const RString line, const int rowsPerBeat )
|
||||||
{
|
{
|
||||||
vector<RString> arrayBPMChangeExpressions;
|
vector<RString> arrayBPMChangeExpressions;
|
||||||
split( sParam, ",", arrayBPMChangeExpressions );
|
split( line, ",", arrayBPMChangeExpressions );
|
||||||
|
|
||||||
// prepare storage variables for negative BPMs -> Warps.
|
// prepare storage variables for negative BPMs -> Warps.
|
||||||
float negBeat = -1;
|
float negBeat = -1;
|
||||||
@@ -196,7 +220,7 @@ bool SMLoader::ProcessBPMs( TimingData &out, const RString sParam )
|
|||||||
|
|
||||||
bNotEmpty = true;
|
bNotEmpty = true;
|
||||||
|
|
||||||
const float fBeat = StringToFloat( arrayBPMChangeValues[0] );
|
const float fBeat = RowToBeat( arrayBPMChangeValues[0], rowsPerBeat );
|
||||||
const float fNewBPM = StringToFloat( arrayBPMChangeValues[1] );
|
const float fNewBPM = StringToFloat( arrayBPMChangeValues[1] );
|
||||||
|
|
||||||
if( fNewBPM < 0.0f )
|
if( fNewBPM < 0.0f )
|
||||||
@@ -242,10 +266,10 @@ bool SMLoader::ProcessBPMs( TimingData &out, const RString sParam )
|
|||||||
return bNotEmpty;
|
return bNotEmpty;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMLoader::ProcessStops( TimingData &out, const RString sParam )
|
void SMLoader::ProcessStops( TimingData &out, const RString line, const int rowsPerBeat )
|
||||||
{
|
{
|
||||||
vector<RString> arrayFreezeExpressions;
|
vector<RString> arrayFreezeExpressions;
|
||||||
split( sParam, ",", arrayFreezeExpressions );
|
split( line, ",", arrayFreezeExpressions );
|
||||||
|
|
||||||
// Prepare variables for negative stop conversion.
|
// Prepare variables for negative stop conversion.
|
||||||
float negBeat = -1;
|
float negBeat = -1;
|
||||||
@@ -263,7 +287,7 @@ void SMLoader::ProcessStops( TimingData &out, const RString sParam )
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float fFreezeBeat = StringToFloat( arrayFreezeValues[0] );
|
const float fFreezeBeat = RowToBeat( arrayFreezeValues[0], rowsPerBeat );
|
||||||
const float fFreezeSeconds = StringToFloat( arrayFreezeValues[1] );
|
const float fFreezeSeconds = StringToFloat( arrayFreezeValues[1] );
|
||||||
|
|
||||||
// Process the prior stop.
|
// Process the prior stop.
|
||||||
@@ -308,10 +332,10 @@ void SMLoader::ProcessStops( TimingData &out, const RString sParam )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMLoader::ProcessDelays( TimingData &out, const RString sParam )
|
void SMLoader::ProcessDelays( TimingData &out, const RString line, const int rowsPerBeat )
|
||||||
{
|
{
|
||||||
vector<RString> arrayDelayExpressions;
|
vector<RString> arrayDelayExpressions;
|
||||||
split( sParam, ",", arrayDelayExpressions );
|
split( line, ",", arrayDelayExpressions );
|
||||||
|
|
||||||
for( unsigned f=0; f<arrayDelayExpressions.size(); f++ )
|
for( unsigned f=0; f<arrayDelayExpressions.size(); f++ )
|
||||||
{
|
{
|
||||||
@@ -325,7 +349,7 @@ void SMLoader::ProcessDelays( TimingData &out, const RString sParam )
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float fFreezeBeat = StringToFloat( arrayDelayValues[0] );
|
const float fFreezeBeat = RowToBeat( arrayDelayValues[0], rowsPerBeat );
|
||||||
const float fFreezeSeconds = StringToFloat( arrayDelayValues[1] );
|
const float fFreezeSeconds = StringToFloat( arrayDelayValues[1] );
|
||||||
|
|
||||||
StopSegment new_seg( fFreezeBeat, fFreezeSeconds, true );
|
StopSegment new_seg( fFreezeBeat, fFreezeSeconds, true );
|
||||||
@@ -342,10 +366,10 @@ void SMLoader::ProcessDelays( TimingData &out, const RString sParam )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMLoader::ProcessTimeSignatures( TimingData &out, const RString sParam )
|
void SMLoader::ProcessTimeSignatures( TimingData &out, const RString line, const int rowsPerBeat )
|
||||||
{
|
{
|
||||||
vector<RString> vs1;
|
vector<RString> vs1;
|
||||||
split( sParam, ",", vs1 );
|
split( line, ",", vs1 );
|
||||||
|
|
||||||
FOREACH_CONST( RString, vs1, s1 )
|
FOREACH_CONST( RString, vs1, s1 )
|
||||||
{
|
{
|
||||||
@@ -358,9 +382,9 @@ void SMLoader::ProcessTimeSignatures( TimingData &out, const RString sParam )
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float fBeat = StringToFloat( vs2[0] );
|
const float fBeat = RowToBeat( vs2[0], rowsPerBeat );
|
||||||
|
|
||||||
TimeSignatureSegment seg( BeatToNoteRow( fBeat ), StringToInt( vs2[1] ), StringToInt( vs2[2] ));
|
TimeSignatureSegment seg( fBeat, StringToInt( vs2[1] ), StringToInt( vs2[2] ));
|
||||||
|
|
||||||
if( fBeat < 0 )
|
if( fBeat < 0 )
|
||||||
{
|
{
|
||||||
@@ -384,10 +408,10 @@ void SMLoader::ProcessTimeSignatures( TimingData &out, const RString sParam )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMLoader::ProcessTickcounts( TimingData &out, const RString sParam )
|
void SMLoader::ProcessTickcounts( TimingData &out, const RString line, const int rowsPerBeat )
|
||||||
{
|
{
|
||||||
vector<RString> arrayTickcountExpressions;
|
vector<RString> arrayTickcountExpressions;
|
||||||
split( sParam, ",", arrayTickcountExpressions );
|
split( line, ",", arrayTickcountExpressions );
|
||||||
|
|
||||||
for( unsigned f=0; f<arrayTickcountExpressions.size(); f++ )
|
for( unsigned f=0; f<arrayTickcountExpressions.size(); f++ )
|
||||||
{
|
{
|
||||||
@@ -401,14 +425,90 @@ void SMLoader::ProcessTickcounts( TimingData &out, const RString sParam )
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float fTickcountBeat = StringToFloat( arrayTickcountValues[0] );
|
const float fTickcountBeat = RowToBeat( arrayTickcountValues[0], rowsPerBeat );
|
||||||
int iTicks = clamp(atoi( arrayTickcountValues[1] ), 0, ROWS_PER_BEAT);
|
int iTicks = clamp(atoi( arrayTickcountValues[1] ), 0, ROWS_PER_BEAT);
|
||||||
|
|
||||||
TickcountSegment new_seg( BeatToNoteRow(fTickcountBeat), iTicks );
|
TickcountSegment new_seg( fTickcountBeat, iTicks );
|
||||||
out.AddTickcountSegment( new_seg );
|
out.AddTickcountSegment( new_seg );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SMLoader::ProcessSpeeds( TimingData &out, const RString line, const int rowsPerBeat )
|
||||||
|
{
|
||||||
|
vector<RString> vs1;
|
||||||
|
split( line, ",", vs1 );
|
||||||
|
|
||||||
|
FOREACH_CONST( RString, vs1, s1 )
|
||||||
|
{
|
||||||
|
vector<RString> vs2;
|
||||||
|
split( *s1, "=", vs2 );
|
||||||
|
|
||||||
|
if( vs2[0] == 0 && vs2.size() == 2 ) // First one always seems to have 2.
|
||||||
|
{
|
||||||
|
vs2.push_back("0");
|
||||||
|
}
|
||||||
|
|
||||||
|
if( vs2.size() == 3 ) // use beats by default.
|
||||||
|
{
|
||||||
|
vs2.push_back("0");
|
||||||
|
}
|
||||||
|
|
||||||
|
if( vs2.size() < 4 )
|
||||||
|
{
|
||||||
|
LOG->UserLog( "Song file", "(UNKNOWN)", "has an speed change with %i values.", (int)vs2.size() );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float fBeat = RowToBeat( vs2[0], rowsPerBeat );
|
||||||
|
|
||||||
|
SpeedSegment seg( fBeat, StringToFloat( vs2[1] ), StringToFloat( vs2[2] ));
|
||||||
|
seg.SetUnit(StringToInt(vs2[3]));
|
||||||
|
|
||||||
|
if( fBeat < 0 )
|
||||||
|
{
|
||||||
|
LOG->UserLog( "Song file", "(UNKNOWN)", "has an speed change with beat %f.", fBeat );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( seg.GetLength() < 0 )
|
||||||
|
{
|
||||||
|
LOG->UserLog( "Song file", "(UNKNOWN)", "has an speed change with beat %f, length %f.", fBeat, seg.GetLength() );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
out.AddSpeedSegment( seg );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SMLoader::ProcessFakes( TimingData &out, const RString line, const int rowsPerBeat )
|
||||||
|
{
|
||||||
|
vector<RString> arrayFakeExpressions;
|
||||||
|
split( line, ",", arrayFakeExpressions );
|
||||||
|
|
||||||
|
for( unsigned b=0; b<arrayFakeExpressions.size(); b++ )
|
||||||
|
{
|
||||||
|
vector<RString> arrayFakeValues;
|
||||||
|
split( arrayFakeExpressions[b], "=", arrayFakeValues );
|
||||||
|
// XXX: Hard to tell which file caused this.
|
||||||
|
if( arrayFakeValues.size() != 2 )
|
||||||
|
{
|
||||||
|
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #FAKES value \"%s\" (must have exactly one '='), ignored.",
|
||||||
|
arrayFakeExpressions[b].c_str() );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float fBeat = RowToBeat( arrayFakeValues[0], rowsPerBeat );
|
||||||
|
const float fNewBeat = StringToFloat( arrayFakeValues[1] );
|
||||||
|
|
||||||
|
if(fNewBeat > 0)
|
||||||
|
out.AddFakeSegment( FakeSegment(fBeat, fNewBeat) );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid Fake at beat %f, BPM %f.", fBeat, fNewBeat );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool SMLoader::LoadFromBGChangesString( BackgroundChange &change, const RString &sBGChangeExpression )
|
bool SMLoader::LoadFromBGChangesString( BackgroundChange &change, const RString &sBGChangeExpression )
|
||||||
{
|
{
|
||||||
vector<RString> aBGChangeValues;
|
vector<RString> aBGChangeValues;
|
||||||
@@ -495,7 +595,7 @@ bool SMLoader::LoadFromBGChangesString( BackgroundChange &change, const RString
|
|||||||
return aBGChangeValues.size() >= 2;
|
return aBGChangeValues.size() >= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SMLoader::LoadFromSMFile( const RString &sPath, Song &out, bool bFromCache )
|
bool SMLoader::LoadFromSimfile( const RString &sPath, Song &out, bool bFromCache )
|
||||||
{
|
{
|
||||||
LOG->Trace( "Song::LoadFromSMFile(%s)", sPath.c_str() );
|
LOG->Trace( "Song::LoadFromSMFile(%s)", sPath.c_str() );
|
||||||
|
|
||||||
@@ -719,7 +819,7 @@ bool SMLoader::LoadFromSMFile( const RString &sPath, Song &out, bool bFromCache
|
|||||||
}
|
}
|
||||||
|
|
||||||
Steps* pNewNotes = out.CreateSteps();
|
Steps* pNewNotes = out.CreateSteps();
|
||||||
LoadFromSMTokens(
|
LoadFromTokens(
|
||||||
sParams[1],
|
sParams[1],
|
||||||
sParams[2],
|
sParams[2],
|
||||||
sParams[3],
|
sParams[3],
|
||||||
@@ -743,33 +843,6 @@ bool SMLoader::LoadFromSMFile( const RString &sPath, Song &out, bool bFromCache
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SMLoader::LoadFromDir( const RString &sPath, Song &out )
|
|
||||||
{
|
|
||||||
vector<RString> aFileNames;
|
|
||||||
GetApplicableFiles( sPath, aFileNames );
|
|
||||||
|
|
||||||
if( aFileNames.size() > 1 )
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Song", sPath, "has more than one SM file. There can be only one (unless you are using TougaKiryuu's AnimeMix files somehow, which assume a different version of StepMania)!" );
|
|
||||||
return false;
|
|
||||||
/*
|
|
||||||
for( unsigned i=0; i<aFileNames.size(); i++ )
|
|
||||||
{
|
|
||||||
if(!LoadFromSMFile( sPath + aFileNames[i], out ))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT( aFileNames.size() == 1 );
|
|
||||||
/* We should have at least one; if we had none, we shouldn't have been
|
|
||||||
* called to begin with. */
|
|
||||||
//ASSERT( aFileNames.size() >= 1 );
|
|
||||||
|
|
||||||
return LoadFromSMFile( sPath + aFileNames[0], out );
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SMLoader::LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong )
|
bool SMLoader::LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong )
|
||||||
{
|
{
|
||||||
LOG->Trace( "SMLoader::LoadEditFromFile(%s)", sEditFilePath.c_str() );
|
LOG->Trace( "SMLoader::LoadEditFromFile(%s)", sEditFilePath.c_str() );
|
||||||
@@ -853,7 +926,7 @@ bool SMLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
Steps* pNewNotes = pSong->CreateSteps();
|
Steps* pNewNotes = pSong->CreateSteps();
|
||||||
LoadFromSMTokens(
|
LoadFromTokens(
|
||||||
sParams[1], sParams[2], sParams[3], sParams[4], sParams[5], sParams[6],
|
sParams[1], sParams[2], sParams[3], sParams[4], sParams[5], sParams[6],
|
||||||
*pNewNotes);
|
*pNewNotes);
|
||||||
|
|
||||||
@@ -881,6 +954,11 @@ bool SMLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SMLoader::GetApplicableFiles( const RString &sPath, vector<RString> &out )
|
||||||
|
{
|
||||||
|
GetDirListing( sPath + RString("*" + this->GetFileExtension() ), out );
|
||||||
|
}
|
||||||
|
|
||||||
void SMLoader::TidyUpData( Song &song, bool bFromCache )
|
void SMLoader::TidyUpData( Song &song, bool bFromCache )
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
|||||||
+142
-18
@@ -15,33 +15,157 @@ class TimingData;
|
|||||||
* This was brought in from StepMania 4's recent betas. */
|
* This was brought in from StepMania 4's recent betas. */
|
||||||
const float FAST_BPM_WARP = 9999999.f;
|
const float FAST_BPM_WARP = 9999999.f;
|
||||||
|
|
||||||
|
/** @brief The maximum file size for edits. */
|
||||||
|
const int MAX_EDIT_STEPS_SIZE_BYTES = 60*1024; // 60KB
|
||||||
|
|
||||||
/** @brief Reads a Song from an .SM file. */
|
/** @brief Reads a Song from an .SM file. */
|
||||||
namespace SMLoader
|
struct SMLoader
|
||||||
{
|
{
|
||||||
void LoadFromSMTokens( RString sStepsType, RString sDescription, RString sDifficulty,
|
SMLoader() : fileExt(".sm") {}
|
||||||
RString sMeter, RString sRadarValues, RString sNoteData, Steps &out );
|
|
||||||
|
|
||||||
bool LoadFromDir( const RString &sPath, Song &out );
|
SMLoader(RString ext) : fileExt(ext) {}
|
||||||
void TidyUpData( Song &song, bool bFromCache );
|
|
||||||
|
|
||||||
bool LoadFromSMFile( const RString &sPath, Song &out, bool bFromCache = false );
|
virtual ~SMLoader() {}
|
||||||
void GetApplicableFiles( const RString &sPath, vector<RString> &out );
|
|
||||||
bool LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
|
|
||||||
bool LoadEditFromBuffer( const RString &sBuffer, const RString &sEditFilePath, ProfileSlot slot );
|
|
||||||
bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
|
|
||||||
bool LoadFromBGChangesString( BackgroundChange &change, const RString &sBGChangeExpression );
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Attempt to load a song from a specified path.
|
||||||
|
* @param sPath a const reference to the path on the hard drive to check.
|
||||||
|
* @param out a reference to the Song that will retrieve the song information.
|
||||||
|
* @return its success or failure.
|
||||||
|
*/
|
||||||
|
virtual bool LoadFromDir( const RString &sPath, Song &out );
|
||||||
|
/**
|
||||||
|
* @brief Perform some cleanup on the loaded song.
|
||||||
|
* @param song a reference to the song that may need cleaning up.
|
||||||
|
* @param bFromCache a flag to determine if this song is loaded from a cache file.
|
||||||
|
*/
|
||||||
|
virtual void TidyUpData( Song &song, bool bFromCache );
|
||||||
|
|
||||||
bool ProcessBPMs( TimingData &, const RString );
|
/**
|
||||||
void ProcessStops( TimingData &, const RString );
|
* @brief Attempt to load the specified sm file.
|
||||||
void ProcessDelays( TimingData &, const RString );
|
* @param sPath a const reference to the path on the hard drive to check.
|
||||||
void ProcessTimeSignatures( TimingData &, const RString );
|
* @param out a reference to the Song that will retrieve the song information.
|
||||||
void ProcessTickcounts( TimingData &, const RString );
|
* @param bFromCache a check to see if we are getting certain information from the cache file.
|
||||||
void ProcessBGChanges( Song &out, const RString &sValueName,
|
* @return its success or failure.
|
||||||
|
*/
|
||||||
|
virtual bool LoadFromSimfile( const RString &sPath, Song &out, bool bFromCache = false );
|
||||||
|
/**
|
||||||
|
* @brief Retrieve the list of .sm files.
|
||||||
|
* @param sPath a const reference to the path on the hard drive to check.
|
||||||
|
* @param out a vector of files found in the path.
|
||||||
|
*/
|
||||||
|
virtual void GetApplicableFiles( const RString &sPath, vector<RString> &out );
|
||||||
|
virtual bool LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
|
||||||
|
virtual bool LoadEditFromBuffer( const RString &sBuffer, const RString &sEditFilePath, ProfileSlot slot );
|
||||||
|
virtual bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
|
||||||
|
virtual bool LoadFromBGChangesString(BackgroundChange &change,
|
||||||
|
const RString &sBGChangeExpression );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Process the BPM Segments from the string.
|
||||||
|
* @param out the TimingData being modified.
|
||||||
|
* @param line the string in question.
|
||||||
|
* @param rowsPerBeat the number of rows per beat for this purpose.
|
||||||
|
* @return true if there was at least one segment found, false otherwise. */
|
||||||
|
bool ProcessBPMs(TimingData & out,
|
||||||
|
const RString line,
|
||||||
|
const int rowsPerBeat = -1);
|
||||||
|
/**
|
||||||
|
* @brief Process the Stop Segments from the string.
|
||||||
|
* @param out the TimingData being modified.
|
||||||
|
* @param line the string in question.
|
||||||
|
* @param rowsPerBeat the number of rows per beat for this purpose. */
|
||||||
|
void ProcessStops(TimingData & out,
|
||||||
|
const RString line,
|
||||||
|
const int rowsPerBeat = -1);
|
||||||
|
/**
|
||||||
|
* @brief Process the Delay Segments from the string.
|
||||||
|
* @param out the TimingData being modified.
|
||||||
|
* @param line the string in question.
|
||||||
|
* @param rowsPerBeat the number of rows per beat for this purpose. */
|
||||||
|
void ProcessDelays(TimingData & out,
|
||||||
|
const RString line,
|
||||||
|
const int rowsPerBeat = -1);
|
||||||
|
/**
|
||||||
|
* @brief Process the Time Signature Segments from the string.
|
||||||
|
* @param out the TimingData being modified.
|
||||||
|
* @param line the string in question.
|
||||||
|
* @param rowsPerBeat the number of rows per beat for this purpose. */
|
||||||
|
void ProcessTimeSignatures(TimingData & out,
|
||||||
|
const RString line,
|
||||||
|
const int rowsPerBeat = -1);
|
||||||
|
/**
|
||||||
|
* @brief Process the Tickcount Segments from the string.
|
||||||
|
* @param out the TimingData being modified.
|
||||||
|
* @param line the string in question.
|
||||||
|
* @param rowsPerBeat the number of rows per beat for this purpose. */
|
||||||
|
void ProcessTickcounts(TimingData & out,
|
||||||
|
const RString line,
|
||||||
|
const int rowsPerBeat = -1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Process the Speed Segments from the string.
|
||||||
|
* @param out the TimingData being modified.
|
||||||
|
* @param line the string in question.
|
||||||
|
* @param rowsPerBeat the number of rows per beat for this purpose. */
|
||||||
|
virtual void ProcessSpeeds(TimingData & out,
|
||||||
|
const RString line,
|
||||||
|
const int rowsPerBeat = -1);
|
||||||
|
|
||||||
|
virtual void ProcessCombos(TimingData & out,
|
||||||
|
const RString line,
|
||||||
|
const int rowsPerBeat = -1) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Process the Fake Segments from the string.
|
||||||
|
* @param out the TimingData being modified.
|
||||||
|
* @param line the string in question.
|
||||||
|
* @param rowsPerBeat the number of rows per beat for this purpose. */
|
||||||
|
virtual void ProcessFakes(TimingData & out,
|
||||||
|
const RString line,
|
||||||
|
const int rowsPerBeat = -1);
|
||||||
|
|
||||||
|
virtual void ProcessBGChanges( Song &out, const RString &sValueName,
|
||||||
const RString &sPath, const RString &sParam );
|
const RString &sPath, const RString &sParam );
|
||||||
void ProcessAttacks( Song &out, MsdFile::value_t sParams );
|
void ProcessAttacks( Song &out, MsdFile::value_t sParams );
|
||||||
void ProcessInstrumentTracks( Song &out, const RString &sParam );
|
void ProcessInstrumentTracks( Song &out, const RString &sParam );
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* @brief Convert a row value to the proper beat value.
|
||||||
|
*
|
||||||
|
* This is primarily used for assistance with converting SMA files.
|
||||||
|
* @param line The line that contains the value.
|
||||||
|
* @param rowsPerBeat the number of rows per beat according to the original file.
|
||||||
|
* @return the converted beat value. */
|
||||||
|
float RowToBeat(RString line, const int rowsPerBeat);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* @brief Process the different tokens we have available to get NoteData.
|
||||||
|
* @param stepsType The current StepsType.
|
||||||
|
* @param description The description of the chart.
|
||||||
|
* @param difficulty The difficulty (in words) of the chart.
|
||||||
|
* @param meter the difficulty (in numbers) of the chart.
|
||||||
|
* @param radarValues the calculated radar values.
|
||||||
|
* @param noteData the note data itself.
|
||||||
|
* @param out the Steps getting the data. */
|
||||||
|
virtual void LoadFromTokens(RString sStepsType,
|
||||||
|
RString sDescription,
|
||||||
|
RString sDifficulty,
|
||||||
|
RString sMeter,
|
||||||
|
RString sRadarValues,
|
||||||
|
RString sNoteData,
|
||||||
|
Steps &out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retrieve the file extension associated with this loader.
|
||||||
|
* @return the file extension. */
|
||||||
|
RString GetFileExtension() const { return fileExt; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
/** @brief The file extension in use. */
|
||||||
|
const RString fileExt;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
+11
-415
@@ -14,240 +14,6 @@
|
|||||||
#include "Steps.h"
|
#include "Steps.h"
|
||||||
#include "Attack.h"
|
#include "Attack.h"
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A custom .edit file can only be so big before we have to reject it.
|
|
||||||
*/
|
|
||||||
const int MAX_EDIT_STEPS_SIZE_BYTES = 60*1024; // 60 KB
|
|
||||||
|
|
||||||
bool SMALoader::LoadFromBGChangesString( BackgroundChange &change,
|
|
||||||
const RString &sBGChangeExpression )
|
|
||||||
{
|
|
||||||
return SMLoader::LoadFromBGChangesString(change, sBGChangeExpression);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SMALoader::LoadFromDir( const RString &sPath, Song &out )
|
|
||||||
{
|
|
||||||
vector<RString> aFileNames;
|
|
||||||
GetApplicableFiles( sPath, aFileNames );
|
|
||||||
|
|
||||||
if( aFileNames.size() > 1 )
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Song", sPath, "has more than one SMA file. Only one SMA file is allowed per song." );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
ASSERT( aFileNames.size() == 1 );
|
|
||||||
return LoadFromSMAFile( sPath + aFileNames[0], out );
|
|
||||||
}
|
|
||||||
|
|
||||||
float SMALoader::RowToBeat( RString sLine, const int iRowsPerBeat )
|
|
||||||
{
|
|
||||||
if( sLine.find("R") || sLine.find("r") )
|
|
||||||
{
|
|
||||||
sLine = sLine.Left(sLine.size()-1);
|
|
||||||
return StringToFloat( sLine ) / iRowsPerBeat;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return StringToFloat( sLine );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SMALoader::ProcessBPMs( TimingData &out, const int iRowsPerBeat, const RString sParam )
|
|
||||||
{
|
|
||||||
vector<RString> arrayBPMChangeExpressions;
|
|
||||||
split( sParam, ",", arrayBPMChangeExpressions );
|
|
||||||
|
|
||||||
// prepare storage variables for negative BPMs -> Warps.
|
|
||||||
float negBeat = -1;
|
|
||||||
float negBPM = 1;
|
|
||||||
float highspeedBeat = -1;
|
|
||||||
bool bNotEmpty = false;
|
|
||||||
|
|
||||||
for( unsigned b=0; b<arrayBPMChangeExpressions.size(); b++ )
|
|
||||||
{
|
|
||||||
vector<RString> arrayBPMChangeValues;
|
|
||||||
split( arrayBPMChangeExpressions[b], "=", arrayBPMChangeValues );
|
|
||||||
// XXX: Hard to tell which file caused this.
|
|
||||||
if( arrayBPMChangeValues.size() != 2 )
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #BPMs value \"%s\" (must have exactly one '='), ignored.",
|
|
||||||
arrayBPMChangeExpressions[b].c_str() );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bNotEmpty = true;
|
|
||||||
|
|
||||||
const float fBeat = RowToBeat( arrayBPMChangeValues[0], iRowsPerBeat );
|
|
||||||
const float fNewBPM = StringToFloat( arrayBPMChangeValues[1] );
|
|
||||||
|
|
||||||
if( fNewBPM < 0.0f )
|
|
||||||
{
|
|
||||||
out.m_bHasNegativeBpms = true;
|
|
||||||
negBeat = fBeat;
|
|
||||||
negBPM = fNewBPM;
|
|
||||||
}
|
|
||||||
else if( fNewBPM > 0.0f )
|
|
||||||
{
|
|
||||||
// add in a warp.
|
|
||||||
if( negBPM < 0 )
|
|
||||||
{
|
|
||||||
float endBeat = fBeat + (fNewBPM / -negBPM) * (fBeat - negBeat);
|
|
||||||
WarpSegment new_seg(negBeat, endBeat - negBeat);
|
|
||||||
out.AddWarpSegment( new_seg );
|
|
||||||
|
|
||||||
negBeat = -1;
|
|
||||||
negBPM = 1;
|
|
||||||
}
|
|
||||||
// too fast. make it a warp.
|
|
||||||
if( fNewBPM > FAST_BPM_WARP )
|
|
||||||
{
|
|
||||||
highspeedBeat = fBeat;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// add in a warp.
|
|
||||||
if( highspeedBeat > 0 )
|
|
||||||
{
|
|
||||||
WarpSegment new_seg(highspeedBeat, fBeat - highspeedBeat);
|
|
||||||
out.AddWarpSegment( new_seg );
|
|
||||||
highspeedBeat = -1;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
BPMSegment new_seg( BeatToNoteRow( fBeat ), fNewBPM );
|
|
||||||
out.AddBPMSegment( new_seg );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bNotEmpty;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SMALoader::ProcessStops( TimingData &out, const int iRowsPerBeat, const RString sParam )
|
|
||||||
{
|
|
||||||
vector<RString> arrayFreezeExpressions;
|
|
||||||
split( sParam, ",", arrayFreezeExpressions );
|
|
||||||
|
|
||||||
// Prepare variables for negative stop conversion.
|
|
||||||
float negBeat = -1;
|
|
||||||
float negPause = 0;
|
|
||||||
|
|
||||||
for( unsigned f=0; f<arrayFreezeExpressions.size(); f++ )
|
|
||||||
{
|
|
||||||
vector<RString> arrayFreezeValues;
|
|
||||||
split( arrayFreezeExpressions[f], "=", arrayFreezeValues );
|
|
||||||
if( arrayFreezeValues.size() != 2 )
|
|
||||||
{
|
|
||||||
// XXX: Hard to tell which file caused this.
|
|
||||||
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #STOPS value \"%s\" (must have exactly one '='), ignored.",
|
|
||||||
arrayFreezeExpressions[f].c_str() );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float fFreezeBeat = RowToBeat( arrayFreezeValues[0], iRowsPerBeat );
|
|
||||||
const float fFreezeSeconds = StringToFloat( arrayFreezeValues[1] );
|
|
||||||
|
|
||||||
// Process the prior stop.
|
|
||||||
if( negPause > 0 )
|
|
||||||
{
|
|
||||||
BPMSegment oldBPM = out.GetBPMSegmentAtRow(BeatToNoteRow(negBeat));
|
|
||||||
float fSecondsPerBeat = 60 / oldBPM.GetBPM();
|
|
||||||
float fSkipBeats = negPause / fSecondsPerBeat;
|
|
||||||
|
|
||||||
if( negBeat + fSkipBeats > fFreezeBeat )
|
|
||||||
fSkipBeats = fFreezeBeat - negBeat;
|
|
||||||
|
|
||||||
WarpSegment ws( negBeat, fSkipBeats);
|
|
||||||
out.AddWarpSegment( ws );
|
|
||||||
|
|
||||||
negBeat = -1;
|
|
||||||
negPause = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( fFreezeSeconds < 0.0f )
|
|
||||||
{
|
|
||||||
negBeat = fFreezeBeat;
|
|
||||||
negPause = -fFreezeSeconds;
|
|
||||||
}
|
|
||||||
else if( fFreezeSeconds > 0.0f )
|
|
||||||
{
|
|
||||||
StopSegment ss( BeatToNoteRow(fFreezeBeat), fFreezeSeconds );
|
|
||||||
out.AddStopSegment( ss );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process the prior stop if there was one.
|
|
||||||
if( negPause > 0 )
|
|
||||||
{
|
|
||||||
BPMSegment oldBPM = out.GetBPMSegmentAtRow(BeatToNoteRow(negBeat));
|
|
||||||
float fSecondsPerBeat = 60 / oldBPM.GetBPM();
|
|
||||||
float fSkipBeats = negPause / fSecondsPerBeat;
|
|
||||||
|
|
||||||
WarpSegment ws( negBeat, fSkipBeats);
|
|
||||||
out.AddWarpSegment( ws );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SMALoader::ProcessDelays( TimingData &out, const int iRowsPerBeat, const RString sParam )
|
|
||||||
{
|
|
||||||
vector<RString> arrayDelayExpressions;
|
|
||||||
split( sParam, ",", arrayDelayExpressions );
|
|
||||||
|
|
||||||
for( unsigned f=0; f<arrayDelayExpressions.size(); f++ )
|
|
||||||
{
|
|
||||||
vector<RString> arrayDelayValues;
|
|
||||||
split( arrayDelayExpressions[f], "=", arrayDelayValues );
|
|
||||||
if( arrayDelayValues.size() != 2 )
|
|
||||||
{
|
|
||||||
// XXX: Hard to tell which file caused this.
|
|
||||||
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #DELAYS value \"%s\" (must have exactly one '='), ignored.",
|
|
||||||
arrayDelayExpressions[f].c_str() );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float fFreezeBeat = RowToBeat( arrayDelayValues[0], iRowsPerBeat );
|
|
||||||
const float fFreezeSeconds = StringToFloat( arrayDelayValues[1] );
|
|
||||||
|
|
||||||
StopSegment new_seg( fFreezeBeat, fFreezeSeconds, true );
|
|
||||||
// XXX: Remove Negatives Bug?
|
|
||||||
new_seg.SetBeat(fFreezeBeat);
|
|
||||||
new_seg.SetPause(fFreezeSeconds);
|
|
||||||
|
|
||||||
// LOG->Trace( "Adding a delay segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds );
|
|
||||||
|
|
||||||
if(fFreezeSeconds > 0.0f)
|
|
||||||
out.AddStopSegment( new_seg );
|
|
||||||
else
|
|
||||||
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid delay at beat %f, length %f.", fFreezeBeat, fFreezeSeconds );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SMALoader::ProcessTickcounts( TimingData &out, const int iRowsPerBeat, const RString sParam )
|
|
||||||
{
|
|
||||||
vector<RString> arrayTickcountExpressions;
|
|
||||||
split( sParam, ",", arrayTickcountExpressions );
|
|
||||||
|
|
||||||
for( unsigned f=0; f<arrayTickcountExpressions.size(); f++ )
|
|
||||||
{
|
|
||||||
vector<RString> arrayTickcountValues;
|
|
||||||
split( arrayTickcountExpressions[f], "=", arrayTickcountValues );
|
|
||||||
if( arrayTickcountValues.size() != 2 )
|
|
||||||
{
|
|
||||||
// XXX: Hard to tell which file caused this.
|
|
||||||
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #TICKCOUNTS value \"%s\" (must have exactly one '='), ignored.",
|
|
||||||
arrayTickcountExpressions[f].c_str() );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float fTickcountBeat = RowToBeat( arrayTickcountValues[0], iRowsPerBeat );
|
|
||||||
int iTicks = clamp(atoi( arrayTickcountValues[1] ), 0, ROWS_PER_BEAT);
|
|
||||||
|
|
||||||
TickcountSegment new_seg( BeatToNoteRow(fTickcountBeat), iTicks );
|
|
||||||
out.AddTickcountSegment( new_seg );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SMALoader::ProcessMultipliers( TimingData &out, const int iRowsPerBeat, const RString sParam )
|
void SMALoader::ProcessMultipliers( TimingData &out, const int iRowsPerBeat, const RString sParam )
|
||||||
{
|
{
|
||||||
vector<RString> arrayMultiplierExpressions;
|
vector<RString> arrayMultiplierExpressions;
|
||||||
@@ -306,15 +72,10 @@ void SMALoader::ProcessBeatsPerMeasure( TimingData &out, const RString sParam )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float BeatToSeconds(float fromBeat, RString toSomething)
|
void SMALoader::ProcessSpeeds( TimingData &out, const RString line, const int rowsPerBeat )
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SMALoader::ProcessSpeeds( TimingData &out, const int iRowsPerBeat, const RString sParam )
|
|
||||||
{
|
{
|
||||||
vector<RString> vs1;
|
vector<RString> vs1;
|
||||||
split( sParam, ",", vs1 );
|
split( line, ",", vs1 );
|
||||||
|
|
||||||
FOREACH_CONST( RString, vs1, s1 )
|
FOREACH_CONST( RString, vs1, s1 )
|
||||||
{
|
{
|
||||||
@@ -335,7 +96,7 @@ void SMALoader::ProcessSpeeds( TimingData &out, const int iRowsPerBeat, const RS
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float fBeat = RowToBeat( vs2[0], iRowsPerBeat );
|
const float fBeat = RowToBeat( vs2[0], rowsPerBeat );
|
||||||
|
|
||||||
RString backup = vs2[2];
|
RString backup = vs2[2];
|
||||||
Trim(vs2[2], "s");
|
Trim(vs2[2], "s");
|
||||||
@@ -362,57 +123,7 @@ void SMALoader::ProcessSpeeds( TimingData &out, const int iRowsPerBeat, const RS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMALoader::ProcessFakes( TimingData &out, const int iRowsPerBeat, const RString sParam )
|
bool SMALoader::LoadFromSimfile( const RString &sPath, Song &out, bool bFromCache )
|
||||||
{
|
|
||||||
vector<RString> arrayFakeExpressions;
|
|
||||||
split( sParam, ",", arrayFakeExpressions );
|
|
||||||
|
|
||||||
for( unsigned b=0; b<arrayFakeExpressions.size(); b++ )
|
|
||||||
{
|
|
||||||
vector<RString> arrayFakeValues;
|
|
||||||
split( arrayFakeExpressions[b], "=", arrayFakeValues );
|
|
||||||
// XXX: Hard to tell which file caused this.
|
|
||||||
if( arrayFakeValues.size() != 2 )
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #FAKES value \"%s\" (must have exactly one '='), ignored.",
|
|
||||||
arrayFakeExpressions[b].c_str() );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float fBeat = RowToBeat( arrayFakeValues[0], iRowsPerBeat );
|
|
||||||
const float fNewBeat = StringToFloat( arrayFakeValues[1] );
|
|
||||||
|
|
||||||
if(fNewBeat > 0)
|
|
||||||
out.AddFakeSegment( FakeSegment(fBeat, fNewBeat) );
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid Fake at beat %f, BPM %f.", fBeat, fNewBeat );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void SMALoader::LoadFromSMATokens(
|
|
||||||
RString sStepsType,
|
|
||||||
RString sDescription,
|
|
||||||
RString sDifficulty,
|
|
||||||
RString sMeter,
|
|
||||||
RString sRadarValues,
|
|
||||||
RString sNoteData,
|
|
||||||
Steps &out
|
|
||||||
)
|
|
||||||
{
|
|
||||||
SMLoader::LoadFromSMTokens( sStepsType, sDescription,
|
|
||||||
sDifficulty, sMeter, sRadarValues,
|
|
||||||
sNoteData, out );
|
|
||||||
}
|
|
||||||
|
|
||||||
void SMALoader::TidyUpData( Song &song, bool bFromCache )
|
|
||||||
{
|
|
||||||
SMLoader::TidyUpData( song, bFromCache );
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out )
|
|
||||||
{
|
{
|
||||||
LOG->Trace( "Song::LoadFromSMAFile(%s)", sPath.c_str() );
|
LOG->Trace( "Song::LoadFromSMAFile(%s)", sPath.c_str() );
|
||||||
|
|
||||||
@@ -635,28 +346,28 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out )
|
|||||||
{
|
{
|
||||||
TimingData &timing = (state == SMA_GETTING_STEP_INFO
|
TimingData &timing = (state == SMA_GETTING_STEP_INFO
|
||||||
? pNewNotes->m_Timing : out.m_SongTiming);
|
? pNewNotes->m_Timing : out.m_SongTiming);
|
||||||
ProcessBPMs( timing, iRowsPerBeat, sParams[1] );
|
ProcessBPMs( timing, sParams[1], iRowsPerBeat );
|
||||||
}
|
}
|
||||||
|
|
||||||
else if( sValueName=="STOPS" || sValueName=="FREEZES" )
|
else if( sValueName=="STOPS" || sValueName=="FREEZES" )
|
||||||
{
|
{
|
||||||
TimingData &timing = (state == SMA_GETTING_STEP_INFO
|
TimingData &timing = (state == SMA_GETTING_STEP_INFO
|
||||||
? pNewNotes->m_Timing : out.m_SongTiming);
|
? pNewNotes->m_Timing : out.m_SongTiming);
|
||||||
ProcessStops( timing, iRowsPerBeat, sParams[1] );
|
ProcessStops( timing, sParams[1], iRowsPerBeat );
|
||||||
}
|
}
|
||||||
|
|
||||||
else if( sValueName=="DELAYS" )
|
else if( sValueName=="DELAYS" )
|
||||||
{
|
{
|
||||||
TimingData &timing = (state == SMA_GETTING_STEP_INFO
|
TimingData &timing = (state == SMA_GETTING_STEP_INFO
|
||||||
? pNewNotes->m_Timing : out.m_SongTiming);
|
? pNewNotes->m_Timing : out.m_SongTiming);
|
||||||
ProcessDelays( timing, iRowsPerBeat, sParams[1] );
|
ProcessDelays( timing, sParams[1], iRowsPerBeat );
|
||||||
}
|
}
|
||||||
|
|
||||||
else if( sValueName=="TICKCOUNT" )
|
else if( sValueName=="TICKCOUNT" )
|
||||||
{
|
{
|
||||||
TimingData &timing = (state == SMA_GETTING_STEP_INFO
|
TimingData &timing = (state == SMA_GETTING_STEP_INFO
|
||||||
? pNewNotes->m_Timing : out.m_SongTiming);
|
? pNewNotes->m_Timing : out.m_SongTiming);
|
||||||
ProcessTickcounts( timing, iRowsPerBeat, sParams[1] );
|
ProcessTickcounts( timing, sParams[1], iRowsPerBeat );
|
||||||
}
|
}
|
||||||
|
|
||||||
else if( sValueName=="SPEED" )
|
else if( sValueName=="SPEED" )
|
||||||
@@ -665,7 +376,7 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out )
|
|||||||
? pNewNotes->m_Timing : out.m_SongTiming);
|
? pNewNotes->m_Timing : out.m_SongTiming);
|
||||||
RString tmp = sParams[1];
|
RString tmp = sParams[1];
|
||||||
Trim( tmp );
|
Trim( tmp );
|
||||||
ProcessSpeeds( timing, iRowsPerBeat, tmp );
|
ProcessSpeeds( timing, tmp, iRowsPerBeat );
|
||||||
}
|
}
|
||||||
|
|
||||||
else if( sValueName=="MULTIPLIER" )
|
else if( sValueName=="MULTIPLIER" )
|
||||||
@@ -679,7 +390,7 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out )
|
|||||||
{
|
{
|
||||||
TimingData &timing = (state == SMA_GETTING_STEP_INFO
|
TimingData &timing = (state == SMA_GETTING_STEP_INFO
|
||||||
? pNewNotes->m_Timing : out.m_SongTiming);
|
? pNewNotes->m_Timing : out.m_SongTiming);
|
||||||
ProcessFakes( timing, iRowsPerBeat, sParams[1] );
|
ProcessFakes( timing, sParams[1], iRowsPerBeat );
|
||||||
}
|
}
|
||||||
|
|
||||||
else if( sValueName=="METERTYPE" )
|
else if( sValueName=="METERTYPE" )
|
||||||
@@ -706,7 +417,7 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out )
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadFromSMATokens(
|
LoadFromTokens(
|
||||||
sParams[1],
|
sParams[1],
|
||||||
sParams[2],
|
sParams[2],
|
||||||
sParams[3],
|
sParams[3],
|
||||||
@@ -727,121 +438,6 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out )
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMALoader::GetApplicableFiles( const RString &sPath, vector<RString> &out )
|
|
||||||
{
|
|
||||||
GetDirListing( sPath + RString("*.sma"), out );
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SMALoader::LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong )
|
|
||||||
{
|
|
||||||
LOG->Trace( "SMALoader::LoadEditFromFile(%s)", sEditFilePath.c_str() );
|
|
||||||
|
|
||||||
int iBytes = FILEMAN->GetFileSizeInBytes( sEditFilePath );
|
|
||||||
if( iBytes > MAX_EDIT_STEPS_SIZE_BYTES )
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Edit file", sEditFilePath, "is unreasonably large. It won't be loaded." );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
MsdFile msd;
|
|
||||||
if( !msd.ReadFile( sEditFilePath, true ) ) // unescape
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Edit file", sEditFilePath, "couldn't be opened: %s", msd.GetError().c_str() );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return LoadEditFromMsd( msd, sEditFilePath, slot, bAddStepsToSong );
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SMALoader::LoadEditFromBuffer( const RString &sBuffer, const RString &sEditFilePath, ProfileSlot slot )
|
|
||||||
{
|
|
||||||
MsdFile msd;
|
|
||||||
msd.ReadFromString( sBuffer, true ); // unescape
|
|
||||||
return LoadEditFromMsd( msd, sEditFilePath, slot, true );
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SMALoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong )
|
|
||||||
{
|
|
||||||
Song* pSong = NULL;
|
|
||||||
|
|
||||||
for( unsigned i=0; i<msd.GetNumValues(); i++ )
|
|
||||||
{
|
|
||||||
int iNumParams = msd.GetNumParams(i);
|
|
||||||
const MsdFile::value_t &sParams = msd.GetValue(i);
|
|
||||||
RString sValueName = sParams[0];
|
|
||||||
sValueName.MakeUpper();
|
|
||||||
|
|
||||||
// handle the data
|
|
||||||
if( sValueName=="SONG" )
|
|
||||||
{
|
|
||||||
if( pSong )
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Edit file", sEditFilePath, "has more than one #SONG tag." );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
RString sSongFullTitle = sParams[1];
|
|
||||||
sSongFullTitle.Replace( '\\', '/' );
|
|
||||||
|
|
||||||
pSong = SONGMAN->FindSong( sSongFullTitle );
|
|
||||||
if( pSong == NULL )
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Edit file", sEditFilePath, "requires a song \"%s\" that isn't present.", sSongFullTitle.c_str() );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( pSong->GetNumStepsLoadedFromProfile(slot) >= MAX_EDITS_PER_SONG_PER_PROFILE )
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Song file", sSongFullTitle, "already has the maximum number of edits allowed for ProfileSlotP%d.", slot+1 );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if( sValueName=="NOTES" )
|
|
||||||
{
|
|
||||||
if( pSong == NULL )
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Edit file", sEditFilePath, "doesn't have a #SONG tag preceeding the first #NOTES tag." );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( iNumParams < 7 )
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Edit file", sEditFilePath, "has %d fields in a #NOTES tag, but should have at least 7.", iNumParams );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !bAddStepsToSong )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
Steps* pNewNotes = pSong->CreateSteps();
|
|
||||||
LoadFromSMATokens(
|
|
||||||
sParams[1], sParams[2], sParams[3], sParams[4], sParams[5], sParams[6],
|
|
||||||
*pNewNotes);
|
|
||||||
|
|
||||||
pNewNotes->SetLoadedFromProfile( slot );
|
|
||||||
pNewNotes->SetDifficulty( Difficulty_Edit );
|
|
||||||
pNewNotes->SetFilename( sEditFilePath );
|
|
||||||
|
|
||||||
if( pSong->IsEditAlreadyLoaded(pNewNotes) )
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Edit file", sEditFilePath, "is a duplicate of another edit that was already loaded." );
|
|
||||||
SAFE_DELETE( pNewNotes );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pSong->AddSteps( pNewNotes );
|
|
||||||
return true; // Only allow one Steps per edit file!
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Edit file", sEditFilePath, "has an unexpected value \"%s\".", sValueName.c_str() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file
|
* @file
|
||||||
* @author Aldo Fregoso, Jason Felds (c) 2009-2011
|
* @author Aldo Fregoso, Jason Felds (c) 2009-2011
|
||||||
|
|||||||
+10
-25
@@ -2,6 +2,7 @@
|
|||||||
#define NOTES_LOADER_SMA_H
|
#define NOTES_LOADER_SMA_H
|
||||||
|
|
||||||
#include "GameConstantsAndTypes.h"
|
#include "GameConstantsAndTypes.h"
|
||||||
|
#include "NotesLoaderSM.h"
|
||||||
#include "BackgroundUtil.h"
|
#include "BackgroundUtil.h"
|
||||||
|
|
||||||
class MsdFile;
|
class MsdFile;
|
||||||
@@ -20,37 +21,21 @@ enum SMALoadingStates
|
|||||||
};
|
};
|
||||||
|
|
||||||
/** @brief Reads a Song from a .SMA file. */
|
/** @brief Reads a Song from a .SMA file. */
|
||||||
namespace SMALoader
|
struct SMALoader : public SMLoader
|
||||||
{
|
{
|
||||||
void LoadFromSMATokens( RString sStepsType,
|
SMALoader() : SMLoader(".sma") {}
|
||||||
RString sDescription,
|
|
||||||
RString sDifficulty,
|
|
||||||
RString sMeter,
|
|
||||||
RString sRadarValues,
|
|
||||||
RString sNoteData,
|
|
||||||
Steps &out );
|
|
||||||
|
|
||||||
bool LoadFromDir( const RString &sPath, Song &out );
|
virtual bool LoadFromSimfile( const RString &sPath, Song &out, bool bFromCache = false );
|
||||||
void TidyUpData( Song &song, bool bFromCache );
|
|
||||||
|
|
||||||
bool LoadFromSMAFile( const RString &sPath, Song &out );
|
|
||||||
void GetApplicableFiles( const RString &sPath, vector<RString> &out );
|
|
||||||
|
|
||||||
bool LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
|
|
||||||
bool LoadEditFromBuffer( const RString &sBuffer, const RString &sEditFilePath, ProfileSlot slot );
|
|
||||||
bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
|
|
||||||
bool LoadFromBGChangesString( BackgroundChange &change, const RString &sBGChangeExpression );
|
|
||||||
|
|
||||||
void ProcessBeatsPerMeasure( TimingData &out, const RString sParam );
|
void ProcessBeatsPerMeasure( TimingData &out, const RString sParam );
|
||||||
bool ProcessBPMs( TimingData &out, const int iRowsPerBeat, const RString sParam );
|
|
||||||
void ProcessStops( TimingData &out, const int iRowsPerBeat, const RString sParam );
|
|
||||||
void ProcessDelays( TimingData &out, const int iRowsPerBeat, const RString sParam );
|
|
||||||
void ProcessTickcounts( TimingData &out, const int iRowsPerBeat, const RString sParam );
|
|
||||||
void ProcessMultipliers( TimingData &out, const int iRowsPerBeat, const RString sParam );
|
void ProcessMultipliers( TimingData &out, const int iRowsPerBeat, const RString sParam );
|
||||||
void ProcessSpeeds( TimingData &out, const int iRowsPerBeat, const RString sParam );
|
/**
|
||||||
void ProcessFakes( TimingData &out, const int iRowsPerBeat, const RString sParam );
|
* @brief Process the Speed Segments from the string.
|
||||||
|
* @param out the TimingData being modified.
|
||||||
float RowToBeat( RString sLine, const int iRowsPerBeat );
|
* @param line the string in question.
|
||||||
|
* @param rowsPerBeat the number of rows per beat for this purpose. */
|
||||||
|
virtual void ProcessSpeeds( TimingData &out, const RString line, const int rowsPerBeat );
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+10
-124
@@ -14,38 +14,6 @@
|
|||||||
#include "Attack.h"
|
#include "Attack.h"
|
||||||
#include "PrefsManager.h"
|
#include "PrefsManager.h"
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A custom .edit file can only be so big before we have to reject it.
|
|
||||||
*/
|
|
||||||
const int MAX_EDIT_STEPS_SIZE_BYTES = 60*1024; // 60 KB
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Attempt to load any background changes in use by this song.
|
|
||||||
* @param change a reference to the background change.
|
|
||||||
* @param sBGChangeExpression a reference to the list of changes to be made.
|
|
||||||
* @return its success or failure.
|
|
||||||
*/
|
|
||||||
bool LoadFromBGSSCChangesString( BackgroundChange &change, const RString &sBGChangeExpression )
|
|
||||||
{
|
|
||||||
return SMLoader::LoadFromBGChangesString( change, sBGChangeExpression );
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SSCLoader::LoadFromDir( const RString &sPath, Song &out )
|
|
||||||
{
|
|
||||||
vector<RString> aFileNames;
|
|
||||||
GetApplicableFiles( sPath, aFileNames );
|
|
||||||
|
|
||||||
if( aFileNames.size() > 1 )
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Song", sPath, "has more than one SSC file. Only one SSC file is allowed per song." );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT( aFileNames.size() == 1 ); // Ensure one was found entirely.
|
|
||||||
|
|
||||||
return LoadFromSSCFile( sPath + aFileNames[0], out );
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSCLoader::ProcessWarps( TimingData &out, const RString sParam, const float fVersion )
|
void SSCLoader::ProcessWarps( TimingData &out, const RString sParam, const float fVersion )
|
||||||
{
|
{
|
||||||
vector<RString> arrayWarpExpressions;
|
vector<RString> arrayWarpExpressions;
|
||||||
@@ -108,10 +76,10 @@ void SSCLoader::ProcessLabels( TimingData &out, const RString sParam )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSCLoader::ProcessCombos( TimingData &out, const RString sParam )
|
void SSCLoader::ProcessCombos( TimingData &out, const RString line, const int rowsPerBeat )
|
||||||
{
|
{
|
||||||
vector<RString> arrayComboExpressions;
|
vector<RString> arrayComboExpressions;
|
||||||
split( sParam, ",", arrayComboExpressions );
|
split( line, ",", arrayComboExpressions );
|
||||||
|
|
||||||
for( unsigned f=0; f<arrayComboExpressions.size(); f++ )
|
for( unsigned f=0; f<arrayComboExpressions.size(); f++ )
|
||||||
{
|
{
|
||||||
@@ -130,53 +98,6 @@ void SSCLoader::ProcessCombos( TimingData &out, const RString sParam )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSCLoader::ProcessSpeeds( TimingData &out, const RString sParam )
|
|
||||||
{
|
|
||||||
vector<RString> vs1;
|
|
||||||
split( sParam, ",", vs1 );
|
|
||||||
|
|
||||||
FOREACH_CONST( RString, vs1, s1 )
|
|
||||||
{
|
|
||||||
vector<RString> vs2;
|
|
||||||
split( *s1, "=", vs2 );
|
|
||||||
|
|
||||||
if( vs2[0] == 0 && vs2.size() == 2 ) // First one always seems to have 2.
|
|
||||||
{
|
|
||||||
vs2.push_back("0");
|
|
||||||
}
|
|
||||||
|
|
||||||
if( vs2.size() == 3 ) // use beats by default.
|
|
||||||
{
|
|
||||||
vs2.push_back("0");
|
|
||||||
}
|
|
||||||
|
|
||||||
if( vs2.size() < 4 )
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Song file", "(UNKNOWN)", "has an speed change with %i values.", (int)vs2.size() );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float fBeat = StringToFloat( vs2[0] );
|
|
||||||
|
|
||||||
SpeedSegment seg( fBeat, StringToFloat( vs2[1] ), StringToFloat( vs2[2] ));
|
|
||||||
seg.SetUnit(StringToInt(vs2[3]));
|
|
||||||
|
|
||||||
if( fBeat < 0 )
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Song file", "(UNKNOWN)", "has an speed change with beat %f.", fBeat );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( seg.GetLength() < 0 )
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Song file", "(UNKNOWN)", "has an speed change with beat %f, length %f.", fBeat, seg.GetLength() );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
out.AddSpeedSegment( seg );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSCLoader::ProcessScrolls( TimingData &out, const RString sParam )
|
void SSCLoader::ProcessScrolls( TimingData &out, const RString sParam )
|
||||||
{
|
{
|
||||||
vector<RString> vs1;
|
vector<RString> vs1;
|
||||||
@@ -207,37 +128,8 @@ void SSCLoader::ProcessScrolls( TimingData &out, const RString sParam )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSCLoader::ProcessFakes( TimingData &out, const RString sParam )
|
|
||||||
{
|
|
||||||
vector<RString> arrayFakeExpressions;
|
|
||||||
split( sParam, ",", arrayFakeExpressions );
|
|
||||||
|
|
||||||
for( unsigned b=0; b<arrayFakeExpressions.size(); b++ )
|
bool SSCLoader::LoadFromSimfile( const RString &sPath, Song &out, bool bFromCache )
|
||||||
{
|
|
||||||
vector<RString> arrayFakeValues;
|
|
||||||
split( arrayFakeExpressions[b], "=", arrayFakeValues );
|
|
||||||
// XXX: Hard to tell which file caused this.
|
|
||||||
if( arrayFakeValues.size() != 2 )
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #FAKES value \"%s\" (must have exactly one '='), ignored.",
|
|
||||||
arrayFakeExpressions[b].c_str() );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float fBeat = StringToFloat( arrayFakeValues[0] );
|
|
||||||
const float fNewBeat = StringToFloat( arrayFakeValues[1] );
|
|
||||||
|
|
||||||
if(fNewBeat > 0)
|
|
||||||
out.AddFakeSegment( FakeSegment(fBeat, fNewBeat) );
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid Fake at beat %f, BPM %f.", fBeat, fNewBeat );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCache )
|
|
||||||
{
|
{
|
||||||
LOG->Trace( "Song::LoadFromSSCFile(%s)", sPath.c_str() );
|
LOG->Trace( "Song::LoadFromSSCFile(%s)", sPath.c_str() );
|
||||||
|
|
||||||
@@ -421,7 +313,7 @@ bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCach
|
|||||||
for( unsigned b=0; b<aFGChangeExpressions.size(); b++ )
|
for( unsigned b=0; b<aFGChangeExpressions.size(); b++ )
|
||||||
{
|
{
|
||||||
BackgroundChange change;
|
BackgroundChange change;
|
||||||
if( LoadFromBGSSCChangesString( change, aFGChangeExpressions[b] ) )
|
if( LoadFromBGChangesString( change, aFGChangeExpressions[b] ) )
|
||||||
out.AddForegroundChange( change );
|
out.AddForegroundChange( change );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -665,11 +557,6 @@ bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCach
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSCLoader::GetApplicableFiles( const RString &sPath, vector<RString> &out )
|
|
||||||
{
|
|
||||||
GetDirListing( sPath + RString("*.ssc"), out );
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SSCLoader::LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong )
|
bool SSCLoader::LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong )
|
||||||
{
|
{
|
||||||
LOG->Trace( "SSCLoader::LoadEditFromFile(%s)", sEditFilePath.c_str() );
|
LOG->Trace( "SSCLoader::LoadEditFromFile(%s)", sEditFilePath.c_str() );
|
||||||
@@ -883,8 +770,12 @@ bool SSCLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePat
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
pNewNotes = pSong->CreateSteps();
|
pNewNotes = pSong->CreateSteps();
|
||||||
SMLoader::LoadFromSMTokens(
|
LoadFromTokens(sParams[1],
|
||||||
sParams[1], sParams[2], sParams[3], sParams[4], sParams[5], sParams[6],
|
sParams[2],
|
||||||
|
sParams[3],
|
||||||
|
sParams[4],
|
||||||
|
sParams[5],
|
||||||
|
sParams[6],
|
||||||
*pNewNotes);
|
*pNewNotes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -913,11 +804,6 @@ bool SSCLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePat
|
|||||||
return bSSCFormat;
|
return bSSCFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSCLoader::TidyUpData( Song &song, bool bFromCache )
|
|
||||||
{
|
|
||||||
SMLoader::TidyUpData(song, bFromCache);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (c) 2011 Jason Felds
|
* (c) 2011 Jason Felds
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|||||||
+9
-25
@@ -3,6 +3,7 @@
|
|||||||
#define NotesLoaderSSC_H
|
#define NotesLoaderSSC_H
|
||||||
|
|
||||||
#include "GameConstantsAndTypes.h"
|
#include "GameConstantsAndTypes.h"
|
||||||
|
#include "NotesLoaderSM.h"
|
||||||
|
|
||||||
class MsdFile;
|
class MsdFile;
|
||||||
class Song;
|
class Song;
|
||||||
@@ -29,15 +30,10 @@ const float VERSION_SPLIT_TIMING = 0.7f;
|
|||||||
/**
|
/**
|
||||||
* @brief The SSCLoader handles all of the parsing needed for .ssc files.
|
* @brief The SSCLoader handles all of the parsing needed for .ssc files.
|
||||||
*/
|
*/
|
||||||
namespace SSCLoader
|
struct SSCLoader : public SMLoader
|
||||||
{
|
{
|
||||||
/**
|
SSCLoader() : SMLoader(".ssc") {}
|
||||||
* @brief Attempt to load a song from a specified path.
|
|
||||||
* @param sPath a const reference to the path on the hard drive to check.
|
|
||||||
* @param out a reference to the Song that will retrieve the song information.
|
|
||||||
* @return its success or failure.
|
|
||||||
*/
|
|
||||||
bool LoadFromDir( const RString &sPath, Song &out );
|
|
||||||
/**
|
/**
|
||||||
* @brief Attempt to load the specified ssc file.
|
* @brief Attempt to load the specified ssc file.
|
||||||
* @param sPath a const reference to the path on the hard drive to check.
|
* @param sPath a const reference to the path on the hard drive to check.
|
||||||
@@ -45,13 +41,8 @@ namespace SSCLoader
|
|||||||
* @param bFromCache a check to see if we are getting certain information from the cache file.
|
* @param bFromCache a check to see if we are getting certain information from the cache file.
|
||||||
* @return its success or failure.
|
* @return its success or failure.
|
||||||
*/
|
*/
|
||||||
bool LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCache = false );
|
virtual bool LoadFromSimfile( const RString &sPath, Song &out, bool bFromCache = false );
|
||||||
/**
|
|
||||||
* @brief Retrieve the list of .ssc files.
|
|
||||||
* @param sPath a const reference to the path on the hard drive to check.
|
|
||||||
* @param out a vector of files found in the path.
|
|
||||||
*/
|
|
||||||
void GetApplicableFiles( const RString &sPath, vector<RString> &out );
|
|
||||||
/**
|
/**
|
||||||
* @brief Attempt to load an edit from the hard drive.
|
* @brief Attempt to load an edit from the hard drive.
|
||||||
* @param sEditFilePath a path on the hard drive to check.
|
* @param sEditFilePath a path on the hard drive to check.
|
||||||
@@ -69,21 +60,14 @@ namespace SSCLoader
|
|||||||
* @return its success or failure.
|
* @return its success or failure.
|
||||||
*/
|
*/
|
||||||
bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
|
bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
|
||||||
/**
|
|
||||||
* @brief Perform some cleanup on the loaded song.
|
|
||||||
* @param song a reference to the song that may need cleaning up.
|
|
||||||
* @param bFromCache a flag to determine if this song is loaded from a cache file.
|
|
||||||
*/
|
|
||||||
void TidyUpData( Song &song, bool bFromCache );
|
|
||||||
|
|
||||||
|
|
||||||
void ProcessWarps( TimingData &, const RString, const float );
|
void ProcessWarps( TimingData &, const RString, const float );
|
||||||
void ProcessLabels( TimingData &, const RString );
|
void ProcessLabels( TimingData &, const RString );
|
||||||
void ProcessCombos( TimingData &, const RString );
|
virtual void ProcessCombos( TimingData &, const RString, const int = -1 );
|
||||||
void ProcessSpeeds( TimingData &, const RString );
|
|
||||||
void ProcessScrolls( TimingData &, const RString );
|
void ProcessScrolls( TimingData &, const RString );
|
||||||
void ProcessFakes( TimingData &, const RString );
|
};
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
/**
|
/**
|
||||||
* @file
|
* @file
|
||||||
|
|||||||
@@ -21,10 +21,12 @@ void ScreenGameplaySyncMachine::Init()
|
|||||||
|
|
||||||
RString sFile = THEME->GetPathO("ScreenGameplaySyncMachine","music");
|
RString sFile = THEME->GetPathO("ScreenGameplaySyncMachine","music");
|
||||||
// Allow themers to use either a .ssc or .sm file for this. -aj
|
// Allow themers to use either a .ssc or .sm file for this. -aj
|
||||||
|
SSCLoader loaderSSC;
|
||||||
|
SMLoader loaderSM;
|
||||||
if(sFile.Right(4) == ".ssc")
|
if(sFile.Right(4) == ".ssc")
|
||||||
SSCLoader::LoadFromSSCFile( sFile, m_Song );
|
loaderSSC.LoadFromSimfile( sFile, m_Song );
|
||||||
else
|
else
|
||||||
SMLoader::LoadFromSMFile( sFile, m_Song );
|
loaderSM.LoadFromSimfile( sFile, m_Song );
|
||||||
|
|
||||||
m_Song.SetSongDir( Dirname(sFile) );
|
m_Song.SetSongDir( Dirname(sFile) );
|
||||||
m_Song.TidyUpData();
|
m_Song.TidyUpData();
|
||||||
|
|||||||
@@ -135,10 +135,12 @@ void ScreenHowToPlay::Init()
|
|||||||
|
|
||||||
// Allow themers to use either a .ssc or .sm file for this. -aj
|
// Allow themers to use either a .ssc or .sm file for this. -aj
|
||||||
RString sStepsPath = THEME->GetPathO(m_sName, "steps");
|
RString sStepsPath = THEME->GetPathO(m_sName, "steps");
|
||||||
|
SSCLoader loaderSSC;
|
||||||
|
SMLoader loaderSM;
|
||||||
if( sStepsPath.Right(4) == ".ssc" )
|
if( sStepsPath.Right(4) == ".ssc" )
|
||||||
SSCLoader::LoadFromSSCFile( sStepsPath, m_Song, false );
|
loaderSSC.LoadFromSimfile( sStepsPath, m_Song, false );
|
||||||
else
|
else
|
||||||
SMLoader::LoadFromSMFile( sStepsPath, m_Song, false );
|
loaderSM.LoadFromSimfile( sStepsPath, m_Song, false );
|
||||||
m_Song.AddAutoGenNotes();
|
m_Song.AddAutoGenNotes();
|
||||||
|
|
||||||
const Style* pStyle = GAMESTATE->GetCurrentStyle();
|
const Style* pStyle = GAMESTATE->GetCurrentStyle();
|
||||||
|
|||||||
@@ -197,7 +197,8 @@ static void CopyEdits( const RString &sFromProfileDir, const RString &sToProfile
|
|||||||
iNumErrored++;
|
iNumErrored++;
|
||||||
|
|
||||||
// Test whether the song we need for this edit is present and ignore this edit if not present.
|
// Test whether the song we need for this edit is present and ignore this edit if not present.
|
||||||
if( !SSCLoader::LoadEditFromFile( sFromDir+*i, ProfileSlot_Machine, false ) )
|
SSCLoader loaderSSC;
|
||||||
|
if( !loaderSSC.LoadEditFromFile( sFromDir+*i, ProfileSlot_Machine, false ) )
|
||||||
{
|
{
|
||||||
iNumIgnored++;
|
iNumIgnored++;
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
+5
-3
@@ -235,12 +235,14 @@ bool Song::LoadFromSongDir( RString sDir )
|
|||||||
if( bUseCache )
|
if( bUseCache )
|
||||||
{
|
{
|
||||||
// LOG->Trace( "Loading '%s' from cache file '%s'.", m_sSongDir.c_str(), GetCacheFilePath().c_str() );
|
// LOG->Trace( "Loading '%s' from cache file '%s'.", m_sSongDir.c_str(), GetCacheFilePath().c_str() );
|
||||||
bool bLoadedFromSSC = SSCLoader::LoadFromSSCFile( sCacheFilePath, *this, true );
|
SSCLoader loaderSSC;
|
||||||
|
bool bLoadedFromSSC = loaderSSC.LoadFromSimfile( sCacheFilePath, *this, true );
|
||||||
if( !bLoadedFromSSC )
|
if( !bLoadedFromSSC )
|
||||||
{
|
{
|
||||||
// load from .sm
|
// load from .sm
|
||||||
SMLoader::LoadFromSMFile( sCacheFilePath, *this, true );
|
SMLoader loaderSM;
|
||||||
SMLoader::TidyUpData( *this, true );
|
loaderSM.LoadFromSimfile( sCacheFilePath, *this, true );
|
||||||
|
loaderSM.TidyUpData( *this, true );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
+6
-3
@@ -1655,12 +1655,15 @@ void SongManager::LoadStepEditsFromProfileDir( const RString &sProfileDir, Profi
|
|||||||
for( int i=0; i<size; i++ )
|
for( int i=0; i<size; i++ )
|
||||||
{
|
{
|
||||||
RString fn = vsFiles[i];
|
RString fn = vsFiles[i];
|
||||||
|
SSCLoader loaderSSC;
|
||||||
bool bLoadedFromSSC = SSCLoader::LoadEditFromFile( fn, slot, true );
|
bool bLoadedFromSSC = loaderSSC.LoadEditFromFile( fn, slot, true );
|
||||||
// If we don't load the edit from a .ssc-style .edit, then we should
|
// If we don't load the edit from a .ssc-style .edit, then we should
|
||||||
// also try the .sm-style edit file. -aj
|
// also try the .sm-style edit file. -aj
|
||||||
if( !bLoadedFromSSC )
|
if( !bLoadedFromSSC )
|
||||||
SMLoader::LoadEditFromFile( fn, slot, true );
|
{
|
||||||
|
SMLoader loaderSM;
|
||||||
|
loaderSM.LoadEditFromFile( fn, slot, true );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -242,11 +242,13 @@ void Steps::Decompress() const
|
|||||||
{
|
{
|
||||||
// We have data on disk and not in memory. Load it.
|
// We have data on disk and not in memory. Load it.
|
||||||
Song s;
|
Song s;
|
||||||
bool bLoadedFromSSC = SSCLoader::LoadFromSSCFile(m_sFilename, s, true);
|
SSCLoader loaderSSC;
|
||||||
|
bool bLoadedFromSSC = loaderSSC.LoadFromSimfile(m_sFilename, s, true);
|
||||||
if( !bLoadedFromSSC )
|
if( !bLoadedFromSSC )
|
||||||
{
|
{
|
||||||
// try reading from .sm instead
|
// try reading from .sm instead
|
||||||
if( !SMLoader::LoadFromSMFile(m_sFilename, s, true) )
|
SMLoader loaderSM;
|
||||||
|
if( !loaderSM.LoadFromSimfile(m_sFilename, s, true) )
|
||||||
{
|
{
|
||||||
LOG->Warn( "Couldn't load \"%s\"", m_sFilename.c_str() );
|
LOG->Warn( "Couldn't load \"%s\"", m_sFilename.c_str() );
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user