Changeset - r25693:311303f64840
[Not reviewed]
master
0 7 0
Patric Stout - 3 years ago 2021-06-06 21:23:12
truebrain@openttd.org
Change: store length of SL_STRUCTLIST in the savegame

This wasn't consistently done, and often variables were used that
were read by an earlier blob. By moving it next to the struct
itself, the code becomes a bit more self-contained and easier to
read.

Additionally, this allows for external tooling to know how many
structs to expect, instead of having to know where to find the
length-field or a hard-coded value that can change at any moment.
7 files changed with 156 insertions and 42 deletions:
0 comments (0 inline, 0 general)
src/saveload/company_sl.cpp
Show inline comments
 
@@ -372,8 +372,19 @@ public:
 

	
 
class SlCompanyOldEconomy : public SlCompanyEconomy {
 
public:
 
	void GenericSaveLoad(CompanyProperties *c) const
 
	void Save(CompanyProperties *c) const override
 
	{
 
		SlSetStructListLength(c->num_valid_stat_ent);
 
		for (int i = 0; i < c->num_valid_stat_ent; i++) {
 
			SlObject(&c->old_economy[i], this->GetDescription());
 
		}
 
	}
 

	
 
	void Load(CompanyProperties *c) const override
 
	{
 
		if (!IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) {
 
			c->num_valid_stat_ent = (uint8)SlGetStructListLength(UINT8_MAX);
 
		}
 
		if (c->num_valid_stat_ent > lengthof(c->old_economy)) SlErrorCorrupt("Too many old economy entries");
 

	
 
		for (int i = 0; i < c->num_valid_stat_ent; i++) {
 
@@ -381,10 +392,7 @@ public:
 
		}
 
	}
 

	
 
	void Save(CompanyProperties *c) const override { this->GenericSaveLoad(c); }
 
	void Load(CompanyProperties *c) const override { this->GenericSaveLoad(c); }
 
	void LoadCheck(CompanyProperties *c) const override { this->GenericSaveLoad(c); }
 
	void FixPointers(CompanyProperties *c) const override { this->GenericSaveLoad(c); }
 
	void LoadCheck(CompanyProperties *c) const override { this->Load(c); }
 
};
 

	
 
class SlCompanyLiveries : public DefaultSaveLoadHandler<SlCompanyLiveries, CompanyProperties> {
 
@@ -395,12 +403,33 @@ public:
 
		SLE_CONDVAR(Livery, colour2, SLE_UINT8, SLV_34, SL_MAX_VERSION),
 
	};
 

	
 
	void GenericSaveLoad(CompanyProperties *c) const
 
	/**
 
	 * Get the number of liveries used by this savegame version.
 
	 * @return The number of liveries used by this savegame version.
 
	 */
 
	size_t GetNumLiveries() const
 
	{
 
		int num_liveries = IsSavegameVersionBefore(SLV_63) ? LS_END - 4 : (IsSavegameVersionBefore(SLV_85) ? LS_END - 2: LS_END);
 
		if (IsSavegameVersionBefore(SLV_63)) return LS_END - 4;
 
		if (IsSavegameVersionBefore(SLV_85)) return LS_END - 2;
 
		if (IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) return LS_END;
 
		/* Read from the savegame how long the list is. */
 
		return SlGetStructListLength(LS_END);
 
	}
 

	
 
	void Save(CompanyProperties *c) const override
 
	{
 
		SlSetStructListLength(LS_END);
 
		for (int i = 0; i < LS_END; i++) {
 
			SlObject(&c->livery[i], this->GetDescription());
 
		}
 
	}
 

	
 
	void Load(CompanyProperties *c) const override
 
	{
 
		size_t num_liveries = this->GetNumLiveries();
 
		bool update_in_use = IsSavegameVersionBefore(SLV_GROUP_LIVERIES);
 

	
 
		for (int i = 0; i < num_liveries; i++) {
 
		for (size_t i = 0; i < num_liveries; i++) {
 
			SlObject(&c->livery[i], this->GetDescription());
 
			if (update_in_use && i != LS_DEFAULT) {
 
				if (c->livery[i].in_use == 0) {
 
@@ -426,10 +455,7 @@ public:
 
		}
 
	}
 

	
 
	void Save(CompanyProperties *c) const override { this->GenericSaveLoad(c); }
 
	void Load(CompanyProperties *c) const override { this->GenericSaveLoad(c); }
 
	void LoadCheck(CompanyProperties *c) const override { this->GenericSaveLoad(c); }
 
	void FixPointers(CompanyProperties *c) const override { this->GenericSaveLoad(c); }
 
	void LoadCheck(CompanyProperties *c) const override { this->Load(c); }
 
};
 

	
 
/* Save/load of companies */
 
@@ -467,7 +493,7 @@ static const SaveLoad _company_desc[] = 
 

	
 
	    SLE_ARR(CompanyProperties, share_owners,          SLE_UINT8, 4),
 

	
 
	    SLE_VAR(CompanyProperties, num_valid_stat_ent,    SLE_UINT8),
 
	SLE_CONDVAR(CompanyProperties, num_valid_stat_ent,    SLE_UINT8,                   SL_MIN_VERSION, SLV_SAVELOAD_LIST_LENGTH),
 

	
 
	    SLE_VAR(CompanyProperties, months_of_bankruptcy,  SLE_UINT8),
 
	SLE_CONDVAR(CompanyProperties, bankrupt_asked,        SLE_FILE_U8  | SLE_VAR_U16,  SL_MIN_VERSION, SLV_104),
src/saveload/game_sl.cpp
Show inline comments
 
@@ -121,6 +121,8 @@ public:
 

	
 
	void Save(LanguageStrings *ls) const override
 
	{
 
		SlSetStructListLength(ls->lines.size());
 

	
 
		for (const auto &string : ls->lines) {
 
			_game_saveload_string = string;
 
			SlObject(nullptr, this->GetDescription());
 
@@ -129,7 +131,9 @@ public:
 

	
 
	void Load(LanguageStrings *ls) const override
 
	{
 
		for (uint32 i = 0; i < _game_saveload_strings; i++) {
 
		uint32 length = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? _game_saveload_strings : (uint32)SlGetStructListLength(UINT32_MAX);
 

	
 
		for (uint32 i = 0; i < length; i++) {
 
			SlObject(nullptr, this->GetDescription());
 
			ls->lines.emplace_back(_game_saveload_string);
 
		}
 
@@ -138,7 +142,7 @@ public:
 

	
 
static const SaveLoad _game_language_desc[] = {
 
	SLE_SSTR(LanguageStrings, language, SLE_STR),
 
	SLEG_VAR(_game_saveload_strings, SLE_UINT32),
 
	SLEG_CONDVAR(_game_saveload_strings, SLE_UINT32, SL_MIN_VERSION, SLV_SAVELOAD_LIST_LENGTH),
 
	SLEG_STRUCTLIST(SlGameLanguageString),
 
};
 

	
 
@@ -170,9 +174,7 @@ static void Save_GSTR()
 

	
 
	for (uint i = 0; i < _current_data->raw_strings.size(); i++) {
 
		SlSetArrayIndex(i);
 
		LanguageStrings *ls = &_current_data->raw_strings[i];
 
		_game_saveload_strings = (uint32)ls->lines.size();
 
		SlObject(ls, _game_language_desc);
 
		SlObject(&_current_data->raw_strings[i], _game_language_desc);
 
	}
 
}
 

	
src/saveload/linkgraph_sl.cpp
Show inline comments
 
@@ -37,6 +37,12 @@ public:
 

	
 
	void Save(Node *bn) const override
 
	{
 
		uint16 size = 0;
 
		for (NodeID to = _linkgraph_from; to != INVALID_NODE; to = _linkgraph->edges[_linkgraph_from][to].next_edge) {
 
			size++;
 
		}
 

	
 
		SlSetStructListLength(size);
 
		for (NodeID to = _linkgraph_from; to != INVALID_NODE; to = _linkgraph->edges[_linkgraph_from][to].next_edge) {
 
			SlObject(&_linkgraph->edges[_linkgraph_from][to], this->GetDescription());
 
		}
 
@@ -54,11 +60,18 @@ public:
 
			return;
 
		}
 

	
 
		size_t used_size = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? max_size : SlGetStructListLength(UINT16_MAX);
 

	
 
		/* ... but as that wasted a lot of space we save a sparse matrix now. */
 
		for (NodeID to = _linkgraph_from; to != INVALID_NODE; to = _linkgraph->edges[_linkgraph_from][to].next_edge) {
 
			if (used_size == 0) SlErrorCorrupt("Link graph structure overflow");
 
			used_size--;
 

	
 
			if (to >= max_size) SlErrorCorrupt("Link graph structure overflow");
 
			SlObject(&_linkgraph->edges[_linkgraph_from][to], this->GetDescription());
 
		}
 

	
 
		if (!IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) && used_size > 0) SlErrorCorrupt("Corrupted link graph");
 
	}
 
};
 

	
 
@@ -77,6 +90,7 @@ public:
 
	{
 
		_linkgraph = lg;
 

	
 
		SlSetStructListLength(lg->Size());
 
		for (NodeID from = 0; from < lg->Size(); ++from) {
 
			_linkgraph_from = from;
 
			SlObject(&lg->nodes[from], this->GetDescription());
 
@@ -87,8 +101,9 @@ public:
 
	{
 
		_linkgraph = lg;
 

	
 
		lg->Init(_num_nodes);
 
		for (NodeID from = 0; from < _num_nodes; ++from) {
 
		uint16 length = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? _num_nodes : (uint16)SlGetStructListLength(UINT16_MAX);
 
		lg->Init(length);
 
		for (NodeID from = 0; from < length; ++from) {
 
			_linkgraph_from = from;
 
			SlObject(&lg->nodes[from], this->GetDescription());
 
		}
 
@@ -103,7 +118,7 @@ SaveLoadTable GetLinkGraphDesc()
 
{
 
	static const SaveLoad link_graph_desc[] = {
 
		 SLE_VAR(LinkGraph, last_compression, SLE_INT32),
 
		SLEG_VAR(_num_nodes,                  SLE_UINT16),
 
		SLEG_CONDVAR(_num_nodes,              SLE_UINT16, SL_MIN_VERSION, SLV_SAVELOAD_LIST_LENGTH),
 
		 SLE_VAR(LinkGraph, cargo,            SLE_UINT8),
 
		SLEG_STRUCTLIST(SlLinkgraphNode),
 
	};
 
@@ -227,8 +242,6 @@ void AfterLoadLinkGraphs()
 
static void Save_LGRP()
 
{
 
	for (LinkGraph *lg : LinkGraph::Iterate()) {
 
		_num_nodes = lg->Size();
 

	
 
		SlSetArrayIndex(lg->index);
 
		SlObject(lg, GetLinkGraphDesc());
 
	}
 
@@ -252,8 +265,6 @@ static void Load_LGRP()
 
static void Save_LGRJ()
 
{
 
	for (LinkGraphJob *lgj : LinkGraphJob::Iterate()) {
 
		_num_nodes = lgj->Size();
 

	
 
		SlSetArrayIndex(lgj->index);
 
		SlObject(lgj, GetLinkGraphJobDesc());
 
	}
src/saveload/saveload.cpp
Show inline comments
 
@@ -1590,6 +1590,34 @@ static bool SlObjectMember(void *object,
 
}
 

	
 
/**
 
 * Set the length of this list.
 
 * @param The length of the list.
 
 */
 
void SlSetStructListLength(size_t length)
 
{
 
	/* Automatically calculate the length? */
 
	if (_sl.need_length != NL_NONE) {
 
		SlSetLength(SlGetArrayLength(length));
 
		if (_sl.need_length == NL_CALCLENGTH) return;
 
	}
 

	
 
	SlWriteArrayLength(length);
 
}
 

	
 
/**
 
 * Get the length of this list; if it exceeds the limit, error out.
 
 * @param limit The maximum size the list can be.
 
 * @return The length of the list.
 
 */
 
size_t SlGetStructListLength(size_t limit)
 
{
 
	size_t length = SlReadArrayLength();
 
	if (length > limit) SlErrorCorrupt("List exceeds storage size");
 

	
 
	return length;
 
}
 

	
 
/**
 
 * Main SaveLoad function.
 
 * @param object The object that is being saved or loaded.
 
 * @param slt The SaveLoad table with objects to save/load.
src/saveload/saveload.h
Show inline comments
 
@@ -326,9 +326,11 @@ enum SaveLoadVersion : uint16 {
 
	SLV_GS_INDUSTRY_CONTROL,                ///< 287  PR#7912 and PR#8115 GS industry control.
 
	SLV_VEH_MOTION_COUNTER,                 ///< 288  PR#8591 Desync safe motion counter
 
	SLV_INDUSTRY_TEXT,                      ///< 289  PR#8576 v1.11.0-RC1  Additional GS text for industries.
 

	
 
	SLV_MAPGEN_SETTINGS_REVAMP,             ///< 290  PR#8891 v1.11  Revamp of some mapgen settings (snow coverage, desert coverage, heightmap height, custom terrain type).
 
	SLV_GROUP_REPLACE_WAGON_REMOVAL,        ///< 291  PR#7441 Per-group wagon removal flag.
 
	SLV_CUSTOM_SUBSIDY_DURATION,            ///< 292  PR#9081 Configurable subsidy duration.
 
	SLV_SAVELOAD_LIST_LENGTH,               ///< 293  PR#9374 Consistency in list length with SL_STRUCT / SL_STRUCTLIST / SL_DEQUE / SL_REFLIST.
 

	
 
	SL_MAX_VERSION,                         ///< Highest possible saveload version
 
};
 
@@ -992,6 +994,9 @@ void WriteValue(void *ptr, VarType conv,
 
void SlSetArrayIndex(uint index);
 
int SlIterateArray();
 

	
 
void SlSetStructListLength(size_t length);
 
size_t SlGetStructListLength(size_t limit);
 

	
 
void SlAutolength(AutolengthProc *proc, void *arg);
 
size_t SlGetFieldLength();
 
void SlSetLength(size_t length);
src/saveload/station_sl.cpp
Show inline comments
 
@@ -157,14 +157,14 @@ static const SaveLoad _roadstop_desc[] =
 
};
 

	
 
static uint16 _waiting_acceptance;
 
static uint32 _num_flows;
 
static uint32 _old_num_flows;
 
static uint16 _cargo_source;
 
static uint32 _cargo_source_xy;
 
static uint8  _cargo_days;
 
static Money  _cargo_feeder_share;
 

	
 
std::list<CargoPacket *> _packets;
 
uint32 _num_dests;
 
uint32 _old_num_dests;
 

	
 
struct FlowSaveLoad {
 
	FlowSaveLoad() : source(0), via(0), share(0), restricted(false) {}
 
@@ -209,6 +209,7 @@ public:
 

	
 
	void Save(BaseStation *bst) const override
 
	{
 
		SlSetStructListLength(bst->num_specs);
 
		for (uint i = 0; i < bst->num_specs; i++) {
 
			SlObject(&bst->speclist[i], this->GetDescription());
 
		}
 
@@ -216,6 +217,10 @@ public:
 

	
 
	void Load(BaseStation *bst) const override
 
	{
 
		if (!IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) {
 
			bst->num_specs = (uint8)SlGetStructListLength(UINT8_MAX);
 
		}
 

	
 
		if (bst->num_specs != 0) {
 
			/* Allocate speclist memory when loading a game */
 
			bst->speclist = CallocT<StationSpecList>(bst->num_specs);
 
@@ -235,6 +240,7 @@ public:
 

	
 
	void Save(GoodsEntry *ge) const override
 
	{
 
		SlSetStructListLength(ge->cargo.Packets()->MapSize());
 
		for (StationCargoPacketMap::ConstMapIterator it(ge->cargo.Packets()->begin()); it != ge->cargo.Packets()->end(); ++it) {
 
			SlObject(const_cast<StationCargoPacketMap::value_type *>(&(*it)), this->GetDescription());
 
		}
 
@@ -242,8 +248,10 @@ public:
 

	
 
	void Load(GoodsEntry *ge) const override
 
	{
 
		size_t num_dests = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? _old_num_dests : SlGetStructListLength(UINT32_MAX);
 

	
 
		StationCargoPair pair;
 
		for (uint j = 0; j < _num_dests; ++j) {
 
		for (uint j = 0; j < num_dests; ++j) {
 
			SlObject(&pair, this->GetDescription());
 
			const_cast<StationCargoPacketMap &>(*(ge->cargo.Packets()))[pair.first].swap(pair.second);
 
			assert(pair.second.empty());
 
@@ -269,6 +277,12 @@ public:
 

	
 
	void Save(GoodsEntry *ge) const override
 
	{
 
		uint32 num_flows = 0;
 
		for (FlowStatMap::const_iterator it(ge->flows.begin()); it != ge->flows.end(); ++it) {
 
			num_flows += (uint32)it->second.GetShares()->size();
 
		}
 
		SlSetStructListLength(num_flows);
 

	
 
		for (FlowStatMap::const_iterator outer_it(ge->flows.begin()); outer_it != ge->flows.end(); ++outer_it) {
 
			const FlowStat::SharesMap *shares = outer_it->second.GetShares();
 
			uint32 sum_shares = 0;
 
@@ -287,10 +301,12 @@ public:
 

	
 
	void Load(GoodsEntry *ge) const override
 
	{
 
		size_t num_flows = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? _old_num_flows : SlGetStructListLength(UINT32_MAX);
 

	
 
		FlowSaveLoad flow;
 
		FlowStat *fs = nullptr;
 
		StationID prev_source = INVALID_STATION;
 
		for (uint32 j = 0; j < _num_flows; ++j) {
 
		for (uint32 j = 0; j < num_flows; ++j) {
 
			SlObject(&flow, this->GetDescription());
 
			if (fs == nullptr || prev_source != flow.source) {
 
				fs = &(ge->flows.insert(std::make_pair(flow.source, FlowStat(flow.via, flow.share, flow.restricted))).first->second);
 
@@ -330,11 +346,11 @@ public:
 
		SLEG_CONDVAR(            _cargo_feeder_share,  SLE_INT64,                  SLV_65, SLV_68),
 
		 SLE_CONDVAR(GoodsEntry, amount_fract,         SLE_UINT8,                 SLV_150, SL_MAX_VERSION),
 
		SLEG_CONDREFLIST(        _packets,             REF_CARGO_PACKET,           SLV_68, SLV_183),
 
		SLEG_CONDVAR(            _num_dests,           SLE_UINT32,                SLV_183, SL_MAX_VERSION),
 
		SLEG_CONDVAR(            _old_num_dests,       SLE_UINT32,                SLV_183, SLV_SAVELOAD_LIST_LENGTH),
 
		 SLE_CONDVAR(GoodsEntry, cargo.reserved_count, SLE_UINT,                  SLV_181, SL_MAX_VERSION),
 
		 SLE_CONDVAR(GoodsEntry, link_graph,           SLE_UINT16,                SLV_183, SL_MAX_VERSION),
 
		 SLE_CONDVAR(GoodsEntry, node,                 SLE_UINT16,                SLV_183, SL_MAX_VERSION),
 
		SLEG_CONDVAR(            _num_flows,           SLE_UINT32,                SLV_183, SL_MAX_VERSION),
 
		SLEG_CONDVAR(            _old_num_flows,       SLE_UINT32,                SLV_183, SLV_SAVELOAD_LIST_LENGTH),
 
		 SLE_CONDVAR(GoodsEntry, max_waiting_cargo,    SLE_UINT32,                SLV_183, SL_MAX_VERSION),
 
		SLEG_CONDSTRUCTLIST(SlStationFlow,                                        SLV_183, SL_MAX_VERSION),
 
		SLEG_CONDSTRUCTLIST(SlStationCargo,                                       SLV_183, SL_MAX_VERSION),
 
@@ -344,15 +360,26 @@ public:
 
	}
 
#endif
 

	
 
	/**
 
	 * Get the number of cargoes used by this savegame version.
 
	 * @return The number of cargoes used by this savegame version.
 
	 */
 
	size_t GetNumCargo() const
 
	{
 
		if (IsSavegameVersionBefore(SLV_55)) return 12;
 
		if (IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES)) return 32;
 
		if (IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) return NUM_CARGO;
 
		/* Read from the savegame how long the list is. */
 
		return SlGetStructListLength(NUM_CARGO);
 
	}
 

	
 
	void Save(BaseStation *bst) const override
 
	{
 
		Station *st = Station::From(bst);
 

	
 
		SlSetStructListLength(NUM_CARGO);
 

	
 
		for (CargoID i = 0; i < NUM_CARGO; i++) {
 
			_num_dests = (uint32)st->goods[i].cargo.Packets()->MapSize();
 
			_num_flows = 0;
 
			for (FlowStatMap::const_iterator it(st->goods[i].flows.begin()); it != st->goods[i].flows.end(); ++it) {
 
				_num_flows += (uint32)it->second.GetShares()->size();
 
			}
 
			SlObject(&st->goods[i], this->GetDescription());
 
		}
 
	}
 
@@ -369,7 +396,7 @@ public:
 
			memcpy(st->airport.psa->storage, _old_st_persistent_storage.storage, sizeof(_old_st_persistent_storage.storage));
 
		}
 

	
 
		uint num_cargo = IsSavegameVersionBefore(SLV_55) ? 12 : IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO;
 
		size_t num_cargo = this->GetNumCargo();
 
		for (CargoID i = 0; i < num_cargo; i++) {
 
			GoodsEntry *ge = &st->goods[i];
 
			SlObject(ge, this->GetDescription());
 
@@ -520,7 +547,7 @@ public:
 
		/* Used by newstations for graphic variations */
 
		    SLE_VAR(BaseStation, random_bits,            SLE_UINT16),
 
		    SLE_VAR(BaseStation, waiting_triggers,       SLE_UINT8),
 
		    SLE_VAR(BaseStation, num_specs,              SLE_UINT8),
 
		SLE_CONDVAR(BaseStation, num_specs,              SLE_UINT8,                   SL_MIN_VERSION, SLV_SAVELOAD_LIST_LENGTH),
 
	};
 

	
 
	void GenericSaveLoad(BaseStation *bst) const
 
@@ -626,7 +653,7 @@ static void Save_STNN()
 

	
 
static void Load_STNN()
 
{
 
	_num_flows = 0;
 
	_old_num_flows = 0;
 

	
 
	int index;
 
	while ((index = SlIterateArray()) != -1) {
src/saveload/town_sl.cpp
Show inline comments
 
@@ -122,8 +122,21 @@ public:
 
		SLE_CONDVAR(TransportedCargoStat<uint32>, new_act, SLE_UINT32, SLV_165, SL_MAX_VERSION),
 
	};
 

	
 
	/**
 
	 * Get the number of cargoes used by this savegame version.
 
	 * @return The number of cargoes used by this savegame version.
 
	 */
 
	size_t GetNumCargo() const
 
	{
 
		if (IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES)) return 32;
 
		if (IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) return NUM_CARGO;
 
		/* Read from the savegame how long the list is. */
 
		return SlGetStructListLength(NUM_CARGO);
 
	}
 

	
 
	void Save(Town *t) const override
 
	{
 
		SlSetStructListLength(NUM_CARGO);
 
		for (CargoID i = 0; i < NUM_CARGO; i++) {
 
			SlObject(&t->supplied[i], this->GetDescription());
 
		}
 
@@ -131,7 +144,7 @@ public:
 

	
 
	void Load(Town *t) const override
 
	{
 
		uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO;
 
		size_t num_cargo = this->GetNumCargo();
 
		for (CargoID i = 0; i < num_cargo; i++) {
 
			SlObject(&t->supplied[i], this->GetDescription());
 
		}
 
@@ -149,14 +162,16 @@ public:
 

	
 
	void Save(Town *t) const override
 
	{
 
		for (int i = TE_BEGIN; i < TE_END; i++) {
 
		SlSetStructListLength(NUM_TE);
 
		for (size_t i = TE_BEGIN; i < TE_END; i++) {
 
			SlObject(&t->received[i], this->GetDescription());
 
		}
 
	}
 

	
 
	void Load(Town *t) const override
 
	{
 
		for (int i = TE_BEGIN; i < TE_END; i++) {
 
		size_t length = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? (size_t)TE_END : SlGetStructListLength(TE_END);
 
		for (size_t i = 0; i < length; i++) {
 
			SlObject(&t->received[i], this->GetDescription());
 
		}
 
	}
0 comments (0 inline, 0 general)