From 4600d289b5d12389137d36e57bfda09c26ed6caf Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Tue, 8 Jun 2021 13:21:31 +0200 Subject: [PATCH 01/20] Codechange: ability to store structs and list of structs in savegames The commits following this will use this new functionality. Currently, a few places do this manually. This has as drawback that the Save() and Load() code need to be in sync, and that any change can result in (old) savegames no longer loading. In general, it is annoying code to maintain. By putting everything in a description table, and use that for both Save() and Load(), it becomes easier to see what is going on, and hopefully less likely for people to make mistakes. --- src/saveload/saveload.cpp | 55 ++++++++++++++++-- src/saveload/saveload.h | 119 ++++++++++++++++++++++++++++++++++---- src/settings.cpp | 2 +- 3 files changed, 157 insertions(+), 19 deletions(-) diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index f9abac3baf..6be86a7acd 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -1450,6 +1450,27 @@ size_t SlCalcObjMemberLength(const void *object, const SaveLoad &sld) case SL_WRITEBYTE: return 1; // a byte is logically of size 1 case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END)); case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription()); + case SL_STRUCT: + case SL_STRUCTLIST: { + if (!SlIsObjectValidInSavegame(sld)) break; + + NeedLength old_need_length = _sl.need_length; + size_t old_obj_len = _sl.obj_len; + + _sl.need_length = NL_CALCLENGTH; + _sl.obj_len = 0; + + /* Pretend that we are saving to collect the object size. Other + * means are difficult, as we don't know the length of the list we + * are about to store. */ + sld.handler->Save(const_cast(object)); + size_t length = _sl.obj_len; + + _sl.obj_len = old_obj_len; + _sl.need_length = old_need_length; + + return length; + } default: NOT_REACHED(); } return 0; @@ -1505,8 +1526,6 @@ size_t SlCalcObjMemberLength(const void *object, const SaveLoad &sld) static bool SlObjectMember(void *object, const SaveLoad &sld) { - void *ptr = GetVariableAddress(object, sld); - assert(IsVariableSizeRight(sld)); VarType conv = GB(sld.conv, 0, 8); @@ -1517,10 +1536,12 @@ static bool SlObjectMember(void *object, const SaveLoad &sld) case SL_STR: case SL_REFLIST: case SL_DEQUE: - case SL_STDSTR: + case SL_STDSTR: { /* CONDITIONAL saveload types depend on the savegame version */ if (!SlIsObjectValidInSavegame(sld)) return false; + void *ptr = GetVariableAddress(object, sld); + switch (sld.cmd) { case SL_VAR: SlSaveLoadConv(ptr, conv); break; case SL_REF: SlSaveLoadRef(ptr, conv); break; @@ -1532,11 +1553,14 @@ static bool SlObjectMember(void *object, const SaveLoad &sld) default: NOT_REACHED(); } break; + } /* SL_WRITEBYTE writes a value to the savegame to identify the type of an object. * When loading, the value is read explicitly with SlReadByte() to determine which * object description to use. */ - case SL_WRITEBYTE: + case SL_WRITEBYTE: { + void *ptr = GetVariableAddress(object, sld); + switch (_sl.action) { case SLA_SAVE: SlWriteByte(*(uint8 *)ptr); break; case SLA_LOAD_CHECK: @@ -1546,15 +1570,34 @@ static bool SlObjectMember(void *object, const SaveLoad &sld) default: NOT_REACHED(); } break; + } /* SL_VEH_INCLUDE loads common code for vehicles */ - case SL_VEH_INCLUDE: + case SL_VEH_INCLUDE: { + void *ptr = GetVariableAddress(object, sld); SlObject(ptr, GetVehicleDescription(VEH_END)); break; + } - case SL_ST_INCLUDE: + case SL_ST_INCLUDE: { + void *ptr = GetVariableAddress(object, sld); SlObject(ptr, GetBaseStationDescription()); break; + } + + case SL_STRUCT: + case SL_STRUCTLIST: + if (!SlIsObjectValidInSavegame(sld)) return false; + + switch (_sl.action) { + case SLA_SAVE: sld.handler->Save(object); break; + case SLA_LOAD_CHECK: sld.handler->LoadCheck(object); break; + case SLA_LOAD: sld.handler->Load(object); break; + case SLA_PTRS: sld.handler->FixPointers(object); break; + case SLA_NULL: break; + default: NOT_REACHED(); + } + break; default: NOT_REACHED(); } diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index 28af1fd37d..ff0982569b 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -400,6 +400,73 @@ struct ChunkHandler { /** A table of ChunkHandler entries. */ using ChunkHandlerTable = span; +/** A table of SaveLoad entries. */ +using SaveLoadTable = span; + +/** Handler for saving/loading an object to/from disk. */ +class SaveLoadHandler { +public: + virtual ~SaveLoadHandler() {} + + /** + * Save the object to disk. + * @param object The object to store. + */ + virtual void Save(void *object) const {} + + /** + * Load the object from disk. + * @param object The object to load. + */ + virtual void Load(void *object) const {} + + /** + * Similar to load, but used only to validate savegames. + * @param object The object to load. + */ + virtual void LoadCheck(void *object) const {} + + /** + * A post-load callback to fix #SL_REF integers into pointers. + * @param object The object to fix. + */ + virtual void FixPointers(void *object) const {} + + /** + * Get the description of the fields in the savegame. + */ + virtual SaveLoadTable GetDescription() const = 0; +}; + +/** + * Default handler for saving/loading an object to/from disk. + * + * This handles a few common things for handlers, meaning the actual handler + * needs less code. + * + * Usage: class SlMine : public DefaultSaveLoadHandler {} + * + * @tparam TImpl The class initializing this template. + * @tparam TObject The class of the object using this SaveLoadHandler. + */ +template +class DefaultSaveLoadHandler : public SaveLoadHandler { +public: + SaveLoadTable GetDescription() const override { return static_cast(this)->description; } + + virtual void Save(TObject *object) const {} + void Save(void *object) const override { this->Save(static_cast(object)); } + + virtual void Load(TObject *object) const {} + void Load(void *object) const override { this->Load(static_cast(object)); } + + virtual void LoadCheck(TObject *object) const {} + void LoadCheck(void *object) const override { this->LoadCheck(static_cast(object)); } + + virtual void FixPointers(TObject *object) const {} + void FixPointers(void *object) const override { this->FixPointers(static_cast(object)); } +}; + /** Type of reference (#SLE_REF, #SLE_CONDREF). */ enum SLRefType { REF_ORDER = 0, ///< Load/save a reference to an order. @@ -501,10 +568,12 @@ enum SaveLoadType : byte { SL_REFLIST = 4, ///< Save/load a list of #SL_REF elements. SL_DEQUE = 5, ///< Save/load a deque of #SL_VAR elements. SL_STDSTR = 6, ///< Save/load a \c std::string. + SL_STRUCT = 7, ///< Save/load a struct. + SL_STRUCTLIST = 8, ///< Save/load a list of structs. /* non-normal save-load types */ - SL_WRITEBYTE = 8, - SL_VEH_INCLUDE = 9, - SL_ST_INCLUDE = 10, + SL_WRITEBYTE = 9, + SL_VEH_INCLUDE = 10, + SL_ST_INCLUDE = 11, }; typedef void *SaveLoadAddrProc(void *base, size_t extra); @@ -519,11 +588,9 @@ struct SaveLoad { size_t size; ///< the sizeof size. SaveLoadAddrProc *address_proc; ///< callback proc the get the actual variable address in memory size_t extra_data; ///< extra data for the callback proc + SaveLoadHandler *handler; ///< Custom handler for Save/Load procs. }; -/** A table of SaveLoad entries. */ -using SaveLoadTable = span; - /** * Storage of simple variables, references (pointers), and arrays. * @param cmd Load/save type. @see SaveLoadType @@ -535,7 +602,7 @@ using SaveLoadTable = span; * @param extra Extra data to pass to the address callback function. * @note In general, it is better to use one of the SLE_* macros below. */ -#define SLE_GENERAL(cmd, base, variable, type, length, from, to, extra) {cmd, type, length, from, to, cpp_sizeof(base, variable), [] (void *b, size_t) -> void * { assert(b != nullptr); return const_cast(static_cast(std::addressof(static_cast(b)->variable))); }, extra} +#define SLE_GENERAL(cmd, base, variable, type, length, from, to, extra) {cmd, type, length, from, to, cpp_sizeof(base, variable), [] (void *b, size_t) -> void * { assert(b != nullptr); return const_cast(static_cast(std::addressof(static_cast(b)->variable))); }, extra, nullptr} /** * Storage of a variable in some savegame versions. @@ -671,13 +738,13 @@ using SaveLoadTable = span; * @param from First savegame version that has the empty space. * @param to Last savegame version that has the empty space. */ -#define SLE_CONDNULL(length, from, to) {SL_ARR, SLE_FILE_U8 | SLE_VAR_NULL, length, from, to, 0, nullptr, 0} +#define SLE_CONDNULL(length, from, to) {SL_ARR, SLE_FILE_U8 | SLE_VAR_NULL, length, from, to, 0, nullptr, 0, nullptr} /** Translate values ingame to different values in the savegame and vv. */ #define SLE_WRITEBYTE(base, variable) SLE_GENERAL(SL_WRITEBYTE, base, variable, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION, 0) -#define SLE_VEH_INCLUDE() {SL_VEH_INCLUDE, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION, 0, [] (void *b, size_t) { return b; }, 0} -#define SLE_ST_INCLUDE() {SL_ST_INCLUDE, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION, 0, [] (void *b, size_t) { return b; }, 0} +#define SLE_VEH_INCLUDE() {SL_VEH_INCLUDE, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION, 0, [] (void *b, size_t) { return b; }, 0, nullptr} +#define SLE_ST_INCLUDE() {SL_ST_INCLUDE, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION, 0, [] (void *b, size_t) { return b; }, 0, nullptr} /** * Storage of global simple variables, references (pointers), and arrays. @@ -689,7 +756,7 @@ using SaveLoadTable = span; * @param extra Extra data to pass to the address callback function. * @note In general, it is better to use one of the SLEG_* macros below. */ -#define SLEG_GENERAL(cmd, variable, type, length, from, to, extra) {cmd, type, length, from, to, sizeof(variable), [] (void *, size_t) -> void * { return static_cast(std::addressof(variable)); }, extra} +#define SLEG_GENERAL(cmd, variable, type, length, from, to, extra) {cmd, type, length, from, to, sizeof(variable), [] (void *, size_t) -> void * { return static_cast(std::addressof(variable)); }, extra, nullptr} /** * Storage of a global variable in some savegame versions. @@ -738,6 +805,14 @@ using SaveLoadTable = span; */ #define SLEG_CONDSSTR(variable, type, from, to) SLEG_GENERAL(SL_STDSTR, variable, type, 0, from, to, 0) +/** + * Storage of a structs in some savegame versions. + * @param handler SaveLoadHandler for the structs. + * @param from First savegame version that has the struct. + * @param to Last savegame version that has the struct. + */ +#define SLEG_CONDSTRUCT(handler, from, to) {SL_STRUCT, 0, 0, from, to, 0, nullptr, 0, new handler()} + /** * Storage of a global reference list in some savegame versions. * @param variable Name of the global variable. @@ -747,6 +822,14 @@ using SaveLoadTable = span; */ #define SLEG_CONDREFLIST(variable, type, from, to) SLEG_GENERAL(SL_REFLIST, variable, type, 0, from, to, 0) +/** + * Storage of a list of structs in some savegame versions. + * @param handler SaveLoadHandler for the list of structs. + * @param from First savegame version that has the list. + * @param to Last savegame version that has the list. + */ +#define SLEG_CONDSTRUCTLIST(handler, from, to) {SL_STRUCTLIST, 0, 0, from, to, 0, nullptr, 0, new handler()} + /** * Storage of a global variable in every savegame version. * @param variable Name of the global variable. @@ -782,6 +865,12 @@ using SaveLoadTable = span; */ #define SLEG_SSTR(variable, type) SLEG_CONDSSTR(variable, type, SL_MIN_VERSION, SL_MAX_VERSION) +/** + * Storage of a structs in every savegame version. + * @param handler SaveLoadHandler for the structs. + */ +#define SLEG_STRUCT(handler) SLEG_CONDSTRUCT(handler, SL_MIN_VERSION, SL_MAX_VERSION) + /** * Storage of a global reference list in every savegame version. * @param variable Name of the global variable. @@ -789,13 +878,19 @@ using SaveLoadTable = span; */ #define SLEG_REFLIST(variable, type) SLEG_CONDREFLIST(variable, type, SL_MIN_VERSION, SL_MAX_VERSION) +/** + * Storage of a list of structs in every savegame version. + * @param handler SaveLoadHandler for the list of structs. + */ +#define SLEG_STRUCTLIST(handler) SLEG_CONDSTRUCTLIST(handler, SL_MIN_VERSION, SL_MAX_VERSION) + /** * Empty global space in some savegame versions. * @param length Length of the empty space. * @param from First savegame version that has the empty space. * @param to Last savegame version that has the empty space. */ -#define SLEG_CONDNULL(length, from, to) {SL_ARR, SLE_FILE_U8 | SLE_VAR_NULL, length, from, to, 0, nullptr, 0} +#define SLEG_CONDNULL(length, from, to) {SL_ARR, SLE_FILE_U8 | SLE_VAR_NULL, length, from, to, 0, nullptr, 0, nullptr} /** * Checks whether the savegame is below \a major.\a minor. diff --git a/src/settings.cpp b/src/settings.cpp index 2b222ad785..23f43d24f2 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -2024,7 +2024,7 @@ static std::vector GetSettingsDesc(const SettingTable &settings, bool if (is_loading && (sd->flags & SF_NO_NETWORK_SYNC) && _networking && !_network_server) { /* We don't want to read this setting, so we do need to skip over it. */ - saveloads.push_back({sd->save.cmd, GetVarFileType(sd->save.conv) | SLE_VAR_NULL, sd->save.length, sd->save.version_from, sd->save.version_to, 0, nullptr, 0}); + saveloads.push_back({sd->save.cmd, GetVarFileType(sd->save.conv) | SLE_VAR_NULL, sd->save.length, sd->save.version_from, sd->save.version_to, 0, nullptr, 0, nullptr}); continue; } From 4e4720f2178c9e0faf7233e55bec71e6ae19f9ad Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Sun, 6 Jun 2021 16:03:56 +0200 Subject: [PATCH 02/20] Codechange: remove the special station/vehicle code from SaveLoad With the new SLEG_STRUCT it is much easier to embed a struct in a struct, where the sub-struct has limitations on when it is being used. This makes both the code easier to read (less magic) and avoids the SaveLoad needing to know all these things about Stations and Vehicles. --- src/cargopacket.h | 4 +- src/order_base.h | 4 +- src/saveload/saveload.cpp | 21 +- src/saveload/saveload.h | 21 +- src/saveload/saveload_internal.h | 1 - src/saveload/station_sl.cpp | 180 ++++++++------ src/saveload/vehicle_sl.cpp | 400 +++++++++++++++++++------------ src/vehicle_base.h | 6 +- 8 files changed, 381 insertions(+), 256 deletions(-) diff --git a/src/cargopacket.h b/src/cargopacket.h index abb8d98c2c..a5166e9594 100644 --- a/src/cargopacket.h +++ b/src/cargopacket.h @@ -305,8 +305,8 @@ public: friend class StationCargoList; /** The super class ought to know what it's doing. */ friend class CargoList; - /** The vehicles have a cargo list (and we want that saved). */ - friend SaveLoadTable GetVehicleDescription(VehicleType vt); + /* So we can use private/protected variables in the saveload code */ + friend class SlVehicleCommon; friend class CargoShift; friend class CargoTransfer; diff --git a/src/order_base.h b/src/order_base.h index c510bd3e06..84f5289ec1 100644 --- a/src/order_base.h +++ b/src/order_base.h @@ -32,9 +32,11 @@ extern OrderListPool _orderlist_pool; */ struct Order : OrderPool::PoolItem<&_order_pool> { private: - friend SaveLoadTable GetVehicleDescription(VehicleType vt); ///< Saving and loading the current order of vehicles. friend void Load_VEHS(); ///< Loading of ancient vehicles. friend SaveLoadTable GetOrderDescription(); ///< Saving and loading of orders. + /* So we can use private/protected variables in the saveload code */ + friend class SlVehicleCommon; + friend class SlVehicleDisaster; uint8 type; ///< The type of order + non-stop flags uint8 flags; ///< Load/unload types, depot order/action types. diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index 6be86a7acd..cb28fb6d28 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -1447,9 +1447,7 @@ size_t SlCalcObjMemberLength(const void *object, const SaveLoad &sld) default: NOT_REACHED(); } break; - case SL_WRITEBYTE: return 1; // a byte is logically of size 1 - case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END)); - case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription()); + case SL_SAVEBYTE: return 1; // a byte is logically of size 1 case SL_STRUCT: case SL_STRUCTLIST: { if (!SlIsObjectValidInSavegame(sld)) break; @@ -1555,10 +1553,10 @@ static bool SlObjectMember(void *object, const SaveLoad &sld) break; } - /* SL_WRITEBYTE writes a value to the savegame to identify the type of an object. + /* SL_SAVEBYTE writes a value to the savegame to identify the type of an object. * When loading, the value is read explicitly with SlReadByte() to determine which * object description to use. */ - case SL_WRITEBYTE: { + case SL_SAVEBYTE: { void *ptr = GetVariableAddress(object, sld); switch (_sl.action) { @@ -1572,19 +1570,6 @@ static bool SlObjectMember(void *object, const SaveLoad &sld) break; } - /* SL_VEH_INCLUDE loads common code for vehicles */ - case SL_VEH_INCLUDE: { - void *ptr = GetVariableAddress(object, sld); - SlObject(ptr, GetVehicleDescription(VEH_END)); - break; - } - - case SL_ST_INCLUDE: { - void *ptr = GetVariableAddress(object, sld); - SlObject(ptr, GetBaseStationDescription()); - break; - } - case SL_STRUCT: case SL_STRUCTLIST: if (!SlIsObjectValidInSavegame(sld)) return false; diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index ff0982569b..7b0127709f 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -570,10 +570,7 @@ enum SaveLoadType : byte { SL_STDSTR = 6, ///< Save/load a \c std::string. SL_STRUCT = 7, ///< Save/load a struct. SL_STRUCTLIST = 8, ///< Save/load a list of structs. - /* non-normal save-load types */ - SL_WRITEBYTE = 9, - SL_VEH_INCLUDE = 10, - SL_ST_INCLUDE = 11, + SL_SAVEBYTE = 9, ///< Save (but not load) a byte. }; typedef void *SaveLoadAddrProc(void *base, size_t extra); @@ -740,11 +737,17 @@ struct SaveLoad { */ #define SLE_CONDNULL(length, from, to) {SL_ARR, SLE_FILE_U8 | SLE_VAR_NULL, length, from, to, 0, nullptr, 0, nullptr} -/** Translate values ingame to different values in the savegame and vv. */ -#define SLE_WRITEBYTE(base, variable) SLE_GENERAL(SL_WRITEBYTE, base, variable, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION, 0) - -#define SLE_VEH_INCLUDE() {SL_VEH_INCLUDE, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION, 0, [] (void *b, size_t) { return b; }, 0, nullptr} -#define SLE_ST_INCLUDE() {SL_ST_INCLUDE, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION, 0, [] (void *b, size_t) { return b; }, 0, nullptr} +/** + * Only write byte during saving; never read it during loading. + * When using SLE_SAVEBYTE you will have to read this byte before the table + * this is in is read. This also means SLE_SAVEBYTE can only be used at the + * top of a chunk. + * This is intended to be used to indicate what type of entry this is in a + * list of entries. + * @param base Name of the class or struct containing the variable. + * @param variable Name of the variable in the class or struct referenced by \a base. + */ +#define SLE_SAVEBYTE(base, variable) SLE_GENERAL(SL_SAVEBYTE, base, variable, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION, 0) /** * Storage of global simple variables, references (pointers), and arrays. diff --git a/src/saveload/saveload_internal.h b/src/saveload/saveload_internal.h index 920be04178..a7fc54d7d3 100644 --- a/src/saveload/saveload_internal.h +++ b/src/saveload/saveload_internal.h @@ -23,7 +23,6 @@ void ResetOldNames(); void ResetOldWaypoints(); void MoveBuoysToWaypoints(); void MoveWaypointsToBaseStations(); -SaveLoadTable GetBaseStationDescription(); void AfterLoadVehicles(bool part_of_load); void FixupTrainLengths(); diff --git a/src/saveload/station_sl.cpp b/src/saveload/station_sl.cpp index 92fa2bafdf..9c07834e4c 100644 --- a/src/saveload/station_sl.cpp +++ b/src/saveload/station_sl.cpp @@ -374,89 +374,125 @@ static void Ptrs_STNS() } } - -static const SaveLoad _base_station_desc[] = { - SLE_VAR(BaseStation, xy, SLE_UINT32), - SLE_REF(BaseStation, town, REF_TOWN), - SLE_VAR(BaseStation, string_id, SLE_STRINGID), - SLE_SSTR(BaseStation, name, SLE_STR | SLF_ALLOW_CONTROL), - SLE_VAR(BaseStation, delete_ctr, SLE_UINT8), - SLE_VAR(BaseStation, owner, SLE_UINT8), - SLE_VAR(BaseStation, facilities, SLE_UINT8), - SLE_VAR(BaseStation, build_date, SLE_INT32), - - /* Used by newstations for graphic variations */ - SLE_VAR(BaseStation, random_bits, SLE_UINT16), - SLE_VAR(BaseStation, waiting_triggers, SLE_UINT8), - SLE_VAR(BaseStation, num_specs, SLE_UINT8), -}; - static OldPersistentStorage _old_st_persistent_storage; -static const SaveLoad _station_desc[] = { - SLE_WRITEBYTE(Station, facilities), - SLE_ST_INCLUDE(), +/** + * SaveLoad handler for the BaseStation, which all other stations / waypoints + * make use of. + */ +class SlStationBase : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_VAR(BaseStation, xy, SLE_UINT32), + SLE_REF(BaseStation, town, REF_TOWN), + SLE_VAR(BaseStation, string_id, SLE_STRINGID), + SLE_SSTR(BaseStation, name, SLE_STR | SLF_ALLOW_CONTROL), + SLE_VAR(BaseStation, delete_ctr, SLE_UINT8), + SLE_VAR(BaseStation, owner, SLE_UINT8), + SLE_VAR(BaseStation, facilities, SLE_UINT8), + SLE_VAR(BaseStation, build_date, SLE_INT32), - 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), + /* Used by newstations for graphic variations */ + SLE_VAR(BaseStation, random_bits, SLE_UINT16), + SLE_VAR(BaseStation, waiting_triggers, SLE_UINT8), + SLE_VAR(BaseStation, num_specs, SLE_UINT8), + }; - SLE_REF(Station, bus_stops, REF_ROADSTOPS), - SLE_REF(Station, truck_stops, REF_ROADSTOPS), - SLE_CONDNULL(4, SL_MIN_VERSION, SLV_MULTITILE_DOCKS), - 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_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_VAR(Station, airport.flags, SLE_UINT64), - 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), + void GenericSaveLoad(BaseStation *bst) const + { + SlObject(bst, this->GetDescription()); + } - SLE_VAR(Station, indtype, SLE_UINT8), - - SLE_VAR(Station, time_since_load, SLE_UINT8), - SLE_VAR(Station, time_since_unload, SLE_UINT8), - SLE_VAR(Station, last_vehicle_type, SLE_UINT8), - SLE_VAR(Station, had_vehicle_of_type, SLE_UINT8), - SLE_REFLIST(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), -}; - -static const SaveLoad _waypoint_desc[] = { - SLE_WRITEBYTE(Waypoint, facilities), - SLE_ST_INCLUDE(), - - SLE_VAR(Waypoint, town_cn, SLE_UINT16), - - SLE_CONDVAR(Waypoint, train_station.tile, SLE_UINT32, SLV_124, SL_MAX_VERSION), - 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), + void Save(BaseStation *bst) const override { this->GenericSaveLoad(bst); } + void Load(BaseStation *bst) const override { this->GenericSaveLoad(bst); } + void FixPointers(BaseStation *bst) const override { this->GenericSaveLoad(bst); } }; /** - * Get the base station description to be used for SL_ST_INCLUDE - * @return the base station description. + * SaveLoad handler for a normal station (read: not a waypoint). */ -SaveLoadTable GetBaseStationDescription() -{ - return _base_station_desc; -} +class SlStationNormal : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLEG_STRUCT(SlStationBase), + 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_CONDNULL(4, SL_MIN_VERSION, SLV_MULTITILE_DOCKS), + 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_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_VAR(Station, airport.flags, SLE_UINT64), + 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_VAR(Station, time_since_load, SLE_UINT8), + SLE_VAR(Station, time_since_unload, SLE_UINT8), + SLE_VAR(Station, last_vehicle_type, SLE_UINT8), + SLE_VAR(Station, had_vehicle_of_type, SLE_UINT8), + SLE_REFLIST(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), + }; + + void GenericSaveLoad(BaseStation *bst) const + { + if ((bst->facilities & FACIL_WAYPOINT) != 0) return; + SlObject(bst, this->GetDescription()); + } + + void Save(BaseStation *bst) const override { this->GenericSaveLoad(bst); } + void Load(BaseStation *bst) const override { this->GenericSaveLoad(bst); } + void FixPointers(BaseStation *bst) const override { this->GenericSaveLoad(bst); } +}; + +class SlStationWaypoint : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLEG_STRUCT(SlStationBase), + SLE_VAR(Waypoint, town_cn, SLE_UINT16), + + SLE_CONDVAR(Waypoint, train_station.tile, SLE_UINT32, SLV_124, SL_MAX_VERSION), + 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), + }; + + void GenericSaveLoad(BaseStation *bst) const + { + if ((bst->facilities & FACIL_WAYPOINT) == 0) return; + SlObject(bst, this->GetDescription()); + } + + void Save(BaseStation *bst) const override { this->GenericSaveLoad(bst); } + void Load(BaseStation *bst) const override { this->GenericSaveLoad(bst); } + void FixPointers(BaseStation *bst) const override { this->GenericSaveLoad(bst); } +}; + +static const SaveLoad _station_desc[] = { + SLE_SAVEBYTE(BaseStation, facilities), + SLEG_STRUCT(SlStationNormal), + SLEG_STRUCT(SlStationWaypoint), +}; static void RealSave_STNN(BaseStation *bst) { - bool waypoint = (bst->facilities & FACIL_WAYPOINT) != 0; - SlObject(bst, waypoint ? SaveLoadTable(_waypoint_desc) : SaveLoadTable(_station_desc)); + SlObject(bst, _station_desc); - if (!waypoint) { + if ((bst->facilities & FACIL_WAYPOINT) == 0) { Station *st = Station::From(bst); for (CargoID i = 0; i < NUM_CARGO; i++) { _num_dests = (uint32)st->goods[i].cargo.Packets()->MapSize(); @@ -509,7 +545,7 @@ static void Load_STNN() bool waypoint = (SlReadByte() & FACIL_WAYPOINT) != 0; BaseStation *bst = waypoint ? (BaseStation *)new (index) Waypoint() : new (index) Station(); - SlObject(bst, waypoint ? SaveLoadTable(_waypoint_desc) : SaveLoadTable(_station_desc)); + SlObject(bst, _station_desc); if (!waypoint) { Station *st = Station::From(bst); @@ -583,7 +619,7 @@ static void Ptrs_STNN() } for (Waypoint *wp : Waypoint::Iterate()) { - SlObject(wp, _waypoint_desc); + SlObject(wp, _station_desc); } } diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp index 2609730506..ffa0206771 100644 --- a/src/saveload/vehicle_sl.cpp +++ b/src/saveload/vehicle_sl.cpp @@ -573,150 +573,169 @@ static uint16 _cargo_paid_for; static Money _cargo_feeder_share; static uint32 _cargo_loaded_at_xy; -/** - * Make it possible to make the saveload tables "friends" of other classes. - * @param vt the vehicle type. Can be VEH_END for the common vehicle description data - * @return the saveload description - */ -SaveLoadTable GetVehicleDescription(VehicleType vt) -{ - /** Save and load of vehicles */ - static const SaveLoad _common_veh_desc[] = { - SLE_VAR(Vehicle, subtype, SLE_UINT8), +class SlVehicleCommon : public DefaultSaveLoadHandler { +public: +#if defined(_MSC_VER) && (_MSC_VER == 1915 || _MSC_VER == 1916) + /* This table access private members of other classes; they have this + * class as friend. For MSVC CL 19.15 and 19.16 this doesn't work for + * "inline static const", so we are forced to wrap the table in a + * function. CL 19.16 is the latest for VS2017. */ + inline static const SaveLoad description[] = {{}}; + SaveLoadTable GetDescription() const override { +#else + inline +#endif + static const SaveLoad description[] = { + SLE_VAR(Vehicle, subtype, SLE_UINT8), - SLE_REF(Vehicle, next, REF_VEHICLE_OLD), - SLE_CONDVAR(Vehicle, name, SLE_NAME, SL_MIN_VERSION, SLV_84), + SLE_REF(Vehicle, next, REF_VEHICLE_OLD), + SLE_CONDVAR(Vehicle, name, SLE_NAME, SL_MIN_VERSION, SLV_84), SLE_CONDSSTR(Vehicle, name, SLE_STR | SLF_ALLOW_CONTROL, SLV_84, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, unitnumber, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_8), - SLE_CONDVAR(Vehicle, unitnumber, SLE_UINT16, SLV_8, SL_MAX_VERSION), - SLE_VAR(Vehicle, owner, SLE_UINT8), - SLE_CONDVAR(Vehicle, tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), - SLE_CONDVAR(Vehicle, tile, SLE_UINT32, SLV_6, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, dest_tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), - SLE_CONDVAR(Vehicle, dest_tile, SLE_UINT32, SLV_6, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, unitnumber, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_8), + SLE_CONDVAR(Vehicle, unitnumber, SLE_UINT16, SLV_8, SL_MAX_VERSION), + SLE_VAR(Vehicle, owner, SLE_UINT8), + SLE_CONDVAR(Vehicle, tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), + SLE_CONDVAR(Vehicle, tile, SLE_UINT32, SLV_6, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, dest_tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), + SLE_CONDVAR(Vehicle, dest_tile, SLE_UINT32, SLV_6, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, x_pos, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), - SLE_CONDVAR(Vehicle, x_pos, SLE_UINT32, SLV_6, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, y_pos, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), - SLE_CONDVAR(Vehicle, y_pos, SLE_UINT32, SLV_6, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, z_pos, SLE_FILE_U8 | SLE_VAR_I32, SL_MIN_VERSION, SLV_164), - SLE_CONDVAR(Vehicle, z_pos, SLE_INT32, SLV_164, SL_MAX_VERSION), - SLE_VAR(Vehicle, direction, SLE_UINT8), + SLE_CONDVAR(Vehicle, x_pos, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), + SLE_CONDVAR(Vehicle, x_pos, SLE_UINT32, SLV_6, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, y_pos, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), + SLE_CONDVAR(Vehicle, y_pos, SLE_UINT32, SLV_6, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, z_pos, SLE_FILE_U8 | SLE_VAR_I32, SL_MIN_VERSION, SLV_164), + SLE_CONDVAR(Vehicle, z_pos, SLE_INT32, SLV_164, SL_MAX_VERSION), + SLE_VAR(Vehicle, direction, SLE_UINT8), SLE_CONDNULL(2, SL_MIN_VERSION, SLV_58), - SLE_VAR(Vehicle, spritenum, SLE_UINT8), + SLE_VAR(Vehicle, spritenum, SLE_UINT8), SLE_CONDNULL(5, SL_MIN_VERSION, SLV_58), - SLE_VAR(Vehicle, engine_type, SLE_UINT16), + SLE_VAR(Vehicle, engine_type, SLE_UINT16), SLE_CONDNULL(2, SL_MIN_VERSION, SLV_152), - SLE_VAR(Vehicle, cur_speed, SLE_UINT16), - SLE_VAR(Vehicle, subspeed, SLE_UINT8), - SLE_VAR(Vehicle, acceleration, SLE_UINT8), - SLE_CONDVAR(Vehicle, motion_counter, SLE_UINT32, SLV_VEH_MOTION_COUNTER, SL_MAX_VERSION), - SLE_VAR(Vehicle, progress, SLE_UINT8), + SLE_VAR(Vehicle, cur_speed, SLE_UINT16), + SLE_VAR(Vehicle, subspeed, SLE_UINT8), + SLE_VAR(Vehicle, acceleration, SLE_UINT8), + SLE_CONDVAR(Vehicle, motion_counter, SLE_UINT32, SLV_VEH_MOTION_COUNTER, SL_MAX_VERSION), + SLE_VAR(Vehicle, progress, SLE_UINT8), - SLE_VAR(Vehicle, vehstatus, SLE_UINT8), - SLE_CONDVAR(Vehicle, last_station_visited, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_5), - SLE_CONDVAR(Vehicle, last_station_visited, SLE_UINT16, SLV_5, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, last_loading_station, SLE_UINT16, SLV_182, SL_MAX_VERSION), + SLE_VAR(Vehicle, vehstatus, SLE_UINT8), + SLE_CONDVAR(Vehicle, last_station_visited, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_5), + SLE_CONDVAR(Vehicle, last_station_visited, SLE_UINT16, SLV_5, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, last_loading_station, SLE_UINT16, SLV_182, SL_MAX_VERSION), - SLE_VAR(Vehicle, cargo_type, SLE_UINT8), - SLE_CONDVAR(Vehicle, cargo_subtype, SLE_UINT8, SLV_35, SL_MAX_VERSION), + SLE_VAR(Vehicle, cargo_type, SLE_UINT8), + SLE_CONDVAR(Vehicle, cargo_subtype, SLE_UINT8, SLV_35, SL_MAX_VERSION), SLEG_CONDVAR( _cargo_days, SLE_UINT8, SL_MIN_VERSION, SLV_68), 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), SLEG_CONDVAR( _cargo_source_xy, SLE_UINT32, SLV_44, SLV_68), - SLE_VAR(Vehicle, cargo_cap, SLE_UINT16), - SLE_CONDVAR(Vehicle, refit_cap, SLE_UINT16, SLV_182, SL_MAX_VERSION), + SLE_VAR(Vehicle, cargo_cap, SLE_UINT16), + SLE_CONDVAR(Vehicle, refit_cap, SLE_UINT16, SLV_182, SL_MAX_VERSION), SLEG_CONDVAR( _cargo_count, SLE_UINT16, SL_MIN_VERSION, SLV_68), SLE_CONDREFLIST(Vehicle, cargo.packets, REF_CARGO_PACKET, SLV_68, SL_MAX_VERSION), - SLE_CONDARR(Vehicle, cargo.action_counts, SLE_UINT, VehicleCargoList::NUM_MOVE_TO_ACTION, SLV_181, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, cargo_age_counter, SLE_UINT16, SLV_162, SL_MAX_VERSION), + SLE_CONDARR(Vehicle, cargo.action_counts, SLE_UINT, VehicleCargoList::NUM_MOVE_TO_ACTION, SLV_181, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, cargo_age_counter, SLE_UINT16, SLV_162, SL_MAX_VERSION), - SLE_VAR(Vehicle, day_counter, SLE_UINT8), - SLE_VAR(Vehicle, tick_counter, SLE_UINT8), - SLE_CONDVAR(Vehicle, running_ticks, SLE_UINT8, SLV_88, SL_MAX_VERSION), + SLE_VAR(Vehicle, day_counter, SLE_UINT8), + SLE_VAR(Vehicle, tick_counter, SLE_UINT8), + SLE_CONDVAR(Vehicle, running_ticks, SLE_UINT8, SLV_88, SL_MAX_VERSION), - SLE_VAR(Vehicle, cur_implicit_order_index, SLE_UINT8), - SLE_CONDVAR(Vehicle, cur_real_order_index, SLE_UINT8, SLV_158, SL_MAX_VERSION), + SLE_VAR(Vehicle, cur_implicit_order_index, SLE_UINT8), + SLE_CONDVAR(Vehicle, cur_real_order_index, SLE_UINT8, SLV_158, SL_MAX_VERSION), /* num_orders is now part of OrderList and is not saved but counted */ SLE_CONDNULL(1, SL_MIN_VERSION, SLV_105), /* This next line is for version 4 and prior compatibility.. it temporarily reads - type and flags (which were both 4 bits) into type. Later on this is - converted correctly */ - SLE_CONDVAR(Vehicle, current_order.type, SLE_UINT8, SL_MIN_VERSION, SLV_5), - SLE_CONDVAR(Vehicle, current_order.dest, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_5), + type and flags (which were both 4 bits) into type. Later on this is + converted correctly */ + SLE_CONDVAR(Vehicle, current_order.type, SLE_UINT8, SL_MIN_VERSION, SLV_5), + SLE_CONDVAR(Vehicle, current_order.dest, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_5), /* Orders for version 5 and on */ - SLE_CONDVAR(Vehicle, current_order.type, SLE_UINT8, SLV_5, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, current_order.flags, SLE_UINT8, SLV_5, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, current_order.dest, SLE_UINT16, SLV_5, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, current_order.type, SLE_UINT8, SLV_5, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, current_order.flags, SLE_UINT8, SLV_5, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, current_order.dest, SLE_UINT16, SLV_5, SL_MAX_VERSION), /* Refit in current order */ - SLE_CONDVAR(Vehicle, current_order.refit_cargo, SLE_UINT8, SLV_36, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, current_order.refit_cargo, SLE_UINT8, SLV_36, SL_MAX_VERSION), SLE_CONDNULL(1, SLV_36, SLV_182), // refit_subtype /* Timetable in current order */ - SLE_CONDVAR(Vehicle, current_order.wait_time, SLE_UINT16, SLV_67, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, current_order.travel_time, SLE_UINT16, SLV_67, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, current_order.max_speed, SLE_UINT16, SLV_174, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, timetable_start, SLE_INT32, SLV_129, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, current_order.wait_time, SLE_UINT16, SLV_67, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, current_order.travel_time, SLE_UINT16, SLV_67, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, current_order.max_speed, SLE_UINT16, SLV_174, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, timetable_start, SLE_INT32, SLV_129, SL_MAX_VERSION), - SLE_CONDREF(Vehicle, orders, REF_ORDER, SL_MIN_VERSION, SLV_105), - SLE_CONDREF(Vehicle, orders, REF_ORDERLIST, SLV_105, SL_MAX_VERSION), + SLE_CONDREF(Vehicle, orders, REF_ORDER, SL_MIN_VERSION, SLV_105), + SLE_CONDREF(Vehicle, orders, REF_ORDERLIST, SLV_105, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, age, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31), - SLE_CONDVAR(Vehicle, age, SLE_INT32, SLV_31, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, max_age, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31), - SLE_CONDVAR(Vehicle, max_age, SLE_INT32, SLV_31, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, date_of_last_service, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31), - SLE_CONDVAR(Vehicle, date_of_last_service, SLE_INT32, SLV_31, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, service_interval, SLE_UINT16, SL_MIN_VERSION, SLV_31), - SLE_CONDVAR(Vehicle, service_interval, SLE_FILE_U32 | SLE_VAR_U16, SLV_31, SLV_180), - SLE_CONDVAR(Vehicle, service_interval, SLE_UINT16, SLV_180, SL_MAX_VERSION), - SLE_VAR(Vehicle, reliability, SLE_UINT16), - SLE_VAR(Vehicle, reliability_spd_dec, SLE_UINT16), - SLE_VAR(Vehicle, breakdown_ctr, SLE_UINT8), - SLE_VAR(Vehicle, breakdown_delay, SLE_UINT8), - SLE_VAR(Vehicle, breakdowns_since_last_service, SLE_UINT8), - SLE_VAR(Vehicle, breakdown_chance, SLE_UINT8), - SLE_CONDVAR(Vehicle, build_year, SLE_FILE_U8 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31), - SLE_CONDVAR(Vehicle, build_year, SLE_INT32, SLV_31, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, age, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31), + SLE_CONDVAR(Vehicle, age, SLE_INT32, SLV_31, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, max_age, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31), + SLE_CONDVAR(Vehicle, max_age, SLE_INT32, SLV_31, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, date_of_last_service, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31), + SLE_CONDVAR(Vehicle, date_of_last_service, SLE_INT32, SLV_31, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, service_interval, SLE_UINT16, SL_MIN_VERSION, SLV_31), + SLE_CONDVAR(Vehicle, service_interval, SLE_FILE_U32 | SLE_VAR_U16, SLV_31, SLV_180), + SLE_CONDVAR(Vehicle, service_interval, SLE_UINT16, SLV_180, SL_MAX_VERSION), + SLE_VAR(Vehicle, reliability, SLE_UINT16), + SLE_VAR(Vehicle, reliability_spd_dec, SLE_UINT16), + SLE_VAR(Vehicle, breakdown_ctr, SLE_UINT8), + SLE_VAR(Vehicle, breakdown_delay, SLE_UINT8), + SLE_VAR(Vehicle, breakdowns_since_last_service, SLE_UINT8), + SLE_VAR(Vehicle, breakdown_chance, SLE_UINT8), + SLE_CONDVAR(Vehicle, build_year, SLE_FILE_U8 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31), + SLE_CONDVAR(Vehicle, build_year, SLE_INT32, SLV_31, SL_MAX_VERSION), - SLE_VAR(Vehicle, load_unload_ticks, SLE_UINT16), + SLE_VAR(Vehicle, load_unload_ticks, SLE_UINT16), SLEG_CONDVAR( _cargo_paid_for, SLE_UINT16, SLV_45, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, vehicle_flags, SLE_FILE_U8 | SLE_VAR_U16, SLV_40, SLV_180), - SLE_CONDVAR(Vehicle, vehicle_flags, SLE_UINT16, SLV_180, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, vehicle_flags, SLE_FILE_U8 | SLE_VAR_U16, SLV_40, SLV_180), + SLE_CONDVAR(Vehicle, vehicle_flags, SLE_UINT16, SLV_180, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, profit_this_year, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_65), - SLE_CONDVAR(Vehicle, profit_this_year, SLE_INT64, SLV_65, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, profit_last_year, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_65), - SLE_CONDVAR(Vehicle, profit_last_year, SLE_INT64, SLV_65, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, profit_this_year, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_65), + SLE_CONDVAR(Vehicle, profit_this_year, SLE_INT64, SLV_65, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, profit_last_year, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_65), + SLE_CONDVAR(Vehicle, profit_last_year, SLE_INT64, SLV_65, SL_MAX_VERSION), SLEG_CONDVAR( _cargo_feeder_share, SLE_FILE_I32 | SLE_VAR_I64, SLV_51, SLV_65), SLEG_CONDVAR( _cargo_feeder_share, SLE_INT64, SLV_65, SLV_68), SLEG_CONDVAR( _cargo_loaded_at_xy, SLE_UINT32, SLV_51, SLV_68), - SLE_CONDVAR(Vehicle, value, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_65), - SLE_CONDVAR(Vehicle, value, SLE_INT64, SLV_65, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, value, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_65), + SLE_CONDVAR(Vehicle, value, SLE_INT64, SLV_65, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, random_bits, SLE_UINT8, SLV_2, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, waiting_triggers, SLE_UINT8, SLV_2, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, random_bits, SLE_UINT8, SLV_2, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, waiting_triggers, SLE_UINT8, SLV_2, SL_MAX_VERSION), - SLE_CONDREF(Vehicle, next_shared, REF_VEHICLE, SLV_2, SL_MAX_VERSION), + SLE_CONDREF(Vehicle, next_shared, REF_VEHICLE, SLV_2, SL_MAX_VERSION), SLE_CONDNULL(2, SLV_2, SLV_69), SLE_CONDNULL(4, SLV_69, SLV_101), - SLE_CONDVAR(Vehicle, group_id, SLE_UINT16, SLV_60, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, group_id, SLE_UINT16, SLV_60, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, current_order_time, SLE_UINT32, SLV_67, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, lateness_counter, SLE_INT32, SLV_67, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, current_order_time, SLE_UINT32, SLV_67, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, lateness_counter, SLE_INT32, SLV_67, SL_MAX_VERSION), SLE_CONDNULL(10, SLV_2, SLV_144), // old reserved space }; +#if defined(_MSC_VER) && (_MSC_VER == 1915 || _MSC_VER == 1916) + return description; + } +#endif - static const SaveLoad _train_desc[] = { - SLE_WRITEBYTE(Vehicle, type), - SLE_VEH_INCLUDE(), + void GenericSaveLoad(Vehicle *v) const + { + SlObject(v, this->GetDescription()); + } + + void Save(Vehicle *v) const override { this->GenericSaveLoad(v); } + void Load(Vehicle *v) const override { this->GenericSaveLoad(v); } + void FixPointers(Vehicle *v) const override { this->GenericSaveLoad(v); } +}; + +class SlVehicleTrain : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLEG_STRUCT(SlVehicleCommon), SLE_VAR(Train, crash_anim_pos, SLE_UINT16), SLE_VAR(Train, force_proceed, SLE_UINT8), SLE_VAR(Train, railtype, SLE_UINT8), @@ -733,9 +752,21 @@ SaveLoadTable GetVehicleDescription(VehicleType vt) SLE_CONDNULL(11, SLV_2, SLV_144), // old reserved space }; - static const SaveLoad _roadveh_desc[] = { - SLE_WRITEBYTE(Vehicle, type), - SLE_VEH_INCLUDE(), + void GenericSaveLoad(Vehicle *v) const + { + if (v->type != VEH_TRAIN) return; + SlObject(v, this->GetDescription()); + } + + void Save(Vehicle *v) const override { this->GenericSaveLoad(v); } + void Load(Vehicle *v) const override { this->GenericSaveLoad(v); } + void FixPointers(Vehicle *v) const override { this->GenericSaveLoad(v); } +}; + +class SlVehicleRoadVeh : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLEG_STRUCT(SlVehicleCommon), SLE_VAR(RoadVehicle, state, SLE_UINT8), SLE_VAR(RoadVehicle, frame, SLE_UINT8), SLE_VAR(RoadVehicle, blocked_ctr, SLE_UINT16), @@ -753,9 +784,21 @@ SaveLoadTable GetVehicleDescription(VehicleType vt) SLE_CONDNULL(16, SLV_2, SLV_144), // old reserved space }; - static const SaveLoad _ship_desc[] = { - SLE_WRITEBYTE(Vehicle, type), - SLE_VEH_INCLUDE(), + void GenericSaveLoad(Vehicle *v) const + { + if (v->type != VEH_ROAD) return; + SlObject(v, this->GetDescription()); + } + + void Save(Vehicle *v) const override { this->GenericSaveLoad(v); } + void Load(Vehicle *v) const override { this->GenericSaveLoad(v); } + void FixPointers(Vehicle *v) const override { this->GenericSaveLoad(v); } +}; + +class SlVehicleShip : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLEG_STRUCT(SlVehicleCommon), SLE_VAR(Ship, state, SLE_UINT8), SLE_CONDDEQUE(Ship, path, SLE_UINT8, SLV_SHIP_PATH_CACHE, SL_MAX_VERSION), SLE_CONDVAR(Ship, rotation, SLE_UINT8, SLV_SHIP_ROTATION, SL_MAX_VERSION), @@ -763,9 +806,21 @@ SaveLoadTable GetVehicleDescription(VehicleType vt) SLE_CONDNULL(16, SLV_2, SLV_144), // old reserved space }; - static const SaveLoad _aircraft_desc[] = { - SLE_WRITEBYTE(Vehicle, type), - SLE_VEH_INCLUDE(), + void GenericSaveLoad(Vehicle *v) const + { + if (v->type != VEH_SHIP) return; + SlObject(v, this->GetDescription()); + } + + void Save(Vehicle *v) const override { this->GenericSaveLoad(v); } + void Load(Vehicle *v) const override { this->GenericSaveLoad(v); } + void FixPointers(Vehicle *v) const override { this->GenericSaveLoad(v); } +}; + +class SlVehicleAircraft : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLEG_STRUCT(SlVehicleCommon), SLE_VAR(Aircraft, crashed_counter, SLE_UINT16), SLE_VAR(Aircraft, pos, SLE_UINT8), @@ -784,9 +839,20 @@ SaveLoadTable GetVehicleDescription(VehicleType vt) SLE_CONDNULL(13, SLV_2, SLV_144), // old reserved space }; - static const SaveLoad _special_desc[] = { - SLE_WRITEBYTE(Vehicle, type), + void GenericSaveLoad(Vehicle *v) const + { + if (v->type != VEH_AIRCRAFT) return; + SlObject(v, this->GetDescription()); + } + void Save(Vehicle *v) const override { this->GenericSaveLoad(v); } + void Load(Vehicle *v) const override { this->GenericSaveLoad(v); } + void FixPointers(Vehicle *v) const override { this->GenericSaveLoad(v); } +}; + +class SlVehicleEffect : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { SLE_VAR(Vehicle, subtype, SLE_UINT8), SLE_CONDVAR(Vehicle, tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), @@ -812,58 +878,90 @@ SaveLoadTable GetVehicleDescription(VehicleType vt) SLE_CONDNULL(15, SLV_2, SLV_144), // old reserved space }; - static const SaveLoad _disaster_desc[] = { - SLE_WRITEBYTE(Vehicle, type), + void GenericSaveLoad(Vehicle *v) const + { + if (v->type != VEH_EFFECT) return; + SlObject(v, this->GetDescription()); + } - SLE_REF(Vehicle, next, REF_VEHICLE_OLD), + void Save(Vehicle *v) const override { this->GenericSaveLoad(v); } + void Load(Vehicle *v) const override { this->GenericSaveLoad(v); } + void FixPointers(Vehicle *v) const override { this->GenericSaveLoad(v); } +}; - SLE_VAR(Vehicle, subtype, SLE_UINT8), - SLE_CONDVAR(Vehicle, tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), - SLE_CONDVAR(Vehicle, tile, SLE_UINT32, SLV_6, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, dest_tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), - SLE_CONDVAR(Vehicle, dest_tile, SLE_UINT32, SLV_6, SL_MAX_VERSION), +class SlVehicleDisaster : public DefaultSaveLoadHandler { +public: +#if defined(_MSC_VER) && (_MSC_VER == 1915 || _MSC_VER == 1916) + /* This table access private members of other classes; they have this + * class as friend. For MSVC CL 19.15 and 19.16 this doesn't work for + * "inline static const", so we are forced to wrap the table in a + * function. CL 19.16 is the latest for VS2017. */ + inline static const SaveLoad description[] = {{}}; + SaveLoadTable GetDescription() const override { +#else + inline +#endif + static const SaveLoad description[] = { + SLE_REF(Vehicle, next, REF_VEHICLE_OLD), - SLE_CONDVAR(Vehicle, x_pos, SLE_FILE_I16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_6), - SLE_CONDVAR(Vehicle, x_pos, SLE_INT32, SLV_6, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, y_pos, SLE_FILE_I16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_6), - SLE_CONDVAR(Vehicle, y_pos, SLE_INT32, SLV_6, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, z_pos, SLE_FILE_U8 | SLE_VAR_I32, SL_MIN_VERSION, SLV_164), - SLE_CONDVAR(Vehicle, z_pos, SLE_INT32, SLV_164, SL_MAX_VERSION), - SLE_VAR(Vehicle, direction, SLE_UINT8), + SLE_VAR(Vehicle, subtype, SLE_UINT8), + SLE_CONDVAR(Vehicle, tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), + SLE_CONDVAR(Vehicle, tile, SLE_UINT32, SLV_6, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, dest_tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), + SLE_CONDVAR(Vehicle, dest_tile, SLE_UINT32, SLV_6, SL_MAX_VERSION), + + SLE_CONDVAR(Vehicle, x_pos, SLE_FILE_I16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_6), + SLE_CONDVAR(Vehicle, x_pos, SLE_INT32, SLV_6, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, y_pos, SLE_FILE_I16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_6), + SLE_CONDVAR(Vehicle, y_pos, SLE_INT32, SLV_6, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, z_pos, SLE_FILE_U8 | SLE_VAR_I32, SL_MIN_VERSION, SLV_164), + SLE_CONDVAR(Vehicle, z_pos, SLE_INT32, SLV_164, SL_MAX_VERSION), + SLE_VAR(Vehicle, direction, SLE_UINT8), SLE_CONDNULL(5, SL_MIN_VERSION, SLV_58), - SLE_VAR(Vehicle, owner, SLE_UINT8), - SLE_VAR(Vehicle, vehstatus, SLE_UINT8), - SLE_CONDVAR(Vehicle, current_order.dest, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_5), - SLE_CONDVAR(Vehicle, current_order.dest, SLE_UINT16, SLV_5, SL_MAX_VERSION), + SLE_VAR(Vehicle, owner, SLE_UINT8), + SLE_VAR(Vehicle, vehstatus, SLE_UINT8), + SLE_CONDVAR(Vehicle, current_order.dest, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_5), + SLE_CONDVAR(Vehicle, current_order.dest, SLE_UINT16, SLV_5, SL_MAX_VERSION), - SLE_VAR(Vehicle, sprite_cache.sprite_seq.seq[0].sprite, SLE_FILE_U16 | SLE_VAR_U32), - SLE_CONDVAR(Vehicle, age, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31), - SLE_CONDVAR(Vehicle, age, SLE_INT32, SLV_31, SL_MAX_VERSION), - SLE_VAR(Vehicle, tick_counter, SLE_UINT8), + SLE_VAR(Vehicle, sprite_cache.sprite_seq.seq[0].sprite, SLE_FILE_U16 | SLE_VAR_U32), + SLE_CONDVAR(Vehicle, age, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31), + SLE_CONDVAR(Vehicle, age, SLE_INT32, SLV_31, SL_MAX_VERSION), + SLE_VAR(Vehicle, tick_counter, SLE_UINT8), - SLE_CONDVAR(DisasterVehicle, image_override, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_191), - SLE_CONDVAR(DisasterVehicle, image_override, SLE_UINT32, SLV_191, SL_MAX_VERSION), - SLE_CONDVAR(DisasterVehicle, big_ufo_destroyer_target, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_191), - SLE_CONDVAR(DisasterVehicle, big_ufo_destroyer_target, SLE_UINT32, SLV_191, SL_MAX_VERSION), - SLE_CONDVAR(DisasterVehicle, flags, SLE_UINT8, SLV_194, SL_MAX_VERSION), + SLE_CONDVAR(DisasterVehicle, image_override, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_191), + SLE_CONDVAR(DisasterVehicle, image_override, SLE_UINT32, SLV_191, SL_MAX_VERSION), + SLE_CONDVAR(DisasterVehicle, big_ufo_destroyer_target, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_191), + SLE_CONDVAR(DisasterVehicle, big_ufo_destroyer_target, SLE_UINT32, SLV_191, SL_MAX_VERSION), + SLE_CONDVAR(DisasterVehicle, flags, SLE_UINT8, SLV_194, SL_MAX_VERSION), SLE_CONDNULL(16, SLV_2, SLV_144), // old reserved space }; +#if defined(_MSC_VER) && (_MSC_VER == 1915 || _MSC_VER == 1916) + return description; + } +#endif + void GenericSaveLoad(Vehicle *v) const + { + if (v->type != VEH_DISASTER) return; + SlObject(v, this->GetDescription()); + } - static const SaveLoadTable _veh_descs[] = { - _train_desc, - _roadveh_desc, - _ship_desc, - _aircraft_desc, - _special_desc, - _disaster_desc, - _common_veh_desc, - }; + void Save(Vehicle *v) const override { this->GenericSaveLoad(v); } + void Load(Vehicle *v) const override { this->GenericSaveLoad(v); } + void FixPointers(Vehicle *v) const override { this->GenericSaveLoad(v); } +}; - return _veh_descs[vt]; -} +const static SaveLoad _vehicle_desc[] = { + SLE_SAVEBYTE(Vehicle, type), + SLEG_STRUCT(SlVehicleTrain), + SLEG_STRUCT(SlVehicleRoadVeh), + SLEG_STRUCT(SlVehicleShip), + SLEG_STRUCT(SlVehicleAircraft), + SLEG_STRUCT(SlVehicleEffect), + SLEG_STRUCT(SlVehicleDisaster), +}; /** Will be called when the vehicles need to be saved. */ static void Save_VEHS() @@ -871,7 +969,7 @@ static void Save_VEHS() /* Write the vehicles */ for (Vehicle *v : Vehicle::Iterate()) { SlSetArrayIndex(v->index); - SlObject(v, GetVehicleDescription(v->type)); + SlObject(v, _vehicle_desc); } } @@ -897,7 +995,7 @@ void Load_VEHS() default: SlErrorCorrupt("Invalid vehicle type"); } - SlObject(v, GetVehicleDescription(vtype)); + SlObject(v, _vehicle_desc); if (_cargo_count != 0 && IsCompanyBuildableVehicleType(v) && CargoPacket::CanAllocateItem()) { /* Don't construct the packet with station here, because that'll fail with old savegames */ @@ -924,10 +1022,10 @@ void Load_VEHS() } } -static void Ptrs_VEHS() +void Ptrs_VEHS() { for (Vehicle *v : Vehicle::Iterate()) { - SlObject(v, GetVehicleDescription(v->type)); + SlObject(v, _vehicle_desc); } } diff --git a/src/vehicle_base.h b/src/vehicle_base.h index 029ddcf667..a5549b4441 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -200,7 +200,6 @@ extern VehiclePool _vehicle_pool; /* Some declarations of functions, so we can make them friendly */ struct GroundVehicleCache; -extern SaveLoadTable GetVehicleDescription(VehicleType vt); struct LoadgameState; extern bool LoadOldVehicle(LoadgameState *ls, int num); extern void FixOldVehicles(); @@ -232,10 +231,13 @@ private: Vehicle *previous_shared; ///< NOSAVE: pointer to the previous vehicle in the shared order chain public: - friend SaveLoadTable GetVehicleDescription(VehicleType vt); ///< So we can use private/protected variables in the saveload code friend void FixOldVehicles(); friend void AfterLoadVehicles(bool part_of_load); ///< So we can set the #previous and #first pointers while loading friend bool LoadOldVehicle(LoadgameState *ls, int num); ///< So we can set the proper next pointer while loading + /* So we can use private/protected variables in the saveload code */ + friend class SlVehicleCommon; + friend class SlVehicleDisaster; + friend void Ptrs_VEHS(); TileIndex tile; ///< Current tile index From 0bb1d2fa8eaeb72213909100331c5c28e6decc9f Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Tue, 8 Jun 2021 15:42:27 +0200 Subject: [PATCH 03/20] Codechange: use SLE_STRUCT(LIST) for Town chunks --- src/saveload/town_sl.cpp | 131 ++++++++++++++++++++++----------------- 1 file changed, 73 insertions(+), 58 deletions(-) diff --git a/src/saveload/town_sl.cpp b/src/saveload/town_sl.cpp index 581d26cd77..4151e3c754 100644 --- a/src/saveload/town_sl.cpp +++ b/src/saveload/town_sl.cpp @@ -113,7 +113,75 @@ void UpdateHousesAndTowns() RebuildTownCaches(); } -/** Save and load of towns. */ +class SlTownSupplied : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_CONDVAR(TransportedCargoStat, old_max, SLE_UINT32, SLV_165, SL_MAX_VERSION), + SLE_CONDVAR(TransportedCargoStat, new_max, SLE_UINT32, SLV_165, SL_MAX_VERSION), + SLE_CONDVAR(TransportedCargoStat, old_act, SLE_UINT32, SLV_165, SL_MAX_VERSION), + SLE_CONDVAR(TransportedCargoStat, new_act, SLE_UINT32, SLV_165, SL_MAX_VERSION), + }; + + void Save(Town *t) const override + { + for (CargoID i = 0; i < NUM_CARGO; i++) { + SlObject(&t->supplied[i], this->GetDescription()); + } + } + + void Load(Town *t) const override + { + uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO; + for (CargoID i = 0; i < num_cargo; i++) { + SlObject(&t->supplied[i], this->GetDescription()); + } + } +}; + +class SlTownReceived : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_CONDVAR(TransportedCargoStat, old_max, SLE_UINT16, SLV_165, SL_MAX_VERSION), + SLE_CONDVAR(TransportedCargoStat, new_max, SLE_UINT16, SLV_165, SL_MAX_VERSION), + SLE_CONDVAR(TransportedCargoStat, old_act, SLE_UINT16, SLV_165, SL_MAX_VERSION), + SLE_CONDVAR(TransportedCargoStat, new_act, SLE_UINT16, SLV_165, SL_MAX_VERSION), + }; + + void Save(Town *t) const override + { + for (int i = TE_BEGIN; i < TE_END; i++) { + SlObject(&t->received[i], this->GetDescription()); + } + } + + void Load(Town *t) const override + { + for (int i = TE_BEGIN; i < TE_END; i++) { + SlObject(&t->received[i], this->GetDescription()); + } + } +}; + +class SlTownAcceptanceMatrix : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_VAR(AcceptanceMatrix, area.tile, SLE_UINT32), + SLE_VAR(AcceptanceMatrix, area.w, SLE_UINT16), + SLE_VAR(AcceptanceMatrix, area.h, SLE_UINT16), + }; + + void Load(Town *t) const override + { + /* Discard now unused acceptance matrix. */ + AcceptanceMatrix dummy; + SlObject(&dummy, this->GetDescription()); + if (dummy.area.w != 0) { + uint arr_len = dummy.area.w / AcceptanceMatrix::GRID * dummy.area.h / AcceptanceMatrix::GRID; + SlSkipBytes(4 * arr_len); + } + } +}; + static const SaveLoad _town_desc[] = { SLE_CONDVAR(Town, xy, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), SLE_CONDVAR(Town, xy, SLE_UINT32, SLV_6, SL_MAX_VERSION), @@ -194,20 +262,10 @@ static const SaveLoad _town_desc[] = { SLE_CONDNULL(4, SLV_166, SLV_EXTEND_CARGOTYPES), ///< cargo_produced, no longer in use SLE_CONDNULL(8, SLV_EXTEND_CARGOTYPES, SLV_REMOVE_TOWN_CARGO_CACHE), ///< cargo_produced, no longer in use SLE_CONDNULL(30, SLV_2, SLV_REMOVE_TOWN_CARGO_CACHE), ///< old reserved space -}; -static const SaveLoad _town_supplied_desc[] = { - SLE_CONDVAR(TransportedCargoStat, old_max, SLE_UINT32, SLV_165, SL_MAX_VERSION), - SLE_CONDVAR(TransportedCargoStat, new_max, SLE_UINT32, SLV_165, SL_MAX_VERSION), - SLE_CONDVAR(TransportedCargoStat, old_act, SLE_UINT32, SLV_165, SL_MAX_VERSION), - SLE_CONDVAR(TransportedCargoStat, new_act, SLE_UINT32, SLV_165, SL_MAX_VERSION), -}; - -static const SaveLoad _town_received_desc[] = { - SLE_CONDVAR(TransportedCargoStat, old_max, SLE_UINT16, SLV_165, SL_MAX_VERSION), - SLE_CONDVAR(TransportedCargoStat, new_max, SLE_UINT16, SLV_165, SL_MAX_VERSION), - SLE_CONDVAR(TransportedCargoStat, old_act, SLE_UINT16, SLV_165, SL_MAX_VERSION), - SLE_CONDVAR(TransportedCargoStat, new_act, SLE_UINT16, SLV_165, SL_MAX_VERSION), + SLEG_CONDSTRUCTLIST(SlTownSupplied, SLV_165, SL_MAX_VERSION), + SLEG_CONDSTRUCTLIST(SlTownReceived, SLV_165, SL_MAX_VERSION), + SLEG_CONDSTRUCTLIST(SlTownAcceptanceMatrix, SLV_166, SLV_REMOVE_TOWN_CARGO_CACHE), }; static void Save_HIDS() @@ -220,74 +278,31 @@ static void Load_HIDS() Load_NewGRFMapping(_house_mngr); } -SaveLoadTable GetTileMatrixDesc() -{ - /* Here due to private member vars. */ - static const SaveLoad _tilematrix_desc[] = { - SLE_VAR(AcceptanceMatrix, area.tile, SLE_UINT32), - SLE_VAR(AcceptanceMatrix, area.w, SLE_UINT16), - SLE_VAR(AcceptanceMatrix, area.h, SLE_UINT16), - }; - - return _tilematrix_desc; -} - -static void RealSave_Town(Town *t) -{ - SlObject(t, _town_desc); - - for (CargoID i = 0; i < NUM_CARGO; i++) { - SlObject(&t->supplied[i], _town_supplied_desc); - } - for (int i = TE_BEGIN; i < NUM_TE; i++) { - SlObject(&t->received[i], _town_received_desc); - } -} - static void Save_TOWN() { for (Town *t : Town::Iterate()) { SlSetArrayIndex(t->index); - SlAutolength((AutolengthProc*)RealSave_Town, t); + SlObject(t, _town_desc); } } static void Load_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); - for (CargoID i = 0; i < num_cargo; i++) { - SlObject(&t->supplied[i], _town_supplied_desc); - } - for (int i = TE_BEGIN; i < TE_END; i++) { - SlObject(&t->received[i], _town_received_desc); - } - if (t->townnamegrfid == 0 && !IsInsideMM(t->townnametype, SPECSTR_TOWNNAME_START, SPECSTR_TOWNNAME_LAST + 1) && GetStringTab(t->townnametype) != TEXT_TAB_OLD_CUSTOM) { SlErrorCorrupt("Invalid town name generator"); } - - if (!IsSavegameVersionBefore(SLV_166) && IsSavegameVersionBefore(SLV_REMOVE_TOWN_CARGO_CACHE)) { - /* Discard now unused acceptance matrix. */ - AcceptanceMatrix dummy; - SlObject(&dummy, GetTileMatrixDesc()); - if (dummy.area.w != 0) { - uint arr_len = dummy.area.w / AcceptanceMatrix::GRID * dummy.area.h / AcceptanceMatrix::GRID; - SlSkipBytes(4 * arr_len); - } - } } } /** Fix pointers when loading town data. */ static void Ptrs_TOWN() { - /* Don't run when savegame version lower than 161. */ if (IsSavegameVersionBefore(SLV_161)) return; for (Town *t : Town::Iterate()) { From af43fc3d62cbeccd0cde3280b273e83889a0697c Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Wed, 9 Jun 2021 20:04:53 +0200 Subject: [PATCH 04/20] Codechange: use SLE_STRUCT(LIST) for Company chunks --- src/company_base.h | 12 +- src/saveload/company_sl.cpp | 384 +++++++++++++++++++----------------- 2 files changed, 210 insertions(+), 186 deletions(-) diff --git a/src/company_base.h b/src/company_base.h index e21bf9bf3d..065931c6ce 100644 --- a/src/company_base.h +++ b/src/company_base.h @@ -98,28 +98,30 @@ struct CompanyProperties { CompanyEconomyEntry old_economy[MAX_HISTORY_QUARTERS]; ///< Economic data of the company of the last #MAX_HISTORY_QUARTERS quarters. byte num_valid_stat_ent; ///< Number of valid statistical entries in #old_economy. + Livery livery[LS_END]; + + EngineRenewList engine_renew_list; ///< Engine renewals of this company. + CompanySettings settings; ///< settings specific for each company + // TODO: Change some of these member variables to use relevant INVALID_xxx constants CompanyProperties() : name_2(0), name_1(0), president_name_1(0), president_name_2(0), face(0), money(0), money_fraction(0), current_loan(0), colour(0), block_preview(0), location_of_HQ(0), last_build_coordinate(0), share_owners(), inaugurated_year(0), months_of_bankruptcy(0), bankrupt_asked(0), bankrupt_timeout(0), bankrupt_value(0), - terraform_limit(0), clear_limit(0), tree_limit(0), is_ai(false) {} + terraform_limit(0), clear_limit(0), tree_limit(0), is_ai(false), engine_renew_list(nullptr) {} }; -struct Company : CompanyPool::PoolItem<&_company_pool>, CompanyProperties { +struct Company : CompanyProperties, CompanyPool::PoolItem<&_company_pool> { Company(uint16 name_1 = 0, bool is_ai = false); ~Company(); - Livery livery[LS_END]; RailTypes avail_railtypes; ///< Rail types available to this company. RoadTypes avail_roadtypes; ///< Road types available to this company. class AIInstance *ai_instance; class AIInfo *ai_info; - EngineRenewList engine_renew_list; ///< Engine renewals of this company. - CompanySettings settings; ///< settings specific for each company GroupStatistics group_all[VEH_COMPANY_END]; ///< NOSAVE: Statistics for the ALL_GROUP group. GroupStatistics group_default[VEH_COMPANY_END]; ///< NOSAVE: Statistics for the DEFAULT_GROUP group. diff --git a/src/saveload/company_sl.cpp b/src/saveload/company_sl.cpp index 4c64376385..550816a077 100644 --- a/src/saveload/company_sl.cpp +++ b/src/saveload/company_sl.cpp @@ -236,7 +236,201 @@ void AfterLoadCompanyStats() } } +/* We do need to read this single value, as the bigger it gets, the more data is stored */ +struct CompanyOldAI { + uint8 num_build_rec; +}; +class SlCompanyOldAIBuildRec : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_CONDNULL(2, SL_MIN_VERSION, SLV_6), + SLE_CONDNULL(4, SLV_6, SLV_107), + SLE_CONDNULL(2, SL_MIN_VERSION, SLV_6), + SLE_CONDNULL(4, SLV_6, SLV_107), + SLE_CONDNULL(8, SL_MIN_VERSION, SLV_107), + }; + + void GenericSaveLoad(CompanyOldAI *old_ai) const + { + for (int i = 0; i != old_ai->num_build_rec; i++) { + SlObject(nullptr, this->GetDescription()); + } + } + + // No Save(); this is for backwards compatibility. + void Load(CompanyOldAI *old_ai) const override { this->GenericSaveLoad(old_ai); } + void LoadCheck(CompanyOldAI *old_ai) const override { this->GenericSaveLoad(old_ai); } + void FixPointers(CompanyOldAI *old_ai) const override { this->GenericSaveLoad(old_ai); } +}; + +class SlCompanyOldAI : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_CONDNULL(2, SL_MIN_VERSION, SLV_107), + SLE_CONDNULL(2, SL_MIN_VERSION, SLV_13), + SLE_CONDNULL(4, SLV_13, SLV_107), + SLE_CONDNULL(8, SL_MIN_VERSION, SLV_107), + SLE_CONDVAR(CompanyOldAI, num_build_rec, SLE_UINT8, SL_MIN_VERSION, SLV_107), + SLE_CONDNULL(3, SL_MIN_VERSION, SLV_107), + + SLE_CONDNULL(2, SL_MIN_VERSION, SLV_6), + SLE_CONDNULL(4, SLV_6, SLV_107), + SLE_CONDNULL(2, SL_MIN_VERSION, SLV_6), + SLE_CONDNULL(4, SLV_6, SLV_107), + SLE_CONDNULL(2, SL_MIN_VERSION, SLV_107), + + SLE_CONDNULL(2, SL_MIN_VERSION, SLV_6), + SLE_CONDNULL(4, SLV_6, SLV_107), + SLE_CONDNULL(2, SL_MIN_VERSION, SLV_6), + SLE_CONDNULL(4, SLV_6, SLV_107), + SLE_CONDNULL(2, SL_MIN_VERSION, SLV_107), + + SLE_CONDNULL(2, SL_MIN_VERSION, SLV_69), + SLE_CONDNULL(4, SLV_69, SLV_107), + + SLE_CONDNULL(18, SL_MIN_VERSION, SLV_107), + SLE_CONDNULL(20, SL_MIN_VERSION, SLV_107), + SLE_CONDNULL(32, SL_MIN_VERSION, SLV_107), + + SLE_CONDNULL(64, SLV_2, SLV_107), + SLEG_STRUCTLIST(SlCompanyOldAIBuildRec), + }; + + void GenericSaveLoad(CompanyProperties *c) const + { + if (!c->is_ai) return; + + CompanyOldAI old_ai; + SlObject(&old_ai, this->GetDescription()); + } + + // No Save(); this is for backwards compatibility. + void Load(CompanyProperties *c) const override { this->GenericSaveLoad(c); } + void LoadCheck(CompanyProperties *c) const override { this->GenericSaveLoad(c); } + void FixPointers(CompanyProperties *c) const override { this->GenericSaveLoad(c); } +}; + +class SlCompanySettings : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + /* Engine renewal settings */ + SLE_CONDNULL(512, SLV_16, SLV_19), + SLE_CONDREF(CompanyProperties, engine_renew_list, REF_ENGINE_RENEWS, SLV_19, SL_MAX_VERSION), + SLE_CONDVAR(CompanyProperties, settings.engine_renew, SLE_BOOL, SLV_16, SL_MAX_VERSION), + SLE_CONDVAR(CompanyProperties, settings.engine_renew_months, SLE_INT16, SLV_16, SL_MAX_VERSION), + SLE_CONDVAR(CompanyProperties, settings.engine_renew_money, SLE_UINT32, SLV_16, SL_MAX_VERSION), + SLE_CONDVAR(CompanyProperties, settings.renew_keep_length, SLE_BOOL, SLV_2, SL_MAX_VERSION), + + /* Default vehicle settings */ + SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_ispercent, SLE_BOOL, SLV_120, SL_MAX_VERSION), + SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_trains, SLE_UINT16, SLV_120, SL_MAX_VERSION), + SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_roadveh, SLE_UINT16, SLV_120, SL_MAX_VERSION), + SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_aircraft, SLE_UINT16, SLV_120, SL_MAX_VERSION), + SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_ships, SLE_UINT16, SLV_120, SL_MAX_VERSION), + + SLE_CONDNULL(63, SLV_2, SLV_144), // old reserved space + }; + + void GenericSaveLoad(CompanyProperties *c) const + { + SlObject(c, this->GetDescription()); + } + + void Save(CompanyProperties *c) const override { this->GenericSaveLoad(c); } + void Load(CompanyProperties *c) const override { this->GenericSaveLoad(c); } + void LoadCheck(CompanyProperties *c) const override { this->GenericSaveLoad(c); } + void FixPointers(CompanyProperties *c) const override { this->GenericSaveLoad(c); } +}; + +class SlCompanyEconomy : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_CONDVAR(CompanyEconomyEntry, income, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_2), + SLE_CONDVAR(CompanyEconomyEntry, income, SLE_INT64, SLV_2, SL_MAX_VERSION), + SLE_CONDVAR(CompanyEconomyEntry, expenses, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_2), + SLE_CONDVAR(CompanyEconomyEntry, expenses, SLE_INT64, SLV_2, SL_MAX_VERSION), + SLE_CONDVAR(CompanyEconomyEntry, company_value, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_2), + SLE_CONDVAR(CompanyEconomyEntry, company_value, SLE_INT64, SLV_2, SL_MAX_VERSION), + + SLE_CONDVAR(CompanyEconomyEntry, delivered_cargo[NUM_CARGO - 1], SLE_INT32, SL_MIN_VERSION, SLV_170), + SLE_CONDARR(CompanyEconomyEntry, delivered_cargo, SLE_UINT32, 32, SLV_170, SLV_EXTEND_CARGOTYPES), + SLE_CONDARR(CompanyEconomyEntry, delivered_cargo, SLE_UINT32, NUM_CARGO, SLV_EXTEND_CARGOTYPES, SL_MAX_VERSION), + SLE_VAR(CompanyEconomyEntry, performance_history, SLE_INT32), + }; + + void GenericSaveLoad(CompanyProperties *c) const + { + SlObject(&c->cur_economy, this->GetDescription()); + } + + void Save(CompanyProperties *c) const override { this->GenericSaveLoad(c); } + void Load(CompanyProperties *c) const override { this->GenericSaveLoad(c); } + void LoadCheck(CompanyProperties *c) const override { this->GenericSaveLoad(c); } + void FixPointers(CompanyProperties *c) const override { this->GenericSaveLoad(c); } +}; + +class SlCompanyOldEconomy : public SlCompanyEconomy { +public: + void GenericSaveLoad(CompanyProperties *c) const + { + if (c->num_valid_stat_ent > lengthof(c->old_economy)) SlErrorCorrupt("Too many old economy entries"); + + for (int i = 0; i < c->num_valid_stat_ent; i++) { + SlObject(&c->old_economy[i], this->GetDescription()); + } + } + + void Save(CompanyProperties *c) const override { this->GenericSaveLoad(c); } + void Load(CompanyProperties *c) const override { this->GenericSaveLoad(c); } + void LoadCheck(CompanyProperties *c) const override { this->GenericSaveLoad(c); } + void FixPointers(CompanyProperties *c) const override { this->GenericSaveLoad(c); } +}; + +class SlCompanyLiveries : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_CONDVAR(Livery, in_use, SLE_UINT8, SLV_34, SL_MAX_VERSION), + SLE_CONDVAR(Livery, colour1, SLE_UINT8, SLV_34, SL_MAX_VERSION), + SLE_CONDVAR(Livery, colour2, SLE_UINT8, SLV_34, SL_MAX_VERSION), + }; + + void GenericSaveLoad(CompanyProperties *c) const + { + int num_liveries = IsSavegameVersionBefore(SLV_63) ? LS_END - 4 : (IsSavegameVersionBefore(SLV_85) ? LS_END - 2: LS_END); + bool update_in_use = IsSavegameVersionBefore(SLV_GROUP_LIVERIES); + + for (int i = 0; i < num_liveries; i++) { + SlObject(&c->livery[i], this->GetDescription()); + if (update_in_use && i != LS_DEFAULT) { + if (c->livery[i].in_use == 0) { + c->livery[i].colour1 = c->livery[LS_DEFAULT].colour1; + c->livery[i].colour2 = c->livery[LS_DEFAULT].colour2; + } else { + c->livery[i].in_use = 3; + } + } + } + + if (num_liveries < LS_END) { + /* We want to insert some liveries somewhere in between. This means some have to be moved. */ + memmove(&c->livery[LS_FREIGHT_WAGON], &c->livery[LS_PASSENGER_WAGON_MONORAIL], (LS_END - LS_FREIGHT_WAGON) * sizeof(c->livery[0])); + c->livery[LS_PASSENGER_WAGON_MONORAIL] = c->livery[LS_MONORAIL]; + c->livery[LS_PASSENGER_WAGON_MAGLEV] = c->livery[LS_MAGLEV]; + } + + if (num_liveries == LS_END - 4) { + /* Copy bus/truck liveries over to trams */ + c->livery[LS_PASSENGER_TRAM] = c->livery[LS_BUS]; + c->livery[LS_FREIGHT_TRAM] = c->livery[LS_TRUCK]; + } + } + + void Save(CompanyProperties *c) const override { this->GenericSaveLoad(c); } + void Load(CompanyProperties *c) const override { this->GenericSaveLoad(c); } + void LoadCheck(CompanyProperties *c) const override { this->GenericSaveLoad(c); } + void FixPointers(CompanyProperties *c) const override { this->GenericSaveLoad(c); } +}; /* Save/load of companies */ static const SaveLoad _company_desc[] = { @@ -293,190 +487,18 @@ static const SaveLoad _company_desc[] = { SLE_CONDVAR(CompanyProperties, terraform_limit, SLE_UINT32, SLV_156, SL_MAX_VERSION), SLE_CONDVAR(CompanyProperties, clear_limit, SLE_UINT32, SLV_156, SL_MAX_VERSION), SLE_CONDVAR(CompanyProperties, tree_limit, SLE_UINT32, SLV_175, SL_MAX_VERSION), + SLEG_STRUCT(SlCompanySettings), + SLEG_CONDSTRUCT(SlCompanyOldAI, SL_MIN_VERSION, SLV_107), + SLEG_STRUCT(SlCompanyEconomy), + SLEG_STRUCTLIST(SlCompanyOldEconomy), + SLEG_CONDSTRUCTLIST(SlCompanyLiveries, SLV_34, SL_MAX_VERSION), }; -static const SaveLoad _company_settings_desc[] = { - /* Engine renewal settings */ - SLE_CONDNULL(512, SLV_16, SLV_19), - SLE_CONDREF(Company, engine_renew_list, REF_ENGINE_RENEWS, SLV_19, SL_MAX_VERSION), - SLE_CONDVAR(Company, settings.engine_renew, SLE_BOOL, SLV_16, SL_MAX_VERSION), - SLE_CONDVAR(Company, settings.engine_renew_months, SLE_INT16, SLV_16, SL_MAX_VERSION), - SLE_CONDVAR(Company, settings.engine_renew_money, SLE_UINT32, SLV_16, SL_MAX_VERSION), - SLE_CONDVAR(Company, settings.renew_keep_length, SLE_BOOL, SLV_2, SL_MAX_VERSION), - - /* Default vehicle settings */ - SLE_CONDVAR(Company, settings.vehicle.servint_ispercent, SLE_BOOL, SLV_120, SL_MAX_VERSION), - SLE_CONDVAR(Company, settings.vehicle.servint_trains, SLE_UINT16, SLV_120, SL_MAX_VERSION), - SLE_CONDVAR(Company, settings.vehicle.servint_roadveh, SLE_UINT16, SLV_120, SL_MAX_VERSION), - SLE_CONDVAR(Company, settings.vehicle.servint_aircraft, SLE_UINT16, SLV_120, SL_MAX_VERSION), - SLE_CONDVAR(Company, settings.vehicle.servint_ships, SLE_UINT16, SLV_120, SL_MAX_VERSION), - - SLE_CONDNULL(63, SLV_2, SLV_144), // old reserved space -}; - -static const SaveLoad _company_settings_skip_desc[] = { - /* Engine renewal settings */ - SLE_CONDNULL(512, SLV_16, SLV_19), - SLE_CONDNULL(2, SLV_19, SLV_69), // engine_renew_list - SLE_CONDNULL(4, SLV_69, SL_MAX_VERSION), // engine_renew_list - SLE_CONDNULL(1, SLV_16, SL_MAX_VERSION), // settings.engine_renew - SLE_CONDNULL(2, SLV_16, SL_MAX_VERSION), // settings.engine_renew_months - SLE_CONDNULL(4, SLV_16, SL_MAX_VERSION), // settings.engine_renew_money - SLE_CONDNULL(1, SLV_2, SL_MAX_VERSION), // settings.renew_keep_length - - /* Default vehicle settings */ - SLE_CONDNULL(1, SLV_120, SL_MAX_VERSION), // settings.vehicle.servint_ispercent - SLE_CONDNULL(2, SLV_120, SL_MAX_VERSION), // settings.vehicle.servint_trains - SLE_CONDNULL(2, SLV_120, SL_MAX_VERSION), // settings.vehicle.servint_roadveh - SLE_CONDNULL(2, SLV_120, SL_MAX_VERSION), // settings.vehicle.servint_aircraft - SLE_CONDNULL(2, SLV_120, SL_MAX_VERSION), // settings.vehicle.servint_ships - - SLE_CONDNULL(63, SLV_2, SLV_144), // old reserved space -}; - -static const SaveLoad _company_economy_desc[] = { - /* these were changed to 64-bit in savegame format 2 */ - SLE_CONDVAR(CompanyEconomyEntry, income, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_2), - SLE_CONDVAR(CompanyEconomyEntry, income, SLE_INT64, SLV_2, SL_MAX_VERSION), - SLE_CONDVAR(CompanyEconomyEntry, expenses, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_2), - SLE_CONDVAR(CompanyEconomyEntry, expenses, SLE_INT64, SLV_2, SL_MAX_VERSION), - SLE_CONDVAR(CompanyEconomyEntry, company_value, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_2), - SLE_CONDVAR(CompanyEconomyEntry, company_value, SLE_INT64, SLV_2, SL_MAX_VERSION), - - SLE_CONDVAR(CompanyEconomyEntry, delivered_cargo[NUM_CARGO - 1], SLE_INT32, SL_MIN_VERSION, SLV_170), - SLE_CONDARR(CompanyEconomyEntry, delivered_cargo, SLE_UINT32, 32, SLV_170, SLV_EXTEND_CARGOTYPES), - SLE_CONDARR(CompanyEconomyEntry, delivered_cargo, SLE_UINT32, NUM_CARGO, SLV_EXTEND_CARGOTYPES, SL_MAX_VERSION), - SLE_VAR(CompanyEconomyEntry, performance_history, SLE_INT32), -}; - -/* We do need to read this single value, as the bigger it gets, the more data is stored */ -struct CompanyOldAI { - uint8 num_build_rec; -}; - -static const SaveLoad _company_ai_desc[] = { - SLE_CONDNULL(2, SL_MIN_VERSION, SLV_107), - SLE_CONDNULL(2, SL_MIN_VERSION, SLV_13), - SLE_CONDNULL(4, SLV_13, SLV_107), - SLE_CONDNULL(8, SL_MIN_VERSION, SLV_107), - SLE_CONDVAR(CompanyOldAI, num_build_rec, SLE_UINT8, SL_MIN_VERSION, SLV_107), - SLE_CONDNULL(3, SL_MIN_VERSION, SLV_107), - - SLE_CONDNULL(2, SL_MIN_VERSION, SLV_6), - SLE_CONDNULL(4, SLV_6, SLV_107), - SLE_CONDNULL(2, SL_MIN_VERSION, SLV_6), - SLE_CONDNULL(4, SLV_6, SLV_107), - SLE_CONDNULL(2, SL_MIN_VERSION, SLV_107), - - SLE_CONDNULL(2, SL_MIN_VERSION, SLV_6), - SLE_CONDNULL(4, SLV_6, SLV_107), - SLE_CONDNULL(2, SL_MIN_VERSION, SLV_6), - SLE_CONDNULL(4, SLV_6, SLV_107), - SLE_CONDNULL(2, SL_MIN_VERSION, SLV_107), - - SLE_CONDNULL(2, SL_MIN_VERSION, SLV_69), - SLE_CONDNULL(4, SLV_69, SLV_107), - - SLE_CONDNULL(18, SL_MIN_VERSION, SLV_107), - SLE_CONDNULL(20, SL_MIN_VERSION, SLV_107), - SLE_CONDNULL(32, SL_MIN_VERSION, SLV_107), - - SLE_CONDNULL(64, SLV_2, SLV_107), -}; - -static const SaveLoad _company_ai_build_rec_desc[] = { - SLE_CONDNULL(2, SL_MIN_VERSION, SLV_6), - SLE_CONDNULL(4, SLV_6, SLV_107), - SLE_CONDNULL(2, SL_MIN_VERSION, SLV_6), - SLE_CONDNULL(4, SLV_6, SLV_107), - SLE_CONDNULL(8, SL_MIN_VERSION, SLV_107), -}; - -static const SaveLoad _company_livery_desc[] = { - SLE_CONDVAR(Livery, in_use, SLE_UINT8, SLV_34, SL_MAX_VERSION), - SLE_CONDVAR(Livery, colour1, SLE_UINT8, SLV_34, SL_MAX_VERSION), - SLE_CONDVAR(Livery, colour2, SLE_UINT8, SLV_34, SL_MAX_VERSION), -}; - -static void SaveLoad_PLYR_common(Company *c, CompanyProperties *cprops) -{ - int i; - - SlObject(cprops, _company_desc); - if (c != nullptr) { - SlObject(c, _company_settings_desc); - } else { - char nothing; - SlObject(¬hing, _company_settings_skip_desc); - } - - /* Keep backwards compatible for savegames, so load the old AI block */ - if (IsSavegameVersionBefore(SLV_107) && cprops->is_ai) { - CompanyOldAI old_ai; - char nothing; - - SlObject(&old_ai, _company_ai_desc); - for (i = 0; i != old_ai.num_build_rec; i++) { - SlObject(¬hing, _company_ai_build_rec_desc); - } - } - - /* Write economy */ - SlObject(&cprops->cur_economy, _company_economy_desc); - - /* Write old economy entries. */ - if (cprops->num_valid_stat_ent > lengthof(cprops->old_economy)) SlErrorCorrupt("Too many old economy entries"); - for (i = 0; i < cprops->num_valid_stat_ent; i++) { - SlObject(&cprops->old_economy[i], _company_economy_desc); - } - - /* Write each livery entry. */ - int num_liveries = IsSavegameVersionBefore(SLV_63) ? LS_END - 4 : (IsSavegameVersionBefore(SLV_85) ? LS_END - 2: LS_END); - bool update_in_use = IsSavegameVersionBefore(SLV_GROUP_LIVERIES); - if (c != nullptr) { - for (i = 0; i < num_liveries; i++) { - SlObject(&c->livery[i], _company_livery_desc); - if (update_in_use && i != LS_DEFAULT) { - if (c->livery[i].in_use == 0) { - c->livery[i].colour1 = c->livery[LS_DEFAULT].colour1; - c->livery[i].colour2 = c->livery[LS_DEFAULT].colour2; - } else { - c->livery[i].in_use = 3; - } - } - } - - if (num_liveries < LS_END) { - /* We want to insert some liveries somewhere in between. This means some have to be moved. */ - memmove(&c->livery[LS_FREIGHT_WAGON], &c->livery[LS_PASSENGER_WAGON_MONORAIL], (LS_END - LS_FREIGHT_WAGON) * sizeof(c->livery[0])); - c->livery[LS_PASSENGER_WAGON_MONORAIL] = c->livery[LS_MONORAIL]; - c->livery[LS_PASSENGER_WAGON_MAGLEV] = c->livery[LS_MAGLEV]; - } - - if (num_liveries == LS_END - 4) { - /* Copy bus/truck liveries over to trams */ - c->livery[LS_PASSENGER_TRAM] = c->livery[LS_BUS]; - c->livery[LS_FREIGHT_TRAM] = c->livery[LS_TRUCK]; - } - } else { - /* Skip liveries */ - Livery dummy_livery; - for (i = 0; i < num_liveries; i++) { - SlObject(&dummy_livery, _company_livery_desc); - } - } -} - -static void SaveLoad_PLYR(Company *c) -{ - SaveLoad_PLYR_common(c, c); -} - static void Save_PLYR() { for (Company *c : Company::Iterate()) { SlSetArrayIndex(c->index); - SlAutolength((AutolengthProc*)SaveLoad_PLYR, c); + SlObject(c, _company_desc); } } @@ -485,7 +507,7 @@ static void Load_PLYR() int index; while ((index = SlIterateArray()) != -1) { Company *c = new (index) Company(); - SaveLoad_PLYR(c); + SlObject(c, _company_desc); _company_colours[index] = (Colours)c->colour; } } @@ -495,7 +517,7 @@ static void Check_PLYR() int index; while ((index = SlIterateArray()) != -1) { CompanyProperties *cprops = new CompanyProperties(); - SaveLoad_PLYR_common(nullptr, cprops); + SlObject(cprops, _company_desc); /* We do not load old custom names */ if (IsSavegameVersionBefore(SLV_84)) { @@ -522,7 +544,7 @@ static void Check_PLYR() static void Ptrs_PLYR() { for (Company *c : Company::Iterate()) { - SlObject(c, _company_settings_desc); + SlObject(c, _company_desc); } } From 0bdca02bdf524647c8496318551ed48220bd90de Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Thu, 10 Jun 2021 09:44:04 +0200 Subject: [PATCH 05/20] Codechange: use SLE_STRUCT(LIST) for Station chunks --- src/cargopacket.h | 4 +- src/saveload/station_sl.cpp | 371 ++++++++++++++++++++---------------- 2 files changed, 212 insertions(+), 163 deletions(-) diff --git a/src/cargopacket.h b/src/cargopacket.h index a5166e9594..0e24bc6233 100644 --- a/src/cargopacket.h +++ b/src/cargopacket.h @@ -456,8 +456,8 @@ protected: public: /** The super class ought to know what it's doing. */ friend class CargoList; - /** The stations, via GoodsEntry, have a CargoList. */ - friend SaveLoadTable GetGoodsDesc(); + /* So we can use private/protected variables in the saveload code */ + friend class SlStationGoods; friend class CargoLoad; friend class CargoTransfer; diff --git a/src/saveload/station_sl.cpp b/src/saveload/station_sl.cpp index 9c07834e4c..21989139f9 100644 --- a/src/saveload/station_sl.cpp +++ b/src/saveload/station_sl.cpp @@ -220,11 +220,6 @@ static uint32 _cargo_source_xy; static uint8 _cargo_days; static Money _cargo_feeder_share; -static const SaveLoad _station_speclist_desc[] = { - SLE_CONDVAR(StationSpecList, grfid, SLE_UINT32, SLV_27, SL_MAX_VERSION), - SLE_CONDVAR(StationSpecList, localidx, SLE_UINT8, SLV_27, SL_MAX_VERSION), -}; - std::list _packets; uint32 _num_dests; @@ -236,53 +231,9 @@ struct FlowSaveLoad { bool restricted; }; -static const SaveLoad _flow_desc[] = { - SLE_VAR(FlowSaveLoad, source, SLE_UINT16), - SLE_VAR(FlowSaveLoad, via, SLE_UINT16), - SLE_VAR(FlowSaveLoad, share, SLE_UINT32), - SLE_CONDVAR(FlowSaveLoad, restricted, SLE_BOOL, SLV_187, SL_MAX_VERSION), -}; - -/** - * Wrapper function to get the GoodsEntry's internal structure while - * some of the variables itself are private. - * @return the saveload description for GoodsEntry. - */ -SaveLoadTable GetGoodsDesc() -{ - static const SaveLoad goods_desc[] = { - SLEG_CONDVAR( _waiting_acceptance, SLE_UINT16, SL_MIN_VERSION, SLV_68), - SLE_CONDVAR(GoodsEntry, status, SLE_UINT8, SLV_68, SL_MAX_VERSION), - SLE_CONDNULL(2, SLV_51, SLV_68), - SLE_VAR(GoodsEntry, time_since_pickup, SLE_UINT8), - SLE_VAR(GoodsEntry, rating, SLE_UINT8), - 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), - SLEG_CONDVAR( _cargo_source_xy, SLE_UINT32, SLV_44, SLV_68), - SLEG_CONDVAR( _cargo_days, SLE_UINT8, SL_MIN_VERSION, SLV_68), - SLE_VAR(GoodsEntry, last_speed, SLE_UINT8), - SLE_VAR(GoodsEntry, last_age, SLE_UINT8), - 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), - SLE_CONDVAR(GoodsEntry, amount_fract, SLE_UINT8, SLV_150, SL_MAX_VERSION), - SLEG_CONDREFLIST( _packets, REF_CARGO_PACKET, SLV_68, SLV_183), - SLEG_CONDVAR( _num_dests, SLE_UINT32, SLV_183, SL_MAX_VERSION), - SLE_CONDVAR(GoodsEntry, cargo.reserved_count, SLE_UINT, SLV_181, SL_MAX_VERSION), - SLE_CONDVAR(GoodsEntry, link_graph, SLE_UINT16, SLV_183, SL_MAX_VERSION), - SLE_CONDVAR(GoodsEntry, node, SLE_UINT16, SLV_183, SL_MAX_VERSION), - SLEG_CONDVAR( _num_flows, SLE_UINT32, SLV_183, SL_MAX_VERSION), - SLE_CONDVAR(GoodsEntry, max_waiting_cargo, SLE_UINT32, SLV_183, SL_MAX_VERSION), - }; - - return goods_desc; -} - typedef std::pair > StationCargoPair; -static const SaveLoad _cargo_list_desc[] = { - SLE_VAR(StationCargoPair, first, SLE_UINT16), - SLE_REFLIST(StationCargoPair, second, REF_CARGO_PACKET), -}; +static OldPersistentStorage _old_st_persistent_storage; /** * Swap the temporary packets with the packets without specific destination in @@ -306,8 +257,207 @@ static void SwapPackets(GoodsEntry *ge) } } +class SlStationSpecList : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_CONDVAR(StationSpecList, grfid, SLE_UINT32, SLV_27, SL_MAX_VERSION), + SLE_CONDVAR(StationSpecList, localidx, SLE_UINT8, SLV_27, SL_MAX_VERSION), + }; + + void Save(BaseStation *bst) const override + { + for (uint i = 0; i < bst->num_specs; i++) { + SlObject(&bst->speclist[i], this->GetDescription()); + } + } + + void Load(BaseStation *bst) const override + { + if (bst->num_specs != 0) { + /* 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], this->GetDescription()); + } + } + } +}; + +class SlStationCargo : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_VAR(StationCargoPair, first, SLE_UINT16), + SLE_REFLIST(StationCargoPair, second, REF_CARGO_PACKET), + }; + + void Save(GoodsEntry *ge) const override + { + for (StationCargoPacketMap::ConstMapIterator it(ge->cargo.Packets()->begin()); it != ge->cargo.Packets()->end(); ++it) { + SlObject(const_cast(&(*it)), this->GetDescription()); + } + } + + void Load(GoodsEntry *ge) const override + { + StationCargoPair pair; + for (uint j = 0; j < _num_dests; ++j) { + SlObject(&pair, this->GetDescription()); + const_cast(*(ge->cargo.Packets()))[pair.first].swap(pair.second); + assert(pair.second.empty()); + } + } + + void FixPointers(GoodsEntry *ge) const override + { + for (StationCargoPacketMap::ConstMapIterator it = ge->cargo.Packets()->begin(); it != ge->cargo.Packets()->end(); ++it) { + SlObject(const_cast(&(*it)), this->GetDescription()); + } + } +}; + +class SlStationFlow : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_VAR(FlowSaveLoad, source, SLE_UINT16), + SLE_VAR(FlowSaveLoad, via, SLE_UINT16), + SLE_VAR(FlowSaveLoad, share, SLE_UINT32), + SLE_CONDVAR(FlowSaveLoad, restricted, SLE_BOOL, SLV_187, SL_MAX_VERSION), + }; + + void Save(GoodsEntry *ge) const override + { + for (FlowStatMap::const_iterator outer_it(ge->flows.begin()); outer_it != ge->flows.end(); ++outer_it) { + const FlowStat::SharesMap *shares = outer_it->second.GetShares(); + uint32 sum_shares = 0; + FlowSaveLoad flow; + flow.source = outer_it->first; + for (FlowStat::SharesMap::const_iterator inner_it(shares->begin()); inner_it != shares->end(); ++inner_it) { + flow.via = inner_it->second; + flow.share = inner_it->first - sum_shares; + flow.restricted = inner_it->first > outer_it->second.GetUnrestricted(); + sum_shares = inner_it->first; + assert(flow.share > 0); + SlObject(&flow, this->GetDescription()); + } + } + } + + void Load(GoodsEntry *ge) const override + { + FlowSaveLoad flow; + FlowStat *fs = nullptr; + StationID prev_source = INVALID_STATION; + for (uint32 j = 0; j < _num_flows; ++j) { + SlObject(&flow, this->GetDescription()); + if (fs == nullptr || prev_source != flow.source) { + fs = &(ge->flows.insert(std::make_pair(flow.source, FlowStat(flow.via, flow.share, flow.restricted))).first->second); + } else { + fs->AppendShare(flow.via, flow.share, flow.restricted); + } + prev_source = flow.source; + } + } +}; + +class SlStationGoods : public DefaultSaveLoadHandler { +public: +#if defined(_MSC_VER) && (_MSC_VER == 1915 || _MSC_VER == 1916) + /* This table access private members of other classes; they have this + * class as friend. For MSVC CL 19.15 and 19.16 this doesn't work for + * "inline static const", so we are forced to wrap the table in a + * function. CL 19.16 is the latest for VS2017. */ + inline static const SaveLoad description[] = {{}}; + SaveLoadTable GetDescription() const override { +#else + inline +#endif + static const SaveLoad description[] = { + SLEG_CONDVAR( _waiting_acceptance, SLE_UINT16, SL_MIN_VERSION, SLV_68), + SLE_CONDVAR(GoodsEntry, status, SLE_UINT8, SLV_68, SL_MAX_VERSION), + SLE_CONDNULL(2, SLV_51, SLV_68), + SLE_VAR(GoodsEntry, time_since_pickup, SLE_UINT8), + SLE_VAR(GoodsEntry, rating, SLE_UINT8), + 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), + SLEG_CONDVAR( _cargo_source_xy, SLE_UINT32, SLV_44, SLV_68), + SLEG_CONDVAR( _cargo_days, SLE_UINT8, SL_MIN_VERSION, SLV_68), + SLE_VAR(GoodsEntry, last_speed, SLE_UINT8), + SLE_VAR(GoodsEntry, last_age, SLE_UINT8), + 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), + SLE_CONDVAR(GoodsEntry, amount_fract, SLE_UINT8, SLV_150, SL_MAX_VERSION), + SLEG_CONDREFLIST( _packets, REF_CARGO_PACKET, SLV_68, SLV_183), + SLEG_CONDVAR( _num_dests, SLE_UINT32, SLV_183, SL_MAX_VERSION), + SLE_CONDVAR(GoodsEntry, cargo.reserved_count, SLE_UINT, SLV_181, SL_MAX_VERSION), + SLE_CONDVAR(GoodsEntry, link_graph, SLE_UINT16, SLV_183, SL_MAX_VERSION), + SLE_CONDVAR(GoodsEntry, node, SLE_UINT16, SLV_183, SL_MAX_VERSION), + SLEG_CONDVAR( _num_flows, SLE_UINT32, SLV_183, SL_MAX_VERSION), + SLE_CONDVAR(GoodsEntry, max_waiting_cargo, SLE_UINT32, SLV_183, SL_MAX_VERSION), + SLEG_CONDSTRUCTLIST(SlStationFlow, SLV_183, SL_MAX_VERSION), + SLEG_CONDSTRUCTLIST(SlStationCargo, SLV_183, SL_MAX_VERSION), + }; +#if defined(_MSC_VER) && (_MSC_VER == 1915 || _MSC_VER == 1916) + return description; + } +#endif + + void Save(BaseStation *bst) const override + { + Station *st = Station::From(bst); + for (CargoID i = 0; i < NUM_CARGO; i++) { + _num_dests = (uint32)st->goods[i].cargo.Packets()->MapSize(); + _num_flows = 0; + for (FlowStatMap::const_iterator it(st->goods[i].flows.begin()); it != st->goods[i].flows.end(); ++it) { + _num_flows += (uint32)it->second.GetShares()->size(); + } + SlObject(&st->goods[i], this->GetDescription()); + } + } + + void Load(BaseStation *bst) const override + { + Station *st = Station::From(bst); + + /* Before savegame version 161, persistent storages were not stored in a pool. */ + if (IsSavegameVersionBefore(SLV_161) && !IsSavegameVersionBefore(SLV_145) && st->facilities & FACIL_AIRPORT) { + /* Store the old persistent storage. The GRFID will be added later. */ + assert(PersistentStorage::CanAllocateItem()); + st->airport.psa = new PersistentStorage(0, 0, 0); + memcpy(st->airport.psa->storage, _old_st_persistent_storage.storage, sizeof(_old_st_persistent_storage.storage)); + } + + uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO; + for (CargoID i = 0; i < num_cargo; i++) { + SlObject(&st->goods[i], this->GetDescription()); + if (IsSavegameVersionBefore(SLV_183)) { + SwapPackets(&st->goods[i]); + } + } + } + + void FixPointers(BaseStation *bst) const override + { + Station *st = Station::From(bst); + + uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO; + for (CargoID i = 0; i < num_cargo; i++) { + GoodsEntry *ge = &st->goods[i]; + if (IsSavegameVersionBefore(SLV_183)) { + SwapPackets(ge); // We have to swap back again to be in the format pre-183 expects. + SlObject(ge, this->GetDescription()); + SwapPackets(ge); + } else { + SlObject(ge, this->GetDescription()); + } + } + } +}; + static void Load_STNS() { + static const SlStationGoods station_goods; + static const SlStationSpecList station_spec_list; + _cargo_source_xy = 0; _cargo_days = 0; _cargo_feeder_share = 0; @@ -323,7 +473,7 @@ static void Load_STNS() for (CargoID i = 0; i < num_cargo; i++) { GoodsEntry *ge = &st->goods[i]; - SlObject(ge, GetGoodsDesc()); + SlObject(ge, station_goods.GetDescription()); SwapPackets(ge); if (IsSavegameVersionBefore(SLV_68)) { SB(ge->status, GoodsEntry::GES_ACCEPTANCE, 1, HasBit(_waiting_acceptance, 15)); @@ -349,7 +499,7 @@ static void Load_STNS() /* Allocate speclist memory when loading a game */ st->speclist = CallocT(st->num_specs); for (uint i = 0; i < st->num_specs; i++) { - SlObject(&st->speclist[i], _station_speclist_desc); + SlObject(&st->speclist[i], station_spec_list.GetDescription()); } } } @@ -357,6 +507,8 @@ static void Load_STNS() static void Ptrs_STNS() { + static const SlStationGoods station_goods; + /* Don't run when savegame version is higher than or equal to 123. */ if (!IsSavegameVersionBefore(SLV_123)) return; @@ -366,7 +518,7 @@ static void Ptrs_STNS() for (CargoID i = 0; i < num_cargo; i++) { GoodsEntry *ge = &st->goods[i]; SwapPackets(ge); - SlObject(ge, GetGoodsDesc()); + SlObject(ge, station_goods.GetDescription()); SwapPackets(ge); } } @@ -374,8 +526,6 @@ static void Ptrs_STNS() } } -static OldPersistentStorage _old_st_persistent_storage; - /** * SaveLoad handler for the BaseStation, which all other stations / waypoints * make use of. @@ -447,6 +597,7 @@ public: SLE_REFLIST(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), + SLEG_STRUCTLIST(SlStationGoods), }; void GenericSaveLoad(BaseStation *bst) const @@ -486,52 +637,15 @@ static const SaveLoad _station_desc[] = { SLE_SAVEBYTE(BaseStation, facilities), SLEG_STRUCT(SlStationNormal), SLEG_STRUCT(SlStationWaypoint), + SLEG_CONDSTRUCTLIST(SlStationSpecList, SLV_27, SL_MAX_VERSION), }; -static void RealSave_STNN(BaseStation *bst) -{ - SlObject(bst, _station_desc); - - if ((bst->facilities & FACIL_WAYPOINT) == 0) { - Station *st = Station::From(bst); - for (CargoID i = 0; i < NUM_CARGO; i++) { - _num_dests = (uint32)st->goods[i].cargo.Packets()->MapSize(); - _num_flows = 0; - for (FlowStatMap::const_iterator it(st->goods[i].flows.begin()); it != st->goods[i].flows.end(); ++it) { - _num_flows += (uint32)it->second.GetShares()->size(); - } - SlObject(&st->goods[i], GetGoodsDesc()); - 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; - FlowSaveLoad flow; - flow.source = outer_it->first; - for (FlowStat::SharesMap::const_iterator inner_it(shares->begin()); inner_it != shares->end(); ++inner_it) { - flow.via = inner_it->second; - flow.share = inner_it->first - sum_shares; - flow.restricted = inner_it->first > outer_it->second.GetUnrestricted(); - sum_shares = inner_it->first; - assert(flow.share > 0); - SlObject(&flow, _flow_desc); - } - } - 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); - } - } - } - - for (uint i = 0; i < bst->num_specs; i++) { - SlObject(&bst->speclist[i], _station_speclist_desc); - } -} - static void Save_STNN() { /* Write the stations */ for (BaseStation *st : BaseStation::Iterate()) { SlSetArrayIndex(st->index); - SlAutolength((AutolengthProc*)RealSave_STNN, st); + SlObject(st, _station_desc); } } @@ -539,59 +653,12 @@ static void Load_STNN() { _num_flows = 0; - uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO; int index; while ((index = SlIterateArray()) != -1) { bool waypoint = (SlReadByte() & FACIL_WAYPOINT) != 0; BaseStation *bst = waypoint ? (BaseStation *)new (index) Waypoint() : new (index) Station(); SlObject(bst, _station_desc); - - if (!waypoint) { - Station *st = Station::From(bst); - - /* Before savegame version 161, persistent storages were not stored in a pool. */ - if (IsSavegameVersionBefore(SLV_161) && !IsSavegameVersionBefore(SLV_145) && st->facilities & FACIL_AIRPORT) { - /* Store the old persistent storage. The GRFID will be added later. */ - assert(PersistentStorage::CanAllocateItem()); - st->airport.psa = new PersistentStorage(0, 0, 0); - memcpy(st->airport.psa->storage, _old_st_persistent_storage.storage, sizeof(_old_st_persistent_storage.storage)); - } - - for (CargoID i = 0; i < num_cargo; i++) { - SlObject(&st->goods[i], GetGoodsDesc()); - FlowSaveLoad flow; - FlowStat *fs = nullptr; - StationID prev_source = INVALID_STATION; - for (uint32 j = 0; j < _num_flows; ++j) { - SlObject(&flow, _flow_desc); - if (fs == nullptr || prev_source != flow.source) { - fs = &(st->goods[i].flows.insert(std::make_pair(flow.source, FlowStat(flow.via, flow.share, flow.restricted))).first->second); - } else { - fs->AppendShare(flow.via, flow.share, flow.restricted); - } - prev_source = flow.source; - } - if (IsSavegameVersionBefore(SLV_183)) { - SwapPackets(&st->goods[i]); - } else { - StationCargoPair pair; - for (uint j = 0; j < _num_dests; ++j) { - SlObject(&pair, _cargo_list_desc); - const_cast(*(st->goods[i].cargo.Packets()))[pair.first].swap(pair.second); - assert(pair.second.empty()); - } - } - } - } - - if (bst->num_specs != 0) { - /* 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); - } - } } } @@ -600,26 +667,8 @@ static void Ptrs_STNN() /* Don't run when savegame version lower than 123. */ if (IsSavegameVersionBefore(SLV_123)) return; - uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO; - for (Station *st : Station::Iterate()) { - for (CargoID i = 0; i < num_cargo; i++) { - GoodsEntry *ge = &st->goods[i]; - if (IsSavegameVersionBefore(SLV_183)) { - SwapPackets(ge); - SlObject(ge, GetGoodsDesc()); - SwapPackets(ge); - } else { - SlObject(ge, GetGoodsDesc()); - for (StationCargoPacketMap::ConstMapIterator it = ge->cargo.Packets()->begin(); it != ge->cargo.Packets()->end(); ++it) { - SlObject(const_cast(&(*it)), _cargo_list_desc); - } - } - } - SlObject(st, _station_desc); - } - - for (Waypoint *wp : Waypoint::Iterate()) { - SlObject(wp, _station_desc); + for (BaseStation *bst : BaseStation::Iterate()) { + SlObject(bst, _station_desc); } } From aa02bf27f6217f6ba9006ae95856ecdd837245c9 Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Thu, 10 Jun 2021 11:11:55 +0200 Subject: [PATCH 06/20] Codechange: use as much of STNN code for STNS as possible There was a lot of code duplication for no real reason. Now with SLEG_STRUCT support, we can just re-use the code, hopefully making it easier for future-us to make changes to this, without breaking everything for old games. --- src/saveload/station_sl.cpp | 215 ++++++++++++++++-------------------- 1 file changed, 96 insertions(+), 119 deletions(-) diff --git a/src/saveload/station_sl.cpp b/src/saveload/station_sl.cpp index 21989139f9..4421e0f9f6 100644 --- a/src/saveload/station_sl.cpp +++ b/src/saveload/station_sl.cpp @@ -156,63 +156,6 @@ static const SaveLoad _roadstop_desc[] = { SLE_CONDNULL(1, SLV_25, SLV_26), }; -static const SaveLoad _old_station_desc[] = { - SLE_CONDVAR(Station, xy, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), - SLE_CONDVAR(Station, xy, SLE_UINT32, SLV_6, SL_MAX_VERSION), - SLE_CONDNULL(4, SL_MIN_VERSION, SLV_6), ///< bus/lorry tile - SLE_CONDVAR(Station, train_station.tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), - SLE_CONDVAR(Station, train_station.tile, SLE_UINT32, SLV_6, SL_MAX_VERSION), - SLE_CONDVAR(Station, airport.tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), - SLE_CONDVAR(Station, airport.tile, SLE_UINT32, SLV_6, SL_MAX_VERSION), - SLE_CONDNULL(2, SL_MIN_VERSION, SLV_6), - SLE_CONDNULL(4, SLV_6, SLV_MULTITILE_DOCKS), - SLE_REF(Station, town, REF_TOWN), - SLE_VAR(Station, train_station.w, SLE_FILE_U8 | SLE_VAR_U16), - SLE_CONDVAR(Station, train_station.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_2, SL_MAX_VERSION), - - SLE_CONDNULL(1, SL_MIN_VERSION, SLV_4), ///< alpha_order - - SLE_VAR(Station, string_id, SLE_STRINGID), - SLE_CONDSSTR(Station, name, SLE_STR | SLF_ALLOW_CONTROL, SLV_84, SL_MAX_VERSION), - SLE_CONDVAR(Station, indtype, SLE_UINT8, SLV_103, SL_MAX_VERSION), - SLE_CONDVAR(Station, had_vehicle_of_type, SLE_FILE_U16 | SLE_VAR_U8, SL_MIN_VERSION, SLV_122), - SLE_CONDVAR(Station, had_vehicle_of_type, SLE_UINT8, SLV_122, SL_MAX_VERSION), - - SLE_VAR(Station, time_since_load, SLE_UINT8), - SLE_VAR(Station, time_since_unload, SLE_UINT8), - SLE_VAR(Station, delete_ctr, SLE_UINT8), - SLE_VAR(Station, owner, SLE_UINT8), - SLE_VAR(Station, facilities, SLE_UINT8), - SLE_VAR(Station, airport.type, SLE_UINT8), - - SLE_CONDNULL(2, SL_MIN_VERSION, SLV_6), ///< Truck/bus stop status - SLE_CONDNULL(1, SL_MIN_VERSION, SLV_5), ///< Blocked months - - SLE_CONDVAR(Station, airport.flags, SLE_VAR_U64 | SLE_FILE_U16, SL_MIN_VERSION, SLV_3), - SLE_CONDVAR(Station, airport.flags, SLE_VAR_U64 | SLE_FILE_U32, SLV_3, SLV_46), - SLE_CONDVAR(Station, airport.flags, SLE_UINT64, SLV_46, SL_MAX_VERSION), - - SLE_CONDNULL(2, SL_MIN_VERSION, SLV_26), ///< last-vehicle - SLE_CONDVAR(Station, last_vehicle_type, SLE_UINT8, SLV_26, SL_MAX_VERSION), - - SLE_CONDNULL(2, SLV_3, SLV_26), ///< custom station class and id - SLE_CONDVAR(Station, build_date, SLE_FILE_U16 | SLE_VAR_I32, SLV_3, SLV_31), - SLE_CONDVAR(Station, build_date, SLE_INT32, SLV_31, SL_MAX_VERSION), - - SLE_CONDREF(Station, bus_stops, REF_ROADSTOPS, SLV_6, SL_MAX_VERSION), - SLE_CONDREF(Station, truck_stops, REF_ROADSTOPS, SLV_6, SL_MAX_VERSION), - - /* Used by newstations for graphic variations */ - SLE_CONDVAR(Station, random_bits, SLE_UINT16, SLV_27, SL_MAX_VERSION), - SLE_CONDVAR(Station, waiting_triggers, SLE_UINT8, SLV_27, SL_MAX_VERSION), - SLE_CONDVAR(Station, num_specs, SLE_UINT8, SLV_27, SL_MAX_VERSION), - - SLE_CONDREFLIST(Station, loading_vehicles, REF_VEHICLE, SLV_57, SL_MAX_VERSION), - - /* reserve extra space in savegame here. (currently 32 bytes) */ - SLE_CONDNULL(32, SLV_2, SL_MAX_VERSION), -}; - static uint16 _waiting_acceptance; static uint32 _num_flows; static uint16 _cargo_source; @@ -426,55 +369,13 @@ public: memcpy(st->airport.psa->storage, _old_st_persistent_storage.storage, sizeof(_old_st_persistent_storage.storage)); } - uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO; - for (CargoID i = 0; i < num_cargo; i++) { - SlObject(&st->goods[i], this->GetDescription()); - if (IsSavegameVersionBefore(SLV_183)) { - SwapPackets(&st->goods[i]); - } - } - } - - void FixPointers(BaseStation *bst) const override - { - Station *st = Station::From(bst); - - uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO; + uint num_cargo = IsSavegameVersionBefore(SLV_55) ? 12 : IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO; for (CargoID i = 0; i < num_cargo; i++) { GoodsEntry *ge = &st->goods[i]; + SlObject(ge, this->GetDescription()); if (IsSavegameVersionBefore(SLV_183)) { - SwapPackets(ge); // We have to swap back again to be in the format pre-183 expects. - SlObject(ge, this->GetDescription()); SwapPackets(ge); - } else { - SlObject(ge, this->GetDescription()); } - } - } -}; - -static void Load_STNS() -{ - static const SlStationGoods station_goods; - static const SlStationSpecList station_spec_list; - - _cargo_source_xy = 0; - _cargo_days = 0; - _cargo_feeder_share = 0; - - uint num_cargo = IsSavegameVersionBefore(SLV_55) ? 12 : IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO; - int index; - while ((index = SlIterateArray()) != -1) { - Station *st = new (index) Station(); - - SlObject(st, _old_station_desc); - - _waiting_acceptance = 0; - - for (CargoID i = 0; i < num_cargo; i++) { - GoodsEntry *ge = &st->goods[i]; - SlObject(ge, station_goods.GetDescription()); - SwapPackets(ge); if (IsSavegameVersionBefore(SLV_68)) { SB(ge->status, GoodsEntry::GES_ACCEPTANCE, 1, HasBit(_waiting_acceptance, 15)); if (GB(_waiting_acceptance, 0, 12) != 0) { @@ -494,34 +395,108 @@ static void Load_STNS() } } } + } - if (st->num_specs != 0) { - /* Allocate speclist memory when loading a game */ - st->speclist = CallocT(st->num_specs); - for (uint i = 0; i < st->num_specs; i++) { - SlObject(&st->speclist[i], station_spec_list.GetDescription()); + void FixPointers(BaseStation *bst) const override + { + Station *st = Station::From(bst); + + uint num_cargo = IsSavegameVersionBefore(SLV_55) ? 12 : IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO; + for (CargoID i = 0; i < num_cargo; i++) { + GoodsEntry *ge = &st->goods[i]; + if (IsSavegameVersionBefore(SLV_183)) { + SwapPackets(ge); // We have to swap back again to be in the format pre-183 expects. + SlObject(ge, this->GetDescription()); + SwapPackets(ge); + } else { + SlObject(ge, this->GetDescription()); } } } +}; + +static const SaveLoad _old_station_desc[] = { + SLE_CONDVAR(Station, xy, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), + SLE_CONDVAR(Station, xy, SLE_UINT32, SLV_6, SL_MAX_VERSION), + SLE_CONDNULL(4, SL_MIN_VERSION, SLV_6), ///< bus/lorry tile + SLE_CONDVAR(Station, train_station.tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), + SLE_CONDVAR(Station, train_station.tile, SLE_UINT32, SLV_6, SL_MAX_VERSION), + SLE_CONDVAR(Station, airport.tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), + SLE_CONDVAR(Station, airport.tile, SLE_UINT32, SLV_6, SL_MAX_VERSION), + SLE_CONDNULL(2, SL_MIN_VERSION, SLV_6), + SLE_CONDNULL(4, SLV_6, SLV_MULTITILE_DOCKS), + SLE_REF(Station, town, REF_TOWN), + SLE_VAR(Station, train_station.w, SLE_FILE_U8 | SLE_VAR_U16), + SLE_CONDVAR(Station, train_station.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_2, SL_MAX_VERSION), + + SLE_CONDNULL(1, SL_MIN_VERSION, SLV_4), ///< alpha_order + + SLE_VAR(Station, string_id, SLE_STRINGID), + SLE_CONDSSTR(Station, name, SLE_STR | SLF_ALLOW_CONTROL, SLV_84, SL_MAX_VERSION), + SLE_CONDVAR(Station, indtype, SLE_UINT8, SLV_103, SL_MAX_VERSION), + SLE_CONDVAR(Station, had_vehicle_of_type, SLE_FILE_U16 | SLE_VAR_U8, SL_MIN_VERSION, SLV_122), + SLE_CONDVAR(Station, had_vehicle_of_type, SLE_UINT8, SLV_122, SL_MAX_VERSION), + + SLE_VAR(Station, time_since_load, SLE_UINT8), + SLE_VAR(Station, time_since_unload, SLE_UINT8), + SLE_VAR(Station, delete_ctr, SLE_UINT8), + SLE_VAR(Station, owner, SLE_UINT8), + SLE_VAR(Station, facilities, SLE_UINT8), + SLE_VAR(Station, airport.type, SLE_UINT8), + + SLE_CONDNULL(2, SL_MIN_VERSION, SLV_6), ///< Truck/bus stop status + SLE_CONDNULL(1, SL_MIN_VERSION, SLV_5), ///< Blocked months + + SLE_CONDVAR(Station, airport.flags, SLE_VAR_U64 | SLE_FILE_U16, SL_MIN_VERSION, SLV_3), + SLE_CONDVAR(Station, airport.flags, SLE_VAR_U64 | SLE_FILE_U32, SLV_3, SLV_46), + SLE_CONDVAR(Station, airport.flags, SLE_UINT64, SLV_46, SL_MAX_VERSION), + + SLE_CONDNULL(2, SL_MIN_VERSION, SLV_26), ///< last-vehicle + SLE_CONDVAR(Station, last_vehicle_type, SLE_UINT8, SLV_26, SL_MAX_VERSION), + + SLE_CONDNULL(2, SLV_3, SLV_26), ///< custom station class and id + SLE_CONDVAR(Station, build_date, SLE_FILE_U16 | SLE_VAR_I32, SLV_3, SLV_31), + SLE_CONDVAR(Station, build_date, SLE_INT32, SLV_31, SL_MAX_VERSION), + + SLE_CONDREF(Station, bus_stops, REF_ROADSTOPS, SLV_6, SL_MAX_VERSION), + SLE_CONDREF(Station, truck_stops, REF_ROADSTOPS, SLV_6, SL_MAX_VERSION), + + /* Used by newstations for graphic variations */ + SLE_CONDVAR(Station, random_bits, SLE_UINT16, SLV_27, SL_MAX_VERSION), + SLE_CONDVAR(Station, waiting_triggers, SLE_UINT8, SLV_27, SL_MAX_VERSION), + SLE_CONDVAR(Station, num_specs, SLE_UINT8, SLV_27, SL_MAX_VERSION), + + SLE_CONDREFLIST(Station, loading_vehicles, REF_VEHICLE, SLV_57, SL_MAX_VERSION), + + /* reserve extra space in savegame here. (currently 32 bytes) */ + SLE_CONDNULL(32, SLV_2, SL_MAX_VERSION), + SLEG_STRUCTLIST(SlStationGoods), + SLEG_CONDSTRUCTLIST(SlStationSpecList, SLV_27, SL_MAX_VERSION), +}; + +static void Load_STNS() +{ + _cargo_source_xy = 0; + _cargo_days = 0; + _cargo_feeder_share = 0; + + int index; + while ((index = SlIterateArray()) != -1) { + Station *st = new (index) Station(); + + _waiting_acceptance = 0; + SlObject(st, _old_station_desc); + } } static void Ptrs_STNS() { - static const SlStationGoods station_goods; - - /* Don't run when savegame version is higher than or equal to 123. */ + /* From SLV_123 we store stations in STNN; before that in STNS. So do not + * fix pointers when the version is SLV_123 or up, as that would fix + * pointers twice: once in STNN chunk and once here. */ if (!IsSavegameVersionBefore(SLV_123)) return; - uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO; for (Station *st : Station::Iterate()) { - if (!IsSavegameVersionBefore(SLV_68)) { - for (CargoID i = 0; i < num_cargo; i++) { - GoodsEntry *ge = &st->goods[i]; - SwapPackets(ge); - SlObject(ge, station_goods.GetDescription()); - SwapPackets(ge); - } - } SlObject(st, _old_station_desc); } } @@ -664,7 +639,9 @@ static void Load_STNN() static void Ptrs_STNN() { - /* Don't run when savegame version lower than 123. */ + /* From SLV_123 we store stations in STNN; before that in STNS. So do not + * fix pointers when the version is below SLV_123, as that would fix + * pointers twice: once in STNS chunk and once here. */ if (IsSavegameVersionBefore(SLV_123)) return; for (BaseStation *bst : BaseStation::Iterate()) { From af3aba7a8830ad19fbb32819cd74ff4d5d7f51c5 Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Mon, 14 Jun 2021 13:32:12 +0200 Subject: [PATCH 07/20] Codechange: use SLE_STRUCT(LIST) for GameScript chunks --- src/saveload/game_sl.cpp | 61 +++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/src/saveload/game_sl.cpp b/src/saveload/game_sl.cpp index a1093eaf49..af01d5bd07 100644 --- a/src/saveload/game_sl.cpp +++ b/src/saveload/game_sl.cpp @@ -111,28 +111,36 @@ static void Save_GSDT() extern GameStrings *_current_data; static std::string _game_saveload_string; -static uint _game_saveload_strings; +static uint32 _game_saveload_strings; -static const SaveLoad _game_language_header[] = { - SLEG_SSTR(_game_saveload_string, SLE_STR), - SLEG_VAR(_game_saveload_strings, SLE_UINT32), -}; +class SlGameLanguageString : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLEG_SSTR(_game_saveload_string, SLE_STR | SLF_ALLOW_CONTROL), + }; -static const SaveLoad _game_language_string[] = { - SLEG_SSTR(_game_saveload_string, SLE_STR | SLF_ALLOW_CONTROL), -}; - -static void SaveReal_GSTR(const LanguageStrings *ls) -{ - _game_saveload_string = ls->language.c_str(); - _game_saveload_strings = (uint)ls->lines.size(); - - SlObject(nullptr, _game_language_header); - for (const auto &i : ls->lines) { - _game_saveload_string = i.c_str(); - SlObject(nullptr, _game_language_string); + void Save(LanguageStrings *ls) const override + { + for (const auto &string : ls->lines) { + _game_saveload_string = string; + SlObject(nullptr, this->GetDescription()); + } } -} + + void Load(LanguageStrings *ls) const override + { + for (uint32 i = 0; i < _game_saveload_strings; i++) { + SlObject(nullptr, this->GetDescription()); + ls->lines.emplace_back(_game_saveload_string); + } + } +}; + +static const SaveLoad _game_language_desc[] = { + SLE_SSTR(LanguageStrings, language, SLE_STR), + SLEG_VAR(_game_saveload_strings, SLE_UINT32), + SLEG_STRUCTLIST(SlGameLanguageString), +}; static void Load_GSTR() { @@ -140,15 +148,8 @@ static void Load_GSTR() _current_data = new GameStrings(); while (SlIterateArray() != -1) { - _game_saveload_string.clear(); - SlObject(nullptr, _game_language_header); - - LanguageStrings ls(_game_saveload_string); - for (uint i = 0; i < _game_saveload_strings; i++) { - SlObject(nullptr, _game_language_string); - ls.lines.emplace_back(_game_saveload_string); - } - + LanguageStrings ls; + SlObject(&ls, _game_language_desc); _current_data->raw_strings.push_back(std::move(ls)); } @@ -169,7 +170,9 @@ static void Save_GSTR() for (uint i = 0; i < _current_data->raw_strings.size(); i++) { SlSetArrayIndex(i); - SlAutolength((AutolengthProc *)SaveReal_GSTR, &_current_data->raw_strings[i]); + LanguageStrings *ls = &_current_data->raw_strings[i]; + _game_saveload_strings = (uint32)ls->lines.size(); + SlObject(ls, _game_language_desc); } } From 5cd0c65787a4c04bbb2294cf2e676eb5649e49fe Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Mon, 14 Jun 2021 14:03:03 +0200 Subject: [PATCH 08/20] Codechange: move Save/Load functions of same chunk next to each other --- src/saveload/linkgraph_sl.cpp | 138 +++++++++++++++++----------------- 1 file changed, 69 insertions(+), 69 deletions(-) diff --git a/src/saveload/linkgraph_sl.cpp b/src/saveload/linkgraph_sl.cpp index 0640dba19c..4fcc36e960 100644 --- a/src/saveload/linkgraph_sl.cpp +++ b/src/saveload/linkgraph_sl.cpp @@ -143,75 +143,6 @@ void SaveLoad_LinkGraph(LinkGraph &lg) } } -/** - * Save a link graph job. - * @param lgj LinkGraphJob to be saved. - */ -static void DoSave_LGRJ(LinkGraphJob *lgj) -{ - SlObject(lgj, GetLinkGraphJobDesc()); - _num_nodes = lgj->Size(); - SlObject(const_cast(&lgj->Graph()), GetLinkGraphDesc()); - SaveLoad_LinkGraph(const_cast(lgj->Graph())); -} - -/** - * Save a link graph. - * @param lg LinkGraph to be saved. - */ -static void DoSave_LGRP(LinkGraph *lg) -{ - _num_nodes = lg->Size(); - SlObject(lg, GetLinkGraphDesc()); - SaveLoad_LinkGraph(*lg); -} - -/** - * Load all link graphs. - */ -static void Load_LGRP() -{ - int index; - while ((index = SlIterateArray()) != -1) { - if (!LinkGraph::CanAllocateItem()) { - /* Impossible as they have been present in previous game. */ - NOT_REACHED(); - } - LinkGraph *lg = new (index) LinkGraph(); - SlObject(lg, GetLinkGraphDesc()); - lg->Init(_num_nodes); - SaveLoad_LinkGraph(*lg); - } -} - -/** - * Load all link graph jobs. - */ -static void Load_LGRJ() -{ - int index; - while ((index = SlIterateArray()) != -1) { - if (!LinkGraphJob::CanAllocateItem()) { - /* Impossible as they have been present in previous game. */ - NOT_REACHED(); - } - LinkGraphJob *lgj = new (index) LinkGraphJob(); - SlObject(lgj, GetLinkGraphJobDesc()); - LinkGraph &lg = const_cast(lgj->Graph()); - SlObject(&lg, GetLinkGraphDesc()); - lg.Init(_num_nodes); - SaveLoad_LinkGraph(lg); - } -} - -/** - * Load the link graph schedule. - */ -static void Load_LGRS() -{ - SlObject(&LinkGraphSchedule::instance, GetLinkGraphScheduleDesc()); -} - /** * Spawn the threads for running link graph calculations. * Has to be done after loading as the cargo classes might have changed. @@ -242,6 +173,17 @@ void AfterLoadLinkGraphs() } } +/** + * Save a link graph. + * @param lg LinkGraph to be saved. + */ +static void DoSave_LGRP(LinkGraph *lg) +{ + _num_nodes = lg->Size(); + SlObject(lg, GetLinkGraphDesc()); + SaveLoad_LinkGraph(*lg); +} + /** * Save all link graphs. */ @@ -253,6 +195,36 @@ static void Save_LGRP() } } +/** + * Load all link graphs. + */ +static void Load_LGRP() +{ + int index; + while ((index = SlIterateArray()) != -1) { + if (!LinkGraph::CanAllocateItem()) { + /* Impossible as they have been present in previous game. */ + NOT_REACHED(); + } + LinkGraph *lg = new (index) LinkGraph(); + SlObject(lg, GetLinkGraphDesc()); + lg->Init(_num_nodes); + SaveLoad_LinkGraph(*lg); + } +} + +/** + * Save a link graph job. + * @param lgj LinkGraphJob to be saved. + */ +static void DoSave_LGRJ(LinkGraphJob *lgj) +{ + SlObject(lgj, GetLinkGraphJobDesc()); + _num_nodes = lgj->Size(); + SlObject(const_cast(&lgj->Graph()), GetLinkGraphDesc()); + SaveLoad_LinkGraph(const_cast(lgj->Graph())); +} + /** * Save all link graph jobs. */ @@ -264,6 +236,26 @@ static void Save_LGRJ() } } +/** + * Load all link graph jobs. + */ +static void Load_LGRJ() +{ + int index; + while ((index = SlIterateArray()) != -1) { + if (!LinkGraphJob::CanAllocateItem()) { + /* Impossible as they have been present in previous game. */ + NOT_REACHED(); + } + LinkGraphJob *lgj = new (index) LinkGraphJob(); + SlObject(lgj, GetLinkGraphJobDesc()); + LinkGraph &lg = const_cast(lgj->Graph()); + SlObject(&lg, GetLinkGraphDesc()); + lg.Init(_num_nodes); + SaveLoad_LinkGraph(lg); + } +} + /** * Save the link graph schedule. */ @@ -272,6 +264,14 @@ static void Save_LGRS() SlObject(&LinkGraphSchedule::instance, GetLinkGraphScheduleDesc()); } +/** + * Load the link graph schedule. + */ +static void Load_LGRS() +{ + SlObject(&LinkGraphSchedule::instance, GetLinkGraphScheduleDesc()); +} + /** * Substitute pointers in link graph schedule. */ From 7b135a8269c6165f9d9fdec005413c5c3cd7797a Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Mon, 14 Jun 2021 14:55:37 +0200 Subject: [PATCH 09/20] Codechange: use SLE_STRUCT(LIST) for Linkgraph chunks --- src/linkgraph/linkgraph.h | 3 +- src/saveload/linkgraph_sl.cpp | 193 ++++++++++++++++++---------------- 2 files changed, 106 insertions(+), 90 deletions(-) diff --git a/src/linkgraph/linkgraph.h b/src/linkgraph/linkgraph.h index 5eb85e4c3c..a11b67a521 100644 --- a/src/linkgraph/linkgraph.h +++ b/src/linkgraph/linkgraph.h @@ -527,7 +527,8 @@ protected: friend class LinkGraph::Node; friend SaveLoadTable GetLinkGraphDesc(); friend SaveLoadTable GetLinkGraphJobDesc(); - friend void SaveLoad_LinkGraph(LinkGraph &lg); + friend class SlLinkgraphNode; + friend class SlLinkgraphEdge; 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/linkgraph_sl.cpp b/src/saveload/linkgraph_sl.cpp index 4fcc36e960..cf0292e6ef 100644 --- a/src/saveload/linkgraph_sl.cpp +++ b/src/saveload/linkgraph_sl.cpp @@ -21,6 +21,79 @@ typedef LinkGraph::BaseNode Node; typedef LinkGraph::BaseEdge Edge; static uint16 _num_nodes; +static LinkGraph *_linkgraph; ///< Contains the current linkgraph being saved/loaded. +static NodeID _linkgraph_from; ///< Contains the current "from" node being saved/loaded. + +class SlLinkgraphEdge : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_CONDNULL(4, SL_MIN_VERSION, SLV_191), // distance + SLE_VAR(Edge, capacity, SLE_UINT32), + SLE_VAR(Edge, usage, SLE_UINT32), + SLE_VAR(Edge, last_unrestricted_update, SLE_INT32), + SLE_CONDVAR(Edge, last_restricted_update, SLE_INT32, SLV_187, SL_MAX_VERSION), + SLE_VAR(Edge, next_edge, SLE_UINT16), + }; + + void Save(Node *bn) const override + { + for (NodeID to = _linkgraph_from; to != INVALID_NODE; to = _linkgraph->edges[_linkgraph_from][to].next_edge) { + SlObject(&_linkgraph->edges[_linkgraph_from][to], this->GetDescription()); + } + } + + void Load(Node *bn) const override + { + uint16 max_size = _linkgraph->Size(); + + if (IsSavegameVersionBefore(SLV_191)) { + /* We used to save the full matrix ... */ + for (NodeID to = 0; to < max_size; ++to) { + SlObject(&_linkgraph->edges[_linkgraph_from][to], this->GetDescription()); + } + return; + } + + /* ... but as that wasted a lot of space we save a sparse matrix now. */ + for (NodeID to = _linkgraph_from; to != INVALID_NODE; to = _linkgraph->edges[_linkgraph_from][to].next_edge) { + if (to >= max_size) SlErrorCorrupt("Link graph structure overflow"); + SlObject(&_linkgraph->edges[_linkgraph_from][to], this->GetDescription()); + } + } +}; + +class SlLinkgraphNode : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_CONDVAR(Node, xy, SLE_UINT32, SLV_191, SL_MAX_VERSION), + SLE_VAR(Node, supply, SLE_UINT32), + SLE_VAR(Node, demand, SLE_UINT32), + SLE_VAR(Node, station, SLE_UINT16), + SLE_VAR(Node, last_update, SLE_INT32), + SLEG_STRUCTLIST(SlLinkgraphEdge), + }; + + void Save(LinkGraph *lg) const override + { + _linkgraph = lg; + + for (NodeID from = 0; from < lg->Size(); ++from) { + _linkgraph_from = from; + SlObject(&lg->nodes[from], this->GetDescription()); + } + } + + void Load(LinkGraph *lg) const override + { + _linkgraph = lg; + + lg->Init(_num_nodes); + for (NodeID from = 0; from < _num_nodes; ++from) { + _linkgraph_from = from; + SlObject(&lg->nodes[from], this->GetDescription()); + } + } +}; /** * Get a SaveLoad array for a link graph. @@ -32,10 +105,34 @@ SaveLoadTable GetLinkGraphDesc() SLE_VAR(LinkGraph, last_compression, SLE_INT32), SLEG_VAR(_num_nodes, SLE_UINT16), SLE_VAR(LinkGraph, cargo, SLE_UINT8), + SLEG_STRUCTLIST(SlLinkgraphNode), }; return link_graph_desc; } +/** + * Proxy to reuse LinkGraph to save/load a LinkGraphJob. + * One of the members of a LinkGraphJob is a LinkGraph, but SLEG_STRUCT() + * doesn't allow us to select a member. So instead, we add a bit of glue to + * accept a LinkGraphJob, get the LinkGraph, and use that to call the + * save/load routines for a regular LinkGraph. + */ +class SlLinkgraphJobProxy : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = {{}}; // Needed to keep DefaultSaveLoadHandler happy. + SaveLoadTable GetDescription() const override { return GetLinkGraphDesc(); } + + void Save(LinkGraphJob *lgj) const override + { + SlObject(const_cast(&lgj->Graph()), GetLinkGraphDesc()); + } + + void Load(LinkGraphJob *lgj) const override + { + SlObject(const_cast(&lgj->Graph()), GetLinkGraphDesc()); + } +}; + /** * Get a SaveLoad array for a link graph job. The settings struct is derived from * the global settings saveload array. The exact entries are calculated when the function @@ -53,6 +150,7 @@ SaveLoadTable GetLinkGraphJobDesc() static const SaveLoad job_desc[] = { SLE_VAR(LinkGraphJob, join_date, SLE_INT32), SLE_VAR(LinkGraphJob, link_graph.index, SLE_UINT16), + SLEG_STRUCT(SlLinkgraphJobProxy), }; /* The member offset arithmetic below is only valid if the types in question @@ -93,56 +191,6 @@ SaveLoadTable GetLinkGraphScheduleDesc() return schedule_desc; } -/* Edges and nodes are saved in the correct order, so we don't need to save their IDs. */ - -/** - * SaveLoad desc for a link graph node. - */ -static const SaveLoad _node_desc[] = { - SLE_CONDVAR(Node, xy, SLE_UINT32, SLV_191, SL_MAX_VERSION), - SLE_VAR(Node, supply, SLE_UINT32), - SLE_VAR(Node, demand, SLE_UINT32), - SLE_VAR(Node, station, SLE_UINT16), - SLE_VAR(Node, last_update, SLE_INT32), -}; - -/** - * SaveLoad desc for a link graph edge. - */ -static const SaveLoad _edge_desc[] = { - SLE_CONDNULL(4, SL_MIN_VERSION, SLV_191), // distance - SLE_VAR(Edge, capacity, SLE_UINT32), - SLE_VAR(Edge, usage, SLE_UINT32), - SLE_VAR(Edge, last_unrestricted_update, SLE_INT32), - SLE_CONDVAR(Edge, last_restricted_update, SLE_INT32, SLV_187, SL_MAX_VERSION), - SLE_VAR(Edge, next_edge, SLE_UINT16), -}; - -/** - * Save/load a link graph. - * @param lg Link graph to be saved or loaded. - */ -void SaveLoad_LinkGraph(LinkGraph &lg) -{ - uint16 size = lg.Size(); - for (NodeID from = 0; from < size; ++from) { - Node *node = &lg.nodes[from]; - SlObject(node, _node_desc); - 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); - } - } 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) { - if (to >= size) SlErrorCorrupt("Link graph structure overflow"); - SlObject(&lg.edges[from][to], _edge_desc); - } - } - } -} - /** * Spawn the threads for running link graph calculations. * Has to be done after loading as the cargo classes might have changed. @@ -173,25 +221,16 @@ void AfterLoadLinkGraphs() } } -/** - * Save a link graph. - * @param lg LinkGraph to be saved. - */ -static void DoSave_LGRP(LinkGraph *lg) -{ - _num_nodes = lg->Size(); - SlObject(lg, GetLinkGraphDesc()); - SaveLoad_LinkGraph(*lg); -} - /** * Save all link graphs. */ static void Save_LGRP() { for (LinkGraph *lg : LinkGraph::Iterate()) { + _num_nodes = lg->Size(); + SlSetArrayIndex(lg->index); - SlAutolength((AutolengthProc*)DoSave_LGRP, lg); + SlObject(lg, GetLinkGraphDesc()); } } @@ -202,37 +241,21 @@ static void Load_LGRP() { int index; while ((index = SlIterateArray()) != -1) { - if (!LinkGraph::CanAllocateItem()) { - /* Impossible as they have been present in previous game. */ - NOT_REACHED(); - } LinkGraph *lg = new (index) LinkGraph(); SlObject(lg, GetLinkGraphDesc()); - lg->Init(_num_nodes); - SaveLoad_LinkGraph(*lg); } } -/** - * Save a link graph job. - * @param lgj LinkGraphJob to be saved. - */ -static void DoSave_LGRJ(LinkGraphJob *lgj) -{ - SlObject(lgj, GetLinkGraphJobDesc()); - _num_nodes = lgj->Size(); - SlObject(const_cast(&lgj->Graph()), GetLinkGraphDesc()); - SaveLoad_LinkGraph(const_cast(lgj->Graph())); -} - /** * Save all link graph jobs. */ static void Save_LGRJ() { for (LinkGraphJob *lgj : LinkGraphJob::Iterate()) { + _num_nodes = lgj->Size(); + SlSetArrayIndex(lgj->index); - SlAutolength((AutolengthProc*)DoSave_LGRJ, lgj); + SlObject(lgj, GetLinkGraphJobDesc()); } } @@ -243,16 +266,8 @@ static void Load_LGRJ() { int index; while ((index = SlIterateArray()) != -1) { - if (!LinkGraphJob::CanAllocateItem()) { - /* Impossible as they have been present in previous game. */ - NOT_REACHED(); - } LinkGraphJob *lgj = new (index) LinkGraphJob(); SlObject(lgj, GetLinkGraphJobDesc()); - LinkGraph &lg = const_cast(lgj->Graph()); - SlObject(&lg, GetLinkGraphDesc()); - lg.Init(_num_nodes); - SaveLoad_LinkGraph(lg); } } From 9e32c618f900746dd6848809bb175c993976316b Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Sun, 13 Jun 2021 23:06:15 +0200 Subject: [PATCH 10/20] Fix: [Network] Determining GetNetworkRevisionString could overflow and underflow its buffer Tagged releases are not affected --- src/network/core/game_info.cpp | 49 ++++++++++++++-------------------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/src/network/core/game_info.cpp b/src/network/core/game_info.cpp index 539b48af5f..15648de62f 100644 --- a/src/network/core/game_info.cpp +++ b/src/network/core/game_info.cpp @@ -36,45 +36,36 @@ NetworkServerGameInfo _network_game_info; ///< Information about our game. /** * Get the network version string used by this build. - * The returned string is guaranteed to be at most NETWORK_REVISON_LENGTH bytes. + * The returned string is guaranteed to be at most NETWORK_REVISON_LENGTH bytes including '\0' terminator. */ const char *GetNetworkRevisionString() { - /* This will be allocated on heap and never free'd, but only once so not a "real" leak. */ - static char *network_revision = nullptr; + static std::string network_revision; - if (!network_revision) { - /* Start by taking a chance on the full revision string. */ - network_revision = stredup(_openttd_revision); - /* Ensure it's not longer than the packet buffer length. */ - if (strlen(network_revision) >= NETWORK_REVISION_LENGTH) network_revision[NETWORK_REVISION_LENGTH - 1] = '\0'; - - /* Tag names are not mangled further. */ + if (network_revision.empty()) { + std::string network_revision = _openttd_revision; if (_openttd_revision_tagged) { - Debug(net, 3, "Network revision name: {}", network_revision); - return network_revision; - } + /* Tagged; do not mangle further, though ensure it's not too long. */ + if (network_revision.size() >= NETWORK_REVISION_LENGTH) network_revision.resize(NETWORK_REVISION_LENGTH - 1); + } else { + /* Not tagged; add the githash suffix while ensuring the string does not become too long. */ + assert(_openttd_revision_modified < 3); + std::string githash_suffix = fmt::format("-{}{}", "gum"[_openttd_revision_modified], _openttd_revision_hash); + if (githash_suffix.size() > GITHASH_SUFFIX_LEN) githash_suffix.resize(GITHASH_SUFFIX_LEN); - /* Prepare a prefix of the git hash. - * Size is length + 1 for terminator, +2 for -g prefix. */ - assert(_openttd_revision_modified < 3); - char githash_suffix[GITHASH_SUFFIX_LEN + 1] = "-"; - githash_suffix[1] = "gum"[_openttd_revision_modified]; - for (uint i = 2; i < GITHASH_SUFFIX_LEN; i++) { - githash_suffix[i] = _openttd_revision_hash[i-2]; - } + /* Where did the hash start in the original string? Overwrite from that position, unless that would create a too long string. */ + size_t hash_end = network_revision.find_last_of('-'); + if (hash_end == std::string::npos) hash_end = network_revision.size(); + if (hash_end + githash_suffix.size() >= NETWORK_REVISION_LENGTH) hash_end = NETWORK_REVISION_LENGTH - githash_suffix.size() - 1; - /* Where did the hash start in the original string? - * Overwrite from that position, unless that would go past end of packet buffer length. */ - ptrdiff_t hashofs = strrchr(_openttd_revision, '-') - _openttd_revision; - if (hashofs + strlen(githash_suffix) + 1 > NETWORK_REVISION_LENGTH) hashofs = strlen(network_revision) - strlen(githash_suffix); - /* Replace the git hash in revision string. */ - strecpy(network_revision + hashofs, githash_suffix, network_revision + NETWORK_REVISION_LENGTH); - assert(strlen(network_revision) < NETWORK_REVISION_LENGTH); // strlen does not include terminator, constant does, hence strictly less than + /* Replace the git hash in revision string. */ + network_revision.replace(hash_end, std::string::npos, githash_suffix); + } + assert(network_revision.size() < NETWORK_REVISION_LENGTH); // size does not include terminator, constant does, hence strictly less than Debug(net, 3, "Network revision name: {}", network_revision); } - return network_revision; + return network_revision.c_str(); } /** From 36705f1dc0d7c5436780d8915c147d9f55eaa191 Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Sun, 13 Jun 2021 20:59:42 +0200 Subject: [PATCH 11/20] Codechange: [Network] Simplify formatting of network addresses to string --- src/network/core/address.cpp | 32 ++++++++++---------------------- src/network/core/address.h | 1 - 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/src/network/core/address.cpp b/src/network/core/address.cpp index 8f74ed7542..478dc1b2cd 100644 --- a/src/network/core/address.cpp +++ b/src/network/core/address.cpp @@ -71,26 +71,17 @@ void NetworkAddress::SetPort(uint16 port) } /** - * Get the address as a string, e.g. 127.0.0.1:12345. - * @param buffer the buffer to write to - * @param last the last element in the buffer - * @param with_family whether to add the family (e.g. IPvX). + * Helper to get the formatting string of an address for a given family. + * @param family The family to get the address format for. + * @param with_family Whether to add the familty to the address (e.g. IPv4). + * @return The format string for the address. */ -void NetworkAddress::GetAddressAsString(char *buffer, const char *last, bool with_family) +static const char *GetAddressFormatString(uint16 family, bool with_family) { - if (this->GetAddress()->ss_family == AF_INET6) buffer = strecpy(buffer, "[", last); - buffer = strecpy(buffer, this->GetHostname(), last); - if (this->GetAddress()->ss_family == AF_INET6) buffer = strecpy(buffer, "]", last); - buffer += seprintf(buffer, last, ":%d", this->GetPort()); - - if (with_family) { - char family; - switch (this->address.ss_family) { - case AF_INET: family = '4'; break; - case AF_INET6: family = '6'; break; - default: family = '?'; break; - } - seprintf(buffer, last, " (IPv%c)", family); + switch (family) { + case AF_INET: return with_family ? "{}:{} (IPv4)" : "{}:{}"; + case AF_INET6: return with_family ? "[{}]:{} (IPv6)" : "[{}]:{}"; + default: return with_family ? "{}:{} (IPv?)" : "{}:{}"; } } @@ -101,10 +92,7 @@ void NetworkAddress::GetAddressAsString(char *buffer, const char *last, bool wit */ std::string NetworkAddress::GetAddressAsString(bool with_family) { - /* 7 extra are for with_family, which adds " (IPvX)". */ - char buf[NETWORK_HOSTNAME_PORT_LENGTH + 7]; - this->GetAddressAsString(buf, lastof(buf), with_family); - return buf; + return fmt::format(GetAddressFormatString(this->GetAddress()->ss_family, with_family), this->GetHostname(), this->GetPort()); } /** diff --git a/src/network/core/address.h b/src/network/core/address.h index c3f95b4925..eac21c76ae 100644 --- a/src/network/core/address.h +++ b/src/network/core/address.h @@ -89,7 +89,6 @@ public: } const char *GetHostname(); - void GetAddressAsString(char *buffer, const char *last, bool with_family = true); std::string GetAddressAsString(bool with_family = true); const sockaddr_storage *GetAddress(); From a91e29b656d91b1f1c6a906ee8e81ddd716723aa Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Sun, 13 Jun 2021 21:29:40 +0200 Subject: [PATCH 12/20] Codechange: [Network] Let IsInNetmask use std::string --- src/network/core/address.cpp | 11 +++++------ src/network/core/address.h | 2 +- src/network/core/tcp_listen.h | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/network/core/address.cpp b/src/network/core/address.cpp index 478dc1b2cd..ba9ae69fc4 100644 --- a/src/network/core/address.cpp +++ b/src/network/core/address.cpp @@ -143,7 +143,7 @@ bool NetworkAddress::IsFamily(int family) * @note netmask without /n assumes all bits need to match. * @return true if this IP is within the netmask. */ -bool NetworkAddress::IsInNetmask(const char *netmask) +bool NetworkAddress::IsInNetmask(const std::string &netmask) { /* Resolve it if we didn't do it already */ if (!this->IsResolved()) this->GetAddress(); @@ -153,16 +153,15 @@ bool NetworkAddress::IsInNetmask(const char *netmask) NetworkAddress mask_address; /* Check for CIDR separator */ - const char *chr_cidr = strchr(netmask, '/'); - if (chr_cidr != nullptr) { - int tmp_cidr = atoi(chr_cidr + 1); + auto cidr_separator_location = netmask.find('/'); + if (cidr_separator_location != std::string::npos) { + int tmp_cidr = atoi(netmask.substr(cidr_separator_location + 1).c_str()); /* Invalid CIDR, treat as single host */ if (tmp_cidr > 0 && tmp_cidr < cidr) cidr = tmp_cidr; /* Remove the / so that NetworkAddress works on the IP portion */ - std::string ip_str(netmask, chr_cidr - netmask); - mask_address = NetworkAddress(ip_str.c_str(), 0, this->address.ss_family); + mask_address = NetworkAddress(netmask.substr(0, cidr_separator_location), 0, this->address.ss_family); } else { mask_address = NetworkAddress(netmask, 0, this->address.ss_family); } diff --git a/src/network/core/address.h b/src/network/core/address.h index eac21c76ae..46d0acef13 100644 --- a/src/network/core/address.h +++ b/src/network/core/address.h @@ -116,7 +116,7 @@ public: } bool IsFamily(int family); - bool IsInNetmask(const char *netmask); + bool IsInNetmask(const std::string &netmask); /** * Compare the address of this class with the address of another. diff --git a/src/network/core/tcp_listen.h b/src/network/core/tcp_listen.h index 1cde4a1797..03945e230f 100644 --- a/src/network/core/tcp_listen.h +++ b/src/network/core/tcp_listen.h @@ -56,7 +56,7 @@ public: /* Check if the client is banned */ bool banned = false; for (const auto &entry : _network_ban_list) { - banned = address.IsInNetmask(entry.c_str()); + banned = address.IsInNetmask(entry); if (banned) { Packet p(Tban_packet); p.PrepareToSend(); From 667301e3ecc39ecd6bce286fafe25247d774642f Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Sun, 13 Jun 2021 21:05:15 +0200 Subject: [PATCH 13/20] Codechange: [Network] Make hostname/client IP return strings instead of a C-string --- src/network/core/address.cpp | 4 ++-- src/network/core/address.h | 2 +- src/network/core/tcp_connect.cpp | 2 +- src/network/network_server.cpp | 4 ++-- src/network/network_server.h | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/network/core/address.cpp b/src/network/core/address.cpp index ba9ae69fc4..0c16a2c3c2 100644 --- a/src/network/core/address.cpp +++ b/src/network/core/address.cpp @@ -19,7 +19,7 @@ * IPv4 dotted representation is given. * @return the hostname */ -const char *NetworkAddress::GetHostname() +const std::string &NetworkAddress::GetHostname() { if (this->hostname.empty() && this->address.ss_family != AF_UNSPEC) { assert(this->address_length != 0); @@ -27,7 +27,7 @@ const char *NetworkAddress::GetHostname() getnameinfo((struct sockaddr *)&this->address, this->address_length, buffer, sizeof(buffer), nullptr, 0, NI_NUMERICHOST); this->hostname = buffer; } - return this->hostname.c_str(); + return this->hostname; } /** diff --git a/src/network/core/address.h b/src/network/core/address.h index 46d0acef13..af10a27568 100644 --- a/src/network/core/address.h +++ b/src/network/core/address.h @@ -88,7 +88,7 @@ public: this->SetPort(port); } - const char *GetHostname(); + const std::string &GetHostname(); std::string GetAddressAsString(bool with_family = true); const sockaddr_storage *GetAddress(); diff --git a/src/network/core/tcp_connect.cpp b/src/network/core/tcp_connect.cpp index 5538416f6b..f251f02884 100644 --- a/src/network/core/tcp_connect.cpp +++ b/src/network/core/tcp_connect.cpp @@ -183,7 +183,7 @@ void TCPConnecter::Resolve() auto start = std::chrono::steady_clock::now(); addrinfo *ai; - int error = getaddrinfo(address.GetHostname(), port_name, &hints, &ai); + int error = getaddrinfo(address.GetHostname().c_str(), port_name, &hints, &ai); auto end = std::chrono::steady_clock::now(); auto duration = std::chrono::duration_cast(end - start); diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index 81d4500a29..9868c905ea 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -1924,7 +1924,7 @@ void NetworkServerDailyLoop() * Get the IP address/hostname of the connected client. * @return The IP address. */ -const char *ServerNetworkGameSocketHandler::GetClientIP() +const std::string &ServerNetworkGameSocketHandler::GetClientIP() { return this->client_address.GetHostname(); } @@ -2094,7 +2094,7 @@ uint NetworkServerKickOrBanIP(const std::string &ip, bool ban, const std::string for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) { if (cs->client_id == CLIENT_ID_SERVER) continue; if (cs->client_id == _redirect_console_to_client) continue; - if (cs->client_address.IsInNetmask(ip.c_str())) { + if (cs->client_address.IsInNetmask(ip)) { NetworkServerKickClient(cs->client_id, reason); n++; } diff --git a/src/network/network_server.h b/src/network/network_server.h index 7a3fa3eacd..fe15e2a54f 100644 --- a/src/network/network_server.h +++ b/src/network/network_server.h @@ -115,7 +115,7 @@ public: return "server"; } - const char *GetClientIP(); + const std::string &GetClientIP(); static ServerNetworkGameSocketHandler *GetByClientID(ClientID client_id); }; From 53b4786037d8b040991eb7d2146ac11ebd8cb718 Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Sun, 13 Jun 2021 21:41:07 +0200 Subject: [PATCH 14/20] Codechange: [Network] Let NetworkError return its std::string instead of a C-string --- src/network/core/os_abstraction.cpp | 4 ++-- src/network/core/os_abstraction.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/network/core/os_abstraction.cpp b/src/network/core/os_abstraction.cpp index b2d3475d01..202806a345 100644 --- a/src/network/core/os_abstraction.cpp +++ b/src/network/core/os_abstraction.cpp @@ -76,7 +76,7 @@ bool NetworkError::IsConnectInProgress() const * Get the string representation of the error message. * @return The string representation that will get overwritten by next calls. */ -const char *NetworkError::AsString() const +const std::string &NetworkError::AsString() const { if (this->message.empty()) { #if defined(_WIN32) @@ -97,7 +97,7 @@ const char *NetworkError::AsString() const this->message.assign(strerror(this->error)); #endif } - return this->message.c_str(); + return this->message; } /** diff --git a/src/network/core/os_abstraction.h b/src/network/core/os_abstraction.h index 8cf8202550..fbde92c051 100644 --- a/src/network/core/os_abstraction.h +++ b/src/network/core/os_abstraction.h @@ -29,7 +29,7 @@ public: bool WouldBlock() const; bool IsConnectionReset() const; bool IsConnectInProgress() const; - const char *AsString() const; + const std::string &AsString() const; static NetworkError GetLast(); }; From 49dcf0c772606bfd76ffa083a11d77c8e273f919 Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Sun, 13 Jun 2021 21:47:32 +0200 Subject: [PATCH 15/20] Codechange: [Network] Simplify constructing the HTTP request with fmt --- src/network/core/tcp_http.cpp | 15 ++++++--------- src/network/core/tcp_http.h | 4 ++-- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/network/core/tcp_http.cpp b/src/network/core/tcp_http.cpp index abb2407081..3472a7642a 100644 --- a/src/network/core/tcp_http.cpp +++ b/src/network/core/tcp_http.cpp @@ -32,7 +32,7 @@ static std::vector _http_connections; * @param depth the depth (redirect recursion) of the queries */ NetworkHTTPSocketHandler::NetworkHTTPSocketHandler(SOCKET s, - HTTPCallback *callback, const char *host, const char *url, + HTTPCallback *callback, const std::string &host, const char *url, const char *data, int depth) : NetworkSocketHandler(), recv_pos(0), @@ -42,19 +42,16 @@ NetworkHTTPSocketHandler::NetworkHTTPSocketHandler(SOCKET s, redirect_depth(depth), sock(s) { - size_t bufferSize = strlen(url) + strlen(host) + strlen(GetNetworkRevisionString()) + (data == nullptr ? 0 : strlen(data)) + 128; - char *buffer = AllocaM(char, bufferSize); - Debug(net, 5, "[tcp/http] Requesting {}{}", host, url); + std::string request; if (data != nullptr) { - seprintf(buffer, buffer + bufferSize - 1, "POST %s HTTP/1.0\r\nHost: %s\r\nUser-Agent: OpenTTD/%s\r\nContent-Type: text/plain\r\nContent-Length: %d\r\n\r\n%s\r\n", url, host, GetNetworkRevisionString(), (int)strlen(data), data); + request = fmt::format("POST {} HTTP/1.0\r\nHost: {}\r\nUser-Agent: OpenTTD/{}\r\nContent-Type: text/plain\r\nContent-Length: {}\r\n\r\n{}\r\n", url, host, GetNetworkRevisionString(), strlen(data), data); } else { - seprintf(buffer, buffer + bufferSize - 1, "GET %s HTTP/1.0\r\nHost: %s\r\nUser-Agent: OpenTTD/%s\r\n\r\n", url, host, GetNetworkRevisionString()); + request = fmt::format("GET {} HTTP/1.0\r\nHost: {}\r\nUser-Agent: OpenTTD/{}\r\n\r\n", url, host, GetNetworkRevisionString()); } - ssize_t size = strlen(buffer); - ssize_t res = send(this->sock, (const char*)buffer, size, 0); - if (res != size) { + ssize_t res = send(this->sock, request.data(), (int)request.size(), 0); + if (res != (ssize_t)request.size()) { /* Sending all data failed. Socket can't handle this little bit * of information? Just fall back to the old system! */ this->callback->OnFailure(); diff --git a/src/network/core/tcp_http.h b/src/network/core/tcp_http.h index da7a04ac48..608d50200c 100644 --- a/src/network/core/tcp_http.h +++ b/src/network/core/tcp_http.h @@ -61,7 +61,7 @@ public: void CloseSocket(); NetworkHTTPSocketHandler(SOCKET sock, HTTPCallback *callback, - const char *host, const char *url, const char *data, int depth); + const std::string &host, const char *url, const char *data, int depth); ~NetworkHTTPSocketHandler(); @@ -112,7 +112,7 @@ public: void OnConnect(SOCKET s) override { - new NetworkHTTPSocketHandler(s, this->callback, this->hostname.c_str(), this->url, this->data, this->depth); + new NetworkHTTPSocketHandler(s, this->callback, this->hostname, this->url, this->data, this->depth); /* We've relinquished control of data now. */ this->data = nullptr; } From a8b3afb236ba564a0c9d47adacc70ba701525c78 Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Sun, 13 Jun 2021 23:41:15 +0200 Subject: [PATCH 16/20] Codechange: [Network] Use string_view for network compatability check --- src/network/core/game_info.cpp | 24 +++++++++++++----------- src/network/core/game_info.h | 4 ++-- src/network/network_server.cpp | 2 +- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/network/core/game_info.cpp b/src/network/core/game_info.cpp index 15648de62f..a52de6c18c 100644 --- a/src/network/core/game_info.cpp +++ b/src/network/core/game_info.cpp @@ -38,7 +38,7 @@ NetworkServerGameInfo _network_game_info; ///< Information about our game. * Get the network version string used by this build. * The returned string is guaranteed to be at most NETWORK_REVISON_LENGTH bytes including '\0' terminator. */ -const char *GetNetworkRevisionString() +std::string_view GetNetworkRevisionString() { static std::string network_revision; @@ -65,17 +65,19 @@ const char *GetNetworkRevisionString() Debug(net, 3, "Network revision name: {}", network_revision); } - return network_revision.c_str(); + return network_revision; } /** * Extract the git hash from the revision string. - * @param revstr The revision string (formatted as DATE-BRANCH-GITHASH). + * @param revision_string The revision string (formatted as DATE-BRANCH-GITHASH). * @return The git has part of the revision. */ -static const char *ExtractNetworkRevisionHash(const char *revstr) +static std::string_view ExtractNetworkRevisionHash(std::string_view revision_string) { - return strrchr(revstr, '-'); + size_t index = revision_string.find_last_of('-'); + if (index == std::string::npos) return {}; + return revision_string.substr(index); } /** @@ -83,18 +85,18 @@ static const char *ExtractNetworkRevisionHash(const char *revstr) * First tries to match the full string, if that fails, attempts to compare just git hashes. * @param other the version string to compare to */ -bool IsNetworkCompatibleVersion(const char *other) +bool IsNetworkCompatibleVersion(std::string_view other) { - if (strncmp(GetNetworkRevisionString(), other, NETWORK_REVISION_LENGTH - 1) == 0) return true; + if (GetNetworkRevisionString() == other) return true; /* If this version is tagged, then the revision string must be a complete match, * since there is no git hash suffix in it. * This is needed to avoid situations like "1.9.0-beta1" comparing equal to "2.0.0-beta1". */ if (_openttd_revision_tagged) return false; - const char *hash1 = ExtractNetworkRevisionHash(GetNetworkRevisionString()); - const char *hash2 = ExtractNetworkRevisionHash(other); - return hash1 != nullptr && hash2 != nullptr && strncmp(hash1, hash2, GITHASH_SUFFIX_LEN) == 0; + std::string_view hash1 = ExtractNetworkRevisionHash(GetNetworkRevisionString()); + std::string_view hash2 = ExtractNetworkRevisionHash(other); + return hash1 == hash2; } /** @@ -103,7 +105,7 @@ bool IsNetworkCompatibleVersion(const char *other) void CheckGameCompatibility(NetworkGameInfo &ngi) { /* Check if we are allowed on this server based on the revision-check. */ - ngi.version_compatible = IsNetworkCompatibleVersion(ngi.server_revision.c_str()); + ngi.version_compatible = IsNetworkCompatibleVersion(ngi.server_revision); ngi.compatible = ngi.version_compatible; /* Check if we have all the GRFs on the client-system too. */ diff --git a/src/network/core/game_info.h b/src/network/core/game_info.h index 668b9801da..1ea77ae773 100644 --- a/src/network/core/game_info.h +++ b/src/network/core/game_info.h @@ -89,8 +89,8 @@ struct NetworkGameInfo : NetworkServerGameInfo { extern NetworkServerGameInfo _network_game_info; -const char *GetNetworkRevisionString(); -bool IsNetworkCompatibleVersion(const char *other); +std::string_view GetNetworkRevisionString(); +bool IsNetworkCompatibleVersion(std::string_view other); void CheckGameCompatibility(NetworkGameInfo &ngi); void FillStaticNetworkServerGameInfo(); diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index 9868c905ea..d67343359c 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -878,7 +878,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet *p) uint32 newgrf_version = p->Recv_uint32(); /* Check if the client has revision control enabled */ - if (!IsNetworkCompatibleVersion(client_revision.c_str()) || _openttd_newgrf_version != newgrf_version) { + if (!IsNetworkCompatibleVersion(client_revision) || _openttd_newgrf_version != newgrf_version) { /* Different revisions!! */ return this->SendError(NETWORK_ERROR_WRONG_REVISION); } From 981cd0197a8f180dd3a29e83d1c088dcb52e4920 Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Mon, 14 Jun 2021 16:09:50 +0200 Subject: [PATCH 17/20] Codechange: [Network] Use std::string for the client name in the network server --- src/network/network_server.cpp | 41 ++++++++++------------------------ src/network/network_server.h | 2 +- 2 files changed, 13 insertions(+), 30 deletions(-) diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index d67343359c..d44b61d3df 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -258,9 +258,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::CloseConnection(NetworkRecvSta if (status != NETWORK_RECV_STATUS_CLIENT_QUIT && status != NETWORK_RECV_STATUS_SERVER_ERROR && !this->HasClientQuit() && this->status >= STATUS_AUTHORIZED) { /* We did not receive a leave message from this client... */ - char client_name[NETWORK_CLIENT_NAME_LENGTH]; - - this->GetClientName(client_name, lastof(client_name)); + std::string client_name = this->GetClientName(); NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, "", STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST); @@ -381,9 +379,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendCompanyInfo() } for (NetworkClientSocket *csi : NetworkClientSocket::Iterate()) { - char client_name[NETWORK_CLIENT_NAME_LENGTH]; - - ((ServerNetworkGameSocketHandler*)csi)->GetClientName(client_name, lastof(client_name)); + std::string client_name = static_cast(csi)->GetClientName(); ci = csi->GetInfo(); if (ci != nullptr && Company::IsValidID(ci->client_playas)) { @@ -441,9 +437,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendError(NetworkErrorCode err /* Only send when the current client was in game */ if (this->status > STATUS_AUTHORIZED) { - char client_name[NETWORK_CLIENT_NAME_LENGTH]; - - this->GetClientName(client_name, lastof(client_name)); + std::string client_name = this->GetClientName(); Debug(net, 1, "'{}' made an error and has been disconnected: {}", client_name, GetString(strid)); @@ -1010,9 +1004,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_MAP_OK(Packet * { /* Client has the map, now start syncing */ if (this->status == STATUS_DONE_MAP && !this->HasClientQuit()) { - char client_name[NETWORK_CLIENT_NAME_LENGTH]; - - this->GetClientName(client_name, lastof(client_name)); + std::string client_name = this->GetClientName(); NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, client_name, "", this->client_id); InvalidateWindowData(WC_CLIENT_LIST, 0); @@ -1121,7 +1113,6 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_ERROR(Packet *p { /* This packets means a client noticed an error and is reporting this * to us. Display the error and report it to the other clients */ - char client_name[NETWORK_CLIENT_NAME_LENGTH]; NetworkErrorCode errorno = (NetworkErrorCode)p->Recv_uint8(); /* The client was never joined.. thank the client for the packet, but ignore it */ @@ -1129,8 +1120,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_ERROR(Packet *p return this->CloseConnection(NETWORK_RECV_STATUS_CLIENT_QUIT); } - this->GetClientName(client_name, lastof(client_name)); - + std::string client_name = this->GetClientName(); StringID strid = GetNetworkErrorMsg(errorno); Debug(net, 1, "'{}' reported an error and is closing its connection: {}", client_name, GetString(strid)); @@ -1150,17 +1140,13 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_ERROR(Packet *p NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_QUIT(Packet *p) { - /* The client wants to leave. Display this and report it to the other - * clients. */ - char client_name[NETWORK_CLIENT_NAME_LENGTH]; - /* The client was never joined.. thank the client for the packet, but ignore it */ if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) { return this->CloseConnection(NETWORK_RECV_STATUS_CLIENT_QUIT); } - this->GetClientName(client_name, lastof(client_name)); - + /* The client wants to leave. Display this and report it to the other clients. */ + std::string client_name = this->GetClientName(); NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, "", STR_NETWORK_MESSAGE_CLIENT_LEAVING); for (NetworkClientSocket *new_cs : NetworkClientSocket::Iterate()) { @@ -2122,15 +2108,12 @@ bool NetworkCompanyHasClients(CompanyID company) * @param client_name The variable to write the name to. * @param last The pointer to the last element of the destination buffer */ -void ServerNetworkGameSocketHandler::GetClientName(char *client_name, const char *last) const +std::string ServerNetworkGameSocketHandler::GetClientName() const { const NetworkClientInfo *ci = this->GetInfo(); + if (ci != nullptr && !ci->client_name.empty()) return ci->client_name; - if (ci == nullptr || ci->client_name.empty()) { - seprintf(client_name, last, "Client #%4d", this->client_id); - } else { - strecpy(client_name, ci->client_name.c_str(), last); - } + return fmt::format("Client #{}", this->client_id); } /** @@ -2142,13 +2125,13 @@ void NetworkPrintClients() if (_network_server) { IConsolePrint(CC_INFO, "Client #{} name: '{}' company: {} IP: {}", ci->client_id, - ci->client_name.c_str(), + ci->client_name, ci->client_playas + (Company::IsValidID(ci->client_playas) ? 1 : 0), ci->client_id == CLIENT_ID_SERVER ? "server" : NetworkClientSocket::GetByClientID(ci->client_id)->GetClientIP()); } else { IConsolePrint(CC_INFO, "Client #{} name: '{}' company: {}", ci->client_id, - ci->client_name.c_str(), + ci->client_name, ci->client_playas + (Company::IsValidID(ci->client_playas) ? 1 : 0)); } } diff --git a/src/network/network_server.h b/src/network/network_server.h index fe15e2a54f..76bc95dbc9 100644 --- a/src/network/network_server.h +++ b/src/network/network_server.h @@ -79,7 +79,7 @@ public: virtual Packet *ReceivePacket() override; NetworkRecvStatus CloseConnection(NetworkRecvStatus status) override; - void GetClientName(char *client_name, const char *last) const; + std::string GetClientName() const; void CheckNextClientToSendMap(NetworkClientSocket *ignore_cs = nullptr); From 05005dcdfa4f2d0c8fe2e0f0a92103dccd4691ab Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Mon, 14 Jun 2021 16:16:10 +0200 Subject: [PATCH 18/20] Codechange: [Network] Use std::string instead of char[] for the name of the file that is downloading --- src/network/network_content_gui.cpp | 4 ++-- src/network/network_content_gui.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/network/network_content_gui.cpp b/src/network/network_content_gui.cpp index dfd4370b36..483e2b5273 100644 --- a/src/network/network_content_gui.cpp +++ b/src/network/network_content_gui.cpp @@ -131,7 +131,7 @@ void BaseNetworkContentDownloadStatusWindow::DrawWidget(const Rect &r, int widge StringID str; if (this->downloaded_bytes == this->total_bytes) { str = STR_CONTENT_DOWNLOAD_COMPLETE; - } else if (!StrEmpty(this->name)) { + } else if (!this->name.empty()) { SetDParamStr(0, this->name); SetDParam(1, this->downloaded_files); SetDParam(2, this->total_files); @@ -147,7 +147,7 @@ void BaseNetworkContentDownloadStatusWindow::DrawWidget(const Rect &r, int widge void BaseNetworkContentDownloadStatusWindow::OnDownloadProgress(const ContentInfo *ci, int bytes) { if (ci->id != this->cur_id) { - strecpy(this->name, ci->filename.c_str(), lastof(this->name)); + this->name = ci->filename; this->cur_id = ci->id; this->downloaded_files++; } diff --git a/src/network/network_content_gui.h b/src/network/network_content_gui.h index dd9d9cfdf4..54fbcc36b3 100644 --- a/src/network/network_content_gui.h +++ b/src/network/network_content_gui.h @@ -22,8 +22,8 @@ protected: uint total_files; ///< Number of files to download uint downloaded_files; ///< Number of files downloaded - uint32 cur_id; ///< The current ID of the downloaded file - char name[48]; ///< The current name of the downloaded file + uint32 cur_id; ///< The current ID of the downloaded file + std::string name; ///< The current name of the downloaded file public: /** From d31a535c87a5dc9f2333ddb00a116109fed68ec8 Mon Sep 17 00:00:00 2001 From: Rubidium Date: Mon, 14 Jun 2021 23:17:58 +0200 Subject: [PATCH 19/20] Cleanup: remove some unneeded c_str() calls --- src/game/game_text.cpp | 2 +- src/script/script_scanner.cpp | 2 +- src/settings.cpp | 6 +++--- src/vehicle_cmd.cpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/game/game_text.cpp b/src/game/game_text.cpp index 74e8d63bd8..ca102f9120 100644 --- a/src/game/game_text.cpp +++ b/src/game/game_text.cpp @@ -231,7 +231,7 @@ GameStrings *LoadTranslations() basename.erase(e + 1); std::string filename = basename + "lang" PATHSEP "english.txt"; - if (!FioCheckFileExists(filename.c_str() , GAME_DIR)) return nullptr; + if (!FioCheckFileExists(filename, GAME_DIR)) return nullptr; auto ls = ReadRawLanguageStrings(filename); if (!ls.IsValid()) return nullptr; diff --git a/src/script/script_scanner.cpp b/src/script/script_scanner.cpp index dc14da1db3..319a1c7fc0 100644 --- a/src/script/script_scanner.cpp +++ b/src/script/script_scanner.cpp @@ -182,7 +182,7 @@ struct ScriptFileChecksumCreator : FileScanner { byte tmp_md5sum[16]; /* Open the file ... */ - FILE *f = FioFOpenFile(filename.c_str(), "rb", this->dir, &size); + FILE *f = FioFOpenFile(filename, "rb", this->dir, &size); if (f == nullptr) return false; /* ... calculate md5sum... */ diff --git a/src/settings.cpp b/src/settings.cpp index 23f43d24f2..54189a0fce 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -708,7 +708,7 @@ static void IniSaveSettingList(IniFile *ini, const char *grpname, StringList &li group->Clear(); for (const auto &iter : list) { - group->GetItem(iter.c_str(), true)->SetValue(""); + group->GetItem(iter, true)->SetValue(""); } } @@ -1272,7 +1272,7 @@ static void AILoadConfig(IniFile *ini, const char *grpname) continue; } } - if (item->value.has_value()) config->StringToSettings(item->value->c_str()); + if (item->value.has_value()) config->StringToSettings(*item->value); } } @@ -1299,7 +1299,7 @@ static void GameLoadConfig(IniFile *ini, const char *grpname) return; } } - if (item->value.has_value()) config->StringToSettings(item->value->c_str()); + if (item->value.has_value()) config->StringToSettings(*item->value); } /** diff --git a/src/vehicle_cmd.cpp b/src/vehicle_cmd.cpp index 84d339b279..499b3b3ebd 100644 --- a/src/vehicle_cmd.cpp +++ b/src/vehicle_cmd.cpp @@ -804,7 +804,7 @@ static void CloneVehicleName(const Vehicle *src, Vehicle *dst) /* Check the name is unique. */ auto new_name = oss.str(); - if (IsUniqueVehicleName(new_name.c_str())) { + if (IsUniqueVehicleName(new_name)) { dst->name = new_name; break; } From d0bcb9839a9080326ade985e4b109752fd88e2a6 Mon Sep 17 00:00:00 2001 From: SamuXarick <43006711+SamuXarick@users.noreply.github.com> Date: Tue, 15 Jun 2021 13:00:50 +0100 Subject: [PATCH 20/20] Fix: you could join an AI company in multiplayer via the GUI (#9369) --- src/network/network_gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index 3cdece77c5..04303e7ac5 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -1894,7 +1894,7 @@ private: if (_network_server) this->buttons[line_count].emplace_back(new CompanyButton(SPR_ADMIN, STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP, COLOUR_RED, company_id, &NetworkClientListWindow::OnClickCompanyAdmin, company_id == COMPANY_SPECTATOR)); this->buttons[line_count].emplace_back(chat_button); - if (own_ci->client_playas != company_id) this->buttons[line_count].emplace_back(new CompanyButton(SPR_JOIN, STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP, COLOUR_ORANGE, company_id, &NetworkClientListWindow::OnClickCompanyJoin)); + if (own_ci->client_playas != company_id) this->buttons[line_count].emplace_back(new CompanyButton(SPR_JOIN, STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP, COLOUR_ORANGE, company_id, &NetworkClientListWindow::OnClickCompanyJoin, company_id != COMPANY_SPECTATOR && Company::Get(company_id)->is_ai)); this->line_count += 1;