changeset 17782:043b87d0dbec draft

(svn r22567) -Codechange: Store persistent storages inside a pool.
author terkhen <terkhen@openttd.org>
date Sun, 12 Jun 2011 20:47:45 +0000
parents dceca5355f39
children 1719e5568a82
files projects/openttd_vs100.vcxproj projects/openttd_vs100.vcxproj.filters projects/openttd_vs80.vcproj projects/openttd_vs90.vcproj source.list src/industry.h src/industry_cmd.cpp src/newgrf_airport.cpp src/newgrf_debug_gui.cpp src/newgrf_industries.cpp src/newgrf_industrytiles.cpp src/newgrf_storage.cpp src/newgrf_storage.h src/saveload/afterload.cpp src/saveload/industry_sl.cpp src/saveload/saveload.cpp src/saveload/saveload.h src/saveload/station_sl.cpp src/saveload/storage_sl.cpp src/station.cpp src/station_base.h src/station_cmd.cpp src/table/newgrf_debug_data.h
diffstat 23 files changed, 257 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/projects/openttd_vs100.vcxproj
+++ b/projects/openttd_vs100.vcxproj
@@ -740,6 +740,7 @@
     <ClInclude Include="..\src\saveload\saveload_internal.h" />
     <ClCompile Include="..\src\saveload\signs_sl.cpp" />
     <ClCompile Include="..\src\saveload\station_sl.cpp" />
+    <ClCompile Include="..\src\saveload\storage_sl.cpp" />
     <ClCompile Include="..\src\saveload\strings_sl.cpp" />
     <ClCompile Include="..\src\saveload\subsidy_sl.cpp" />
     <ClCompile Include="..\src\saveload\town_sl.cpp" />
--- a/projects/openttd_vs100.vcxproj.filters
+++ b/projects/openttd_vs100.vcxproj.filters
@@ -1440,6 +1440,9 @@
     <ClCompile Include="..\src\saveload\station_sl.cpp">
       <Filter>Save/Load handlers</Filter>
     </ClCompile>
+    <ClCompile Include="..\src\saveload\storage_sl.cpp">
+      <Filter>Save/Load handlers</Filter>
+    </ClCompile>
     <ClCompile Include="..\src\saveload\strings_sl.cpp">
       <Filter>Save/Load handlers</Filter>
     </ClCompile>
--- a/projects/openttd_vs80.vcproj
+++ b/projects/openttd_vs80.vcproj
@@ -2255,6 +2255,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\saveload\storage_sl.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\saveload\strings_sl.cpp"
 				>
 			</File>
--- a/projects/openttd_vs90.vcproj
+++ b/projects/openttd_vs90.vcproj
@@ -2252,6 +2252,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\saveload\storage_sl.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\saveload\strings_sl.cpp"
 				>
 			</File>
--- a/source.list
+++ b/source.list
@@ -498,6 +498,7 @@
 saveload/saveload_internal.h
 saveload/signs_sl.cpp
 saveload/station_sl.cpp
+saveload/storage_sl.cpp
 saveload/strings_sl.cpp
 saveload/subsidy_sl.cpp
 saveload/town_sl.cpp
--- a/src/industry.h
+++ b/src/industry.h
@@ -38,8 +38,6 @@
  * Defines the internal data of a functional industry.
  */
 struct Industry : IndustryPool::PoolItem<&_industry_pool> {
-	typedef PersistentStorageArray<int32, 16> PersistentStorage;
-
 	TileArea location;                  ///< Location of the industry
 	Town *town;                         ///< Nearest town
 	CargoID produced_cargo[2];          ///< 2 production cargo slots
@@ -72,7 +70,7 @@
 	byte random_triggers;               ///< Triggers for the random
 	uint16 random;                      ///< Random value used for randomisation of all kinds of things
 
-	PersistentStorage psa;              ///< Persistent storage for NewGRF industries.
+	PersistentStorage *psa;             ///< Persistent storage for NewGRF industries.
 
 	Industry(TileIndex tile = INVALID_TILE) : location(tile, 0, 0) {}
 	~Industry();
--- a/src/industry_cmd.cpp
+++ b/src/industry_cmd.cpp
@@ -167,6 +167,9 @@
 	/* don't let any disaster vehicle target invalid industry */
 	ReleaseDisastersTargetingIndustry(this->index);
 
+	/* Clear the persistent storage. */
+	delete this->psa;
+
 	DecIndustryTypeCount(this->type);
 
 	DeleteIndustryNews(this->index);
--- a/src/newgrf_airport.cpp
+++ b/src/newgrf_airport.cpp
@@ -149,7 +149,7 @@
 
 	switch (variable) {
 		/* Get a variable from the persistent storage */
-		case 0x7C: return st->airport.psa.GetValue(parameter);
+		case 0x7C: return (st->airport.psa != NULL) ? st->airport.psa->GetValue(parameter) : 0;
 
 		case 0xF0: return st->facilities;
 		case 0xFA: return Clamp(st->build_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 65535);
@@ -194,7 +194,17 @@
 {
 	Station *st = object->u.airport.st;
 	if (object->scope != VSG_SCOPE_SELF || st == NULL) return;
-	st->airport.psa.StoreValue(pos, value);
+
+	if (st->airport.psa == NULL) {
+		/* There is no need to create a storage if the value is zero. */
+		if (value == 0) return;
+
+		/* Create storage on first modification. */
+		uint32 grfid = (object->grffile != NULL) ? object->grffile->grfid : 0;
+		assert(PersistentStorage::CanAllocateItem());
+		st->airport.psa = new PersistentStorage(grfid);
+	}
+	st->airport.psa->StoreValue(pos, value);
 }
 
 static void NewAirportResolver(ResolverObject *res, TileIndex tile, Station *st, byte airport_id, byte layout)
--- a/src/newgrf_debug_gui.cpp
+++ b/src/newgrf_debug_gui.cpp
@@ -158,7 +158,7 @@
 
 	/**
 	 * Allows to know the size of the persistent storage.
-	 * @param index Unused.
+	 * @param index Index of the item.
 	 * @param grfid Unused.
 	 * @return Size of the persistent storage in indices.
 	 */
@@ -169,7 +169,7 @@
 
 	/**
 	 * Gets the first position of the array containing the persistent storage.
-	 * @param index Unused.
+	 * @param index Index of the item.
 	 * @param grfid Unused.
 	 * @return Pointer to the first position of the storage array or NULL if not present.
 	 */
@@ -368,11 +368,11 @@
 			}
 		}
 
-		uint psa_size = nih->GetPSASize(0, 0);
-		if (psa_size != 0) {
+		uint psa_size = nih->GetPSASize(index, 0);
+		int32 *psa = nih->GetPSAFirstPosition(index, 0);
+		if (psa_size != 0 && psa != NULL) {
 			this->DrawString(r, i++, "Persistent storage:");
 			assert(psa_size % 4 == 0);
-			int32 *psa = nih->GetPSAFirstPosition(0, 0);
 			for (uint j = 0; j < psa_size; j += 4, psa += 4) {
 				this->DrawString(r, i++, "  %i: %i %i %i %i", j, psa[0], psa[1], psa[2], psa[3]);
 			}
--- a/src/newgrf_industries.cpp
+++ b/src/newgrf_industries.cpp
@@ -283,7 +283,7 @@
 		}
 
 		/* Get a variable from the persistent storage */
-		case 0x7C: return industry->psa.GetValue(parameter);
+		case 0x7C: return (industry->psa != NULL) ? industry->psa->GetValue(parameter) : 0;
 
 		/* Industry structure access*/
 		case 0x80: return industry->location.tile;
@@ -386,7 +386,19 @@
 {
 	Industry *ind = object->u.industry.ind;
 	if (object->scope != VSG_SCOPE_SELF || ind->index == INVALID_INDUSTRY) return;
-	ind->psa.StoreValue(pos, value);
+
+	if (ind->psa == NULL) {
+		/* There is no need to create a storage if the value is zero. */
+		if (value == 0) return;
+
+		/* Create storage on first modification. */
+		const IndustrySpec *indsp = GetIndustrySpec(ind->type);
+		uint32 grfid = (indsp->grf_prop.grffile != NULL) ? indsp->grf_prop.grffile->grfid : 0;
+		assert(PersistentStorage::CanAllocateItem());
+		ind->psa = new PersistentStorage(grfid);
+	}
+
+	ind->psa->StoreValue(pos, value);
 }
 
 static void NewIndustryResolver(ResolverObject *res, TileIndex tile, Industry *indus, IndustryType type)
--- a/src/newgrf_industrytiles.cpp
+++ b/src/newgrf_industrytiles.cpp
@@ -158,7 +158,19 @@
 {
 	Industry *ind = object->u.industry.ind;
 	if (object->scope != VSG_SCOPE_PARENT || ind->index == INVALID_INDUSTRY) return;
-	ind->psa.StoreValue(pos, value);
+
+	if (ind->psa == NULL) {
+		/* There is no need to create a storage if the value is zero. */
+		if (value == 0) return;
+
+		/* Create storage on first modification. */
+		const IndustrySpec *indsp = GetIndustrySpec(ind->type);
+		uint32 grfid = (indsp->grf_prop.grffile != NULL) ? indsp->grf_prop.grffile->grfid : 0;
+		assert(PersistentStorage::CanAllocateItem());
+		ind->psa = new PersistentStorage(grfid);
+	}
+
+	ind->psa->StoreValue(pos, value);
 }
 
 static void NewIndustryTileResolver(ResolverObject *res, IndustryGfx gfx, TileIndex tile, Industry *indus)
--- a/src/newgrf_storage.cpp
+++ b/src/newgrf_storage.cpp
@@ -11,8 +11,12 @@
 
 #include "stdafx.h"
 #include "newgrf_storage.h"
+#include "core/pool_func.hpp"
 #include <set>
 
+PersistentStoragePool _persistent_storage_pool("PersistentStorage");
+INSTANTIATE_POOL_METHODS(PersistentStorage)
+
 /** The changed storage arrays */
 static std::set<BaseStorageArray*> _changed_storage_arrays;
 
--- a/src/newgrf_storage.h
+++ b/src/newgrf_storage.h
@@ -13,6 +13,7 @@
 #define NEWGRF_STORAGE_H
 
 #include "core/alloc_func.hpp"
+#include "core/pool_type.hpp"
 
 /**
  * Base class for all NewGRF storage arrays. Nothing fancy, only here
@@ -178,4 +179,40 @@
 void AddChangedStorage(BaseStorageArray *storage);
 void ClearStorageChanges(bool keep_changes);
 
+
+typedef PersistentStorageArray<int32, 16> OldPersistentStorage;
+
+typedef uint32 PersistentStorageID;
+
+struct PersistentStorage;
+typedef Pool<PersistentStorage, PersistentStorageID, 1, 0xFF000> PersistentStoragePool;
+
+extern PersistentStoragePool _persistent_storage_pool;
+
+/**
+ * Class for pooled persistent storage of data.
+ * On ClearChanges that data is always zero-ed.
+ */
+struct PersistentStorage : PersistentStorageArray<int32, 16>, PersistentStoragePool::PoolItem<&_persistent_storage_pool> {
+	uint32 grfid; ///< GRFID associated to this persistent storage. A value of zero means "default".
+
+	/** We don't want GCC to zero our struct! It already is zeroed and has an index! */
+	PersistentStorage(const uint32 new_grfid) : grfid(new_grfid)
+	{
+		this->prev_storage = NULL;
+		memset(this->storage, 0, sizeof(this->storage));
+	}
+
+	/** Free the memory used by the persistent storage. */
+	~PersistentStorage()
+	{
+		free(this->prev_storage);
+	}
+};
+
+assert_compile(cpp_lengthof(OldPersistentStorage, storage) == cpp_lengthof(PersistentStorage, storage));
+
+#define FOR_ALL_STORAGES_FROM(var, start) FOR_ALL_ITEMS_FROM(PersistentStorage, storage_index, var, start)
+#define FOR_ALL_STORAGES(var) FOR_ALL_STORAGES_FROM(var, 0)
+
 #endif /* NEWGRF_STORAGE_H */
--- a/src/saveload/afterload.cpp
+++ b/src/saveload/afterload.cpp
@@ -2595,6 +2595,58 @@
 		}
 	}
 
+	if (IsSavegameVersionBefore(161)) {
+		/* Before savegame version 161, persistent storages were not stored in a pool. */
+
+		if (!IsSavegameVersionBefore(76)) {
+			Industry *ind;
+			FOR_ALL_INDUSTRIES(ind) {
+				assert(ind->psa != NULL);
+
+				/* Check if the old storage was empty. */
+				bool is_empty = true;
+				for (uint i = 0; i < sizeof(ind->psa->storage); i++) {
+					if (ind->psa->GetValue(i) != 0) {
+						is_empty = false;
+						break;
+					}
+				}
+
+				if (!is_empty) {
+					ind->psa->grfid = _industry_mngr.GetGRFID(ind->type);
+				} else {
+					delete ind->psa;
+					ind->psa = NULL;
+				}
+			}
+		}
+
+		if (!IsSavegameVersionBefore(145)) {
+			Station *st;
+			FOR_ALL_STATIONS(st) {
+				if (!st->facilities & FACIL_AIRPORT) continue;
+				assert(st->airport.psa != NULL);
+
+				/* Check if the old storage was empty. */
+				bool is_empty = true;
+				for (uint i = 0; i < sizeof(st->airport.psa->storage); i++) {
+					if (st->airport.psa->GetValue(i) != 0) {
+						is_empty = false;
+						break;
+					}
+				}
+
+				if (!is_empty) {
+					st->airport.psa->grfid = _airport_mngr.GetGRFID(st->airport.type);
+				} else {
+					delete st->airport.psa;
+					st->airport.psa = NULL;
+
+				}
+			}
+		}
+	}
+
 	/* Road stops is 'only' updating some caches */
 	AfterLoadRoadStops();
 	AfterLoadLabelMaps();
--- a/src/saveload/industry_sl.cpp
+++ b/src/saveload/industry_sl.cpp
@@ -11,10 +11,13 @@
 
 #include "../stdafx.h"
 #include "../industry.h"
+#include "../newgrf.h"
 
 #include "saveload.h"
 #include "newgrf_sl.h"
 
+static OldPersistentStorage _old_ind_persistent_storage;
+
 static const SaveLoad _industry_desc[] = {
 	SLE_CONDVAR(Industry, location.tile,              SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
 	SLE_CONDVAR(Industry, location.tile,              SLE_UINT32,                  6, SL_MAX_VERSION),
@@ -50,7 +53,8 @@
 	SLE_CONDVAR(Industry, last_cargo_accepted_at,     SLE_INT32,                 70, SL_MAX_VERSION),
 	SLE_CONDVAR(Industry, selected_layout,            SLE_UINT8,                 73, SL_MAX_VERSION),
 
-	SLE_CONDARR(Industry, psa.storage,                SLE_UINT32, 16,            76, SL_MAX_VERSION),
+	SLEG_CONDARR(_old_ind_persistent_storage.storage, SLE_UINT32, 16,            76, 160),
+	SLE_CONDREF(Industry, psa,                        REF_STORAGE,              161, SL_MAX_VERSION),
 
 	SLE_CONDVAR(Industry, random_triggers,            SLE_UINT8,                 82, SL_MAX_VERSION),
 	SLE_CONDVAR(Industry, random,                     SLE_UINT16,                82, SL_MAX_VERSION),
@@ -90,6 +94,14 @@
 	while ((index = SlIterateArray()) != -1) {
 		Industry *i = new (index) Industry();
 		SlObject(i, _industry_desc);
+
+		/* Before savegame version 161, persistent storages were not stored in a pool. */
+		if (IsSavegameVersionBefore(161) && !IsSavegameVersionBefore(76)) {
+			/* Store the old persistent storage. The GRFID will be added later. */
+			assert(PersistentStorage::CanAllocateItem());
+			i->psa = new PersistentStorage(0);
+			memcpy(i->psa->storage, _old_ind_persistent_storage.storage, sizeof(i->psa->storage));
+		}
 		Industry::IncIndustryTypeCount(i->type);
 	}
 }
--- a/src/saveload/saveload.cpp
+++ b/src/saveload/saveload.cpp
@@ -225,8 +225,9 @@
  *  158   21933
  *  159   21962
  *  160   21974
+ *  161   22567
  */
-extern const uint16 SAVEGAME_VERSION = 160; ///< Current savegame version of OpenTTD.
+extern const uint16 SAVEGAME_VERSION = 161; ///< Current savegame version of OpenTTD.
 
 SavegameType _savegame_type; ///< type of savegame we are loading
 
@@ -404,6 +405,7 @@
 extern const ChunkHandler _labelmaps_chunk_handlers[];
 extern const ChunkHandler _airport_chunk_handlers[];
 extern const ChunkHandler _object_chunk_handlers[];
+extern const ChunkHandler _persistent_storage_chunk_handlers[];
 
 /** Array of all chunks in a savegame, \c NULL terminated. */
 static const ChunkHandler * const _chunk_handlers[] = {
@@ -434,6 +436,7 @@
 	_labelmaps_chunk_handlers,
 	_airport_chunk_handlers,
 	_object_chunk_handlers,
+	_persistent_storage_chunk_handlers,
 	NULL,
 };
 
@@ -1173,9 +1176,10 @@
 		case REF_TOWN:      return ((const     Town*)obj)->index + 1;
 		case REF_ORDER:     return ((const    Order*)obj)->index + 1;
 		case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
-		case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
-		case REF_CARGO_PACKET:  return ((const CargoPacket*)obj)->index + 1;
-		case REF_ORDERLIST:     return ((const   OrderList*)obj)->index + 1;
+		case REF_ENGINE_RENEWS: return ((const       EngineRenew*)obj)->index + 1;
+		case REF_CARGO_PACKET:  return ((const       CargoPacket*)obj)->index + 1;
+		case REF_ORDERLIST:     return ((const         OrderList*)obj)->index + 1;
+		case REF_STORAGE:       return ((const PersistentStorage*)obj)->index + 1;
 		default: NOT_REACHED();
 	}
 }
@@ -1245,6 +1249,10 @@
 			if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index);
 			SlErrorCorrupt("Referencing invalid CargoPacket");
 
+		case REF_STORAGE:
+			if (PersistentStorage::IsValidID(index)) return PersistentStorage::Get(index);
+			SlErrorCorrupt("Referencing invalid PersistentStorage");
+
 		default: NOT_REACHED();
 	}
 }
--- a/src/saveload/saveload.h
+++ b/src/saveload/saveload.h
@@ -88,6 +88,7 @@
 	REF_ENGINE_RENEWS = 6, ///< Load/save a reference to an engine renewal (autoreplace).
 	REF_CARGO_PACKET  = 7, ///< Load/save a reference to a cargo packet.
 	REF_ORDERLIST     = 8, ///< Load/save a reference to an orderlist.
+	REF_STORAGE       = 9, ///< Load/save a reference to a persistent storage.
 };
 
 /** Highest possible savegame version. */
--- a/src/saveload/station_sl.cpp
+++ b/src/saveload/station_sl.cpp
@@ -15,6 +15,7 @@
 #include "../roadstop_base.h"
 #include "../vehicle_base.h"
 #include "../newgrf_station.h"
+#include "../newgrf.h"
 
 #include "saveload.h"
 #include "table/strings.h"
@@ -344,6 +345,8 @@
 	      SLE_END()
 };
 
+static OldPersistentStorage _old_st_persistent_storage;
+
 static const SaveLoad _station_desc[] = {
 	SLE_WRITEBYTE(Station, facilities,                 FACIL_NONE),
 	SLE_ST_INCLUDE(),
@@ -362,7 +365,8 @@
 	  SLE_CONDVAR(Station, airport.layout,             SLE_UINT8,                 145, SL_MAX_VERSION),
 	      SLE_VAR(Station, airport.flags,              SLE_UINT64),
 	  SLE_CONDVAR(Station, airport.rotation,           SLE_UINT8,                 145, SL_MAX_VERSION),
-	  SLE_CONDARR(Station, airport.psa.storage,        SLE_UINT32, 16,            145, SL_MAX_VERSION),
+	 SLEG_CONDARR(_old_st_persistent_storage.storage,  SLE_UINT32, 16,            145, 160),
+	  SLE_CONDREF(Station, airport.psa,                REF_STORAGE,               161, SL_MAX_VERSION),
 
 	      SLE_VAR(Station, indtype,                    SLE_UINT8),
 
@@ -437,6 +441,15 @@
 
 		if (!waypoint) {
 			Station *st = Station::From(bst);
+
+			/* Before savegame version 161, persistent storages were not stored in a pool. */
+			if (IsSavegameVersionBefore(161) && !IsSavegameVersionBefore(145) && st->facilities & FACIL_AIRPORT) {
+				/* Store the old persistent storage. The GRFID will be added later. */
+				assert(PersistentStorage::CanAllocateItem());
+				st->airport.psa = new PersistentStorage(0);
+				memcpy(st->airport.psa->storage, _old_st_persistent_storage.storage, sizeof(st->airport.psa->storage));
+			}
+
 			for (CargoID i = 0; i < NUM_CARGO; i++) {
 				SlObject(&st->goods[i], GetGoodsDesc());
 			}
new file mode 100644
--- /dev/null
+++ b/src/saveload/storage_sl.cpp
@@ -0,0 +1,50 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
+ * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** @file persistent_storage_sl.cpp Code handling saving and loading of persistent storages. */
+
+#include "../stdafx.h"
+#include "../newgrf_storage.h"
+#include "saveload.h"
+
+/** Description of the data to save and load in #PersistentStorage. */
+static const SaveLoad _storage_desc[] = {
+	 SLE_CONDVAR(PersistentStorage, grfid,    SLE_UINT32,                  6, SL_MAX_VERSION),
+	 SLE_CONDARR(PersistentStorage, storage,  SLE_UINT32, 16,            161, SL_MAX_VERSION),
+	 SLE_END()
+};
+
+/** Load persistent storage data. */
+static void Load_PSAC()
+{
+	int index;
+
+	while ((index = SlIterateArray()) != -1) {
+		assert(PersistentStorage::CanAllocateItem());
+		PersistentStorage *ps = new (index) PersistentStorage(0);
+		SlObject(ps, _storage_desc);
+	}
+}
+
+/** Save persistent storage data. */
+static void Save_PSAC()
+{
+	PersistentStorage *ps;
+
+	/* Write the industries */
+	FOR_ALL_STORAGES(ps) {
+		SlSetArrayIndex(ps->index);
+		SlObject(ps, _storage_desc);
+	}
+}
+
+/** Chunk handler for persistent storages. */
+extern const ChunkHandler _persistent_storage_chunk_handlers[] = {
+	{ 'PSAC', Save_PSAC, Load_PSAC, NULL, NULL, CH_ARRAY | CH_LAST},
+};
--- a/src/station.cpp
+++ b/src/station.cpp
@@ -96,6 +96,10 @@
 		}
 	}
 
+	/* Clear the persistent storage. */
+	delete this->airport.psa;
+
+
 	InvalidateWindowData(WC_STATION_LIST, this->owner, 0);
 
 	DeleteWindowById(WC_STATION_VIEW, index);
--- a/src/station_base.h
+++ b/src/station_base.h
@@ -56,15 +56,14 @@
 
 /** All airport-related information. Only valid if tile != INVALID_TILE. */
 struct Airport : public TileArea {
-	typedef PersistentStorageArray<int32, 16> PersistentStorage;
-
 	Airport() : TileArea(INVALID_TILE, 0, 0) {}
 
 	uint64 flags;       ///< stores which blocks on the airport are taken. was 16 bit earlier on, then 32
 	byte type;          ///< Type of this airport, @see AirportTypes.
 	byte layout;        ///< Airport layout number.
 	Direction rotation; ///< How this airport is rotated.
-	PersistentStorage psa; ///< Persistent storage for NewGRF airports
+
+	PersistentStorage *psa; ///< Persistent storage for NewGRF airports.
 
 	/**
 	 * Get the AirportSpec that from the airport type of this airport. If there
--- a/src/station_cmd.cpp
+++ b/src/station_cmd.cpp
@@ -2191,7 +2191,6 @@
 		st->airport.layout = layout;
 		st->airport.flags = 0;
 		st->airport.rotation = rotation;
-		st->airport.psa.ResetToZero();
 
 		st->rect.BeforeAddRect(tile, w, h, StationRect::ADD_TRY);
 
@@ -2271,6 +2270,9 @@
 	}
 
 	if (flags & DC_EXEC) {
+		/* Clear the persistent storage. */
+		delete st->airport.psa;
+
 		const AirportSpec *as = st->airport.GetSpec();
 		for (uint i = 0; i < st->airport.GetNumHangars(); ++i) {
 			DeleteWindowById(
@@ -2288,7 +2290,6 @@
 
 		st->airport.Clear();
 		st->facilities &= ~FACIL_AIRPORT;
-		st->airport.psa.ResetToZero();
 
 		SetWindowWidgetDirty(WC_STATION_VIEW, st->index, SVW_PLANES);
 
--- a/src/table/newgrf_debug_data.h
+++ b/src/table/newgrf_debug_data.h
@@ -291,12 +291,13 @@
 	const void *GetSpec(uint index) const                { return GetIndustrySpec(Industry::Get(index)->type); }
 	void SetStringParameters(uint index) const           { this->SetSimpleStringParameters(STR_INDUSTRY_NAME, index); }
 	void Resolve(ResolverObject *ro, uint32 index) const { extern void GetIndustryResolver(ResolverObject *ro, uint index); GetIndustryResolver(ro, index); }
-	uint GetPSASize(uint index, uint32 grfid) const      { return cpp_lengthof(Industry, psa.storage); }
+	uint GetPSASize(uint index, uint32 grfid) const      { return cpp_lengthof(PersistentStorage, storage); }
 
 	int32 *GetPSAFirstPosition(uint index, uint32 grfid) const
 	{
-		const void *base = this->GetInstance(index);
-		return (int32*)((byte*)base + cpp_offsetof(Industry, psa.storage));
+		Industry *i = (Industry *)this->GetInstance(index);
+		if (i->psa == NULL) return NULL;
+		return (int32 *)(&i->psa->storage);
 	}
 };