Saveload: Use table format for station/waypoint chunk

pull/726/head
Jonathan G Rennison 2 months ago
parent a192485ce9
commit f724853985

@ -582,7 +582,7 @@ public:
/** The super class ought to know what it's doing. */ /** The super class ought to know what it's doing. */
friend class CargoList<StationCargoList, StationCargoPacketMap>; friend class CargoList<StationCargoList, StationCargoPacketMap>;
/** The stations, via GoodsEntry, have a CargoList. */ /** The stations, via GoodsEntry, have a CargoList. */
friend SaveLoadTable GetGoodsDesc(); friend NamedSaveLoadTable GetGoodsDesc();
friend upstream_sl::SlStationGoods; friend upstream_sl::SlStationGoods;
friend class CargoLoad; friend class CargoLoad;

@ -219,6 +219,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
{ XSLFI_TABLE_SCRIPT_SL, XSCF_NULL, 1, 1, "table_script_sl", nullptr, nullptr, nullptr }, { XSLFI_TABLE_SCRIPT_SL, XSCF_NULL, 1, 1, "table_script_sl", nullptr, nullptr, nullptr },
{ XSLFI_TABLE_NEWGRF_SL, XSCF_NULL, 2, 2, "table_newgrf_sl", nullptr, nullptr, nullptr }, { XSLFI_TABLE_NEWGRF_SL, XSCF_NULL, 2, 2, "table_newgrf_sl", nullptr, nullptr, nullptr },
{ XSLFI_TABLE_INDUSTRY_SL, XSCF_NULL, 2, 2, "table_industry_sl", nullptr, nullptr, nullptr }, { XSLFI_TABLE_INDUSTRY_SL, XSCF_NULL, 2, 2, "table_industry_sl", nullptr, nullptr, nullptr },
{ XSLFI_TABLE_STATION_SL, XSCF_NULL, 1, 1, "table_station_sl", nullptr, nullptr, nullptr },
{ XSLFI_NULL, XSCF_NULL, 0, 0, nullptr, nullptr, nullptr, nullptr }, // This is the end marker { XSLFI_NULL, XSCF_NULL, 0, 0, nullptr, nullptr, nullptr, nullptr }, // This is the end marker
}; };

@ -174,6 +174,8 @@ enum SlXvFeatureIndex {
XSLFI_TABLE_INDUSTRY_SL, ///< Use table format for industry chunks: XSLFI_TABLE_INDUSTRY_SL, ///< Use table format for industry chunks:
///< v1: IBLD, ITBL ///< v1: IBLD, ITBL
///< v2: INDY ///< v2: INDY
XSLFI_TABLE_STATION_SL, ///< Use table format for station chunks:
///< v1: STNN
XSLFI_RIFF_HEADER_60_BIT, ///< Size field in RIFF chunk header is 60 bit XSLFI_RIFF_HEADER_60_BIT, ///< Size field in RIFF chunk header is 60 bit
XSLFI_HEIGHT_8_BIT, ///< Map tile height is 8 bit instead of 4 bit, but savegame version may be before this became true in trunk XSLFI_HEIGHT_8_BIT, ///< Map tile height is 8 bit instead of 4 bit, but savegame version may be before this became true in trunk

@ -1898,7 +1898,6 @@ size_t SlCalcObjMemberLength(const void *object, const SaveLoad &sld)
break; break;
case SL_WRITEBYTE: return 1; // a uint8_t is logically of size 1 case SL_WRITEBYTE: return 1; // a uint8_t is logically of size 1
case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END)); case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription());
case SL_STRUCT: case SL_STRUCT:
case SL_STRUCTLIST: case SL_STRUCTLIST:
@ -1968,8 +1967,8 @@ static void SlFilterObjectMember(const SaveLoad &sld, std::vector<SaveLoad> &sav
SlFilterObject(GetVehicleDescription(VEH_END), save); SlFilterObject(GetVehicleDescription(VEH_END), save);
break; break;
case SL_ST_INCLUDE: case SL_INCLUDE:
SlFilterObject(GetBaseStationDescription(), save); sld.include_functor(save);
break; break;
default: NOT_REACHED(); default: NOT_REACHED();
@ -2133,10 +2132,6 @@ bool SlObjectMemberGeneric(void *object, const SaveLoad &sld)
SlObject(ptr, GetVehicleDescription(VEH_END)); SlObject(ptr, GetVehicleDescription(VEH_END));
break; break;
case SL_ST_INCLUDE:
SlObject(ptr, GetBaseStationDescription());
break;
default: NOT_REACHED(); default: NOT_REACHED();
} }
return true; return true;

@ -719,7 +719,9 @@ inline constexpr void *SlVarWrapper(void* ptr)
#define SLE_WRITEBYTE(base, variable) SLE_GENERAL(SL_WRITEBYTE, base, variable, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION) #define SLE_WRITEBYTE(base, variable) SLE_GENERAL(SL_WRITEBYTE, base, variable, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION)
#define SLE_VEH_INCLUDE() SaveLoad { false, SL_VEH_INCLUDE, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION, SLTAG_DEFAULT, { nullptr }, SlXvFeatureTest()} #define SLE_VEH_INCLUDE() SaveLoad { false, SL_VEH_INCLUDE, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION, SLTAG_DEFAULT, { nullptr }, SlXvFeatureTest()}
#define SLE_ST_INCLUDE() SaveLoad { false, SL_ST_INCLUDE, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION, SLTAG_DEFAULT, { nullptr }, SlXvFeatureTest()}
/** SaveLoad include, for non-table use with SlFilterObject/SlFilterNamedSaveLoadTable. */
#define SLE_INCLUDE(inc_functor) SaveLoad { false, SL_INCLUDE, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION, SLTAG_DEFAULT, { .include_functor = inc_functor }, SlXvFeatureTest()}
/** /**
* Storage of global simple variables, references (pointers), and arrays. * Storage of global simple variables, references (pointers), and arrays.
@ -987,6 +989,7 @@ size_t SlCalcObjLength(const void *object, const SaveLoadTable &slt);
uint SlReadSimpleGamma(); uint SlReadSimpleGamma();
void SlWriteSimpleGamma(size_t i); void SlWriteSimpleGamma(size_t i);
uint SlGetGammaLength(size_t i); uint SlGetGammaLength(size_t i);
constexpr uint SlGetMaxGammaLength() { return 5; }
/** /**
* Run proc, automatically prepending the written length * Run proc, automatically prepending the written length
@ -1084,6 +1087,7 @@ void SlObject(void *object, const SaveLoadTable &slt);
bool SlObjectMember(void *object, const SaveLoad &sld); bool SlObjectMember(void *object, const SaveLoad &sld);
std::vector<SaveLoad> SlFilterObject(const SaveLoadTable &slt); std::vector<SaveLoad> SlFilterObject(const SaveLoadTable &slt);
void SlFilterNamedSaveLoadTable(const NamedSaveLoadTable &nslt, std::vector<SaveLoad> &save);
std::vector<SaveLoad> SlFilterNamedSaveLoadTable(const NamedSaveLoadTable &nslt); std::vector<SaveLoad> SlFilterNamedSaveLoadTable(const NamedSaveLoadTable &nslt);
void SlObjectSaveFiltered(void *object, const SaveLoadTable &slt); void SlObjectSaveFiltered(void *object, const SaveLoadTable &slt);
void SlObjectLoadFiltered(void *object, const SaveLoadTable &slt); void SlObjectLoadFiltered(void *object, const SaveLoadTable &slt);

@ -23,7 +23,6 @@ void ResetOldNames();
void ResetOldWaypoints(); void ResetOldWaypoints();
void MoveBuoysToWaypoints(); void MoveBuoysToWaypoints();
void MoveWaypointsToBaseStations(); void MoveWaypointsToBaseStations();
SaveLoadTable GetBaseStationDescription();
void AfterLoadVehiclesPhase1(bool part_of_load); void AfterLoadVehiclesPhase1(bool part_of_load);
void AfterLoadVehiclesPhase2(bool part_of_load); void AfterLoadVehiclesPhase2(bool part_of_load);

@ -120,12 +120,13 @@ enum SaveLoadTypes {
/* non-normal save-load types */ /* non-normal save-load types */
SL_WRITEBYTE, SL_WRITEBYTE,
SL_VEH_INCLUDE, SL_VEH_INCLUDE,
SL_ST_INCLUDE, SL_INCLUDE,
}; };
typedef uint8_t SaveLoadType; ///< Save/load type. @see SaveLoadTypes typedef uint8_t SaveLoadType; ///< Save/load type. @see SaveLoadTypes
using SaveLoadStructHandlerFactory = std::unique_ptr<class SaveLoadStructHandler> (*)(); using SaveLoadStructHandlerFactory = std::unique_ptr<class SaveLoadStructHandler> (*)();
using SaveLoadIncludeFunctor = void (*)(std::vector<struct SaveLoad> &);
/** SaveLoad type struct. Do NOT use this directly but use the SLE_ macros defined just below! */ /** SaveLoad type struct. Do NOT use this directly but use the SLE_ macros defined just below! */
struct SaveLoad { struct SaveLoad {
@ -144,6 +145,7 @@ struct SaveLoad {
* that is called to save it. address: global=true, offset: global=false */ * that is called to save it. address: global=true, offset: global=false */
void *address; ///< address of variable OR offset of variable in the struct (max offset is 65536) void *address; ///< address of variable OR offset of variable in the struct (max offset is 65536)
SaveLoadStructHandlerFactory struct_handler_factory; ///< factory function pointer for SaveLoadStructHandler SaveLoadStructHandlerFactory struct_handler_factory; ///< factory function pointer for SaveLoadStructHandler
SaveLoadIncludeFunctor include_functor; ///< include functor for SL_INCLUDE
}; };
SlXvFeatureTest ext_feature_test; ///< extended feature test SlXvFeatureTest ext_feature_test; ///< extended feature test
@ -162,6 +164,7 @@ enum SaveLoadTags {
SLTAG_CUSTOM_START, SLTAG_CUSTOM_START,
SLTAG_CUSTOM_0 = SLTAG_CUSTOM_START, SLTAG_CUSTOM_0 = SLTAG_CUSTOM_START,
SLTAG_CUSTOM_1, SLTAG_CUSTOM_1,
SLTAG_CUSTOM_2,
}; };
enum NamedSaveLoadFlags : uint8_t { enum NamedSaveLoadFlags : uint8_t {
@ -215,6 +218,12 @@ inline constexpr NamedSaveLoad NSLT_STRUCTLIST(const char *name, SaveLoadVersion
return NSLT_STRUCTLIST(name, factory, from, to, extver); return NSLT_STRUCTLIST(name, factory, from, to, extver);
} }
inline constexpr NamedSaveLoad NSLTAG(uint16_t label_tag, NamedSaveLoad nsl)
{
nsl.save_load.label_tag = label_tag;
return nsl;
}
struct SaveLoadTableData : public std::vector<SaveLoad> { struct SaveLoadTableData : public std::vector<SaveLoad> {
std::vector<std::unique_ptr<class SaveLoadStructHandler>> struct_handlers; std::vector<std::unique_ptr<class SaveLoadStructHandler>> struct_handlers;
}; };

@ -28,6 +28,7 @@ static uint8_t _num_roadstop_specs;
static uint32_t _num_roadstop_custom_tiles; static uint32_t _num_roadstop_custom_tiles;
static std::vector<TileIndex> _custom_road_stop_tiles; static std::vector<TileIndex> _custom_road_stop_tiles;
static std::vector<uint16_t> _custom_road_stop_data; static std::vector<uint16_t> _custom_road_stop_data;
static std::vector<uint16_t> _station_history_data_dummy;
/** /**
* Update the buoy orders to be waypoint orders. * Update the buoy orders to be waypoint orders.
@ -223,27 +224,28 @@ static uint8_t _cargo_periods;
static Money _cargo_feeder_share; static Money _cargo_feeder_share;
static uint _cargo_reserved_count; static uint _cargo_reserved_count;
static const SaveLoad _station_speclist_desc[] = { static const NamedSaveLoad _station_speclist_desc[] = {
SLE_CONDVAR(StationSpecList, grfid, SLE_UINT32, SLV_27, SL_MAX_VERSION), NSL("grfid", SLE_CONDVAR(StationSpecList, grfid, SLE_UINT32, SLV_27, SL_MAX_VERSION)),
SLE_CONDVAR_X(StationSpecList, localidx, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_NEWGRF_ENTITY_EXTRA, 0, 1)), NSL("localidx", SLE_CONDVAR_X(StationSpecList, localidx, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_NEWGRF_ENTITY_EXTRA, 0, 1))),
SLE_CONDVAR_X(StationSpecList, localidx, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_NEWGRF_ENTITY_EXTRA, 2)), NSL("localidx", SLE_CONDVAR_X(StationSpecList, localidx, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_NEWGRF_ENTITY_EXTRA, 2))),
}; };
static const SaveLoad _roadstop_speclist_desc[] = { static const NamedSaveLoad _roadstop_speclist_desc[] = {
SLE_CONDVAR(RoadStopSpecList, grfid, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION), NSL("grfid", SLE_CONDVAR(RoadStopSpecList, grfid, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION)),
SLE_CONDVAR_X(RoadStopSpecList, localidx, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_GRF_ROADSTOPS, 0, 2)), NSL("localidx", SLE_CONDVAR_X(RoadStopSpecList, localidx, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_GRF_ROADSTOPS, 0, 2))),
SLE_CONDVAR_X(RoadStopSpecList, localidx, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_GRF_ROADSTOPS, 3)), NSL("localidx", SLE_CONDVAR_X(RoadStopSpecList, localidx, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_GRF_ROADSTOPS, 3))),
}; };
CargoPacketList _packets; CargoPacketList _packets;
uint32_t _num_dests; uint32_t _num_dests;
struct FlowSaveLoad { struct FlowSaveLoad {
FlowSaveLoad() : source(0), via(0), share(0), restricted(false) {} FlowSaveLoad() : source(0), via(0), share(0), restricted(false), flags(0) {}
StationID source; StationID source;
StationID via; StationID via;
uint32_t share; uint32_t share;
bool restricted; bool restricted;
uint16_t flags;
}; };
#if 0 #if 0
@ -255,50 +257,195 @@ static const SaveLoad _flow_desc[] = {
}; };
#endif #endif
static const NamedSaveLoad _inner_flow_desc[] = {
NSL("via", SLTAG(SLTAG_CUSTOM_0, SLE_VAR(FlowSaveLoad, via, SLE_UINT16))),
NSL("share", SLTAG(SLTAG_CUSTOM_1, SLE_VAR(FlowSaveLoad, share, SLE_UINT32))),
NSL("restricted", SLTAG(SLTAG_CUSTOM_2, SLE_CONDVAR(FlowSaveLoad, restricted, SLE_BOOL, SLV_187, SL_MAX_VERSION))),
};
struct StationGoodsInnerFlowStructHandler final : public HeaderOnlySaveLoadStructHandler {
NamedSaveLoadTable GetDescription() const override
{
return _inner_flow_desc;
}
void LoadedTableDescription() override
{
SaveLoadTable slt = this->GetLoadDescription();
if (slt.size() != 3 || slt[0].label_tag != SLTAG_CUSTOM_0 || slt[1].label_tag != SLTAG_CUSTOM_1 || slt[2].label_tag != SLTAG_CUSTOM_2) {
SlErrorCorrupt("Station goods flow inner sub-chunk fields not as expected");
}
}
};
static const NamedSaveLoad _outer_flow_desc[] = {
NSL("source", SLTAG(SLTAG_CUSTOM_0, SLE_VAR(FlowSaveLoad, source, SLE_UINT16))),
NSL("flags", SLTAG(SLTAG_CUSTOM_1, SLE_VAR(FlowSaveLoad, flags, SLE_UINT16))),
NSLTAG(SLTAG_CUSTOM_2, NSLT_STRUCTLIST<StationGoodsInnerFlowStructHandler>("flow")),
};
struct StationGoodsFlowStructHandler final : public TypedSaveLoadStructHandler<StationGoodsFlowStructHandler, GoodsEntry> {
NamedSaveLoadTable GetDescription() const override
{
return _outer_flow_desc;
}
void Save(GoodsEntry *ge) const override
{
const GoodsEntryData *ged = ge->data.get();
if (ged == nullptr) {
SlSetStructListLength(0);
return;
}
MemoryDumper *dumper = MemoryDumper::GetCurrent();
SlSetStructListLength(ged->flows.size());
for (const FlowStat &stat : ged->flows) {
uint32_t sum_shares = 0;
dumper->CheckBytes(2 + 2);
dumper->RawWriteUint16(stat.GetOrigin());
dumper->RawWriteUint16(stat.GetRawFlags());
SlWriteSimpleGamma(stat.size());
for (const auto &it : stat) {
StationID via = it.second;
uint32_t share = it.first - sum_shares;
bool restricted = it.first > stat.GetUnrestricted();
sum_shares = it.first;
dbg_assert(share > 0);
/* This is performance-sensitive, manually unroll */
dumper->CheckBytes(2 + 4 + 1);
dumper->RawWriteUint16(via);
dumper->RawWriteUint32(share);
dumper->RawWriteByte(restricted ? 1 : 0);
}
}
}
void Load(GoodsEntry *ge) const override
{
ReadBuffer *buffer = ReadBuffer::GetCurrent();
uint num_flows = SlGetStructListLength(UINT32_MAX);
FlowStatMap &flows = ge->data->flows;
flows.reserve(num_flows);
for (uint32_t j = 0; j < num_flows; ++j) {
buffer->CheckBytes(2 + 2);
StationID source = buffer->RawReadUint16();
uint16_t flags = buffer->RawReadUint16();
uint32_t flow_count = SlReadSimpleGamma();
buffer->CheckBytes(2 + 4 + 1);
StationID via = buffer->RawReadUint16();
uint32_t share = buffer->RawReadUint32();
bool restricted = (buffer->RawReadByte() != 0);
FlowStat &fs = *(flows.insert(flows.end(), FlowStat(source, via, share, restricted)));
fs.SetRawFlags(flags);
for (uint32_t k = 1; k < flow_count; ++k) {
buffer->CheckBytes(2 + 4 + 1);
via = buffer->RawReadUint16();
share = buffer->RawReadUint32();
restricted = (buffer->RawReadByte() != 0);
fs.AppendShare(via, share, restricted);
}
}
}
void LoadedTableDescription() override
{
if (!SlXvIsFeaturePresent(XSLFI_FLOW_STAT_FLAGS)) {
SlErrorCorrupt("XSLFI_FLOW_STAT_FLAGS unexpectedly not present");
}
SaveLoadTable slt = this->GetLoadDescription();
if (slt.size() != 3 || slt[0].label_tag != SLTAG_CUSTOM_0 || slt[1].label_tag != SLTAG_CUSTOM_1 || slt[2].label_tag != SLTAG_CUSTOM_2) {
SlErrorCorrupt("Station goods flow outer sub-chunk fields not as expected");
}
}
};
typedef std::pair<const StationID, CargoPacketList> StationCargoPair;
static const NamedSaveLoad _cargo_list_desc[] = {
NSL("first", SLE_VAR(StationCargoPair, first, SLE_UINT16)),
NSL("second", SLE_PTRRING(StationCargoPair, second, REF_CARGO_PACKET)),
};
struct StationGoodsCargoStructHandler final : public TypedSaveLoadStructHandler<StationGoodsCargoStructHandler, GoodsEntry> {
NamedSaveLoadTable GetDescription() const override
{
return _cargo_list_desc;
}
void Save(GoodsEntry *ge) const override
{
const GoodsEntryData *ged = ge->data.get();
if (ged == nullptr) {
SlSetStructListLength(0);
return;
}
SlSetStructListLength(ged->cargo.Packets()->MapSize());
for (StationCargoPacketMap::ConstMapIterator it(ged->cargo.Packets()->begin()); it != ged->cargo.Packets()->end(); ++it) {
SlObjectSaveFiltered(const_cast<StationCargoPacketMap::value_type *>(&(*it)), this->GetLoadDescription());
}
}
void Load(GoodsEntry *ge) const override
{
uint num_dests = SlGetStructListLength(UINT32_MAX);
StationCargoPair pair;
for (uint j = 0; j < num_dests; ++j) {
SlObjectLoadFiltered(&pair, this->GetLoadDescription());
const_cast<StationCargoPacketMap &>(*(ge->data->cargo.Packets()))[pair.first].swap(pair.second);
assert(pair.second.empty());
}
}
};
/** /**
* Wrapper function to get the GoodsEntry's internal structure while * Wrapper function to get the GoodsEntry's internal structure while
* some of the variables itself are private. * some of the variables itself are private.
* @return the saveload description for GoodsEntry. * @return the saveload description for GoodsEntry.
*/ */
SaveLoadTable GetGoodsDesc() NamedSaveLoadTable GetGoodsDesc()
{ {
static const SaveLoad goods_desc[] = { static const NamedSaveLoad goods_desc[] = {
SLEG_CONDVAR( _waiting_acceptance, SLE_UINT16, SL_MIN_VERSION, SLV_68), NSL("", SLEG_CONDVAR( _waiting_acceptance, SLE_UINT16, SL_MIN_VERSION, SLV_68)),
SLE_CONDVAR(GoodsEntry, status, SLE_UINT8, SLV_68, SL_MAX_VERSION), NSL("status", SLE_CONDVAR(GoodsEntry, status, SLE_UINT8, SLV_68, SL_MAX_VERSION)),
SLE_CONDNULL(2, SLV_51, SLV_68), NSL("", SLE_CONDNULL(2, SLV_51, SLV_68)),
SLE_VAR(GoodsEntry, time_since_pickup, SLE_UINT8), NSL("time_since_pickup", SLE_VAR(GoodsEntry, time_since_pickup, SLE_UINT8)),
SLE_CONDNULL_X(6, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SPRINGPP, 4)), NSL("", SLE_CONDNULL_X(6, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SPRINGPP, 4))),
SLE_VAR(GoodsEntry, rating, SLE_UINT8), NSL("rating", SLE_VAR(GoodsEntry, rating, SLE_UINT8)),
SLEG_CONDVAR( _cargo_source, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_7), NSL("", SLEG_CONDVAR( _cargo_source, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_7)),
SLEG_CONDVAR( _cargo_source, SLE_UINT16, SLV_7, SLV_68), NSL("", SLEG_CONDVAR( _cargo_source, SLE_UINT16, SLV_7, SLV_68)),
SLEG_CONDVAR( _cargo_source_xy, SLE_UINT32, SLV_44, SLV_68), NSL("", SLEG_CONDVAR( _cargo_source_xy, SLE_UINT32, SLV_44, SLV_68)),
SLEG_CONDVAR( _cargo_periods, SLE_UINT8, SL_MIN_VERSION, SLV_68), NSL("", SLEG_CONDVAR( _cargo_periods, SLE_UINT8, SL_MIN_VERSION, SLV_68)),
SLE_VAR(GoodsEntry, last_speed, SLE_UINT8), NSL("last_speed", SLE_VAR(GoodsEntry, last_speed, SLE_UINT8)),
SLE_VAR(GoodsEntry, last_age, SLE_UINT8), NSL("last_age", SLE_VAR(GoodsEntry, last_age, SLE_UINT8)),
SLEG_CONDVAR( _cargo_feeder_share, SLE_FILE_U32 | SLE_VAR_I64, SLV_14, SLV_65), NSL("", SLEG_CONDVAR( _cargo_feeder_share, SLE_FILE_U32 | SLE_VAR_I64, SLV_14, SLV_65)),
SLEG_CONDVAR( _cargo_feeder_share, SLE_INT64, SLV_65, SLV_68), NSL("", SLEG_CONDVAR( _cargo_feeder_share, SLE_INT64, SLV_65, SLV_68)),
SLE_CONDVAR(GoodsEntry, amount_fract, SLE_UINT8, SLV_150, SL_MAX_VERSION), NSL("amount_fract", SLE_CONDVAR(GoodsEntry, amount_fract, SLE_UINT8, SLV_150, SL_MAX_VERSION)),
SLEG_CONDPTRRING_X( _packets, REF_CARGO_PACKET, SLV_68, SLV_183, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, 0, 0)), NSL("", SLEG_CONDPTRRING_X( _packets, REF_CARGO_PACKET, SLV_68, SLV_183, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, 0, 0))),
SLEG_CONDVAR_X( _num_dests, SLE_UINT32, SLV_183, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_OR, XSLFI_CHILLPP)), NSL("", SLEG_CONDVAR_X( _num_dests, SLE_UINT32, SLV_183, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_OR, XSLFI_CHILLPP))),
SLEG_CONDVAR( _cargo_reserved_count,SLE_UINT, SLV_181, SL_MAX_VERSION), NSL("cargo.reserved_count", SLEG_CONDVAR( _cargo_reserved_count, SLE_UINT, SLV_181, SL_MAX_VERSION)),
SLE_CONDVAR(GoodsEntry, link_graph, SLE_UINT16, SLV_183, SL_MAX_VERSION), NSL("link_graph", SLE_CONDVAR(GoodsEntry, link_graph, SLE_UINT16, SLV_183, SL_MAX_VERSION)),
SLE_CONDVAR(GoodsEntry, node, SLE_UINT16, SLV_183, SL_MAX_VERSION), NSL("node", SLE_CONDVAR(GoodsEntry, node, SLE_UINT16, SLV_183, SL_MAX_VERSION)),
SLEG_CONDVAR( _num_flows, SLE_UINT32, SLV_183, SL_MAX_VERSION), NSL("", SLEG_CONDVAR( _num_flows, SLE_UINT32, SLV_183, SL_MAX_VERSION)),
SLE_CONDVAR(GoodsEntry, max_waiting_cargo, SLE_UINT32, SLV_183, SL_MAX_VERSION), NSL("max_waiting_cargo", SLE_CONDVAR(GoodsEntry, max_waiting_cargo, SLE_UINT32, SLV_183, SL_MAX_VERSION)),
SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP)), NSL("", SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP))),
SLE_CONDVAR_X(GoodsEntry, last_vehicle_type, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ST_LAST_VEH_TYPE, 1)), NSL("last_vehicle_type", SLE_CONDVAR_X(GoodsEntry, last_vehicle_type, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ST_LAST_VEH_TYPE, 1))),
NSLT_STRUCTLIST<StationGoodsFlowStructHandler>("flow"),
NSLT_STRUCTLIST<StationGoodsCargoStructHandler>("cargo"),
}; };
return goods_desc; return goods_desc;
} }
typedef std::pair<const StationID, CargoPacketList> StationCargoPair;
static const SaveLoad _cargo_list_desc[] = {
SLE_VAR(StationCargoPair, first, SLE_UINT16),
SLE_PTRRING(StationCargoPair, second, REF_CARGO_PACKET),
};
/** /**
* Swap the temporary packets with the packets without specific destination in * Swap the temporary packets with the packets without specific destination in
* the given goods entry. Assert that at least one of those is empty. * the given goods entry. Assert that at least one of those is empty.
@ -331,6 +478,9 @@ static void Load_STNS()
_num_specs = 0; _num_specs = 0;
_cargo_reserved_count = 0; _cargo_reserved_count = 0;
std::vector<SaveLoad> goods_desc = SlFilterNamedSaveLoadTable(GetGoodsDesc());
std::vector<SaveLoad> speclist_desc = SlFilterNamedSaveLoadTable(_station_speclist_desc);
uint num_cargo = IsSavegameVersionBefore(SLV_55) ? 12 : IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO; uint num_cargo = IsSavegameVersionBefore(SLV_55) ? 12 : IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO;
int index; int index;
while ((index = SlIterateArray()) != -1) { while ((index = SlIterateArray()) != -1) {
@ -342,7 +492,7 @@ static void Load_STNS()
for (CargoID i = 0; i < num_cargo; i++) { for (CargoID i = 0; i < num_cargo; i++) {
GoodsEntry *ge = &st->goods[i]; GoodsEntry *ge = &st->goods[i];
SlObject(ge, GetGoodsDesc()); SlObjectLoadFiltered(ge, goods_desc);
if (_cargo_reserved_count) ge->CreateData().cargo.LoadSetReservedCount(_cargo_reserved_count); if (_cargo_reserved_count) ge->CreateData().cargo.LoadSetReservedCount(_cargo_reserved_count);
SwapPackets(ge); SwapPackets(ge);
if (IsSavegameVersionBefore(SLV_68)) { if (IsSavegameVersionBefore(SLV_68)) {
@ -370,7 +520,7 @@ static void Load_STNS()
/* Allocate speclist memory when loading a game */ /* Allocate speclist memory when loading a game */
st->speclist.resize(_num_specs); st->speclist.resize(_num_specs);
for (uint i = 0; i < st->speclist.size(); i++) { for (uint i = 0; i < st->speclist.size(); i++) {
SlObject(&st->speclist[i], _station_speclist_desc); SlObjectLoadFiltered(&st->speclist[i], speclist_desc);
} }
} }
} }
@ -381,13 +531,15 @@ static void Ptrs_STNS()
/* Don't run when savegame version is higher than or equal to 123. */ /* Don't run when savegame version is higher than or equal to 123. */
if (!IsSavegameVersionBefore(SLV_123)) return; if (!IsSavegameVersionBefore(SLV_123)) return;
std::vector<SaveLoad> goods_desc = SlFilterNamedSaveLoadTable(GetGoodsDesc());
uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO; uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO;
for (Station *st : Station::Iterate()) { for (Station *st : Station::Iterate()) {
if (!IsSavegameVersionBefore(SLV_68)) { if (!IsSavegameVersionBefore(SLV_68)) {
for (CargoID i = 0; i < num_cargo; i++) { for (CargoID i = 0; i < num_cargo; i++) {
GoodsEntry *ge = &st->goods[i]; GoodsEntry *ge = &st->goods[i];
SwapPackets(ge); SwapPackets(ge);
SlObject(ge, GetGoodsDesc()); SlObject(ge, goods_desc);
SwapPackets(ge); SwapPackets(ge);
} }
} }
@ -396,177 +548,124 @@ static void Ptrs_STNS()
} }
static const SaveLoad _base_station_desc[] = { static const NamedSaveLoad _base_station_desc[] = {
SLE_VAR(BaseStation, xy, SLE_UINT32), NSL("xy", SLE_VAR(BaseStation, xy, SLE_UINT32)),
SLE_REF(BaseStation, town, REF_TOWN), NSL("town", SLE_REF(BaseStation, town, REF_TOWN)),
SLE_VAR(BaseStation, string_id, SLE_STRINGID), NSL("string_id", SLE_VAR(BaseStation, string_id, SLE_STRINGID)),
SLE_STR(BaseStation, name, SLE_STR | SLF_ALLOW_CONTROL, 0), NSL("name", SLE_STR(BaseStation, name, SLE_STR | SLF_ALLOW_CONTROL, 0)),
SLE_CONDVAR_X(Station, delete_ctr, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SPRINGPP, 0, 3)), NSL("delete_ctr", SLE_CONDVAR_X(Station, delete_ctr, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SPRINGPP, 0, 3))),
SLE_CONDVAR_X(Station, delete_ctr, SLE_FILE_U16 | SLE_VAR_U8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SPRINGPP, 4)), NSL("delete_ctr", SLE_CONDVAR_X(Station, delete_ctr, SLE_FILE_U16 | SLE_VAR_U8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SPRINGPP, 4))),
SLE_VAR(BaseStation, owner, SLE_UINT8), NSL("owner", SLE_VAR(BaseStation, owner, SLE_UINT8)),
SLE_VAR(BaseStation, facilities, SLE_UINT8), NSL("facilities", SLE_VAR(BaseStation, facilities, SLE_UINT8)),
SLE_VAR(BaseStation, build_date, SLE_INT32), NSL("build_date", SLE_VAR(BaseStation, build_date, SLE_INT32)),
/* Used by newstations for graphic variations */ /* Used by newstations for graphic variations */
SLE_VAR(BaseStation, random_bits, SLE_UINT16), NSL("random_bits", SLE_VAR(BaseStation, random_bits, SLE_UINT16)),
SLE_VAR(BaseStation, waiting_triggers, SLE_UINT8), NSL("waiting_triggers", SLE_VAR(BaseStation, waiting_triggers, SLE_UINT8)),
SLEG_VAR(_num_specs, SLE_UINT8), NSL("", SLEG_VAR(_num_specs, SLE_UINT8)),
SLEG_CONDVAR_X(_num_roadstop_specs, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_GRF_ROADSTOPS)), NSL("", SLEG_CONDVAR_X(_num_roadstop_specs, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_GRF_ROADSTOPS))),
SLEG_CONDVARVEC_X(_custom_road_stop_tiles, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_GRF_ROADSTOPS, 1, 1)), NSL("", SLEG_CONDVARVEC_X(_custom_road_stop_tiles, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_GRF_ROADSTOPS, 1, 1))),
SLEG_CONDVARVEC_X(_custom_road_stop_data, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_GRF_ROADSTOPS, 1, 1)), NSL("", SLEG_CONDVARVEC_X(_custom_road_stop_data, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_GRF_ROADSTOPS, 1, 1))),
SLEG_CONDVAR_X(_num_roadstop_custom_tiles, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_GRF_ROADSTOPS, 2)), NSL("", SLEG_CONDVAR_X(_num_roadstop_custom_tiles, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_GRF_ROADSTOPS, 2))),
}; };
static OldPersistentStorage _old_st_persistent_storage; void IncludeBaseStationDescription(std::vector<SaveLoad> &slt)
{
static const SaveLoad _station_desc[] = { SlFilterNamedSaveLoadTable(_base_station_desc, slt);
SLE_WRITEBYTE(Station, facilities), }
SLE_ST_INCLUDE(),
SLE_VAR(Station, train_station.tile, SLE_UINT32),
SLE_VAR(Station, train_station.w, SLE_FILE_U8 | SLE_VAR_U16),
SLE_VAR(Station, train_station.h, SLE_FILE_U8 | SLE_VAR_U16),
SLE_REF(Station, bus_stops, REF_ROADSTOPS),
SLE_REF(Station, truck_stops, REF_ROADSTOPS),
SLE_CONDVAR_X(Station, ship_station.tile, SLE_UINT32, SL_MIN_VERSION, SLV_MULTITILE_DOCKS, SlXvFeatureTest(XSLFTO_AND, XSLFI_MULTIPLE_DOCKS, 0, 0)),
SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_MULTIPLE_DOCKS, 1, 1)),
SLE_CONDVAR(Station, ship_station.tile, SLE_UINT32, SLV_MULTITILE_DOCKS, SL_MAX_VERSION),
SLE_CONDVAR(Station, ship_station.w, SLE_FILE_U8 | SLE_VAR_U16, SLV_MULTITILE_DOCKS, SL_MAX_VERSION),
SLE_CONDVAR(Station, ship_station.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_MULTITILE_DOCKS, SL_MAX_VERSION),
SLE_CONDVAR(Station, docking_station.tile, SLE_UINT32, SLV_MULTITILE_DOCKS, SL_MAX_VERSION),
SLE_CONDVAR(Station, docking_station.w, SLE_FILE_U8 | SLE_VAR_U16, SLV_MULTITILE_DOCKS, SL_MAX_VERSION),
SLE_CONDVAR(Station, docking_station.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_MULTITILE_DOCKS, SL_MAX_VERSION),
SLE_CONDVARVEC_X(Station, docking_tiles, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_MULTIPLE_DOCKS, 2)),
SLE_VAR(Station, airport.tile, SLE_UINT32),
SLE_CONDVAR(Station, airport.w, SLE_FILE_U8 | SLE_VAR_U16, SLV_140, SL_MAX_VERSION),
SLE_CONDVAR(Station, airport.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_140, SL_MAX_VERSION),
SLE_VAR(Station, airport.type, SLE_UINT8),
SLE_CONDVAR(Station, airport.layout, SLE_UINT8, SLV_145, SL_MAX_VERSION),
SLE_CONDNULL_X(1, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SPRINGPP, 1, 6)),
SLE_VAR(Station, airport.flags, SLE_UINT64),
SLE_CONDNULL_X(8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SPRINGPP, 1, 6)),
SLE_CONDVAR(Station, airport.rotation, SLE_UINT8, SLV_145, SL_MAX_VERSION),
SLEG_CONDARR(_old_st_persistent_storage.storage, SLE_UINT32, 16, SLV_145, SLV_161),
SLE_CONDREF(Station, airport.psa, REF_STORAGE, SLV_161, SL_MAX_VERSION),
SLE_VAR(Station, indtype, SLE_UINT8),
SLE_CONDVAR_X(Station, extra_name_index, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_EXTRA_STATION_NAMES)),
SLE_VAR(Station, time_since_load, SLE_UINT8),
SLE_VAR(Station, time_since_unload, SLE_UINT8),
SLEG_CONDVAR_X(_old_last_vehicle_type, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ST_LAST_VEH_TYPE, 0, 0)),
SLE_CONDNULL_X(1, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP)),
SLE_VAR(Station, had_vehicle_of_type, SLE_UINT8),
SLE_VEC(Station, loading_vehicles, REF_VEHICLE),
SLE_CONDVAR(Station, always_accepted, SLE_FILE_U32 | SLE_VAR_U64, SLV_127, SLV_EXTEND_CARGOTYPES),
SLE_CONDVAR(Station, always_accepted, SLE_UINT64, SLV_EXTEND_CARGOTYPES, SL_MAX_VERSION),
SLE_CONDNULL_X(32 * 24, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP, SL_JOKER_1_22)),
SLE_CONDVAR_X(Station, station_cargo_history_cargoes, SLE_UINT64, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_STATION_CARGO_HISTORY)),
};
static const SaveLoad _waypoint_desc[] = { struct BaseStationStructHandler final : public TypedSaveLoadStructHandler<BaseStationStructHandler, BaseStation> {
SLE_WRITEBYTE(Waypoint, facilities), NamedSaveLoadTable GetDescription() const override
SLE_ST_INCLUDE(), {
return _base_station_desc;
}
SLE_VAR(Waypoint, town_cn, SLE_UINT16), void Save(BaseStation *bst) const override
{
SlObjectSaveFiltered(bst, this->GetLoadDescription());
}
SLE_CONDVAR(Waypoint, train_station.tile, SLE_UINT32, SLV_124, SL_MAX_VERSION), void Load(BaseStation *bst) const override
SLE_CONDVAR(Waypoint, train_station.w, SLE_FILE_U8 | SLE_VAR_U16, SLV_124, SL_MAX_VERSION), {
SLE_CONDVAR(Waypoint, train_station.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_124, SL_MAX_VERSION), SlObjectLoadFiltered(bst, this->GetLoadDescription());
SLE_CONDVAR_X(Waypoint, waypoint_flags, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_WAYPOINT_FLAGS)), }
SLE_CONDVAR_X(Waypoint, road_waypoint_area.tile, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ROAD_WAYPOINTS)),
SLE_CONDVAR_X(Waypoint, road_waypoint_area.w, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ROAD_WAYPOINTS)),
SLE_CONDVAR_X(Waypoint, road_waypoint_area.h, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ROAD_WAYPOINTS)),
}; };
static const SaveLoad _custom_roadstop_tile_data_desc[] = { static const NamedSaveLoad _station_cargo_history_desc[] = {
SLE_VAR(RoadStopTileData, tile, SLE_UINT32), NSL("cargoes", SLTAG(SLTAG_CUSTOM_0, SLE_CONDVAR_X(Station, station_cargo_history_cargoes, SLE_UINT64, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_STATION_CARGO_HISTORY)))),
SLE_VAR(RoadStopTileData, random_bits, SLE_UINT8), NSL("history", SLTAG(SLTAG_CUSTOM_1, SLEG_CONDVARVEC_X(_station_history_data_dummy, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_STATION_CARGO_HISTORY)))),
SLE_VAR(RoadStopTileData, animation_frame, SLE_UINT8),
}; };
/** static void LoadStationCargoHistoryData(Station *st)
* Get the base station description to be used for SL_ST_INCLUDE
* @return the base station description.
*/
SaveLoadTable GetBaseStationDescription()
{ {
return _base_station_desc; uint16_t *data = st->station_cargo_history[0].data();
ReadBuffer::GetCurrent()->ReadUint16sToHandler(st->station_cargo_history.size() * MAX_STATION_CARGO_HISTORY_DAYS, [&](uint16_t val) {
*data = val;
data++;
});
if (SlXvIsFeaturePresent(XSLFI_STATION_CARGO_HISTORY, 1, 1)) {
for (auto &history : st->station_cargo_history) {
for (uint16_t &amount : history) {
amount = RXCompressUint(amount);
}
}
}
st->station_cargo_history_offset = 0;
} }
std::vector<SaveLoad> _filtered_station_desc; struct StationGoodsStructHandler final : public TypedSaveLoadStructHandler<StationGoodsStructHandler, Station> {
std::vector<SaveLoad> _filtered_waypoint_desc; mutable std::unique_ptr<GoodsEntryData> spare_ged;
std::vector<SaveLoad> _filtered_goods_desc;
std::vector<SaveLoad> _filtered_station_speclist_desc;
std::vector<SaveLoad> _filtered_roadstop_speclist_desc;
static void SetupDescs_STNN() NamedSaveLoadTable GetDescription() const override
{ {
_filtered_station_desc = SlFilterObject(_station_desc); return GetGoodsDesc();
_filtered_waypoint_desc = SlFilterObject(_waypoint_desc);
_filtered_goods_desc = SlFilterObject(GetGoodsDesc());
_filtered_station_speclist_desc = SlFilterObject(_station_speclist_desc);
_filtered_roadstop_speclist_desc = SlFilterObject(_roadstop_speclist_desc);
} }
static void RealSave_STNN(BaseStation *bst) void Save(Station *st) const override
{ {
_num_specs = (uint8_t)bst->speclist.size(); SlSetStructListLength(NUM_CARGO);
_num_roadstop_specs = (uint8_t)bst->roadstop_speclist.size();
_num_roadstop_custom_tiles = (uint32_t)bst->custom_roadstop_tile_data.size();
bool waypoint = (bst->facilities & FACIL_WAYPOINT) != 0; for (GoodsEntry &ge : st->goods) {
SlObjectSaveFiltered(bst, waypoint ? SaveLoadTable(_filtered_waypoint_desc) : SaveLoadTable(_filtered_station_desc)); SlObjectSaveFiltered(&ge, this->GetLoadDescription());
}
}
MemoryDumper *dumper = MemoryDumper::GetCurrent(); void Load(Station *st) const override
{
uint num_cargo = static_cast<uint>(SlGetStructListLength(NUM_CARGO));
if (!waypoint) { for (CargoID i = 0; i < num_cargo; i++) {
Station *st = Station::From(bst); GoodsEntry &ge = st->goods[i];
for (CargoID i = 0; i < NUM_CARGO; i++) { if (ge.data == nullptr) {
const GoodsEntryData *ged = st->goods[i].data.get(); if (this->spare_ged != nullptr) {
if (ged != nullptr) { ge.data = std::move(this->spare_ged);
_cargo_reserved_count = ged->cargo.ReservedCount();
_num_dests = (uint32_t)ged->cargo.Packets()->MapSize();
_num_flows = (uint32_t)ged->flows.size();
} else { } else {
_cargo_reserved_count = 0; ge.data.reset(new GoodsEntryData());
_num_dests = 0;
_num_flows = 0;
} }
SlObjectSaveFiltered(&st->goods[i], _filtered_goods_desc);
if (ged == nullptr) continue;
for (FlowStatMap::const_iterator outer_it(ged->flows.begin()); outer_it != ged->flows.end(); ++outer_it) {
uint32_t sum_shares = 0;
FlowSaveLoad flow;
flow.source = outer_it->GetOrigin();
dumper->CheckBytes(2 + 4);
dumper->RawWriteUint16(flow.source);
dumper->RawWriteUint32((uint32_t)outer_it->size());
FlowStat::const_iterator inner_it(outer_it->begin());
const FlowStat::const_iterator end(outer_it->end());
for (; inner_it != end; ++inner_it) {
flow.via = inner_it->second;
flow.share = inner_it->first - sum_shares;
flow.restricted = inner_it->first > outer_it->GetUnrestricted();
sum_shares = inner_it->first;
assert(flow.share > 0);
// SlObject(&flow, _flow_desc); /* this is highly performance-sensitive, manually unroll */
dumper->CheckBytes(2 + 4 + 1);
dumper->RawWriteUint16(flow.via);
dumper->RawWriteUint32(flow.share);
dumper->RawWriteByte(flow.restricted != 0);
} }
SlWriteUint16(outer_it->GetRawFlags()); SlObjectLoadFiltered(&ge, this->GetLoadDescription());
ge.data->cargo.LoadSetReservedCount(_cargo_reserved_count);
if (SlXvIsFeatureMissing(XSLFI_ST_LAST_VEH_TYPE)) ge.last_vehicle_type = _old_last_vehicle_type;
if (ge.data->MayBeRemoved()) {
this->spare_ged = std::move(ge.data);
}
} }
for (StationCargoPacketMap::ConstMapIterator it(ged->cargo.Packets()->begin()); it != ged->cargo.Packets()->end(); ++it) {
SlObjectSaveFiltered(const_cast<StationCargoPacketMap::value_type *>(&(*it)), _cargo_list_desc); // _cargo_list_desc has no conditionals
} }
};
struct StationCargoHistoryStructHandler final : public TypedSaveLoadStructHandler<StationCargoHistoryStructHandler, Station> {
NamedSaveLoadTable GetDescription() const override
{
return _station_cargo_history_desc;
} }
assert(st->station_cargo_history.size() == CountBits(st->station_cargo_history_cargoes)); void Save(Station *st) const override
{
MemoryDumper *dumper = MemoryDumper::GetCurrent();
SlWriteUint64(st->station_cargo_history_cargoes);
SlWriteSimpleGamma(st->station_cargo_history.size() * MAX_STATION_CARGO_HISTORY_DAYS);
dumper->CheckBytes(st->station_cargo_history.size() * MAX_STATION_CARGO_HISTORY_DAYS * 2); dumper->CheckBytes(st->station_cargo_history.size() * MAX_STATION_CARGO_HISTORY_DAYS * 2);
for (const auto &history : st->station_cargo_history) { for (const auto &history : st->station_cargo_history) {
uint i = st->station_cargo_history_offset; uint i = st->station_cargo_history_offset;
@ -578,40 +677,276 @@ static void RealSave_STNN(BaseStation *bst)
} }
} }
for (uint i = 0; i < bst->speclist.size(); i++) { void Load(Station *st) const override
SlObjectSaveFiltered(&bst->speclist[i], _filtered_station_speclist_desc); {
st->station_cargo_history_cargoes = SlReadUint64();
st->station_cargo_history.resize(CountBits(st->station_cargo_history_cargoes));
if (SlReadSimpleGamma() != st->station_cargo_history.size() * MAX_STATION_CARGO_HISTORY_DAYS) {
SlErrorCorrupt("Station cargo history data of wrong size");
}
LoadStationCargoHistoryData(st);
} }
for (uint i = 0; i < bst->roadstop_speclist.size(); i++) { void LoadedTableDescription() override
SlObjectSaveFiltered(&bst->roadstop_speclist[i], _filtered_roadstop_speclist_desc); {
SaveLoadTable slt = this->GetLoadDescription();
if (slt.size() != 2 || slt[0].label_tag != SLTAG_CUSTOM_0 || slt[1].label_tag != SLTAG_CUSTOM_1) {
SlErrorCorrupt("Station cargo history sub-chunk fields not as expected");
}
} }
};
for (uint i = 0; i < bst->custom_roadstop_tile_data.size(); i++) { static OldPersistentStorage _old_st_persistent_storage;
SlObjectSaveFiltered(&bst->custom_roadstop_tile_data[i], _custom_roadstop_tile_data_desc); // _custom_roadstop_tile_data_desc has no conditionals
static const NamedSaveLoad _station_desc[] = {
NSL("", SLE_WRITEBYTE(Station, facilities)),
NSL("", SLE_INCLUDE(IncludeBaseStationDescription)),
NSLT_STRUCT<BaseStationStructHandler>("base"),
NSL("train_station.tile", SLE_VAR(Station, train_station.tile, SLE_UINT32)),
NSL("train_station.w", SLE_VAR(Station, train_station.w, SLE_FILE_U8 | SLE_VAR_U16)),
NSL("train_station.h", SLE_VAR(Station, train_station.h, SLE_FILE_U8 | SLE_VAR_U16)),
NSL("bus_stops", SLE_REF(Station, bus_stops, REF_ROADSTOPS)),
NSL("truck_stops", SLE_REF(Station, truck_stops, REF_ROADSTOPS)),
NSL("ship_station.tile", SLE_CONDVAR_X(Station, ship_station.tile, SLE_UINT32, SL_MIN_VERSION, SLV_MULTITILE_DOCKS, SlXvFeatureTest(XSLFTO_AND, XSLFI_MULTIPLE_DOCKS, 0, 0))),
NSL("", SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_MULTIPLE_DOCKS, 1, 1))),
NSL("ship_station.tile", SLE_CONDVAR(Station, ship_station.tile, SLE_UINT32, SLV_MULTITILE_DOCKS, SL_MAX_VERSION)),
NSL("ship_station.w", SLE_CONDVAR(Station, ship_station.w, SLE_FILE_U8 | SLE_VAR_U16, SLV_MULTITILE_DOCKS, SL_MAX_VERSION)),
NSL("ship_station.h", SLE_CONDVAR(Station, ship_station.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_MULTITILE_DOCKS, SL_MAX_VERSION)),
NSL("docking_station.tile", SLE_CONDVAR(Station, docking_station.tile, SLE_UINT32, SLV_MULTITILE_DOCKS, SL_MAX_VERSION)),
NSL("docking_station.w", SLE_CONDVAR(Station, docking_station.w, SLE_FILE_U8 | SLE_VAR_U16, SLV_MULTITILE_DOCKS, SL_MAX_VERSION)),
NSL("docking_station.h", SLE_CONDVAR(Station, docking_station.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_MULTITILE_DOCKS, SL_MAX_VERSION)),
NSL("docking_tiles", SLE_CONDVARVEC_X(Station, docking_tiles, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_MULTIPLE_DOCKS, 2))),
NSL("airport.tile", SLE_VAR(Station, airport.tile, SLE_UINT32)),
NSL("airport.w", SLE_CONDVAR(Station, airport.w, SLE_FILE_U8 | SLE_VAR_U16, SLV_140, SL_MAX_VERSION)),
NSL("airport.h", SLE_CONDVAR(Station, airport.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_140, SL_MAX_VERSION)),
NSL("airport.type", SLE_VAR(Station, airport.type, SLE_UINT8)),
NSL("airport.layout", SLE_CONDVAR(Station, airport.layout, SLE_UINT8, SLV_145, SL_MAX_VERSION)),
NSL("", SLE_CONDNULL_X(1, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SPRINGPP, 1, 6))),
NSL("airport.flags", SLE_VAR(Station, airport.flags, SLE_UINT64)),
NSL("", SLE_CONDNULL_X(8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SPRINGPP, 1, 6))),
NSL("airport.rotation", SLE_CONDVAR(Station, airport.rotation, SLE_UINT8, SLV_145, SL_MAX_VERSION)),
NSL("", SLEG_CONDARR(_old_st_persistent_storage.storage, SLE_UINT32, 16, SLV_145, SLV_161)),
NSL("irport.psa", SLE_CONDREF(Station, airport.psa, REF_STORAGE, SLV_161, SL_MAX_VERSION)),
NSL("indtype", SLE_VAR(Station, indtype, SLE_UINT8)),
NSL("extra_name_index", SLE_CONDVAR_X(Station, extra_name_index, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_EXTRA_STATION_NAMES))),
NSL("time_since_load", SLE_VAR(Station, time_since_load, SLE_UINT8)),
NSL("time_since_unload", SLE_VAR(Station, time_since_unload, SLE_UINT8)),
NSL("", SLEG_CONDVAR_X(_old_last_vehicle_type, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ST_LAST_VEH_TYPE, 0, 0))),
NSL("", SLE_CONDNULL_X(1, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP))),
NSL("had_vehicle_of_type", SLE_VAR(Station, had_vehicle_of_type, SLE_UINT8)),
NSL("loading_vehicles", SLE_VEC(Station, loading_vehicles, REF_VEHICLE)),
NSL("always_accepted", SLE_CONDVAR(Station, always_accepted, SLE_FILE_U32 | SLE_VAR_U64, SLV_127, SLV_EXTEND_CARGOTYPES)),
NSL("always_accepted", SLE_CONDVAR(Station, always_accepted, SLE_UINT64, SLV_EXTEND_CARGOTYPES, SL_MAX_VERSION)),
NSL("", SLE_CONDNULL_X(32 * 24, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP, SL_JOKER_1_22))),
NSL("", SLE_CONDVAR_X(Station, station_cargo_history_cargoes, SLE_UINT64, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_STATION_CARGO_HISTORY))),
NSLT_STRUCTLIST<StationGoodsStructHandler>("goods"),
NSLT_STRUCT<StationCargoHistoryStructHandler>("cargo_history"),
};
static const NamedSaveLoad _waypoint_desc[] = {
NSL("", SLE_WRITEBYTE(Waypoint, facilities)),
NSL("", SLE_INCLUDE(IncludeBaseStationDescription)),
NSLT_STRUCT<BaseStationStructHandler>("base"),
NSL("town_cn", SLE_VAR(Waypoint, town_cn, SLE_UINT16)),
NSL("train_station.tile", SLE_CONDVAR(Waypoint, train_station.tile, SLE_UINT32, SLV_124, SL_MAX_VERSION)),
NSL("train_station.w", SLE_CONDVAR(Waypoint, train_station.w, SLE_FILE_U8 | SLE_VAR_U16, SLV_124, SL_MAX_VERSION)),
NSL("train_station.h", SLE_CONDVAR(Waypoint, train_station.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_124, SL_MAX_VERSION)),
NSL("waypoint_flags", SLE_CONDVAR_X(Waypoint, waypoint_flags, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_WAYPOINT_FLAGS))),
NSL("road_waypoint_area.tile", SLE_CONDVAR_X(Waypoint, road_waypoint_area.tile, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ROAD_WAYPOINTS))),
NSL("road_waypoint_area.w", SLE_CONDVAR_X(Waypoint, road_waypoint_area.w, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ROAD_WAYPOINTS))),
NSL("road_waypoint_area.h", SLE_CONDVAR_X(Waypoint, road_waypoint_area.h, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ROAD_WAYPOINTS))),
};
static const NamedSaveLoad _custom_roadstop_tile_data_desc[] = {
NSL("tile", SLE_VAR(RoadStopTileData, tile, SLE_UINT32)),
NSL("random_bits", SLE_VAR(RoadStopTileData, random_bits, SLE_UINT8)),
NSL("animation_frame", SLE_VAR(RoadStopTileData, animation_frame, SLE_UINT8)),
};
class StationSpecListStructHandler final : public TypedSaveLoadStructHandler<StationSpecListStructHandler, BaseStation> {
public:
NamedSaveLoadTable GetDescription() const override
{
return _station_speclist_desc;
}
void Save(BaseStation *bst) const override
{
SlSetStructListLength(bst->speclist.size());
for (StationSpecList &spec : bst->speclist) {
SlObjectSaveFiltered(&spec, this->GetLoadDescription());
}
}
void Load(BaseStation *bst) const override
{
bst->speclist.resize(SlGetStructListLength(UINT8_MAX));
for (StationSpecList &spec : bst->speclist) {
SlObjectLoadFiltered(&spec, this->GetLoadDescription());
}
}
};
class RoadStopSpecListStructHandler final : public TypedSaveLoadStructHandler<RoadStopSpecListStructHandler, BaseStation> {
public:
NamedSaveLoadTable GetDescription() const override
{
return _roadstop_speclist_desc;
}
void Save(BaseStation *bst) const override
{
SlSetStructListLength(bst->roadstop_speclist.size());
for (RoadStopSpecList &spec : bst->roadstop_speclist) {
SlObjectSaveFiltered(&spec, this->GetLoadDescription());
}
}
void Load(BaseStation *bst) const override
{
bst->roadstop_speclist.resize(SlGetStructListLength(UINT8_MAX));
for (RoadStopSpecList &spec : bst->roadstop_speclist) {
SlObjectLoadFiltered(&spec, this->GetLoadDescription());
}
}
};
class RoadStopTileDataStructHandler final : public TypedSaveLoadStructHandler<RoadStopTileDataStructHandler, BaseStation> {
public:
NamedSaveLoadTable GetDescription() const override
{
return _custom_roadstop_tile_data_desc;
}
void Save(BaseStation *bst) const override
{
SlSetStructListLength(bst->custom_roadstop_tile_data.size());
for (RoadStopTileData &data : bst->custom_roadstop_tile_data) {
SlObjectSaveFiltered(&data, this->GetLoadDescription());
}
}
void Load(BaseStation *bst) const override
{
bst->custom_roadstop_tile_data.resize(SlGetStructListLength(UINT32_MAX));
for (RoadStopTileData &data : bst->custom_roadstop_tile_data) {
SlObjectLoadFiltered(&data, this->GetLoadDescription());
}
}
};
struct NormalStationStructHandler final : public TypedSaveLoadStructHandler<NormalStationStructHandler, BaseStation> {
NamedSaveLoadTable GetDescription() const override
{
return _station_desc;
}
void Save(BaseStation *bst) const override
{
if ((bst->facilities & FACIL_WAYPOINT) != 0) return;
SlObjectSaveFiltered(static_cast<Station *>(bst), this->GetLoadDescription());
}
void Load(BaseStation *bst) const override
{
if ((bst->facilities & FACIL_WAYPOINT) != 0) SlErrorCorrupt("Waypoint with normal station struct");
SlObjectLoadFiltered(static_cast<Station *>(bst), this->GetLoadDescription());
}
};
struct WaypointStructHandler final : public TypedSaveLoadStructHandler<WaypointStructHandler, BaseStation> {
NamedSaveLoadTable GetDescription() const override
{
return _waypoint_desc;
}
void Save(BaseStation *bst) const override
{
if ((bst->facilities & FACIL_WAYPOINT) == 0) return;
SlObjectSaveFiltered(static_cast<Waypoint *>(bst), this->GetLoadDescription());
} }
void Load(BaseStation *bst) const override
{
if ((bst->facilities & FACIL_WAYPOINT) == 0) SlErrorCorrupt("Normal station with waypoint struct");
SlObjectLoadFiltered(static_cast<Waypoint *>(bst), this->GetLoadDescription());
} }
};
static const NamedSaveLoad _table_station_desc[] = {
NSLT("facilities", SLE_WRITEBYTE(BaseStation, facilities)),
NSLT_STRUCT<NormalStationStructHandler>("normal"),
NSLT_STRUCT<WaypointStructHandler>("waypoint"),
NSLT_STRUCTLIST<StationSpecListStructHandler>("speclist"),
NSLT_STRUCTLIST<RoadStopSpecListStructHandler>("roadstopspeclist"),
NSLT_STRUCTLIST<RoadStopTileDataStructHandler>("roadstoptiledata"),
};
static void Save_STNN() static void Save_STNN()
{ {
SetupDescs_STNN(); SaveLoadTableData slt = SlTableHeader(_table_station_desc);
/* Write the stations */ /* Write the stations */
for (BaseStation *st : BaseStation::Iterate()) { for (BaseStation *st : BaseStation::Iterate()) {
SlSetArrayIndex(st->index); SlSetArrayIndex(st->index);
SlAutolength(RealSave_STNN, st); SlObjectSaveFiltered(st, slt);
} }
} }
static void Load_STNN() static void PostLoadStation_STNN(BaseStation *bst)
{
if (SlXvIsFeaturePresent(XSLFI_GRF_ROADSTOPS, 1, 1)) {
for (size_t i = 0; i < _custom_road_stop_tiles.size(); i++) {
bst->custom_roadstop_tile_data.push_back({ _custom_road_stop_tiles[i], (uint8_t)GB(_custom_road_stop_data[i], 0, 8), (uint8_t)GB(_custom_road_stop_data[i], 8, 8) });
}
_custom_road_stop_tiles.clear();
_custom_road_stop_data.clear();
}
}
static void Load_STNN_table()
{ {
SetupDescs_STNN(); SaveLoadTableData slt = SlTableHeaderOrRiff(_table_station_desc);
int index;
while ((index = SlIterateArray()) != -1) {
bool waypoint = (SlReadByte() & FACIL_WAYPOINT) != 0;
BaseStation *bst = waypoint ? (BaseStation *)new (index) Waypoint() : new (index) Station();
SlObjectLoadFiltered(bst, slt);
PostLoadStation_STNN(bst);
}
}
static void Load_STNN()
{
_num_flows = 0; _num_flows = 0;
_num_specs = 0; _num_specs = 0;
_num_roadstop_specs = 0; _num_roadstop_specs = 0;
_num_roadstop_custom_tiles = 0; _num_roadstop_custom_tiles = 0;
_cargo_reserved_count = 0; _cargo_reserved_count = 0;
if (SlIsTableChunk()) {
Load_STNN_table();
return;
}
std::vector<SaveLoad> filtered_station_desc = SlFilterNamedSaveLoadTable(_station_desc);
std::vector<SaveLoad> filtered_waypoint_desc = SlFilterNamedSaveLoadTable(_waypoint_desc);
std::vector<SaveLoad> filtered_goods_desc = SlFilterNamedSaveLoadTable(GetGoodsDesc());
std::vector<SaveLoad> cargo_list_desc = SlFilterNamedSaveLoadTable(_cargo_list_desc);
std::vector<SaveLoad> filtered_station_speclist_desc = SlFilterNamedSaveLoadTable(_station_speclist_desc);
std::vector<SaveLoad> filtered_roadstop_speclist_desc = SlFilterNamedSaveLoadTable(_roadstop_speclist_desc);
std::vector<SaveLoad> custom_roadstop_tile_data_desc = SlFilterNamedSaveLoadTable(_custom_roadstop_tile_data_desc);
std::unique_ptr<GoodsEntryData> spare_ged; std::unique_ptr<GoodsEntryData> spare_ged;
const uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO; const uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO;
@ -622,7 +957,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();
SlObjectLoadFiltered(bst, waypoint ? SaveLoadTable(_filtered_waypoint_desc) : SaveLoadTable(_filtered_station_desc)); SlObjectLoadFiltered(bst, waypoint ? SaveLoadTable(filtered_waypoint_desc) : SaveLoadTable(filtered_station_desc));
if (!waypoint) { if (!waypoint) {
Station *st = Station::From(bst); Station *st = Station::From(bst);
@ -644,7 +979,7 @@ static void Load_STNN()
ge.data.reset(new GoodsEntryData()); ge.data.reset(new GoodsEntryData());
} }
} }
SlObjectLoadFiltered(&ge, _filtered_goods_desc); SlObjectLoadFiltered(&ge, filtered_goods_desc);
ge.data->cargo.LoadSetReservedCount(_cargo_reserved_count); ge.data->cargo.LoadSetReservedCount(_cargo_reserved_count);
StationID prev_source = INVALID_STATION; StationID prev_source = INVALID_STATION;
if (SlXvIsFeaturePresent(XSLFI_FLOW_STAT_FLAGS)) { if (SlXvIsFeaturePresent(XSLFI_FLOW_STAT_FLAGS)) {
@ -702,7 +1037,7 @@ static void Load_STNN()
StationCargoPair pair; StationCargoPair pair;
for (uint j = 0; j < _num_dests; ++j) { for (uint j = 0; j < _num_dests; ++j) {
SlObjectLoadFiltered(&pair, _cargo_list_desc); // _cargo_list_desc has no conditionals SlObjectLoadFiltered(&pair, cargo_list_desc);
const_cast<StationCargoPacketMap &>(*(ge.data->cargo.Packets()))[pair.first].swap(pair.second); const_cast<StationCargoPacketMap &>(*(ge.data->cargo.Packets()))[pair.first].swap(pair.second);
assert(pair.second.empty()); assert(pair.second.empty());
} }
@ -714,27 +1049,14 @@ static void Load_STNN()
} }
st->station_cargo_history.resize(CountBits(st->station_cargo_history_cargoes)); st->station_cargo_history.resize(CountBits(st->station_cargo_history_cargoes));
buffer->CheckBytes(st->station_cargo_history.size() * MAX_STATION_CARGO_HISTORY_DAYS * 2); LoadStationCargoHistoryData(st);
for (auto &history : st->station_cargo_history) {
for (uint16_t &amount : history) {
amount = buffer->RawReadUint16();
}
}
if (SlXvIsFeaturePresent(XSLFI_STATION_CARGO_HISTORY, 1, 1)) {
for (auto &history : st->station_cargo_history) {
for (uint16_t &amount : history) {
amount = RXCompressUint(amount);
}
}
}
st->station_cargo_history_offset = 0;
} }
if (_num_specs != 0) { if (_num_specs != 0) {
/* Allocate speclist memory when loading a game */ /* Allocate speclist memory when loading a game */
bst->speclist.resize(_num_specs); bst->speclist.resize(_num_specs);
for (uint i = 0; i < bst->speclist.size(); i++) { for (uint i = 0; i < bst->speclist.size(); i++) {
SlObjectLoadFiltered(&bst->speclist[i], _filtered_station_speclist_desc); SlObjectLoadFiltered(&bst->speclist[i], filtered_station_speclist_desc);
} }
} }
@ -742,7 +1064,7 @@ static void Load_STNN()
/* Allocate speclist memory when loading a game */ /* Allocate speclist memory when loading a game */
bst->roadstop_speclist.resize(_num_roadstop_specs); bst->roadstop_speclist.resize(_num_roadstop_specs);
for (uint i = 0; i < bst->roadstop_speclist.size(); i++) { for (uint i = 0; i < bst->roadstop_speclist.size(); i++) {
SlObjectLoadFiltered(&bst->roadstop_speclist[i], _filtered_roadstop_speclist_desc); SlObjectLoadFiltered(&bst->roadstop_speclist[i], filtered_roadstop_speclist_desc);
} }
} }
@ -750,17 +1072,11 @@ static void Load_STNN()
/* Allocate custom road stop tile data memory when loading a game */ /* Allocate custom road stop tile data memory when loading a game */
bst->custom_roadstop_tile_data.resize(_num_roadstop_custom_tiles); bst->custom_roadstop_tile_data.resize(_num_roadstop_custom_tiles);
for (uint i = 0; i < bst->custom_roadstop_tile_data.size(); i++) { for (uint i = 0; i < bst->custom_roadstop_tile_data.size(); i++) {
SlObjectLoadFiltered(&bst->custom_roadstop_tile_data[i], _custom_roadstop_tile_data_desc); // _custom_roadstop_tile_data_desc has no conditionals SlObjectLoadFiltered(&bst->custom_roadstop_tile_data[i], custom_roadstop_tile_data_desc);
} }
} }
if (SlXvIsFeaturePresent(XSLFI_GRF_ROADSTOPS, 1, 1)) { PostLoadStation_STNN(bst);
for (size_t i = 0; i < _custom_road_stop_tiles.size(); i++) {
bst->custom_roadstop_tile_data.push_back({ _custom_road_stop_tiles[i], (uint8_t)GB(_custom_road_stop_data[i], 0, 8), (uint8_t)GB(_custom_road_stop_data[i], 8, 8) });
}
_custom_road_stop_tiles.clear();
_custom_road_stop_data.clear();
}
} }
} }
@ -769,10 +1085,13 @@ 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(); std::vector<SaveLoad> filtered_station_desc = SlFilterNamedSaveLoadTable(_station_desc);
std::vector<SaveLoad> filtered_waypoint_desc = SlFilterNamedSaveLoadTable(_waypoint_desc);
std::vector<SaveLoad> filtered_goods_desc = SlFilterNamedSaveLoadTable(GetGoodsDesc());
std::vector<SaveLoad> cargolist_desc = SlFilterNamedSaveLoadTable(_cargo_list_desc);
if (!IsSavegameVersionBefore(SLV_183)) { if (!IsSavegameVersionBefore(SLV_183)) {
assert(_filtered_goods_desc.size() == 0); assert(filtered_goods_desc.size() == 0);
} }
uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO; uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO;
@ -781,22 +1100,22 @@ static void Ptrs_STNN()
GoodsEntry *ge = &st->goods[i]; GoodsEntry *ge = &st->goods[i];
if (IsSavegameVersionBefore(SLV_183) && SlXvIsFeatureMissing(XSLFI_CHILLPP)) { if (IsSavegameVersionBefore(SLV_183) && SlXvIsFeatureMissing(XSLFI_CHILLPP)) {
SwapPackets(ge); SwapPackets(ge);
SlObjectPtrOrNullFiltered(ge, _filtered_goods_desc); SlObjectPtrOrNullFiltered(ge, filtered_goods_desc);
SwapPackets(ge); SwapPackets(ge);
} else { } else {
//SlObject(ge, GetGoodsDesc()); //SlObject(ge, GetGoodsDesc());
if (ge->data != nullptr) { if (ge->data != nullptr) {
for (StationCargoPacketMap::ConstMapIterator it = ge->data->cargo.Packets()->begin(); it != ge->data->cargo.Packets()->end(); ++it) { for (StationCargoPacketMap::ConstMapIterator it = ge->data->cargo.Packets()->begin(); it != ge->data->cargo.Packets()->end(); ++it) {
SlObjectPtrOrNullFiltered(const_cast<StationCargoPair *>(&(*it)), _cargo_list_desc); // _cargo_list_desc has no conditionals SlObjectPtrOrNullFiltered(const_cast<StationCargoPair *>(&(*it)), cargolist_desc);
} }
} }
} }
} }
SlObjectPtrOrNullFiltered(st, _filtered_station_desc); SlObjectPtrOrNullFiltered(st, filtered_station_desc);
} }
for (Waypoint *wp : Waypoint::Iterate()) { for (Waypoint *wp : Waypoint::Iterate()) {
SlObjectPtrOrNullFiltered(wp, _filtered_waypoint_desc); SlObjectPtrOrNullFiltered(wp, filtered_waypoint_desc);
} }
} }
@ -808,7 +1127,7 @@ static void Load_DOCK()
static const ChunkHandler station_chunk_handlers[] = { static const ChunkHandler station_chunk_handlers[] = {
{ 'STNS', nullptr, Load_STNS, Ptrs_STNS, nullptr, CH_READONLY }, { 'STNS', nullptr, Load_STNS, Ptrs_STNS, nullptr, CH_READONLY },
{ 'STNN', Save_STNN, Load_STNN, Ptrs_STNN, nullptr, CH_ARRAY }, { 'STNN', Save_STNN, Load_STNN, Ptrs_STNN, nullptr, CH_TABLE },
MakeUpstreamChunkHandler<'ROAD', GeneralUpstreamChunkLoadInfo>(), MakeUpstreamChunkHandler<'ROAD', GeneralUpstreamChunkLoadInfo>(),
{ 'DOCK', nullptr, Load_DOCK, nullptr, nullptr, CH_READONLY }, { 'DOCK', nullptr, Load_DOCK, nullptr, nullptr, CH_READONLY },
}; };

Loading…
Cancel
Save