diff --git a/src/network/core/tcp_game.cpp b/src/network/core/tcp_game.cpp index 9b3f7b5ef3..caa378fc4c 100644 --- a/src/network/core/tcp_game.cpp +++ b/src/network/core/tcp_game.cpp @@ -45,6 +45,8 @@ NetworkRecvStatus NetworkGameSocketHandler::CloseConnection(bool error) { /* Clients drop back to the main menu */ if (!_network_server && _networking) { + extern void ClientNetworkEmergencySave(); // from network_client.cpp + ClientNetworkEmergencySave(); _switch_mode = SM_MENU; _networking = false; ShowErrorMessage(STR_NETWORK_ERROR_LOSTCONNECTION, INVALID_STRING_ID, WL_CRITICAL); diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index e3bcbb2d87..4b066681d7 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -119,6 +119,19 @@ struct PacketReader : LoadFilter { }; +/** + * Create an emergency savegame when the network connection is lost. + */ +void ClientNetworkEmergencySave() +{ + if (!_settings_client.gui.autosave_on_network_disconnect) return; + + const char *filename = "netsave.sav"; + DEBUG(net, 0, "Client: Performing emergency save (%s)", filename); + SaveOrLoad(filename, SLO_SAVE, DFT_GAME_FILE, AUTOSAVE_DIR, false); +} + + /** * Create a new socket for the client side of the game connection. * @param s The socket to connect with. @@ -670,6 +683,9 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR(Packet *p ShowErrorMessage(err, INVALID_STRING_ID, WL_CRITICAL); + /* Perform an emergency save if we had already entered the game */ + if (this->status == STATUS_ACTIVE) ClientNetworkEmergencySave(); + DeleteWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN); return NETWORK_RECV_STATUS_SERVER_ERROR; @@ -1051,6 +1067,8 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_SHUTDOWN(Packet ShowErrorMessage(STR_NETWORK_MESSAGE_SERVER_SHUTDOWN, INVALID_STRING_ID, WL_CRITICAL); } + if (this->status == STATUS_ACTIVE) ClientNetworkEmergencySave(); + return NETWORK_RECV_STATUS_SERVER_ERROR; } @@ -1066,6 +1084,8 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEWGAME(Packet ShowErrorMessage(STR_NETWORK_MESSAGE_SERVER_REBOOT, INVALID_STRING_ID, WL_CRITICAL); } + if (this->status == STATUS_ACTIVE) ClientNetworkEmergencySave(); + return NETWORK_RECV_STATUS_SERVER_ERROR; } @@ -1153,6 +1173,7 @@ void ClientNetworkGameSocketHandler::CheckConnection() if (lag > 20) { this->NetworkGameSocketHandler::CloseConnection(); ShowErrorMessage(STR_NETWORK_ERROR_LOSTCONNECTION, INVALID_STRING_ID, WL_CRITICAL); + ClientNetworkEmergencySave(); return; } diff --git a/src/settings_type.h b/src/settings_type.h index fc4059c7bf..f9cc00f3a3 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -114,6 +114,7 @@ struct GUISettings { bool threaded_saves; ///< should we do threaded saves? bool keep_all_autosave; ///< name the autosave in a different way bool autosave_on_exit; ///< save an autosave when you quit the game, but do not ask "Do you really want to quit?" + bool autosave_on_network_disconnect; ///< save an autosave when you get disconnected from a network game with an error? uint8 date_format_in_default_names; ///< should the default savegame/screenshot name use long dates (31th Dec 2008), short dates (31-12-2008) or ISO dates (2008-12-31) byte max_num_autosaves; ///< controls how many autosavegames are made before the game starts to overwrite (names them 0 to max_num_autosaves - 1) bool population_in_label; ///< show the population of a town in his label? diff --git a/src/table/settings.ini b/src/table/settings.ini index 693c8246c4..c061c394f0 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -2987,6 +2987,12 @@ flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = false cat = SC_BASIC +[SDTC_BOOL] +var = gui.autosave_on_network_disconnect +flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC +def = true +cat = SC_EXPERT + [SDTC_VAR] var = gui.max_num_autosaves type = SLE_UINT8