Changeset - r15386:717f25b0b15f
[Not reviewed]
master
0 1 0
rubidium - 14 years ago 2010-06-30 21:38:51
rubidium@openttd.org
(svn r20039) -Fix [FS#3907]: instead of loading the intro game when loading a savegame fails on the dedicated server, generate a new game.
Generating a new game is the least bad solution:
* loading the intro game: desyncs due to GM_MENU on the server and GM_NORMAL on the clients, NewGRFs not being loaded on the server but being loaded on the client;
* creating an empty map: OpenTTD will go crazy due to missing towns. Also clients can't properly join because of the missing towns;
* loading the last saved game: doesn't always exist and loading it might fail causing an infinite loop;
* stopping being a server: breaks the dedicated server horribly; if you loaded the game via rcon you can't connect with it anymore as you can't join the server;
* generating a new game: should always succeed, although people might think a scenario loaded fine because there are no companies and such.
1 file changed with 14 insertions and 3 deletions:
0 comments (0 inline, 0 general)
src/openttd.cpp
Show inline comments
 
@@ -851,91 +851,103 @@ static void MakeNewEditorWorld()
 

	
 
void StartupCompanies();
 
void StartupDisasters();
 
extern void StartupEconomy();
 

	
 
/**
 
 * Load the specified savegame but on error do different things.
 
 * If loading fails due to corrupt savegame, bad version, etc. go back to
 
 * a previous correct state. In the menu for example load the intro game again.
 
 * @param filename file to be loaded
 
 * @param mode mode of loading, either SL_LOAD or SL_OLD_LOAD
 
 * @param newgm switch to this mode of loading fails due to some unknown error
 
 * @param subdir default directory to look for filename, set to 0 if not needed
 
 */
 
bool SafeSaveOrLoad(const char *filename, int mode, GameMode newgm, Subdirectory subdir)
 
{
 
	GameMode ogm = _game_mode;
 

	
 
	_game_mode = newgm;
 
	assert(mode == SL_LOAD || mode == SL_OLD_LOAD);
 
	switch (SaveOrLoad(filename, mode, subdir)) {
 
		case SL_OK: return true;
 

	
 
		case SL_REINIT:
 
			if (_network_dedicated) {
 
				/*
 
				 * We need to reinit a network map...
 
				 * We can't simply load the intro game here as that game has many
 
				 * special cases which make clients desync immediately. So we fall
 
				 * back to just generating a new game with the current settings.
 
				 */
 
				DEBUG(net, 0, "Loading game failed, so a new (random) game will be started!");
 
				MakeNewGame(false, true);
 
				return false;
 
			}
 

	
 
			switch (ogm) {
 
				default:
 
				case GM_MENU:   LoadIntroGame();      break;
 
				case GM_EDITOR: MakeNewEditorWorld(); break;
 
			}
 
			return false;
 

	
 
		default:
 
			_game_mode = ogm;
 
			return false;
 
	}
 
}
 

	
 
/**
 
 * Start Scenario starts a new game based on a scenario.
 
 * Eg 'New Game' --> select a preset scenario
 
 * This starts a scenario based on your current difficulty settings
 
 */
 
static void StartScenario()
 
{
 
	_game_mode = GM_NORMAL;
 

	
 
	/* invalid type */
 
	if (_file_to_saveload.mode == SL_INVALID) {
 
		DEBUG(sl, 0, "Savegame is obsolete or invalid format: '%s'", _file_to_saveload.name);
 
		SetDParamStr(0, GetSaveLoadErrorString());
 
		ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
 
		_game_mode = GM_MENU;
 
		return;
 
	}
 

	
 
	/* Reinitialize windows */
 
	ResetWindowSystem();
 

	
 
	SetupColoursAndInitialWindow();
 

	
 
	ResetGRFConfig(true);
 

	
 
	/* Load game */
 
	if (SaveOrLoad(_file_to_saveload.name, _file_to_saveload.mode, SCENARIO_DIR) != SL_OK) {
 
		LoadIntroGame();
 
	if (!SafeSaveOrLoad(_file_to_saveload.name, _file_to_saveload.mode, GM_NORMAL, SCENARIO_DIR)) {
 
		SetDParamStr(0, GetSaveLoadErrorString());
 
		ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
 
		return;
 
	}
 

	
 
	_settings_game.difficulty = _settings_newgame.difficulty;
 

	
 
	/* Inititalize data */
 
	StartupEconomy();
 
	StartupCompanies();
 
	StartupEngines();
 
	StartupDisasters();
 

	
 
	SetLocalCompany(COMPANY_FIRST);
 
	Company *c = Company::Get(COMPANY_FIRST);
 
	c->settings = _settings_client.company;
 

	
 
	MarkWholeScreenDirty();
 
}
 

	
 
void SwitchToMode(SwitchMode new_mode)
 
{
 
#ifdef ENABLE_NETWORK
 
	/* If we are saving something, the network stays in his current state */
 
	if (new_mode != SM_SAVE) {
 
		/* If the network is active, make it not-active */
 
		if (_networking) {
 
@@ -975,49 +987,48 @@ void SwitchToMode(SwitchMode new_mode)
 
		case SM_RESTARTGAME: // Restart --> 'Random game' with current settings
 
		case SM_NEWGAME: // New Game --> 'Random game'
 
#ifdef ENABLE_NETWORK
 
			if (_network_server) {
 
				snprintf(_network_game_info.map_name, lengthof(_network_game_info.map_name), "Random Map");
 
			}
 
#endif /* ENABLE_NETWORK */
 
			MakeNewGame(false, new_mode == SM_NEWGAME);
 
			break;
 

	
 
		case SM_START_SCENARIO: // New Game --> Choose one of the preset scenarios
 
#ifdef ENABLE_NETWORK
 
			if (_network_server) {
 
				snprintf(_network_game_info.map_name, lengthof(_network_game_info.map_name), "%s (Loaded scenario)", _file_to_saveload.title);
 
			}
 
#endif /* ENABLE_NETWORK */
 
			StartScenario();
 
			break;
 

	
 
		case SM_LOAD: { // Load game, Play Scenario
 
			ResetGRFConfig(true);
 
			ResetWindowSystem();
 

	
 
			if (!SafeSaveOrLoad(_file_to_saveload.name, _file_to_saveload.mode, GM_NORMAL, NO_DIRECTORY)) {
 
				LoadIntroGame();
 
				SetDParamStr(0, GetSaveLoadErrorString());
 
				ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
 
			} else {
 
				if (_saveload_mode == SLD_LOAD_SCENARIO) {
 
					StartupEngines();
 
				}
 
				/* Update the local company for a loaded game. It is either always
 
				 * company #1 (eg 0) or in the case of a dedicated server a spectator */
 
				SetLocalCompany(_network_dedicated ? COMPANY_SPECTATOR : COMPANY_FIRST);
 
				/* Execute the game-start script */
 
				IConsoleCmdExec("exec scripts/game_start.scr 0");
 
				/* Decrease pause counter (was increased from opening load dialog) */
 
				DoCommandP(0, PM_PAUSED_SAVELOAD, 0, CMD_PAUSE);
 
#ifdef ENABLE_NETWORK
 
				if (_network_server) {
 
					snprintf(_network_game_info.map_name, lengthof(_network_game_info.map_name), "%s (Loaded game)", _file_to_saveload.title);
 
				}
 
#endif /* ENABLE_NETWORK */
 
			}
 
			break;
 
		}
 

	
 
		case SM_START_HEIGHTMAP: // Load a heightmap and start a new game from it
 
#ifdef ENABLE_NETWORK
0 comments (0 inline, 0 general)