From 51df7ecb04099c2dce268fe52f3864a62c97d378 Mon Sep 17 00:00:00 2001 From: skyjake Date: Sat, 15 Sep 2012 14:37:47 +0300 Subject: [PATCH] Updater|All Games: Ask to save before installing update The Updater will now prompt the user the save the game, if a map is in progress when one attempts to start the update installation. This required adding a few new interfaces between the engine and the game: - The engine will ask the game whether it looks like the game should be saved (DD_GAME_RECOMMENDS_SAVING) via the game's GetInteger method. - The game will notify the engine when a save has been written using a new public function called Game_Notify(). This will allow the engine to re-show the download dialog (or start the installation outright; currently the user has to manually start the install in the dialog). --- doomsday/engine/api/dd_share.h | 20 ++++++++++--- doomsday/engine/portable/src/game.c | 16 ++++++++++ doomsday/engine/portable/src/updater.cpp | 30 ++++++++++++++++++- .../portable/src/updater/downloaddialog.cpp | 25 ++++++++++++---- .../portable/src/updater/downloaddialog.h | 4 +++ doomsday/plugins/common/src/g_game.c | 9 ++++-- 6 files changed, 92 insertions(+), 12 deletions(-) diff --git a/doomsday/engine/api/dd_share.h b/doomsday/engine/api/dd_share.h index 31c2df12e9..bdc8df8069 100644 --- a/doomsday/engine/api/dd_share.h +++ b/doomsday/engine/api/dd_share.h @@ -303,9 +303,11 @@ enum { DD_TORCH_GREEN, DD_TORCH_BLUE, DD_TORCH_ADDITIVE, - DD_TM_FLOOR_Z, ///< output from P_CheckPosition - DD_TM_CEILING_Z, ///< output from P_CheckPosition - DD_SHIFT_DOWN + DD_TM_FLOOR_Z, ///< output from P_CheckPosition + DD_TM_CEILING_Z, ///< output from P_CheckPosition + DD_SHIFT_DOWN, + DD_GAME_RECOMMENDS_SAVING, ///< engine asks whether game should be saved (e.g., when upgrading) (game's GetInteger) + DD_NOTIFY_GAME_SAVED ///< savegame was written }; /// Bounding box coordinates. @@ -368,6 +370,16 @@ typedef struct gameinfo_s { const char* identityKey; } GameInfo; +/** + * Provides a way for games (or other plugins) to notify the engine of game-related + * important events. + * + * @param notification One of the DD_NOTIFY_* enums. + * @param param Additional arguments about the notification, dependin + * on the notification type. + */ +void Game_Notify(int notification, void* param); + /** * @defgroup resourceFlags Resource Flags * @ingroup apiFlags resource @@ -758,7 +770,7 @@ typedef struct ddmobj_base_s { enum { DDSMM_AFTER_LOADING, ///< After loading a savegame... DDSMM_FINALIZE, ///< After everything else is done. - DDSMM_INITIALIZE, ///< Before anything else if done. + DDSMM_INITIALIZE ///< Before anything else if done. }; /// Sector reverb data indices. @ingroup map diff --git a/doomsday/engine/portable/src/game.c b/doomsday/engine/portable/src/game.c index 82d0b35da2..c4cb7d51ed 100644 --- a/doomsday/engine/portable/src/game.c +++ b/doomsday/engine/portable/src/game.c @@ -25,6 +25,7 @@ #include "dd_main.h" #include "de_console.h" #include "de_filesys.h" +#include "updater/downloaddialog.h" #include "game.h" #include "abstractresource.h" @@ -304,3 +305,18 @@ Game* Game_FromDef(const GameDef* def) return game; } + +void Game_Notify(int notification, void* param) +{ + DENG_UNUSED(param); + + switch(notification) + { + case DD_NOTIFY_GAME_SAVED: + // If an update has been downloaded and is ready to go, we should + // re-show the dialog now that the user has saved the game as + // prompted. + Updater_RaiseCompletedDownloadDialog(); + break; + } +} diff --git a/doomsday/engine/portable/src/updater.cpp b/doomsday/engine/portable/src/updater.cpp index 4c537f0eba..8bc50ebc8b 100644 --- a/doomsday/engine/portable/src/updater.cpp +++ b/doomsday/engine/portable/src/updater.cpp @@ -46,7 +46,9 @@ #include #include "sys_system.h" #include "dd_version.h" +#include "dd_def.h" #include "dd_types.h" +#include "dd_main.h" #include "con_main.h" #include "nativeui.h" #include "window.h" @@ -130,13 +132,21 @@ struct Updater::Instance UpdateAvailableDialog* availableDlg; UpdaterSettingsDialog* settingsDlg; bool backToFullscreen; + bool savingSuggested; VersionInfo latestVersion; QString latestPackageUri; QString latestPackageUri2; // fallback location QString latestLogUri; - Instance(Updater* up) : self(up), network(0), download(0), availableDlg(0), settingsDlg(0), backToFullscreen(false) + Instance(Updater* up) + : self(up), + network(0), + download(0), + availableDlg(0), + settingsDlg(0), + backToFullscreen(false), + savingSuggested(false) { network = new QNetworkAccessManager(self); @@ -468,6 +478,23 @@ void Updater::downloadCompleted(int result) if(result == DownloadDialog::Accepted) { // Autosave the game. + // Well, we can't do that yet so just remind the user about saving. + if(!d->savingSuggested && gx.GetInteger(DD_GAME_RECOMMENDS_SAVING)) + { + d->savingSuggested = true; + + const char* buttons[] = { "I'll Save First", "Discard Progress && Install", NULL }; + if(Sys_MessageBoxWithButtons(MBT_INFORMATION, DOOMSDAY_NICENAME, + "Installing the update will discard unsaved progress in the game.", + "Doomsday will be shut down before the installation can start. " + "The game is not saved automatically, so you will have to " + "save the game before installing the update.", + buttons) == 0) + { + Con_Execute(CMDS_DDAY, "savegame", false, false); + return; + } + } // Check the signature of the downloaded file. @@ -478,6 +505,7 @@ void Updater::downloadCompleted(int result) // The download dialgo can be dismissed now. d->download->deleteLater(); d->download = 0; + d->savingSuggested = false; } void Updater::settingsDialogClosed(int /*result*/) diff --git a/doomsday/engine/portable/src/updater/downloaddialog.cpp b/doomsday/engine/portable/src/updater/downloaddialog.cpp index 4dfe808e0c..1567f0deec 100644 --- a/doomsday/engine/portable/src/updater/downloaddialog.cpp +++ b/doomsday/engine/portable/src/updater/downloaddialog.cpp @@ -37,7 +37,7 @@ #include #include -static bool downloadInProgress; +static DownloadDialog* downloadInProgress; struct DownloadDialog::Instance { @@ -110,7 +110,7 @@ struct DownloadDialog::Instance LOG_INFO("Downloading %s, saving as: %s") << uri.toString() << savedFilePath; // Global state flag. - downloadInProgress = true; + downloadInProgress = self; } void setProgressText(de::String text) @@ -132,7 +132,7 @@ DownloadDialog::DownloadDialog(de::String downloadUri, de::String fallbackUri, Q DownloadDialog::~DownloadDialog() { - downloadInProgress = false; + downloadInProgress = 0; delete d; } @@ -142,11 +142,16 @@ de::String DownloadDialog::downloadedFilePath() const return d->savedFilePath; } +bool DownloadDialog::isReadyToInstall() const +{ + return d->fileReady; +} + void DownloadDialog::finished(QNetworkReply* reply) { LOG_AS("Download"); - downloadInProgress = false; + downloadInProgress = 0; reply->deleteLater(); d->reply = 0; @@ -269,5 +274,15 @@ void DownloadDialog::replyMetaDataChanged() int Updater_IsDownloadInProgress(void) { - return downloadInProgress; + return downloadInProgress != 0; +} + +void Updater_RaiseCompletedDownloadDialog(void) +{ + if(downloadInProgress && downloadInProgress->isReadyToInstall()) + { + downloadInProgress->show(); + downloadInProgress->raise(); + downloadInProgress->activateWindow(); + } } diff --git a/doomsday/engine/portable/src/updater/downloaddialog.h b/doomsday/engine/portable/src/updater/downloaddialog.h index 4effed3c2c..5246f43a89 100644 --- a/doomsday/engine/portable/src/updater/downloaddialog.h +++ b/doomsday/engine/portable/src/updater/downloaddialog.h @@ -49,6 +49,8 @@ class DownloadDialog : public UpdaterDialog * successfully. */ de::String downloadedFilePath() const; + + bool isReadyToInstall() const; signals: void downloadFailed(QString uri); @@ -72,6 +74,8 @@ extern "C" { int Updater_IsDownloadInProgress(void); +void Updater_RaiseCompletedDownloadDialog(void); + #ifdef __cplusplus } // extern "C" #endif diff --git a/doomsday/plugins/common/src/g_game.c b/doomsday/plugins/common/src/g_game.c index 10224cfa3a..e6d9260345 100644 --- a/doomsday/plugins/common/src/g_game.c +++ b/doomsday/plugins/common/src/g_game.c @@ -3003,12 +3003,17 @@ void G_DoSaveGame(void) p.name = name; p.slot = gaSaveGameSlot; /// @todo Use progress bar mode and update progress during the setup. - didSave = 0 == BusyMode_RunNewTaskWithName(BUSYF_ACTIVITY | /*BUSYF_PROGRESS_BAR |*/ (verbose? BUSYF_CONSOLE_OUTPUT : 0), - G_SaveStateWorker, &p, "Saving game..."); + didSave = (BusyMode_RunNewTaskWithName(BUSYF_ACTIVITY | /*BUSYF_PROGRESS_BAR |*/ (verbose? BUSYF_CONSOLE_OUTPUT : 0), + G_SaveStateWorker, &p, "Saving game...") != 0); if(didSave) { //Hu_MenuUpdateGameSaveWidgets(); P_SetMessage(&players[CONSOLEPLAYER], TXT_GAMESAVED, false); + + // Notify the engine that the game was saved. + /// @todo After the engine has the primary responsibility of + /// saving the game, this notification is unnecessary. + Game_Notify(DD_NOTIFY_GAME_SAVED, NULL); } G_SetGameAction(GA_NONE); }