Implemented emergency save on crash, closes #572

master
krzys-h 2015-08-17 20:56:42 +02:00
parent ee9457f156
commit 7e028977bd
4 changed files with 69 additions and 19 deletions

View File

@ -21,6 +21,8 @@
#include "common/config.h"
#include "common/resources/resourcemanager.h"
#include "app/system.h"
#include "common/stringutils.h"
@ -93,6 +95,8 @@ void CSignalHandlers::HandleOtherUncaughtException()
void CSignalHandlers::ReportError(const std::string& errorMessage)
{
static bool triedSaving = false;
std::stringstream msg;
msg << "Unhandled exception occured!" << std::endl;
msg << "==============================" << std::endl;
@ -109,21 +113,44 @@ void CSignalHandlers::ReportError(const std::string& errorMessage)
msg << "You are running version " << COLOBOT_VERSION_DISPLAY << " from CI build #" << BUILD_NUMBER << std::endl;
#endif
msg << std::endl;
bool canSave = false;
CRobotMain* robotMain = nullptr;
if (!CRobotMain::IsCreated())
{
msg << "CRobotMain instance does not seem to exist" << std::endl;
}
else
{
CRobotMain* robotMain = CRobotMain::GetInstancePointer();
robotMain = CRobotMain::GetInstancePointer();
msg << "The game was in phase " << PhaseToString(robotMain->GetPhase()) << " (ID=" << robotMain->GetPhase() << ")" << std::endl;
msg << "Last started level was: category=" << GetLevelCategoryDir(robotMain->GetLevelCategory()) << " chap=" << robotMain->GetLevelChap() << " rank=" << robotMain->GetLevelRank() << std::endl;
canSave = (robotMain->GetPhase() == PHASE_SIMUL);
}
msg << "==============================" << std::endl;
msg << std::endl;
msg << "Sorry for inconvenience!";
std::cerr << std::endl << msg.str() << std::endl;
m_systemUtils->SystemDialog(SDT_ERROR, "Unhandled exception occured!", msg.str());
if (canSave && !triedSaving)
{
msg.str("");
msg << "You can try saving the game at the moment of a crash. Keep in mind, the game engine is in" << std::endl;
msg << "an unstable state so the saved game may be corrupted or even cause another crash." << std::endl;
msg << std::endl;
msg << "Do you want to try saving now?";
SystemDialogResult result = m_systemUtils->SystemDialog(SDT_YES_NO, "Try to save?", msg.str());
if (result == SDR_YES)
{
CResourceManager::CreateDirectory("crashsave");
robotMain->IOWriteScene("crashsave/data.sav", "crashsave/cbot.run", "crashsave/screen.png", "Backup at the moment of a crash", true);
m_systemUtils->SystemDialog(SDT_INFO, "Try to save?", "Saving finished.\nPlease restart the game now");
}
triedSaving = true;
}
exit(1);
}

View File

@ -471,7 +471,7 @@ void CPlayerProfile::SaveScene(std::string dir, std::string info)
CResourceManager::CreateDirectory(dir);
}
CRobotMain::GetInstancePointer()->IOWriteScene(dir + "/data.sav", dir + "/cbot.run", dir + "/screen.png", const_cast<char*>(info.c_str()));
CRobotMain::GetInstancePointer()->IOWriteScene(dir + "/data.sav", dir + "/cbot.run", dir + "/screen.png", info.c_str());
}
void CPlayerProfile::LoadScene(std::string dir)

View File

@ -481,6 +481,23 @@ void CRobotMain::ChangePhase(Phase phase)
pb->SetState(Ui::STATE_SIMPLY);
pb->ClearState(Ui::STATE_VISIBLE);
if (m_phase == PHASE_PLAYER_SELECT)
{
if (CResourceManager::DirectoryExists("crashsave"))
{
GetLogger()->Info("Pre-crash save found!\n");
m_ui->GetDialog()->StartQuestion("Your game seems to have crashed. Do you want to restore pre-crash state?", false, false, false, [&]() {
GetLogger()->Info("Trying to restore pre-crash state...\n");
assert(m_playerProfile != nullptr);
m_playerProfile->LoadScene("../../crashsave");
CResourceManager::RemoveDirectory("../../crashsave");
}, [&]() {
GetLogger()->Info("Not restoring pre-crash state\n");
CResourceManager::RemoveDirectory("../../crashsave");
});
}
}
m_ui->ChangePhase(m_phase);
if (!resetWorld) return;
@ -4486,11 +4503,14 @@ void CRobotMain::IOWriteObject(CLevelParserLine* line, CObject* obj, const std::
}
//! Saves the current game
bool CRobotMain::IOWriteScene(std::string filename, std::string filecbot, std::string filescreenshot, char *info)
bool CRobotMain::IOWriteScene(std::string filename, std::string filecbot, std::string filescreenshot, const std::string& info, bool emergencySave)
{
// Render the indicator to show that we are working
ShowSaveIndicator(true);
m_app->Render(); // update
if (!emergencySave)
{
// Render the indicator to show that we are working
ShowSaveIndicator(true);
m_app->Render(); // update
}
std::string dirname = filename.substr(0, filename.find_last_of("/"));
@ -4609,21 +4629,24 @@ bool CRobotMain::IOWriteScene(std::string filename, std::string filecbot, std::s
CBotClass::SaveStaticState(file);
fClose(file);
ShowSaveIndicator(false); // force hide for screenshot
MouseMode oldMouseMode = m_app->GetMouseMode();
m_app->SetMouseMode(MOUSE_NONE); // disable the mouse
m_displayText->HideText(true); // hide
m_engine->SetScreenshotMode(true);
if (!emergencySave)
{
ShowSaveIndicator(false); // force hide for screenshot
MouseMode oldMouseMode = m_app->GetMouseMode();
m_app->SetMouseMode(MOUSE_NONE); // disable the mouse
m_displayText->HideText(true); // hide
m_engine->SetScreenshotMode(true);
m_engine->Render(); // update (but don't show, we're not swapping buffers here!)
m_engine->WriteScreenShot(CResourceManager::GetSaveLocation() + "/" + filescreenshot); //TODO: Use PHYSFS?
m_shotSaving++;
m_engine->Render(); // update (but don't show, we're not swapping buffers here!)
m_engine->WriteScreenShot(CResourceManager::GetSaveLocation() + "/" + filescreenshot); //TODO: Use PHYSFS?
m_shotSaving++;
m_engine->SetScreenshotMode(false);
m_displayText->HideText(false);
m_app->SetMouseMode(oldMouseMode);
m_engine->SetScreenshotMode(false);
m_displayText->HideText(false);
m_app->SetMouseMode(oldMouseMode);
m_app->ResetTimeAfterLoading();
m_app->ResetTimeAfterLoading();
}
return true;
}

View File

@ -288,7 +288,7 @@ public:
CPlayerProfile* GetPlayerProfile();
bool IOIsBusy();
bool IOWriteScene(std::string filename, std::string filecbot, std::string filescreenshot, char *info);
bool IOWriteScene(std::string filename, std::string filecbot, std::string filescreenshot, const std::string& info, bool emergencySave = false);
void IOWriteSceneFinished();
CObject* IOReadScene(std::string filename, std::string filecbot);
void IOWriteObject(CLevelParserLine *line, CObject* obj, const std::string& programDir, int objRank);