← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~widelands-dev/widelands/remove-savegame-compatibility-after-economy-change into lp:widelands

 

GunChleoc has proposed merging lp:~widelands-dev/widelands/remove-savegame-compatibility-after-economy-change into lp:widelands.

Commit message:
Removed savegame compatibility code

Requested reviews:
  Widelands Developers (widelands-dev)

For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/remove-savegame-compatibility-after-economy-change/+merge/349390

Since we just broke savegame compatibility, we can get rid of the compatibility code.

Old maps should still be loadable.
-- 
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/remove-savegame-compatibility-after-economy-change into lp:widelands.
=== modified file 'src/economy/expedition_bootstrap.cc'
--- src/economy/expedition_bootstrap.cc	2018-04-07 16:59:00 +0000
+++ src/economy/expedition_bootstrap.cc	2018-07-12 05:46:37 +0000
@@ -206,19 +206,11 @@
    Warehouse& warehouse, FileRead& fr, Game& game, MapObjectLoader& mol, uint16_t packet_version) {
 
 	static const uint16_t kCurrentPacketVersion = 7;
-
 	assert(queues_.empty());
 	// Load worker queues
 	std::vector<WorkersQueue*> wqs;
 	try {
-		if (packet_version <= 6) {
-			// This code is actually quite broken/inflexible but it should work
-			// If we are here, use the old loader for build 19 packets
-			const uint8_t num_workers = fr.unsigned_8();
-			WorkersQueue* wq = new WorkersQueue(warehouse, warehouse.owner().tribe().builder(), 1);
-			wq->load_for_expedition(fr, game, mol, num_workers);
-			wqs.push_back(wq);
-		} else if (packet_version >= kCurrentPacketVersion) {
+		if (packet_version == kCurrentPacketVersion) {
 			uint8_t num_queues = fr.unsigned_8();
 			for (uint8_t i = 0; i < num_queues; ++i) {
 				WorkersQueue* wq = new WorkersQueue(warehouse, INVALID_INDEX, 0);

=== modified file 'src/economy/workers_queue.cc'
--- src/economy/workers_queue.cc	2018-04-07 16:59:00 +0000
+++ src/economy/workers_queue.cc	2018-07-12 05:46:37 +0000
@@ -176,23 +176,6 @@
 	return w;
 }
 
-void WorkersQueue::load_for_expedition(FileRead& fr,
-                                       Game& game,
-                                       MapObjectLoader& mol,
-                                       uint8_t num_workers) {
-	assert(type_ == wwWORKER);
-	assert(index_ != INVALID_INDEX);
-	for (uint8_t i = 0; i < num_workers; ++i) {
-		if (fr.unsigned_8() == 1) {
-			request_.reset(new Request(owner_, 0, InputQueue::request_callback, wwWORKER));
-			request_->read(fr, game, mol);
-		} else {
-			workers_.push_back(&mol.get<Worker>(fr.unsigned_32()));
-		}
-	}
-	// All other values have hopefully be set by the constructor or the caller
-}
-
 /**
  * Read and write
  */

=== modified file 'src/economy/workers_queue.h'
--- src/economy/workers_queue.h	2018-04-07 16:59:00 +0000
+++ src/economy/workers_queue.h	2018-07-12 05:46:37 +0000
@@ -70,14 +70,6 @@
 	 */
 	Worker* extract_worker();
 
-	/**
-	 * Loads the state of this WorkersQueue.
-	 * This method should only be used by ExpeditionBootstrap as compatibility helper when loading
-	 * save games for build 19.
-	 * If we ever drop support for them, remove this method and rework ExpeditionBootstrap::load().
-	 */
-	void load_for_expedition(FileRead&, Game&, MapObjectLoader&, uint8_t);
-
 protected:
 	void read_child(FileRead&, Game&, MapObjectLoader&) override;
 	void write_child(FileWrite&, Game&, MapObjectSaver&) override;

=== modified file 'src/game_io/game_interactive_player_packet.cc'
--- src/game_io/game_interactive_player_packet.cc	2018-04-07 16:59:00 +0000
+++ src/game_io/game_interactive_player_packet.cc	2018-07-12 05:46:37 +0000
@@ -34,17 +34,6 @@
 
 constexpr uint16_t kCurrentPacketVersion = 4;
 
-void load_landmarks_pre_zoom(FileRead* fr, InteractiveBase* ibase) {
-	size_t no_of_landmarks = fr->unsigned_8();
-	for (size_t i = 0; i < no_of_landmarks; ++i) {
-		uint8_t set = fr->unsigned_8();
-		MapView::View view = {Vector2f(fr->signed_32(), fr->signed_32()), 1.f};
-		if (set > 0) {
-			ibase->set_landmark(i, view);
-		}
-	}
-}
-
 }  // namespace
 
 void GameInteractivePlayerPacket::read(FileSystem& fs, Game& game, MapObjectLoader*) {
@@ -52,7 +41,7 @@
 		FileRead fr;
 		fr.open(fs, "binary/interactive_player");
 		uint16_t const packet_version = fr.unsigned_16();
-		if (packet_version >= 2 && packet_version <= kCurrentPacketVersion) {
+		if (packet_version == kCurrentPacketVersion) {
 			PlayerNumber player_number = fr.unsigned_8();
 			if (!(0 < player_number && player_number <= game.map().get_nrplayers())) {
 				throw GameDataError("Invalid player number: %i.", player_number);
@@ -70,15 +59,7 @@
 				if (player_number > max)
 					throw GameDataError("The game has no players!");
 			}
-			Vector2f center_map_pixel = Vector2f::zero();
-			if (packet_version <= 3) {
-				center_map_pixel.x = fr.unsigned_16();
-				center_map_pixel.y = fr.unsigned_16();
-			} else {
-				center_map_pixel.x = fr.float_32();
-				center_map_pixel.y = fr.float_32();
-			}
-
+			Vector2f center_map_pixel(fr.float_32(), fr.float_32());
 			uint32_t const display_flags = fr.unsigned_32();
 
 			if (InteractiveBase* const ibase = game.get_ibase()) {
@@ -96,19 +77,15 @@
 
 			// Map landmarks
 			if (InteractiveBase* const ibase = game.get_ibase()) {
-				if (packet_version == 3) {
-					load_landmarks_pre_zoom(&fr, ibase);
-				} else if (packet_version >= 4) {
-					size_t no_of_landmarks = fr.unsigned_8();
-					for (size_t i = 0; i < no_of_landmarks; ++i) {
-						uint8_t set = fr.unsigned_8();
-						const float x = fr.float_32();
-						const float y = fr.float_32();
-						const float zoom = fr.float_32();
-						MapView::View view = {Vector2f(x, y), zoom};
-						if (set > 0) {
-							ibase->set_landmark(i, view);
-						}
+				size_t no_of_landmarks = fr.unsigned_8();
+				for (size_t i = 0; i < no_of_landmarks; ++i) {
+					uint8_t set = fr.unsigned_8();
+					const float x = fr.float_32();
+					const float y = fr.float_32();
+					const float zoom = fr.float_32();
+					MapView::View view = {Vector2f(x, y), zoom};
+					if (set > 0) {
+						ibase->set_landmark(i, view);
 					}
 				}
 			}

=== modified file 'src/game_io/game_player_ai_persistent_packet.cc'
--- src/game_io/game_player_ai_persistent_packet.cc	2018-04-07 16:59:00 +0000
+++ src/game_io/game_player_ai_persistent_packet.cc	2018-07-12 05:46:37 +0000
@@ -28,14 +28,7 @@
 
 namespace Widelands {
 
-// Introduction of genetic algorithm with all structures that are needed for it
 constexpr uint16_t kCurrentPacketVersion = 5;
-// Last version with 150 magic numbers
-constexpr uint16_t kOldMagicNumbers = 4;
-// First version with genetics
-constexpr uint16_t kPacketVersion3 = 3;
-// Old Version before using genetics
-constexpr uint16_t kPacketVersion2 = 2;
 
 void GamePlayerAiPersistentPacket::read(FileSystem& fs, Game& game, MapObjectLoader*) {
 	try {
@@ -44,129 +37,84 @@
 		FileRead fr;
 		fr.open(fs, "binary/player_ai");
 		uint16_t const packet_version = fr.unsigned_16();
-		// TODO(GunChleoc): Savegame compatibility, remove after Build20
-		if (packet_version >= kPacketVersion2 && packet_version <= kCurrentPacketVersion) {
+		if (packet_version == kCurrentPacketVersion) {
 			iterate_players_existing(p, nr_players, game, player) try {
 				// Make sure that all containers are reset properly etc.
 				player->ai_data.initialize();
-
-				if (packet_version == kPacketVersion2) {
-					// Packet is not compatible. Consume without using the data.
-					fr.unsigned_8();
-					fr.unsigned_32();
-					fr.unsigned_32();
-					fr.unsigned_32();
-					fr.unsigned_16();
-					fr.unsigned_8();
-					fr.signed_16();
-					fr.unsigned_32();
-					fr.unsigned_32();
-					fr.signed_16();
-					fr.signed_32();
-					fr.unsigned_32();
-					fr.signed_32();
-					fr.unsigned_32();
-					fr.unsigned_32();
-					// Make the AI initialize itself
-					player->ai_data.initialized = 0;
-				} else {
-					// Contains Genetic algorithm data
-					player->ai_data.initialized = (fr.unsigned_8() == 1) ? true : false;
-					player->ai_data.colony_scan_area = fr.unsigned_32();
-					player->ai_data.trees_around_cutters = fr.unsigned_32();
-					player->ai_data.expedition_start_time = fr.unsigned_32();
-					player->ai_data.ships_utilization = fr.unsigned_16();
-					player->ai_data.no_more_expeditions = (fr.unsigned_8() == 1) ? true : false;
-					player->ai_data.last_attacked_player = fr.signed_16();
-					player->ai_data.least_military_score = fr.unsigned_32();
-					player->ai_data.target_military_score = fr.unsigned_32();
-					player->ai_data.ai_productionsites_ratio = fr.unsigned_32();
-					player->ai_data.ai_personality_mil_upper_limit = fr.signed_32();
-
-					// Magic numbers
-					size_t magic_numbers_size = fr.unsigned_32();
-
-					// Here we deal with old savegames that contains 150 magic numbers only
-					if (packet_version <= kOldMagicNumbers) {
-						// The savegame contains less then expected number of magic numbers
-						assert(magic_numbers_size <
-						       Widelands::Player::AiPersistentState::kMagicNumbersSize);
-						assert(player->ai_data.magic_numbers.size() ==
-						       Widelands::Player::AiPersistentState::kMagicNumbersSize);
-						for (size_t i = 0; i < magic_numbers_size; ++i) {
-							player->ai_data.magic_numbers.at(i) = fr.signed_16();
-						}
-						// Adding '50' to missing possitions
-						for (size_t i = magic_numbers_size;
-						     i < Widelands::Player::AiPersistentState::kMagicNumbersSize; ++i) {
-							player->ai_data.magic_numbers.at(i) = 50;
-						}
-					} else {
-						if (magic_numbers_size >
-						    Widelands::Player::AiPersistentState::kMagicNumbersSize) {
-							throw GameDataError("Too many magic numbers: We have %" PRIuS
-							                    " but only %" PRIuS "are allowed",
-							                    magic_numbers_size,
-							                    Widelands::Player::AiPersistentState::kMagicNumbersSize);
-						}
-						assert(player->ai_data.magic_numbers.size() ==
-						       Widelands::Player::AiPersistentState::kMagicNumbersSize);
-						for (size_t i = 0; i < magic_numbers_size; ++i) {
-							player->ai_data.magic_numbers.at(i) = fr.signed_16();
-						}
-					}
-
-					// Neurons
-					const size_t neuron_pool_size = fr.unsigned_32();
-					if (neuron_pool_size > Widelands::Player::AiPersistentState::kNeuronPoolSize) {
-						throw GameDataError(
-						   "Too many neurons: We have %" PRIuS " but only %" PRIuS "are allowed",
-						   neuron_pool_size, Widelands::Player::AiPersistentState::kNeuronPoolSize);
-					}
-					assert(player->ai_data.neuron_weights.size() ==
-					       Widelands::Player::AiPersistentState::kNeuronPoolSize);
-					for (size_t i = 0; i < neuron_pool_size; ++i) {
-						player->ai_data.neuron_weights.at(i) = fr.signed_8();
-					}
-					assert(player->ai_data.neuron_functs.size() ==
-					       Widelands::Player::AiPersistentState::kNeuronPoolSize);
-					for (size_t i = 0; i < neuron_pool_size; ++i) {
-						player->ai_data.neuron_functs.at(i) = fr.signed_8();
-					}
-
-					// F-neurons
-					const size_t f_neuron_pool_size = fr.unsigned_32();
-					if (f_neuron_pool_size > Widelands::Player::AiPersistentState::kFNeuronPoolSize) {
-						throw GameDataError(
-						   "Too many f neurons: We have %" PRIuS " but only %" PRIuS "are allowed",
-						   f_neuron_pool_size, Widelands::Player::AiPersistentState::kFNeuronPoolSize);
-					}
-					assert(player->ai_data.f_neurons.size() ==
-					       Widelands::Player::AiPersistentState::kFNeuronPoolSize);
-					for (size_t i = 0; i < f_neuron_pool_size; ++i) {
-						player->ai_data.f_neurons.at(i) = fr.unsigned_32();
-					}
-
-					// Remaining buildings for basic economy
-					assert(player->ai_data.remaining_basic_buildings.empty());
-
-					size_t remaining_basic_buildings_size = fr.unsigned_32();
-					for (uint16_t i = 0; i < remaining_basic_buildings_size; ++i) {
-						if (packet_version == kPacketVersion3) {  // Old genetics (buildings saved as idx)
-							player->ai_data.remaining_basic_buildings.emplace(
-							   static_cast<Widelands::DescriptionIndex>(fr.unsigned_32()),
-							   fr.unsigned_32());
-						} else {  // New genetics (buildings saved as strigs)
-							const std::string building_string = fr.string();
-							const Widelands::DescriptionIndex bld_idx =
-							   player->tribe().building_index(building_string);
-							player->ai_data.remaining_basic_buildings.emplace(bld_idx, fr.unsigned_32());
-						}
-					}
-					// Basic sanity check for remaining basic buildings
-					assert(player->ai_data.remaining_basic_buildings.size() <
-					       player->tribe().buildings().size());
-				}
+				// Contains Genetic algorithm data
+				player->ai_data.initialized = (fr.unsigned_8() == 1) ? true : false;
+				player->ai_data.colony_scan_area = fr.unsigned_32();
+				player->ai_data.trees_around_cutters = fr.unsigned_32();
+				player->ai_data.expedition_start_time = fr.unsigned_32();
+				player->ai_data.ships_utilization = fr.unsigned_16();
+				player->ai_data.no_more_expeditions = (fr.unsigned_8() == 1) ? true : false;
+				player->ai_data.last_attacked_player = fr.signed_16();
+				player->ai_data.least_military_score = fr.unsigned_32();
+				player->ai_data.target_military_score = fr.unsigned_32();
+				player->ai_data.ai_productionsites_ratio = fr.unsigned_32();
+				player->ai_data.ai_personality_mil_upper_limit = fr.signed_32();
+
+				// Magic numbers
+				const size_t magic_numbers_size = fr.unsigned_32();
+				if (magic_numbers_size >
+					Widelands::Player::AiPersistentState::kMagicNumbersSize) {
+					throw GameDataError("Too many magic numbers: We have %" PRIuS
+										" but only %" PRIuS "are allowed",
+										magic_numbers_size,
+										Widelands::Player::AiPersistentState::kMagicNumbersSize);
+				}
+				assert(player->ai_data.magic_numbers.size() ==
+					   Widelands::Player::AiPersistentState::kMagicNumbersSize);
+				for (size_t i = 0; i < magic_numbers_size; ++i) {
+					player->ai_data.magic_numbers.at(i) = fr.signed_16();
+				}
+
+				// Neurons
+				const size_t neuron_pool_size = fr.unsigned_32();
+				if (neuron_pool_size > Widelands::Player::AiPersistentState::kNeuronPoolSize) {
+					throw GameDataError(
+					   "Too many neurons: We have %" PRIuS " but only %" PRIuS "are allowed",
+					   neuron_pool_size, Widelands::Player::AiPersistentState::kNeuronPoolSize);
+				}
+				assert(player->ai_data.neuron_weights.size() ==
+					   Widelands::Player::AiPersistentState::kNeuronPoolSize);
+				for (size_t i = 0; i < neuron_pool_size; ++i) {
+					player->ai_data.neuron_weights.at(i) = fr.signed_8();
+				}
+				assert(player->ai_data.neuron_functs.size() ==
+					   Widelands::Player::AiPersistentState::kNeuronPoolSize);
+				for (size_t i = 0; i < neuron_pool_size; ++i) {
+					player->ai_data.neuron_functs.at(i) = fr.signed_8();
+				}
+
+				// F-neurons
+				const size_t f_neuron_pool_size = fr.unsigned_32();
+				if (f_neuron_pool_size > Widelands::Player::AiPersistentState::kFNeuronPoolSize) {
+					throw GameDataError(
+					   "Too many f neurons: We have %" PRIuS " but only %" PRIuS "are allowed",
+					   f_neuron_pool_size, Widelands::Player::AiPersistentState::kFNeuronPoolSize);
+				}
+				assert(player->ai_data.f_neurons.size() ==
+					   Widelands::Player::AiPersistentState::kFNeuronPoolSize);
+				for (size_t i = 0; i < f_neuron_pool_size; ++i) {
+					player->ai_data.f_neurons.at(i) = fr.unsigned_32();
+				}
+
+				// Remaining buildings for basic economy
+				assert(player->ai_data.remaining_basic_buildings.empty());
+
+				size_t remaining_basic_buildings_size = fr.unsigned_32();
+				for (uint16_t i = 0; i < remaining_basic_buildings_size; ++i) {
+					// Buildings saved as strings
+					const std::string building_string = fr.string();
+					const Widelands::DescriptionIndex bld_idx =
+					   player->tribe().building_index(building_string);
+					player->ai_data.remaining_basic_buildings.emplace(bld_idx, fr.unsigned_32());
+				}
+				// Basic sanity check for remaining basic buildings
+				assert(player->ai_data.remaining_basic_buildings.size() <
+					   player->tribe().buildings().size());
+
 			} catch (const WException& e) {
 				throw GameDataError("player %u: %s", p, e.what());
 			}

=== modified file 'src/game_io/game_player_info_packet.cc'
--- src/game_io/game_player_info_packet.cc	2018-04-28 07:02:42 +0000
+++ src/game_io/game_player_info_packet.cc	2018-07-12 05:46:37 +0000
@@ -37,7 +37,7 @@
 		FileRead fr;
 		fr.open(fs, "binary/player_info");
 		uint16_t const packet_version = fr.unsigned_16();
-		if (packet_version >= 19 && packet_version <= kCurrentPacketVersion) {
+		if (packet_version == kCurrentPacketVersion) {
 			uint32_t const max_players = fr.unsigned_16();
 			for (uint32_t i = 1; i < max_players + 1; ++i) {
 				game.remove_player(i);
@@ -60,7 +60,7 @@
 
 					player->set_ai(fr.c_string());
 					player->read_statistics(fr);
-					player->read_remaining_shipnames(fr, packet_version);
+					player->read_remaining_shipnames(fr);
 
 					player->casualties_ = fr.unsigned_32();
 					player->kills_ = fr.unsigned_32();
@@ -72,17 +72,15 @@
 			}
 
 			// Result screen
-			if (packet_version > 19) {
-				PlayersManager* manager = game.player_manager();
-				const uint8_t no_endstatus = fr.unsigned_8();
-				for (uint8_t i = 0; i < no_endstatus; ++i) {
-					PlayerEndStatus status;
-					status.player = fr.unsigned_8();
-					status.result = static_cast<PlayerEndResult>(fr.unsigned_8());
-					status.time = fr.unsigned_32();
-					status.info = fr.c_string();
-					manager->set_player_end_status(status);
-				}
+			PlayersManager* manager = game.player_manager();
+			const uint8_t no_endstatus = fr.unsigned_8();
+			for (uint8_t i = 0; i < no_endstatus; ++i) {
+				PlayerEndStatus status;
+				status.player = fr.unsigned_8();
+				status.result = static_cast<PlayerEndResult>(fr.unsigned_8());
+				status.time = fr.unsigned_32();
+				status.info = fr.c_string();
+				manager->set_player_end_status(status);
 			}
 
 			game.read_statistics(fr);

=== modified file 'src/logic/map_objects/immovable.cc'
--- src/logic/map_objects/immovable.cc	2018-04-07 16:59:00 +0000
+++ src/logic/map_objects/immovable.cc	2018-07-12 05:46:37 +0000
@@ -550,6 +550,7 @@
 
 	Immovable& imm = dynamic_cast<Immovable&>(*get_object());
 
+	// Supporting older versions for map loading
 	if (packet_version >= 5) {
 		PlayerNumber pn = fr.unsigned_8();
 		if (pn && pn <= kMaxPlayers) {

=== modified file 'src/logic/map_objects/map_object.cc'
--- src/logic/map_objects/map_object.cc	2018-04-07 16:59:00 +0000
+++ src/logic/map_objects/map_object.cc	2018-07-12 05:46:37 +0000
@@ -592,6 +592,7 @@
 			throw wexception("header is %u, expected %u", header, HeaderMapObject);
 
 		uint8_t const packet_version = fr.unsigned_8();
+		// Supporting older versions for map loading
 		if (packet_version < 1 || packet_version > kCurrentPacketVersionMapObject) {
 			throw UnhandledVersionError("MapObject", packet_version, kCurrentPacketVersionMapObject);
 		}

=== modified file 'src/logic/map_objects/tribes/militarysite.h'
--- src/logic/map_objects/tribes/militarysite.h	2018-04-07 16:59:00 +0000
+++ src/logic/map_objects/tribes/militarysite.h	2018-07-12 05:46:37 +0000
@@ -36,7 +36,6 @@
 
 // I assume elsewhere, that enum SoldierPreference fits to uint8_t.
 enum class SoldierPreference : uint8_t {
-	kNotSet,  // For savegame compatibility only.
 	kRookies,
 	kHeroes,
 };

=== modified file 'src/logic/map_objects/tribes/ship.cc'
--- src/logic/map_objects/tribes/ship.cc	2018-05-27 06:02:18 +0000
+++ src/logic/map_objects/tribes/ship.cc	2018-07-12 05:46:37 +0000
@@ -1110,7 +1110,7 @@
 ==============================
 */
 
-constexpr uint8_t kCurrentPacketVersion = 7;
+constexpr uint8_t kCurrentPacketVersion = 8;
 
 const Bob::Task* Ship::Loader::get_task(const std::string& name) {
 	if (name == "shipidle" || name == "ship")

=== modified file 'src/logic/map_objects/tribes/ship.h'
--- src/logic/map_objects/tribes/ship.h	2018-07-12 04:41:20 +0000
+++ src/logic/map_objects/tribes/ship.h	2018-07-12 05:46:37 +0000
@@ -35,10 +35,11 @@
 class PortDock;
 
 // This can't be part of the Ship class because of forward declaration in game.h
+// Keep the order of entries for savegame compatibility.
 enum class IslandExploreDirection {
-	kCounterClockwise = 0,  // This comes first for savegame compatibility (used to be = 0)
-	kClockwise = 1,
-	kNotSet
+	kNotSet,
+	kCounterClockwise,
+	kClockwise,
 };
 
 struct NoteShip {

=== modified file 'src/logic/map_objects/tribes/soldier.cc'
--- src/logic/map_objects/tribes/soldier.cc	2018-04-07 16:59:00 +0000
+++ src/logic/map_objects/tribes/soldier.cc	2018-07-12 05:46:37 +0000
@@ -1574,9 +1574,6 @@
 */
 
 constexpr uint8_t kCurrentPacketVersion = 3;
-// TODO(TiborB): This is only for map compatibility in regression tests, we should get rid of this
-// ASAP
-constexpr uint8_t kOldPacketVersion = 2;
 
 Soldier::Loader::Loader() : battle_(0) {
 }
@@ -1586,17 +1583,10 @@
 
 	try {
 		uint8_t packet_version = fr.unsigned_8();
-		if (packet_version == kCurrentPacketVersion || packet_version == kOldPacketVersion) {
-
+		if (packet_version == kCurrentPacketVersion) {
 			Soldier& soldier = get<Soldier>();
 			soldier.current_health_ = fr.unsigned_32();
-			if (packet_version == kCurrentPacketVersion) {
-				soldier.retreat_health_ = fr.unsigned_32();
-			} else {
-				// not ideal but will be used only for regression tests
-				soldier.retreat_health_ = 0;
-			}
-
+			soldier.retreat_health_ = fr.unsigned_32();
 			soldier.health_level_ = std::min(fr.unsigned_32(), soldier.descr().get_max_health_level());
 			soldier.attack_level_ = std::min(fr.unsigned_32(), soldier.descr().get_max_attack_level());
 			soldier.defense_level_ =
@@ -1614,7 +1604,6 @@
 				soldier.combat_walkstart_ = fr.unsigned_32();
 				soldier.combat_walkend_ = fr.unsigned_32();
 			}
-
 			battle_ = fr.unsigned_32();
 		} else {
 			throw UnhandledVersionError("Soldier", packet_version, kCurrentPacketVersion);

=== modified file 'src/logic/map_objects/tribes/worker.cc'
--- src/logic/map_objects/tribes/worker.cc	2018-05-05 17:10:37 +0000
+++ src/logic/map_objects/tribes/worker.cc	2018-07-12 05:46:37 +0000
@@ -2959,21 +2959,6 @@
 	}
 
 	const Map& map = game.map();
-
-	if (scouts_worklist.empty()) {
-		// This routine assumes that scouts_worklist is not empty. There is one exception:
-		// First call to this routine after loading an old savegame. The least-invasive
-		// way to acquire old savegame compatibility was to simply ask the scout to go home early,
-		// under this special situation. Anybody reading this,
-		// TODO(kxq): Please remove this code block (and compatibility_2017 code from load routine)
-		// once Build 20 is out. Thanks.
-		log("Warning: sending scout home. Assuming the game was just started, from savegame, in "
-		    "compatibility mode.\n");
-		pop_task(game);
-		schedule_act(game, 10);
-		return;
-	}
-
 	bool do_run = static_cast<int32_t>(state.ivar2 - game.get_gametime()) > 0;
 
 	// do not pop; this function is called many times per run.
@@ -3044,12 +3029,7 @@
 	Bob::Loader::load(fr);
 	try {
 		uint8_t packet_version = fr.unsigned_8();
-		// TODO(kxq): Remove the compatibility_2017 code (and similars, dozen lines below) after B20
-		// TODO(kxq): Also remove the code fragment from Worker::scout_update with compatibility_2017
-		// in comment.
-		bool compatibility_2017 = 2 == packet_version;
-		if (packet_version == kCurrentPacketVersion || compatibility_2017) {
-
+		if (packet_version == kCurrentPacketVersion) {
 			Worker& worker = get<Worker>();
 			location_ = fr.unsigned_32();
 			carried_ware_ = fr.unsigned_32();
@@ -3059,14 +3039,7 @@
 				worker.transfer_ = new Transfer(dynamic_cast<Game&>(egbase()), worker);
 				worker.transfer_->read(fr, transfer_);
 			}
-			unsigned veclen;
-			// TODO(kxq): Remove compatibility_2017 associated code from here and above,
-			// after build 20 has been released.
-			if (compatibility_2017) {
-				veclen = 0;
-			} else {
-				veclen = fr.unsigned_8();
-			}
+			const unsigned veclen = fr.unsigned_8();
 			for (unsigned q = 0; q < veclen; q++) {
 				if (fr.unsigned_8()) {
 					const PlaceToScout gsw;
@@ -3079,7 +3052,6 @@
 					worker.scouts_worklist.push_back(gtt);
 				}
 			}
-
 		} else {
 			throw UnhandledVersionError("Worker", packet_version, kCurrentPacketVersion);
 		}

=== modified file 'src/logic/player.cc'
--- src/logic/player.cc	2018-07-12 04:41:20 +0000
+++ src/logic/player.cc	2018-07-12 05:46:37 +0000
@@ -1337,19 +1337,14 @@
  *
  * \param fr source stream
  */
-void Player::read_remaining_shipnames(FileRead& fr, uint16_t packet_version) {
+void Player::read_remaining_shipnames(FileRead& fr) {
 	// First get rid of default shipnames
 	remaining_shipnames_.clear();
 	const uint16_t count = fr.unsigned_16();
 	for (uint16_t i = 0; i < count; ++i) {
 		remaining_shipnames_.insert(fr.string());
 	}
-	// TODO(GunChleoc): Savegame compatibility. Remove after Build 20.
-	if (packet_version >= 21) {
-		ship_name_counter_ = fr.unsigned_32();
-	} else {
-		ship_name_counter_ = ships_.size();
-	}
+	ship_name_counter_ = fr.unsigned_32();
 }
 
 /**

=== modified file 'src/logic/player.h'
--- src/logic/player.h	2018-07-12 04:41:20 +0000
+++ src/logic/player.h	2018-07-12 05:46:37 +0000
@@ -581,7 +581,7 @@
 
 	void read_statistics(FileRead&);
 	void write_statistics(FileWrite&) const;
-	void read_remaining_shipnames(FileRead&, uint16_t packet_version);
+	void read_remaining_shipnames(FileRead&);
 	void write_remaining_shipnames(FileWrite&) const;
 	void sample_statistics();
 	void ware_produced(DescriptionIndex);

=== modified file 'src/logic/playercommand.cc'
--- src/logic/playercommand.cc	2018-07-12 04:41:20 +0000
+++ src/logic/playercommand.cc	2018-07-12 05:46:37 +0000
@@ -199,7 +199,7 @@
 void PlayerCommand::read(FileRead& fr, EditorGameBase& egbase, MapObjectLoader& mol) {
 	try {
 		const uint16_t packet_version = fr.unsigned_16();
-		if (packet_version >= 2 && packet_version <= kCurrentPacketVersionPlayerCommand) {
+		if (packet_version == kCurrentPacketVersionPlayerCommand) {
 			GameLogicCommand::read(fr, egbase, mol);
 			sender_ = fr.unsigned_8();
 			if (!egbase.get_player(sender_))
@@ -1140,16 +1140,14 @@
 void CmdSetInputMaxFill::read(FileRead& fr, EditorGameBase& egbase, MapObjectLoader& mol) {
 	try {
 		const uint16_t packet_version = fr.unsigned_16();
-		if (packet_version >= 1 && packet_version <= kCurrentPacketVersionCmdSetInputMaxFill) {
+		if (packet_version == kCurrentPacketVersionCmdSetInputMaxFill) {
 			PlayerCommand::read(fr, egbase, mol);
 			serial_ = get_object_serial_or_zero<Building>(fr.unsigned_32(), mol);
 			index_ = fr.signed_32();
-			if (packet_version > 1) {
-				if (fr.unsigned_8() == 0) {
-					type_ = wwWARE;
-				} else {
-					type_ = wwWORKER;
-				}
+			if (fr.unsigned_8() == 0) {
+				type_ = wwWARE;
+			} else {
+				type_ = wwWORKER;
 			}
 			max_fill_ = fr.unsigned_32();
 		} else {

=== modified file 'src/map_io/map_allowed_building_types_packet.cc'
--- src/map_io/map_allowed_building_types_packet.cc	2018-04-07 16:59:00 +0000
+++ src/map_io/map_allowed_building_types_packet.cc	2018-07-12 05:46:37 +0000
@@ -85,23 +85,6 @@
 				} catch (const WException& e) {
 					throw GameDataError("player %u (%s): %s", p, tribe.name().c_str(), e.what());
 				}
-
-				// Savegame compatibility: If all buildings except for the barracks are allowed, allow
-				// it too. This will make games playable again except for scenarios that restrict the
-				// number of buildings and need soldier creation.
-				// TODO(Notabilis): Remove this when we break save game compatibility anyway
-				if (!player->is_building_type_allowed(player->tribe().barracks())) {
-					size_t allowed_buildings = 0;
-					for (const Widelands::DescriptionIndex& index : player->tribe().buildings()) {
-						if (player->is_building_type_allowed(index)) {
-							++allowed_buildings;
-						}
-					}
-					if (player->tribe().buildings().size() - 1 == allowed_buildings) {
-						log("WARNING: Enabling barracks for player %u.\n", player->player_number());
-						player->allow_building_type(player->tribe().barracks(), true);
-					}
-				}
 			}
 		} else {
 			throw UnhandledVersionError(

=== modified file 'src/map_io/map_buildingdata_packet.cc'
--- src/map_io/map_buildingdata_packet.cc	2018-04-07 16:59:00 +0000
+++ src/map_io/map_buildingdata_packet.cc	2018-07-12 05:46:37 +0000
@@ -508,10 +508,6 @@
 			militarysite.soldier_upgrade_requirements_ =
 			   RequireAttribute(TrainingAttribute::kTotal, reqmin, reqmax);
 			militarysite.soldier_preference_ = static_cast<SoldierPreference>(fr.unsigned_8());
-			// TODO(GunChleoc): Savegame compatibility, remove kNotSet after Build 20.
-			if (militarysite.soldier_preference_ == SoldierPreference::kNotSet) {
-				militarysite.soldier_preference_ = SoldierPreference::kRookies;
-			}
 			militarysite.next_swap_soldiers_time_ = fr.signed_32();
 			militarysite.soldier_upgrade_try_ = 0 != fr.unsigned_8() ? true : false;
 			militarysite.doing_upgrade_request_ = 0 != fr.unsigned_8() ? true : false;

=== modified file 'src/map_io/map_players_view_packet.cc'
--- src/map_io/map_players_view_packet.cc	2018-04-28 09:45:36 +0000
+++ src/map_io/map_players_view_packet.cc	2018-07-12 05:46:37 +0000
@@ -37,23 +37,13 @@
 #include "logic/map_objects/tribes/tribe_descr.h"
 #include "logic/map_objects/world/world.h"
 #include "logic/player.h"
-
 namespace Widelands {
 
-#define PLAYERDIRNAME_TEMPLATE "player/%u"
-#define DIRNAME_TEMPLATE PLAYERDIRNAME_TEMPLATE "/view"
+#define DIRNAME_TEMPLATE "player/%u/view"
 
 constexpr uint8_t kCurrentPacketVersionUnseenTimes = 1;
 #define UNSEEN_TIMES_FILENAME_TEMPLATE DIRNAME_TEMPLATE "/unseen_times_%u"
 
-constexpr uint8_t kCurrentPacketVersionImmovableKinds = 2;
-#define NODE_IMMOVABLE_KINDS_FILENAME_TEMPLATE DIRNAME_TEMPLATE "/node_immovable_kinds_%u"
-#define TRIANGLE_IMMOVABLE_KINDS_FILENAME_TEMPLATE DIRNAME_TEMPLATE "/triangle_immovable_kinds_%u"
-
-constexpr uint8_t kCurrentPacketVersionImmovables = 2;
-#define NODE_IMMOVABLES_FILENAME_TEMPLATE DIRNAME_TEMPLATE "/node_immovables_%u"
-#define TRIANGLE_IMMOVABLES_FILENAME_TEMPLATE DIRNAME_TEMPLATE "/triangle_immovables_%u"
-
 constexpr uint8_t kCurrentPacketVersionRoads = 2;
 #define ROADS_FILENAME_TEMPLATE DIRNAME_TEMPLATE "/roads_%u"
 
@@ -109,13 +99,6 @@
 //                /     \ /
 //              bl------br
 
-struct MapObjectData {
-	MapObjectData() : map_object_descr(nullptr) {
-	}
-	const MapObjectDescr* map_object_descr;
-	ConstructionsiteInformation csi;
-};
-
 namespace {
 #define OPEN_INPUT_FILE(filetype, file, filename, filename_template, version)                      \
 	char(filename)[FILENAME_SIZE];                                                                  \
@@ -168,118 +151,8 @@
 		   "MapPlayersViewPacket::read: player %u:"                                                  \
 		   "Found %lu trailing bytes in \"%s\"",                                                     \
 		   plnum, static_cast<long unsigned int>((file).get_size() - (file).get_pos()), filename);
-
-// Errors for the Read* functions.
-struct TribeImmovableNonexistent : public FileRead::DataError {
-	explicit TribeImmovableNonexistent(const std::string& Name)
-	   : DataError("immovable type \"%s\" does not seem to be a tribe immovable", Name.c_str()),
-	     name(Name) {
-	}
-
-	std::string name;
-};
-struct WorldImmovableNonexistent : public FileRead::DataError {
-	explicit WorldImmovableNonexistent(char const* const Name)
-	   : DataError("world does not define immovable type \"%s\"", Name), name(Name) {
-	}
-	char const* const name;
-};
-struct BuildingNonexistent : public FileRead::DataError {
-	explicit BuildingNonexistent(char const* const Name)
-	   : DataError("tribes do not define building type \"%s\"", Name), name(Name) {
-	}
-	char const* const name;
-};
-
-// reads an immovable depending on whether it is a tribe or world immovable
-const ImmovableDescr& read_immovable_type(StreamRead* fr, const EditorGameBase& egbase) {
-	uint8_t owner = fr->unsigned_8();
-	char const* const name = fr->c_string();
-	if (owner == static_cast<uint8_t>(MapObjectDescr::OwnerType::kWorld)) {
-		DescriptionIndex const index = egbase.world().get_immovable_index(name);
-		if (index == Widelands::INVALID_INDEX)
-			throw WorldImmovableNonexistent(name);
-		return *egbase.world().get_immovable_descr(index);
-	} else {
-		assert(owner == static_cast<uint8_t>(MapObjectDescr::OwnerType::kTribe));
-		DescriptionIndex const index = egbase.tribes().immovable_index(name);
-		if (index == Widelands::INVALID_INDEX)
-			throw TribeImmovableNonexistent(name);
-		return *egbase.tribes().get_immovable_descr(index);
-	}
-}
-
-// Reads a c_string and interprets it as the name of an immovable type.
-//
-// \returns a reference to the building type description.
-//
-// \throws Building_Nonexistent if there is no building type with that name
-const BuildingDescr& read_building_type(StreamRead* fr, const EditorGameBase& egbase) {
-	char const* const name = fr->c_string();
-	DescriptionIndex const index = egbase.tribes().building_index(name);
-	if (!egbase.tribes().building_exists(index)) {
-		throw BuildingNonexistent(name);
-	}
-	return *egbase.tribes().get_building_descr(index);
-}
-
-// Encode a Immovable_Type into 'wr'.
-void write_immovable_type(StreamWrite* wr, const ImmovableDescr& immovable) {
-	wr->unsigned_8(static_cast<uint8_t>(immovable.owner_type()));
-	wr->string(immovable.name());
-}
-
-// Encode a Building_Type into 'wr'.
-void write_building_type(StreamWrite* wr, const BuildingDescr& building) {
-	wr->string(building.name());
-}
-
 }  // namespace
 
-inline static MapObjectData read_unseen_immovable(const EditorGameBase& egbase,
-                                                  uint8_t& immovable_kind,
-                                                  FileRead& immovables_file,
-                                                  uint8_t& version) {
-	MapObjectData m;
-	try {
-		switch (immovable_kind) {
-		case UNSEEN_NONE:  //  The player sees no immovable.
-			m.map_object_descr = nullptr;
-			break;
-		case UNSEEN_TRIBEORWORLD:  //  The player sees a tribe or world immovable.
-			m.map_object_descr = &read_immovable_type(&immovables_file, egbase);
-			break;
-		case UNSEEN_FLAG:  //  The player sees a flag.
-			m.map_object_descr = &g_flag_descr;
-			break;
-		case UNSEEN_BUILDING:  //  The player sees a building.
-			m.map_object_descr = &read_building_type(&immovables_file, egbase);
-			if (version == kCurrentPacketVersionImmovables) {
-				// Read data from immovables file
-				if (immovables_file.unsigned_8() == 1) {  // the building is a constructionsite
-					m.csi.becomes = &read_building_type(&immovables_file, egbase);
-					if (immovables_file.unsigned_8() == 1) {
-						m.csi.was = &read_building_type(&immovables_file, egbase);
-					}
-					m.csi.totaltime = immovables_file.unsigned_32();
-					m.csi.completedtime = immovables_file.unsigned_32();
-				}
-			} else {
-				throw UnhandledVersionError(
-				   "MapPlayersViewPacket", version, kCurrentPacketVersionImmovables);
-			}
-			break;
-		case UNSEEN_PORTDOCK:  // The player sees a port dock
-			m.map_object_descr = &g_portdock_descr;
-			break;
-		default:
-			throw GameDataError("Unknown immovable-kind type %d", immovable_kind);
-		}
-	} catch (const WException& e) {
-		throw GameDataError("unseen immovable: %s", e.what());
-	}
-	return m;
-}
 
 void MapPlayersViewPacket::read(FileSystem& fs,
                                 EditorGameBase& egbase,
@@ -431,31 +304,12 @@
 		}
 
 		// Read the player's knowledge about all fields
-		OPEN_INPUT_FILE_NEW_VERSION(FileRead, node_immovable_kinds_file,
-		                            node_immovable_kinds_filename, node_immovable_kinds_file_version,
-		                            NODE_IMMOVABLE_KINDS_FILENAME_TEMPLATE,
-		                            kCurrentPacketVersionImmovableKinds);
-
-		OPEN_INPUT_FILE_NEW_VERSION(FileRead, node_immovables_file, node_immovables_filename,
-		                            node_immovables_file_version, NODE_IMMOVABLES_FILENAME_TEMPLATE,
-		                            kCurrentPacketVersionImmovables);
-
 		OPEN_INPUT_FILE_NEW_VERSION(FileRead, roads_file, roads_filename, road_file_version,
 		                            ROADS_FILENAME_TEMPLATE, kCurrentPacketVersionRoads);
 
 		OPEN_INPUT_FILE_NEW_VERSION(FileRead, terrains_file, terrains_filename, terrains_file_version,
 		                            TERRAINS_FILENAME_TEMPLATE, kCurrentPacketVersionTerrains);
 
-		OPEN_INPUT_FILE_NEW_VERSION(
-		   FileRead, triangle_immovable_kinds_file, triangle_immovable_kinds_filename,
-		   triangle_immovable_kinds_file_version, TRIANGLE_IMMOVABLE_KINDS_FILENAME_TEMPLATE,
-		   kCurrentPacketVersionImmovableKinds);
-
-		OPEN_INPUT_FILE_NEW_VERSION(FileRead, triangle_immovables_file, triangle_immovables_filename,
-		                            triangle_immovables_file_version,
-		                            TRIANGLE_IMMOVABLES_FILENAME_TEMPLATE,
-		                            kCurrentPacketVersionImmovables);
-
 		OPEN_INPUT_FILE(FileRead, owners_file, owners_filename, OWNERS_FILENAME_TEMPLATE,
 		                kCurrentPacketVersionOwners);
 
@@ -550,19 +404,6 @@
 						                    static_cast<long unsigned int>(owners_file.get_pos() - 1),
 						                    f.x, f.y, owner, nr_players);
 					}
-					uint8_t imm_kind = 0;
-					if (node_immovable_kinds_file_version == kCurrentPacketVersionImmovableKinds) {
-						imm_kind = node_immovable_kinds_file.unsigned_8();
-					} else {
-						throw UnhandledVersionError("MapPlayersViewPacket - Node Immovable kinds",
-						                            node_immovable_kinds_file_version,
-						                            kCurrentPacketVersionImmovableKinds);
-					}
-					MapObjectData mod = read_unseen_immovable(
-					   egbase, imm_kind, node_immovables_file, node_immovables_file_version);
-					f_player_field.map_object_descr = mod.map_object_descr;
-					f_player_field.constructionsite = mod.csi;
-
 					// Read in whether this field had a border the last time it was seen
 					if (border_file_version == kCurrentPacketVersionBorder) {
 						uint8_t borders = border_file.unsigned_8();
@@ -618,22 +459,6 @@
 						throw UnhandledVersionError("MapPlayersViewPacket - Terrains",
 						                            terrains_file_version, kCurrentPacketVersionTerrains);
 					}
-					uint8_t im_kind = 0;
-					if (triangle_immovable_kinds_file_version == kCurrentPacketVersionImmovableKinds) {
-						im_kind = triangle_immovable_kinds_file.unsigned_8();
-					} else {
-						throw UnhandledVersionError("MapPlayersViewPacket - Triangle Immovable kinds",
-						                            triangle_immovable_kinds_file_version,
-						                            kCurrentPacketVersionImmovableKinds);
-					}
-					// We read and ignore the immovable information on the D
-					// triangle. This was done because there were vague plans of
-					// suporting immovables on the triangles instead as on the
-					// nodes.
-					// TODO(sirver): Remove this logic the next time we break
-					// savegame compatibility.
-					read_unseen_immovable(
-					   egbase, im_kind, triangle_immovables_file, triangle_immovables_file_version);
 				}
 				if (f_seen | br_seen | r_seen) {
 					//  The player currently sees the R triangle. Therefore his
@@ -649,20 +474,6 @@
 						throw UnhandledVersionError("MapPlayersViewPacket - Terrains",
 						                            terrains_file_version, kCurrentPacketVersionTerrains);
 					}
-					uint8_t im_kind = 0;
-					if (triangle_immovable_kinds_file_version == kCurrentPacketVersionImmovableKinds) {
-						im_kind = triangle_immovable_kinds_file.unsigned_8();
-					} else {
-						throw UnhandledVersionError("MapPlayersViewPacket - Triangle Immovable kinds",
-						                            triangle_immovable_kinds_file_version,
-						                            kCurrentPacketVersionImmovableKinds);
-					}
-					// We read and ignore the immovable information on the D
-					// triangle. This was done because there were vague plans of
-					// suporting immovables on the triangles instead as on the
-					// nodes.
-					read_unseen_immovable(
-					   egbase, im_kind, triangle_immovables_file, triangle_immovables_file_version);
 				}
 
 				{  //  edges
@@ -791,23 +602,14 @@
 				player->hidden_fields_.insert(
 				   std::make_pair(hidden_file.unsigned_32(), hidden_file.unsigned_16()));
 			}
-		} else if (hidden_file_version < 0) {
-			// TODO(GunChleoc): Savegame compatibility - remove after Build 20
-			log("MapPlayersViewPacket - No hidden fields to read for Player %d - probably an old save "
-			    "file\n",
-			    plnum);
 		} else {
 			throw UnhandledVersionError("MapPlayersViewPacket - Hidden fields file",
 			                            hidden_file_version, kCurrentPacketVersionHidden);
 		}
 
 		CHECK_TRAILING_BYTES(unseen_times_file, unseen_times_filename);
-		CHECK_TRAILING_BYTES(node_immovable_kinds_file, node_immovable_kinds_filename);
-		CHECK_TRAILING_BYTES(node_immovables_file, node_immovables_filename);
 		CHECK_TRAILING_BYTES(roads_file, roads_filename);
 		CHECK_TRAILING_BYTES(terrains_file, terrains_filename);
-		CHECK_TRAILING_BYTES(triangle_immovable_kinds_file, triangle_immovable_kinds_filename);
-		CHECK_TRAILING_BYTES(triangle_immovables_file, triangle_immovables_filename);
 		CHECK_TRAILING_BYTES(owners_file, owners_filename);
 		CHECK_TRAILING_BYTES(surveys_file, surveys_filename);
 		CHECK_TRAILING_BYTES(survey_amounts_file, survey_amounts_filename);
@@ -817,52 +619,6 @@
 	}
 }
 
-inline static void write_unseen_immovable(MapObjectData const* map_object_data,
-                                          FileWrite& immovable_kinds_file,
-                                          FileWrite& immovables_file) {
-	MapObjectDescr const* const map_object_descr = map_object_data->map_object_descr;
-	const ConstructionsiteInformation& csi = map_object_data->csi;
-	assert(!Road::is_road_descr(map_object_descr));
-	uint8_t immovable_kind = 255;
-
-	if (!map_object_descr)
-		immovable_kind = UNSEEN_NONE;
-	else if (upcast(ImmovableDescr const, immovable_descr, map_object_descr)) {
-		immovable_kind = UNSEEN_TRIBEORWORLD;
-		write_immovable_type(&immovables_file, *immovable_descr);
-	} else if (map_object_descr->type() == MapObjectType::FLAG)
-		immovable_kind = UNSEEN_FLAG;
-	else if (upcast(BuildingDescr const, building_descr, map_object_descr)) {
-		immovable_kind = UNSEEN_BUILDING;
-		write_building_type(&immovables_file, *building_descr);
-		if (!csi.becomes)
-			immovables_file.unsigned_8(0);
-		else {
-			// the building is a constructionsite
-			immovables_file.unsigned_8(1);
-			write_building_type(&immovables_file, *csi.becomes);
-			if (!csi.was)
-				immovables_file.unsigned_8(0);
-			else {
-				// constructionsite is an enhancement, therefor we write down the enhancement
-				immovables_file.unsigned_8(1);
-				write_building_type(&immovables_file, *csi.was);
-			}
-			immovables_file.unsigned_32(csi.totaltime);
-			immovables_file.unsigned_32(csi.completedtime);
-		}
-	} else if (map_object_descr->type() == MapObjectType::PORTDOCK)
-		immovable_kind = UNSEEN_PORTDOCK;
-	else {
-		// We should never get here.. output some information about the situation.
-		log("\nwidelands_map_players_view_data_packet.cc::write_unseen_immovable(): ");
-		log("%s %s (%s) was not expected.\n", typeid(*map_object_descr).name(),
-		    map_object_descr->name().c_str(), map_object_descr->descname().c_str());
-		NEVER_HERE();
-	}
-	immovable_kinds_file.unsigned_8(immovable_kind);
-}
-
 #define WRITE(file, filename_template, version)                                                    \
 	snprintf(filename, sizeof(filename), filename_template, plnum, version);                        \
 	(file).write(fs, filename);
@@ -880,12 +636,8 @@
 	   plnum, nr_players, egbase,
 	   player) if (const Player::Field* const player_fields = player->fields_) {
 		FileWrite unseen_times_file;
-		FileWrite node_immovable_kinds_file;
-		FileWrite node_immovables_file;
 		FileWrite roads_file;
 		FileWrite terrains_file;
-		FileWrite triangle_immovable_kinds_file;
-		FileWrite triangle_immovables_file;
 		FileWrite owners_file;
 		FileWrite surveys_file;
 		FileWrite survey_amounts_file;
@@ -929,10 +681,6 @@
 						unseen_times_file.unsigned_32(f_player_field.time_node_last_unseen);
 						assert(f_player_field.owner < 0x20);
 						owners_file.unsigned_8(f_player_field.owner);
-						MapObjectData mod;
-						mod.map_object_descr = f_player_field.map_object_descr;
-						mod.csi = f_player_field.constructionsite;
-						write_unseen_immovable(&mod, node_immovable_kinds_file, node_immovables_file);
 
 						// write whether this field had a border the last time it was seen
 						uint8_t borders = 0;
@@ -949,20 +697,12 @@
 					   //  seen it
 					   ((!bl_seen) & (!br_seen) & (f_everseen | bl_everseen | br_everseen)) {
 						terrains_file.unsigned_8(f_player_field.terrains.d);
-						MapObjectData mod;
-						mod.map_object_descr = nullptr;
-						write_unseen_immovable(
-						   &mod, triangle_immovable_kinds_file, triangle_immovables_file);
 					}
 					if
 					   //  the player does not see the R triangle now but has
 					   //  seen it
 					   ((!br_seen) & (!r_seen) & (f_everseen | br_everseen | r_everseen)) {
 						terrains_file.unsigned_8(f_player_field.terrains.r);
-						MapObjectData mod;
-						mod.map_object_descr = nullptr;
-						write_unseen_immovable(
-						   &mod, triangle_immovable_kinds_file, triangle_immovables_file);
 					}
 
 					//  edges
@@ -1007,28 +747,14 @@
 		char filename[FILENAME_SIZE];
 
 		fs.ensure_directory_exists(
-		   (boost::format(PLAYERDIRNAME_TEMPLATE) % static_cast<unsigned int>(plnum)).str());
-		fs.ensure_directory_exists(
 		   (boost::format(DIRNAME_TEMPLATE) % static_cast<unsigned int>(plnum)).str());
 
 		WRITE(unseen_times_file, UNSEEN_TIMES_FILENAME_TEMPLATE, kCurrentPacketVersionUnseenTimes);
 
-		WRITE(node_immovable_kinds_file, NODE_IMMOVABLE_KINDS_FILENAME_TEMPLATE,
-		      kCurrentPacketVersionImmovableKinds);
-
-		WRITE(
-		   node_immovables_file, NODE_IMMOVABLES_FILENAME_TEMPLATE, kCurrentPacketVersionImmovables);
-
 		WRITE(roads_file, ROADS_FILENAME_TEMPLATE, kCurrentPacketVersionRoads);
 
 		WRITE(terrains_file, TERRAINS_FILENAME_TEMPLATE, kCurrentPacketVersionTerrains);
 
-		WRITE(triangle_immovable_kinds_file, TRIANGLE_IMMOVABLE_KINDS_FILENAME_TEMPLATE,
-		      kCurrentPacketVersionImmovableKinds);
-
-		WRITE(triangle_immovables_file, TRIANGLE_IMMOVABLES_FILENAME_TEMPLATE,
-		      kCurrentPacketVersionImmovables);
-
 		WRITE(owners_file, OWNERS_FILENAME_TEMPLATE, kCurrentPacketVersionOwners);
 
 		WRITE(surveys_file, SURVEYS_FILENAME_TEMPLATE, kCurrentPacketVersionSurveys);

=== modified file 'src/wui/soldierlist.cc'
--- src/wui/soldierlist.cc	2018-04-07 16:59:00 +0000
+++ src/wui/soldierlist.cc	2018-07-12 05:46:37 +0000
@@ -436,8 +436,6 @@
 	if (upcast(Widelands::MilitarySite, ms, &building_)) {
 		switch (ms->get_soldier_preference()) {
 		case Widelands::SoldierPreference::kRookies:
-			FALLS_THROUGH;
-		case Widelands::SoldierPreference::kNotSet:
 			soldier_preference_.set_state(0);
 			break;
 		case Widelands::SoldierPreference::kHeroes:

=== modified file 'test/maps/lua_testsuite.wmf/binary/mapobjects'
Binary files test/maps/lua_testsuite.wmf/binary/mapobjects	2018-04-17 03:17:15 +0000 and test/maps/lua_testsuite.wmf/binary/mapobjects	2018-07-12 05:46:37 +0000 differ

Follow ups