From 7e028977bd2b7090c96ef8f9a05947c15607c32a Mon Sep 17 00:00:00 2001 From: krzys-h Date: Mon, 17 Aug 2015 20:56:42 +0200 Subject: [PATCH] Implemented emergency save on crash, closes #572 --- src/app/signal_handlers.cpp | 29 ++++++++++++++++++- src/level/player_profile.cpp | 2 +- src/level/robotmain.cpp | 55 +++++++++++++++++++++++++----------- src/level/robotmain.h | 2 +- 4 files changed, 69 insertions(+), 19 deletions(-) diff --git a/src/app/signal_handlers.cpp b/src/app/signal_handlers.cpp index f3125d3f..781cfb42 100644 --- a/src/app/signal_handlers.cpp +++ b/src/app/signal_handlers.cpp @@ -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); } diff --git a/src/level/player_profile.cpp b/src/level/player_profile.cpp index 7a685759..08277323 100644 --- a/src/level/player_profile.cpp +++ b/src/level/player_profile.cpp @@ -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(info.c_str())); + CRobotMain::GetInstancePointer()->IOWriteScene(dir + "/data.sav", dir + "/cbot.run", dir + "/screen.png", info.c_str()); } void CPlayerProfile::LoadScene(std::string dir) diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp index 4e215599..146f6c78 100644 --- a/src/level/robotmain.cpp +++ b/src/level/robotmain.cpp @@ -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; } diff --git a/src/level/robotmain.h b/src/level/robotmain.h index 16f53629..14e79f62 100644 --- a/src/level/robotmain.h +++ b/src/level/robotmain.h @@ -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);