Added autosave to edit mode.
This commit is contained in:
@@ -1486,6 +1486,7 @@ Zoom In Camera=Zoom In Camera
|
||||
Adding New Attack=Enter the new modifier for this attack.\nThe length can be adjusted later.\nLeave it blank to cancel.
|
||||
Adding New Mod=Please enter the new modifier for this attack.\n\nLeave it blank to cancel.
|
||||
Are you sure you want to clear %d notes?=Are you sure you want to clear %d notes?
|
||||
Autosave successful.=Autosave successful.
|
||||
Edit Existing Mod=Please adjust the present modifier below.\n\nLeave it blank to erase the mod.
|
||||
Edit Attack Start=Enter the time when this attack starts.
|
||||
Edit Attack Length=Enter how long it takes for this attack to finish.
|
||||
|
||||
+1
-10
@@ -27,16 +27,6 @@ bool SMLoader::LoadFromDir( const RString &sPath, Song &out )
|
||||
{
|
||||
vector<RString> aFileNames;
|
||||
GetApplicableFiles( sPath, aFileNames );
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
@@ -1229,6 +1219,7 @@ bool SMLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath
|
||||
|
||||
void SMLoader::GetApplicableFiles( const RString &sPath, vector<RString> &out )
|
||||
{
|
||||
GetDirListing( sPath + RString("*.ats" ), out );
|
||||
GetDirListing( sPath + RString("*" + this->GetFileExtension() ), out );
|
||||
}
|
||||
|
||||
|
||||
+110
-69
@@ -45,6 +45,7 @@ static Preference<bool> g_bEditorShowBGChangesPlay( "EditorShowBGChangesPlay", t
|
||||
/** @brief How long must the button be held to generate a hold in record mode? */
|
||||
const float record_hold_default= 0.3f;
|
||||
float record_hold_seconds = record_hold_default;
|
||||
const float time_between_autosave= 300.0f; // 5 minutes. -Kyz
|
||||
|
||||
#define PLAYER_X (SCREEN_CENTER_X)
|
||||
#define PLAYER_Y (SCREEN_CENTER_Y)
|
||||
@@ -110,6 +111,7 @@ AutoScreenMessage( SM_BackFromStepMusicChange );
|
||||
AutoScreenMessage( SM_DoEraseStepTiming );
|
||||
AutoScreenMessage( SM_DoSaveAndExit );
|
||||
AutoScreenMessage( SM_DoExit );
|
||||
AutoScreenMessage( SM_AutoSaveSuccessful );
|
||||
AutoScreenMessage( SM_SaveSuccessful );
|
||||
AutoScreenMessage( SM_SaveFailed );
|
||||
|
||||
@@ -1390,7 +1392,11 @@ void ScreenEdit::Init()
|
||||
m_bHasUndo = false;
|
||||
m_Undo.SetNumTracks( m_NoteDataEdit.GetNumTracks() );
|
||||
|
||||
m_bDirty = m_NoteDataEdit.IsEmpty(); // require the usage of saving if empty.
|
||||
SetDirty(m_NoteDataEdit.IsEmpty()); // require saving if empty.
|
||||
if(GAMESTATE->m_pCurSong->WasLoadedFromAutosave())
|
||||
{
|
||||
SetDirty(true);
|
||||
}
|
||||
|
||||
m_Player->Init( "Player", GAMESTATE->m_pPlayerState[PLAYER_1], NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
|
||||
m_Player->CacheAllUsedNoteSkins();
|
||||
@@ -1526,6 +1532,16 @@ void ScreenEdit::Update( float fDeltaTime )
|
||||
GAMESTATE->UpdateSongPosition( fSeconds, GAMESTATE->m_pCurSong->m_SongTiming, tm );
|
||||
}
|
||||
|
||||
if(m_EditState == STATE_EDITING)
|
||||
{
|
||||
if(IsDirty() && m_next_autosave_time > -1.0f &&
|
||||
RageTimer::GetTimeSinceStartFast() > m_next_autosave_time)
|
||||
{
|
||||
PerformSave(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if( m_EditState == STATE_RECORDING )
|
||||
{
|
||||
// TODO: Find a way to prevent STATE_RECORDING when in Song Timing.
|
||||
@@ -1611,7 +1627,6 @@ void ScreenEdit::Update( float fDeltaTime )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//LOG->Trace( "ScreenEdit::Update(%f)", fDeltaTime );
|
||||
ScreenWithMenuElements::Update( fDeltaTime );
|
||||
|
||||
@@ -3467,6 +3482,7 @@ void ScreenEdit::HandleMessage( const Message &msg )
|
||||
}
|
||||
|
||||
static LocalizedString SAVE_SUCCESSFUL ( "ScreenEdit", "Save successful." );
|
||||
static LocalizedString AUTOSAVE_SUCCESSFUL ( "ScreenEdit", "Autosave successful." );
|
||||
|
||||
static LocalizedString ADD_NEW_MOD ("ScreenEdit", "Adding New Mod");
|
||||
static LocalizedString ADD_NEW_ATTACK ("ScreenEdit", "Adding New Attack");
|
||||
@@ -4189,6 +4205,12 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM )
|
||||
else
|
||||
SCREENMAN->SystemMessage( SAVE_SUCCESSFUL );
|
||||
}
|
||||
else if( SM == SM_AutoSaveSuccessful )
|
||||
{
|
||||
LOG->Trace( "AutoSave successful." );
|
||||
m_next_autosave_time= RageTimer::GetTimeSinceStartFast() + time_between_autosave;
|
||||
SCREENMAN->SystemMessage(AUTOSAVE_SUCCESSFUL);
|
||||
}
|
||||
else if( SM == SM_SaveFailed ) // save failed; stay in the editor
|
||||
{
|
||||
/* We committed the steps to SongManager. Revert to the last save, and
|
||||
@@ -4258,6 +4280,90 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM )
|
||||
ScreenWithMenuElements::HandleScreenMessage( SM );
|
||||
}
|
||||
|
||||
void ScreenEdit::SetDirty(bool dirty)
|
||||
{
|
||||
if(dirty)
|
||||
{
|
||||
if(!m_dirty)
|
||||
{
|
||||
m_next_autosave_time= RageTimer::GetTimeSinceStartFast() + time_between_autosave;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_next_autosave_time= -1.0f;
|
||||
}
|
||||
m_dirty= dirty;
|
||||
}
|
||||
|
||||
void ScreenEdit::PerformSave(bool autosave)
|
||||
{
|
||||
// copy edit into current Steps
|
||||
m_pSteps->SetNoteData( m_NoteDataEdit );
|
||||
|
||||
// don't forget the attacks.
|
||||
m_pSong->m_Attacks = GAMESTATE->m_pCurSong->m_Attacks;
|
||||
m_pSong->m_sAttackString = GAMESTATE->m_pCurSong->m_Attacks.ToVectorString();
|
||||
m_pSteps->m_Attacks = GAMESTATE->m_pCurSteps[PLAYER_1]->m_Attacks;
|
||||
m_pSteps->m_sAttackString = GAMESTATE->m_pCurSteps[PLAYER_1]->m_Attacks.ToVectorString();
|
||||
|
||||
const ScreenMessage save_message= autosave ? SM_AutoSaveSuccessful
|
||||
: SM_SaveSuccessful;
|
||||
|
||||
switch( EDIT_MODE.GetValue() )
|
||||
{
|
||||
DEFAULT_FAIL( EDIT_MODE.GetValue() );
|
||||
case EditMode_Home:
|
||||
{
|
||||
ASSERT( m_pSteps->IsAnEdit() );
|
||||
|
||||
RString sError;
|
||||
m_pSteps->CalculateRadarValues( m_pSong->m_fMusicLengthSeconds );
|
||||
if( !NotesWriterSM::WriteEditFileToMachine(m_pSong, m_pSteps, sError) )
|
||||
{
|
||||
ScreenPrompt::Prompt( SM_None, sError );
|
||||
break;
|
||||
}
|
||||
|
||||
m_pSteps->SetSavedToDisk( true );
|
||||
|
||||
// HACK: clear undo, so "exit" below knows we don't need to save.
|
||||
// This only works because important non-steps data can't be changed in
|
||||
// home mode (BPMs, stops).
|
||||
ClearUndo();
|
||||
|
||||
SCREENMAN->ZeroNextUpdate();
|
||||
|
||||
HandleScreenMessage(save_message);
|
||||
|
||||
/* FIXME
|
||||
RString s;
|
||||
switch( c )
|
||||
{
|
||||
case save: s = "ScreenMemcardSaveEditsAfterSave"; break;
|
||||
case save_on_exit: s = "ScreenMemcardSaveEditsAfterExit"; break;
|
||||
default: FAIL_M(ssprintf("Invalid menu choice: %i", c));
|
||||
}
|
||||
SCREENMAN->AddNewScreenToTop( s );
|
||||
*/
|
||||
}
|
||||
break;
|
||||
case EditMode_Full:
|
||||
{
|
||||
// This will recalculate radar values.
|
||||
m_pSong->Save(autosave);
|
||||
SCREENMAN->ZeroNextUpdate();
|
||||
|
||||
HandleScreenMessage(save_message);
|
||||
}
|
||||
break;
|
||||
case EditMode_CourseMods:
|
||||
case EditMode_Practice:
|
||||
break;
|
||||
}
|
||||
m_soundSave.Play(true);
|
||||
}
|
||||
|
||||
void ScreenEdit::OnSnapModeChange()
|
||||
{
|
||||
m_soundChangeSnap.Play(true);
|
||||
@@ -4659,73 +4765,8 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector<int> &iAns
|
||||
}
|
||||
case save:
|
||||
case save_on_exit:
|
||||
{
|
||||
m_CurrentAction = c;
|
||||
|
||||
// copy edit into current Steps
|
||||
m_pSteps->SetNoteData( m_NoteDataEdit );
|
||||
|
||||
// don't forget the attacks.
|
||||
m_pSong->m_Attacks = GAMESTATE->m_pCurSong->m_Attacks;
|
||||
m_pSong->m_sAttackString = GAMESTATE->m_pCurSong->m_Attacks.ToVectorString();
|
||||
m_pSteps->m_Attacks = GAMESTATE->m_pCurSteps[PLAYER_1]->m_Attacks;
|
||||
m_pSteps->m_sAttackString = GAMESTATE->m_pCurSteps[PLAYER_1]->m_Attacks.ToVectorString();
|
||||
|
||||
switch( EDIT_MODE.GetValue() )
|
||||
{
|
||||
DEFAULT_FAIL( EDIT_MODE.GetValue() );
|
||||
case EditMode_Home:
|
||||
{
|
||||
ASSERT( m_pSteps->IsAnEdit() );
|
||||
|
||||
RString sError;
|
||||
|
||||
m_pSteps->CalculateRadarValues( m_pSong->m_fMusicLengthSeconds );
|
||||
if( !NotesWriterSM::WriteEditFileToMachine(m_pSong, m_pSteps, sError) )
|
||||
{
|
||||
ScreenPrompt::Prompt( SM_None, sError );
|
||||
break;
|
||||
}
|
||||
|
||||
m_pSteps->SetSavedToDisk( true );
|
||||
|
||||
// HACK: clear undo, so "exit" below knows we don't need to save.
|
||||
// This only works because important non-steps data can't be changed in
|
||||
// home mode (BPMs, stops).
|
||||
ClearUndo();
|
||||
|
||||
SCREENMAN->ZeroNextUpdate();
|
||||
|
||||
HandleScreenMessage( SM_SaveSuccessful );
|
||||
|
||||
/* FIXME
|
||||
RString s;
|
||||
switch( c )
|
||||
{
|
||||
case save: s = "ScreenMemcardSaveEditsAfterSave"; break;
|
||||
case save_on_exit: s = "ScreenMemcardSaveEditsAfterExit"; break;
|
||||
default: FAIL_M(ssprintf("Invalid menu choice: %i", c));
|
||||
}
|
||||
SCREENMAN->AddNewScreenToTop( s );
|
||||
*/
|
||||
}
|
||||
break;
|
||||
case EditMode_Full:
|
||||
{
|
||||
// This will recalculate radar values.
|
||||
m_pSong->Save();
|
||||
SCREENMAN->ZeroNextUpdate();
|
||||
|
||||
HandleScreenMessage( SM_SaveSuccessful );
|
||||
}
|
||||
break;
|
||||
case EditMode_CourseMods:
|
||||
case EditMode_Practice:
|
||||
break;
|
||||
}
|
||||
|
||||
m_soundSave.Play(true);
|
||||
}
|
||||
m_CurrentAction = c;
|
||||
PerformSave(false);
|
||||
break;
|
||||
case revert_to_last_save:
|
||||
ScreenPrompt::Prompt( SM_DoRevertToLastSave, REVERT_LAST_SAVE.GetValue() + "\n\n" + DESTROY_ALL_UNSAVED_CHANGES.GetValue(), PROMPT_YES_NO, ANSWER_NO );
|
||||
|
||||
+6
-3
@@ -217,8 +217,10 @@ public:
|
||||
virtual void HandleMessage( const Message &msg );
|
||||
virtual void HandleScreenMessage( const ScreenMessage SM );
|
||||
|
||||
void SetDirty( bool bDirty ) { m_bDirty = bDirty; }
|
||||
bool IsDirty() const { return m_bDirty; }
|
||||
void SetDirty(bool dirty);
|
||||
bool IsDirty() const { return m_dirty; }
|
||||
|
||||
void PerformSave(bool autosave);
|
||||
|
||||
EditState GetEditState(){ return m_EditState; }
|
||||
|
||||
@@ -326,7 +328,8 @@ protected:
|
||||
NoteData m_Undo;
|
||||
|
||||
/** @brief Has the NoteData been changed such that a user should be prompted to save? */
|
||||
bool m_bDirty;
|
||||
bool m_dirty;
|
||||
float m_next_autosave_time;
|
||||
|
||||
/** @brief The sound that is played when a note is added. */
|
||||
RageSound m_soundAddNote;
|
||||
|
||||
+25
-7
@@ -991,7 +991,7 @@ bool Song::HasStepsTypeAndDifficulty( StepsType st, Difficulty dc ) const
|
||||
return SongUtil::GetOneSteps( this, st, dc ) != NULL;
|
||||
}
|
||||
|
||||
void Song::Save()
|
||||
void Song::Save(bool autosave)
|
||||
{
|
||||
LOG->Trace( "Song::SaveToSongFile()" );
|
||||
|
||||
@@ -999,11 +999,16 @@ void Song::Save()
|
||||
TranslateTitles();
|
||||
|
||||
// Save the new files. These calls make backups on their own.
|
||||
if( !SaveToSSCFile(GetSongFilePath(), false) )
|
||||
if( !SaveToSSCFile(GetSongFilePath(), false, autosave) )
|
||||
return;
|
||||
SaveToCacheFile();
|
||||
// Skip saving the sm and .old files if we are autosaving. -Kyz
|
||||
if(autosave)
|
||||
{
|
||||
return;
|
||||
}
|
||||
SaveToSMFile();
|
||||
//SaveToDWIFile();
|
||||
SaveToCacheFile();
|
||||
|
||||
/* We've safely written our files and created backups. Rename non-SM and
|
||||
* non-DWI files to avoid confusion. */
|
||||
@@ -1058,16 +1063,20 @@ bool Song::SaveToSMFile()
|
||||
|
||||
}
|
||||
|
||||
bool Song::SaveToSSCFile( RString sPath, bool bSavingCache )
|
||||
bool Song::SaveToSSCFile( RString sPath, bool bSavingCache, bool autosave )
|
||||
{
|
||||
RString path = sPath;
|
||||
if (!bSavingCache)
|
||||
path = SetExtension(sPath, "ssc");
|
||||
|
||||
if(autosave)
|
||||
{
|
||||
path = SetExtension(sPath, "ats");
|
||||
}
|
||||
|
||||
LOG->Trace( "Song::SaveToSSCFile('%s')", path.c_str() );
|
||||
|
||||
// If the file exists, make a backup.
|
||||
if( !bSavingCache && IsAFile(path) )
|
||||
if(!bSavingCache && !autosave && IsAFile(path))
|
||||
FileCopy( path, path + ".old" );
|
||||
|
||||
vector<Steps*> vpStepsToSave;
|
||||
@@ -1090,7 +1099,7 @@ bool Song::SaveToSSCFile( RString sPath, bool bSavingCache )
|
||||
vpStepsToSave.push_back(*s);
|
||||
}
|
||||
|
||||
if (bSavingCache)
|
||||
if(bSavingCache || autosave)
|
||||
{
|
||||
return NotesWriterSSC::Write(path, *this, vpStepsToSave, bSavingCache);
|
||||
}
|
||||
@@ -1098,6 +1107,15 @@ bool Song::SaveToSSCFile( RString sPath, bool bSavingCache )
|
||||
if( !NotesWriterSSC::Write(path, *this, vpStepsToSave, bSavingCache) )
|
||||
return false;
|
||||
|
||||
// Remove the autosave file so that edit mode won't auto load it. -Kyz
|
||||
RString autosave_path= sPath;
|
||||
SetExtension(autosave_path, "ats");
|
||||
if(FILEMAN->DoesFileExist(autosave_path))
|
||||
{
|
||||
FILEMAN->Remove(autosave_path);
|
||||
}
|
||||
|
||||
|
||||
if( g_BackUpAllSongSaves.Get() )
|
||||
{
|
||||
RString sExt = GetExtension( path );
|
||||
|
||||
+5
-2
@@ -113,9 +113,9 @@ public:
|
||||
* @param sPath the path where we're saving the file.
|
||||
* @param bSavingCache a flag to determine if we're saving cache data.
|
||||
*/
|
||||
bool SaveToSSCFile( RString sPath, bool bSavingCache );
|
||||
bool SaveToSSCFile(RString sPath, bool bSavingCache, bool autosave= false);
|
||||
/** @brief Save to the SSC and SM files no matter what. */
|
||||
void Save();
|
||||
void Save(bool autosave= false);
|
||||
/**
|
||||
* @brief Save the current Song to a JSON file.
|
||||
* @return its success or failure. */
|
||||
@@ -133,6 +133,9 @@ public:
|
||||
* @return its success or failure. */
|
||||
bool SaveToDWIFile();
|
||||
|
||||
bool WasLoadedFromAutosave() const
|
||||
{ return GetExtension(m_sSongFileName) == "ats"; }
|
||||
|
||||
const RString &GetSongFilePath() const;
|
||||
RString GetCacheFilePath() const;
|
||||
|
||||
|
||||
+2
-1
@@ -105,7 +105,8 @@ bool Steps::GetNoteDataFromSimfile()
|
||||
RString extension = GetExtension(stepFile);
|
||||
extension.MakeLower(); // must do this because the code is expecting lowercase
|
||||
|
||||
if (extension.empty() || extension == "ssc") // remember cache files.
|
||||
if (extension.empty() || extension == "ssc"
|
||||
|| extension == "ats") // remember cache files.
|
||||
{
|
||||
SSCLoader loader;
|
||||
if ( ! loader.LoadNoteDataFromSimfile(stepFile, *this) )
|
||||
|
||||
Reference in New Issue
Block a user