diff --git a/src/linkgraph/linkgraph.h b/src/linkgraph/linkgraph.h index 748299fc00..250152bca9 100644 --- a/src/linkgraph/linkgraph.h +++ b/src/linkgraph/linkgraph.h @@ -534,7 +534,8 @@ protected: friend class LinkGraph::Node; friend const SaveLoad *GetLinkGraphDesc(); friend const SaveLoad *GetLinkGraphJobDesc(); - friend void SaveLoad_LinkGraph(LinkGraph &lg); + friend void Save_LinkGraph(LinkGraph &lg); + friend void Load_LinkGraph(LinkGraph &lg); CargoID cargo; ///< Cargo of this component's link graph. Date last_compression; ///< Last time the capacities and supplies were compressed. diff --git a/src/saveload/cargopacket_sl.cpp b/src/saveload/cargopacket_sl.cpp index 9d254e6e9a..f6eb2b2e93 100644 --- a/src/saveload/cargopacket_sl.cpp +++ b/src/saveload/cargopacket_sl.cpp @@ -119,11 +119,11 @@ const SaveLoad *GetCargoPacketDesc() */ static void Save_CAPA() { + std::vector filtered_packet_desc = SlFilterObject(GetCargoPacketDesc()); CargoPacket *cp; - FOR_ALL_CARGOPACKETS(cp) { SlSetArrayIndex(cp->index); - SlObject(cp, GetCargoPacketDesc()); + SlObjectSaveFiltered(cp, filtered_packet_desc.data()); } } @@ -132,11 +132,11 @@ static void Save_CAPA() */ static void Load_CAPA() { + std::vector filtered_packet_desc = SlFilterObject(GetCargoPacketDesc()); int index; - while ((index = SlIterateArray()) != -1) { CargoPacket *cp = new (index) CargoPacket(); - SlObject(cp, GetCargoPacketDesc()); + SlObjectLoadFiltered(cp, filtered_packet_desc.data()); } } diff --git a/src/saveload/linkgraph_sl.cpp b/src/saveload/linkgraph_sl.cpp index 272be7a0d3..ea62d47d21 100644 --- a/src/saveload/linkgraph_sl.cpp +++ b/src/saveload/linkgraph_sl.cpp @@ -138,25 +138,53 @@ static const SaveLoad _edge_desc[] = { SLE_END() }; +std::vector _filtered_node_desc; +std::vector _filtered_edge_desc; +std::vector _filtered_job_desc; + +static void FilterDescs() +{ + _filtered_node_desc = SlFilterObject(_node_desc); + _filtered_edge_desc = SlFilterObject(_edge_desc); + _filtered_job_desc = SlFilterObject(GetLinkGraphJobDesc()); +} + /** - * Save/load a link graph. + * Save a link graph. * @param lg Link graph to be saved or loaded. */ -void SaveLoad_LinkGraph(LinkGraph &lg) +void Save_LinkGraph(LinkGraph &lg) { uint size = lg.Size(); for (NodeID from = 0; from < size; ++from) { Node *node = &lg.nodes[from]; - SlObject(node, _node_desc); + SlObjectSaveFiltered(node, _filtered_node_desc.data()); + /* ... but as that wasted a lot of space we save a sparse matrix now. */ + for (NodeID to = from; to != INVALID_NODE; to = lg.edges[from][to].next_edge) { + SlObjectSaveFiltered(&lg.edges[from][to], _filtered_edge_desc.data()); + } + } +} + +/** + * Load a link graph. + * @param lg Link graph to be saved or loaded. + */ +void Load_LinkGraph(LinkGraph &lg) +{ + uint size = lg.Size(); + for (NodeID from = 0; from < size; ++from) { + Node *node = &lg.nodes[from]; + SlObjectLoadFiltered(node, _filtered_node_desc.data()); if (IsSavegameVersionBefore(SLV_191)) { /* We used to save the full matrix ... */ for (NodeID to = 0; to < size; ++to) { - SlObject(&lg.edges[from][to], _edge_desc); + SlObjectLoadFiltered(&lg.edges[from][to], _filtered_edge_desc.data()); } } else { /* ... but as that wasted a lot of space we save a sparse matrix now. */ for (NodeID to = from; to != INVALID_NODE; to = lg.edges[from][to].next_edge) { - SlObject(&lg.edges[from][to], _edge_desc); + SlObjectLoadFiltered(&lg.edges[from][to], _filtered_edge_desc.data()); } } } @@ -168,10 +196,10 @@ void SaveLoad_LinkGraph(LinkGraph &lg) */ static void DoSave_LGRJ(LinkGraphJob *lgj) { - SlObject(lgj, GetLinkGraphJobDesc()); + SlObjectSaveFiltered(lgj, _filtered_job_desc.data()); _num_nodes = lgj->Size(); - SlObject(const_cast(&lgj->Graph()), GetLinkGraphDesc()); - SaveLoad_LinkGraph(const_cast(lgj->Graph())); + SlObjectSaveFiltered(const_cast(&lgj->Graph()), GetLinkGraphDesc()); // GetLinkGraphDesc has no conditionals + Save_LinkGraph(const_cast(lgj->Graph())); } /** @@ -181,8 +209,8 @@ static void DoSave_LGRJ(LinkGraphJob *lgj) static void DoSave_LGRP(LinkGraph *lg) { _num_nodes = lg->Size(); - SlObject(lg, GetLinkGraphDesc()); - SaveLoad_LinkGraph(*lg); + SlObjectSaveFiltered(lg, GetLinkGraphDesc()); // GetLinkGraphDesc has no conditionals + Save_LinkGraph(*lg); } /** @@ -190,6 +218,7 @@ static void DoSave_LGRP(LinkGraph *lg) */ static void Load_LGRP() { + FilterDescs(); int index; while ((index = SlIterateArray()) != -1) { if (!LinkGraph::CanAllocateItem()) { @@ -197,9 +226,9 @@ static void Load_LGRP() NOT_REACHED(); } LinkGraph *lg = new (index) LinkGraph(); - SlObject(lg, GetLinkGraphDesc()); + SlObjectLoadFiltered(lg, GetLinkGraphDesc()); // GetLinkGraphDesc has no conditionals lg->Init(_num_nodes); - SaveLoad_LinkGraph(*lg); + Load_LinkGraph(*lg); } } @@ -208,6 +237,7 @@ static void Load_LGRP() */ static void Load_LGRJ() { + FilterDescs(); int index; while ((index = SlIterateArray()) != -1) { if (!LinkGraphJob::CanAllocateItem()) { @@ -215,14 +245,14 @@ static void Load_LGRJ() NOT_REACHED(); } LinkGraphJob *lgj = new (index) LinkGraphJob(); - SlObject(lgj, GetLinkGraphJobDesc()); + SlObjectLoadFiltered(lgj, _filtered_job_desc.data()); if (SlXvIsFeatureMissing(XSLFI_LINKGRAPH_DAY_SCALE)) { GetLinkGraphJobDayLengthScaleAfterLoad(lgj); } LinkGraph &lg = const_cast(lgj->Graph()); - SlObject(&lg, GetLinkGraphDesc()); + SlObjectLoadFiltered(&lg, GetLinkGraphDesc()); // GetLinkGraphDesc has no conditionals lg.Init(_num_nodes); - SaveLoad_LinkGraph(lg); + Load_LinkGraph(lg); } } @@ -267,6 +297,7 @@ void AfterLoadLinkGraphs() */ static void Save_LGRP() { + FilterDescs(); LinkGraph *lg; FOR_ALL_LINK_GRAPHS(lg) { SlSetArrayIndex(lg->index); @@ -279,6 +310,7 @@ static void Save_LGRP() */ static void Save_LGRJ() { + FilterDescs(); LinkGraphJob *lgj; FOR_ALL_LINK_GRAPH_JOBS(lgj) { SlSetArrayIndex(lgj->index); diff --git a/src/saveload/newgrf_sl.cpp b/src/saveload/newgrf_sl.cpp index 2f7dfb3568..dfa36356fb 100644 --- a/src/saveload/newgrf_sl.cpp +++ b/src/saveload/newgrf_sl.cpp @@ -33,7 +33,8 @@ void Save_NewGRFMapping(const OverrideManagerBase &mapping) { for (uint i = 0; i < mapping.GetMaxMapping(); i++) { SlSetArrayIndex(i); - SlObject(&mapping.mapping_ID[i], _newgrf_mapping_desc); + SlSetLength(4 + 1 + 1); + SlObjectSaveFiltered(&mapping.mapping_ID[i], _newgrf_mapping_desc); // _newgrf_mapping_desc has no conditionals } } @@ -51,8 +52,8 @@ void Load_NewGRFMapping(OverrideManagerBase &mapping) int index; while ((index = SlIterateArray()) != -1) { - if ((uint)index >= max_id) SlErrorCorrupt("Too many NewGRF entity mappings"); - SlObject(&mapping.mapping_ID[index], _newgrf_mapping_desc); + if (unlikely((uint)index >= max_id)) SlErrorCorrupt("Too many NewGRF entity mappings"); + SlObjectLoadFiltered(&mapping.mapping_ID[index], _newgrf_mapping_desc); // _newgrf_mapping_desc has no conditionals } } diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index acbfed22e8..57b70743b4 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -889,9 +889,10 @@ void WriteValue(void *ptr, VarType conv, int64 val) * @param ptr The object being filled/read * @param conv VarType type of the current element of the struct */ -static void SlSaveLoadConv(void *ptr, VarType conv) +template +static void SlSaveLoadConvGeneric(void *ptr, VarType conv) { - switch (_sl.action) { + switch (action) { case SLA_SAVE: { int64 x = ReadValue(ptr, conv); @@ -937,6 +938,23 @@ static void SlSaveLoadConv(void *ptr, VarType conv) } } +void SlSaveLoadConv(void *ptr, VarType conv) +{ + switch (_sl.action) { + case SLA_SAVE: + SlSaveLoadConvGeneric(ptr, conv); + return; + case SLA_LOAD_CHECK: + case SLA_LOAD: + SlSaveLoadConvGeneric(ptr, conv); + return; + case SLA_PTRS: + case SLA_NULL: + return; + default: NOT_REACHED(); + } +} + /** * Calculate the net length of a string. This is in almost all cases * just strlen(), but if the string is not properly terminated, we'll @@ -1679,12 +1697,96 @@ static bool IsVariableSizeRight(const SaveLoad *sld) #endif /* OTTD_ASSERT */ -bool SlObjectMember(void *ptr, const SaveLoad *sld) +void SlFilterObject(const SaveLoad *sld, std::vector &save); + +static void SlFilterObjectMember(const SaveLoad *sld, std::vector &save) { #ifdef OTTD_ASSERT assert(IsVariableSizeRight(sld)); #endif + switch (sld->cmd) { + case SL_VAR: + case SL_REF: + case SL_ARR: + case SL_STR: + case SL_LST: + case SL_PTRDEQ: + case SL_VEC: + case SL_DEQUE: + case SL_STDSTR: + case SL_VARVEC: + /* CONDITIONAL saveload types depend on the savegame version */ + if (!SlIsObjectValidInSavegame(sld)) return; + if (SlSkipVariableOnLoad(sld)) return; + + switch (_sl.action) { + case SLA_SAVE: + case SLA_LOAD_CHECK: + case SLA_LOAD: + break; + case SLA_PTRS: + case SLA_NULL: + switch (sld->cmd) { + case SL_REF: + case SL_LST: + case SL_PTRDEQ: + case SL_VEC: + break; + + /* non-ptr types do not require SLA_PTRS or SLA_NULL actions */ + default: + return; + } + break; + default: NOT_REACHED(); + } + + save.push_back(*sld); + break; + + /* SL_WRITEBYTE writes a value to the savegame to identify the type of an object. + * When loading, the value is read explictly with SlReadByte() to determine which + * object description to use. */ + case SL_WRITEBYTE: + if (_sl.action == SLA_SAVE) save.push_back(*sld); + break; + + /* SL_VEH_INCLUDE loads common code for vehicles */ + case SL_VEH_INCLUDE: + SlFilterObject(GetVehicleDescription(VEH_END), save); + break; + + case SL_ST_INCLUDE: + SlFilterObject(GetBaseStationDescription(), save); + break; + + default: NOT_REACHED(); + } +} + +void SlFilterObject(const SaveLoad *sld, std::vector &save) +{ + for (; sld->cmd != SL_END; sld++) { + SlFilterObjectMember(sld, save); + } +} + +std::vector SlFilterObject(const SaveLoad *sld) +{ + std::vector save; + SlFilterObject(sld, save); + save.push_back(SLE_END()); + return save; +} + +template +bool SlObjectMemberGeneric(void *ptr, const SaveLoad *sld) +{ +#ifdef OTTD_ASSERT + if (check_version) assert(IsVariableSizeRight(sld)); +#endif + VarType conv = GB(sld->conv, 0, 8); switch (sld->cmd) { case SL_VAR: @@ -1698,13 +1800,15 @@ bool SlObjectMember(void *ptr, const SaveLoad *sld) case SL_STDSTR: case SL_VARVEC: /* CONDITIONAL saveload types depend on the savegame version */ - if (!SlIsObjectValidInSavegame(sld)) return false; - if (SlSkipVariableOnLoad(sld)) return false; + if (check_version) { + if (!SlIsObjectValidInSavegame(sld)) return false; + if (SlSkipVariableOnLoad(sld)) return false; + } switch (sld->cmd) { - case SL_VAR: SlSaveLoadConv(ptr, conv); break; + case SL_VAR: SlSaveLoadConvGeneric(ptr, conv); break; case SL_REF: // Reference variable, translate - switch (_sl.action) { + switch (action) { case SLA_SAVE: SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv)); break; @@ -1747,7 +1851,7 @@ bool SlObjectMember(void *ptr, const SaveLoad *sld) * When loading, the value is read explictly with SlReadByte() to determine which * object description to use. */ case SL_WRITEBYTE: - switch (_sl.action) { + switch (action) { case SLA_SAVE: SlWriteByte(*(uint8 *)ptr); break; case SLA_LOAD_CHECK: case SLA_LOAD: @@ -1771,6 +1875,22 @@ bool SlObjectMember(void *ptr, const SaveLoad *sld) return true; } +bool SlObjectMember(void *ptr, const SaveLoad *sld) +{ + switch (_sl.action) { + case SLA_SAVE: + return SlObjectMemberGeneric(ptr, sld); + case SLA_LOAD_CHECK: + case SLA_LOAD: + return SlObjectMemberGeneric(ptr, sld); + case SLA_PTRS: + return SlObjectMemberGeneric(ptr, sld); + case SLA_NULL: + return SlObjectMemberGeneric(ptr, sld); + default: NOT_REACHED(); + } +} + /** * Main SaveLoad function. * @param object The object that is being saved or loaded @@ -1789,6 +1909,48 @@ void SlObject(void *object, const SaveLoad *sld) } } +template +void SlObjectIterateBase(void *object, const SaveLoad *sld) +{ + for (; sld->cmd != SL_END; sld++) { + void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld); + SlObjectMemberGeneric(ptr, sld); + } +} + +void SlObjectSaveFiltered(void *object, const SaveLoad *sld) +{ + if (_sl.need_length != NL_NONE) { + _sl.need_length = NL_NONE; + _sl.dumper->StartAutoLength(); + SlObjectIterateBase(object, sld); + auto result = _sl.dumper->StopAutoLength(); + _sl.need_length = NL_WANTLENGTH; + SlSetLength(result.second); + _sl.dumper->CopyBytes(result.first, result.second); + } else { + SlObjectIterateBase(object, sld); + } +} + +void SlObjectLoadFiltered(void *object, const SaveLoad *sld) +{ + SlObjectIterateBase(object, sld); +} + +void SlObjectPtrOrNullFiltered(void *object, const SaveLoad *sld) +{ + switch (_sl.action) { + case SLA_PTRS: + SlObjectIterateBase(object, sld); + return; + case SLA_NULL: + SlObjectIterateBase(object, sld); + return; + default: NOT_REACHED(); + } +} + /** * Save or Load (a list of) global variables * @param sldg The global variable that is being loaded or saved diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index 1dd052b3d9..c5fb6cdd45 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -17,6 +17,7 @@ #include "extended_ver_sl.h" #include +#include /** SaveLoad versions * Previous savegame versions, the trunk revision where they were @@ -1024,6 +1025,12 @@ void SlGlobList(const SaveLoadGlobVarList *sldg); void SlArray(void *array, size_t length, VarType conv); void SlObject(void *object, const SaveLoad *sld); bool SlObjectMember(void *object, const SaveLoad *sld); + +std::vector SlFilterObject(const SaveLoad *sld); +void SlObjectSaveFiltered(void *object, const SaveLoad *sld); +void SlObjectLoadFiltered(void *object, const SaveLoad *sld); +void SlObjectPtrOrNullFiltered(void *object, const SaveLoad *sld); + void NORETURN SlError(StringID string, const char *extra_msg = nullptr, bool already_malloced = false); void NORETURN SlErrorCorrupt(const char *msg, bool already_malloced = false); void NORETURN CDECL SlErrorFmt(StringID string, const char *msg, ...) WARN_FORMAT(2, 3); diff --git a/src/saveload/station_sl.cpp b/src/saveload/station_sl.cpp index 8b6248b985..29e3107daa 100644 --- a/src/saveload/station_sl.cpp +++ b/src/saveload/station_sl.cpp @@ -489,10 +489,31 @@ const SaveLoad *GetBaseStationDescription() return _base_station_desc; } +std::vector _filtered_station_desc; +std::vector _filtered_waypoint_desc; +std::vector _filtered_goods_desc; +std::vector _filtered_station_speclist_desc; + +static void SetupDescs_STNN() +{ + _filtered_station_desc = SlFilterObject(_station_desc); + _filtered_waypoint_desc = SlFilterObject(_waypoint_desc); + _filtered_goods_desc = SlFilterObject(GetGoodsDesc()); + _filtered_station_speclist_desc = SlFilterObject(_station_speclist_desc); +} + +std::vector _filtered_roadstop_desc; + +static void SetupDescs_ROADSTOP() +{ + _filtered_roadstop_desc = SlFilterObject(_roadstop_desc); +} + + static void RealSave_STNN(BaseStation *bst) { bool waypoint = (bst->facilities & FACIL_WAYPOINT) != 0; - SlObject(bst, waypoint ? _waypoint_desc : _station_desc); + SlObjectSaveFiltered(bst, waypoint ? _filtered_waypoint_desc.data() : _filtered_station_desc.data()); MemoryDumper *dumper = MemoryDumper::GetCurrent(); @@ -504,7 +525,7 @@ static void RealSave_STNN(BaseStation *bst) 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], GetGoodsDesc()); + SlObjectSaveFiltered(&st->goods[i], _filtered_goods_desc.data()); for (FlowStatMap::const_iterator outer_it(st->goods[i].flows.begin()); outer_it != st->goods[i].flows.end(); ++outer_it) { const FlowStat::SharesMap *shares = outer_it->second.GetShares(); uint32 sum_shares = 0; @@ -526,18 +547,20 @@ static void RealSave_STNN(BaseStation *bst) } } for (StationCargoPacketMap::ConstMapIterator it(st->goods[i].cargo.Packets()->begin()); it != st->goods[i].cargo.Packets()->end(); ++it) { - SlObject(const_cast(&(*it)), _cargo_list_desc); + SlObjectSaveFiltered(const_cast(&(*it)), _cargo_list_desc); // _cargo_list_desc has no conditionals } } } for (uint i = 0; i < bst->num_specs; i++) { - SlObject(&bst->speclist[i], _station_speclist_desc); + SlObjectSaveFiltered(&bst->speclist[i], _filtered_station_speclist_desc.data()); } } static void Save_STNN() { + SetupDescs_STNN(); + BaseStation *st; /* Write the stations */ FOR_ALL_BASE_STATIONS(st) { @@ -548,6 +571,8 @@ static void Save_STNN() static void Load_STNN() { + SetupDescs_STNN(); + _num_flows = 0; const uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO; @@ -558,7 +583,7 @@ static void Load_STNN() bool waypoint = (SlReadByte() & FACIL_WAYPOINT) != 0; BaseStation *bst = waypoint ? (BaseStation *)new (index) Waypoint() : new (index) Station(); - SlObject(bst, waypoint ? _waypoint_desc : _station_desc); + SlObjectLoadFiltered(bst, waypoint ? _filtered_waypoint_desc.data() : _filtered_station_desc.data()); if (!waypoint) { Station *st = Station::From(bst); @@ -572,7 +597,7 @@ static void Load_STNN() } for (CargoID i = 0; i < num_cargo; i++) { - SlObject(&st->goods[i], GetGoodsDesc()); + SlObjectLoadFiltered(&st->goods[i], _filtered_goods_desc.data()); FlowSaveLoad flow; FlowStat *fs = nullptr; StationID prev_source = INVALID_STATION; @@ -596,7 +621,7 @@ static void Load_STNN() } else { StationCargoPair pair; for (uint j = 0; j < _num_dests; ++j) { - SlObject(&pair, _cargo_list_desc); + SlObjectLoadFiltered(&pair, _cargo_list_desc); // _cargo_list_desc has no conditionals const_cast(*(st->goods[i].cargo.Packets()))[pair.first].swap(pair.second); assert(pair.second.empty()); } @@ -609,7 +634,7 @@ static void Load_STNN() /* Allocate speclist memory when loading a game */ bst->speclist = CallocT(bst->num_specs); for (uint i = 0; i < bst->num_specs; i++) { - SlObject(&bst->speclist[i], _station_speclist_desc); + SlObjectLoadFiltered(&bst->speclist[i], _filtered_station_speclist_desc.data()); } } } @@ -620,6 +645,12 @@ static void Ptrs_STNN() /* Don't run when savegame version lower than 123. */ if (IsSavegameVersionBefore(SLV_123)) return; + SetupDescs_STNN(); + + if (!IsSavegameVersionBefore(SLV_183)) { + assert(_filtered_goods_desc[0].cmd == SL_END); + } + uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO; Station *st; FOR_ALL_STATIONS(st) { @@ -627,50 +658,51 @@ static void Ptrs_STNN() GoodsEntry *ge = &st->goods[i]; if (IsSavegameVersionBefore(SLV_183)) { SwapPackets(ge); - SlObject(ge, GetGoodsDesc()); + SlObjectPtrOrNullFiltered(ge, _filtered_goods_desc.data()); SwapPackets(ge); } else { - SlObject(ge, GetGoodsDesc()); + //SlObject(ge, GetGoodsDesc()); for (StationCargoPacketMap::ConstMapIterator it = ge->cargo.Packets()->begin(); it != ge->cargo.Packets()->end(); ++it) { - SlObject(const_cast(&(*it)), _cargo_list_desc); + SlObjectPtrOrNullFiltered(const_cast(&(*it)), _cargo_list_desc); // _cargo_list_desc has no conditionals } } } - SlObject(st, _station_desc); + SlObjectPtrOrNullFiltered(st, _filtered_station_desc.data()); } Waypoint *wp; FOR_ALL_WAYPOINTS(wp) { - SlObject(wp, _waypoint_desc); + SlObjectPtrOrNullFiltered(wp, _filtered_waypoint_desc.data()); } } static void Save_ROADSTOP() { + SetupDescs_ROADSTOP(); RoadStop *rs; - FOR_ALL_ROADSTOPS(rs) { SlSetArrayIndex(rs->index); - SlObject(rs, _roadstop_desc); + SlObjectSaveFiltered(rs, _filtered_roadstop_desc.data()); } } static void Load_ROADSTOP() { + SetupDescs_ROADSTOP(); int index; - while ((index = SlIterateArray()) != -1) { RoadStop *rs = new (index) RoadStop(INVALID_TILE); - SlObject(rs, _roadstop_desc); + SlObjectLoadFiltered(rs, _filtered_roadstop_desc.data()); } } static void Ptrs_ROADSTOP() { + SetupDescs_ROADSTOP(); RoadStop *rs; FOR_ALL_ROADSTOPS(rs) { - SlObject(rs, _roadstop_desc); + SlObjectPtrOrNullFiltered(rs, _filtered_roadstop_desc.data()); } } diff --git a/src/saveload/town_sl.cpp b/src/saveload/town_sl.cpp index fc3dbe6065..2b64c5f002 100644 --- a/src/saveload/town_sl.cpp +++ b/src/saveload/town_sl.cpp @@ -239,6 +239,17 @@ static const SaveLoad _town_received_desc_spp[] = { SLE_END() }; +std::vector _filtered_town_desc; +std::vector _filtered_town_supplied_desc; +std::vector _filtered_town_received_desc; + +static void SetupDescs_TOWN() +{ + _filtered_town_desc = SlFilterObject(_town_desc); + _filtered_town_supplied_desc = SlFilterObject(_town_supplied_desc); + _filtered_town_received_desc = SlFilterObject(_town_received_desc); +} + static void Save_HIDS() { Save_NewGRFMapping(_house_mngr); @@ -264,22 +275,16 @@ const SaveLoad *GetTileMatrixDesc() static void RealSave_Town(Town *t) { - SlObject(t, _town_desc); + SlObjectSaveFiltered(t, _filtered_town_desc.data()); for (CargoID i = 0; i < NUM_CARGO; i++) { - SlObject(&t->supplied[i], _town_supplied_desc); + SlObjectSaveFiltered(&t->supplied[i], _filtered_town_supplied_desc.data()); } - if (SlXvIsFeaturePresent(XSLFI_SPRINGPP)) { - for (int i = TE_BEGIN; i < NUM_TE; i++) { - SlObject(&t->received[i], _town_received_desc_spp); - } - } else { - for (int i = TE_BEGIN; i < NUM_TE; i++) { - SlObject(&t->received[i], _town_received_desc); - } + for (int i = TE_BEGIN; i < NUM_TE; i++) { + SlObjectSaveFiltered(&t->received[i], _filtered_town_received_desc.data()); } - SlObject(&t->cargo_accepted, GetTileMatrixDesc()); + SlObjectSaveFiltered(&t->cargo_accepted, GetTileMatrixDesc()); // GetTileMatrixDesc() has no conditionals if (t->cargo_accepted.area.w != 0) { uint arr_len = t->cargo_accepted.area.w / AcceptanceMatrix::GRID * t->cargo_accepted.area.h / AcceptanceMatrix::GRID; SlArray(t->cargo_accepted.data, arr_len, SLE_UINT64); @@ -288,8 +293,8 @@ static void RealSave_Town(Town *t) static void Save_TOWN() { + SetupDescs_TOWN(); Town *t; - FOR_ALL_TOWNS(t) { SlSetArrayIndex(t->index); SlAutolength((AutolengthProc*)RealSave_Town, t); @@ -298,15 +303,16 @@ static void Save_TOWN() static void Load_TOWN() { + SetupDescs_TOWN(); int index; uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO; while ((index = SlIterateArray()) != -1) { Town *t = new (index) Town(); - SlObject(t, _town_desc); + SlObjectLoadFiltered(t, _filtered_town_desc.data()); for (CargoID i = 0; i < num_cargo; i++) { - SlObject(&t->supplied[i], _town_supplied_desc); + SlObjectLoadFiltered(&t->supplied[i], _filtered_town_supplied_desc.data()); } if (SlXvIsFeaturePresent(XSLFI_SPRINGPP)) { for (int i = TE_BEGIN; i < NUM_TE; i++) { @@ -314,7 +320,7 @@ static void Load_TOWN() } } else { for (int i = TE_BEGIN; i < NUM_TE; i++) { - SlObject(&t->received[i], _town_received_desc); + SlObjectLoadFiltered(&t->received[i], _filtered_town_received_desc.data()); } } @@ -331,7 +337,7 @@ static void Load_TOWN() } } if (SlXvIsFeaturePresent(XSLFI_TOWN_CARGO_MATRIX)) { - SlObject(&t->cargo_accepted, GetTileMatrixDesc()); + SlObjectLoadFiltered(&t->cargo_accepted, GetTileMatrixDesc()); // GetTileMatrixDesc() has no conditionals if (t->cargo_accepted.area.w != 0) { uint arr_len = t->cargo_accepted.area.w / AcceptanceMatrix::GRID * t->cargo_accepted.area.h / AcceptanceMatrix::GRID; t->cargo_accepted.data = MallocT(arr_len); @@ -349,9 +355,10 @@ static void Ptrs_TOWN() /* Don't run when savegame version lower than 161. */ if (IsSavegameVersionBefore(SLV_161)) return; + SetupDescs_TOWN(); Town *t; FOR_ALL_TOWNS(t) { - SlObject(t, _town_desc); + SlObjectPtrOrNullFiltered(t, _filtered_town_desc.data()); } } diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp index de15910f53..50a8012e36 100644 --- a/src/saveload/vehicle_sl.cpp +++ b/src/saveload/vehicle_sl.cpp @@ -951,20 +951,51 @@ const SaveLoad *GetVehicleDescription(VehicleType vt) return _veh_descs[vt]; } +static std::vector _filtered_train_desc; +static std::vector _filtered_roadveh_desc; +static std::vector _filtered_ship_desc; +static std::vector _filtered_aircraft_desc; +static std::vector _filtered_special_desc; +static std::vector _filtered_disaster_desc; + +static std::vector * const _filtered_veh_descs[] = { + &_filtered_train_desc, + &_filtered_roadveh_desc, + &_filtered_ship_desc, + &_filtered_aircraft_desc, + &_filtered_special_desc, + &_filtered_disaster_desc, +}; + +const SaveLoad *GetVehicleDescriptionFiltered(VehicleType vt) +{ + return _filtered_veh_descs[vt]->data(); +} + +static void SetupDescs_VEHS() +{ + for (size_t i = 0; i < lengthof(_filtered_veh_descs); i++) { + *(_filtered_veh_descs[i]) = SlFilterObject(GetVehicleDescription((VehicleType) i)); + } +} + /** Will be called when the vehicles need to be saved. */ static void Save_VEHS() { + SetupDescs_VEHS(); Vehicle *v; /* Write the vehicles */ FOR_ALL_VEHICLES(v) { SlSetArrayIndex(v->index); - SlObject(v, GetVehicleDescription(v->type)); + SlObjectSaveFiltered(v, GetVehicleDescriptionFiltered(v->type)); } } /** Will be called when vehicles need to be loaded. */ void Load_VEHS() { + SetupDescs_VEHS(); + int index; _cargo_count = 0; @@ -984,7 +1015,7 @@ void Load_VEHS() default: SlErrorCorrupt("Invalid vehicle type"); } - SlObject(v, GetVehicleDescription(vtype)); + SlObjectLoadFiltered(v, GetVehicleDescriptionFiltered(vtype)); if (_cargo_count != 0 && IsCompanyBuildableVehicleType(v) && CargoPacket::CanAllocateItem()) { /* Don't construct the packet with station here, because that'll fail with old savegames */ @@ -1013,9 +1044,11 @@ void Load_VEHS() static void Ptrs_VEHS() { + SetupDescs_VEHS(); + Vehicle *v; FOR_ALL_VEHICLES(v) { - SlObject(v, GetVehicleDescription(v->type)); + SlObjectPtrOrNullFiltered(v, GetVehicleDescriptionFiltered(v->type)); } }