Save/load: Pre-filter SaveLoad descriptor arrays for current version/mode, for chunks with many objects

This commit is contained in:
Jonathan G Rennison
2019-09-23 17:30:09 +01:00
parent 02bd91477d
commit 0a1c1809ab
9 changed files with 344 additions and 69 deletions

View File

@@ -534,7 +534,8 @@ protected:
friend class LinkGraph::Node; friend class LinkGraph::Node;
friend const SaveLoad *GetLinkGraphDesc(); friend const SaveLoad *GetLinkGraphDesc();
friend const SaveLoad *GetLinkGraphJobDesc(); 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. CargoID cargo; ///< Cargo of this component's link graph.
Date last_compression; ///< Last time the capacities and supplies were compressed. Date last_compression; ///< Last time the capacities and supplies were compressed.

View File

@@ -119,11 +119,11 @@ const SaveLoad *GetCargoPacketDesc()
*/ */
static void Save_CAPA() static void Save_CAPA()
{ {
std::vector<SaveLoad> filtered_packet_desc = SlFilterObject(GetCargoPacketDesc());
CargoPacket *cp; CargoPacket *cp;
FOR_ALL_CARGOPACKETS(cp) { FOR_ALL_CARGOPACKETS(cp) {
SlSetArrayIndex(cp->index); SlSetArrayIndex(cp->index);
SlObject(cp, GetCargoPacketDesc()); SlObjectSaveFiltered(cp, filtered_packet_desc.data());
} }
} }
@@ -132,11 +132,11 @@ static void Save_CAPA()
*/ */
static void Load_CAPA() static void Load_CAPA()
{ {
std::vector<SaveLoad> filtered_packet_desc = SlFilterObject(GetCargoPacketDesc());
int index; int index;
while ((index = SlIterateArray()) != -1) { while ((index = SlIterateArray()) != -1) {
CargoPacket *cp = new (index) CargoPacket(); CargoPacket *cp = new (index) CargoPacket();
SlObject(cp, GetCargoPacketDesc()); SlObjectLoadFiltered(cp, filtered_packet_desc.data());
} }
} }

View File

@@ -138,25 +138,53 @@ static const SaveLoad _edge_desc[] = {
SLE_END() SLE_END()
}; };
std::vector<SaveLoad> _filtered_node_desc;
std::vector<SaveLoad> _filtered_edge_desc;
std::vector<SaveLoad> _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. * @param lg Link graph to be saved or loaded.
*/ */
void SaveLoad_LinkGraph(LinkGraph &lg) void Save_LinkGraph(LinkGraph &lg)
{ {
uint size = lg.Size(); uint size = lg.Size();
for (NodeID from = 0; from < size; ++from) { for (NodeID from = 0; from < size; ++from) {
Node *node = &lg.nodes[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)) { if (IsSavegameVersionBefore(SLV_191)) {
/* We used to save the full matrix ... */ /* We used to save the full matrix ... */
for (NodeID to = 0; to < size; ++to) { for (NodeID to = 0; to < size; ++to) {
SlObject(&lg.edges[from][to], _edge_desc); SlObjectLoadFiltered(&lg.edges[from][to], _filtered_edge_desc.data());
} }
} else { } else {
/* ... but as that wasted a lot of space we save a sparse matrix now. */ /* ... 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) { 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) static void DoSave_LGRJ(LinkGraphJob *lgj)
{ {
SlObject(lgj, GetLinkGraphJobDesc()); SlObjectSaveFiltered(lgj, _filtered_job_desc.data());
_num_nodes = lgj->Size(); _num_nodes = lgj->Size();
SlObject(const_cast<LinkGraph *>(&lgj->Graph()), GetLinkGraphDesc()); SlObjectSaveFiltered(const_cast<LinkGraph *>(&lgj->Graph()), GetLinkGraphDesc()); // GetLinkGraphDesc has no conditionals
SaveLoad_LinkGraph(const_cast<LinkGraph &>(lgj->Graph())); Save_LinkGraph(const_cast<LinkGraph &>(lgj->Graph()));
} }
/** /**
@@ -181,8 +209,8 @@ static void DoSave_LGRJ(LinkGraphJob *lgj)
static void DoSave_LGRP(LinkGraph *lg) static void DoSave_LGRP(LinkGraph *lg)
{ {
_num_nodes = lg->Size(); _num_nodes = lg->Size();
SlObject(lg, GetLinkGraphDesc()); SlObjectSaveFiltered(lg, GetLinkGraphDesc()); // GetLinkGraphDesc has no conditionals
SaveLoad_LinkGraph(*lg); Save_LinkGraph(*lg);
} }
/** /**
@@ -190,6 +218,7 @@ static void DoSave_LGRP(LinkGraph *lg)
*/ */
static void Load_LGRP() static void Load_LGRP()
{ {
FilterDescs();
int index; int index;
while ((index = SlIterateArray()) != -1) { while ((index = SlIterateArray()) != -1) {
if (!LinkGraph::CanAllocateItem()) { if (!LinkGraph::CanAllocateItem()) {
@@ -197,9 +226,9 @@ static void Load_LGRP()
NOT_REACHED(); NOT_REACHED();
} }
LinkGraph *lg = new (index) LinkGraph(); LinkGraph *lg = new (index) LinkGraph();
SlObject(lg, GetLinkGraphDesc()); SlObjectLoadFiltered(lg, GetLinkGraphDesc()); // GetLinkGraphDesc has no conditionals
lg->Init(_num_nodes); lg->Init(_num_nodes);
SaveLoad_LinkGraph(*lg); Load_LinkGraph(*lg);
} }
} }
@@ -208,6 +237,7 @@ static void Load_LGRP()
*/ */
static void Load_LGRJ() static void Load_LGRJ()
{ {
FilterDescs();
int index; int index;
while ((index = SlIterateArray()) != -1) { while ((index = SlIterateArray()) != -1) {
if (!LinkGraphJob::CanAllocateItem()) { if (!LinkGraphJob::CanAllocateItem()) {
@@ -215,14 +245,14 @@ static void Load_LGRJ()
NOT_REACHED(); NOT_REACHED();
} }
LinkGraphJob *lgj = new (index) LinkGraphJob(); LinkGraphJob *lgj = new (index) LinkGraphJob();
SlObject(lgj, GetLinkGraphJobDesc()); SlObjectLoadFiltered(lgj, _filtered_job_desc.data());
if (SlXvIsFeatureMissing(XSLFI_LINKGRAPH_DAY_SCALE)) { if (SlXvIsFeatureMissing(XSLFI_LINKGRAPH_DAY_SCALE)) {
GetLinkGraphJobDayLengthScaleAfterLoad(lgj); GetLinkGraphJobDayLengthScaleAfterLoad(lgj);
} }
LinkGraph &lg = const_cast<LinkGraph &>(lgj->Graph()); LinkGraph &lg = const_cast<LinkGraph &>(lgj->Graph());
SlObject(&lg, GetLinkGraphDesc()); SlObjectLoadFiltered(&lg, GetLinkGraphDesc()); // GetLinkGraphDesc has no conditionals
lg.Init(_num_nodes); lg.Init(_num_nodes);
SaveLoad_LinkGraph(lg); Load_LinkGraph(lg);
} }
} }
@@ -267,6 +297,7 @@ void AfterLoadLinkGraphs()
*/ */
static void Save_LGRP() static void Save_LGRP()
{ {
FilterDescs();
LinkGraph *lg; LinkGraph *lg;
FOR_ALL_LINK_GRAPHS(lg) { FOR_ALL_LINK_GRAPHS(lg) {
SlSetArrayIndex(lg->index); SlSetArrayIndex(lg->index);
@@ -279,6 +310,7 @@ static void Save_LGRP()
*/ */
static void Save_LGRJ() static void Save_LGRJ()
{ {
FilterDescs();
LinkGraphJob *lgj; LinkGraphJob *lgj;
FOR_ALL_LINK_GRAPH_JOBS(lgj) { FOR_ALL_LINK_GRAPH_JOBS(lgj) {
SlSetArrayIndex(lgj->index); SlSetArrayIndex(lgj->index);

View File

@@ -33,7 +33,8 @@ void Save_NewGRFMapping(const OverrideManagerBase &mapping)
{ {
for (uint i = 0; i < mapping.GetMaxMapping(); i++) { for (uint i = 0; i < mapping.GetMaxMapping(); i++) {
SlSetArrayIndex(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; int index;
while ((index = SlIterateArray()) != -1) { while ((index = SlIterateArray()) != -1) {
if ((uint)index >= max_id) SlErrorCorrupt("Too many NewGRF entity mappings"); if (unlikely((uint)index >= max_id)) SlErrorCorrupt("Too many NewGRF entity mappings");
SlObject(&mapping.mapping_ID[index], _newgrf_mapping_desc); SlObjectLoadFiltered(&mapping.mapping_ID[index], _newgrf_mapping_desc); // _newgrf_mapping_desc has no conditionals
} }
} }

View File

@@ -889,9 +889,10 @@ void WriteValue(void *ptr, VarType conv, int64 val)
* @param ptr The object being filled/read * @param ptr The object being filled/read
* @param conv VarType type of the current element of the struct * @param conv VarType type of the current element of the struct
*/ */
static void SlSaveLoadConv(void *ptr, VarType conv) template <SaveLoadAction action>
static void SlSaveLoadConvGeneric(void *ptr, VarType conv)
{ {
switch (_sl.action) { switch (action) {
case SLA_SAVE: { case SLA_SAVE: {
int64 x = ReadValue(ptr, conv); 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<SLA_SAVE>(ptr, conv);
return;
case SLA_LOAD_CHECK:
case SLA_LOAD:
SlSaveLoadConvGeneric<SLA_LOAD>(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 * 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 * 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 */ #endif /* OTTD_ASSERT */
bool SlObjectMember(void *ptr, const SaveLoad *sld) void SlFilterObject(const SaveLoad *sld, std::vector<SaveLoad> &save);
static void SlFilterObjectMember(const SaveLoad *sld, std::vector<SaveLoad> &save)
{ {
#ifdef OTTD_ASSERT #ifdef OTTD_ASSERT
assert(IsVariableSizeRight(sld)); assert(IsVariableSizeRight(sld));
#endif #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<SaveLoad> &save)
{
for (; sld->cmd != SL_END; sld++) {
SlFilterObjectMember(sld, save);
}
}
std::vector<SaveLoad> SlFilterObject(const SaveLoad *sld)
{
std::vector<SaveLoad> save;
SlFilterObject(sld, save);
save.push_back(SLE_END());
return save;
}
template <SaveLoadAction action, bool check_version>
bool SlObjectMemberGeneric(void *ptr, const SaveLoad *sld)
{
#ifdef OTTD_ASSERT
if (check_version) assert(IsVariableSizeRight(sld));
#endif
VarType conv = GB(sld->conv, 0, 8); VarType conv = GB(sld->conv, 0, 8);
switch (sld->cmd) { switch (sld->cmd) {
case SL_VAR: case SL_VAR:
@@ -1698,13 +1800,15 @@ bool SlObjectMember(void *ptr, const SaveLoad *sld)
case SL_STDSTR: case SL_STDSTR:
case SL_VARVEC: case SL_VARVEC:
/* CONDITIONAL saveload types depend on the savegame version */ /* CONDITIONAL saveload types depend on the savegame version */
if (!SlIsObjectValidInSavegame(sld)) return false; if (check_version) {
if (SlSkipVariableOnLoad(sld)) return false; if (!SlIsObjectValidInSavegame(sld)) return false;
if (SlSkipVariableOnLoad(sld)) return false;
}
switch (sld->cmd) { switch (sld->cmd) {
case SL_VAR: SlSaveLoadConv(ptr, conv); break; case SL_VAR: SlSaveLoadConvGeneric<action>(ptr, conv); break;
case SL_REF: // Reference variable, translate case SL_REF: // Reference variable, translate
switch (_sl.action) { switch (action) {
case SLA_SAVE: case SLA_SAVE:
SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv)); SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv));
break; break;
@@ -1747,7 +1851,7 @@ bool SlObjectMember(void *ptr, const SaveLoad *sld)
* When loading, the value is read explictly with SlReadByte() to determine which * When loading, the value is read explictly with SlReadByte() to determine which
* object description to use. */ * object description to use. */
case SL_WRITEBYTE: case SL_WRITEBYTE:
switch (_sl.action) { switch (action) {
case SLA_SAVE: SlWriteByte(*(uint8 *)ptr); break; case SLA_SAVE: SlWriteByte(*(uint8 *)ptr); break;
case SLA_LOAD_CHECK: case SLA_LOAD_CHECK:
case SLA_LOAD: case SLA_LOAD:
@@ -1771,6 +1875,22 @@ bool SlObjectMember(void *ptr, const SaveLoad *sld)
return true; return true;
} }
bool SlObjectMember(void *ptr, const SaveLoad *sld)
{
switch (_sl.action) {
case SLA_SAVE:
return SlObjectMemberGeneric<SLA_SAVE, true>(ptr, sld);
case SLA_LOAD_CHECK:
case SLA_LOAD:
return SlObjectMemberGeneric<SLA_LOAD, true>(ptr, sld);
case SLA_PTRS:
return SlObjectMemberGeneric<SLA_PTRS, true>(ptr, sld);
case SLA_NULL:
return SlObjectMemberGeneric<SLA_NULL, true>(ptr, sld);
default: NOT_REACHED();
}
}
/** /**
* Main SaveLoad function. * Main SaveLoad function.
* @param object The object that is being saved or loaded * @param object The object that is being saved or loaded
@@ -1789,6 +1909,48 @@ void SlObject(void *object, const SaveLoad *sld)
} }
} }
template <SaveLoadAction action, bool check_version>
void SlObjectIterateBase(void *object, const SaveLoad *sld)
{
for (; sld->cmd != SL_END; sld++) {
void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
SlObjectMemberGeneric<action, check_version>(ptr, sld);
}
}
void SlObjectSaveFiltered(void *object, const SaveLoad *sld)
{
if (_sl.need_length != NL_NONE) {
_sl.need_length = NL_NONE;
_sl.dumper->StartAutoLength();
SlObjectIterateBase<SLA_SAVE, false>(object, sld);
auto result = _sl.dumper->StopAutoLength();
_sl.need_length = NL_WANTLENGTH;
SlSetLength(result.second);
_sl.dumper->CopyBytes(result.first, result.second);
} else {
SlObjectIterateBase<SLA_SAVE, false>(object, sld);
}
}
void SlObjectLoadFiltered(void *object, const SaveLoad *sld)
{
SlObjectIterateBase<SLA_LOAD, false>(object, sld);
}
void SlObjectPtrOrNullFiltered(void *object, const SaveLoad *sld)
{
switch (_sl.action) {
case SLA_PTRS:
SlObjectIterateBase<SLA_PTRS, false>(object, sld);
return;
case SLA_NULL:
SlObjectIterateBase<SLA_NULL, false>(object, sld);
return;
default: NOT_REACHED();
}
}
/** /**
* Save or Load (a list of) global variables * Save or Load (a list of) global variables
* @param sldg The global variable that is being loaded or saved * @param sldg The global variable that is being loaded or saved

View File

@@ -17,6 +17,7 @@
#include "extended_ver_sl.h" #include "extended_ver_sl.h"
#include <stdarg.h> #include <stdarg.h>
#include <vector>
/** SaveLoad versions /** SaveLoad versions
* Previous savegame versions, the trunk revision where they were * 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 SlArray(void *array, size_t length, VarType conv);
void SlObject(void *object, const SaveLoad *sld); void SlObject(void *object, const SaveLoad *sld);
bool SlObjectMember(void *object, const SaveLoad *sld); bool SlObjectMember(void *object, const SaveLoad *sld);
std::vector<SaveLoad> 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 SlError(StringID string, const char *extra_msg = nullptr, bool already_malloced = false);
void NORETURN SlErrorCorrupt(const char *msg, 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); void NORETURN CDECL SlErrorFmt(StringID string, const char *msg, ...) WARN_FORMAT(2, 3);

View File

@@ -489,10 +489,31 @@ const SaveLoad *GetBaseStationDescription()
return _base_station_desc; return _base_station_desc;
} }
std::vector<SaveLoad> _filtered_station_desc;
std::vector<SaveLoad> _filtered_waypoint_desc;
std::vector<SaveLoad> _filtered_goods_desc;
std::vector<SaveLoad> _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<SaveLoad> _filtered_roadstop_desc;
static void SetupDescs_ROADSTOP()
{
_filtered_roadstop_desc = SlFilterObject(_roadstop_desc);
}
static void RealSave_STNN(BaseStation *bst) static void RealSave_STNN(BaseStation *bst)
{ {
bool waypoint = (bst->facilities & FACIL_WAYPOINT) != 0; 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(); 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) { for (FlowStatMap::const_iterator it(st->goods[i].flows.begin()); it != st->goods[i].flows.end(); ++it) {
_num_flows += (uint32)it->second.GetShares()->size(); _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) { 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(); const FlowStat::SharesMap *shares = outer_it->second.GetShares();
uint32 sum_shares = 0; 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) { for (StationCargoPacketMap::ConstMapIterator it(st->goods[i].cargo.Packets()->begin()); it != st->goods[i].cargo.Packets()->end(); ++it) {
SlObject(const_cast<StationCargoPacketMap::value_type *>(&(*it)), _cargo_list_desc); SlObjectSaveFiltered(const_cast<StationCargoPacketMap::value_type *>(&(*it)), _cargo_list_desc); // _cargo_list_desc has no conditionals
} }
} }
} }
for (uint i = 0; i < bst->num_specs; i++) { 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() static void Save_STNN()
{ {
SetupDescs_STNN();
BaseStation *st; BaseStation *st;
/* Write the stations */ /* Write the stations */
FOR_ALL_BASE_STATIONS(st) { FOR_ALL_BASE_STATIONS(st) {
@@ -548,6 +571,8 @@ static void Save_STNN()
static void Load_STNN() static void Load_STNN()
{ {
SetupDescs_STNN();
_num_flows = 0; _num_flows = 0;
const uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO; 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; bool waypoint = (SlReadByte() & FACIL_WAYPOINT) != 0;
BaseStation *bst = waypoint ? (BaseStation *)new (index) Waypoint() : new (index) Station(); 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) { if (!waypoint) {
Station *st = Station::From(bst); Station *st = Station::From(bst);
@@ -572,7 +597,7 @@ static void Load_STNN()
} }
for (CargoID i = 0; i < num_cargo; i++) { for (CargoID i = 0; i < num_cargo; i++) {
SlObject(&st->goods[i], GetGoodsDesc()); SlObjectLoadFiltered(&st->goods[i], _filtered_goods_desc.data());
FlowSaveLoad flow; FlowSaveLoad flow;
FlowStat *fs = nullptr; FlowStat *fs = nullptr;
StationID prev_source = INVALID_STATION; StationID prev_source = INVALID_STATION;
@@ -596,7 +621,7 @@ static void Load_STNN()
} else { } else {
StationCargoPair pair; StationCargoPair pair;
for (uint j = 0; j < _num_dests; ++j) { 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<StationCargoPacketMap &>(*(st->goods[i].cargo.Packets()))[pair.first].swap(pair.second); const_cast<StationCargoPacketMap &>(*(st->goods[i].cargo.Packets()))[pair.first].swap(pair.second);
assert(pair.second.empty()); assert(pair.second.empty());
} }
@@ -609,7 +634,7 @@ static void Load_STNN()
/* Allocate speclist memory when loading a game */ /* Allocate speclist memory when loading a game */
bst->speclist = CallocT<StationSpecList>(bst->num_specs); bst->speclist = CallocT<StationSpecList>(bst->num_specs);
for (uint i = 0; i < bst->num_specs; i++) { 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. */ /* Don't run when savegame version lower than 123. */
if (IsSavegameVersionBefore(SLV_123)) return; 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; uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO;
Station *st; Station *st;
FOR_ALL_STATIONS(st) { FOR_ALL_STATIONS(st) {
@@ -627,50 +658,51 @@ static void Ptrs_STNN()
GoodsEntry *ge = &st->goods[i]; GoodsEntry *ge = &st->goods[i];
if (IsSavegameVersionBefore(SLV_183)) { if (IsSavegameVersionBefore(SLV_183)) {
SwapPackets(ge); SwapPackets(ge);
SlObject(ge, GetGoodsDesc()); SlObjectPtrOrNullFiltered(ge, _filtered_goods_desc.data());
SwapPackets(ge); SwapPackets(ge);
} else { } else {
SlObject(ge, GetGoodsDesc()); //SlObject(ge, GetGoodsDesc());
for (StationCargoPacketMap::ConstMapIterator it = ge->cargo.Packets()->begin(); it != ge->cargo.Packets()->end(); ++it) { for (StationCargoPacketMap::ConstMapIterator it = ge->cargo.Packets()->begin(); it != ge->cargo.Packets()->end(); ++it) {
SlObject(const_cast<StationCargoPair *>(&(*it)), _cargo_list_desc); SlObjectPtrOrNullFiltered(const_cast<StationCargoPair *>(&(*it)), _cargo_list_desc); // _cargo_list_desc has no conditionals
} }
} }
} }
SlObject(st, _station_desc); SlObjectPtrOrNullFiltered(st, _filtered_station_desc.data());
} }
Waypoint *wp; Waypoint *wp;
FOR_ALL_WAYPOINTS(wp) { FOR_ALL_WAYPOINTS(wp) {
SlObject(wp, _waypoint_desc); SlObjectPtrOrNullFiltered(wp, _filtered_waypoint_desc.data());
} }
} }
static void Save_ROADSTOP() static void Save_ROADSTOP()
{ {
SetupDescs_ROADSTOP();
RoadStop *rs; RoadStop *rs;
FOR_ALL_ROADSTOPS(rs) { FOR_ALL_ROADSTOPS(rs) {
SlSetArrayIndex(rs->index); SlSetArrayIndex(rs->index);
SlObject(rs, _roadstop_desc); SlObjectSaveFiltered(rs, _filtered_roadstop_desc.data());
} }
} }
static void Load_ROADSTOP() static void Load_ROADSTOP()
{ {
SetupDescs_ROADSTOP();
int index; int index;
while ((index = SlIterateArray()) != -1) { while ((index = SlIterateArray()) != -1) {
RoadStop *rs = new (index) RoadStop(INVALID_TILE); RoadStop *rs = new (index) RoadStop(INVALID_TILE);
SlObject(rs, _roadstop_desc); SlObjectLoadFiltered(rs, _filtered_roadstop_desc.data());
} }
} }
static void Ptrs_ROADSTOP() static void Ptrs_ROADSTOP()
{ {
SetupDescs_ROADSTOP();
RoadStop *rs; RoadStop *rs;
FOR_ALL_ROADSTOPS(rs) { FOR_ALL_ROADSTOPS(rs) {
SlObject(rs, _roadstop_desc); SlObjectPtrOrNullFiltered(rs, _filtered_roadstop_desc.data());
} }
} }

View File

@@ -239,6 +239,17 @@ static const SaveLoad _town_received_desc_spp[] = {
SLE_END() SLE_END()
}; };
std::vector<SaveLoad> _filtered_town_desc;
std::vector<SaveLoad> _filtered_town_supplied_desc;
std::vector<SaveLoad> _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() static void Save_HIDS()
{ {
Save_NewGRFMapping(_house_mngr); Save_NewGRFMapping(_house_mngr);
@@ -264,22 +275,16 @@ const SaveLoad *GetTileMatrixDesc()
static void RealSave_Town(Town *t) static void RealSave_Town(Town *t)
{ {
SlObject(t, _town_desc); SlObjectSaveFiltered(t, _filtered_town_desc.data());
for (CargoID i = 0; i < NUM_CARGO; i++) { 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++) {
for (int i = TE_BEGIN; i < NUM_TE; i++) { SlObjectSaveFiltered(&t->received[i], _filtered_town_received_desc.data());
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);
}
} }
SlObject(&t->cargo_accepted, GetTileMatrixDesc()); SlObjectSaveFiltered(&t->cargo_accepted, GetTileMatrixDesc()); // GetTileMatrixDesc() has no conditionals
if (t->cargo_accepted.area.w != 0) { if (t->cargo_accepted.area.w != 0) {
uint arr_len = t->cargo_accepted.area.w / AcceptanceMatrix::GRID * t->cargo_accepted.area.h / AcceptanceMatrix::GRID; 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); SlArray(t->cargo_accepted.data, arr_len, SLE_UINT64);
@@ -288,8 +293,8 @@ static void RealSave_Town(Town *t)
static void Save_TOWN() static void Save_TOWN()
{ {
SetupDescs_TOWN();
Town *t; Town *t;
FOR_ALL_TOWNS(t) { FOR_ALL_TOWNS(t) {
SlSetArrayIndex(t->index); SlSetArrayIndex(t->index);
SlAutolength((AutolengthProc*)RealSave_Town, t); SlAutolength((AutolengthProc*)RealSave_Town, t);
@@ -298,15 +303,16 @@ static void Save_TOWN()
static void Load_TOWN() static void Load_TOWN()
{ {
SetupDescs_TOWN();
int index; int index;
uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO; uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO;
while ((index = SlIterateArray()) != -1) { while ((index = SlIterateArray()) != -1) {
Town *t = new (index) Town(); Town *t = new (index) Town();
SlObject(t, _town_desc); SlObjectLoadFiltered(t, _filtered_town_desc.data());
for (CargoID i = 0; i < num_cargo; i++) { 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)) { if (SlXvIsFeaturePresent(XSLFI_SPRINGPP)) {
for (int i = TE_BEGIN; i < NUM_TE; i++) { for (int i = TE_BEGIN; i < NUM_TE; i++) {
@@ -314,7 +320,7 @@ static void Load_TOWN()
} }
} else { } else {
for (int i = TE_BEGIN; i < NUM_TE; i++) { 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)) { 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) { if (t->cargo_accepted.area.w != 0) {
uint arr_len = t->cargo_accepted.area.w / AcceptanceMatrix::GRID * t->cargo_accepted.area.h / AcceptanceMatrix::GRID; uint arr_len = t->cargo_accepted.area.w / AcceptanceMatrix::GRID * t->cargo_accepted.area.h / AcceptanceMatrix::GRID;
t->cargo_accepted.data = MallocT<CargoTypes>(arr_len); t->cargo_accepted.data = MallocT<CargoTypes>(arr_len);
@@ -349,9 +355,10 @@ static void Ptrs_TOWN()
/* Don't run when savegame version lower than 161. */ /* Don't run when savegame version lower than 161. */
if (IsSavegameVersionBefore(SLV_161)) return; if (IsSavegameVersionBefore(SLV_161)) return;
SetupDescs_TOWN();
Town *t; Town *t;
FOR_ALL_TOWNS(t) { FOR_ALL_TOWNS(t) {
SlObject(t, _town_desc); SlObjectPtrOrNullFiltered(t, _filtered_town_desc.data());
} }
} }

View File

@@ -951,20 +951,51 @@ const SaveLoad *GetVehicleDescription(VehicleType vt)
return _veh_descs[vt]; return _veh_descs[vt];
} }
static std::vector<SaveLoad> _filtered_train_desc;
static std::vector<SaveLoad> _filtered_roadveh_desc;
static std::vector<SaveLoad> _filtered_ship_desc;
static std::vector<SaveLoad> _filtered_aircraft_desc;
static std::vector<SaveLoad> _filtered_special_desc;
static std::vector<SaveLoad> _filtered_disaster_desc;
static std::vector<SaveLoad> * 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. */ /** Will be called when the vehicles need to be saved. */
static void Save_VEHS() static void Save_VEHS()
{ {
SetupDescs_VEHS();
Vehicle *v; Vehicle *v;
/* Write the vehicles */ /* Write the vehicles */
FOR_ALL_VEHICLES(v) { FOR_ALL_VEHICLES(v) {
SlSetArrayIndex(v->index); SlSetArrayIndex(v->index);
SlObject(v, GetVehicleDescription(v->type)); SlObjectSaveFiltered(v, GetVehicleDescriptionFiltered(v->type));
} }
} }
/** Will be called when vehicles need to be loaded. */ /** Will be called when vehicles need to be loaded. */
void Load_VEHS() void Load_VEHS()
{ {
SetupDescs_VEHS();
int index; int index;
_cargo_count = 0; _cargo_count = 0;
@@ -984,7 +1015,7 @@ void Load_VEHS()
default: SlErrorCorrupt("Invalid vehicle type"); default: SlErrorCorrupt("Invalid vehicle type");
} }
SlObject(v, GetVehicleDescription(vtype)); SlObjectLoadFiltered(v, GetVehicleDescriptionFiltered(vtype));
if (_cargo_count != 0 && IsCompanyBuildableVehicleType(v) && CargoPacket::CanAllocateItem()) { if (_cargo_count != 0 && IsCompanyBuildableVehicleType(v) && CargoPacket::CanAllocateItem()) {
/* Don't construct the packet with station here, because that'll fail with old savegames */ /* 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() static void Ptrs_VEHS()
{ {
SetupDescs_VEHS();
Vehicle *v; Vehicle *v;
FOR_ALL_VEHICLES(v) { FOR_ALL_VEHICLES(v) {
SlObject(v, GetVehicleDescription(v->type)); SlObjectPtrOrNullFiltered(v, GetVehicleDescriptionFiltered(v->type));
} }
} }