changeset 11935:afd8caa1ae0d draft

(svn r16338) -Codechange: split loading of references to two phases In the first phase, indexes are stored. In the second phase, indexes are checked for validity and converted to pointers
author smatz <smatz@openttd.org>
date Sun, 17 May 2009 16:28:29 +0000
parents f65c82141aa9
children 470c8bd99dd6
files src/cargopacket.h src/order_base.h src/saveload/ai_sl.cpp src/saveload/animated_tile_sl.cpp src/saveload/autoreplace_sl.cpp src/saveload/cargopacket_sl.cpp src/saveload/cheat_sl.cpp src/saveload/company_sl.cpp src/saveload/depot_sl.cpp src/saveload/economy_sl.cpp src/saveload/engine_sl.cpp src/saveload/gamelog_sl.cpp src/saveload/group_sl.cpp src/saveload/industry_sl.cpp src/saveload/labelmaps_sl.cpp src/saveload/map_sl.cpp src/saveload/misc_sl.cpp src/saveload/newgrf_sl.cpp src/saveload/order_sl.cpp src/saveload/saveload.cpp src/saveload/saveload.h src/saveload/signs_sl.cpp src/saveload/station_sl.cpp src/saveload/strings_sl.cpp src/saveload/subsidy_sl.cpp src/saveload/town_sl.cpp src/saveload/vehicle_sl.cpp src/saveload/waypoint_sl.cpp src/settings.cpp
diffstat 29 files changed, 222 insertions(+), 90 deletions(-) [+]
line wrap: on
line diff
--- a/src/cargopacket.h
+++ b/src/cargopacket.h
@@ -71,7 +71,7 @@
  */
 #define FOR_ALL_CARGOPACKETS(cp) FOR_ALL_CARGOPACKETS_FROM(cp, 0)
 
-extern void SaveLoad_STNS(Station *st);
+extern const struct SaveLoad *GetGoodsDesc();
 
 /**
  * Simple collection class for a list of cargo packets
@@ -99,7 +99,7 @@
 	uint days_in_transit; ///< Cache for the number of days in transit
 
 public:
-	friend void SaveLoad_STNS(Station *st);
+	friend const struct SaveLoad *GetGoodsDesc();
 
 	/** Create the cargo list */
 	CargoList() { this->InvalidateCache(); }
--- a/src/order_base.h
+++ b/src/order_base.h
@@ -260,8 +260,8 @@
 
 public:
 	/** Default constructor producing an invalid order list. */
-	OrderList()
-		: first(NULL), num_orders(INVALID_VEH_ORDER_ID), num_vehicles(0), first_shared(NULL),
+	OrderList(VehicleOrderID num_orders = INVALID_VEH_ORDER_ID)
+		: first(NULL), num_orders(num_orders), num_vehicles(0), first_shared(NULL),
 		  timetable_duration(0) { }
 
 	/** Create an order list with the given order chain for the given vehicle.
--- a/src/saveload/ai_sl.cpp
+++ b/src/saveload/ai_sl.cpp
@@ -102,5 +102,5 @@
 }
 
 extern const ChunkHandler _ai_chunk_handlers[] = {
-	{ 'AIPL', Save_AIPL, Load_AIPL, CH_ARRAY | CH_LAST},
+	{ 'AIPL', Save_AIPL, Load_AIPL, NULL, CH_ARRAY | CH_LAST},
 };
--- a/src/saveload/animated_tile_sl.cpp
+++ b/src/saveload/animated_tile_sl.cpp
@@ -52,5 +52,5 @@
  * the animated tile table.
  */
 extern const ChunkHandler _animated_tile_chunk_handlers[] = {
-	{ 'ANIT', Save_ANIT, Load_ANIT, CH_RIFF | CH_LAST},
+	{ 'ANIT', Save_ANIT, Load_ANIT, NULL, CH_RIFF | CH_LAST},
 };
--- a/src/saveload/autoreplace_sl.cpp
+++ b/src/saveload/autoreplace_sl.cpp
@@ -45,6 +45,15 @@
 	}
 }
 
+static void Ptrs_ERNW()
+{
+	EngineRenew *er;
+
+	FOR_ALL_ENGINE_RENEWS(er) {
+		SlObject(er, _engine_renew_desc);
+	}
+}
+
 extern const ChunkHandler _autoreplace_chunk_handlers[] = {
-	{ 'ERNW', Save_ERNW,     Load_ERNW,     CH_ARRAY | CH_LAST},
+	{ 'ERNW', Save_ERNW, Load_ERNW, Ptrs_ERNW, CH_ARRAY | CH_LAST},
 };
--- a/src/saveload/cargopacket_sl.cpp
+++ b/src/saveload/cargopacket_sl.cpp
@@ -40,5 +40,5 @@
 }
 
 extern const ChunkHandler _cargopacket_chunk_handlers[] = {
-	{ 'CAPA', Save_CAPA, Load_CAPA, CH_ARRAY | CH_LAST},
+	{ 'CAPA', Save_CAPA, Load_CAPA, NULL, CH_ARRAY | CH_LAST},
 };
--- a/src/saveload/cheat_sl.cpp
+++ b/src/saveload/cheat_sl.cpp
@@ -33,5 +33,5 @@
 }
 
 extern const ChunkHandler _cheat_chunk_handlers[] = {
-	{ 'CHTS', Save_CHTS,     Load_CHTS,     CH_RIFF | CH_LAST}
+	{ 'CHTS', Save_CHTS, Load_CHTS, NULL, CH_RIFF | CH_LAST},
 };
--- a/src/saveload/company_sl.cpp
+++ b/src/saveload/company_sl.cpp
@@ -277,6 +277,15 @@
 	}
 }
 
+static void Ptrs_PLYR()
+{
+	Company *c;
+	FOR_ALL_COMPANIES(c) {
+		SlObject(c, _company_desc);
+	}
+}
+
+
 extern const ChunkHandler _company_chunk_handlers[] = {
-	{ 'PLYR', Save_PLYR, Load_PLYR, CH_ARRAY | CH_LAST},
+	{ 'PLYR', Save_PLYR, Load_PLYR, Ptrs_PLYR, CH_ARRAY | CH_LAST},
 };
--- a/src/saveload/depot_sl.cpp
+++ b/src/saveload/depot_sl.cpp
@@ -35,5 +35,5 @@
 }
 
 extern const ChunkHandler _depot_chunk_handlers[] = {
-	{ 'DEPT', Save_DEPT, Load_DEPT, CH_ARRAY | CH_LAST},
+	{ 'DEPT', Save_DEPT, Load_DEPT, NULL, CH_ARRAY | CH_LAST},
 };
--- a/src/saveload/economy_sl.cpp
+++ b/src/saveload/economy_sl.cpp
@@ -52,7 +52,7 @@
 }
 
 extern const ChunkHandler _economy_chunk_handlers[] = {
-	{ 'PRIC', SaveLoad_PRIC, SaveLoad_PRIC, CH_RIFF | CH_AUTO_LENGTH},
-	{ 'CAPR', SaveLoad_CAPR, SaveLoad_CAPR, CH_RIFF | CH_AUTO_LENGTH},
-	{ 'ECMY', Save_ECMY,     Load_ECMY,     CH_RIFF | CH_LAST},
+	{ 'PRIC', SaveLoad_PRIC, SaveLoad_PRIC, NULL, CH_RIFF | CH_AUTO_LENGTH},
+	{ 'CAPR', SaveLoad_CAPR, SaveLoad_CAPR, NULL, CH_RIFF | CH_AUTO_LENGTH},
+	{ 'ECMY', Save_ECMY,     Load_ECMY,     NULL, CH_RIFF | CH_LAST},
 };
--- a/src/saveload/engine_sl.cpp
+++ b/src/saveload/engine_sl.cpp
@@ -143,7 +143,7 @@
 }
 
 extern const ChunkHandler _engine_chunk_handlers[] = {
-	{ 'EIDS', Save_EIDS,     Load_EIDS,     CH_ARRAY          },
-	{ 'ENGN', Save_ENGN,     Load_ENGN,     CH_ARRAY          },
-	{ 'ENGS', NULL,          Load_ENGS,     CH_RIFF | CH_LAST },
+	{ 'EIDS', Save_EIDS, Load_EIDS, NULL, CH_ARRAY          },
+	{ 'ENGN', Save_ENGN, Load_ENGN, NULL, CH_ARRAY          },
+	{ 'ENGS', NULL,      Load_ENGS, NULL, CH_RIFF | CH_LAST },
 };
--- a/src/saveload/gamelog_sl.cpp
+++ b/src/saveload/gamelog_sl.cpp
@@ -162,5 +162,5 @@
 
 
 extern const ChunkHandler _gamelog_chunk_handlers[] = {
-	{ 'GLOG', Save_GLOG, Load_GLOG, CH_RIFF | CH_LAST }
+	{ 'GLOG', Save_GLOG, Load_GLOG, NULL, CH_RIFF | CH_LAST }
 };
--- a/src/saveload/group_sl.cpp
+++ b/src/saveload/group_sl.cpp
@@ -39,5 +39,5 @@
 }
 
 extern const ChunkHandler _group_chunk_handlers[] = {
-	{ 'GRPS', Save_GRPS, Load_GRPS, CH_ARRAY | CH_LAST},
+	{ 'GRPS', Save_GRPS, Load_GRPS, NULL, CH_ARRAY | CH_LAST},
 };
--- a/src/saveload/industry_sl.cpp
+++ b/src/saveload/industry_sl.cpp
@@ -148,8 +148,17 @@
 	}
 }
 
+static void Ptrs_INDY()
+{
+	Industry *i;
+
+	FOR_ALL_INDUSTRIES(i) {
+		SlObject(i, _industry_desc);
+	}
+}
+
 extern const ChunkHandler _industry_chunk_handlers[] = {
-	{ 'INDY', Save_INDY, Load_INDY, CH_ARRAY},
-	{ 'IIDS', Save_IIDS, Load_IIDS, CH_ARRAY},
-	{ 'TIDS', Save_TIDS, Load_TIDS, CH_ARRAY | CH_LAST},
+	{ 'INDY', Save_INDY, Load_INDY, Ptrs_INDY, CH_ARRAY},
+	{ 'IIDS', Save_IIDS, Load_IIDS,      NULL, CH_ARRAY},
+	{ 'TIDS', Save_TIDS, Load_TIDS,      NULL, CH_ARRAY | CH_LAST},
 };
--- a/src/saveload/labelmaps_sl.cpp
+++ b/src/saveload/labelmaps_sl.cpp
@@ -120,6 +120,6 @@
 }
 
 extern const ChunkHandler _labelmaps_chunk_handlers[] = {
-	{ 'RAIL', Save_RAIL, Load_RAIL, CH_ARRAY | CH_LAST},
+	{ 'RAIL', Save_RAIL, Load_RAIL, NULL, CH_ARRAY | CH_LAST},
 };
 
--- a/src/saveload/map_sl.cpp
+++ b/src/saveload/map_sl.cpp
@@ -236,13 +236,13 @@
 }
 
 extern const ChunkHandler _map_chunk_handlers[] = {
-	{ 'MAPS', Save_MAPS,     Load_MAPS,     CH_RIFF },
-	{ 'MAPT', Save_MAPT,     Load_MAPT,     CH_RIFF },
-	{ 'MAPO', Save_MAP1,     Load_MAP1,     CH_RIFF },
-	{ 'MAP2', Save_MAP2,     Load_MAP2,     CH_RIFF },
-	{ 'M3LO', Save_MAP3,     Load_MAP3,     CH_RIFF },
-	{ 'M3HI', Save_MAP4,     Load_MAP4,     CH_RIFF },
-	{ 'MAP5', Save_MAP5,     Load_MAP5,     CH_RIFF },
-	{ 'MAPE', Save_MAP6,     Load_MAP6,     CH_RIFF },
-	{ 'MAP7', Save_MAP7,     Load_MAP7,     CH_RIFF | CH_LAST },
+	{ 'MAPS', Save_MAPS, Load_MAPS, NULL, CH_RIFF },
+	{ 'MAPT', Save_MAPT, Load_MAPT, NULL, CH_RIFF },
+	{ 'MAPO', Save_MAP1, Load_MAP1, NULL, CH_RIFF },
+	{ 'MAP2', Save_MAP2, Load_MAP2, NULL, CH_RIFF },
+	{ 'M3LO', Save_MAP3, Load_MAP3, NULL, CH_RIFF },
+	{ 'M3HI', Save_MAP4, Load_MAP4, NULL, CH_RIFF },
+	{ 'MAP5', Save_MAP5, Load_MAP5, NULL, CH_RIFF },
+	{ 'MAPE', Save_MAP6, Load_MAP6, NULL, CH_RIFF },
+	{ 'MAP7', Save_MAP7, Load_MAP7, NULL, CH_RIFF | CH_LAST },
 };
--- a/src/saveload/misc_sl.cpp
+++ b/src/saveload/misc_sl.cpp
@@ -102,6 +102,6 @@
 }
 
 extern const ChunkHandler _misc_chunk_handlers[] = {
-	{ 'DATE', SaveLoad_DATE, SaveLoad_DATE, CH_RIFF},
-	{ 'VIEW', SaveLoad_VIEW, SaveLoad_VIEW, CH_RIFF | CH_LAST},
+	{ 'DATE', SaveLoad_DATE, SaveLoad_DATE, NULL, CH_RIFF},
+	{ 'VIEW', SaveLoad_VIEW, SaveLoad_VIEW, NULL, CH_RIFF | CH_LAST},
 };
--- a/src/saveload/newgrf_sl.cpp
+++ b/src/saveload/newgrf_sl.cpp
@@ -48,5 +48,5 @@
 }
 
 extern const ChunkHandler _newgrf_chunk_handlers[] = {
-	{ 'NGRF', Save_NGRF, Load_NGRF, CH_ARRAY | CH_LAST }
+	{ 'NGRF', Save_NGRF, Load_NGRF, NULL, CH_ARRAY | CH_LAST }
 };
--- a/src/saveload/order_sl.cpp
+++ b/src/saveload/order_sl.cpp
@@ -121,7 +121,7 @@
 {
 	if (CheckSavegameVersionOldStyle(5, 2)) {
 		/* Version older than 5.2 did not have a ->next pointer. Convert them
-		    (in the old days, the orderlist was 5000 items big) */
+		 * (in the old days, the orderlist was 5000 items big) */
 		size_t len = SlGetFieldLength();
 		uint i;
 
@@ -170,6 +170,17 @@
 	}
 }
 
+static void Ptrs_ORDR()
+{
+	if (CheckSavegameVersionOldStyle(5, 2)) return;
+
+	Order *o;
+
+	FOR_ALL_ORDERS(o) {
+		SlObject(o, GetOrderDescription());
+	}
+}
+
 const SaveLoad *GetOrderListDescription()
 {
 	static const SaveLoad _orderlist_desc[] = {
@@ -195,12 +206,23 @@
 	int index;
 
 	while ((index = SlIterateArray()) != -1) {
-		OrderList *list = new (index) OrderList();
+		/* set num_orders to 0 so it's a valid OrderList */
+		OrderList *list = new (index) OrderList(0);
+		SlObject(list, GetOrderListDescription());
+	}
+
+}
+
+static void Ptrs_ORDL()
+{
+	OrderList *list;
+
+	FOR_ALL_ORDER_LISTS(list) {
 		SlObject(list, GetOrderListDescription());
 	}
 }
 
 extern const ChunkHandler _order_chunk_handlers[] = {
-	{ 'ORDR', Save_ORDR, Load_ORDR, CH_ARRAY},
-	{ 'ORDL', Save_ORDL, Load_ORDL, CH_ARRAY | CH_LAST},
+	{ 'ORDR', Save_ORDR, Load_ORDR, Ptrs_ORDR, CH_ARRAY},
+	{ 'ORDL', Save_ORDL, Load_ORDL, Ptrs_ORDL, CH_ARRAY | CH_LAST},
 };
--- a/src/saveload/saveload.cpp
+++ b/src/saveload/saveload.cpp
@@ -56,6 +56,7 @@
 enum SaveLoadAction {
 	SLA_LOAD, ///< loading
 	SLA_SAVE, ///< saving
+	SLA_PTRS, ///< fixing pointers
 };
 
 enum NeedLength {
@@ -564,6 +565,7 @@
 			WriteValue(ptr, conv, x);
 			break;
 		}
+		case SLA_PTRS: break;
 		default: NOT_REACHED();
 	}
 }
@@ -671,6 +673,7 @@
 			str_validate((char *)ptr, (char *)ptr + len);
 			break;
 		}
+		case SLA_PTRS: break;
 		default: NOT_REACHED();
 	}
 }
@@ -693,6 +696,8 @@
  */
 void SlArray(void *array, size_t length, VarType conv)
 {
+	if (_sl.action == SLA_PTRS) return;
+
 	/* Automatically calculate the length? */
 	if (_sl.need_length != NL_NONE) {
 		SlSetLength(SlCalcArrayLen(length, conv));
@@ -767,13 +772,14 @@
 		if (_sl.need_length == NL_CALCLENGTH) return;
 	}
 
-	std::list<void *> *l = (std::list<void *> *) list;
+	typedef std::list<void *> PtrList;
+	PtrList *l = (PtrList *)list;
 
 	switch (_sl.action) {
 		case SLA_SAVE: {
 			SlWriteUint32((uint32)l->size());
 
-			std::list<void *>::iterator iter;
+			PtrList::iterator iter;
 			for (iter = l->begin(); iter != l->end(); ++iter) {
 				void *ptr = *iter;
 				SlWriteUint32(ReferenceToInt(ptr, conv));
@@ -785,7 +791,18 @@
 
 			/* Load each reference and push to the end of the list */
 			for (uint i = 0; i < length; i++) {
-				void *ptr = IntToReference(CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32(), conv);
+				size_t data = CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32();
+				l->push_back((void *)data);
+			}
+			break;
+		}
+		case SLA_PTRS: {
+			PtrList temp = *l;
+
+			l->clear();
+			PtrList::iterator iter;
+			for (iter = temp.begin(); iter != temp.end(); ++iter) {
+				void *ptr = IntToReference((size_t)*iter, conv);
 				l->push_back(ptr);
 			}
 			break;
@@ -885,7 +902,10 @@
 							SlWriteUint32(ReferenceToInt(*(void **)ptr, (SLRefType)conv));
 							break;
 						case SLA_LOAD:
-							*(void **)ptr = IntToReference(CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32(), (SLRefType)conv);
+							*(size_t *)ptr = (size_t)(CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32());
+							break;
+						case SLA_PTRS:
+							*(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv);
 							break;
 						default: NOT_REACHED();
 					}
@@ -906,6 +926,7 @@
 			switch (_sl.action) {
 				case SLA_SAVE: SlWriteByte(sld->version_to); break;
 				case SLA_LOAD: *(byte *)ptr = sld->version_from; break;
+				case SLA_PTRS: break;
 				default: NOT_REACHED();
 			}
 			break;
@@ -1116,6 +1137,33 @@
 	}
 }
 
+/** Fix all pointers (convert index -> pointer) */
+static void SlFixPointers()
+{
+	const ChunkHandler *ch;
+	const ChunkHandler * const *chsc;
+
+	_sl.action = SLA_PTRS;
+
+	DEBUG(sl, 1, "Fixing pointers");
+
+	for (chsc = _sl.chs; (ch = *chsc++) != NULL;) {
+		while (true) {
+			if (ch->ptrs_proc != NULL) {
+				DEBUG(sl, 2, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
+				ch->ptrs_proc();
+			}
+			if (ch->flags & CH_LAST)
+				break;
+			ch++;
+		}
+	}
+
+	DEBUG(sl, 1, "All pointers fixed");
+
+	assert(_sl.action == SLA_PTRS);
+}
+
 /*******************************************
  ********** START OF LZO CODE **************
  *******************************************/
@@ -1424,6 +1472,8 @@
  */
 static uint ReferenceToInt(const void *obj, SLRefType rt)
 {
+	assert(_sl.action == SLA_SAVE);
+
 	if (obj == NULL) return 0;
 
 	switch (rt) {
@@ -1452,8 +1502,13 @@
  * @param rt SLRefType type of the object the pointer is sought of
  * @return Return the index converted to a pointer of any type
  */
+
+assert_compile(sizeof(size_t) <= sizeof(void *));
+
 static void *IntToReference(uint index, SLRefType rt)
 {
+	assert(_sl.action == SLA_PTRS);
+
 	/* After version 4.3 REF_VEHICLE_OLD is saved as REF_VEHICLE,
 	 * and should be loaded like that */
 	if (rt == REF_VEHICLE_OLD && !CheckSavegameVersionOldStyle(4, 4)) {
@@ -1461,59 +1516,50 @@
 	}
 
 	/* No need to look up NULL pointers, just return immediately */
-	if (rt != REF_VEHICLE_OLD && index == 0) {
-		return NULL;
-	}
+	if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return NULL;
 
-	index--; // correct for the NULL index
+	/* Correct index. Old vehicles were saved differently:
+	 * invalid vehicle was 0xFFFF, now we use 0x0000 for everything invalid. */
+	if (rt != REF_VEHICLE_OLD) index--;
 
 	switch (rt) {
 		case REF_ORDERLIST:
-			if (_OrderList_pool.AddBlockIfNeeded(index)) return OrderList::Get(index);
-			SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "OrderList index out of range");
+			if (OrderList::IsValidID(index)) return OrderList::Get(index);
+			SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid OrderList");
 
 		case REF_ORDER:
-			if (_Order_pool.AddBlockIfNeeded(index)) return Order::Get(index);
-			SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Order index out of range");
+			if (Order::IsValidID(index)) return Order::Get(index);
+			/* in old versions, invalid order was used to mark end of order list */
+			if (CheckSavegameVersionOldStyle(5, 2)) return NULL;
+			SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid Order");
 
+		case REF_VEHICLE_OLD:
 		case REF_VEHICLE:
-			if (_Vehicle_pool.AddBlockIfNeeded(index)) return Vehicle::Get(index);
-			SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Vehicle index out of range");
+			if (Vehicle::IsValidID(index)) return Vehicle::Get(index);
+			SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid Vehicle");
 
 		case REF_STATION:
-			if (_Station_pool.AddBlockIfNeeded(index)) return Station::Get(index);
-			SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Station index out of range");
+			if (Station::IsValidID(index)) return Station::Get(index);
+			SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid Station");
 
 		case REF_TOWN:
-			if (_Town_pool.AddBlockIfNeeded(index)) return Town::Get(index);
-			SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Town index out of range");
+			if (Town::IsValidID(index)) return Town::Get(index);
+			SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid Town");
 
 		case REF_ROADSTOPS:
-			if (_RoadStop_pool.AddBlockIfNeeded(index)) return RoadStop::Get(index);
-			SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "RoadStop index out of range");
+			if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
+			SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid RoadStop");
 
 		case REF_ENGINE_RENEWS:
-			if (_EngineRenew_pool.AddBlockIfNeeded(index)) return EngineRenew::Get(index);
-			SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "EngineRenew index out of range");
+			if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
+			SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid EngineRenew");
 
 		case REF_CARGO_PACKET:
-			if (_CargoPacket_pool.AddBlockIfNeeded(index)) return CargoPacket::Get(index);
-			SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "CargoPacket index out of range");
-
-		case REF_VEHICLE_OLD:
-			/* Old vehicles were saved differently:
-			 * invalid vehicle was 0xFFFF,
-			 * and the index was not - 1.. correct for this */
-			index++;
-			if (index == INVALID_VEHICLE) return NULL;
-
-			if (_Vehicle_pool.AddBlockIfNeeded(index)) return Vehicle::Get(index);
-			SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Vehicle index out of range");
+			if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index);
+			SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid CargoPacket");
 
 		default: NOT_REACHED();
 	}
-
-	return NULL;
 }
 
 /** The format for a reader/writer type of a savegame */
@@ -1852,6 +1898,7 @@
 			GamelogReset();
 
 			SlLoadChunks();
+			SlFixPointers();
 			fmt->uninit_read();
 			fclose(_sl.fh);
 
--- a/src/saveload/saveload.h
+++ b/src/saveload/saveload.h
@@ -52,6 +52,7 @@
 	uint32 id;
 	ChunkSaveLoadProc *save_proc;
 	ChunkSaveLoadProc *load_proc;
+	ChunkSaveLoadProc *ptrs_proc;
 	uint32 flags;
 };
 
--- a/src/saveload/signs_sl.cpp
+++ b/src/saveload/signs_sl.cpp
@@ -51,5 +51,5 @@
 }
 
 extern const ChunkHandler _sign_chunk_handlers[] = {
-	{ 'SIGN', Save_SIGN, Load_SIGN, CH_ARRAY | CH_LAST},
+	{ 'SIGN', Save_SIGN, Load_SIGN, NULL, CH_ARRAY | CH_LAST},
 };
--- a/src/saveload/station_sl.cpp
+++ b/src/saveload/station_sl.cpp
@@ -118,10 +118,9 @@
 	SLE_END()
 };
 
-
-void SaveLoad_STNS(Station *st)
+const SaveLoad *GetGoodsDesc()
 {
-	static const SaveLoad _goods_desc[] = {
+	static const SaveLoad goods_desc[] = {
 		SLEG_CONDVAR(            _waiting_acceptance, SLE_UINT16,                  0, 67),
 		 SLE_CONDVAR(GoodsEntry, acceptance_pickup,   SLE_UINT8,                  68, SL_MAX_VERSION),
 		SLE_CONDNULL(2,                                                           51, 67),
@@ -140,7 +139,12 @@
 		SLE_END()
 	};
 
+	return goods_desc;
+}
 
+
+static void SaveLoad_STNS(Station *st)
+{
 	SlObject(st, _station_desc);
 
 	_waiting_acceptance = 0;
@@ -148,7 +152,7 @@
 	uint num_cargo = CheckSavegameVersion(55) ? 12 : NUM_CARGO;
 	for (CargoID i = 0; i < num_cargo; i++) {
 		GoodsEntry *ge = &st->goods[i];
-		SlObject(ge, _goods_desc);
+		SlObject(ge, GetGoodsDesc());
 		if (CheckSavegameVersion(68)) {
 			SB(ge->acceptance_pickup, GoodsEntry::ACCEPTANCE, 1, HasBit(_waiting_acceptance, 15));
 			if (GB(_waiting_acceptance, 0, 12) != 0) {
@@ -197,6 +201,21 @@
 	}
 }
 
+void Ptrs_STNS()
+{
+	Station *st;
+	FOR_ALL_STATIONS(st) {
+		if (!CheckSavegameVersion(68)) {
+			for (CargoID i = 0; i < NUM_CARGO; i++) {
+				GoodsEntry *ge = &st->goods[i];
+				SlObject(ge, GetGoodsDesc());
+			}
+		}
+		SlObject(st, _station_desc);
+	}
+}
+
+
 static void Save_ROADSTOP()
 {
 	RoadStop *rs;
@@ -218,7 +237,15 @@
 	}
 }
 
+static void Ptrs_ROADSTOP()
+{
+	RoadStop *rs;
+	FOR_ALL_ROADSTOPS(rs) {
+		SlObject(rs, _roadstop_desc);
+	}
+}
+
 extern const ChunkHandler _station_chunk_handlers[] = {
-	{ 'STNS', Save_STNS,      Load_STNS,      CH_ARRAY },
-	{ 'ROAD', Save_ROADSTOP,  Load_ROADSTOP,  CH_ARRAY | CH_LAST},
+	{ 'STNS', Save_STNS,     Load_STNS,     Ptrs_STNS,     CH_ARRAY },
+	{ 'ROAD', Save_ROADSTOP, Load_ROADSTOP, Ptrs_ROADSTOP, CH_ARRAY | CH_LAST},
 };
--- a/src/saveload/strings_sl.cpp
+++ b/src/saveload/strings_sl.cpp
@@ -119,5 +119,5 @@
 }
 
 extern const ChunkHandler _name_chunk_handlers[] = {
-	{ 'NAME', NULL, Load_NAME, CH_ARRAY | CH_LAST},
+	{ 'NAME', NULL, Load_NAME, NULL, CH_ARRAY | CH_LAST},
 };
--- a/src/saveload/subsidy_sl.cpp
+++ b/src/saveload/subsidy_sl.cpp
@@ -39,5 +39,5 @@
 }
 
 extern const ChunkHandler _subsidy_chunk_handlers[] = {
-	{ 'SUBS', Save_SUBS,     Load_SUBS,     CH_ARRAY | CH_LAST},
+	{ 'SUBS', Save_SUBS, Load_SUBS, NULL, CH_ARRAY | CH_LAST},
 };
--- a/src/saveload/town_sl.cpp
+++ b/src/saveload/town_sl.cpp
@@ -192,6 +192,6 @@
 }
 
 extern const ChunkHandler _town_chunk_handlers[] = {
-	{ 'HIDS', Save_HOUSEIDS, Load_HOUSEIDS, CH_ARRAY },
-	{ 'CITY', Save_TOWN,     Load_TOWN,     CH_ARRAY | CH_LAST},
+	{ 'HIDS', Save_HOUSEIDS, Load_HOUSEIDS, NULL, CH_ARRAY },
+	{ 'CITY', Save_TOWN,     Load_TOWN,     NULL, CH_ARRAY | CH_LAST},
 };
--- a/src/saveload/vehicle_sl.cpp
+++ b/src/saveload/vehicle_sl.cpp
@@ -732,6 +732,14 @@
 	}
 }
 
+void Ptrs_VEHS()
+{
+	Vehicle *v;
+	FOR_ALL_VEHICLES(v) {
+		SlObject(v, GetVehicleDescription(v->type));
+	}
+}
+
 extern const ChunkHandler _veh_chunk_handlers[] = {
-	{ 'VEHS', Save_VEHS, Load_VEHS, CH_SPARSE_ARRAY | CH_LAST},
+	{ 'VEHS', Save_VEHS, Load_VEHS, Ptrs_VEHS, CH_SPARSE_ARRAY | CH_LAST},
 };
--- a/src/saveload/waypoint_sl.cpp
+++ b/src/saveload/waypoint_sl.cpp
@@ -92,5 +92,5 @@
 }
 
 extern const ChunkHandler _waypoint_chunk_handlers[] = {
-	{ 'CHKP', Save_WAYP, Load_WAYP, CH_ARRAY | CH_LAST},
+	{ 'CHKP', Save_WAYP, Load_WAYP, NULL, CH_ARRAY | CH_LAST},
 };
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -1704,8 +1704,8 @@
 }
 
 extern const ChunkHandler _setting_chunk_handlers[] = {
-	{ 'OPTS', NULL,      Load_OPTS, CH_RIFF},
-	{ 'PATS', Save_PATS, Load_PATS, CH_RIFF | CH_LAST},
+	{ 'OPTS', NULL,      Load_OPTS, NULL, CH_RIFF},
+	{ 'PATS', Save_PATS, Load_PATS, NULL, CH_RIFF | CH_LAST},
 };
 
 static bool IsSignedVarMemType(VarType vt)