diff --git a/src/cargopacket.h b/src/cargopacket.h index d064149501..ecee6e97b1 100644 --- a/src/cargopacket.h +++ b/src/cargopacket.h @@ -18,7 +18,7 @@ #include "vehicle_type.h" #include "company_type.h" #include "core/multimap.hpp" -#include "saveload/saveload.h" +#include "saveload/saveload_common.h" #include /** Unique identifier for a single cargo packet. */ @@ -36,6 +36,12 @@ template class CargoList; class StationCargoList; // forward-declare, so we can use it in VehicleCargoList. extern SaveLoadTable GetCargoPacketDesc(); +namespace upstream_sl { + extern upstream_sl::SaveLoadTable GetCargoPacketDesc(); + class SlVehicleCommon; + class SlStationGoods; +} + typedef uint32 TileOrStationID; void ClearCargoPacketDeferredPayments(); @@ -70,6 +76,7 @@ private: friend class StationCargoList; /** We want this to be saved, right? */ friend SaveLoadTable GetCargoPacketDesc(); + friend upstream_sl::SaveLoadTable upstream_sl::GetCargoPacketDesc(); friend void Load_CPDP(); public: /** Maximum number of items in a single cargo packet. */ @@ -340,6 +347,7 @@ protected: public: /** The station cargo list needs to control the unloading. */ friend class StationCargoList; + friend upstream_sl::SlVehicleCommon; /** The super class ought to know what it's doing. */ friend class CargoList; /** The vehicles have a cargo list (and we want that saved). */ @@ -495,6 +503,7 @@ public: friend class CargoList; /** The stations, via GoodsEntry, have a CargoList. */ friend SaveLoadTable GetGoodsDesc(); + friend upstream_sl::SlStationGoods; friend class CargoLoad; friend class CargoTransfer; diff --git a/src/company_base.h b/src/company_base.h index dc046eb907..765ee91fa9 100644 --- a/src/company_base.h +++ b/src/company_base.h @@ -103,28 +103,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_last_asked(INVALID_COMPANY), bankrupt_asked(0), bankrupt_timeout(0), bankrupt_value(0), - terraform_limit(0), clear_limit(0), tree_limit(0), purchase_land_limit(0), build_object_limit(0), is_ai(false) {} + terraform_limit(0), clear_limit(0), tree_limit(0), purchase_land_limit(0), build_object_limit(0), is_ai(false), engine_renew_list(nullptr) {} }; struct Company : CompanyPool::PoolItem<&_company_pool>, CompanyProperties { 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/core/span_type.hpp b/src/core/span_type.hpp index 394b9ef38c..03bc678b7e 100644 --- a/src/core/span_type.hpp +++ b/src/core/span_type.hpp @@ -73,6 +73,8 @@ public: typedef size_t size_type; typedef std::ptrdiff_t difference_type; + constexpr span() noexcept : first(nullptr), last(nullptr) {} + constexpr span(pointer data_in, size_t size_in) : first(data_in), last(data_in + size_in) {} template::value), int>::type = 0> diff --git a/src/gamelog.h b/src/gamelog.h index e7951c50c7..43cd84f3a2 100644 --- a/src/gamelog.h +++ b/src/gamelog.h @@ -13,7 +13,7 @@ #include "newgrf_config.h" /** The actions we log. */ -enum GamelogActionType { +enum GamelogActionType : uint8 { GLAT_START, ///< Game created GLAT_LOAD, ///< Game loaded GLAT_GRF, ///< GRF changed diff --git a/src/linkgraph/linkgraph.h b/src/linkgraph/linkgraph.h index 90f71f4680..bcbe99b54c 100644 --- a/src/linkgraph/linkgraph.h +++ b/src/linkgraph/linkgraph.h @@ -17,7 +17,7 @@ #include "../station_base.h" #include "../cargotype.h" #include "../date_func.h" -#include "../saveload/saveload.h" +#include "../saveload/saveload_common.h" #include "linkgraph_type.h" #include @@ -31,6 +31,13 @@ typedef Pool LinkGraphPool; /** The actual pool with link graphs. */ extern LinkGraphPool _link_graph_pool; +namespace upstream_sl { + SaveLoadTable GetLinkGraphDesc(); + SaveLoadTable GetLinkGraphJobDesc(); + class SlLinkgraphNode; + class SlLinkgraphEdge; +} + /** * A connected component of a link graph. Contains a complete set of stations * connected by links as nodes and edges. Each component also holds a copy of @@ -536,6 +543,11 @@ protected: friend void Save_LinkGraph(LinkGraph &lg); friend void Load_LinkGraph(LinkGraph &lg); + friend upstream_sl::SaveLoadTable upstream_sl::GetLinkGraphDesc(); + friend upstream_sl::SaveLoadTable upstream_sl::GetLinkGraphJobDesc(); + friend upstream_sl::SlLinkgraphNode; + friend upstream_sl::SlLinkgraphEdge; + CargoID cargo; ///< Cargo of this component's link graph. Date last_compression; ///< Last time the capacities and supplies were compressed. NodeVector nodes; ///< Nodes in the component. diff --git a/src/linkgraph/linkgraphjob.h b/src/linkgraph/linkgraphjob.h index 6eb942be7b..e35c9ccb0d 100644 --- a/src/linkgraph/linkgraphjob.h +++ b/src/linkgraph/linkgraphjob.h @@ -27,6 +27,10 @@ typedef Pool LinkGraphJobPool; /** The actual pool with link graph jobs. */ extern LinkGraphJobPool _link_graph_job_pool; +namespace upstream_sl { + SaveLoadTable GetLinkGraphJobDesc(); +} + /** * Class for calculation jobs to be run on link graphs. */ @@ -57,6 +61,7 @@ private: typedef SmallMatrix EdgeAnnotationMatrix; friend SaveLoadTable GetLinkGraphJobDesc(); + friend upstream_sl::SaveLoadTable upstream_sl::GetLinkGraphJobDesc(); friend void GetLinkGraphJobDayLengthScaleAfterLoad(LinkGraphJob *lgj); friend class LinkGraphSchedule; friend class LinkGraphJobGroup; diff --git a/src/linkgraph/linkgraphschedule.h b/src/linkgraph/linkgraphschedule.h index 1df20d380d..e67a978fc5 100644 --- a/src/linkgraph/linkgraphschedule.h +++ b/src/linkgraph/linkgraphschedule.h @@ -16,6 +16,10 @@ class LinkGraphJob; +namespace upstream_sl { + SaveLoadTable GetLinkGraphScheduleDesc(); +} + /** * A handler doing "something" on a link graph component. It must not keep any * state as it is called concurrently from different threads. @@ -42,6 +46,7 @@ private: typedef std::list GraphList; typedef std::list> JobList; friend SaveLoadTable GetLinkGraphScheduleDesc(); + friend upstream_sl::SaveLoadTable upstream_sl::GetLinkGraphScheduleDesc(); protected: std::unique_ptr handlers[6]; ///< Handlers to be run for each job. diff --git a/src/order_backup.h b/src/order_backup.h index d3539e1459..d796052467 100644 --- a/src/order_backup.h +++ b/src/order_backup.h @@ -15,7 +15,7 @@ #include "tile_type.h" #include "vehicle_type.h" #include "base_consist.h" -#include "saveload/saveload.h" +#include "saveload/saveload_common.h" /** Unique identifier for an order backup. */ typedef uint8 OrderBackupID; @@ -29,6 +29,11 @@ extern OrderBackupPool _order_backup_pool; /** Flag to pass to the vehicle construction command when an order should be preserved. */ static const uint32 MAKE_ORDER_BACKUP_FLAG = 1U << 31; +namespace upstream_sl { + SaveLoadTable GetOrderBackupDescription(); + struct BKORChunkHandler; +} + /** * Data for backing up an order of a vehicle so it can be * restored after a vehicle is rebuilt in the same depot. @@ -36,7 +41,9 @@ static const uint32 MAKE_ORDER_BACKUP_FLAG = 1U << 31; struct OrderBackup : OrderBackupPool::PoolItem<&_order_backup_pool>, BaseConsist { private: friend SaveLoadTable GetOrderBackupDescription(); ///< Saving and loading of order backups. + friend upstream_sl::SaveLoadTable upstream_sl::GetOrderBackupDescription(); ///< Saving and loading of order backups. friend void Load_BKOR(); ///< Creating empty orders upon savegame loading. + friend upstream_sl::BKORChunkHandler; uint32 user; ///< The user that requested the backup. TileIndex tile; ///< Tile of the depot where the order was changed. GroupID group; ///< The group the vehicle was part of. diff --git a/src/order_base.h b/src/order_base.h index e62b950e93..12367fc209 100644 --- a/src/order_base.h +++ b/src/order_base.h @@ -19,7 +19,7 @@ #include "vehicle_type.h" #include "date_type.h" #include "schdispatch.h" -#include "saveload/saveload.h" +#include "saveload/saveload_common.h" #include #include @@ -56,6 +56,13 @@ struct OrderExtraInfo { uint8 xflags = 0; ///< Extra flags }; +namespace upstream_sl { + SaveLoadTable GetOrderDescription(); + SaveLoadTable GetOrderListDescription(); + class SlVehicleCommon; + class SlVehicleDisaster; +} + /* If you change this, keep in mind that it is saved on 3 places: * - Load_ORDR, all the global orders * - Vehicle -> current_order @@ -66,6 +73,9 @@ 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. + friend upstream_sl::SaveLoadTable upstream_sl::GetOrderDescription(); ///< Saving and loading of orders. + friend upstream_sl::SlVehicleCommon; + friend upstream_sl::SlVehicleDisaster; friend void Load_ORDX(); ///< Saving and loading of orders. friend void Save_ORDX(); ///< Saving and loading of orders. friend void Load_VEOX(); ///< Saving and loading of orders. @@ -588,6 +598,7 @@ struct OrderList : OrderListPool::PoolItem<&_orderlist_pool> { private: friend void AfterLoadVehicles(bool part_of_load); ///< For instantiating the shared vehicle chain friend SaveLoadTable GetOrderListDescription(); ///< Saving and loading of order lists. + friend upstream_sl::SaveLoadTable upstream_sl::GetOrderListDescription(); ///< Saving and loading of order lists. friend void Ptrs_ORDL(); ///< Saving and loading of order lists. StationID GetBestLoadableNext(const Vehicle *v, const Order *o1, const Order *o2) const; diff --git a/src/saveload/CMakeLists.txt b/src/saveload/CMakeLists.txt index af8909fcde..10141526e3 100644 --- a/src/saveload/CMakeLists.txt +++ b/src/saveload/CMakeLists.txt @@ -1,3 +1,5 @@ +add_subdirectory(upstream) + add_files( afterload.cpp ai_sl.cpp @@ -35,8 +37,10 @@ add_files( saveload.cpp saveload.h saveload_buffer.h + saveload_common.h saveload_filter.h saveload_internal.h + saveload_types.h signal_sl.cpp signs_sl.cpp station_sl.cpp diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index f69717de10..edbfca7679 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -56,6 +56,7 @@ bool _sl_is_ext_version; ///< is this an exte bool _sl_is_faked_ext; ///< is this a faked extended savegame version, with no SLXI chunk? See: SlXvCheckSpecialSavegameVersions. bool _sl_maybe_springpp; ///< is this possibly a SpringPP savegame? bool _sl_maybe_chillpp; ///< is this possibly a ChillPP v8 savegame? +bool _sl_upstream_mode; ///< load game using upstream loader std::vector _sl_xv_discardable_chunk_ids; ///< list of chunks IDs which we can discard if no chunk loader exists std::string _sl_xv_version_label; ///< optional SLXI version label @@ -224,6 +225,7 @@ void SlXvResetState() _sl_is_faked_ext = false; _sl_maybe_springpp = false; _sl_maybe_chillpp = false; + _sl_upstream_mode = false; _sl_xv_discardable_chunk_ids.clear(); memset(_sl_xv_feature_versions, 0, sizeof(_sl_xv_feature_versions)); _sl_xv_version_label.clear(); diff --git a/src/saveload/extended_ver_sl.h b/src/saveload/extended_ver_sl.h index 1182459a5f..52f74b1908 100644 --- a/src/saveload/extended_ver_sl.h +++ b/src/saveload/extended_ver_sl.h @@ -11,6 +11,7 @@ #define EXTENDED_VER_SL_H #include "../core/bitmath_func.hpp" +#include "../core/enum_type.hpp" #include diff --git a/src/saveload/labelmaps_sl.cpp b/src/saveload/labelmaps_sl.cpp index a667c0171f..9d8c084b94 100644 --- a/src/saveload/labelmaps_sl.cpp +++ b/src/saveload/labelmaps_sl.cpp @@ -16,7 +16,7 @@ #include "../safeguards.h" -static std::vector _railtype_list; +std::vector _railtype_list; /** * Test if any saved rail type labels are different to the currently loaded diff --git a/src/saveload/linkgraph_sl.cpp b/src/saveload/linkgraph_sl.cpp index 500caafc44..58b7b92e05 100644 --- a/src/saveload/linkgraph_sl.cpp +++ b/src/saveload/linkgraph_sl.cpp @@ -241,6 +241,7 @@ static void Load_LGRJ() LinkGraphJob *lgj = new (index) LinkGraphJob(); SlObjectLoadFiltered(lgj, _filtered_job_desc); if (SlXvIsFeatureMissing(XSLFI_LINKGRAPH_DAY_SCALE)) { + extern void GetLinkGraphJobDayLengthScaleAfterLoad(LinkGraphJob *lgj); GetLinkGraphJobDayLengthScaleAfterLoad(lgj); } LinkGraph &lg = const_cast(lgj->Graph()); diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index d1b32d4021..b2ff9b78fb 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -74,7 +74,7 @@ #include "../safeguards.h" extern const SaveLoadVersion SAVEGAME_VERSION = SLV_CUSTOM_SUBSIDY_DURATION; ///< Current savegame version of OpenTTD. -extern const SaveLoadVersion MAX_LOAD_SAVEGAME_VERSION = SLV_CUSTOM_SUBSIDY_DURATION; ///< Max loadable savegame version of OpenTTD. +extern const SaveLoadVersion MAX_LOAD_SAVEGAME_VERSION = (SaveLoadVersion)(SL_MAX_VERSION - 1); ///< Max loadable savegame version of OpenTTD. const SaveLoadVersion SAVEGAME_VERSION_EXT = (SaveLoadVersion)(0x8000); ///< Savegame extension indicator mask @@ -90,6 +90,14 @@ bool _do_autosave; ///< are we doing an autosave at the moment? extern bool _sl_is_ext_version; extern bool _sl_maybe_springpp; extern bool _sl_maybe_chillpp; +extern bool _sl_upstream_mode; + +namespace upstream_sl { + void SlNullPointers(); + void SlLoadChunks(); + void SlLoadCheckChunks(); + void SlFixPointers(); +} /** What are we currently doing? */ enum SaveLoadAction { @@ -357,6 +365,11 @@ static const std::vector &ChunkHandlers() /** Null all pointers (convert index -> nullptr) */ static void SlNullPointers() { + if (_sl_upstream_mode) { + upstream_sl::SlNullPointers(); + return; + } + _sl.action = SLA_NULL; /* We don't want any savegame conversion code to run @@ -2277,6 +2290,11 @@ static const ChunkHandler *SlFindChunkHandler(uint32 id) /** Load all chunks */ static void SlLoadChunks() { + if (_sl_upstream_mode) { + upstream_sl::SlLoadChunks(); + return; + } + for (uint32 id = SlReadUint32(); id != 0; id = SlReadUint32()) { DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id); size_t read = 0; @@ -2300,6 +2318,11 @@ static void SlLoadChunks() /** Load all chunks for savegame checking */ static void SlLoadCheckChunks() { + if (_sl_upstream_mode) { + upstream_sl::SlLoadCheckChunks(); + return; + } + uint32 id; const ChunkHandler *ch; @@ -2322,6 +2345,11 @@ static void SlLoadCheckChunks() /** Fix all pointers (convert index -> pointer) */ static void SlFixPointers() { + if (_sl_upstream_mode) { + upstream_sl::SlFixPointers(); + return; + } + _sl.action = SLA_PTRS; for (auto &ch : ChunkHandlers()) { @@ -3388,8 +3416,17 @@ static SaveOrLoadResult DoLoad(LoadFilter *reader, bool load_check) special_version = SlXvCheckSpecialSavegameVersions(); } - DEBUG(sl, 1, "Loading savegame version %d%s%s%s", _sl_version, _sl_is_ext_version ? " (extended)" : "", - _sl_maybe_springpp ? " which might be SpringPP" : "", _sl_maybe_chillpp ? " which might be ChillPP" : ""); + if (_sl_version >= SLV_SAVELOAD_LIST_LENGTH) { + if (_sl_is_ext_version) { + DEBUG(sl, 0, "Got an extended savegame version with a base version in the upstream mode range, giving up"); + SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME); + } else { + _sl_upstream_mode = true; + } + } + + DEBUG(sl, 1, "Loading savegame version %d%s%s%s%s", _sl_version, _sl_is_ext_version ? " (extended)" : "", + _sl_maybe_springpp ? " which might be SpringPP" : "", _sl_maybe_chillpp ? " which might be ChillPP" : "", _sl_upstream_mode ? " (upstream mode)" : ""); /* Is the version higher than the current? */ if (_sl_version > MAX_LOAD_SAVEGAME_VERSION && !special_version) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME); @@ -3684,3 +3721,8 @@ void FileToSaveLoad::SetTitle(const char *title) { strecpy(this->title, title, lastof(this->title)); } + +bool SaveLoadFileTypeIsScenario() +{ + return _file_to_saveload.abstract_ftype == FT_SCENARIO; +} diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index befa835a1b..a0dd9fdb3f 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -10,368 +10,15 @@ #ifndef SAVELOAD_H #define SAVELOAD_H +#include "saveload_types.h" #include "../fileio_type.h" #include "../strings_type.h" -#include "../core/span_type.hpp" -#include "extended_ver_sl.h" #include #include #include #include -/** SaveLoad versions - * Previous savegame versions, the trunk revision where they were - * introduced and the released version that had that particular - * savegame version. - * Up to savegame version 18 there is a minor version as well. - * - * Older entries keep their original numbering. - * - * Newer entries should use a descriptive labels, numeric version - * and PR can be added to comment. - * - * Note that this list must not be reordered. - */ -enum SaveLoadVersion : uint16 { - SL_MIN_VERSION, ///< First savegame version - - SLV_1, ///< 1.0 0.1.x, 0.2.x - SLV_2, /**< 2.0 0.3.0 - * 2.1 0.3.1, 0.3.2 */ - SLV_3, ///< 3.x lost - SLV_4, /**< 4.0 1 - * 4.1 122 0.3.3, 0.3.4 - * 4.2 1222 0.3.5 - * 4.3 1417 - * 4.4 1426 */ - - SLV_5, /**< 5.0 1429 - * 5.1 1440 - * 5.2 1525 0.3.6 */ - SLV_6, /**< 6.0 1721 - * 6.1 1768 */ - SLV_7, ///< 7.0 1770 - SLV_8, ///< 8.0 1786 - SLV_9, ///< 9.0 1909 - - SLV_10, ///< 10.0 2030 - SLV_11, /**< 11.0 2033 - * 11.1 2041 */ - SLV_12, ///< 12.1 2046 - SLV_13, ///< 13.1 2080 0.4.0, 0.4.0.1 - SLV_14, ///< 14.0 2441 - - SLV_15, ///< 15.0 2499 - SLV_16, /**< 16.0 2817 - * 16.1 3155 */ - SLV_17, /**< 17.0 3212 - * 17.1 3218 */ - SLV_18, ///< 18 3227 - SLV_19, ///< 19 3396 - - SLV_20, ///< 20 3403 - SLV_21, ///< 21 3472 0.4.x - SLV_22, ///< 22 3726 - SLV_23, ///< 23 3915 - SLV_24, ///< 24 4150 - - SLV_25, ///< 25 4259 - SLV_26, ///< 26 4466 - SLV_27, ///< 27 4757 - SLV_28, ///< 28 4987 - SLV_29, ///< 29 5070 - - SLV_30, ///< 30 5946 - SLV_31, ///< 31 5999 - SLV_32, ///< 32 6001 - SLV_33, ///< 33 6440 - SLV_34, ///< 34 6455 - - SLV_35, ///< 35 6602 - SLV_36, ///< 36 6624 - SLV_37, ///< 37 7182 - SLV_38, ///< 38 7195 - SLV_39, ///< 39 7269 - - SLV_40, ///< 40 7326 - SLV_41, ///< 41 7348 0.5.x - SLV_42, ///< 42 7573 - SLV_43, ///< 43 7642 - SLV_44, ///< 44 8144 - - SLV_45, ///< 45 8501 - SLV_46, ///< 46 8705 - SLV_47, ///< 47 8735 - SLV_48, ///< 48 8935 - SLV_49, ///< 49 8969 - - SLV_50, ///< 50 8973 - SLV_51, ///< 51 8978 - SLV_52, ///< 52 9066 - SLV_53, ///< 53 9316 - SLV_54, ///< 54 9613 - - SLV_55, ///< 55 9638 - SLV_56, ///< 56 9667 - SLV_57, ///< 57 9691 - SLV_58, ///< 58 9762 - SLV_59, ///< 59 9779 - - SLV_60, ///< 60 9874 - SLV_61, ///< 61 9892 - SLV_62, ///< 62 9905 - SLV_63, ///< 63 9956 - SLV_64, ///< 64 10006 - - SLV_65, ///< 65 10210 - SLV_66, ///< 66 10211 - SLV_67, ///< 67 10236 - SLV_68, ///< 68 10266 - SLV_69, ///< 69 10319 - - SLV_70, ///< 70 10541 - SLV_71, ///< 71 10567 - SLV_72, ///< 72 10601 - SLV_73, ///< 73 10903 - SLV_74, ///< 74 11030 - - SLV_75, ///< 75 11107 - SLV_76, ///< 76 11139 - SLV_77, ///< 77 11172 - SLV_78, ///< 78 11176 - SLV_79, ///< 79 11188 - - SLV_80, ///< 80 11228 - SLV_81, ///< 81 11244 - SLV_82, ///< 82 11410 - SLV_83, ///< 83 11589 - SLV_84, ///< 84 11822 - - SLV_85, ///< 85 11874 - SLV_86, ///< 86 12042 - SLV_87, ///< 87 12129 - SLV_88, ///< 88 12134 - SLV_89, ///< 89 12160 - - SLV_90, ///< 90 12293 - SLV_91, ///< 91 12347 - SLV_92, ///< 92 12381 0.6.x - SLV_93, ///< 93 12648 - SLV_94, ///< 94 12816 - - SLV_95, ///< 95 12924 - SLV_96, ///< 96 13226 - SLV_97, ///< 97 13256 - SLV_98, ///< 98 13375 - SLV_99, ///< 99 13838 - - SLV_100, ///< 100 13952 - SLV_101, ///< 101 14233 - SLV_102, ///< 102 14332 - SLV_103, ///< 103 14598 - SLV_104, ///< 104 14735 - - SLV_105, ///< 105 14803 - SLV_106, ///< 106 14919 - SLV_107, ///< 107 15027 - SLV_108, ///< 108 15045 - SLV_109, ///< 109 15075 - - SLV_110, ///< 110 15148 - SLV_111, ///< 111 15190 - SLV_112, ///< 112 15290 - SLV_113, ///< 113 15340 - SLV_114, ///< 114 15601 - - SLV_115, ///< 115 15695 - SLV_116, ///< 116 15893 0.7.x - SLV_117, ///< 117 16037 - SLV_118, ///< 118 16129 - SLV_119, ///< 119 16242 - - SLV_120, ///< 120 16439 - SLV_121, ///< 121 16694 - SLV_122, ///< 122 16855 - SLV_123, ///< 123 16909 - SLV_124, ///< 124 16993 - - SLV_125, ///< 125 17113 - SLV_126, ///< 126 17433 - SLV_127, ///< 127 17439 - SLV_128, ///< 128 18281 - SLV_129, ///< 129 18292 - - SLV_130, ///< 130 18404 - SLV_131, ///< 131 18481 - SLV_132, ///< 132 18522 - SLV_133, ///< 133 18674 - SLV_134, ///< 134 18703 - - SLV_135, ///< 135 18719 - SLV_136, ///< 136 18764 - SLV_137, ///< 137 18912 - SLV_138, ///< 138 18942 1.0.x - SLV_139, ///< 139 19346 - - SLV_140, ///< 140 19382 - SLV_141, ///< 141 19799 - SLV_142, ///< 142 20003 - SLV_143, ///< 143 20048 - SLV_144, ///< 144 20334 - - SLV_145, ///< 145 20376 - SLV_146, ///< 146 20446 - SLV_147, ///< 147 20621 - SLV_148, ///< 148 20659 - SLV_149, ///< 149 20832 - - SLV_150, ///< 150 20857 - SLV_151, ///< 151 20918 - SLV_152, ///< 152 21171 - SLV_153, ///< 153 21263 - SLV_154, ///< 154 21426 - - SLV_155, ///< 155 21453 - SLV_156, ///< 156 21728 - SLV_157, ///< 157 21862 - SLV_158, ///< 158 21933 - SLV_159, ///< 159 21962 - - SLV_160, ///< 160 21974 1.1.x - SLV_161, ///< 161 22567 - SLV_162, ///< 162 22713 - SLV_163, ///< 163 22767 - SLV_164, ///< 164 23290 - - SLV_165, ///< 165 23304 - SLV_166, ///< 166 23415 - SLV_167, ///< 167 23504 - SLV_168, ///< 168 23637 - SLV_169, ///< 169 23816 - - SLV_170, ///< 170 23826 - SLV_171, ///< 171 23835 - SLV_172, ///< 172 23947 - SLV_173, ///< 173 23967 1.2.0-RC1 - SLV_174, ///< 174 23973 1.2.x - - SLV_175, ///< 175 24136 - SLV_176, ///< 176 24446 - SLV_177, ///< 177 24619 - SLV_178, ///< 178 24789 - SLV_179, ///< 179 24810 - - SLV_180, ///< 180 24998 1.3.x - SLV_181, ///< 181 25012 - SLV_182, ///< 182 25115 FS#5492, r25259, r25296 Goal status - SLV_183, ///< 183 25363 Cargodist - SLV_184, ///< 184 25508 Unit localisation split - - SLV_185, ///< 185 25620 Storybooks - SLV_186, ///< 186 25833 Objects storage - SLV_187, ///< 187 25899 Linkgraph - restricted flows - SLV_188, ///< 188 26169 v1.4 FS#5831 Unify RV travel time - SLV_189, ///< 189 26450 Hierarchical vehicle subgroups - - SLV_190, ///< 190 26547 Separate order travel and wait times - SLV_191, ///< 191 26636 FS#6026 Fix disaster vehicle storage (No bump) - ///< 191 26646 FS#6041 Linkgraph - store locations - SLV_192, ///< 192 26700 FS#6066 Fix saving of order backups - SLV_193, ///< 193 26802 - SLV_194, ///< 194 26881 v1.5 - - SLV_195, ///< 195 27572 v1.6.1 - SLV_196, ///< 196 27778 v1.7 - SLV_197, ///< 197 27978 v1.8 - SLV_198, ///< 198 PR#6763 Switch town growth rate and counter to actual game ticks - SLV_EXTEND_CARGOTYPES, ///< 199 PR#6802 Extend cargotypes to 64 - - SLV_EXTEND_RAILTYPES, ///< 200 PR#6805 Extend railtypes to 64, adding uint16 to map array. - SLV_EXTEND_PERSISTENT_STORAGE, ///< 201 PR#6885 Extend NewGRF persistent storages. - SLV_EXTEND_INDUSTRY_CARGO_SLOTS, ///< 202 PR#6867 Increase industry cargo slots to 16 in, 16 out - SLV_SHIP_PATH_CACHE, ///< 203 PR#7072 Add path cache for ships - SLV_SHIP_ROTATION, ///< 204 PR#7065 Add extra rotation stages for ships. - - SLV_GROUP_LIVERIES, ///< 205 PR#7108 Livery storage change and group liveries. - SLV_SHIPS_STOP_IN_LOCKS, ///< 206 PR#7150 Ship/lock movement changes. - SLV_FIX_CARGO_MONITOR, ///< 207 PR#7175 v1.9 Cargo monitor data packing fix to support 64 cargotypes. - SLV_TOWN_CARGOGEN, ///< 208 PR#6965 New algorithms for town building cargo generation. - SLV_SHIP_CURVE_PENALTY, ///< 209 PR#7289 Configurable ship curve penalties. - - SLV_SERVE_NEUTRAL_INDUSTRIES, ///< 210 PR#7234 Company stations can serve industries with attached neutral stations. - SLV_ROADVEH_PATH_CACHE, ///< 211 PR#7261 Add path cache for road vehicles. - SLV_REMOVE_OPF, ///< 212 PR#7245 Remove OPF. - SLV_TREES_WATER_CLASS, ///< 213 PR#7405 WaterClass update for tree tiles. - SLV_ROAD_TYPES, ///< 214 PR#6811 NewGRF road types. - - SLV_SCRIPT_MEMLIMIT, ///< 215 PR#7516 Limit on AI/GS memory consumption. - SLV_MULTITILE_DOCKS, ///< 216 PR#7380 Multiple docks per station. - SLV_TRADING_AGE, ///< 217 PR#7780 Configurable company trading age. - SLV_ENDING_YEAR, ///< 218 PR#7747 v1.10 Configurable ending year. - SLV_REMOVE_TOWN_CARGO_CACHE, ///< 219 PR#8258 Remove town cargo acceptance and production caches. - - /* Patchpacks for a while considered it a good idea to jump a few versions - * above our version for their savegames. But as time continued, this gap - * has been closing, up to the point we would start to reuse versions from - * their patchpacks. This is not a problem from our perspective: the - * savegame will simply fail to load because they all contain chunks we - * cannot digest. But, this gives for ugly errors. As we have plenty of - * versions anyway, we simply skip the versions we know belong to - * patchpacks. This way we can present the user with a clean error - * indicate they are loading a savegame from a patchpack. - * For future patchpack creators: please follow a system like JGRPP, where - * the version is masked with 0x8000, and the true version is stored in - * its own chunk with feature toggles. - */ - SLV_START_PATCHPACKS, ///< 220 First known patchpack to use a version just above ours. - SLV_END_PATCHPACKS = 286, ///< 286 Last known patchpack to use a version just above ours. - - SLV_GS_INDUSTRY_CONTROL, ///< 287 PR#7912 and PR#8115 GS industry control. - SLV_VEH_MOTION_COUNTER, ///< 288 PR#8591 Desync safe motion counter - SLV_INDUSTRY_TEXT, ///< 289 PR#8576 v1.11.0-RC1 Additional GS text for industries. - SLV_MAPGEN_SETTINGS_REVAMP, ///< 290 PR#8891 v1.11 Revamp of some mapgen settings (snow coverage, desert coverage, heightmap height, custom terrain type). - SLV_GROUP_REPLACE_WAGON_REMOVAL, ///< 291 PR#7441 Per-group wagon removal flag. - SLV_CUSTOM_SUBSIDY_DURATION, ///< 292 PR#9081 Configurable subsidy duration. - - /* upstream savegame versions follow */ - - SLV_SAVELOAD_LIST_LENGTH, ///< 293 PR#9374 Consistency in list length with SL_STRUCT / SL_STRUCTLIST / SL_DEQUE / SL_REFLIST. - SLV_RIFF_TO_ARRAY, ///< 294 PR#9375 Changed many CH_RIFF chunks to CH_ARRAY chunks. - - SLV_TABLE_CHUNKS, ///< 295 PR#9322 Introduction of CH_TABLE and CH_SPARSE_TABLE. - SLV_SCRIPT_INT64, ///< 296 PR#9415 SQInteger is 64bit but was saved as 32bit. - SLV_LINKGRAPH_TRAVEL_TIME, ///< 297 PR#9457 v12.0-RC1 Store travel time in the linkgraph. - SLV_DOCK_DOCKINGTILES, ///< 298 PR#9578 All tiles around docks may be docking tiles. - SLV_REPAIR_OBJECT_DOCKING_TILES, ///< 299 PR#9594 v12.0 Fixing issue with docking tiles overlapping objects. - - SL_MAX_VERSION, ///< Highest possible saveload version - - SL_SPRING_2013_v2_0_102 = 220, - SL_SPRING_2013_v2_1_108 = 221, - SL_SPRING_2013_v2_1_147 = 222, - SL_SPRING_2013_v2_3_XXX = 223, - SL_SPRING_2013_v2_3_b3 = 224, - SL_SPRING_2013_v2_3_b4 = 225, - SL_SPRING_2013_v2_3_b5 = 226, - SL_SPRING_2013_v2_4 = 227, - SL_TRACE_RESTRICT_2000 = 2000, - SL_TRACE_RESTRICT_2001 = 2001, - SL_TRACE_RESTRICT_2002 = 2002, - SL_JOKER_1_19 = 278, - SL_JOKER_1_20 = 279, - SL_JOKER_1_21 = 280, - SL_JOKER_1_22 = 281, - SL_JOKER_1_23 = 282, - SL_JOKER_1_24 = 283, - SL_JOKER_1_25 = 284, - SL_JOKER_1_26 = 285, - SL_JOKER_1_27 = 286, - SL_CHILLPP_201 = 201, - SL_CHILLPP_232 = 232, - SL_CHILLPP_233 = 233, -}; - /** Save or load result codes. */ enum SaveOrLoadResult { SL_OK = 0, ///< completed successfully @@ -475,128 +122,6 @@ enum SaveLoadChunkExtHeaderFlags { }; DECLARE_ENUM_AS_BIT_SET(SaveLoadChunkExtHeaderFlags) -/** - * VarTypes is the general bitmasked magic type that tells us - * certain characteristics about the variable it refers to. For example - * SLE_FILE_* gives the size(type) as it would be in the savegame and - * SLE_VAR_* the size(type) as it is in memory during runtime. These are - * the first 8 bits (0-3 SLE_FILE, 4-7 SLE_VAR). - * Bits 8-15 are reserved for various flags as explained below - */ -enum VarTypes { - /* 4 bits allocated a maximum of 16 types for NumberType */ - SLE_FILE_I8 = 0, - SLE_FILE_U8 = 1, - SLE_FILE_I16 = 2, - SLE_FILE_U16 = 3, - SLE_FILE_I32 = 4, - SLE_FILE_U32 = 5, - SLE_FILE_I64 = 6, - SLE_FILE_U64 = 7, - SLE_FILE_STRINGID = 8, ///< StringID offset into strings-array - SLE_FILE_STRING = 9, - SLE_FILE_VEHORDERID = 10, - /* 5 more possible file-primitives */ - - /* 4 bits allocated a maximum of 16 types for NumberType */ - SLE_VAR_BL = 0 << 4, - SLE_VAR_I8 = 1 << 4, - SLE_VAR_U8 = 2 << 4, - SLE_VAR_I16 = 3 << 4, - SLE_VAR_U16 = 4 << 4, - SLE_VAR_I32 = 5 << 4, - SLE_VAR_U32 = 6 << 4, - SLE_VAR_I64 = 7 << 4, - SLE_VAR_U64 = 8 << 4, - SLE_VAR_NULL = 9 << 4, ///< useful to write zeros in savegame. - SLE_VAR_STRB = 10 << 4, ///< string (with pre-allocated buffer) - SLE_VAR_STR = 12 << 4, ///< string pointer - SLE_VAR_STRQ = 13 << 4, ///< string pointer enclosed in quotes - SLE_VAR_NAME = 14 << 4, ///< old custom name to be converted to a std::string - SLE_VAR_CNAME = 15 << 4, ///< old custom name to be converted to a char pointer - /* 0 more possible memory-primitives */ - - /* Shortcut values */ - SLE_VAR_CHAR = SLE_VAR_I8, - - /* Default combinations of variables. As savegames change, so can variables - * and thus it is possible that the saved value and internal size do not - * match and you need to specify custom combo. The defaults are listed here */ - SLE_BOOL = SLE_FILE_I8 | SLE_VAR_BL, - SLE_INT8 = SLE_FILE_I8 | SLE_VAR_I8, - SLE_UINT8 = SLE_FILE_U8 | SLE_VAR_U8, - SLE_INT16 = SLE_FILE_I16 | SLE_VAR_I16, - SLE_UINT16 = SLE_FILE_U16 | SLE_VAR_U16, - SLE_INT32 = SLE_FILE_I32 | SLE_VAR_I32, - SLE_UINT32 = SLE_FILE_U32 | SLE_VAR_U32, - SLE_INT64 = SLE_FILE_I64 | SLE_VAR_I64, - SLE_UINT64 = SLE_FILE_U64 | SLE_VAR_U64, - SLE_CHAR = SLE_FILE_I8 | SLE_VAR_CHAR, - SLE_STRINGID = SLE_FILE_STRINGID | SLE_VAR_U32, - SLE_STRINGBUF = SLE_FILE_STRING | SLE_VAR_STRB, - SLE_STRING = SLE_FILE_STRING | SLE_VAR_STR, - SLE_STRINGQUOTE = SLE_FILE_STRING | SLE_VAR_STRQ, - SLE_NAME = SLE_FILE_STRINGID | SLE_VAR_NAME, - SLE_CNAME = SLE_FILE_STRINGID | SLE_VAR_CNAME, - SLE_VEHORDERID = SLE_FILE_VEHORDERID | SLE_VAR_U16, - - /* Shortcut values */ - SLE_UINT = SLE_UINT32, - SLE_INT = SLE_INT32, - SLE_STRB = SLE_STRINGBUF, - SLE_STR = SLE_STRING, - SLE_STRQ = SLE_STRINGQUOTE, - - /* 8 bits allocated for a maximum of 8 flags - * Flags directing saving/loading of a variable */ - SLF_ALLOW_CONTROL = 1 << 8, ///< Allow control codes in the strings. - SLF_ALLOW_NEWLINE = 1 << 9, ///< Allow new lines in the strings. -}; - -typedef uint32 VarType; - -/** Type of data saved. */ -enum SaveLoadTypes { - SL_VAR = 0, ///< Save/load a variable. - SL_REF = 1, ///< Save/load a reference. - SL_ARR = 2, ///< Save/load a fixed-size array of #SL_VAR elements. - SL_STR = 3, ///< Save/load a string. - SL_REFLIST = 4, ///< Save/load a list of #SL_REF elements. - SL_DEQUE = 5, ///< Save/load a deque of #SL_VAR elements. - SL_VEC = 6, ///< Save/load a vector of #SL_REF elements. - SL_STDSTR = 7, ///< Save/load a std::string. - - /* non-normal save-load types */ - SL_WRITEBYTE = 8, - SL_VEH_INCLUDE = 9, - SL_ST_INCLUDE = 10, - - SL_PTRDEQ = 13, ///< Save/load a deque of #SL_REF elements. - SL_VARVEC = 14, ///< Save/load a primitive type vector. -}; - -typedef byte SaveLoadType; ///< Save/load type. @see SaveLoadTypes - -/** SaveLoad type struct. Do NOT use this directly but use the SLE_ macros defined just below! */ -struct SaveLoad { - bool global; ///< should we load a global variable or a non-global one - SaveLoadType cmd; ///< the action to take with the saved/loaded type, All types need different action - VarType conv; ///< type of the variable to be saved, int - uint16 length; ///< (conditional) length of the variable (eg. arrays) (max array size is 65536 elements) - SaveLoadVersion version_from; ///< save/load the variable starting from this savegame version - SaveLoadVersion version_to; ///< save/load the variable until this savegame version - /* NOTE: This element either denotes the address of the variable for a global - * variable, or the offset within a struct which is then bound to a variable - * during runtime. Decision on which one to use is controlled by the function - * that is called to save it. address: global=true, offset: global=false */ - void *address; ///< address of variable OR offset of variable in the struct (max offset is 65536) - size_t size; ///< the sizeof size. - SlXvFeatureTest ext_feature_test; ///< extended feature test -}; - -/** A table of SaveLoad entries. */ -using SaveLoadTable = span; - /** * Storage of simple variables, references (pointers), and arrays. * @param cmd Load/save type. @see SaveLoadType @@ -1097,22 +622,6 @@ void SlSetLength(size_t length); size_t SlCalcObjMemberLength(const void *object, const SaveLoad &sld); size_t SlCalcObjLength(const void *object, const SaveLoadTable &slt); -byte SlReadByte(); -void SlWriteByte(byte b); - -int SlReadUint16(); -uint32 SlReadUint32(); -uint64 SlReadUint64(); - -void SlWriteUint16(uint16 v); -void SlWriteUint32(uint32 v); -void SlWriteUint64(uint64 v); - -void SlSkipBytes(size_t length); - -size_t SlGetBytesRead(); -size_t SlGetBytesWritten(); - void SlGlobList(const SaveLoadTable &slt); void SlArray(void *array, size_t length, VarType conv); void SlObject(void *object, const SaveLoadTable &slt); @@ -1123,10 +632,7 @@ void SlObjectSaveFiltered(void *object, const SaveLoadTable &slt); void SlObjectLoadFiltered(void *object, const SaveLoadTable &slt); void SlObjectPtrOrNullFiltered(void *object, const SaveLoadTable &slt); -void NORETURN SlError(StringID string, const char *extra_msg = nullptr, bool already_malloced = false); -void NORETURN SlErrorCorrupt(const char *msg, bool already_malloced = false); void NORETURN CDECL SlErrorFmt(StringID string, const char *msg, ...) WARN_FORMAT(2, 3); -void NORETURN CDECL SlErrorCorruptFmt(const char *format, ...) WARN_FORMAT(1, 2); bool SaveloadCrashWithMissingNewGRFs(); diff --git a/src/saveload/saveload_common.h b/src/saveload/saveload_common.h new file mode 100644 index 0000000000..dd31c2f9af --- /dev/null +++ b/src/saveload/saveload_common.h @@ -0,0 +1,402 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file saveload_common.h Common functions/types for saving and loading games. */ + +#ifndef SAVELOAD_COMMON_H +#define SAVELOAD_COMMON_H + +#include "../strings_type.h" +#include "../core/span_type.hpp" + +struct SaveLoad; + +/** A table of SaveLoad entries. */ +using SaveLoadTable = span; + +namespace upstream_sl { + struct SaveLoad; + + /** A table of SaveLoad entries. */ + using SaveLoadTable = span; +} + +/** SaveLoad versions + * Previous savegame versions, the trunk revision where they were + * introduced and the released version that had that particular + * savegame version. + * Up to savegame version 18 there is a minor version as well. + * + * Older entries keep their original numbering. + * + * Newer entries should use a descriptive labels, numeric version + * and PR can be added to comment. + * + * Note that this list must not be reordered. + */ +enum SaveLoadVersion : uint16 { + SL_MIN_VERSION, ///< First savegame version + + SLV_1, ///< 1.0 0.1.x, 0.2.x + SLV_2, /**< 2.0 0.3.0 + * 2.1 0.3.1, 0.3.2 */ + SLV_3, ///< 3.x lost + SLV_4, /**< 4.0 1 + * 4.1 122 0.3.3, 0.3.4 + * 4.2 1222 0.3.5 + * 4.3 1417 + * 4.4 1426 */ + + SLV_5, /**< 5.0 1429 + * 5.1 1440 + * 5.2 1525 0.3.6 */ + SLV_6, /**< 6.0 1721 + * 6.1 1768 */ + SLV_7, ///< 7.0 1770 + SLV_8, ///< 8.0 1786 + SLV_9, ///< 9.0 1909 + + SLV_10, ///< 10.0 2030 + SLV_11, /**< 11.0 2033 + * 11.1 2041 */ + SLV_12, ///< 12.1 2046 + SLV_13, ///< 13.1 2080 0.4.0, 0.4.0.1 + SLV_14, ///< 14.0 2441 + + SLV_15, ///< 15.0 2499 + SLV_16, /**< 16.0 2817 + * 16.1 3155 */ + SLV_17, /**< 17.0 3212 + * 17.1 3218 */ + SLV_18, ///< 18 3227 + SLV_19, ///< 19 3396 + + SLV_20, ///< 20 3403 + SLV_21, ///< 21 3472 0.4.x + SLV_22, ///< 22 3726 + SLV_23, ///< 23 3915 + SLV_24, ///< 24 4150 + + SLV_25, ///< 25 4259 + SLV_26, ///< 26 4466 + SLV_27, ///< 27 4757 + SLV_28, ///< 28 4987 + SLV_29, ///< 29 5070 + + SLV_30, ///< 30 5946 + SLV_31, ///< 31 5999 + SLV_32, ///< 32 6001 + SLV_33, ///< 33 6440 + SLV_34, ///< 34 6455 + + SLV_35, ///< 35 6602 + SLV_36, ///< 36 6624 + SLV_37, ///< 37 7182 + SLV_38, ///< 38 7195 + SLV_39, ///< 39 7269 + + SLV_40, ///< 40 7326 + SLV_41, ///< 41 7348 0.5.x + SLV_42, ///< 42 7573 + SLV_43, ///< 43 7642 + SLV_44, ///< 44 8144 + + SLV_45, ///< 45 8501 + SLV_46, ///< 46 8705 + SLV_47, ///< 47 8735 + SLV_48, ///< 48 8935 + SLV_49, ///< 49 8969 + + SLV_50, ///< 50 8973 + SLV_51, ///< 51 8978 + SLV_52, ///< 52 9066 + SLV_53, ///< 53 9316 + SLV_54, ///< 54 9613 + + SLV_55, ///< 55 9638 + SLV_56, ///< 56 9667 + SLV_57, ///< 57 9691 + SLV_58, ///< 58 9762 + SLV_59, ///< 59 9779 + + SLV_60, ///< 60 9874 + SLV_61, ///< 61 9892 + SLV_62, ///< 62 9905 + SLV_63, ///< 63 9956 + SLV_64, ///< 64 10006 + + SLV_65, ///< 65 10210 + SLV_66, ///< 66 10211 + SLV_67, ///< 67 10236 + SLV_68, ///< 68 10266 + SLV_69, ///< 69 10319 + + SLV_70, ///< 70 10541 + SLV_71, ///< 71 10567 + SLV_72, ///< 72 10601 + SLV_73, ///< 73 10903 + SLV_74, ///< 74 11030 + + SLV_75, ///< 75 11107 + SLV_76, ///< 76 11139 + SLV_77, ///< 77 11172 + SLV_78, ///< 78 11176 + SLV_79, ///< 79 11188 + + SLV_80, ///< 80 11228 + SLV_81, ///< 81 11244 + SLV_82, ///< 82 11410 + SLV_83, ///< 83 11589 + SLV_84, ///< 84 11822 + + SLV_85, ///< 85 11874 + SLV_86, ///< 86 12042 + SLV_87, ///< 87 12129 + SLV_88, ///< 88 12134 + SLV_89, ///< 89 12160 + + SLV_90, ///< 90 12293 + SLV_91, ///< 91 12347 + SLV_92, ///< 92 12381 0.6.x + SLV_93, ///< 93 12648 + SLV_94, ///< 94 12816 + + SLV_95, ///< 95 12924 + SLV_96, ///< 96 13226 + SLV_97, ///< 97 13256 + SLV_98, ///< 98 13375 + SLV_99, ///< 99 13838 + + SLV_100, ///< 100 13952 + SLV_101, ///< 101 14233 + SLV_102, ///< 102 14332 + SLV_103, ///< 103 14598 + SLV_104, ///< 104 14735 + + SLV_105, ///< 105 14803 + SLV_106, ///< 106 14919 + SLV_107, ///< 107 15027 + SLV_108, ///< 108 15045 + SLV_109, ///< 109 15075 + + SLV_110, ///< 110 15148 + SLV_111, ///< 111 15190 + SLV_112, ///< 112 15290 + SLV_113, ///< 113 15340 + SLV_114, ///< 114 15601 + + SLV_115, ///< 115 15695 + SLV_116, ///< 116 15893 0.7.x + SLV_117, ///< 117 16037 + SLV_118, ///< 118 16129 + SLV_119, ///< 119 16242 + + SLV_120, ///< 120 16439 + SLV_121, ///< 121 16694 + SLV_122, ///< 122 16855 + SLV_123, ///< 123 16909 + SLV_124, ///< 124 16993 + + SLV_125, ///< 125 17113 + SLV_126, ///< 126 17433 + SLV_127, ///< 127 17439 + SLV_128, ///< 128 18281 + SLV_129, ///< 129 18292 + + SLV_130, ///< 130 18404 + SLV_131, ///< 131 18481 + SLV_132, ///< 132 18522 + SLV_133, ///< 133 18674 + SLV_134, ///< 134 18703 + + SLV_135, ///< 135 18719 + SLV_136, ///< 136 18764 + SLV_137, ///< 137 18912 + SLV_138, ///< 138 18942 1.0.x + SLV_139, ///< 139 19346 + + SLV_140, ///< 140 19382 + SLV_141, ///< 141 19799 + SLV_142, ///< 142 20003 + SLV_143, ///< 143 20048 + SLV_144, ///< 144 20334 + + SLV_145, ///< 145 20376 + SLV_146, ///< 146 20446 + SLV_147, ///< 147 20621 + SLV_148, ///< 148 20659 + SLV_149, ///< 149 20832 + + SLV_150, ///< 150 20857 + SLV_151, ///< 151 20918 + SLV_152, ///< 152 21171 + SLV_153, ///< 153 21263 + SLV_154, ///< 154 21426 + + SLV_155, ///< 155 21453 + SLV_156, ///< 156 21728 + SLV_157, ///< 157 21862 + SLV_158, ///< 158 21933 + SLV_159, ///< 159 21962 + + SLV_160, ///< 160 21974 1.1.x + SLV_161, ///< 161 22567 + SLV_162, ///< 162 22713 + SLV_163, ///< 163 22767 + SLV_164, ///< 164 23290 + + SLV_165, ///< 165 23304 + SLV_166, ///< 166 23415 + SLV_167, ///< 167 23504 + SLV_168, ///< 168 23637 + SLV_169, ///< 169 23816 + + SLV_170, ///< 170 23826 + SLV_171, ///< 171 23835 + SLV_172, ///< 172 23947 + SLV_173, ///< 173 23967 1.2.0-RC1 + SLV_174, ///< 174 23973 1.2.x + + SLV_175, ///< 175 24136 + SLV_176, ///< 176 24446 + SLV_177, ///< 177 24619 + SLV_178, ///< 178 24789 + SLV_179, ///< 179 24810 + + SLV_180, ///< 180 24998 1.3.x + SLV_181, ///< 181 25012 + SLV_182, ///< 182 25115 FS#5492, r25259, r25296 Goal status + SLV_183, ///< 183 25363 Cargodist + SLV_184, ///< 184 25508 Unit localisation split + + SLV_185, ///< 185 25620 Storybooks + SLV_186, ///< 186 25833 Objects storage + SLV_187, ///< 187 25899 Linkgraph - restricted flows + SLV_188, ///< 188 26169 v1.4 FS#5831 Unify RV travel time + SLV_189, ///< 189 26450 Hierarchical vehicle subgroups + + SLV_190, ///< 190 26547 Separate order travel and wait times + SLV_191, ///< 191 26636 FS#6026 Fix disaster vehicle storage (No bump) + ///< 191 26646 FS#6041 Linkgraph - store locations + SLV_192, ///< 192 26700 FS#6066 Fix saving of order backups + SLV_193, ///< 193 26802 + SLV_194, ///< 194 26881 v1.5 + + SLV_195, ///< 195 27572 v1.6.1 + SLV_196, ///< 196 27778 v1.7 + SLV_197, ///< 197 27978 v1.8 + SLV_198, ///< 198 PR#6763 Switch town growth rate and counter to actual game ticks + SLV_EXTEND_CARGOTYPES, ///< 199 PR#6802 Extend cargotypes to 64 + + SLV_EXTEND_RAILTYPES, ///< 200 PR#6805 Extend railtypes to 64, adding uint16 to map array. + SLV_EXTEND_PERSISTENT_STORAGE, ///< 201 PR#6885 Extend NewGRF persistent storages. + SLV_EXTEND_INDUSTRY_CARGO_SLOTS, ///< 202 PR#6867 Increase industry cargo slots to 16 in, 16 out + SLV_SHIP_PATH_CACHE, ///< 203 PR#7072 Add path cache for ships + SLV_SHIP_ROTATION, ///< 204 PR#7065 Add extra rotation stages for ships. + + SLV_GROUP_LIVERIES, ///< 205 PR#7108 Livery storage change and group liveries. + SLV_SHIPS_STOP_IN_LOCKS, ///< 206 PR#7150 Ship/lock movement changes. + SLV_FIX_CARGO_MONITOR, ///< 207 PR#7175 v1.9 Cargo monitor data packing fix to support 64 cargotypes. + SLV_TOWN_CARGOGEN, ///< 208 PR#6965 New algorithms for town building cargo generation. + SLV_SHIP_CURVE_PENALTY, ///< 209 PR#7289 Configurable ship curve penalties. + + SLV_SERVE_NEUTRAL_INDUSTRIES, ///< 210 PR#7234 Company stations can serve industries with attached neutral stations. + SLV_ROADVEH_PATH_CACHE, ///< 211 PR#7261 Add path cache for road vehicles. + SLV_REMOVE_OPF, ///< 212 PR#7245 Remove OPF. + SLV_TREES_WATER_CLASS, ///< 213 PR#7405 WaterClass update for tree tiles. + SLV_ROAD_TYPES, ///< 214 PR#6811 NewGRF road types. + + SLV_SCRIPT_MEMLIMIT, ///< 215 PR#7516 Limit on AI/GS memory consumption. + SLV_MULTITILE_DOCKS, ///< 216 PR#7380 Multiple docks per station. + SLV_TRADING_AGE, ///< 217 PR#7780 Configurable company trading age. + SLV_ENDING_YEAR, ///< 218 PR#7747 v1.10 Configurable ending year. + SLV_REMOVE_TOWN_CARGO_CACHE, ///< 219 PR#8258 Remove town cargo acceptance and production caches. + + /* Patchpacks for a while considered it a good idea to jump a few versions + * above our version for their savegames. But as time continued, this gap + * has been closing, up to the point we would start to reuse versions from + * their patchpacks. This is not a problem from our perspective: the + * savegame will simply fail to load because they all contain chunks we + * cannot digest. But, this gives for ugly errors. As we have plenty of + * versions anyway, we simply skip the versions we know belong to + * patchpacks. This way we can present the user with a clean error + * indicate they are loading a savegame from a patchpack. + * For future patchpack creators: please follow a system like JGRPP, where + * the version is masked with 0x8000, and the true version is stored in + * its own chunk with feature toggles. + */ + SLV_START_PATCHPACKS, ///< 220 First known patchpack to use a version just above ours. + SLV_END_PATCHPACKS = 286, ///< 286 Last known patchpack to use a version just above ours. + + SLV_GS_INDUSTRY_CONTROL, ///< 287 PR#7912 and PR#8115 GS industry control. + SLV_VEH_MOTION_COUNTER, ///< 288 PR#8591 Desync safe motion counter + SLV_INDUSTRY_TEXT, ///< 289 PR#8576 v1.11.0-RC1 Additional GS text for industries. + SLV_MAPGEN_SETTINGS_REVAMP, ///< 290 PR#8891 v1.11 Revamp of some mapgen settings (snow coverage, desert coverage, heightmap height, custom terrain type). + SLV_GROUP_REPLACE_WAGON_REMOVAL, ///< 291 PR#7441 Per-group wagon removal flag. + SLV_CUSTOM_SUBSIDY_DURATION, ///< 292 PR#9081 Configurable subsidy duration. + + /* upstream savegame versions follow */ + + SLV_SAVELOAD_LIST_LENGTH, ///< 293 PR#9374 Consistency in list length with SL_STRUCT / SL_STRUCTLIST / SL_DEQUE / SL_REFLIST. + SLV_RIFF_TO_ARRAY, ///< 294 PR#9375 Changed many CH_RIFF chunks to CH_ARRAY chunks. + + SLV_TABLE_CHUNKS, ///< 295 PR#9322 Introduction of CH_TABLE and CH_SPARSE_TABLE. + SLV_SCRIPT_INT64, ///< 296 PR#9415 SQInteger is 64bit but was saved as 32bit. + SLV_LINKGRAPH_TRAVEL_TIME, ///< 297 PR#9457 v12.0-RC1 Store travel time in the linkgraph. + SLV_DOCK_DOCKINGTILES, ///< 298 PR#9578 All tiles around docks may be docking tiles. + SLV_REPAIR_OBJECT_DOCKING_TILES, ///< 299 PR#9594 v12.0 Fixing issue with docking tiles overlapping objects. + + SL_MAX_VERSION, ///< Highest possible saveload version + + SL_SPRING_2013_v2_0_102 = 220, + SL_SPRING_2013_v2_1_108 = 221, + SL_SPRING_2013_v2_1_147 = 222, + SL_SPRING_2013_v2_3_XXX = 223, + SL_SPRING_2013_v2_3_b3 = 224, + SL_SPRING_2013_v2_3_b4 = 225, + SL_SPRING_2013_v2_3_b5 = 226, + SL_SPRING_2013_v2_4 = 227, + SL_TRACE_RESTRICT_2000 = 2000, + SL_TRACE_RESTRICT_2001 = 2001, + SL_TRACE_RESTRICT_2002 = 2002, + SL_JOKER_1_19 = 278, + SL_JOKER_1_20 = 279, + SL_JOKER_1_21 = 280, + SL_JOKER_1_22 = 281, + SL_JOKER_1_23 = 282, + SL_JOKER_1_24 = 283, + SL_JOKER_1_25 = 284, + SL_JOKER_1_26 = 285, + SL_JOKER_1_27 = 286, + SL_CHILLPP_201 = 201, + SL_CHILLPP_232 = 232, + SL_CHILLPP_233 = 233, +}; + +byte SlReadByte(); +void SlWriteByte(byte b); + +int SlReadUint16(); +uint32 SlReadUint32(); +uint64 SlReadUint64(); + +void SlWriteUint16(uint16 v); +void SlWriteUint32(uint32 v); +void SlWriteUint64(uint64 v); + +void SlSkipBytes(size_t length); + +size_t SlGetBytesRead(); +size_t SlGetBytesWritten(); + +void NORETURN SlError(StringID string, const char *extra_msg = nullptr, bool already_malloced = false); +void NORETURN SlErrorCorrupt(const char *msg, bool already_malloced = false); +void NORETURN CDECL SlErrorCorruptFmt(const char *format, ...) WARN_FORMAT(1, 2); + +bool SaveLoadFileTypeIsScenario(); + +#endif diff --git a/src/saveload/saveload_types.h b/src/saveload/saveload_types.h new file mode 100644 index 0000000000..5e59328d59 --- /dev/null +++ b/src/saveload/saveload_types.h @@ -0,0 +1,135 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file saveload_common.h Common functions/types for saving and loading games. */ + +#ifndef SAVELOAD_TYPES_H +#define SAVELOAD_TYPES_H + +#include "saveload_common.h" +#include "extended_ver_sl.h" + +/** + * VarTypes is the general bitmasked magic type that tells us + * certain characteristics about the variable it refers to. For example + * SLE_FILE_* gives the size(type) as it would be in the savegame and + * SLE_VAR_* the size(type) as it is in memory during runtime. These are + * the first 8 bits (0-3 SLE_FILE, 4-7 SLE_VAR). + * Bits 8-15 are reserved for various flags as explained below + */ +enum VarTypes { + /* 4 bits allocated a maximum of 16 types for NumberType */ + SLE_FILE_I8 = 0, + SLE_FILE_U8 = 1, + SLE_FILE_I16 = 2, + SLE_FILE_U16 = 3, + SLE_FILE_I32 = 4, + SLE_FILE_U32 = 5, + SLE_FILE_I64 = 6, + SLE_FILE_U64 = 7, + SLE_FILE_STRINGID = 8, ///< StringID offset into strings-array + SLE_FILE_STRING = 9, + SLE_FILE_VEHORDERID = 10, + /* 5 more possible file-primitives */ + + /* 4 bits allocated a maximum of 16 types for NumberType */ + SLE_VAR_BL = 0 << 4, + SLE_VAR_I8 = 1 << 4, + SLE_VAR_U8 = 2 << 4, + SLE_VAR_I16 = 3 << 4, + SLE_VAR_U16 = 4 << 4, + SLE_VAR_I32 = 5 << 4, + SLE_VAR_U32 = 6 << 4, + SLE_VAR_I64 = 7 << 4, + SLE_VAR_U64 = 8 << 4, + SLE_VAR_NULL = 9 << 4, ///< useful to write zeros in savegame. + SLE_VAR_STRB = 10 << 4, ///< string (with pre-allocated buffer) + SLE_VAR_STR = 12 << 4, ///< string pointer + SLE_VAR_STRQ = 13 << 4, ///< string pointer enclosed in quotes + SLE_VAR_NAME = 14 << 4, ///< old custom name to be converted to a std::string + SLE_VAR_CNAME = 15 << 4, ///< old custom name to be converted to a char pointer + /* 0 more possible memory-primitives */ + + /* Shortcut values */ + SLE_VAR_CHAR = SLE_VAR_I8, + + /* Default combinations of variables. As savegames change, so can variables + * and thus it is possible that the saved value and internal size do not + * match and you need to specify custom combo. The defaults are listed here */ + SLE_BOOL = SLE_FILE_I8 | SLE_VAR_BL, + SLE_INT8 = SLE_FILE_I8 | SLE_VAR_I8, + SLE_UINT8 = SLE_FILE_U8 | SLE_VAR_U8, + SLE_INT16 = SLE_FILE_I16 | SLE_VAR_I16, + SLE_UINT16 = SLE_FILE_U16 | SLE_VAR_U16, + SLE_INT32 = SLE_FILE_I32 | SLE_VAR_I32, + SLE_UINT32 = SLE_FILE_U32 | SLE_VAR_U32, + SLE_INT64 = SLE_FILE_I64 | SLE_VAR_I64, + SLE_UINT64 = SLE_FILE_U64 | SLE_VAR_U64, + SLE_CHAR = SLE_FILE_I8 | SLE_VAR_CHAR, + SLE_STRINGID = SLE_FILE_STRINGID | SLE_VAR_U32, + SLE_STRINGBUF = SLE_FILE_STRING | SLE_VAR_STRB, + SLE_STRING = SLE_FILE_STRING | SLE_VAR_STR, + SLE_STRINGQUOTE = SLE_FILE_STRING | SLE_VAR_STRQ, + SLE_NAME = SLE_FILE_STRINGID | SLE_VAR_NAME, + SLE_CNAME = SLE_FILE_STRINGID | SLE_VAR_CNAME, + SLE_VEHORDERID = SLE_FILE_VEHORDERID | SLE_VAR_U16, + + /* Shortcut values */ + SLE_UINT = SLE_UINT32, + SLE_INT = SLE_INT32, + SLE_STRB = SLE_STRINGBUF, + SLE_STR = SLE_STRING, + SLE_STRQ = SLE_STRINGQUOTE, + + /* 8 bits allocated for a maximum of 8 flags + * Flags directing saving/loading of a variable */ + SLF_ALLOW_CONTROL = 1 << 8, ///< Allow control codes in the strings. + SLF_ALLOW_NEWLINE = 1 << 9, ///< Allow new lines in the strings. +}; + +typedef uint32 VarType; + +/** Type of data saved. */ +enum SaveLoadTypes { + SL_VAR = 0, ///< Save/load a variable. + SL_REF = 1, ///< Save/load a reference. + SL_ARR = 2, ///< Save/load a fixed-size array of #SL_VAR elements. + SL_STR = 3, ///< Save/load a string. + SL_REFLIST = 4, ///< Save/load a list of #SL_REF elements. + SL_DEQUE = 5, ///< Save/load a deque of #SL_VAR elements. + SL_VEC = 6, ///< Save/load a vector of #SL_REF elements. + SL_STDSTR = 7, ///< Save/load a std::string. + + /* non-normal save-load types */ + SL_WRITEBYTE = 8, + SL_VEH_INCLUDE = 9, + SL_ST_INCLUDE = 10, + + SL_PTRDEQ = 13, ///< Save/load a deque of #SL_REF elements. + SL_VARVEC = 14, ///< Save/load a primitive type vector. +}; + +typedef byte SaveLoadType; ///< Save/load type. @see SaveLoadTypes + +/** SaveLoad type struct. Do NOT use this directly but use the SLE_ macros defined just below! */ +struct SaveLoad { + bool global; ///< should we load a global variable or a non-global one + SaveLoadType cmd; ///< the action to take with the saved/loaded type, All types need different action + VarType conv; ///< type of the variable to be saved, int + uint16 length; ///< (conditional) length of the variable (eg. arrays) (max array size is 65536 elements) + SaveLoadVersion version_from; ///< save/load the variable starting from this savegame version + SaveLoadVersion version_to; ///< save/load the variable until this savegame version + /* NOTE: This element either denotes the address of the variable for a global + * variable, or the offset within a struct which is then bound to a variable + * during runtime. Decision on which one to use is controlled by the function + * that is called to save it. address: global=true, offset: global=false */ + void *address; ///< address of variable OR offset of variable in the struct (max offset is 65536) + size_t size; ///< the sizeof size. + SlXvFeatureTest ext_feature_test; ///< extended feature test +}; + +#endif diff --git a/src/saveload/upstream/CMakeLists.txt b/src/saveload/upstream/CMakeLists.txt new file mode 100644 index 0000000000..b969180c19 --- /dev/null +++ b/src/saveload/upstream/CMakeLists.txt @@ -0,0 +1,38 @@ +add_subdirectory(compat) + +add_files( + ai_sl.cpp + airport_sl.cpp + animated_tile_sl.cpp + autoreplace_sl.cpp + cargomonitor_sl.cpp + cargopacket_sl.cpp + cheat_sl.cpp + company_sl.cpp + depot_sl.cpp + economy_sl.cpp + engine_sl.cpp + game_sl.cpp + gamelog_sl.cpp + goal_sl.cpp + group_sl.cpp + industry_sl.cpp + labelmaps_sl.cpp + linkgraph_sl.cpp + map_sl.cpp + misc_sl.cpp + newgrf_sl.cpp + newgrf_sl.h + object_sl.cpp + order_sl.cpp + saveload.cpp + saveload.h + settings_sl.cpp + signs_sl.cpp + station_sl.cpp + storage_sl.cpp + story_sl.cpp + subsidy_sl.cpp + town_sl.cpp + vehicle_sl.cpp +) diff --git a/src/saveload/upstream/ai_sl.cpp b/src/saveload/upstream/ai_sl.cpp new file mode 100644 index 0000000000..ceca8299c2 --- /dev/null +++ b/src/saveload/upstream/ai_sl.cpp @@ -0,0 +1,143 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file ai_sl.cpp Handles the saveload part of the AIs */ + +#include "../../stdafx.h" +#include "../../debug.h" + +#include "saveload.h" +#include "compat/ai_sl_compat.h" + +#include "../../company_base.h" +#include "../../string_func.h" + +#include "../../ai/ai.hpp" +#include "../../ai/ai_config.hpp" +#include "../../network/network.h" +#include "../../ai/ai_instance.hpp" + +#include "../../safeguards.h" + +namespace upstream_sl { + +static std::string _ai_saveload_name; +static int _ai_saveload_version; +static std::string _ai_saveload_settings; +static bool _ai_saveload_is_random; + +static const SaveLoad _ai_company_desc[] = { + SLEG_SSTR("name", _ai_saveload_name, SLE_STR), + SLEG_SSTR("settings", _ai_saveload_settings, SLE_STR), + SLEG_CONDVAR("version", _ai_saveload_version, SLE_UINT32, SLV_108, SL_MAX_VERSION), + SLEG_CONDVAR("is_random", _ai_saveload_is_random, SLE_BOOL, SLV_136, SL_MAX_VERSION), +}; + +static void SaveReal_AIPL(int *index_ptr) +{ + CompanyID index = (CompanyID)*index_ptr; + AIConfig *config = AIConfig::GetConfig(index); + + if (config->HasScript()) { + _ai_saveload_name = config->GetName(); + _ai_saveload_version = config->GetVersion(); + } else { + /* No AI is configured for this so store an empty string as name. */ + _ai_saveload_name.clear(); + _ai_saveload_version = -1; + } + + _ai_saveload_is_random = config->IsRandom(); + _ai_saveload_settings = config->SettingsToString(); + + SlObject(nullptr, _ai_company_desc); + /* If the AI was active, store its data too */ + if (Company::IsValidAiID(index)) AI::Save(index); +} + +struct AIPLChunkHandler : ChunkHandler { + AIPLChunkHandler() : ChunkHandler('AIPL', CH_TABLE) {} + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_ai_company_desc, _ai_company_sl_compat); + + /* Free all current data */ + for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { + AIConfig::GetConfig(c, AIConfig::SSS_FORCE_GAME)->Change(nullptr); + } + + CompanyID index; + while ((index = (CompanyID)SlIterateArray()) != (CompanyID)-1) { + if (index >= MAX_COMPANIES) SlErrorCorrupt("Too many AI configs"); + + _ai_saveload_is_random = false; + _ai_saveload_version = -1; + SlObject(nullptr, slt); + + if (_networking && !_network_server) { + if (Company::IsValidAiID(index)) AIInstance::LoadEmpty(); + continue; + } + + AIConfig *config = AIConfig::GetConfig(index, AIConfig::SSS_FORCE_GAME); + if (_ai_saveload_name.empty()) { + /* A random AI. */ + config->Change(nullptr, -1, false, true); + } else { + config->Change(_ai_saveload_name.c_str(), _ai_saveload_version, false, _ai_saveload_is_random); + if (!config->HasScript()) { + /* No version of the AI available that can load the data. Try to load the + * latest version of the AI instead. */ + config->Change(_ai_saveload_name.c_str(), -1, false, _ai_saveload_is_random); + if (!config->HasScript()) { + if (_ai_saveload_name.compare("%_dummy") != 0) { + DEBUG(script, 0, "The savegame has an AI by the name '%s', version %u which is no longer available.", _ai_saveload_name.c_str(), _ai_saveload_version); + DEBUG(script, 0, "A random other AI will be loaded in its place."); + } else { + DEBUG(script, 0, "The savegame had no AIs available at the time of saving."); + DEBUG(script, 0, "A random available AI will be loaded now."); + } + } else { + DEBUG(script, 0, "The savegame has an AI by the name '%s', version %u which is no longer available.", _ai_saveload_name.c_str(), _ai_saveload_version); + DEBUG(script, 0, "The latest version of that AI has been loaded instead, but it'll not get the savegame data as it's incompatible."); + } + /* Make sure the AI doesn't get the saveload data, as it was not the + * writer of the saveload data in the first place */ + _ai_saveload_version = -1; + } + } + + config->StringToSettings(_ai_saveload_settings); + + /* Start the AI directly if it was active in the savegame */ + if (Company::IsValidAiID(index)) { + AI::StartNew(index, false); + AI::Load(index, _ai_saveload_version); + } + } + } + + void Save() const override + { + SlTableHeader(_ai_company_desc); + + for (int i = COMPANY_FIRST; i < MAX_COMPANIES; i++) { + SlSetArrayIndex(i); + SlAutolength((AutolengthProc *)SaveReal_AIPL, &i); + } + } +}; + +static const AIPLChunkHandler AIPL; +static const ChunkHandlerRef ai_chunk_handlers[] = { + AIPL, +}; + +extern const ChunkHandlerTable _ai_chunk_handlers(ai_chunk_handlers); + +} diff --git a/src/saveload/upstream/airport_sl.cpp b/src/saveload/upstream/airport_sl.cpp new file mode 100644 index 0000000000..969f83ab9d --- /dev/null +++ b/src/saveload/upstream/airport_sl.cpp @@ -0,0 +1,36 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file airport_sl.cpp Code handling saving and loading airport ids */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "newgrf_sl.h" + +#include "../../safeguards.h" + +namespace upstream_sl { + +struct APIDChunkHandler : NewGRFMappingChunkHandler { + APIDChunkHandler() : NewGRFMappingChunkHandler('APID', _airport_mngr) {} +}; + +struct ATIDChunkHandler : NewGRFMappingChunkHandler { + ATIDChunkHandler() : NewGRFMappingChunkHandler('ATID', _airporttile_mngr) {} +}; + +static const ATIDChunkHandler ATID; +static const APIDChunkHandler APID; +static const ChunkHandlerRef airport_chunk_handlers[] = { + ATID, + APID, +}; + +extern const ChunkHandlerTable _airport_chunk_handlers(airport_chunk_handlers); + +} diff --git a/src/saveload/upstream/animated_tile_sl.cpp b/src/saveload/upstream/animated_tile_sl.cpp new file mode 100644 index 0000000000..128bf9c34e --- /dev/null +++ b/src/saveload/upstream/animated_tile_sl.cpp @@ -0,0 +1,84 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file animated_tile_sl.cpp Code handling saving and loading of animated tiles */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "compat/animated_tile_sl_compat.h" + +#include "../../tile_type.h" +#include "../../animated_tile.h" +#include "../../core/alloc_func.hpp" +#include "../../core/smallvec_type.hpp" + +#include "../../safeguards.h" + +namespace upstream_sl { + +static std::vector _tmp_animated_tiles; + +static const SaveLoad _animated_tile_desc[] = { + SLEG_VECTOR("tiles", _tmp_animated_tiles, SLE_UINT32), +}; + +struct ANITChunkHandler : ChunkHandler { + ANITChunkHandler() : ChunkHandler('ANIT', CH_TABLE) {} + + void Save() const override + { + // removed + NOT_REACHED(); + } + + void Load() const override + { + /* Before version 80 we did NOT have a variable length animated tile table */ + if (IsSavegameVersionBefore(SLV_80)) { + /* In pre version 6, we has 16bit per tile, now we have 32bit per tile, convert it ;) */ + TileIndex anim_list[256]; + SlCopy(anim_list, 256, IsSavegameVersionBefore(SLV_6) ? (SLE_FILE_U16 | SLE_VAR_U32) : SLE_UINT32); + + for (int i = 0; i < 256; i++) { + if (anim_list[i] == 0) break; + _animated_tiles[anim_list[i]] = {}; + } + return; + } + + if (IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY)) { + size_t count = SlGetFieldLength() / sizeof(uint32); + _animated_tiles.clear(); + for (uint i = 0; i < count; i++) { + _animated_tiles[SlReadUint32()] = {}; + } + return; + } + + const std::vector slt = SlCompatTableHeader(_animated_tile_desc, _animated_tile_sl_compat); + + if (SlIterateArray() == -1) return; + SlGlobList(slt); + if (SlIterateArray() != -1) SlErrorCorrupt("Too many ANIT entries"); + + for (TileIndex t : _tmp_animated_tiles) { + _animated_tiles[t] = {}; + } + _tmp_animated_tiles.clear(); + } +}; + + +static const ANITChunkHandler ANIT; +static const ChunkHandlerRef animated_tile_chunk_handlers[] = { + ANIT, +}; + +extern const ChunkHandlerTable _animated_tile_chunk_handlers(animated_tile_chunk_handlers); + +} diff --git a/src/saveload/upstream/autoreplace_sl.cpp b/src/saveload/upstream/autoreplace_sl.cpp new file mode 100644 index 0000000000..af0cdbbd0e --- /dev/null +++ b/src/saveload/upstream/autoreplace_sl.cpp @@ -0,0 +1,77 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file autoreplace_sl.cpp Code handling saving and loading of autoreplace rules */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "compat/autoreplace_sl_compat.h" + +#include "../../autoreplace_base.h" + +#include "../../safeguards.h" + +namespace upstream_sl { + +static const SaveLoad _engine_renew_desc[] = { + SLE_VAR(EngineRenew, from, SLE_UINT16), + SLE_VAR(EngineRenew, to, SLE_UINT16), + + SLE_REF(EngineRenew, next, REF_ENGINE_RENEWS), + SLE_CONDVAR(EngineRenew, group_id, SLE_UINT16, SLV_60, SL_MAX_VERSION), + SLE_CONDVAR(EngineRenew, replace_when_old, SLE_BOOL, SLV_175, SL_MAX_VERSION), +}; + +struct ERNWChunkHandler : ChunkHandler { + ERNWChunkHandler() : ChunkHandler('ERNW', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_engine_renew_desc); + + for (EngineRenew *er : EngineRenew::Iterate()) { + SlSetArrayIndex(er->index); + SlObject(er, _engine_renew_desc); + } + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_engine_renew_desc, _engine_renew_sl_compat); + + int index; + + while ((index = SlIterateArray()) != -1) { + EngineRenew *er = new (index) EngineRenew(); + SlObject(er, slt); + + /* Advanced vehicle lists, ungrouped vehicles got added */ + if (IsSavegameVersionBefore(SLV_60)) { + er->group_id = ALL_GROUP; + } else if (IsSavegameVersionBefore(SLV_71)) { + if (er->group_id == DEFAULT_GROUP) er->group_id = ALL_GROUP; + } + } + } + + void FixPointers() const override + { + for (EngineRenew *er : EngineRenew::Iterate()) { + SlObject(er, _engine_renew_desc); + } + } +}; + +static const ERNWChunkHandler ERNW; +static const ChunkHandlerRef autoreplace_chunk_handlers[] = { + ERNW, +}; + +extern const ChunkHandlerTable _autoreplace_chunk_handlers(autoreplace_chunk_handlers); + +} diff --git a/src/saveload/upstream/cargomonitor_sl.cpp b/src/saveload/upstream/cargomonitor_sl.cpp new file mode 100644 index 0000000000..67d48d1ac5 --- /dev/null +++ b/src/saveload/upstream/cargomonitor_sl.cpp @@ -0,0 +1,146 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file cargomonitor_sl.cpp Code handling saving and loading of Cargo monitoring. */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "compat/cargomonitor_sl_compat.h" + +#include "../../cargomonitor.h" + +#include "../../safeguards.h" + +namespace upstream_sl { + +/** Temporary storage of cargo monitoring data for loading or saving it. */ +struct TempStorage { + CargoMonitorID number; + uint32 amount; +}; + +/** Description of the #TempStorage structure for the purpose of load and save. */ +static const SaveLoad _cargomonitor_pair_desc[] = { + SLE_VAR(TempStorage, number, SLE_UINT32), + SLE_VAR(TempStorage, amount, SLE_UINT32), +}; + +static CargoMonitorID FixupCargoMonitor(CargoMonitorID number) +{ + /* Between SLV_EXTEND_CARGOTYPES and SLV_FIX_CARGO_MONITOR, the + * CargoMonitorID structure had insufficient packing for more + * than 32 cargo types. Here we have to shuffle bits to account + * for the change. + * Company moved from bits 24-31 to 25-28. + * Cargo type increased from bits 19-23 to 19-24. + */ + SB(number, 25, 4, GB(number, 24, 4)); + SB(number, 29, 3, 0); + ClrBit(number, 24); + return number; +} + +/** #_cargo_deliveries monitoring map. */ +struct CMDLChunkHandler : ChunkHandler { + CMDLChunkHandler() : ChunkHandler('CMDL', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_cargomonitor_pair_desc); + + TempStorage storage; + + int i = 0; + CargoMonitorMap::const_iterator iter = _cargo_deliveries.begin(); + while (iter != _cargo_deliveries.end()) { + storage.number = iter->first; + storage.amount = iter->second; + + SlSetArrayIndex(i); + SlObject(&storage, _cargomonitor_pair_desc); + + i++; + iter++; + } + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_cargomonitor_pair_desc, _cargomonitor_pair_sl_compat); + + TempStorage storage; + bool fix = IsSavegameVersionBefore(SLV_FIX_CARGO_MONITOR); + + ClearCargoDeliveryMonitoring(); + for (;;) { + if (SlIterateArray() < 0) break; + SlObject(&storage, slt); + + if (fix) storage.number = FixupCargoMonitor(storage.number); + + std::pair p(storage.number, storage.amount); + _cargo_deliveries.insert(p); + } + } +}; + +/** #_cargo_pickups monitoring map. */ +struct CMPUChunkHandler : ChunkHandler { + CMPUChunkHandler() : ChunkHandler('CMPU', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_cargomonitor_pair_desc); + + TempStorage storage; + + int i = 0; + CargoMonitorMap::const_iterator iter = _cargo_pickups.begin(); + while (iter != _cargo_pickups.end()) { + storage.number = iter->first; + storage.amount = iter->second; + + SlSetArrayIndex(i); + SlObject(&storage, _cargomonitor_pair_desc); + + i++; + iter++; + } + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_cargomonitor_pair_desc, _cargomonitor_pair_sl_compat); + + TempStorage storage; + bool fix = IsSavegameVersionBefore(SLV_FIX_CARGO_MONITOR); + + ClearCargoPickupMonitoring(); + for (;;) { + if (SlIterateArray() < 0) break; + SlObject(&storage, slt); + + if (fix) storage.number = FixupCargoMonitor(storage.number); + + std::pair p(storage.number, storage.amount); + _cargo_pickups.insert(p); + } + } +}; + +/** Chunk definition of the cargomonitoring maps. */ +static const CMDLChunkHandler CMDL; +static const CMPUChunkHandler CMPU; +static const ChunkHandlerRef cargomonitor_chunk_handlers[] = { + CMDL, + CMPU, +}; + +extern const ChunkHandlerTable _cargomonitor_chunk_handlers(cargomonitor_chunk_handlers); + +} diff --git a/src/saveload/upstream/cargopacket_sl.cpp b/src/saveload/upstream/cargopacket_sl.cpp new file mode 100644 index 0000000000..b45976b2da --- /dev/null +++ b/src/saveload/upstream/cargopacket_sl.cpp @@ -0,0 +1,75 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file cargopacket_sl.cpp Code handling saving and loading of cargo packets */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "compat/cargopacket_sl_compat.h" + +#include "../../vehicle_base.h" +#include "../../station_base.h" + +#include "../../safeguards.h" + +namespace upstream_sl { + +/** + * Wrapper function to get the CargoPacket's internal structure while + * some of the variables itself are private. + * @return the saveload description for CargoPackets. + */ +SaveLoadTable GetCargoPacketDesc() +{ + static const SaveLoad _cargopacket_desc[] = { + SLE_VAR(CargoPacket, source, SLE_UINT16), + SLE_VAR(CargoPacket, source_xy, SLE_UINT32), + SLE_VAR(CargoPacket, loaded_at_xy, SLE_UINT32), + SLE_VAR(CargoPacket, count, SLE_UINT16), + SLE_VAR(CargoPacket, days_in_transit, SLE_UINT8), + SLE_VAR(CargoPacket, feeder_share, SLE_INT64), + SLE_CONDVAR(CargoPacket, source_type, SLE_UINT8, SLV_125, SL_MAX_VERSION), + SLE_CONDVAR(CargoPacket, source_id, SLE_UINT16, SLV_125, SL_MAX_VERSION), + }; + return _cargopacket_desc; +} + +struct CAPAChunkHandler : ChunkHandler { + CAPAChunkHandler() : ChunkHandler('CAPA', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(GetCargoPacketDesc()); + + for (CargoPacket *cp : CargoPacket::Iterate()) { + SlSetArrayIndex(cp->index); + SlObject(cp, GetCargoPacketDesc()); + } + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(GetCargoPacketDesc(), _cargopacket_sl_compat); + + int index; + + while ((index = SlIterateArray()) != -1) { + CargoPacket *cp = new (index) CargoPacket(); + SlObject(cp, slt); + } + } +}; + +static const CAPAChunkHandler CAPA; +static const ChunkHandlerRef cargopacket_chunk_handlers[] = { + CAPA, +}; + +extern const ChunkHandlerTable _cargopacket_chunk_handlers(cargopacket_chunk_handlers); + +} diff --git a/src/saveload/upstream/cheat_sl.cpp b/src/saveload/upstream/cheat_sl.cpp new file mode 100644 index 0000000000..864c49477b --- /dev/null +++ b/src/saveload/upstream/cheat_sl.cpp @@ -0,0 +1,86 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file cheat_sl.cpp Code handling saving and loading of cheats */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "compat/cheat_sl_compat.h" + +#include "../../cheat_type.h" + +#include "../../safeguards.h" + +namespace upstream_sl { + +static const SaveLoad _cheats_desc[] = { + SLE_VAR(Cheats, magic_bulldozer.been_used, SLE_BOOL), + SLE_VAR(Cheats, magic_bulldozer.value, SLE_BOOL), + SLE_VAR(Cheats, switch_company.been_used, SLE_BOOL), + SLE_VAR(Cheats, switch_company.value, SLE_BOOL), + SLE_VAR(Cheats, money.been_used, SLE_BOOL), + SLE_VAR(Cheats, money.value, SLE_BOOL), + SLE_VAR(Cheats, crossing_tunnels.been_used, SLE_BOOL), + SLE_VAR(Cheats, crossing_tunnels.value, SLE_BOOL), + SLE_VAR(Cheats, no_jetcrash.been_used, SLE_BOOL), + SLE_VAR(Cheats, no_jetcrash.value, SLE_BOOL), + SLE_VAR(Cheats, change_date.been_used, SLE_BOOL), + SLE_VAR(Cheats, change_date.value, SLE_BOOL), + SLE_VAR(Cheats, setup_prod.been_used, SLE_BOOL), + SLE_VAR(Cheats, setup_prod.value, SLE_BOOL), + SLE_VAR(Cheats, edit_max_hl.been_used, SLE_BOOL), + SLE_VAR(Cheats, edit_max_hl.value, SLE_BOOL), +}; + + +struct CHTSChunkHandler : ChunkHandler { + CHTSChunkHandler() : ChunkHandler('CHTS', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_cheats_desc); + + SlSetArrayIndex(0); + SlObject(&_cheats, _cheats_desc); + } + + void Load() const override + { + std::vector slt = SlCompatTableHeader(_cheats_desc, _cheats_sl_compat); + + if (IsSavegameVersionBefore(SLV_TABLE_CHUNKS)) { + size_t count = SlGetFieldLength(); + std::vector oslt; + + /* Cheats were added over the years without a savegame bump. They are + * stored as 2 SLE_BOOLs per entry. "count" indicates how many SLE_BOOLs + * are stored for this savegame. So read only "count" SLE_BOOLs (and in + * result "count / 2" cheats). */ + for (auto &sld : slt) { + count--; + oslt.push_back(sld); + + if (count == 0) break; + } + slt = oslt; + } + + if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() == -1) return; + SlObject(&_cheats, slt); + if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many CHTS entries"); + } +}; + +static const CHTSChunkHandler CHTS; +static const ChunkHandlerRef cheat_chunk_handlers[] = { + CHTS, +}; + +extern const ChunkHandlerTable _cheat_chunk_handlers(cheat_chunk_handlers); + +} diff --git a/src/saveload/upstream/company_sl.cpp b/src/saveload/upstream/company_sl.cpp new file mode 100644 index 0000000000..e1d64084c0 --- /dev/null +++ b/src/saveload/upstream/company_sl.cpp @@ -0,0 +1,363 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file company_sl.cpp Code handling saving and loading of company data */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "compat/company_sl_compat.h" + +#include "../../company_func.h" +#include "../../company_manager_face.h" +#include "../../fios.h" +#include "../../tunnelbridge_map.h" +#include "../../tunnelbridge.h" +#include "../../station_base.h" +#include "../../strings_func.h" + +#include "table/strings.h" + +#include "../../safeguards.h" + +void SetDefaultCompanySettings(CompanyID cid); + +namespace upstream_sl { + +/* 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[] = {{}}; // Needed to keep DefaultSaveLoadHandler happy. + inline const static SaveLoadCompatTable compat_description = _company_old_ai_buildrec_compat; + + SaveLoadTable GetDescription() const override { return {}; } + + void Load(CompanyOldAI *old_ai) const override + { + for (int i = 0; i != old_ai->num_build_rec; i++) { + SlObject(nullptr, this->GetLoadDescription()); + } + } + + void LoadCheck(CompanyOldAI *old_ai) const override { this->Load(old_ai); } +}; + +class SlCompanyOldAI : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_CONDVAR(CompanyOldAI, num_build_rec, SLE_UINT8, SL_MIN_VERSION, SLV_107), + SLEG_STRUCTLIST("buildrec", SlCompanyOldAIBuildRec), + }; + inline const static SaveLoadCompatTable compat_description = _company_old_ai_compat; + + void Load(CompanyProperties *c) const override + { + if (!c->is_ai) return; + + CompanyOldAI old_ai; + SlObject(&old_ai, this->GetLoadDescription()); + } + + void LoadCheck(CompanyProperties *c) const override { this->Load(c); } +}; + +class SlCompanySettings : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + /* Engine renewal settings */ + 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), + }; + inline const static SaveLoadCompatTable compat_description = _company_settings_compat; + + void Save(CompanyProperties *c) const override + { + SlObject(c, this->GetDescription()); + } + + void Load(CompanyProperties *c) const override + { + SlObject(c, this->GetLoadDescription()); + } + + void FixPointers(CompanyProperties *c) const override + { + SlObject(c, this->GetDescription()); + } + + void LoadCheck(CompanyProperties *c) const override { this->Load(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), + }; + inline const static SaveLoadCompatTable compat_description = _company_economy_compat; + + void Save(CompanyProperties *c) const override + { + SlObject(&c->cur_economy, this->GetDescription()); + } + + void Load(CompanyProperties *c) const override + { + SlObject(&c->cur_economy, this->GetLoadDescription()); + } + + void FixPointers(CompanyProperties *c) const override + { + SlObject(&c->cur_economy, this->GetDescription()); + } + + void LoadCheck(CompanyProperties *c) const override { this->Load(c); } +}; + +class SlCompanyOldEconomy : public SlCompanyEconomy { +public: + void Save(CompanyProperties *c) const override + { + SlSetStructListLength(c->num_valid_stat_ent); + for (int i = 0; i < c->num_valid_stat_ent; i++) { + SlObject(&c->old_economy[i], this->GetDescription()); + } + } + + void Load(CompanyProperties *c) const override + { + if (!IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) { + c->num_valid_stat_ent = (uint8)SlGetStructListLength(UINT8_MAX); + } + if (c->num_valid_stat_ent > lengthof(c->old_economy)) SlErrorCorrupt("Too many old economy entries"); + + for (int i = 0; i < c->num_valid_stat_ent; i++) { + SlObject(&c->old_economy[i], this->GetLoadDescription()); + } + } + + void LoadCheck(CompanyProperties *c) const override { this->Load(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), + }; + inline const static SaveLoadCompatTable compat_description = _company_liveries_compat; + + /** + * Get the number of liveries used by this savegame version. + * @return The number of liveries used by this savegame version. + */ + size_t GetNumLiveries() const + { + if (IsSavegameVersionBefore(SLV_63)) return LS_END - 4; + if (IsSavegameVersionBefore(SLV_85)) return LS_END - 2; + if (IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) return LS_END; + /* Read from the savegame how long the list is. */ + return SlGetStructListLength(LS_END); + } + + void Save(CompanyProperties *c) const override + { + SlSetStructListLength(LS_END); + for (int i = 0; i < LS_END; i++) { + SlObject(&c->livery[i], this->GetDescription()); + } + } + + void Load(CompanyProperties *c) const override + { + size_t num_liveries = this->GetNumLiveries(); + bool update_in_use = IsSavegameVersionBefore(SLV_GROUP_LIVERIES); + + for (size_t i = 0; i < num_liveries; i++) { + SlObject(&c->livery[i], this->GetLoadDescription()); + 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 (IsSavegameVersionBefore(SLV_85)) { + /* 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 (IsSavegameVersionBefore(SLV_63)) { + /* 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 LoadCheck(CompanyProperties *c) const override { this->Load(c); } +}; + +/* Save/load of companies */ +static const SaveLoad _company_desc[] = { + SLE_VAR(CompanyProperties, name_2, SLE_UINT32), + SLE_VAR(CompanyProperties, name_1, SLE_STRINGID), + SLE_CONDSSTR(CompanyProperties, name, SLE_STR | SLF_ALLOW_CONTROL, SLV_84, SL_MAX_VERSION), + + SLE_VAR(CompanyProperties, president_name_1, SLE_STRINGID), + SLE_VAR(CompanyProperties, president_name_2, SLE_UINT32), + SLE_CONDSSTR(CompanyProperties, president_name, SLE_STR | SLF_ALLOW_CONTROL, SLV_84, SL_MAX_VERSION), + + SLE_VAR(CompanyProperties, face, SLE_UINT32), + + /* money was changed to a 64 bit field in savegame version 1. */ + SLE_CONDVAR(CompanyProperties, money, SLE_VAR_I64 | SLE_FILE_I32, SL_MIN_VERSION, SLV_1), + SLE_CONDVAR(CompanyProperties, money, SLE_INT64, SLV_1, SL_MAX_VERSION), + + SLE_CONDVAR(CompanyProperties, current_loan, SLE_VAR_I64 | SLE_FILE_I32, SL_MIN_VERSION, SLV_65), + SLE_CONDVAR(CompanyProperties, current_loan, SLE_INT64, SLV_65, SL_MAX_VERSION), + + SLE_VAR(CompanyProperties, colour, SLE_UINT8), + SLE_VAR(CompanyProperties, money_fraction, SLE_UINT8), + SLE_VAR(CompanyProperties, block_preview, SLE_UINT8), + + SLE_CONDVAR(CompanyProperties, location_of_HQ, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), + SLE_CONDVAR(CompanyProperties, location_of_HQ, SLE_UINT32, SLV_6, SL_MAX_VERSION), + SLE_CONDVAR(CompanyProperties, last_build_coordinate, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), + SLE_CONDVAR(CompanyProperties, last_build_coordinate, SLE_UINT32, SLV_6, SL_MAX_VERSION), + SLE_CONDVAR(CompanyProperties, inaugurated_year, SLE_FILE_U8 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31), + SLE_CONDVAR(CompanyProperties, inaugurated_year, SLE_INT32, SLV_31, SL_MAX_VERSION), + + SLE_ARR(CompanyProperties, share_owners, SLE_UINT8, 4), + + SLE_CONDVAR(CompanyProperties, num_valid_stat_ent, SLE_UINT8, SL_MIN_VERSION, SLV_SAVELOAD_LIST_LENGTH), + + SLE_VAR(CompanyProperties, months_of_bankruptcy, SLE_UINT8), + SLE_CONDVAR(CompanyProperties, bankrupt_asked, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_104), + SLE_CONDVAR(CompanyProperties, bankrupt_asked, SLE_UINT16, SLV_104, SL_MAX_VERSION), + SLE_VAR(CompanyProperties, bankrupt_timeout, SLE_INT16), + SLE_CONDVAR(CompanyProperties, bankrupt_value, SLE_VAR_I64 | SLE_FILE_I32, SL_MIN_VERSION, SLV_65), + SLE_CONDVAR(CompanyProperties, bankrupt_value, SLE_INT64, SLV_65, SL_MAX_VERSION), + + /* yearly expenses was changed to 64-bit in savegame version 2. */ + SLE_CONDARR(CompanyProperties, yearly_expenses, SLE_FILE_I32 | SLE_VAR_I64, 3 * 13, SL_MIN_VERSION, SLV_2), + SLE_CONDARR(CompanyProperties, yearly_expenses, SLE_INT64, 3 * 13, SLV_2, SL_MAX_VERSION), + + SLE_CONDVAR(CompanyProperties, is_ai, SLE_BOOL, SLV_2, SL_MAX_VERSION), + + 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("settings", SlCompanySettings), + SLEG_CONDSTRUCT("old_ai", SlCompanyOldAI, SL_MIN_VERSION, SLV_107), + SLEG_STRUCT("cur_economy", SlCompanyEconomy), + SLEG_STRUCTLIST("old_economy", SlCompanyOldEconomy), + SLEG_CONDSTRUCTLIST("liveries", SlCompanyLiveries, SLV_34, SL_MAX_VERSION), +}; + +struct PLYRChunkHandler : ChunkHandler { + PLYRChunkHandler() : ChunkHandler('PLYR', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_company_desc); + + for (Company *c : Company::Iterate()) { + SlSetArrayIndex(c->index); + SlObject(c, _company_desc); + } + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_company_desc, _company_sl_compat); + + int index; + while ((index = SlIterateArray()) != -1) { + Company *c = new (index) Company(); + SetDefaultCompanySettings(c->index); + SlObject((CompanyProperties *)c, slt); + _company_colours[index] = (Colours)c->colour; + } + } + + + void LoadCheck(size_t) const override + { + const std::vector slt = SlCompatTableHeader(_company_desc, _company_sl_compat); + + int index; + while ((index = SlIterateArray()) != -1) { + CompanyProperties *cprops = new CompanyProperties(); + SlObject(cprops, slt); + + /* We do not load old custom names */ + if (IsSavegameVersionBefore(SLV_84)) { + if (GetStringTab(cprops->name_1) == TEXT_TAB_OLD_CUSTOM) { + cprops->name_1 = STR_GAME_SAVELOAD_NOT_AVAILABLE; + } + + if (GetStringTab(cprops->president_name_1) == TEXT_TAB_OLD_CUSTOM) { + cprops->president_name_1 = STR_GAME_SAVELOAD_NOT_AVAILABLE; + } + } + + if (cprops->name.empty() && !IsInsideMM(cprops->name_1, SPECSTR_COMPANY_NAME_START, SPECSTR_COMPANY_NAME_LAST + 1) && + cprops->name_1 != STR_GAME_SAVELOAD_NOT_AVAILABLE && cprops->name_1 != STR_SV_UNNAMED && + cprops->name_1 != SPECSTR_ANDCO_NAME && cprops->name_1 != SPECSTR_PRESIDENT_NAME && + cprops->name_1 != SPECSTR_SILLY_NAME) { + cprops->name_1 = STR_GAME_SAVELOAD_NOT_AVAILABLE; + } + + if (!_load_check_data.companies.Insert(index, cprops)) delete cprops; + } + } + + void FixPointers() const override + { + for (Company *c : Company::Iterate()) { + SlObject((CompanyProperties *)c, _company_desc); + } + } +}; + +static const PLYRChunkHandler PLYR; +static const ChunkHandlerRef company_chunk_handlers[] = { + PLYR, +}; + +extern const ChunkHandlerTable _company_chunk_handlers(company_chunk_handlers); + +} diff --git a/src/saveload/upstream/compat/CMakeLists.txt b/src/saveload/upstream/compat/CMakeLists.txt new file mode 100644 index 0000000000..dc7c57e5c8 --- /dev/null +++ b/src/saveload/upstream/compat/CMakeLists.txt @@ -0,0 +1,29 @@ +add_files( + ai_sl_compat.h + autoreplace_sl_compat.h + cargomonitor_sl_compat.h + cargopacket_sl_compat.h + cheat_sl_compat.h + company_sl_compat.h + depot_sl_compat.h + economy_sl_compat.h + engine_sl_compat.h + game_sl_compat.h + goal_sl_compat.h + group_sl_compat.h + industry_sl_compat.h + labelmaps_sl_compat.h + map_sl_compat.h + misc_sl_compat.h + newgrf_sl_compat.h + object_sl_compat.h + order_sl_compat.h + settings_sl_compat.h + signs_sl_compat.h + station_sl_compat.h + storage_sl_compat.h + story_sl_compat.h + subsidy_sl_compat.h + town_sl_compat.h + vehicle_sl_compat.h +) diff --git a/src/saveload/upstream/compat/ai_sl_compat.h b/src/saveload/upstream/compat/ai_sl_compat.h new file mode 100644 index 0000000000..24ed3a1a8e --- /dev/null +++ b/src/saveload/upstream/compat/ai_sl_compat.h @@ -0,0 +1,27 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file ai_sl_compat.h Loading for ai chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_AI_H +#define SAVELOAD_COMPAT_AI_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for _ai_company_desc. */ +const SaveLoadCompat _ai_company_sl_compat[] = { + SLC_VAR("name"), + SLC_VAR("settings"), + SLC_VAR("version"), + SLC_VAR("is_random"), +}; + +} + +#endif /* SAVELOAD_COMPAT_AI_H */ diff --git a/src/saveload/upstream/compat/animated_tile_sl_compat.h b/src/saveload/upstream/compat/animated_tile_sl_compat.h new file mode 100644 index 0000000000..4d1c2b1e22 --- /dev/null +++ b/src/saveload/upstream/compat/animated_tile_sl_compat.h @@ -0,0 +1,24 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file animated_tile_sl_compat.h Loading for animated_tile chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_ANIMATED_TILE_H +#define SAVELOAD_COMPAT_ANIMATED_TILE_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for _animated_tile_desc. */ +const SaveLoadCompat _animated_tile_sl_compat[] = { + SLC_VAR("tiles"), +}; + +} + +#endif /* SAVELOAD_COMPAT_ANIMATED_TILE_H */ diff --git a/src/saveload/upstream/compat/autoreplace_sl_compat.h b/src/saveload/upstream/compat/autoreplace_sl_compat.h new file mode 100644 index 0000000000..07b3236c9c --- /dev/null +++ b/src/saveload/upstream/compat/autoreplace_sl_compat.h @@ -0,0 +1,28 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file autoreplace_sl_compat.h Loading for autoreplace chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_AUTOREPLACE_H +#define SAVELOAD_COMPAT_AUTOREPLACE_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for _engine_renew_desc. */ +const SaveLoadCompat _engine_renew_sl_compat[] = { + SLC_VAR("from"), + SLC_VAR("to"), + SLC_VAR("next"), + SLC_VAR("group_id"), + SLC_VAR("replace_when_old"), +}; + +} + +#endif /* SAVELOAD_COMPAT_AUTOREPLACE_H */ diff --git a/src/saveload/upstream/compat/cargomonitor_sl_compat.h b/src/saveload/upstream/compat/cargomonitor_sl_compat.h new file mode 100644 index 0000000000..798541a100 --- /dev/null +++ b/src/saveload/upstream/compat/cargomonitor_sl_compat.h @@ -0,0 +1,25 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file cargomonitor_sl_compat.h Loading for cargomonitor chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_CARGOMONITOR_H +#define SAVELOAD_COMPAT_CARGOMONITOR_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for _cargomonitor_pair_desc. */ +const SaveLoadCompat _cargomonitor_pair_sl_compat[] = { + SLC_VAR("number"), + SLC_VAR("amount"), +}; + +} + +#endif /* SAVELOAD_COMPAT_CARGOMONITOR_H */ diff --git a/src/saveload/upstream/compat/cargopacket_sl_compat.h b/src/saveload/upstream/compat/cargopacket_sl_compat.h new file mode 100644 index 0000000000..1d98b2b4e3 --- /dev/null +++ b/src/saveload/upstream/compat/cargopacket_sl_compat.h @@ -0,0 +1,32 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file cargopacket_sl_compat.h Loading for cargopacket chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_CARGOPACKET_H +#define SAVELOAD_COMPAT_CARGOPACKET_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for _cargopacket_desc. */ +const SaveLoadCompat _cargopacket_sl_compat[] = { + SLC_VAR("source"), + SLC_VAR("source_xy"), + SLC_VAR("loaded_at_xy"), + SLC_VAR("count"), + SLC_VAR("days_in_transit"), + SLC_VAR("feeder_share"), + SLC_VAR("source_type"), + SLC_VAR("source_id"), + SLC_NULL(1, SL_MIN_VERSION, SLV_121), +}; + +} + +#endif /* SAVELOAD_COMPAT_CARGOPACKET_H */ diff --git a/src/saveload/upstream/compat/cheat_sl_compat.h b/src/saveload/upstream/compat/cheat_sl_compat.h new file mode 100644 index 0000000000..62069214bd --- /dev/null +++ b/src/saveload/upstream/compat/cheat_sl_compat.h @@ -0,0 +1,45 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file cheat_sl_compat.h Loading for cheat chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_CHEAT_H +#define SAVELOAD_COMPAT_CHEAT_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for _cheats_desc. */ +const SaveLoadCompat _cheats_sl_compat[] = { + SLC_VAR("magic_bulldozer.been_used"), + SLC_VAR("magic_bulldozer.value"), + SLC_VAR("switch_company.been_used"), + SLC_VAR("switch_company.value"), + SLC_VAR("money.been_used"), + SLC_VAR("money.value"), + SLC_VAR("crossing_tunnels.been_used"), + SLC_VAR("crossing_tunnels.value"), + SLC_NULL(1, SL_MIN_VERSION, SLV_TABLE_CHUNKS), + SLC_NULL(1, SL_MIN_VERSION, SLV_TABLE_CHUNKS), // Need to be two NULL fields. See Load_CHTS(). + SLC_VAR("no_jetcrash.been_used"), + SLC_VAR("no_jetcrash.value"), + SLC_NULL(1, SL_MIN_VERSION, SLV_TABLE_CHUNKS), + SLC_NULL(1, SL_MIN_VERSION, SLV_TABLE_CHUNKS), // Need to be two NULL fields. See Load_CHTS(). + SLC_VAR("change_date.been_used"), + SLC_VAR("change_date.value"), + SLC_VAR("setup_prod.been_used"), + SLC_VAR("setup_prod.value"), + SLC_NULL(1, SL_MIN_VERSION, SLV_TABLE_CHUNKS), + SLC_NULL(1, SL_MIN_VERSION, SLV_TABLE_CHUNKS), // Need to be two NULL fields. See Load_CHTS(). + SLC_VAR("edit_max_hl.been_used"), + SLC_VAR("edit_max_hl.value"), +}; + +} + +#endif /* SAVELOAD_COMPAT_CHEAT_H */ diff --git a/src/saveload/upstream/compat/company_sl_compat.h b/src/saveload/upstream/compat/company_sl_compat.h new file mode 100644 index 0000000000..011ebeea7f --- /dev/null +++ b/src/saveload/upstream/compat/company_sl_compat.h @@ -0,0 +1,133 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file company_sl_compat.h Loading of company chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_COMPANY_H +#define SAVELOAD_COMPAT_COMPANY_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for SlCompanyOldAIBuildRec. */ +const SaveLoadCompat _company_old_ai_buildrec_compat[] = { + SLC_NULL(2, SL_MIN_VERSION, SLV_6), + SLC_NULL(4, SLV_6, SLV_107), + SLC_NULL(2, SL_MIN_VERSION, SLV_6), + SLC_NULL(4, SLV_6, SLV_107), + SLC_NULL(8, SL_MIN_VERSION, SLV_107), +}; + +/** Original field order for SlCompanyOldAI. */ +const SaveLoadCompat _company_old_ai_compat[] = { + SLC_NULL(2, SL_MIN_VERSION, SLV_107), + SLC_NULL(2, SL_MIN_VERSION, SLV_13), + SLC_NULL(4, SLV_13, SLV_107), + SLC_NULL(8, SL_MIN_VERSION, SLV_107), + SLC_VAR("num_build_rec"), + SLC_NULL(3, SL_MIN_VERSION, SLV_107), + + SLC_NULL(2, SL_MIN_VERSION, SLV_6), + SLC_NULL(4, SLV_6, SLV_107), + SLC_NULL(2, SL_MIN_VERSION, SLV_6), + SLC_NULL(4, SLV_6, SLV_107), + SLC_NULL(2, SL_MIN_VERSION, SLV_107), + + SLC_NULL(2, SL_MIN_VERSION, SLV_6), + SLC_NULL(4, SLV_6, SLV_107), + SLC_NULL(2, SL_MIN_VERSION, SLV_6), + SLC_NULL(4, SLV_6, SLV_107), + SLC_NULL(2, SL_MIN_VERSION, SLV_107), + + SLC_NULL(2, SL_MIN_VERSION, SLV_69), + SLC_NULL(4, SLV_69, SLV_107), + + SLC_NULL(18, SL_MIN_VERSION, SLV_107), + SLC_NULL(20, SL_MIN_VERSION, SLV_107), + SLC_NULL(32, SL_MIN_VERSION, SLV_107), + + SLC_NULL(64, SLV_2, SLV_107), + SLC_VAR("buildrec"), +}; + +/** Original field order for SlCompanySettings. */ +const SaveLoadCompat _company_settings_compat[] = { + SLC_NULL(512, SLV_16, SLV_19), + SLC_VAR("engine_renew_list"), + SLC_VAR("settings.engine_renew"), + SLC_VAR("settings.engine_renew_months"), + SLC_VAR("settings.engine_renew_money"), + SLC_VAR("settings.renew_keep_length"), + SLC_VAR("settings.vehicle.servint_ispercent"), + SLC_VAR("settings.vehicle.servint_trains"), + SLC_VAR("settings.vehicle.servint_roadveh"), + SLC_VAR("settings.vehicle.servint_aircraft"), + SLC_VAR("settings.vehicle.servint_ships"), + SLC_NULL(63, SLV_2, SLV_144), +}; + +/** Original field order for SlCompanyEconomy. */ +const SaveLoadCompat _company_economy_compat[] = { + SLC_VAR("income"), + SLC_VAR("expenses"), + SLC_VAR("company_value"), + SLC_VAR("delivered_cargo[NUM_CARGO - 1]"), + SLC_VAR("delivered_cargo"), + SLC_VAR("performance_history"), +}; + +/** Original field order for SlCompanyLiveries. */ +const SaveLoadCompat _company_liveries_compat[] = { + SLC_VAR("in_use"), + SLC_VAR("colour1"), + SLC_VAR("colour2"), +}; + +/** Original field order for company_desc. */ +const SaveLoadCompat _company_sl_compat[] = { + SLC_VAR("name_2"), + SLC_VAR("name_1"), + SLC_VAR("name"), + SLC_VAR("president_name_1"), + SLC_VAR("president_name_2"), + SLC_VAR("president_name"), + SLC_VAR("face"), + SLC_VAR("money"), + SLC_VAR("current_loan"), + SLC_VAR("colour"), + SLC_VAR("money_fraction"), + SLC_NULL(1, SL_MIN_VERSION, SLV_58), + SLC_VAR("block_preview"), + SLC_NULL(2, SL_MIN_VERSION, SLV_94), + SLC_NULL(4, SLV_94, SLV_170), + SLC_VAR("location_of_HQ"), + SLC_VAR("last_build_coordinate"), + SLC_VAR("inaugurated_year"), + SLC_VAR("share_owners"), + SLC_VAR("num_valid_stat_ent"), + SLC_VAR("months_of_bankruptcy"), + SLC_VAR("bankrupt_asked"), + SLC_VAR("bankrupt_timeout"), + SLC_VAR("bankrupt_value"), + SLC_VAR("yearly_expenses"), + SLC_VAR("is_ai"), + SLC_NULL(1, SLV_107, SLV_112), + SLC_NULL(1, SLV_4, SLV_100), + SLC_VAR("terraform_limit"), + SLC_VAR("clear_limit"), + SLC_VAR("tree_limit"), + SLC_VAR("settings"), + SLC_VAR("old_ai"), + SLC_VAR("cur_economy"), + SLC_VAR("old_economy"), + SLC_VAR("liveries"), +}; + +} + +#endif /* SAVELOAD_COMPAT_COMPANY_H */ diff --git a/src/saveload/upstream/compat/depot_sl_compat.h b/src/saveload/upstream/compat/depot_sl_compat.h new file mode 100644 index 0000000000..68f370b5c6 --- /dev/null +++ b/src/saveload/upstream/compat/depot_sl_compat.h @@ -0,0 +1,29 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file depot_sl_compat.h Loading for depot chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_DEPOT_H +#define SAVELOAD_COMPAT_DEPOT_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for _depot_desc. */ +const SaveLoadCompat _depot_sl_compat[] = { + SLC_VAR("xy"), + SLC_VAR("town_index"), + SLC_VAR("town"), + SLC_VAR("town_cn"), + SLC_VAR("name"), + SLC_VAR("build_date"), +}; + +} + +#endif /* SAVELOAD_COMPAT_DEPOT_H */ diff --git a/src/saveload/upstream/compat/economy_sl_compat.h b/src/saveload/upstream/compat/economy_sl_compat.h new file mode 100644 index 0000000000..88b04ecb6f --- /dev/null +++ b/src/saveload/upstream/compat/economy_sl_compat.h @@ -0,0 +1,42 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file economy_sl_compat.h Loading for economy chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_ECONOMY_H +#define SAVELOAD_COMPAT_ECONOMY_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for _economy_desc. */ +const SaveLoadCompat _economy_sl_compat[] = { + SLC_NULL(4, SL_MIN_VERSION, SLV_65), + SLC_NULL(8, SLV_65, SLV_144), + SLC_VAR("old_max_loan_unround"), + SLC_VAR("old_max_loan_unround_fract"), + SLC_VAR("inflation_prices"), + SLC_VAR("inflation_payment"), + SLC_VAR("fluct"), + SLC_VAR("interest_rate"), + SLC_VAR("infl_amount"), + SLC_VAR("infl_amount_pr"), + SLC_VAR("industry_daily_change_counter"), +}; + +/** Original field order for _cargopayment_desc. */ +const SaveLoadCompat _cargopayment_sl_compat[] = { + SLC_VAR("front"), + SLC_VAR("route_profit"), + SLC_VAR("visual_profit"), + SLC_VAR("visual_transfer"), +}; + +} + +#endif /* SAVELOAD_COMPAT_ECONOMY_H */ diff --git a/src/saveload/upstream/compat/engine_sl_compat.h b/src/saveload/upstream/compat/engine_sl_compat.h new file mode 100644 index 0000000000..23344850c7 --- /dev/null +++ b/src/saveload/upstream/compat/engine_sl_compat.h @@ -0,0 +1,52 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file engine_sl_compat.h Loading for engine chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_ENGINE_H +#define SAVELOAD_COMPAT_ENGINE_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for _engine_desc. */ +const SaveLoadCompat _engine_sl_compat[] = { + SLC_VAR("intro_date"), + SLC_VAR("age"), + SLC_VAR("reliability"), + SLC_VAR("reliability_spd_dec"), + SLC_VAR("reliability_start"), + SLC_VAR("reliability_max"), + SLC_VAR("reliability_final"), + SLC_VAR("duration_phase_1"), + SLC_VAR("duration_phase_2"), + SLC_VAR("duration_phase_3"), + SLC_NULL(1, SL_MIN_VERSION, SLV_121), + SLC_VAR("flags"), + SLC_NULL(1, SL_MIN_VERSION, SLV_179), + SLC_VAR("preview_asked"), + SLC_VAR("preview_company"), + SLC_VAR("preview_wait"), + SLC_NULL(1, SL_MIN_VERSION, SLV_45), + SLC_VAR("company_avail"), + SLC_VAR("company_hidden"), + SLC_VAR("name"), + SLC_NULL(16, SLV_2, SLV_144), +}; + +/** Original field order for _engine_id_mapping_desc. */ +const SaveLoadCompat _engine_id_mapping_sl_compat[] = { + SLC_VAR("grfid"), + SLC_VAR("internal_id"), + SLC_VAR("type"), + SLC_VAR("substitute_id"), +}; + +} + +#endif /* SAVELOAD_COMPAT_ENGINE_H */ diff --git a/src/saveload/upstream/compat/game_sl_compat.h b/src/saveload/upstream/compat/game_sl_compat.h new file mode 100644 index 0000000000..52dd071779 --- /dev/null +++ b/src/saveload/upstream/compat/game_sl_compat.h @@ -0,0 +1,39 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file game_sl_compat.h Loading for game chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_GAME_H +#define SAVELOAD_COMPAT_GAME_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for _game_script_desc. */ +const SaveLoadCompat _game_script_sl_compat[] = { + SLC_VAR("name"), + SLC_VAR("settings"), + SLC_VAR("version"), + SLC_VAR("is_random"), +}; + +/** Original field order for SlGameLanguageString. */ +const SaveLoadCompat _game_language_string_sl_compat[] = { + SLC_VAR("string"), +}; + +/** Original field order for _game_language_desc. */ +const SaveLoadCompat _game_language_sl_compat[] = { + SLC_VAR("language"), + SLC_VAR("count"), + SLC_VAR("strings"), +}; + +} + +#endif /* SAVELOAD_COMPAT_GAME_H */ diff --git a/src/saveload/upstream/compat/gamelog_sl_compat.h b/src/saveload/upstream/compat/gamelog_sl_compat.h new file mode 100644 index 0000000000..d3b3fc77ed --- /dev/null +++ b/src/saveload/upstream/compat/gamelog_sl_compat.h @@ -0,0 +1,109 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file gamelog_sl_compat.h Loading for gamelog chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_GAMELOG_H +#define SAVELOAD_COMPAT_GAMELOG_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for SlGamelogMode. */ +const SaveLoadCompat _gamelog_mode_sl_compat[] = { + SLC_VAR("mode.mode"), + SLC_VAR("mode.landscape"), +}; + +/** Original field order for SlGamelogRevision. */ +const SaveLoadCompat _gamelog_revision_sl_compat[] = { + SLC_VAR("revision.text"), + SLC_VAR("revision.newgrf"), + SLC_VAR("revision.slver"), + SLC_VAR("revision.modified"), +}; + +/** Original field order for SlGamelogOldver. */ +const SaveLoadCompat _gamelog_oldver_sl_compat[] = { + SLC_VAR("oldver.type"), + SLC_VAR("oldver.version"), +}; + +/** Original field order for SlGamelogSetting. */ +const SaveLoadCompat _gamelog_setting_sl_compat[] = { + SLC_VAR("setting.name"), + SLC_VAR("setting.oldval"), + SLC_VAR("setting.newval"), +}; + +/** Original field order for SlGamelogGrfadd. */ +const SaveLoadCompat _gamelog_grfadd_sl_compat[] = { + SLC_VAR("grfadd.grfid"), + SLC_VAR("grfadd.md5sum"), +}; + +/** Original field order for SlGamelogGrfrem. */ +const SaveLoadCompat _gamelog_grfrem_sl_compat[] = { + SLC_VAR("grfrem.grfid"), +}; + +/** Original field order for SlGamelogGrfcompat. */ +const SaveLoadCompat _gamelog_grfcompat_sl_compat[] = { + SLC_VAR("grfcompat.grfid"), + SLC_VAR("grfcompat.md5sum"), +}; + +/** Original field order for SlGamelogGrfparam. */ +const SaveLoadCompat _gamelog_grfparam_sl_compat[] = { + SLC_VAR("grfparam.grfid"), +}; + +/** Original field order for SlGamelogGrfmove. */ +const SaveLoadCompat _gamelog_grfmove_sl_compat[] = { + SLC_VAR("grfmove.grfid"), + SLC_VAR("grfmove.offset"), +}; + +/** Original field order for SlGamelogGrfbug. */ +const SaveLoadCompat _gamelog_grfbug_sl_compat[] = { + SLC_VAR("grfbug.data"), + SLC_VAR("grfbug.grfid"), + SLC_VAR("grfbug.bug"), +}; + +/** Original field order for SlGamelogEmergency. */ +const SaveLoadCompat _gamelog_emergency_sl_compat[] = { + SLC_VAR("is_emergency_save"), +}; + +/** Original field order for SlGamelogAction. */ +const SaveLoadCompat _gamelog_action_sl_compat[] = { + SLC_VAR("ct"), + SLC_VAR("mode"), + SLC_VAR("revision"), + SLC_VAR("oldver"), + SLC_VAR("setting"), + SLC_VAR("grfadd"), + SLC_VAR("grfrem"), + SLC_VAR("grfcompat"), + SLC_VAR("grfparam"), + SLC_VAR("grfmove"), + SLC_VAR("grfbug"), + SLC_VAR("emergency"), +}; + +/** Original field order for _gamelog_desc. */ +const SaveLoadCompat _gamelog_sl_compat[] = { + SLC_VAR("at"), + SLC_VAR("tick"), + SLC_VAR("action"), +}; + +} + +#endif /* SAVELOAD_COMPAT_GAMELOG_H */ diff --git a/src/saveload/upstream/compat/goal_sl_compat.h b/src/saveload/upstream/compat/goal_sl_compat.h new file mode 100644 index 0000000000..d1d5a9198f --- /dev/null +++ b/src/saveload/upstream/compat/goal_sl_compat.h @@ -0,0 +1,29 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file goal_sl_compat.h Loading of goal chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_GOAL_H +#define SAVELOAD_COMPAT_GOAL_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for _goals_desc. */ +const SaveLoadCompat _goals_sl_compat[] = { + SLC_VAR("company"), + SLC_VAR("type"), + SLC_VAR("dst"), + SLC_VAR("text"), + SLC_VAR("progress"), + SLC_VAR("completed"), +}; + +} + +#endif /* SAVELOAD_COMPAT_GOAL_H */ diff --git a/src/saveload/upstream/compat/group_sl_compat.h b/src/saveload/upstream/compat/group_sl_compat.h new file mode 100644 index 0000000000..a6df8a46ca --- /dev/null +++ b/src/saveload/upstream/compat/group_sl_compat.h @@ -0,0 +1,32 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file group_sl_compat.h Loading of group chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_GROUP_H +#define SAVELOAD_COMPAT_GROUP_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for _group_desc. */ +const SaveLoadCompat _group_sl_compat[] = { + SLC_VAR("name"), + SLC_NULL(2, SL_MIN_VERSION, SLV_164), + SLC_VAR("owner"), + SLC_VAR("vehicle_type"), + SLC_VAR("flags"), + SLC_VAR("livery.in_use"), + SLC_VAR("livery.colour1"), + SLC_VAR("livery.colour2"), + SLC_VAR("parent"), +}; + +} + +#endif /* SAVELOAD_COMPAT_GROUP_H */ diff --git a/src/saveload/upstream/compat/industry_sl_compat.h b/src/saveload/upstream/compat/industry_sl_compat.h new file mode 100644 index 0000000000..e4a5cb387f --- /dev/null +++ b/src/saveload/upstream/compat/industry_sl_compat.h @@ -0,0 +1,76 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file industry_sl_compat.h Loading of industry chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_INDUSTRY_H +#define SAVELOAD_COMPAT_INDUSTRY_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for _industry_desc. */ +const SaveLoadCompat _industry_sl_compat[] = { + SLC_VAR("location.tile"), + SLC_VAR("location.w"), + SLC_VAR("location.h"), + SLC_VAR("town"), + SLC_VAR("neutral_station"), + SLC_NULL(2, SL_MIN_VERSION, SLV_61), + SLC_VAR("produced_cargo"), + SLC_VAR("incoming_cargo_waiting"), + SLC_VAR("produced_cargo_waiting"), + SLC_VAR("production_rate"), + SLC_NULL(3, SL_MIN_VERSION, SLV_61), + SLC_VAR("accepts_cargo"), + SLC_VAR("prod_level"), + SLC_VAR("this_month_production"), + SLC_VAR("this_month_transported"), + SLC_VAR("last_month_pct_transported"), + SLC_VAR("last_month_production"), + SLC_VAR("last_month_transported"), + SLC_VAR("counter"), + SLC_VAR("type"), + SLC_VAR("owner"), + SLC_VAR("random_colour"), + SLC_VAR("last_prod_year"), + SLC_VAR("was_cargo_delivered"), + SLC_VAR("ctlflags"), + SLC_VAR("founder"), + SLC_VAR("construction_date"), + SLC_VAR("construction_type"), + SLC_VAR("last_cargo_accepted_at[0]"), + SLC_VAR("last_cargo_accepted_at"), + SLC_VAR("selected_layout"), + SLC_VAR("exclusive_supplier"), + SLC_VAR("exclusive_consumer"), + SLC_VAR("storage"), + SLC_VAR("psa"), + SLC_NULL(1, SLV_82, SLV_197), + SLC_VAR("random"), + SLC_VAR("text"), + SLC_NULL(32, SLV_2, SLV_144), +}; + +/** Original field order for _industry_builder_desc. */ +const SaveLoadCompat _industry_builder_sl_compat[] = { + SLC_VAR("wanted_inds"), +}; + +/** Original field order for _industrytype_builder_desc. */ +const SaveLoadCompat _industrytype_builder_sl_compat[] = { + SLC_VAR("probability"), + SLC_VAR("min_number"), + SLC_VAR("target_count"), + SLC_VAR("max_wait"), + SLC_VAR("wait_count"), +}; + +} + +#endif /* SAVELOAD_COMPAT_INDUSTRY_H */ diff --git a/src/saveload/upstream/compat/labelmaps_sl_compat.h b/src/saveload/upstream/compat/labelmaps_sl_compat.h new file mode 100644 index 0000000000..9be0df54a5 --- /dev/null +++ b/src/saveload/upstream/compat/labelmaps_sl_compat.h @@ -0,0 +1,24 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file labelmaps_sl_compat.h Loading of labelmaps chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_LABELMAPS_H +#define SAVELOAD_COMPAT_LABELMAPS_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for _label_object_desc. */ +const SaveLoadCompat _label_object_sl_compat[] = { + SLC_VAR("label"), +}; + +} + +#endif /* SAVELOAD_COMPAT_LABELMAPS_H */ diff --git a/src/saveload/upstream/compat/linkgraph_sl_compat.h b/src/saveload/upstream/compat/linkgraph_sl_compat.h new file mode 100644 index 0000000000..429ca9dc07 --- /dev/null +++ b/src/saveload/upstream/compat/linkgraph_sl_compat.h @@ -0,0 +1,70 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file linkgraph_sl_compat.h Loading of linkgraph chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_LINKGRAPH_H +#define SAVELOAD_COMPAT_LINKGRAPH_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for SlLinkgraphEdge. */ +const SaveLoadCompat _linkgraph_edge_sl_compat[] = { + SLC_NULL(4, SL_MIN_VERSION, SLV_191), + SLC_VAR("capacity"), + SLC_VAR("usage"), + SLC_VAR("last_unrestricted_update"), + SLC_VAR("last_restricted_update"), + SLC_VAR("next_edge"), +}; + +/** Original field order for SlLinkgraphNode. */ +const SaveLoadCompat _linkgraph_node_sl_compat[] = { + SLC_VAR("xy"), + SLC_VAR("supply"), + SLC_VAR("demand"), + SLC_VAR("station"), + SLC_VAR("last_update"), + SLC_VAR("edges"), +}; + +/** Original field order for link_graph_desc. */ +const SaveLoadCompat _linkgraph_sl_compat[] = { + SLC_VAR("last_compression"), + SLC_VAR("num_nodes"), + SLC_VAR("cargo"), + SLC_VAR("nodes"), +}; + +/** Original field order for job_desc. */ +const SaveLoadCompat _linkgraph_job_sl_compat[] = { + SLC_VAR("linkgraph.recalc_interval"), + SLC_VAR("linkgraph.recalc_time"), + SLC_VAR("linkgraph.distribution_pax"), + SLC_VAR("linkgraph.distribution_mail"), + SLC_VAR("linkgraph.distribution_armoured"), + SLC_VAR("linkgraph.distribution_default"), + SLC_VAR("linkgraph.accuracy"), + SLC_VAR("linkgraph.demand_distance"), + SLC_VAR("linkgraph.demand_size"), + SLC_VAR("linkgraph.short_path_saturation"), + SLC_VAR("join_date"), + SLC_VAR("link_graph.index"), + SLC_VAR("linkgraph"), +}; + +/** Original field order for schedule_desc. */ +const SaveLoadCompat _linkgraph_schedule_sl_compat[] = { + SLC_VAR("schedule"), + SLC_VAR("running"), +}; + +} + +#endif /* SAVELOAD_COMPAT_LINKGRAPH_H */ diff --git a/src/saveload/upstream/compat/map_sl_compat.h b/src/saveload/upstream/compat/map_sl_compat.h new file mode 100644 index 0000000000..aa855868aa --- /dev/null +++ b/src/saveload/upstream/compat/map_sl_compat.h @@ -0,0 +1,25 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file map_sl_compat.h Loading for map chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_MAP_H +#define SAVELOAD_COMPAT_MAP_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for _map_desc. */ +const SaveLoadCompat _map_sl_compat[] = { + SLC_VAR("dim_x"), + SLC_VAR("dim_y"), +}; + +} + +#endif /* SAVELOAD_COMPAT_MAP_H */ diff --git a/src/saveload/upstream/compat/misc_sl_compat.h b/src/saveload/upstream/compat/misc_sl_compat.h new file mode 100644 index 0000000000..716969da4b --- /dev/null +++ b/src/saveload/upstream/compat/misc_sl_compat.h @@ -0,0 +1,72 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file misc_sl_compat.h Loading for misc chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_MISC_H +#define SAVELOAD_COMPAT_MISC_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for _date_desc. */ +const SaveLoadCompat _date_sl_compat[] = { + SLC_VAR("date"), + SLC_VAR("date_fract"), + SLC_VAR("tick_counter"), + SLC_NULL(2, SL_MIN_VERSION, SLV_157), + SLC_VAR("age_cargo_skip_counter"), + SLC_NULL(1, SL_MIN_VERSION, SLV_46), + SLC_VAR("cur_tileloop_tile"), + SLC_VAR("next_disaster_start"), + SLC_NULL(2, SL_MIN_VERSION, SLV_120), + SLC_VAR("random_state[0]"), + SLC_VAR("random_state[1]"), + SLC_NULL(1, SL_MIN_VERSION, SLV_10), + SLC_NULL(4, SLV_10, SLV_120), + SLC_VAR("company_tick_counter"), + SLC_VAR("next_competitor_start"), + SLC_VAR("trees_tick_counter"), + SLC_VAR("pause_mode"), + SLC_NULL(4, SLV_11, SLV_120), +}; + +/** Original field order for _date_check_desc. */ +const SaveLoadCompat _date_check_sl_compat[] = { + SLC_VAR("date"), + SLC_NULL(2, SL_MIN_VERSION, SL_MAX_VERSION), // date_fract + SLC_NULL(2, SL_MIN_VERSION, SL_MAX_VERSION), // tick_counter + SLC_NULL(2, SL_MIN_VERSION, SLV_157), + SLC_NULL(1, SL_MIN_VERSION, SLV_162), // age_cargo_skip_counter + SLC_NULL(1, SL_MIN_VERSION, SLV_46), + SLC_NULL(2, SL_MIN_VERSION, SLV_6), // cur_tileloop_tile + SLC_NULL(4, SLV_6, SL_MAX_VERSION), // cur_tileloop_tile + SLC_NULL(2, SL_MIN_VERSION, SL_MAX_VERSION), // disaster_delay + SLC_NULL(2, SL_MIN_VERSION, SLV_120), + SLC_NULL(4, SL_MIN_VERSION, SL_MAX_VERSION), // random.state[0] + SLC_NULL(4, SL_MIN_VERSION, SL_MAX_VERSION), // random.state[1] + SLC_NULL(1, SL_MIN_VERSION, SLV_10), + SLC_NULL(4, SLV_10, SLV_120), + SLC_NULL(1, SL_MIN_VERSION, SL_MAX_VERSION), // cur_company_tick_index + SLC_NULL(2, SL_MIN_VERSION, SLV_109), // next_competitor_start + SLC_NULL(4, SLV_109, SL_MAX_VERSION), // next_competitor_start + SLC_NULL(1, SL_MIN_VERSION, SL_MAX_VERSION), // trees_tick_ctr + SLC_NULL(1, SLV_4, SL_MAX_VERSION), // pause_mode + SLC_NULL(4, SLV_11, SLV_120), +}; + +/** Original field order for _view_desc. */ +const SaveLoadCompat _view_sl_compat[] = { + SLC_VAR("x"), + SLC_VAR("y"), + SLC_VAR("zoom"), +}; + +} + +#endif /* SAVELOAD_COMPAT_MISC_H */ diff --git a/src/saveload/upstream/compat/newgrf_sl_compat.h b/src/saveload/upstream/compat/newgrf_sl_compat.h new file mode 100644 index 0000000000..9fc8b75e16 --- /dev/null +++ b/src/saveload/upstream/compat/newgrf_sl_compat.h @@ -0,0 +1,37 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file newgrf_sl_compat.h Loading of newgrf chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_NEWGRF_H +#define SAVELOAD_COMPAT_NEWGRF_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for _newgrf_mapping_desc. */ +const SaveLoadCompat _newgrf_mapping_sl_compat[] = { + SLC_VAR("grfid"), + SLC_VAR("entity_id"), + SLC_VAR("substitute_id"), +}; + +/** Original field order for _newgrf_desc. */ +const SaveLoadCompat _grfconfig_sl_compat[] = { + SLC_VAR("filename"), + SLC_VAR("ident.grfid"), + SLC_VAR("ident.md5sum"), + SLC_VAR("version"), + SLC_VAR("param"), + SLC_VAR("num_params"), + SLC_VAR("palette"), +}; + +} + +#endif /* SAVELOAD_COMPAT_NEWGRF_H */ diff --git a/src/saveload/upstream/compat/object_sl_compat.h b/src/saveload/upstream/compat/object_sl_compat.h new file mode 100644 index 0000000000..79c2ba2ff9 --- /dev/null +++ b/src/saveload/upstream/compat/object_sl_compat.h @@ -0,0 +1,31 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file object_sl_compat.h Loading of object chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_OBJECT_H +#define SAVELOAD_COMPAT_OBJECT_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for _object_desc. */ +const SaveLoadCompat _object_sl_compat[] = { + SLC_VAR("location.tile"), + SLC_VAR("location.w"), + SLC_VAR("location.h"), + SLC_VAR("town"), + SLC_VAR("build_date"), + SLC_VAR("colour"), + SLC_VAR("view"), + SLC_VAR("type"), +}; + +} + +#endif /* SAVELOAD_COMPAT_OBJECT_H */ diff --git a/src/saveload/upstream/compat/order_sl_compat.h b/src/saveload/upstream/compat/order_sl_compat.h new file mode 100644 index 0000000000..c7a6ceceb5 --- /dev/null +++ b/src/saveload/upstream/compat/order_sl_compat.h @@ -0,0 +1,56 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file order_sl_compat.h Loading of order chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_ORDER_H +#define SAVELOAD_COMPAT_ORDER_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for _order_desc. */ +const SaveLoadCompat _order_sl_compat[] = { + SLC_VAR("type"), + SLC_VAR("flags"), + SLC_VAR("dest"), + SLC_VAR("next"), + SLC_VAR("refit_cargo"), + SLC_NULL(1, SLV_36, SLV_182), + SLC_VAR("wait_time"), + SLC_VAR("travel_time"), + SLC_VAR("max_speed"), + SLC_NULL(10, SLV_5, SLV_36), +}; + +/** Original field order for _orderlist_desc. */ +const SaveLoadCompat _orderlist_sl_compat[] = { + SLC_VAR("first"), +}; + +/** Original field order for _order_backup_desc. */ +const SaveLoadCompat _order_backup_sl_compat[] = { + SLC_VAR("user"), + SLC_VAR("tile"), + SLC_VAR("group"), + SLC_VAR("service_interval"), + SLC_VAR("name"), + SLC_NULL(2, SL_MIN_VERSION, SLV_192), + SLC_VAR("clone"), + SLC_VAR("cur_real_order_index"), + SLC_VAR("cur_implicit_order_index"), + SLC_VAR("current_order_time"), + SLC_VAR("lateness_counter"), + SLC_VAR("timetable_start"), + SLC_VAR("vehicle_flags"), + SLC_VAR("orders"), +}; + +} + +#endif /* SAVELOAD_COMPAT_ORDER_H */ diff --git a/src/saveload/upstream/compat/settings_sl_compat.h b/src/saveload/upstream/compat/settings_sl_compat.h new file mode 100644 index 0000000000..36b9976dfd --- /dev/null +++ b/src/saveload/upstream/compat/settings_sl_compat.h @@ -0,0 +1,270 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file settings_sl_compat.h Loading of settings chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_SETTINGS_H +#define SAVELOAD_COMPAT_SETTINGS_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for _gameopt. */ +const SaveLoadCompat _gameopt_sl_compat[] = { + SLC_VAR("diff_custom"), + SLC_VAR("diff_level"), + SLC_VAR("locale.currency"), + SLC_VAR("units"), + SLC_VAR("game_creation.town_name"), + SLC_VAR("game_creation.landscape"), + SLC_VAR("game_creation.snow_line_height"), + SLC_NULL(1, SLV_22, SLV_165), + SLC_NULL(1, SL_MIN_VERSION, SLV_23), + SLC_VAR("vehicle.road_side"), +}; + +/** Original field order for _settings. */ +const SaveLoadCompat _settings_sl_compat[] = { + SLC_VAR("difficulty.max_no_competitors"), + SLC_NULL(1, SLV_97, SLV_110), + SLC_VAR("difficulty.number_towns"), + SLC_VAR("difficulty.industry_density"), + SLC_VAR("difficulty.max_loan"), + SLC_VAR("difficulty.initial_interest"), + SLC_VAR("difficulty.vehicle_costs"), + SLC_VAR("difficulty.competitor_speed"), + SLC_NULL(1, SLV_97, SLV_110), + SLC_VAR("difficulty.vehicle_breakdowns"), + SLC_VAR("difficulty.subsidy_multiplier"), + SLC_VAR("difficulty.subsidy_duration"), + SLC_VAR("difficulty.construction_cost"), + SLC_VAR("difficulty.terrain_type"), + SLC_VAR("difficulty.quantity_sea_lakes"), + SLC_VAR("difficulty.economy"), + SLC_VAR("difficulty.line_reverse_mode"), + SLC_VAR("difficulty.disasters"), + SLC_VAR("difficulty.town_council_tolerance"), + SLC_VAR("diff_level"), + SLC_VAR("game_creation.town_name"), + SLC_VAR("game_creation.landscape"), + SLC_NULL(1, SLV_97, SLV_164), + SLC_VAR("vehicle.road_side"), + SLC_VAR("construction.map_height_limit"), + SLC_VAR("game_creation.heightmap_height"), + SLC_VAR("construction.build_on_slopes"), + SLC_VAR("construction.command_pause_level"), + SLC_VAR("construction.terraform_per_64k_frames"), + SLC_VAR("construction.terraform_frame_burst"), + SLC_VAR("construction.clear_per_64k_frames"), + SLC_VAR("construction.clear_frame_burst"), + SLC_VAR("construction.tree_per_64k_frames"), + SLC_VAR("construction.tree_frame_burst"), + SLC_VAR("construction.autoslope"), + SLC_VAR("construction.extra_dynamite"), + SLC_VAR("construction.max_bridge_length"), + SLC_VAR("construction.max_bridge_height"), + SLC_VAR("construction.max_tunnel_length"), + SLC_NULL(1, SL_MIN_VERSION, SLV_159), + SLC_VAR("construction.train_signal_side"), + SLC_VAR("station.never_expire_airports"), + SLC_VAR("economy.town_layout"), + SLC_VAR("economy.allow_town_roads"), + SLC_VAR("economy.found_town"), + SLC_VAR("economy.allow_town_level_crossings"), + SLC_VAR("economy.town_cargogen_mode"), + SLC_VAR("linkgraph.recalc_interval"), + SLC_VAR("linkgraph.recalc_time"), + SLC_VAR("linkgraph.distribution_pax"), + SLC_VAR("linkgraph.distribution_mail"), + SLC_VAR("linkgraph.distribution_armoured"), + SLC_VAR("linkgraph.distribution_default"), + SLC_VAR("linkgraph.accuracy"), + SLC_VAR("linkgraph.demand_distance"), + SLC_VAR("linkgraph.demand_size"), + SLC_VAR("linkgraph.short_path_saturation"), + SLC_VAR("vehicle.train_acceleration_model"), + SLC_VAR("vehicle.roadveh_acceleration_model"), + SLC_VAR("vehicle.train_slope_steepness"), + SLC_VAR("vehicle.roadveh_slope_steepness"), + SLC_VAR("pf.forbid_90_deg"), + SLC_VAR("vehicle.max_train_length"), + SLC_NULL(1, SL_MIN_VERSION, SLV_159), + SLC_VAR("vehicle.smoke_amount"), + SLC_NULL(1, SL_MIN_VERSION, SLV_159), + SLC_VAR("pf.roadveh_queue"), + SLC_VAR("pf.new_pathfinding_all"), + SLC_VAR("pf.yapf.ship_use_yapf"), + SLC_VAR("pf.yapf.road_use_yapf"), + SLC_VAR("pf.yapf.rail_use_yapf"), + SLC_VAR("pf.pathfinder_for_trains"), + SLC_VAR("pf.pathfinder_for_roadvehs"), + SLC_VAR("pf.pathfinder_for_ships"), + SLC_VAR("vehicle.never_expire_vehicles"), + SLC_VAR("vehicle.max_trains"), + SLC_VAR("vehicle.max_roadveh"), + SLC_VAR("vehicle.max_aircraft"), + SLC_VAR("vehicle.max_ships"), + SLC_VAR("vehicle.servint_ispercent"), + SLC_VAR("vehicle.servint_trains"), + SLC_VAR("vehicle.servint_roadveh"), + SLC_VAR("vehicle.servint_ships"), + SLC_VAR("vehicle.servint_aircraft"), + SLC_VAR("order.no_servicing_if_no_breakdowns"), + SLC_VAR("vehicle.wagon_speed_limits"), + SLC_VAR("vehicle.disable_elrails"), + SLC_VAR("vehicle.freight_trains"), + SLC_NULL(1, SLV_67, SLV_159), + SLC_VAR("vehicle.plane_speed"), + SLC_VAR("vehicle.dynamic_engines"), + SLC_VAR("vehicle.plane_crashes"), + SLC_NULL(1, SL_MIN_VERSION, SLV_159), + SLC_VAR("gui.sg_full_load_any"), + SLC_VAR("order.improved_load"), + SLC_VAR("order.selectgoods"), + SLC_VAR("gui.sg_new_nonstop"), + SLC_NULL(1, SL_MIN_VERSION, SLV_159), + SLC_VAR("station.station_spread"), + SLC_VAR("order.serviceathelipad"), + SLC_VAR("station.modified_catchment"), + SLC_VAR("station.serve_neutral_industries"), + SLC_VAR("order.gradual_loading"), + SLC_VAR("construction.road_stop_on_town_road"), + SLC_VAR("construction.road_stop_on_competitor_road"), + SLC_VAR("station.adjacent_stations"), + SLC_VAR("economy.station_noise_level"), + SLC_VAR("station.distant_join_stations"), + SLC_VAR("economy.inflation"), + SLC_VAR("construction.raw_industry_construction"), + SLC_VAR("construction.industry_platform"), + SLC_VAR("economy.multiple_industry_per_town"), + SLC_NULL(1, SL_MIN_VERSION, SLV_141), + SLC_VAR("economy.bribe"), + SLC_VAR("economy.exclusive_rights"), + SLC_VAR("economy.fund_buildings"), + SLC_VAR("economy.fund_roads"), + SLC_VAR("economy.give_money"), + SLC_VAR("game_creation.snow_line_height"), + SLC_VAR("game_creation.snow_coverage"), + SLC_VAR("game_creation.desert_coverage"), + SLC_NULL(4, SL_MIN_VERSION, SLV_144), + SLC_VAR("game_creation.starting_year"), + SLC_NULL(4, SL_MIN_VERSION, SLV_105), + SLC_VAR("game_creation.ending_year"), + SLC_VAR("economy.type"), + SLC_VAR("economy.allow_shares"), + SLC_VAR("economy.min_years_for_shares"), + SLC_VAR("economy.feeder_payment_share"), + SLC_VAR("economy.town_growth_rate"), + SLC_VAR("economy.larger_towns"), + SLC_VAR("economy.initial_city_size"), + SLC_VAR("economy.mod_road_rebuild"), + SLC_NULL(1, SL_MIN_VERSION, SLV_107), + SLC_VAR("script.settings_profile"), + SLC_VAR("ai.ai_in_multiplayer"), + SLC_VAR("ai.ai_disable_veh_train"), + SLC_VAR("ai.ai_disable_veh_roadveh"), + SLC_VAR("ai.ai_disable_veh_aircraft"), + SLC_VAR("ai.ai_disable_veh_ship"), + SLC_VAR("script.script_max_opcode_till_suspend"), + SLC_VAR("script.script_max_memory_megabytes"), + SLC_VAR("vehicle.extend_vehicle_life"), + SLC_VAR("economy.dist_local_authority"), + SLC_VAR("pf.reverse_at_signals"), + SLC_VAR("pf.wait_oneway_signal"), + SLC_VAR("pf.wait_twoway_signal"), + SLC_VAR("economy.town_noise_population[0]"), + SLC_VAR("economy.town_noise_population[1]"), + SLC_VAR("economy.town_noise_population[2]"), + SLC_VAR("economy.infrastructure_maintenance"), + SLC_VAR("pf.wait_for_pbs_path"), + SLC_VAR("pf.reserve_paths"), + SLC_VAR("pf.path_backoff_interval"), + SLC_NULL(3, SL_MIN_VERSION, SLV_REMOVE_OPF), + SLC_VAR("pf.npf.npf_max_search_nodes"), + SLC_VAR("pf.npf.npf_rail_firstred_penalty"), + SLC_VAR("pf.npf.npf_rail_firstred_exit_penalty"), + SLC_VAR("pf.npf.npf_rail_lastred_penalty"), + SLC_VAR("pf.npf.npf_rail_station_penalty"), + SLC_VAR("pf.npf.npf_rail_slope_penalty"), + SLC_VAR("pf.npf.npf_rail_curve_penalty"), + SLC_VAR("pf.npf.npf_rail_depot_reverse_penalty"), + SLC_VAR("pf.npf.npf_rail_pbs_cross_penalty"), + SLC_VAR("pf.npf.npf_rail_pbs_signal_back_penalty"), + SLC_VAR("pf.npf.npf_buoy_penalty"), + SLC_VAR("pf.npf.npf_water_curve_penalty"), + SLC_VAR("pf.npf.npf_road_curve_penalty"), + SLC_VAR("pf.npf.npf_crossing_penalty"), + SLC_VAR("pf.npf.npf_road_drive_through_penalty"), + SLC_VAR("pf.npf.npf_road_dt_occupied_penalty"), + SLC_VAR("pf.npf.npf_road_bay_occupied_penalty"), + SLC_VAR("pf.npf.maximum_go_to_depot_penalty"), + SLC_VAR("pf.yapf.disable_node_optimization"), + SLC_VAR("pf.yapf.max_search_nodes"), + SLC_VAR("pf.yapf.rail_firstred_twoway_eol"), + SLC_VAR("pf.yapf.rail_firstred_penalty"), + SLC_VAR("pf.yapf.rail_firstred_exit_penalty"), + SLC_VAR("pf.yapf.rail_lastred_penalty"), + SLC_VAR("pf.yapf.rail_lastred_exit_penalty"), + SLC_VAR("pf.yapf.rail_station_penalty"), + SLC_VAR("pf.yapf.rail_slope_penalty"), + SLC_VAR("pf.yapf.rail_curve45_penalty"), + SLC_VAR("pf.yapf.rail_curve90_penalty"), + SLC_VAR("pf.yapf.rail_depot_reverse_penalty"), + SLC_VAR("pf.yapf.rail_crossing_penalty"), + SLC_VAR("pf.yapf.rail_look_ahead_max_signals"), + SLC_VAR("pf.yapf.rail_look_ahead_signal_p0"), + SLC_VAR("pf.yapf.rail_look_ahead_signal_p1"), + SLC_VAR("pf.yapf.rail_look_ahead_signal_p2"), + SLC_VAR("pf.yapf.rail_pbs_cross_penalty"), + SLC_VAR("pf.yapf.rail_pbs_station_penalty"), + SLC_VAR("pf.yapf.rail_pbs_signal_back_penalty"), + SLC_VAR("pf.yapf.rail_doubleslip_penalty"), + SLC_VAR("pf.yapf.rail_longer_platform_penalty"), + SLC_VAR("pf.yapf.rail_longer_platform_per_tile_penalty"), + SLC_VAR("pf.yapf.rail_shorter_platform_penalty"), + SLC_VAR("pf.yapf.rail_shorter_platform_per_tile_penalty"), + SLC_VAR("pf.yapf.road_slope_penalty"), + SLC_VAR("pf.yapf.road_curve_penalty"), + SLC_VAR("pf.yapf.road_crossing_penalty"), + SLC_VAR("pf.yapf.road_stop_penalty"), + SLC_VAR("pf.yapf.road_stop_occupied_penalty"), + SLC_VAR("pf.yapf.road_stop_bay_occupied_penalty"), + SLC_VAR("pf.yapf.maximum_go_to_depot_penalty"), + SLC_VAR("pf.yapf.ship_curve45_penalty"), + SLC_VAR("pf.yapf.ship_curve90_penalty"), + SLC_VAR("game_creation.land_generator"), + SLC_VAR("game_creation.oil_refinery_limit"), + SLC_VAR("game_creation.tgen_smoothness"), + SLC_VAR("game_creation.variety"), + SLC_VAR("game_creation.generation_seed"), + SLC_VAR("game_creation.tree_placer"), + SLC_VAR("construction.freeform_edges"), + SLC_VAR("game_creation.water_borders"), + SLC_VAR("game_creation.custom_town_number"), + SLC_VAR("construction.extra_tree_placement"), + SLC_VAR("game_creation.custom_terrain_type"), + SLC_VAR("game_creation.custom_sea_level"), + SLC_VAR("game_creation.min_river_length"), + SLC_VAR("game_creation.river_route_random"), + SLC_VAR("game_creation.amount_of_rivers"), + SLC_VAR("locale.currency"), + SLC_VAR("units"), + SLC_VAR("locale.units_velocity"), + SLC_VAR("locale.units_power"), + SLC_VAR("locale.units_weight"), + SLC_VAR("locale.units_volume"), + SLC_VAR("locale.units_force"), + SLC_VAR("locale.units_height"), + SLC_VAR("locale.digit_group_separator"), + SLC_VAR("locale.digit_group_separator_currency"), + SLC_VAR("locale.digit_decimal_separator"), +}; + +} + +#endif /* SAVELOAD_COMPAT_SETTINGS_H */ diff --git a/src/saveload/upstream/compat/signs_sl_compat.h b/src/saveload/upstream/compat/signs_sl_compat.h new file mode 100644 index 0000000000..f4eda4bc07 --- /dev/null +++ b/src/saveload/upstream/compat/signs_sl_compat.h @@ -0,0 +1,28 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file signs_sl_compat.h Loading of signs chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_SIGNS_H +#define SAVELOAD_COMPAT_SIGNS_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for _sign_desc. */ +const SaveLoadCompat _sign_sl_compat[] = { + SLC_VAR("name"), + SLC_VAR("x"), + SLC_VAR("y"), + SLC_VAR("owner"), + SLC_VAR("z"), +}; + +} + +#endif /* SAVELOAD_COMPAT_SIGNS_H */ diff --git a/src/saveload/upstream/compat/station_sl_compat.h b/src/saveload/upstream/compat/station_sl_compat.h new file mode 100644 index 0000000000..d596e8bd45 --- /dev/null +++ b/src/saveload/upstream/compat/station_sl_compat.h @@ -0,0 +1,185 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file station_sl_compat.h Loading of station chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_STATION_H +#define SAVELOAD_COMPAT_STATION_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for _roadstop_desc. */ +const SaveLoadCompat _roadstop_sl_compat[] = { + SLC_VAR("xy"), + SLC_NULL(1, SL_MIN_VERSION, SLV_45), + SLC_VAR("status"), + SLC_NULL(4, SL_MIN_VERSION, SLV_9), + SLC_NULL(2, SL_MIN_VERSION, SLV_45), + SLC_NULL(1, SL_MIN_VERSION, SLV_26), + SLC_VAR("next"), + SLC_NULL(2, SL_MIN_VERSION, SLV_45), + SLC_NULL(4, SL_MIN_VERSION, SLV_25), + SLC_NULL(1, SLV_25, SLV_26), +}; + +/** Original field order for SlStationSpecList. */ +const SaveLoadCompat _station_spec_list_sl_compat[] = { + SLC_VAR("grfid"), + SLC_VAR("localidx"), +}; + +/** Original field order for SlStationCargo. */ +const SaveLoadCompat _station_cargo_sl_compat[] = { + SLC_VAR("first"), + SLC_VAR("second"), +}; + +/** Original field order for SlStationFlow. */ +const SaveLoadCompat _station_flow_sl_compat[] = { + SLC_VAR("source"), + SLC_VAR("via"), + SLC_VAR("share"), + SLC_VAR("restricted"), +}; + +/** Original field order for SlStationGoods. */ +const SaveLoadCompat _station_goods_sl_compat[] = { + SLC_VAR("waiting_acceptance"), + SLC_VAR("status"), + SLC_NULL(2, SLV_51, SLV_68), + SLC_VAR("time_since_pickup"), + SLC_VAR("rating"), + SLC_VAR("cargo_source"), + SLC_VAR("cargo_source_xy"), + SLC_VAR("cargo_days"), + SLC_VAR("last_speed"), + SLC_VAR("last_age"), + SLC_VAR("cargo_feeder_share"), + SLC_VAR("amount_fract"), + SLC_VAR("packets"), + SLC_VAR("old_num_dests"), + SLC_VAR("cargo.reserved_count"), + SLC_VAR("link_graph"), + SLC_VAR("node"), + SLC_VAR("old_num_flows"), + SLC_VAR("max_waiting_cargo"), + SLC_VAR("flow"), + SLC_VAR("cargo"), +}; + +/** Original field order for SlStationBase. */ +const SaveLoadCompat _station_base_sl_compat[] = { + SLC_VAR("xy"), + SLC_VAR("town"), + SLC_VAR("string_id"), + SLC_VAR("name"), + SLC_VAR("delete_ctr"), + SLC_VAR("owner"), + SLC_VAR("facilities"), + SLC_VAR("build_date"), + SLC_VAR("random_bits"), + SLC_VAR("waiting_triggers"), + SLC_VAR("num_specs"), +}; + +/** Original field order for SlStationNormal. */ +const SaveLoadCompat _station_normal_sl_compat[] = { + SLC_VAR("base"), + SLC_VAR("train_station.tile"), + SLC_VAR("train_station.w"), + SLC_VAR("train_station.h"), + SLC_VAR("bus_stops"), + SLC_VAR("truck_stops"), + SLC_NULL(4, SL_MIN_VERSION, SLV_MULTITILE_DOCKS), + SLC_VAR("ship_station.tile"), + SLC_VAR("ship_station.w"), + SLC_VAR("ship_station.h"), + SLC_VAR("docking_station.tile"), + SLC_VAR("docking_station.w"), + SLC_VAR("docking_station.h"), + SLC_VAR("airport.tile"), + SLC_VAR("airport.w"), + SLC_VAR("airport.h"), + SLC_VAR("airport.type"), + SLC_VAR("airport.layout"), + SLC_VAR("airport.flags"), + SLC_VAR("airport.rotation"), + SLC_VAR("storage"), + SLC_VAR("airport.psa"), + SLC_VAR("indtype"), + SLC_VAR("time_since_load"), + SLC_VAR("time_since_unload"), + SLC_VAR("last_vehicle_type"), + SLC_VAR("had_vehicle_of_type"), + SLC_VAR("loading_vehicles"), + SLC_VAR("always_accepted"), + SLC_VAR("goods"), +}; + +/** Original field order for SlStationWaypoint. */ +const SaveLoadCompat _station_waypoint_sl_compat[] = { + SLC_VAR("base"), + SLC_VAR("town_cn"), + SLC_VAR("train_station.tile"), + SLC_VAR("train_station.w"), + SLC_VAR("train_station.h"), +}; + +/** Original field order for _station_desc. */ +const SaveLoadCompat _station_sl_compat[] = { + SLC_VAR("facilities"), + SLC_VAR("normal"), + SLC_VAR("waypoint"), + SLC_VAR("speclist"), +}; + +/** Original field order for _old_station_desc. */ +const SaveLoadCompat _old_station_sl_compat[] = { + SLC_VAR("xy"), + SLC_NULL(4, SL_MIN_VERSION, SLV_6), + SLC_VAR("train_station.tile"), + SLC_VAR("airport.tile"), + SLC_NULL(2, SL_MIN_VERSION, SLV_6), + SLC_NULL(4, SLV_6, SLV_MULTITILE_DOCKS), + SLC_VAR("town"), + SLC_VAR("train_station.w"), + SLC_VAR("train_station.h"), + SLC_NULL(1, SL_MIN_VERSION, SLV_4), + SLC_VAR("string_id"), + SLC_VAR("name"), + SLC_VAR("indtype"), + SLC_VAR("had_vehicle_of_type"), + SLC_VAR("time_since_load"), + SLC_VAR("time_since_unload"), + SLC_VAR("delete_ctr"), + SLC_VAR("owner"), + SLC_VAR("facilities"), + SLC_VAR("airport.type"), + SLC_NULL(2, SL_MIN_VERSION, SLV_6), + SLC_NULL(1, SL_MIN_VERSION, SLV_5), + SLC_VAR("airport.flags"), + SLC_NULL(2, SL_MIN_VERSION, SLV_26), + SLC_VAR("last_vehicle_type"), + SLC_NULL(2, SLV_3, SLV_26), + SLC_VAR("build_date"), + SLC_VAR("bus_stops"), + SLC_VAR("truck_stops"), + SLC_VAR("random_bits"), + SLC_VAR("waiting_triggers"), + SLC_VAR("num_specs"), + SLC_VAR("loading_vehicles"), + SLC_NULL(32, SLV_2, SL_MAX_VERSION), + SLC_VAR("goods"), + SLC_VAR("speclist"), + +}; + +} + +#endif /* SAVELOAD_COMPAT_STATION_H */ diff --git a/src/saveload/upstream/compat/storage_sl_compat.h b/src/saveload/upstream/compat/storage_sl_compat.h new file mode 100644 index 0000000000..8d8e309353 --- /dev/null +++ b/src/saveload/upstream/compat/storage_sl_compat.h @@ -0,0 +1,25 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file storage_sl_compat.h Loading of storage chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_STORAGE_H +#define SAVELOAD_COMPAT_STORAGE_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for _storage_desc. */ +const SaveLoadCompat _storage_sl_compat[] = { + SLC_VAR("grfid"), + SLC_VAR("storage"), +}; + +} + +#endif /* SAVELOAD_COMPAT_STORAGE_H */ diff --git a/src/saveload/upstream/compat/story_sl_compat.h b/src/saveload/upstream/compat/story_sl_compat.h new file mode 100644 index 0000000000..f241aba55d --- /dev/null +++ b/src/saveload/upstream/compat/story_sl_compat.h @@ -0,0 +1,36 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file story_sl_compat.h Loading for story chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_STORE_H +#define SAVELOAD_COMPAT_STORE_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for _story_page_elements_desc. */ +const SaveLoadCompat _story_page_elements_sl_compat[] = { + SLC_VAR("sort_value"), + SLC_VAR("page"), + SLC_VAR("type"), + SLC_VAR("referenced_id"), + SLC_VAR("text"), +}; + +/** Original field order for _story_pages_desc. */ +const SaveLoadCompat _story_pages_sl_compat[] = { + SLC_VAR("sort_value"), + SLC_VAR("date"), + SLC_VAR("company"), + SLC_VAR("title"), +}; + +} + +#endif /* SAVELOAD_COMPAT_STORE_H */ diff --git a/src/saveload/upstream/compat/subsidy_sl_compat.h b/src/saveload/upstream/compat/subsidy_sl_compat.h new file mode 100644 index 0000000000..9f3d529fe2 --- /dev/null +++ b/src/saveload/upstream/compat/subsidy_sl_compat.h @@ -0,0 +1,30 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file subsidy_sl_compat.h Loading of subsidy chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_SUBSIDY_H +#define SAVELOAD_COMPAT_SUBSIDY_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for _subsidies_desc. */ +const SaveLoadCompat _subsidies_sl_compat[] = { + SLC_VAR("cargo_type"), + SLC_VAR("remaining"), + SLC_VAR("awarded"), + SLC_VAR("src_type"), + SLC_VAR("dst_type"), + SLC_VAR("src"), + SLC_VAR("dst"), +}; + +} + +#endif /* SAVELOAD_COMPAT_SUBSIDY_H */ diff --git a/src/saveload/upstream/compat/town_sl_compat.h b/src/saveload/upstream/compat/town_sl_compat.h new file mode 100644 index 0000000000..1939228f30 --- /dev/null +++ b/src/saveload/upstream/compat/town_sl_compat.h @@ -0,0 +1,91 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file town_sl_compat.h Loading of town chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_TOWN_H +#define SAVELOAD_COMPAT_TOWN_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for SlTownSupplied. */ +const SaveLoadCompat _town_supplied_sl_compat[] = { + SLC_VAR("old_max"), + SLC_VAR("new_max"), + SLC_VAR("old_act"), + SLC_VAR("new_act"), +}; + +/** Original field order for SlTownReceived. */ +const SaveLoadCompat _town_received_sl_compat[] = { + SLC_VAR("old_max"), + SLC_VAR("new_max"), + SLC_VAR("old_act"), + SLC_VAR("new_act"), +}; + +/** Original field order for SlTownAcceptanceMatrix. */ +const SaveLoadCompat _town_acceptance_matrix_sl_compat[] = { + SLC_VAR("area.tile"), + SLC_VAR("area.w"), + SLC_VAR("area.h"), +}; + +/** Original field order for town_desc. */ +const SaveLoadCompat _town_sl_compat[] = { + SLC_VAR("xy"), + SLC_NULL(2, SL_MIN_VERSION, SLV_3), + SLC_NULL(4, SLV_3, SLV_85), + SLC_NULL(2, SL_MIN_VERSION, SLV_92), + SLC_VAR("townnamegrfid"), + SLC_VAR("townnametype"), + SLC_VAR("townnameparts"), + SLC_VAR("name"), + SLC_VAR("flags"), + SLC_VAR("statues"), + SLC_NULL(1, SL_MIN_VERSION, SLV_2), + SLC_VAR("have_ratings"), + SLC_VAR("ratings"), + SLC_VAR("unwanted"), + SLC_VAR("supplied[CT_PASSENGERS].old_max"), + SLC_VAR("supplied[CT_MAIL].old_max"), + SLC_VAR("supplied[CT_PASSENGERS].new_max"), + SLC_VAR("supplied[CT_MAIL].new_max"), + SLC_VAR("supplied[CT_PASSENGERS].old_act"), + SLC_VAR("supplied[CT_MAIL].old_act"), + SLC_VAR("supplied[CT_PASSENGERS].new_act"), + SLC_VAR("supplied[CT_MAIL].new_act"), + SLC_NULL(2, SL_MIN_VERSION, SLV_164), + SLC_VAR("received[TE_FOOD].old_act"), + SLC_VAR("received[TE_WATER].old_act"), + SLC_VAR("received[TE_FOOD].new_act"), + SLC_VAR("received[TE_WATER].new_act"), + SLC_VAR("goal"), + SLC_VAR("text"), + SLC_VAR("time_until_rebuild"), + SLC_VAR("grow_counter"), + SLC_VAR("growth_rate"), + SLC_VAR("fund_buildings_months"), + SLC_VAR("road_build_months"), + SLC_VAR("exclusivity"), + SLC_VAR("exclusive_counter"), + SLC_VAR("larger_town"), + SLC_VAR("layout"), + SLC_VAR("psa_list"), + SLC_NULL(4, SLV_166, SLV_EXTEND_CARGOTYPES), + SLC_NULL(8, SLV_EXTEND_CARGOTYPES, SLV_REMOVE_TOWN_CARGO_CACHE), + SLC_NULL(30, SLV_2, SLV_REMOVE_TOWN_CARGO_CACHE), + SLC_VAR("supplied"), + SLC_VAR("received"), + SLC_VAR("acceptance_matrix"), +}; + +} + +#endif /* SAVELOAD_COMPAT_TOWN_H */ diff --git a/src/saveload/upstream/compat/vehicle_sl_compat.h b/src/saveload/upstream/compat/vehicle_sl_compat.h new file mode 100644 index 0000000000..0fd19ecc0e --- /dev/null +++ b/src/saveload/upstream/compat/vehicle_sl_compat.h @@ -0,0 +1,211 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file vehicle_sl_compat.h Loading of vehicle chunks before table headers were added. */ + +#ifndef SAVELOAD_COMPAT_VEHICLE_H +#define SAVELOAD_COMPAT_VEHICLE_H + +#include "../saveload.h" + +namespace upstream_sl { + +/** Original field order for SlVehicleCommon. */ +const SaveLoadCompat _vehicle_common_sl_compat[] = { + SLC_VAR("subtype"), + SLC_VAR("next"), + SLC_VAR("name"), + SLC_VAR("unitnumber"), + SLC_VAR("owner"), + SLC_VAR("tile"), + SLC_VAR("dest_tile"), + SLC_VAR("x_pos"), + SLC_VAR("y_pos"), + SLC_VAR("z_pos"), + SLC_VAR("direction"), + SLC_NULL(2, SL_MIN_VERSION, SLV_58), + SLC_VAR("spritenum"), + SLC_NULL(5, SL_MIN_VERSION, SLV_58), + SLC_VAR("engine_type"), + SLC_NULL(2, SL_MIN_VERSION, SLV_152), + SLC_VAR("cur_speed"), + SLC_VAR("subspeed"), + SLC_VAR("acceleration"), + SLC_VAR("motion_counter"), + SLC_VAR("progress"), + SLC_VAR("vehstatus"), + SLC_VAR("last_station_visited"), + SLC_VAR("last_loading_station"), + SLC_VAR("cargo_type"), + SLC_VAR("cargo_subtype"), + SLC_VAR("cargo_days"), + SLC_VAR("cargo_source"), + SLC_VAR("cargo_source_xy"), + SLC_VAR("cargo_cap"), + SLC_VAR("refit_cap"), + SLC_VAR("cargo_count"), + SLC_VAR("cargo.packets"), + SLC_VAR("cargo.action_counts"), + SLC_VAR("cargo_age_counter"), + SLC_VAR("day_counter"), + SLC_VAR("tick_counter"), + SLC_VAR("running_ticks"), + SLC_VAR("cur_implicit_order_index"), + SLC_VAR("cur_real_order_index"), + SLC_NULL(1, SL_MIN_VERSION, SLV_105), + SLC_VAR("current_order.type"), + SLC_VAR("current_order.flags"), + SLC_VAR("current_order.dest"), + SLC_VAR("current_order.refit_cargo"), + SLC_NULL(1, SLV_36, SLV_182), + SLC_VAR("current_order.wait_time"), + SLC_VAR("current_order.travel_time"), + SLC_VAR("current_order.max_speed"), + SLC_VAR("timetable_start"), + SLC_VAR("orders"), + SLC_VAR("age"), + SLC_VAR("max_age"), + SLC_VAR("date_of_last_service"), + SLC_VAR("service_interval"), + SLC_VAR("reliability"), + SLC_VAR("reliability_spd_dec"), + SLC_VAR("breakdown_ctr"), + SLC_VAR("breakdown_delay"), + SLC_VAR("breakdowns_since_last_service"), + SLC_VAR("breakdown_chance"), + SLC_VAR("build_year"), + SLC_VAR("load_unload_ticks"), + SLC_VAR("cargo_paid_for"), + SLC_VAR("vehicle_flags"), + SLC_VAR("profit_this_year"), + SLC_VAR("profit_last_year"), + SLC_VAR("cargo_feeder_share"), + SLC_VAR("cargo_loaded_at_xy"), + SLC_VAR("value"), + SLC_VAR("random_bits"), + SLC_VAR("waiting_triggers"), + SLC_VAR("next_shared"), + SLC_NULL(2, SLV_2, SLV_69), + SLC_NULL(4, SLV_69, SLV_101), + SLC_VAR("group_id"), + SLC_VAR("current_order_time"), + SLC_VAR("lateness_counter"), + SLC_NULL(10, SLV_2, SLV_144), +}; + +/** Original field order for SlVehicleTrain. */ +const SaveLoadCompat _vehicle_train_sl_compat[] = { + SLC_VAR("common"), + SLC_VAR("crash_anim_pos"), + SLC_VAR("force_proceed"), + SLC_VAR("railtype"), + SLC_VAR("track"), + SLC_VAR("flags"), + SLC_NULL(2, SLV_2, SLV_60), + SLC_VAR("wait_counter"), + SLC_NULL(2, SLV_2, SLV_20), + SLC_VAR("gv_flags"), + SLC_NULL(11, SLV_2, SLV_144), +}; + +/** Original field order for SlVehicleRoadVeh. */ +const SaveLoadCompat _vehicle_roadveh_sl_compat[] = { + SLC_VAR("common"), + SLC_VAR("state"), + SLC_VAR("frame"), + SLC_VAR("blocked_ctr"), + SLC_VAR("overtaking"), + SLC_VAR("overtaking_ctr"), + SLC_VAR("crashed_ctr"), + SLC_VAR("reverse_ctr"), + SLC_VAR("path.td"), + SLC_VAR("path.tile"), + SLC_NULL(2, SLV_6, SLV_69), + SLC_VAR("gv_flags"), + SLC_NULL(4, SLV_69, SLV_131), + SLC_NULL(2, SLV_6, SLV_131), + SLC_NULL(16, SLV_2, SLV_144), +}; + +/** Original field order for SlVehicleShip. */ +const SaveLoadCompat _vehicle_ship_sl_compat[] = { + SLC_VAR("common"), + SLC_VAR("state"), + SLC_VAR("path"), + SLC_VAR("rotation"), + SLC_NULL(16, SLV_2, SLV_144), +}; + +/** Original field order for SlVehicleAircraft. */ +const SaveLoadCompat _vehicle_aircraft_sl_compat[] = { + SLC_VAR("common"), + SLC_VAR("crashed_counter"), + SLC_VAR("pos"), + SLC_VAR("targetairport"), + SLC_VAR("state"), + SLC_VAR("previous_pos"), + SLC_VAR("last_direction"), + SLC_VAR("number_consecutive_turns"), + SLC_VAR("turn_counter"), + SLC_VAR("flags"), + SLC_NULL(13, SLV_2, SLV_144), +}; + +/** Original field order for SlVehicleEffect. */ +const SaveLoadCompat _vehicle_effect_sl_compat[] = { + SLC_VAR("subtype"), + SLC_VAR("tile"), + SLC_VAR("x_pos"), + SLC_VAR("y_pos"), + SLC_VAR("z_pos"), + SLC_VAR("sprite_cache.sprite_seq.seq[0].sprite"), + SLC_NULL(5, SL_MIN_VERSION, SLV_59), + SLC_VAR("progress"), + SLC_VAR("vehstatus"), + SLC_VAR("animation_state"), + SLC_VAR("animation_substate"), + SLC_VAR("spritenum"), + SLC_NULL(15, SLV_2, SLV_144), +}; + +/** Original field order for SlVehicleDisaster. */ +const SaveLoadCompat _vehicle_disaster_sl_compat[] = { + SLC_VAR("next"), + SLC_VAR("subtype"), + SLC_VAR("tile"), + SLC_VAR("dest_tile"), + SLC_VAR("x_pos"), + SLC_VAR("y_pos"), + SLC_VAR("z_pos"), + SLC_VAR("direction"), + SLC_NULL(5, SL_MIN_VERSION, SLV_58), + SLC_VAR("owner"), + SLC_VAR("vehstatus"), + SLC_VAR("current_order.dest"), + SLC_VAR("sprite_cache.sprite_seq.seq[0].sprite"), + SLC_VAR("age"), + SLC_VAR("tick_counter"), + SLC_VAR("image_override"), + SLC_VAR("big_ufo_destroyer_target"), + SLC_VAR("flags"), + SLC_NULL(16, SLV_2, SLV_144), +}; + +/** Original field order for vehicle_desc. */ +const SaveLoadCompat _vehicle_sl_compat[] = { + SLC_VAR("type"), + SLC_VAR("train"), + SLC_VAR("roadveh"), + SLC_VAR("ship"), + SLC_VAR("aircraft"), + SLC_VAR("effect"), + SLC_VAR("disaster"), +}; + +} + +#endif /* SAVELOAD_COMPAT_VEHICLE_H */ diff --git a/src/saveload/upstream/depot_sl.cpp b/src/saveload/upstream/depot_sl.cpp new file mode 100644 index 0000000000..b8ea8d7490 --- /dev/null +++ b/src/saveload/upstream/depot_sl.cpp @@ -0,0 +1,78 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file depot_sl.cpp Code handling saving and loading of depots */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "compat/depot_sl_compat.h" + +#include "../../depot_base.h" +#include "../../town.h" + +#include "../../safeguards.h" + +namespace upstream_sl { + +static TownID _town_index; + +static const SaveLoad _depot_desc[] = { + SLE_CONDVAR(Depot, xy, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), + SLE_CONDVAR(Depot, xy, SLE_UINT32, SLV_6, SL_MAX_VERSION), + SLEG_CONDVAR("town_index", _town_index, SLE_UINT16, SL_MIN_VERSION, SLV_141), + SLE_CONDREF(Depot, town, REF_TOWN, SLV_141, SL_MAX_VERSION), + SLE_CONDVAR(Depot, town_cn, SLE_UINT16, SLV_141, SL_MAX_VERSION), + SLE_CONDSTR(Depot, name, SLE_STR, 0, SLV_141, SL_MAX_VERSION), + SLE_CONDVAR(Depot, build_date, SLE_INT32, SLV_142, SL_MAX_VERSION), +}; + +struct DEPTChunkHandler : ChunkHandler { + DEPTChunkHandler() : ChunkHandler('DEPT', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_depot_desc); + + for (Depot *depot : Depot::Iterate()) { + SlSetArrayIndex(depot->index); + SlObject(depot, _depot_desc); + } + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_depot_desc, _depot_sl_compat); + + int index; + + while ((index = SlIterateArray()) != -1) { + Depot *depot = new (index) Depot(); + SlObject(depot, slt); + + /* Set the town 'pointer' so we can restore it later. */ + if (IsSavegameVersionBefore(SLV_141)) depot->town = (Town *)(size_t)_town_index; + } + } + + void FixPointers() const override + { + for (Depot *depot : Depot::Iterate()) { + SlObject(depot, _depot_desc); + if (IsSavegameVersionBefore(SLV_141)) depot->town = Town::Get((size_t)depot->town); + } + } +}; + +static const DEPTChunkHandler DEPT; +static const ChunkHandlerRef depot_chunk_handlers[] = { + DEPT, +}; + +extern const ChunkHandlerTable _depot_chunk_handlers(depot_chunk_handlers); + +} diff --git a/src/saveload/upstream/economy_sl.cpp b/src/saveload/upstream/economy_sl.cpp new file mode 100644 index 0000000000..e6ea184fb8 --- /dev/null +++ b/src/saveload/upstream/economy_sl.cpp @@ -0,0 +1,109 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file economy_sl.cpp Code handling saving and loading of economy data */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "compat/economy_sl_compat.h" + +#include "../../economy_func.h" +#include "../../economy_base.h" + +#include "../../safeguards.h" + +namespace upstream_sl { + +static const SaveLoad _economy_desc[] = { + SLE_CONDVAR(Economy, old_max_loan_unround, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_65), + SLE_CONDVAR(Economy, old_max_loan_unround, SLE_INT64, SLV_65, SLV_126), + SLE_CONDVAR(Economy, old_max_loan_unround_fract, SLE_UINT16, SLV_70, SLV_126), + SLE_CONDVAR(Economy, inflation_prices, SLE_UINT64, SLV_126, SL_MAX_VERSION), + SLE_CONDVAR(Economy, inflation_payment, SLE_UINT64, SLV_126, SL_MAX_VERSION), + SLE_VAR(Economy, fluct, SLE_INT16), + SLE_VAR(Economy, interest_rate, SLE_UINT8), + SLE_VAR(Economy, infl_amount, SLE_UINT8), + SLE_VAR(Economy, infl_amount_pr, SLE_UINT8), + SLE_CONDVAR(Economy, industry_daily_change_counter, SLE_UINT32, SLV_102, SL_MAX_VERSION), +}; + +/** Economy variables */ +struct ECMYChunkHandler : ChunkHandler { + ECMYChunkHandler() : ChunkHandler('ECMY', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_economy_desc); + + SlSetArrayIndex(0); + SlObject(&_economy, _economy_desc); + } + + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_economy_desc, _economy_sl_compat); + + if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() == -1) return; + SlObject(&_economy, slt); + if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many ECMY entries"); + + StartupIndustryDailyChanges(IsSavegameVersionBefore(SLV_102)); // old savegames will need to be initialized + } +}; + +static const SaveLoad _cargopayment_desc[] = { + SLE_REF(CargoPayment, front, REF_VEHICLE), + SLE_VAR(CargoPayment, route_profit, SLE_INT64), + SLE_VAR(CargoPayment, visual_profit, SLE_INT64), + SLE_CONDVAR(CargoPayment, visual_transfer, SLE_INT64, SLV_181, SL_MAX_VERSION), +}; + +struct CAPYChunkHandler : ChunkHandler { + CAPYChunkHandler() : ChunkHandler('CAPY', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_cargopayment_desc); + + for (CargoPayment *cp : CargoPayment::Iterate()) { + SlSetArrayIndex(cp->index); + SlObject(cp, _cargopayment_desc); + } + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_cargopayment_desc, _cargopayment_sl_compat); + + int index; + + while ((index = SlIterateArray()) != -1) { + CargoPayment *cp = new (index) CargoPayment(); + SlObject(cp, slt); + } + } + + void FixPointers() const override + { + for (CargoPayment *cp : CargoPayment::Iterate()) { + SlObject(cp, _cargopayment_desc); + } + } +}; + +static const CAPYChunkHandler CAPY; +static const ECMYChunkHandler ECMY; +static const ChunkHandlerRef economy_chunk_handlers[] = { + CAPY, + ECMY, +}; + +extern const ChunkHandlerTable _economy_chunk_handlers(economy_chunk_handlers); + +} diff --git a/src/saveload/upstream/engine_sl.cpp b/src/saveload/upstream/engine_sl.cpp new file mode 100644 index 0000000000..8f847025ab --- /dev/null +++ b/src/saveload/upstream/engine_sl.cpp @@ -0,0 +1,129 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file engine_sl.cpp Code handling saving and loading of engines */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "compat/engine_sl_compat.h" + +#include "../../engine_base.h" +#include "../../string_func.h" +#include + +#include "../../safeguards.h" + +Engine *GetTempDataEngine(EngineID index); + +namespace upstream_sl { + +static const SaveLoad _engine_desc[] = { + SLE_CONDVAR(Engine, intro_date, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31), + SLE_CONDVAR(Engine, intro_date, SLE_INT32, SLV_31, SL_MAX_VERSION), + SLE_CONDVAR(Engine, age, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31), + SLE_CONDVAR(Engine, age, SLE_INT32, SLV_31, SL_MAX_VERSION), + SLE_VAR(Engine, reliability, SLE_UINT16), + SLE_VAR(Engine, reliability_spd_dec, SLE_UINT16), + SLE_VAR(Engine, reliability_start, SLE_UINT16), + SLE_VAR(Engine, reliability_max, SLE_UINT16), + SLE_VAR(Engine, reliability_final, SLE_UINT16), + SLE_VAR(Engine, duration_phase_1, SLE_UINT16), + SLE_VAR(Engine, duration_phase_2, SLE_UINT16), + SLE_VAR(Engine, duration_phase_3, SLE_UINT16), + SLE_VAR(Engine, flags, SLE_UINT8), + SLE_CONDVAR(Engine, preview_asked, SLE_UINT16, SLV_179, SL_MAX_VERSION), + SLE_CONDVAR(Engine, preview_company, SLE_UINT8, SLV_179, SL_MAX_VERSION), + SLE_VAR(Engine, preview_wait, SLE_UINT8), + SLE_CONDVAR(Engine, company_avail, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_104), + SLE_CONDVAR(Engine, company_avail, SLE_UINT16, SLV_104, SL_MAX_VERSION), + SLE_CONDVAR(Engine, company_hidden, SLE_UINT16, SLV_193, SL_MAX_VERSION), + SLE_CONDSTR(Engine, name, SLE_STR, 0, SLV_84, SL_MAX_VERSION), +}; + +struct ENGNChunkHandler : ChunkHandler { + ENGNChunkHandler() : ChunkHandler('ENGN', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_engine_desc); + + for (Engine *e : Engine::Iterate()) { + SlSetArrayIndex(e->index); + SlObject(e, _engine_desc); + } + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_engine_desc, _engine_sl_compat); + + /* As engine data is loaded before engines are initialized we need to load + * this information into a temporary array. This is then copied into the + * engine pool after processing NewGRFs by CopyTempEngineData(). */ + int index; + while ((index = SlIterateArray()) != -1) { + Engine *e = GetTempDataEngine(index); + SlObject(e, slt); + + if (IsSavegameVersionBefore(SLV_179)) { + /* preview_company_rank was replaced with preview_company and preview_asked. + * Just cancel any previews. */ + e->flags &= ~4; // ENGINE_OFFER_WINDOW_OPEN + e->preview_company = INVALID_COMPANY; + e->preview_asked = (CompanyMask)-1; + } + } + } +}; + +/** Save and load the mapping between the engine id in the pool, and the grf file it came from. */ +static const SaveLoad _engine_id_mapping_desc[] = { + SLE_VAR(EngineIDMapping, grfid, SLE_UINT32), + SLE_VAR(EngineIDMapping, internal_id, SLE_UINT16), + SLE_VAR(EngineIDMapping, type, SLE_UINT8), + SLE_VAR(EngineIDMapping, substitute_id, SLE_UINT8), +}; + +struct EIDSChunkHandler : ChunkHandler { + EIDSChunkHandler() : ChunkHandler('EIDS', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_engine_id_mapping_desc); + + uint index = 0; + for (EngineIDMapping &eid : _engine_mngr) { + SlSetArrayIndex(index); + SlObject(&eid, _engine_id_mapping_desc); + index++; + } + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_engine_id_mapping_desc, _engine_id_mapping_sl_compat); + + _engine_mngr.clear(); + + while (SlIterateArray() != -1) { + EngineIDMapping *eid = &_engine_mngr.emplace_back(); + SlObject(eid, slt); + } + } +}; + +static const EIDSChunkHandler EIDS; +static const ENGNChunkHandler ENGN; +static const ChunkHandlerRef engine_chunk_handlers[] = { + EIDS, + ENGN, +}; + +extern const ChunkHandlerTable _engine_chunk_handlers(engine_chunk_handlers); + +} diff --git a/src/saveload/upstream/game_sl.cpp b/src/saveload/upstream/game_sl.cpp new file mode 100644 index 0000000000..e6e583c065 --- /dev/null +++ b/src/saveload/upstream/game_sl.cpp @@ -0,0 +1,210 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file game_sl.cpp Handles the saveload part of the GameScripts */ + +#include "../../stdafx.h" +#include "../../debug.h" + +#include "saveload.h" +#include "compat/game_sl_compat.h" + +#include "../../string_func.h" +#include "../../game/game.hpp" +#include "../../game/game_config.hpp" +#include "../../network/network.h" +#include "../../game/game_instance.hpp" +#include "../../game/game_text.hpp" + +#include "../../safeguards.h" + +extern GameStrings *_current_data; + +namespace upstream_sl { + +static std::string _game_saveload_name; +static int _game_saveload_version; +static std::string _game_saveload_settings; +static bool _game_saveload_is_random; + +static const SaveLoad _game_script_desc[] = { + SLEG_SSTR("name", _game_saveload_name, SLE_STR), + SLEG_SSTR("settings", _game_saveload_settings, SLE_STR), + SLEG_VAR("version", _game_saveload_version, SLE_UINT32), + SLEG_VAR("is_random", _game_saveload_is_random, SLE_BOOL), +}; + +static void SaveReal_GSDT(int *index_ptr) +{ + GameConfig *config = GameConfig::GetConfig(); + + if (config->HasScript()) { + _game_saveload_name = config->GetName(); + _game_saveload_version = config->GetVersion(); + } else { + /* No GameScript is configured for this so store an empty string as name. */ + _game_saveload_name.clear(); + _game_saveload_version = -1; + } + + _game_saveload_is_random = config->IsRandom(); + _game_saveload_settings = config->SettingsToString(); + + SlObject(nullptr, _game_script_desc); + Game::Save(); +} + +struct GSDTChunkHandler : ChunkHandler { + GSDTChunkHandler() : ChunkHandler('GSDT', CH_TABLE) {} + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_game_script_desc, _game_script_sl_compat); + + /* Free all current data */ + GameConfig::GetConfig(GameConfig::SSS_FORCE_GAME)->Change(nullptr); + + if (SlIterateArray() == -1) return; + + _game_saveload_version = -1; + SlObject(nullptr, slt); + + if (_networking && !_network_server) { + GameInstance::LoadEmpty(); + if (SlIterateArray() != -1) SlErrorCorrupt("Too many GameScript configs"); + return; + } + + GameConfig *config = GameConfig::GetConfig(GameConfig::SSS_FORCE_GAME); + if (!_game_saveload_name.empty()) { + config->Change(_game_saveload_name.c_str(), _game_saveload_version, false, _game_saveload_is_random); + if (!config->HasScript()) { + /* No version of the GameScript available that can load the data. Try to load the + * latest version of the GameScript instead. */ + config->Change(_game_saveload_name.c_str(), -1, false, _game_saveload_is_random); + if (!config->HasScript()) { + if (_game_saveload_name.compare("%_dummy") != 0) { + DEBUG(script, 0, "The savegame has an GameScript by the name '%s', version %u which is no longer available.", _game_saveload_name.c_str(), _game_saveload_version); + DEBUG(script, 0, "This game will continue to run without GameScript."); + } else { + DEBUG(script, 0, "The savegame had no GameScript available at the time of saving."); + DEBUG(script, 0, "This game will continue to run without GameScript."); + } + } else { + DEBUG(script, 0, "The savegame has an GameScript by the name '%s', version %u which is no longer available.", _game_saveload_name.c_str(), _game_saveload_version); + DEBUG(script, 0, "The latest version of that GameScript has been loaded instead, but it'll not get the savegame data as it's incompatible."); + } + /* Make sure the GameScript doesn't get the saveload data, as it was not the + * writer of the saveload data in the first place */ + _game_saveload_version = -1; + } + } + + config->StringToSettings(_game_saveload_settings); + + /* Start the GameScript directly if it was active in the savegame */ + Game::StartNew(); + Game::Load(_game_saveload_version); + + if (SlIterateArray() != -1) SlErrorCorrupt("Too many GameScript configs"); + } + + void Save() const override + { + SlTableHeader(_game_script_desc); + SlSetArrayIndex(0); + SlAutolength((AutolengthProc *)SaveReal_GSDT, nullptr); + } +}; + +static std::string _game_saveload_string; +static uint32 _game_saveload_strings; + +class SlGameLanguageString : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLEG_SSTR("string", _game_saveload_string, SLE_STR | SLF_ALLOW_CONTROL), + }; + inline const static SaveLoadCompatTable compat_description = _game_language_string_sl_compat; + + void Save(LanguageStrings *ls) const override + { + SlSetStructListLength(ls->lines.size()); + + for (const auto &string : ls->lines) { + _game_saveload_string = string; + SlObject(nullptr, this->GetDescription()); + } + } + + void Load(LanguageStrings *ls) const override + { + uint32 length = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? _game_saveload_strings : (uint32)SlGetStructListLength(UINT32_MAX); + + for (uint32 i = 0; i < length; i++) { + SlObject(nullptr, this->GetLoadDescription()); + ls->lines.emplace_back(_game_saveload_string); + } + } +}; + +static const SaveLoad _game_language_desc[] = { + SLE_SSTR(LanguageStrings, language, SLE_STR), + SLEG_CONDVAR("count", _game_saveload_strings, SLE_UINT32, SL_MIN_VERSION, SLV_SAVELOAD_LIST_LENGTH), + SLEG_STRUCTLIST("strings", SlGameLanguageString), +}; + +struct GSTRChunkHandler : ChunkHandler { + GSTRChunkHandler() : ChunkHandler('GSTR', CH_TABLE) {} + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_game_language_desc, _game_language_sl_compat); + + delete _current_data; + _current_data = new GameStrings(); + + while (SlIterateArray() != -1) { + LanguageStrings ls; + SlObject(&ls, slt); + _current_data->raw_strings.push_back(std::move(ls)); + } + + /* If there were no strings in the savegame, set GameStrings to nullptr */ + if (_current_data->raw_strings.size() == 0) { + delete _current_data; + _current_data = nullptr; + return; + } + + _current_data->Compile(); + ReconsiderGameScriptLanguage(); + } + + void Save() const override + { + SlTableHeader(_game_language_desc); + + if (_current_data == nullptr) return; + + for (uint i = 0; i < _current_data->raw_strings.size(); i++) { + SlSetArrayIndex(i); + SlObject(&_current_data->raw_strings[i], _game_language_desc); + } + } +}; + +static const GSTRChunkHandler GSTR; +static const GSDTChunkHandler GSDT; +static const ChunkHandlerRef game_chunk_handlers[] = { + GSTR, + GSDT, +}; + +extern const ChunkHandlerTable _game_chunk_handlers(game_chunk_handlers); + +} diff --git a/src/saveload/upstream/gamelog_sl.cpp b/src/saveload/upstream/gamelog_sl.cpp new file mode 100644 index 0000000000..3622150439 --- /dev/null +++ b/src/saveload/upstream/gamelog_sl.cpp @@ -0,0 +1,416 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file gamelog_sl.cpp Code handling saving and loading of gamelog data */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "compat/gamelog_sl_compat.h" + +#include "../../gamelog_internal.h" +#include "../../fios.h" + +#include "../../safeguards.h" + +namespace upstream_sl { + +class SlGamelogMode : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_VAR(LoggedChange, mode.mode, SLE_UINT8), + SLE_VAR(LoggedChange, mode.landscape, SLE_UINT8), + }; + inline const static SaveLoadCompatTable compat_description = _gamelog_mode_sl_compat; + + void Save(LoggedChange *lc) const override + { + if (lc->ct != GLCT_MODE) return; + SlObject(lc, this->GetDescription()); + } + + void Load(LoggedChange *lc) const override + { + if (lc->ct != GLCT_MODE) return; + SlObject(lc, this->GetLoadDescription()); + } + + void LoadCheck(LoggedChange *lc) const override { this->Load(lc); } +}; + +class SlGamelogRevision : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_ARR(LoggedChange, revision.text, SLE_UINT8, GAMELOG_REVISION_LENGTH), + SLE_VAR(LoggedChange, revision.newgrf, SLE_UINT32), + SLE_VAR(LoggedChange, revision.slver, SLE_UINT16), + SLE_VAR(LoggedChange, revision.modified, SLE_UINT8), + }; + inline const static SaveLoadCompatTable compat_description = _gamelog_revision_sl_compat; + + void Save(LoggedChange *lc) const override + { + if (lc->ct != GLCT_REVISION) return; + SlObject(lc, this->GetDescription()); + } + + void Load(LoggedChange *lc) const override + { + if (lc->ct != GLCT_REVISION) return; + SlObject(lc, this->GetLoadDescription()); + } + + void LoadCheck(LoggedChange *lc) const override { this->Load(lc); } +}; + +class SlGamelogOldver : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_VAR(LoggedChange, oldver.type, SLE_UINT32), + SLE_VAR(LoggedChange, oldver.version, SLE_UINT32), + }; + inline const static SaveLoadCompatTable compat_description = _gamelog_oldver_sl_compat; + + void Save(LoggedChange *lc) const override + { + if (lc->ct != GLCT_OLDVER) return; + SlObject(lc, this->GetDescription()); + } + + void Load(LoggedChange *lc) const override + { + if (lc->ct != GLCT_OLDVER) return; + SlObject(lc, this->GetLoadDescription()); + } + + void LoadCheck(LoggedChange *lc) const override { this->Load(lc); } +}; + +class SlGamelogSetting : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_STR(LoggedChange, setting.name, SLE_STR, 128), + SLE_VAR(LoggedChange, setting.oldval, SLE_INT32), + SLE_VAR(LoggedChange, setting.newval, SLE_INT32), + }; + inline const static SaveLoadCompatTable compat_description = _gamelog_setting_sl_compat; + + void Save(LoggedChange *lc) const override + { + if (lc->ct != GLCT_SETTING) return; + SlObject(lc, this->GetDescription()); + } + + void Load(LoggedChange *lc) const override + { + if (lc->ct != GLCT_SETTING) return; + SlObject(lc, this->GetLoadDescription()); + } + + void LoadCheck(LoggedChange *lc) const override { this->Load(lc); } +}; + +class SlGamelogGrfadd : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_VAR(LoggedChange, grfadd.grfid, SLE_UINT32 ), + SLE_ARR(LoggedChange, grfadd.md5sum, SLE_UINT8, 16), + }; + inline const static SaveLoadCompatTable compat_description = _gamelog_grfadd_sl_compat; + + void Save(LoggedChange *lc) const override + { + if (lc->ct != GLCT_GRFADD) return; + SlObject(lc, this->GetDescription()); + } + + void Load(LoggedChange *lc) const override + { + if (lc->ct != GLCT_GRFADD) return; + SlObject(lc, this->GetLoadDescription()); + } + + void LoadCheck(LoggedChange *lc) const override { this->Load(lc); } +}; + +class SlGamelogGrfrem : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_VAR(LoggedChange, grfrem.grfid, SLE_UINT32), + }; + inline const static SaveLoadCompatTable compat_description = _gamelog_grfrem_sl_compat; + + void Save(LoggedChange *lc) const override + { + if (lc->ct != GLCT_GRFREM) return; + SlObject(lc, this->GetDescription()); + } + + void Load(LoggedChange *lc) const override + { + if (lc->ct != GLCT_GRFREM) return; + SlObject(lc, this->GetLoadDescription()); + } + + void LoadCheck(LoggedChange *lc) const override { this->Load(lc); } +}; + +class SlGamelogGrfcompat : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_VAR(LoggedChange, grfcompat.grfid, SLE_UINT32 ), + SLE_ARR(LoggedChange, grfcompat.md5sum, SLE_UINT8, 16), + }; + inline const static SaveLoadCompatTable compat_description = _gamelog_grfcompat_sl_compat; + + void Save(LoggedChange *lc) const override + { + if (lc->ct != GLCT_GRFCOMPAT) return; + SlObject(lc, this->GetDescription()); + } + + void Load(LoggedChange *lc) const override + { + if (lc->ct != GLCT_GRFCOMPAT) return; + SlObject(lc, this->GetLoadDescription()); + } + + void LoadCheck(LoggedChange *lc) const override { this->Load(lc); } +}; + +class SlGamelogGrfparam : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_VAR(LoggedChange, grfparam.grfid, SLE_UINT32), + }; + inline const static SaveLoadCompatTable compat_description = _gamelog_grfparam_sl_compat; + + void Save(LoggedChange *lc) const override + { + if (lc->ct != GLCT_GRFPARAM) return; + SlObject(lc, this->GetDescription()); + } + + void Load(LoggedChange *lc) const override + { + if (lc->ct != GLCT_GRFPARAM) return; + SlObject(lc, this->GetLoadDescription()); + } + + void LoadCheck(LoggedChange *lc) const override { this->Load(lc); } +}; + +class SlGamelogGrfmove : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_VAR(LoggedChange, grfmove.grfid, SLE_UINT32), + SLE_VAR(LoggedChange, grfmove.offset, SLE_INT32), + }; + inline const static SaveLoadCompatTable compat_description = _gamelog_grfmove_sl_compat; + + void Save(LoggedChange *lc) const override + { + if (lc->ct != GLCT_GRFMOVE) return; + SlObject(lc, this->GetDescription()); + } + + void Load(LoggedChange *lc) const override + { + if (lc->ct != GLCT_GRFMOVE) return; + SlObject(lc, this->GetLoadDescription()); + } + + void LoadCheck(LoggedChange *lc) const override { this->Load(lc); } +}; + +class SlGamelogGrfbug : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_VAR(LoggedChange, grfbug.data, SLE_UINT64), + SLE_VAR(LoggedChange, grfbug.grfid, SLE_UINT32), + SLE_VAR(LoggedChange, grfbug.bug, SLE_UINT8), + }; + inline const static SaveLoadCompatTable compat_description = _gamelog_grfbug_sl_compat; + + void Save(LoggedChange *lc) const override + { + if (lc->ct != GLCT_GRFBUG) return; + SlObject(lc, this->GetDescription()); + } + + void Load(LoggedChange *lc) const override + { + if (lc->ct != GLCT_GRFBUG) return; + SlObject(lc, this->GetLoadDescription()); + } + + void LoadCheck(LoggedChange *lc) const override { this->Load(lc); } +}; + +static bool _is_emergency_save = true; + +class SlGamelogEmergency : public DefaultSaveLoadHandler { +public: + /* We need to store something, so store a "true" value. */ + inline static const SaveLoad description[] = { + SLEG_CONDVAR("is_emergency_save", _is_emergency_save, SLE_BOOL, SLV_RIFF_TO_ARRAY, SL_MAX_VERSION), + }; + inline const static SaveLoadCompatTable compat_description = _gamelog_emergency_sl_compat; + + void Save(LoggedChange *lc) const override + { + if (lc->ct != GLCT_EMERGENCY) return; + + _is_emergency_save = true; + SlObject(lc, this->GetDescription()); + } + + void Load(LoggedChange *lc) const override + { + if (lc->ct != GLCT_EMERGENCY) return; + + SlObject(lc, this->GetLoadDescription()); + } + + void LoadCheck(LoggedChange *lc) const override { this->Load(lc); } +}; + +class SlGamelogAction : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_SAVEBYTE(LoggedChange, ct), + SLEG_STRUCT("mode", SlGamelogMode), + SLEG_STRUCT("revision", SlGamelogRevision), + SLEG_STRUCT("oldver", SlGamelogOldver), + SLEG_STRUCT("setting", SlGamelogSetting), + SLEG_STRUCT("grfadd", SlGamelogGrfadd), + SLEG_STRUCT("grfrem", SlGamelogGrfrem), + SLEG_STRUCT("grfcompat", SlGamelogGrfcompat), + SLEG_STRUCT("grfparam", SlGamelogGrfparam), + SLEG_STRUCT("grfmove", SlGamelogGrfmove), + SLEG_STRUCT("grfbug", SlGamelogGrfbug), + SLEG_STRUCT("emergency", SlGamelogEmergency), + }; + inline const static SaveLoadCompatTable compat_description = _gamelog_action_sl_compat; + + void Save(LoggedAction *la) const override + { + SlSetStructListLength(la->changes); + + const LoggedChange *lcend = &la->change[la->changes]; + for (LoggedChange *lc = la->change; lc != lcend; lc++) { + assert((uint)lc->ct < GLCT_END); + SlObject(lc, this->GetDescription()); + } + } + + void Load(LoggedAction *la) const override + { + if (IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY)) { + byte type; + while ((type = SlReadByte()) != GLCT_NONE) { + if (type >= GLCT_END) SlErrorCorrupt("Invalid gamelog change type"); + GamelogChangeType ct = (GamelogChangeType)type; + + la->change = ReallocT(la->change, la->changes + 1); + + LoggedChange *lc = &la->change[la->changes++]; + memset(lc, 0, sizeof(*lc)); + lc->ct = ct; + + SlObject(lc, this->GetLoadDescription()); + } + return; + } + + size_t length = SlGetStructListLength(UINT32_MAX); + la->change = ReallocT(la->change, length); + + for (size_t i = 0; i < length; i++) { + LoggedChange *lc = &la->change[i]; + memset(lc, 0, sizeof(*lc)); + + lc->ct = (GamelogChangeType)SlReadByte(); + SlObject(lc, this->GetLoadDescription()); + } + } + + void LoadCheck(LoggedAction *la) const override { this->Load(la); } +}; + +static const SaveLoad _gamelog_desc[] = { + SLE_CONDVAR(LoggedAction, at, SLE_UINT8, SLV_RIFF_TO_ARRAY, SL_MAX_VERSION), + SLE_VAR(LoggedAction, tick, SLE_UINT16), + SLEG_STRUCTLIST("action", SlGamelogAction), +}; + +struct GLOGChunkHandler : ChunkHandler { + GLOGChunkHandler() : ChunkHandler('GLOG', CH_TABLE) {} + + void LoadCommon(LoggedAction *&gamelog_action, uint &gamelog_actions) const + { + assert(gamelog_action == nullptr); + assert(gamelog_actions == 0); + + const std::vector slt = SlCompatTableHeader(_gamelog_desc, _gamelog_sl_compat); + + if (IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY)) { + byte type; + while ((type = SlReadByte()) != GLAT_NONE) { + if (type >= GLAT_END) SlErrorCorrupt("Invalid gamelog action type"); + + gamelog_action = ReallocT(gamelog_action, gamelog_actions + 1); + LoggedAction *la = &gamelog_action[gamelog_actions++]; + memset(la, 0, sizeof(*la)); + + la->at = (GamelogActionType)type; + SlObject(la, slt); + } + return; + } + + while (SlIterateArray() != -1) { + gamelog_action = ReallocT(gamelog_action, gamelog_actions + 1); + LoggedAction *la = &gamelog_action[gamelog_actions++]; + memset(la, 0, sizeof(*la)); + + SlObject(la, slt); + } + } + + void Save() const override + { + SlTableHeader(_gamelog_desc); + + const LoggedAction *laend = &_gamelog_action[_gamelog_actions]; + + uint i = 0; + for (LoggedAction *la = _gamelog_action; la != laend; la++, i++) { + SlSetArrayIndex(i); + SlObject(la, _gamelog_desc); + } + } + + void Load() const override + { + this->LoadCommon(_gamelog_action, _gamelog_actions); + } + + void LoadCheck(size_t) const override + { + this->LoadCommon(_load_check_data.gamelog_action, _load_check_data.gamelog_actions); + } +}; + +static const GLOGChunkHandler GLOG; +static const ChunkHandlerRef gamelog_chunk_handlers[] = { + GLOG, +}; + +extern const ChunkHandlerTable _gamelog_chunk_handlers(gamelog_chunk_handlers); + +} diff --git a/src/saveload/upstream/goal_sl.cpp b/src/saveload/upstream/goal_sl.cpp new file mode 100644 index 0000000000..6c1a198a9c --- /dev/null +++ b/src/saveload/upstream/goal_sl.cpp @@ -0,0 +1,62 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file goal_sl.cpp Code handling saving and loading of goals */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "compat/goal_sl_compat.h" + +#include "../../goal_base.h" + +#include "../../safeguards.h" + +namespace upstream_sl { + +static const SaveLoad _goals_desc[] = { + SLE_VAR(Goal, company, SLE_FILE_U16 | SLE_VAR_U8), + SLE_VAR(Goal, type, SLE_FILE_U16 | SLE_VAR_U8), + SLE_VAR(Goal, dst, SLE_UINT32), + SLE_STR(Goal, text, SLE_STR | SLF_ALLOW_CONTROL, 0), + SLE_CONDSTR(Goal, progress, SLE_STR | SLF_ALLOW_CONTROL, 0, SLV_182, SL_MAX_VERSION), + SLE_CONDVAR(Goal, completed, SLE_BOOL, SLV_182, SL_MAX_VERSION), +}; + +struct GOALChunkHandler : ChunkHandler { + GOALChunkHandler() : ChunkHandler('GOAL', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_goals_desc); + + for (Goal *s : Goal::Iterate()) { + SlSetArrayIndex(s->index); + SlObject(s, _goals_desc); + } + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_goals_desc, _goals_sl_compat); + + int index; + while ((index = SlIterateArray()) != -1) { + Goal *s = new (index) Goal(); + SlObject(s, slt); + } + } +}; + +static const GOALChunkHandler GOAL; +static const ChunkHandlerRef goal_chunk_handlers[] = { + GOAL, +}; + +extern const ChunkHandlerTable _goal_chunk_handlers(goal_chunk_handlers); + +} diff --git a/src/saveload/upstream/group_sl.cpp b/src/saveload/upstream/group_sl.cpp new file mode 100644 index 0000000000..d70eb9f363 --- /dev/null +++ b/src/saveload/upstream/group_sl.cpp @@ -0,0 +1,75 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file group_sl.cpp Code handling saving and loading of economy data */ + +#include "../../stdafx.h" +#include "../../group.h" +#include "../../company_base.h" + +#include "saveload.h" +#include "compat/group_sl_compat.h" + +#include "../../safeguards.h" + +namespace upstream_sl { + +static const SaveLoad _group_desc[] = { + SLE_CONDVAR(Group, name, SLE_NAME, SL_MIN_VERSION, SLV_84), + SLE_CONDSSTR(Group, name, SLE_STR | SLF_ALLOW_CONTROL, SLV_84, SL_MAX_VERSION), + SLE_VAR(Group, owner, SLE_UINT8), + SLE_VAR(Group, vehicle_type, SLE_UINT8), + SLE_VAR(Group, flags, SLE_UINT8), + SLE_CONDVAR(Group, livery.in_use, SLE_UINT8, SLV_GROUP_LIVERIES, SL_MAX_VERSION), + SLE_CONDVAR(Group, livery.colour1, SLE_UINT8, SLV_GROUP_LIVERIES, SL_MAX_VERSION), + SLE_CONDVAR(Group, livery.colour2, SLE_UINT8, SLV_GROUP_LIVERIES, SL_MAX_VERSION), + SLE_CONDVAR(Group, parent, SLE_UINT16, SLV_189, SL_MAX_VERSION), +}; + +struct GRPSChunkHandler : ChunkHandler { + GRPSChunkHandler() : ChunkHandler('GRPS', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_group_desc); + + for (Group *g : Group::Iterate()) { + SlSetArrayIndex(g->index); + SlObject(g, _group_desc); + } + } + + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_group_desc, _group_sl_compat); + + int index; + + while ((index = SlIterateArray()) != -1) { + Group *g = new (index) Group(); + SlObject(g, slt); + + if (IsSavegameVersionBefore(SLV_189)) g->parent = INVALID_GROUP; + + if (IsSavegameVersionBefore(SLV_GROUP_LIVERIES)) { + const Company *c = Company::Get(g->owner); + g->livery.colour1 = c->livery[LS_DEFAULT].colour1; + g->livery.colour2 = c->livery[LS_DEFAULT].colour2; + } + } + } +}; + +static const GRPSChunkHandler GRPS; +static const ChunkHandlerRef group_chunk_handlers[] = { + GRPS, +}; + +extern const ChunkHandlerTable _group_chunk_handlers(group_chunk_handlers); + +} diff --git a/src/saveload/upstream/industry_sl.cpp b/src/saveload/upstream/industry_sl.cpp new file mode 100644 index 0000000000..8a58ac043e --- /dev/null +++ b/src/saveload/upstream/industry_sl.cpp @@ -0,0 +1,212 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file industry_sl.cpp Code handling saving and loading of industries */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "compat/industry_sl_compat.h" + +#include "../../industry.h" +#include "newgrf_sl.h" + +#include "../../safeguards.h" + +namespace upstream_sl { + +static OldPersistentStorage _old_ind_persistent_storage; + +static const SaveLoad _industry_desc[] = { + SLE_CONDVAR(Industry, location.tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), + SLE_CONDVAR(Industry, location.tile, SLE_UINT32, SLV_6, SL_MAX_VERSION), + SLE_VAR(Industry, location.w, SLE_FILE_U8 | SLE_VAR_U16), + SLE_VAR(Industry, location.h, SLE_FILE_U8 | SLE_VAR_U16), + SLE_REF(Industry, town, REF_TOWN), + SLE_CONDREF(Industry, neutral_station, REF_STATION, SLV_SERVE_NEUTRAL_INDUSTRIES, SL_MAX_VERSION), + SLE_CONDARR(Industry, produced_cargo, SLE_UINT8, 2, SLV_78, SLV_EXTEND_INDUSTRY_CARGO_SLOTS), + SLE_CONDARR(Industry, produced_cargo, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION), + SLE_CONDARR(Industry, incoming_cargo_waiting, SLE_UINT16, 3, SLV_70, SLV_EXTEND_INDUSTRY_CARGO_SLOTS), + SLE_CONDARR(Industry, incoming_cargo_waiting, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION), + SLE_CONDARR(Industry, produced_cargo_waiting, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS), + SLE_CONDARR(Industry, produced_cargo_waiting, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION), + SLE_CONDARR(Industry, production_rate, SLE_UINT8, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS), + SLE_CONDARR(Industry, production_rate, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION), + SLE_CONDARR(Industry, accepts_cargo, SLE_UINT8, 3, SLV_78, SLV_EXTEND_INDUSTRY_CARGO_SLOTS), + SLE_CONDARR(Industry, accepts_cargo, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION), + SLE_VAR(Industry, prod_level, SLE_UINT8), + SLE_CONDARR(Industry, this_month_production, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS), + SLE_CONDARR(Industry, this_month_production, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION), + SLE_CONDARR(Industry, this_month_transported, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS), + SLE_CONDARR(Industry, this_month_transported, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION), + SLE_CONDARR(Industry, last_month_pct_transported, SLE_UINT8, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS), + SLE_CONDARR(Industry, last_month_pct_transported, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION), + SLE_CONDARR(Industry, last_month_production, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS), + SLE_CONDARR(Industry, last_month_production, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION), + SLE_CONDARR(Industry, last_month_transported, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS), + SLE_CONDARR(Industry, last_month_transported, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION), + + SLE_VAR(Industry, counter, SLE_UINT16), + + SLE_VAR(Industry, type, SLE_UINT8), + SLE_VAR(Industry, owner, SLE_UINT8), + SLE_VAR(Industry, random_colour, SLE_UINT8), + SLE_CONDVAR(Industry, last_prod_year, SLE_FILE_U8 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31), + SLE_CONDVAR(Industry, last_prod_year, SLE_INT32, SLV_31, SL_MAX_VERSION), + SLE_VAR(Industry, was_cargo_delivered, SLE_UINT8), + SLE_CONDVAR(Industry, ctlflags, SLE_UINT8, SLV_GS_INDUSTRY_CONTROL, SL_MAX_VERSION), + + SLE_CONDVAR(Industry, founder, SLE_UINT8, SLV_70, SL_MAX_VERSION), + SLE_CONDVAR(Industry, construction_date, SLE_INT32, SLV_70, SL_MAX_VERSION), + SLE_CONDVAR(Industry, construction_type, SLE_UINT8, SLV_70, SL_MAX_VERSION), + SLE_CONDVAR(Industry, last_cargo_accepted_at[0], SLE_INT32, SLV_70, SLV_EXTEND_INDUSTRY_CARGO_SLOTS), + SLE_CONDARR(Industry, last_cargo_accepted_at, SLE_INT32, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION), + SLE_CONDVAR(Industry, selected_layout, SLE_UINT8, SLV_73, SL_MAX_VERSION), + SLE_CONDVAR(Industry, exclusive_supplier, SLE_UINT8, SLV_GS_INDUSTRY_CONTROL, SL_MAX_VERSION), + SLE_CONDVAR(Industry, exclusive_consumer, SLE_UINT8, SLV_GS_INDUSTRY_CONTROL, SL_MAX_VERSION), + + SLEG_CONDARR("storage", _old_ind_persistent_storage.storage, SLE_UINT32, 16, SLV_76, SLV_161), + SLE_CONDREF(Industry, psa, REF_STORAGE, SLV_161, SL_MAX_VERSION), + + SLE_CONDVAR(Industry, random, SLE_UINT16, SLV_82, SL_MAX_VERSION), + SLE_CONDSSTR(Industry, text, SLE_STR | SLF_ALLOW_CONTROL, SLV_INDUSTRY_TEXT, SL_MAX_VERSION), +}; + +struct INDYChunkHandler : ChunkHandler { + INDYChunkHandler() : ChunkHandler('INDY', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_industry_desc); + + /* Write the industries */ + for (Industry *ind : Industry::Iterate()) { + SlSetArrayIndex(ind->index); + SlObject(ind, _industry_desc); + } + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_industry_desc, _industry_sl_compat); + + int index; + + Industry::ResetIndustryCounts(); + + while ((index = SlIterateArray()) != -1) { + Industry *i = new (index) Industry(); + SlObject(i, slt); + + /* Before savegame version 161, persistent storages were not stored in a pool. */ + if (IsSavegameVersionBefore(SLV_161) && !IsSavegameVersionBefore(SLV_76)) { + /* Store the old persistent storage. The GRFID will be added later. */ + assert(PersistentStorage::CanAllocateItem()); + i->psa = new PersistentStorage(0, 0, 0); + memcpy(i->psa->storage, _old_ind_persistent_storage.storage, sizeof(_old_ind_persistent_storage.storage)); + } + Industry::IncIndustryTypeCount(i->type); + } + } + + void FixPointers() const override + { + for (Industry *i : Industry::Iterate()) { + SlObject(i, _industry_desc); + } + } +}; + +struct IIDSChunkHandler : NewGRFMappingChunkHandler { + IIDSChunkHandler() : NewGRFMappingChunkHandler('IIDS', _industry_mngr) {} +}; + +struct TIDSChunkHandler : NewGRFMappingChunkHandler { + TIDSChunkHandler() : NewGRFMappingChunkHandler('TIDS', _industile_mngr) {} +}; + +/** Description of the data to save and load in #IndustryBuildData. */ +static const SaveLoad _industry_builder_desc[] = { + SLEG_VAR("wanted_inds", _industry_builder.wanted_inds, SLE_UINT32), +}; + +/** Industry builder. */ +struct IBLDChunkHandler : ChunkHandler { + IBLDChunkHandler() : ChunkHandler('IBLD', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_industry_builder_desc); + + SlSetArrayIndex(0); + SlGlobList(_industry_builder_desc); + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_industry_builder_desc, _industry_builder_sl_compat); + + if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() == -1) return; + SlGlobList(slt); + if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many IBLD entries"); + } +}; + +/** Description of the data to save and load in #IndustryTypeBuildData. */ +static const SaveLoad _industrytype_builder_desc[] = { + SLE_VAR(IndustryTypeBuildData, probability, SLE_UINT32), + SLE_VAR(IndustryTypeBuildData, min_number, SLE_UINT8), + SLE_VAR(IndustryTypeBuildData, target_count, SLE_UINT16), + SLE_VAR(IndustryTypeBuildData, max_wait, SLE_UINT16), + SLE_VAR(IndustryTypeBuildData, wait_count, SLE_UINT16), +}; + +/** Industry-type build data. */ +struct ITBLChunkHandler : ChunkHandler { + ITBLChunkHandler() : ChunkHandler('ITBL', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_industrytype_builder_desc); + + for (int i = 0; i < NUM_INDUSTRYTYPES; i++) { + SlSetArrayIndex(i); + SlObject(_industry_builder.builddata + i, _industrytype_builder_desc); + } + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_industrytype_builder_desc, _industrytype_builder_sl_compat); + + for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { + _industry_builder.builddata[it].Reset(); + } + int index; + while ((index = SlIterateArray()) != -1) { + if ((uint)index >= NUM_INDUSTRYTYPES) SlErrorCorrupt("Too many industry builder datas"); + SlObject(_industry_builder.builddata + index, slt); + } + } +}; + +static const INDYChunkHandler INDY; +static const IIDSChunkHandler IIDS; +static const TIDSChunkHandler TIDS; +static const IBLDChunkHandler IBLD; +static const ITBLChunkHandler ITBL; +static const ChunkHandlerRef industry_chunk_handlers[] = { + INDY, + IIDS, + TIDS, + IBLD, + ITBL, +}; + +extern const ChunkHandlerTable _industry_chunk_handlers(industry_chunk_handlers); + +} diff --git a/src/saveload/upstream/labelmaps_sl.cpp b/src/saveload/upstream/labelmaps_sl.cpp new file mode 100644 index 0000000000..9bc1acdb2f --- /dev/null +++ b/src/saveload/upstream/labelmaps_sl.cpp @@ -0,0 +1,74 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file labelmaps_sl.cpp Code handling saving and loading of rail type label mappings */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "compat/labelmaps_sl_compat.h" + +#include "../../station_map.h" +#include "../../tunnelbridge_map.h" + +#include "../../safeguards.h" + +void ResetLabelMaps(); + +extern std::vector _railtype_list; + +namespace upstream_sl { + +/** Container for a label for SaveLoad system */ +struct LabelObject { + uint32 label; +}; + +static const SaveLoad _label_object_desc[] = { + SLE_VAR(LabelObject, label, SLE_UINT32), +}; + +struct RAILChunkHandler : ChunkHandler { + RAILChunkHandler() : ChunkHandler('RAIL', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_label_object_desc); + + LabelObject lo; + + for (RailType r = RAILTYPE_BEGIN; r != RAILTYPE_END; r++) { + lo.label = GetRailTypeInfo(r)->label; + + SlSetArrayIndex(r); + SlObject(&lo, _label_object_desc); + } + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_label_object_desc, _label_object_sl_compat); + + ResetLabelMaps(); + + LabelObject lo; + + while (SlIterateArray() != -1) { + SlObject(&lo, slt); + _railtype_list.push_back((RailTypeLabel)lo.label); + } + } +}; + +static const RAILChunkHandler RAIL; +static const ChunkHandlerRef labelmaps_chunk_handlers[] = { + RAIL, +}; + +extern const ChunkHandlerTable _labelmaps_chunk_handlers(labelmaps_chunk_handlers); + +} diff --git a/src/saveload/upstream/linkgraph_sl.cpp b/src/saveload/upstream/linkgraph_sl.cpp new file mode 100644 index 0000000000..8c06894644 --- /dev/null +++ b/src/saveload/upstream/linkgraph_sl.cpp @@ -0,0 +1,331 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file linkgraph_sl.cpp Code handling saving and loading of link graphs */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "compat/linkgraph_sl_compat.h" + +#include "../../linkgraph/linkgraph.h" +#include "../../linkgraph/linkgraphjob.h" +#include "../../linkgraph/linkgraphschedule.h" +#include "../../network/network.h" + +#include "../../safeguards.h" + +namespace upstream_sl { + +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_VAR(Edge, capacity, SLE_UINT32), + SLE_VAR(Edge, usage, SLE_UINT32), + //SLE_CONDVAR(Edge, travel_time_sum, SLE_UINT64, SLV_LINKGRAPH_TRAVEL_TIME, SL_MAX_VERSION), + 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), + }; + inline const static SaveLoadCompatTable compat_description = _linkgraph_edge_sl_compat; + + void Save(Node *bn) const override + { + uint16 size = 0; + for (NodeID to = _linkgraph_from; to != INVALID_NODE; to = _linkgraph->edges[_linkgraph_from][to].next_edge) { + size++; + } + + SlSetStructListLength(size); + for (NodeID to = _linkgraph_from; to != INVALID_NODE; to = _linkgraph->edges[_linkgraph_from][to].next_edge) { + SlObject(&_linkgraph->edges[_linkgraph_from][to], this->GetDescription()); + } + } + + 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->GetLoadDescription()); + } + return; + } + + size_t used_size = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? max_size : SlGetStructListLength(UINT16_MAX); + + /* ... but as that wasted a lot of space we save a sparse matrix now. */ + for (NodeID to = _linkgraph_from; to != INVALID_NODE; to = _linkgraph->edges[_linkgraph_from][to].next_edge) { + if (used_size == 0) SlErrorCorrupt("Link graph structure overflow"); + used_size--; + + if (to >= max_size) SlErrorCorrupt("Link graph structure overflow"); + SlObject(&_linkgraph->edges[_linkgraph_from][to], this->GetLoadDescription()); + } + + if (!IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) && used_size > 0) SlErrorCorrupt("Corrupted link graph"); + } +}; + +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("edges", SlLinkgraphEdge), + }; + inline const static SaveLoadCompatTable compat_description = _linkgraph_node_sl_compat; + + void Save(LinkGraph *lg) const override + { + _linkgraph = lg; + + SlSetStructListLength(lg->Size()); + 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; + + uint16 length = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? _num_nodes : (uint16)SlGetStructListLength(UINT16_MAX); + lg->Init(length); + for (NodeID from = 0; from < length; ++from) { + _linkgraph_from = from; + SlObject(&lg->nodes[from], this->GetLoadDescription()); + } + } +}; + +/** + * Get a SaveLoad array for a link graph. + * @return SaveLoad array for link graph. + */ +SaveLoadTable GetLinkGraphDesc() +{ + static const SaveLoad link_graph_desc[] = { + SLE_VAR(LinkGraph, last_compression, SLE_INT32), + SLEG_CONDVAR("num_nodes", _num_nodes, SLE_UINT16, SL_MIN_VERSION, SLV_SAVELOAD_LIST_LENGTH), + SLE_VAR(LinkGraph, cargo, SLE_UINT8), + SLEG_STRUCTLIST("nodes", 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(); } + inline const static SaveLoadCompatTable compat_description = _linkgraph_sl_compat; + + void Save(LinkGraphJob *lgj) const override + { + SlObject(const_cast(&lgj->Graph()), this->GetDescription()); + } + + void Load(LinkGraphJob *lgj) const override + { + SlObject(const_cast(&lgj->Graph()), this->GetLoadDescription()); + } +}; + +/** + * 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 + * is called the first time. + * It's necessary to keep a copy of the settings for each link graph job so that you can + * change the settings while in-game and still not mess with current link graph runs. + * Of course the settings have to be saved and loaded, too, to avoid desyncs. + * @return Array of SaveLoad structs. + */ +SaveLoadTable GetLinkGraphJobDesc() +{ + static const SaveLoad job_desc[] = { + SLE_VAR2(LinkGraphJob, "linkgraph.recalc_interval", settings.recalc_interval, SLE_UINT16), + SLE_VAR2(LinkGraphJob, "linkgraph.recalc_time", settings.recalc_time, SLE_UINT16), + SLE_VAR2(LinkGraphJob, "linkgraph.distribution_pax", settings.distribution_pax, SLE_UINT8), + SLE_VAR2(LinkGraphJob, "linkgraph.distribution_mail", settings.distribution_mail, SLE_UINT8), + SLE_VAR2(LinkGraphJob, "linkgraph.distribution_armoured", settings.distribution_armoured, SLE_UINT8), + SLE_VAR2(LinkGraphJob, "linkgraph.distribution_default", settings.distribution_default, SLE_UINT8), + SLE_VAR2(LinkGraphJob, "linkgraph.accuracy", settings.accuracy, SLE_UINT8), + SLE_VAR2(LinkGraphJob, "linkgraph.demand_distance", settings.demand_distance, SLE_UINT8), + SLE_VAR2(LinkGraphJob, "linkgraph.demand_size", settings.demand_size, SLE_UINT8), + SLE_VAR2(LinkGraphJob, "linkgraph.short_path_saturation", settings.short_path_saturation, SLE_UINT8), + + SLE_VAR2(LinkGraphJob, "join_date", join_date_ticks, SLE_INT32), + SLE_VAR(LinkGraphJob, link_graph.index, SLE_UINT16), + SLEG_STRUCT("linkgraph", SlLinkgraphJobProxy), + }; + + return job_desc; +} + +/** + * Get a SaveLoad array for the link graph schedule. + * @return SaveLoad array for the link graph schedule. + */ +SaveLoadTable GetLinkGraphScheduleDesc() +{ + static const SaveLoad schedule_desc[] = { + SLE_REFLIST(LinkGraphSchedule, schedule, REF_LINK_GRAPH), + SLE_REFLIST(LinkGraphSchedule, running, REF_LINK_GRAPH_JOB), + }; + return schedule_desc; +} + +/** + * Spawn the threads for running link graph calculations. + * Has to be done after loading as the cargo classes might have changed. + */ +void AfterLoadLinkGraphs() +{ + if (IsSavegameVersionBefore(SLV_191)) { + for (LinkGraph *lg : LinkGraph::Iterate()) { + for (NodeID node_id = 0; node_id < lg->Size(); ++node_id) { + const Station *st = Station::GetIfValid((*lg)[node_id].Station()); + if (st != nullptr) (*lg)[node_id].UpdateLocation(st->xy); + } + } + + for (LinkGraphJob *lgj : LinkGraphJob::Iterate()) { + LinkGraph *lg = &(const_cast(lgj->Graph())); + for (NodeID node_id = 0; node_id < lg->Size(); ++node_id) { + const Station *st = Station::GetIfValid((*lg)[node_id].Station()); + if (st != nullptr) (*lg)[node_id].UpdateLocation(st->xy); + } + } + } + for (LinkGraphJob *lgj : LinkGraphJob::Iterate()) { + GetLinkGraphJobDayLengthScaleAfterLoad(lgj); + } + + LinkGraphSchedule::instance.SpawnAll(); + + if (!_networking || _network_server) { + AfterLoad_LinkGraphPauseControl(); + } +} + +/** + * All link graphs. + */ +struct LGRPChunkHandler : ChunkHandler { + LGRPChunkHandler() : ChunkHandler('LGRP', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(GetLinkGraphDesc()); + + for (LinkGraph *lg : LinkGraph::Iterate()) { + SlSetArrayIndex(lg->index); + SlObject(lg, GetLinkGraphDesc()); + } + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(GetLinkGraphDesc(), _linkgraph_sl_compat); + + int index; + while ((index = SlIterateArray()) != -1) { + LinkGraph *lg = new (index) LinkGraph(); + SlObject(lg, slt); + } + } +}; + +/** + * All link graph jobs. + */ +struct LGRJChunkHandler : ChunkHandler { + LGRJChunkHandler() : ChunkHandler('LGRJ', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(GetLinkGraphJobDesc()); + + for (LinkGraphJob *lgj : LinkGraphJob::Iterate()) { + SlSetArrayIndex(lgj->index); + SlObject(lgj, GetLinkGraphJobDesc()); + } + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(GetLinkGraphJobDesc(), _linkgraph_job_sl_compat); + + int index; + while ((index = SlIterateArray()) != -1) { + LinkGraphJob *lgj = new (index) LinkGraphJob(); + SlObject(lgj, slt); + } + } +}; + +/** + * Link graph schedule. + */ +struct LGRSChunkHandler : ChunkHandler { + LGRSChunkHandler() : ChunkHandler('LGRS', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(GetLinkGraphScheduleDesc()); + + SlSetArrayIndex(0); + SlObject(&LinkGraphSchedule::instance, GetLinkGraphScheduleDesc()); + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(GetLinkGraphScheduleDesc(), _linkgraph_schedule_sl_compat); + + if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() == -1) return; + SlObject(&LinkGraphSchedule::instance, slt); + if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many LGRS entries"); + } + + void FixPointers() const override + { + SlObject(&LinkGraphSchedule::instance, GetLinkGraphScheduleDesc()); + } +}; + +static const LGRPChunkHandler LGRP; +static const LGRJChunkHandler LGRJ; +static const LGRSChunkHandler LGRS; +static const ChunkHandlerRef linkgraph_chunk_handlers[] = { + LGRP, + LGRJ, + LGRS, +}; + +extern const ChunkHandlerTable _linkgraph_chunk_handlers(linkgraph_chunk_handlers); + +} diff --git a/src/saveload/upstream/map_sl.cpp b/src/saveload/upstream/map_sl.cpp new file mode 100644 index 0000000000..ba477d8f76 --- /dev/null +++ b/src/saveload/upstream/map_sl.cpp @@ -0,0 +1,385 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file map_sl.cpp Code handling saving and loading of map */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "compat/map_sl_compat.h" + +#include "../../map_func.h" +#include "../../core/bitmath_func.hpp" +#include "../../fios.h" +#include + +#include "../../safeguards.h" + +namespace upstream_sl { + +static uint32 _map_dim_x; +static uint32 _map_dim_y; + +static const SaveLoad _map_desc[] = { + SLEG_CONDVAR("dim_x", _map_dim_x, SLE_UINT32, SLV_6, SL_MAX_VERSION), + SLEG_CONDVAR("dim_y", _map_dim_y, SLE_UINT32, SLV_6, SL_MAX_VERSION), +}; + +struct MAPSChunkHandler : ChunkHandler { + MAPSChunkHandler() : ChunkHandler('MAPS', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_map_desc); + + _map_dim_x = MapSizeX(); + _map_dim_y = MapSizeY(); + + SlSetArrayIndex(0); + SlGlobList(_map_desc); + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_map_desc, _map_sl_compat); + + if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() == -1) return; + SlGlobList(slt); + if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many MAPS entries"); + + AllocateMap(_map_dim_x, _map_dim_y); + } + + void LoadCheck(size_t) const override + { + const std::vector slt = SlCompatTableHeader(_map_desc, _map_sl_compat); + + if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() == -1) return; + SlGlobList(slt); + if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many MAPS entries"); + + _load_check_data.map_size_x = _map_dim_x; + _load_check_data.map_size_y = _map_dim_y; + } +}; + +static const uint MAP_SL_BUF_SIZE = 4096; + +struct MAPTChunkHandler : ChunkHandler { + MAPTChunkHandler() : ChunkHandler('MAPT', CH_RIFF) {} + + void Load() const override + { + std::array buf; + TileIndex size = MapSize(); + + for (TileIndex i = 0; i != size;) { + SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].type = buf[j]; + } + } + + void Save() const override + { + std::array buf; + TileIndex size = MapSize(); + + SlSetLength(size); + for (TileIndex i = 0; i != size;) { + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].type; + SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); + } + } +}; + +struct MAPHChunkHandler : ChunkHandler { + MAPHChunkHandler() : ChunkHandler('MAPH', CH_RIFF) {} + + void Load() const override + { + std::array buf; + TileIndex size = MapSize(); + + for (TileIndex i = 0; i != size;) { + SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].height = buf[j]; + } + } + + void Save() const override + { + std::array buf; + TileIndex size = MapSize(); + + SlSetLength(size); + for (TileIndex i = 0; i != size;) { + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].height; + SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); + } + } +}; + +struct MAPOChunkHandler : ChunkHandler { + MAPOChunkHandler() : ChunkHandler('MAPO', CH_RIFF) {} + + void Load() const override + { + std::array buf; + TileIndex size = MapSize(); + + for (TileIndex i = 0; i != size;) { + SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m1 = buf[j]; + } + } + + void Save() const override + { + std::array buf; + TileIndex size = MapSize(); + + SlSetLength(size); + for (TileIndex i = 0; i != size;) { + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m1; + SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); + } + } +}; + +struct MAP2ChunkHandler : ChunkHandler { + MAP2ChunkHandler() : ChunkHandler('MAP2', CH_RIFF) {} + + void Load() const override + { + std::array buf; + TileIndex size = MapSize(); + + for (TileIndex i = 0; i != size;) { + SlCopy(buf.data(), MAP_SL_BUF_SIZE, + /* In those versions the m2 was 8 bits */ + IsSavegameVersionBefore(SLV_5) ? SLE_FILE_U8 | SLE_VAR_U16 : SLE_UINT16 + ); + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m2 = buf[j]; + } + } + + void Save() const override + { + std::array buf; + TileIndex size = MapSize(); + + SlSetLength(size * sizeof(uint16)); + for (TileIndex i = 0; i != size;) { + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m2; + SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT16); + } + } +}; + +struct M3LOChunkHandler : ChunkHandler { + M3LOChunkHandler() : ChunkHandler('M3LO', CH_RIFF) {} + + void Load() const override + { + std::array buf; + TileIndex size = MapSize(); + + for (TileIndex i = 0; i != size;) { + SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m3 = buf[j]; + } + } + + void Save() const override + { + std::array buf; + TileIndex size = MapSize(); + + SlSetLength(size); + for (TileIndex i = 0; i != size;) { + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m3; + SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); + } + } +}; + +struct M3HIChunkHandler : ChunkHandler { + M3HIChunkHandler() : ChunkHandler('M3HI', CH_RIFF) {} + + void Load() const override + { + std::array buf; + TileIndex size = MapSize(); + + for (TileIndex i = 0; i != size;) { + SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m4 = buf[j]; + } + } + + void Save() const override + { + std::array buf; + TileIndex size = MapSize(); + + SlSetLength(size); + for (TileIndex i = 0; i != size;) { + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m4; + SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); + } + } +}; + +struct MAP5ChunkHandler : ChunkHandler { + MAP5ChunkHandler() : ChunkHandler('MAP5', CH_RIFF) {} + + void Load() const override + { + std::array buf; + TileIndex size = MapSize(); + + for (TileIndex i = 0; i != size;) { + SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m5 = buf[j]; + } + } + + void Save() const override + { + std::array buf; + TileIndex size = MapSize(); + + SlSetLength(size); + for (TileIndex i = 0; i != size;) { + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m5; + SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); + } + } +}; + +struct MAPEChunkHandler : ChunkHandler { + MAPEChunkHandler() : ChunkHandler('MAPE', CH_RIFF) {} + + void Load() const override + { + std::array buf; + TileIndex size = MapSize(); + + if (IsSavegameVersionBefore(SLV_42)) { + for (TileIndex i = 0; i != size;) { + /* 1024, otherwise we overflow on 64x64 maps! */ + SlCopy(buf.data(), 1024, SLE_UINT8); + for (uint j = 0; j != 1024; j++) { + _me[i++].m6 = GB(buf[j], 0, 2); + _me[i++].m6 = GB(buf[j], 2, 2); + _me[i++].m6 = GB(buf[j], 4, 2); + _me[i++].m6 = GB(buf[j], 6, 2); + } + } + } else { + for (TileIndex i = 0; i != size;) { + SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _me[i++].m6 = buf[j]; + } + } + } + + void Save() const override + { + std::array buf; + TileIndex size = MapSize(); + + SlSetLength(size); + for (TileIndex i = 0; i != size;) { + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _me[i++].m6; + SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); + } + } +}; + +struct MAP7ChunkHandler : ChunkHandler { + MAP7ChunkHandler() : ChunkHandler('MAP7', CH_RIFF) {} + + void Load() const override + { + std::array buf; + TileIndex size = MapSize(); + + for (TileIndex i = 0; i != size;) { + SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _me[i++].m7 = buf[j]; + } + } + + void Save() const override + { + std::array buf; + TileIndex size = MapSize(); + + SlSetLength(size); + for (TileIndex i = 0; i != size;) { + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _me[i++].m7; + SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); + } + } +}; + +struct MAP8ChunkHandler : ChunkHandler { + MAP8ChunkHandler() : ChunkHandler('MAP8', CH_RIFF) {} + + void Load() const override + { + std::array buf; + TileIndex size = MapSize(); + + for (TileIndex i = 0; i != size;) { + SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT16); + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _me[i++].m8 = buf[j]; + } + } + + void Save() const override + { + std::array buf; + TileIndex size = MapSize(); + + SlSetLength(size * sizeof(uint16)); + for (TileIndex i = 0; i != size;) { + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _me[i++].m8; + SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT16); + } + } +}; + +static const MAPSChunkHandler MAPS; +static const MAPTChunkHandler MAPT; +static const MAPHChunkHandler MAPH; +static const MAPOChunkHandler MAPO; +static const MAP2ChunkHandler MAP2; +static const M3LOChunkHandler M3LO; +static const M3HIChunkHandler M3HI; +static const MAP5ChunkHandler MAP5; +static const MAPEChunkHandler MAPE; +static const MAP7ChunkHandler MAP7; +static const MAP8ChunkHandler MAP8; +static const ChunkHandlerRef map_chunk_handlers[] = { + MAPS, + MAPT, + MAPH, + MAPO, + MAP2, + M3LO, + M3HI, + MAP5, + MAPE, + MAP7, + MAP8, +}; + +extern const ChunkHandlerTable _map_chunk_handlers(map_chunk_handlers); + +} diff --git a/src/saveload/upstream/misc_sl.cpp b/src/saveload/upstream/misc_sl.cpp new file mode 100644 index 0000000000..4afa2ed0ba --- /dev/null +++ b/src/saveload/upstream/misc_sl.cpp @@ -0,0 +1,138 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file misc_sl.cpp Saving and loading of things that didn't fit anywhere else */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "compat/misc_sl_compat.h" + +#include "../../date_func.h" +#include "../../zoom_func.h" +#include "../../window_gui.h" +#include "../../window_func.h" +#include "../../viewport_func.h" +#include "../../gfx_func.h" +#include "../../core/random_func.hpp" +#include "../../fios.h" + +#include "../../safeguards.h" + +extern TileIndex _cur_tileloop_tile; +extern uint16 _disaster_delay; +extern byte _trees_tick_ctr; + +/* Keep track of current game position */ +extern int _saved_scrollpos_x; +extern int _saved_scrollpos_y; +extern ZoomLevel _saved_scrollpos_zoom; + +extern byte _age_cargo_skip_counter; ///< Skip aging of cargo? Used before savegame version 162. + +namespace upstream_sl { + +static const SaveLoad _date_desc[] = { + SLEG_CONDVAR("date", _date, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31), + SLEG_CONDVAR("date", _date, SLE_INT32, SLV_31, SL_MAX_VERSION), + SLEG_VAR("date_fract", _date_fract, SLE_UINT16), + SLEG_VAR("tick_counter", _tick_counter, SLE_UINT16), + SLEG_CONDVAR("age_cargo_skip_counter", _age_cargo_skip_counter, SLE_UINT8, SL_MIN_VERSION, SLV_162), + SLEG_CONDVAR("cur_tileloop_tile", _cur_tileloop_tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), + SLEG_CONDVAR("cur_tileloop_tile", _cur_tileloop_tile, SLE_UINT32, SLV_6, SL_MAX_VERSION), + SLEG_VAR("next_disaster_start", _disaster_delay, SLE_UINT16), + SLEG_VAR("random_state[0]", _random.state[0], SLE_UINT32), + SLEG_VAR("random_state[1]", _random.state[1], SLE_UINT32), + SLEG_VAR("company_tick_counter", _cur_company_tick_index, SLE_FILE_U8 | SLE_VAR_U32), + SLEG_CONDVAR("next_competitor_start", _next_competitor_start, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_109), + SLEG_CONDVAR("next_competitor_start", _next_competitor_start, SLE_UINT32, SLV_109, SL_MAX_VERSION), + SLEG_VAR("trees_tick_counter", _trees_tick_ctr, SLE_UINT8), + SLEG_CONDVAR("pause_mode", _pause_mode, SLE_UINT8, SLV_4, SL_MAX_VERSION), +}; + +static const SaveLoad _date_check_desc[] = { + SLEG_CONDVAR("date", _load_check_data.current_date, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31), + SLEG_CONDVAR("date", _load_check_data.current_date, SLE_INT32, SLV_31, SL_MAX_VERSION), +}; + +/* Save load date related variables as well as persistent tick counters + * XXX: currently some unrelated stuff is just put here */ +struct DATEChunkHandler : ChunkHandler { + DATEChunkHandler() : ChunkHandler('DATE', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_date_desc); + + SlSetArrayIndex(0); + SlGlobList(_date_desc); + } + + void LoadCommon(const SaveLoadTable &slt, const SaveLoadCompatTable &slct) const + { + const std::vector oslt = SlCompatTableHeader(slt, slct); + + if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() == -1) return; + SlGlobList(oslt); + if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many DATE entries"); + } + + void Load() const override + { + this->LoadCommon(_date_desc, _date_sl_compat); + } + + + void LoadCheck(size_t) const override + { + this->LoadCommon(_date_check_desc, _date_check_sl_compat); + + if (IsSavegameVersionBefore(SLV_31)) { + _load_check_data.current_date += DAYS_TILL_ORIGINAL_BASE_YEAR; + } + } +}; + +static const SaveLoad _view_desc[] = { + SLEG_CONDVAR("x", _saved_scrollpos_x, SLE_FILE_I16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_6), + SLEG_CONDVAR("x", _saved_scrollpos_x, SLE_INT32, SLV_6, SL_MAX_VERSION), + SLEG_CONDVAR("y", _saved_scrollpos_y, SLE_FILE_I16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_6), + SLEG_CONDVAR("y", _saved_scrollpos_y, SLE_INT32, SLV_6, SL_MAX_VERSION), + SLEG_VAR("zoom", _saved_scrollpos_zoom, SLE_UINT8), +}; + +struct VIEWChunkHandler : ChunkHandler { + VIEWChunkHandler() : ChunkHandler('VIEW', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_view_desc); + + SlSetArrayIndex(0); + SlGlobList(_view_desc); + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_view_desc, _view_sl_compat); + + if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() == -1) return; + SlGlobList(slt); + if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many DATE entries"); + } +}; + +static const DATEChunkHandler DATE; +static const VIEWChunkHandler VIEW; +static const ChunkHandlerRef misc_chunk_handlers[] = { + DATE, + VIEW, +}; + +extern const ChunkHandlerTable _misc_chunk_handlers(misc_chunk_handlers); + +} diff --git a/src/saveload/upstream/newgrf_sl.cpp b/src/saveload/upstream/newgrf_sl.cpp new file mode 100644 index 0000000000..0de1ac53c9 --- /dev/null +++ b/src/saveload/upstream/newgrf_sl.cpp @@ -0,0 +1,135 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file newgrf_sl.cpp Code handling saving and loading of newgrf config */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "compat/newgrf_sl_compat.h" + +#include "newgrf_sl.h" +#include "../../fios.h" + +#include "../../safeguards.h" + +namespace upstream_sl { + +/** Save and load the mapping between a spec and the NewGRF it came from. */ +static const SaveLoad _newgrf_mapping_desc[] = { + SLE_VAR(EntityIDMapping, grfid, SLE_UINT32), + SLE_VAR(EntityIDMapping, entity_id, SLE_UINT8), + SLE_VAR(EntityIDMapping, substitute_id, SLE_UINT8), +}; + +/** + * Save a GRF ID + local id -> OpenTTD's id mapping. + */ +void NewGRFMappingChunkHandler::Save() const +{ + SlTableHeader(_newgrf_mapping_desc); + + for (uint i = 0; i < this->mapping.GetMaxMapping(); i++) { + if (this->mapping.mapping_ID[i].grfid == 0 && + this->mapping.mapping_ID[i].entity_id == 0) continue; + SlSetArrayIndex(i); + SlObject(&this->mapping.mapping_ID[i], _newgrf_mapping_desc); + } +} + +/** + * Load a GRF ID + local id -> OpenTTD's id mapping. + */ +void NewGRFMappingChunkHandler::Load() const +{ + const std::vector slt = SlCompatTableHeader(_newgrf_mapping_desc, _newgrf_mapping_sl_compat); + + /* Clear the current mapping stored. + * This will create the manager if ever it is not yet done */ + this->mapping.ResetMapping(); + + uint max_id = this->mapping.GetMaxMapping(); + + int index; + while ((index = SlIterateArray()) != -1) { + if ((uint)index >= max_id) SlErrorCorrupt("Too many NewGRF entity mappings"); + SlObject(&this->mapping.mapping_ID[index], slt); + } +} + + +static const SaveLoad _grfconfig_desc[] = { + SLE_STR(GRFConfig, filename, SLE_STR, 0x40), + SLE_VAR(GRFConfig, ident.grfid, SLE_UINT32), + SLE_ARR(GRFConfig, ident.md5sum, SLE_UINT8, 16), + SLE_CONDVAR(GRFConfig, version, SLE_UINT32, SLV_151, SL_MAX_VERSION), + SLE_ARR(GRFConfig, param, SLE_UINT32, 0x80), + SLE_VAR(GRFConfig, num_params, SLE_UINT8), + SLE_CONDVAR(GRFConfig, palette, SLE_UINT8, SLV_101, SL_MAX_VERSION), +}; + + +struct NGRFChunkHandler : ChunkHandler { + NGRFChunkHandler() : ChunkHandler('NGRF', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_grfconfig_desc); + + int index = 0; + + for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { + if (HasBit(c->flags, GCF_STATIC) || HasBit(c->flags, GCF_INIT_ONLY)) continue; + SlSetArrayIndex(index++); + SlObject(c, _grfconfig_desc); + } + } + + + void LoadCommon(GRFConfig *&grfconfig) const + { + const std::vector slt = SlCompatTableHeader(_grfconfig_desc, _grfconfig_sl_compat); + + ClearGRFConfigList(&grfconfig); + while (SlIterateArray() != -1) { + GRFConfig *c = new GRFConfig(); + SlObject(c, slt); + if (IsSavegameVersionBefore(SLV_101)) c->SetSuitablePalette(); + AppendToGRFConfigList(&grfconfig, c); + } + } + + void Load() const override + { + this->LoadCommon(_grfconfig); + + if (_game_mode == GM_MENU) { + /* Intro game must not have NewGRF. */ + if (_grfconfig != nullptr) SlErrorCorrupt("The intro game must not use NewGRF"); + + /* Activate intro NewGRFs (townnames) */ + ResetGRFConfig(false); + } else { + /* Append static NewGRF configuration */ + AppendStaticGRFConfigs(&_grfconfig); + } + } + + void LoadCheck(size_t) const override + { + this->LoadCommon(_load_check_data.grfconfig); + } +}; + +static const NGRFChunkHandler NGRF; +static const ChunkHandlerRef newgrf_chunk_handlers[] = { + NGRF, +}; + +extern const ChunkHandlerTable _newgrf_chunk_handlers(newgrf_chunk_handlers); + +} diff --git a/src/saveload/upstream/newgrf_sl.h b/src/saveload/upstream/newgrf_sl.h new file mode 100644 index 0000000000..99136fba28 --- /dev/null +++ b/src/saveload/upstream/newgrf_sl.h @@ -0,0 +1,27 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file newgrf_sl.h Code handling saving and loading of NewGRF mappings. */ + +#ifndef SAVELOAD_UPSTREAM_NEWGRF_SL_H +#define SAVELOAD_UPSTREAM_NEWGRF_SL_H + +#include "../../newgrf_commons.h" + +namespace upstream_sl { + +struct NewGRFMappingChunkHandler : ChunkHandler { + OverrideManagerBase &mapping; + + NewGRFMappingChunkHandler(uint32 id, OverrideManagerBase &mapping) : ChunkHandler(id, CH_TABLE), mapping(mapping) {} + void Save() const override; + void Load() const override; +}; + +} + +#endif /* SAVELOAD_UPSTREAM_NEWGRF_SL_H */ diff --git a/src/saveload/upstream/object_sl.cpp b/src/saveload/upstream/object_sl.cpp new file mode 100644 index 0000000000..852e52558e --- /dev/null +++ b/src/saveload/upstream/object_sl.cpp @@ -0,0 +1,84 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file object_sl.cpp Code handling saving and loading of objects */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "compat/object_sl_compat.h" + +#include "../../object_base.h" +#include "../../object_map.h" +#include "newgrf_sl.h" + +#include "../../safeguards.h" + +namespace upstream_sl { + +static const SaveLoad _object_desc[] = { + SLE_VAR(Object, location.tile, SLE_UINT32), + SLE_VAR(Object, location.w, SLE_FILE_U8 | SLE_VAR_U16), + SLE_VAR(Object, location.h, SLE_FILE_U8 | SLE_VAR_U16), + SLE_REF(Object, town, REF_TOWN), + SLE_VAR(Object, build_date, SLE_UINT32), + SLE_CONDVAR(Object, colour, SLE_UINT8, SLV_148, SL_MAX_VERSION), + SLE_CONDVAR(Object, view, SLE_UINT8, SLV_155, SL_MAX_VERSION), + SLE_CONDVAR(Object, type, SLE_UINT16, SLV_186, SL_MAX_VERSION), +}; + +struct OBJSChunkHandler : ChunkHandler { + OBJSChunkHandler() : ChunkHandler('OBJS', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_object_desc); + + /* Write the objects */ + for (Object *o : Object::Iterate()) { + SlSetArrayIndex(o->index); + SlObject(o, _object_desc); + } + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_object_desc, _object_sl_compat); + + int index; + while ((index = SlIterateArray()) != -1) { + Object *o = new (index) Object(); + SlObject(o, slt); + } + } + + void FixPointers() const override + { + for (Object *o : Object::Iterate()) { + SlObject(o, _object_desc); + if (IsSavegameVersionBefore(SLV_148) && !IsTileType(o->location.tile, MP_OBJECT)) { + /* Due to a small bug stale objects could remain. */ + delete o; + } + } + } +}; + +struct OBIDChunkHandler : NewGRFMappingChunkHandler { + OBIDChunkHandler() : NewGRFMappingChunkHandler('OBID', _object_mngr) {} +}; + +static const OBIDChunkHandler OBID; +static const OBJSChunkHandler OBJS; +static const ChunkHandlerRef object_chunk_handlers[] = { + OBID, + OBJS, +}; + +extern const ChunkHandlerTable _object_chunk_handlers(object_chunk_handlers); + +} diff --git a/src/saveload/upstream/order_sl.cpp b/src/saveload/upstream/order_sl.cpp new file mode 100644 index 0000000000..661d6990cb --- /dev/null +++ b/src/saveload/upstream/order_sl.cpp @@ -0,0 +1,273 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file order_sl.cpp Code handling saving and loading of orders */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "compat/order_sl_compat.h" + +#include "../../order_backup.h" +#include "../../order_base.h" +#include "../../settings_type.h" +#include "../../network/network.h" + +#include "../../safeguards.h" + +namespace upstream_sl { + +/** + * Unpacks a order from savegames with version 4 and lower + * @param packed packed order + * @return unpacked order + */ +static Order UnpackVersion4Order(uint16 packed) +{ + return Order(GB(packed, 8, 8) << 16 | GB(packed, 4, 4) << 8 | GB(packed, 0, 4)); +} + +/** + * Unpacks a order from savegames made with TTD(Patch) + * @param packed packed order + * @return unpacked order + */ +Order UnpackOldOrder(uint16 packed) +{ + Order order = UnpackVersion4Order(packed); + + /* + * Sanity check + * TTD stores invalid orders as OT_NOTHING with non-zero flags/station + */ + if (order.IsType(OT_NOTHING) && packed != 0) order.MakeDummy(); + + return order; +} + +SaveLoadTable GetOrderDescription() +{ + static const SaveLoad _order_desc[] = { + SLE_VAR(Order, type, SLE_UINT8), + SLE_VAR(Order, flags, SLE_FILE_U8 | SLE_VAR_U16), + SLE_VAR(Order, dest, SLE_UINT16), + SLE_REF(Order, next, REF_ORDER), + SLE_CONDVAR(Order, refit_cargo, SLE_UINT8, SLV_36, SL_MAX_VERSION), + SLE_CONDVAR(Order, wait_time, SLE_FILE_U16 | SLE_VAR_U32, SLV_67, SL_MAX_VERSION), + SLE_CONDVAR(Order, travel_time, SLE_FILE_U16 | SLE_VAR_U32, SLV_67, SL_MAX_VERSION), + SLE_CONDVAR(Order, max_speed, SLE_UINT16, SLV_172, SL_MAX_VERSION), + }; + + return _order_desc; +} + +struct ORDRChunkHandler : ChunkHandler { + ORDRChunkHandler() : ChunkHandler('ORDR', CH_TABLE) {} + + void Save() const override + { + const SaveLoadTable slt = GetOrderDescription(); + SlTableHeader(slt); + + for (Order *order : Order::Iterate()) { + SlSetArrayIndex(order->index); + SlObject(order, slt); + } + } + + void Load() const override + { + if (IsSavegameVersionBefore(SLV_5, 2)) { + /* Version older than 5.2 did not have a ->next pointer. Convert them + * (in the old days, the orderlist was 5000 items big) */ + size_t len = SlGetFieldLength(); + + if (IsSavegameVersionBefore(SLV_5)) { + /* Pre-version 5 had another layout for orders + * (uint16 instead of uint32) */ + len /= sizeof(uint16); + uint16 *orders = MallocT(len + 1); + + SlCopy(orders, len, SLE_UINT16); + + for (size_t i = 0; i < len; ++i) { + Order *o = new (i) Order(); + o->AssignOrder(UnpackVersion4Order(orders[i])); + } + + free(orders); + } else if (IsSavegameVersionBefore(SLV_5, 2)) { + len /= sizeof(uint32); + uint32 *orders = MallocT(len + 1); + + SlCopy(orders, len, SLE_UINT32); + + for (size_t i = 0; i < len; ++i) { + new (i) Order(orders[i]); + } + + free(orders); + } + + /* Update all the next pointer */ + for (Order *o : Order::Iterate()) { + size_t order_index = o->index; + /* Delete invalid orders */ + if (o->IsType(OT_NOTHING)) { + delete o; + continue; + } + /* The orders were built like this: + * While the order is valid, set the previous will get its next pointer set */ + Order *prev = Order::GetIfValid(order_index - 1); + if (prev != nullptr) prev->next = o; + } + } else { + const std::vector slt = SlCompatTableHeader(GetOrderDescription(), _order_sl_compat); + + int index; + + while ((index = SlIterateArray()) != -1) { + Order *order = new (index) Order(); + SlObject(order, slt); + } + } + } + + void FixPointers() const override + { + /* Orders from old savegames have pointers corrected in Load_ORDR */ + if (IsSavegameVersionBefore(SLV_5, 2)) return; + + for (Order *o : Order::Iterate()) { + SlObject(o, GetOrderDescription()); + } + } +}; + +SaveLoadTable GetOrderListDescription() +{ + static const SaveLoad _orderlist_desc[] = { + SLE_REF(OrderList, first, REF_ORDER), + }; + + return _orderlist_desc; +} + +struct ORDLChunkHandler : ChunkHandler { + ORDLChunkHandler() : ChunkHandler('ORDL', CH_TABLE) {} + + void Save() const override + { + const SaveLoadTable slt = GetOrderListDescription(); + SlTableHeader(slt); + + for (OrderList *list : OrderList::Iterate()) { + SlSetArrayIndex(list->index); + SlObject(list, slt); + } + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(GetOrderListDescription(), _orderlist_sl_compat); + + int index; + + while ((index = SlIterateArray()) != -1) { + /* set num_orders to 0 so it's a valid OrderList */ + OrderList *list = new (index) OrderList(0); + SlObject(list, slt); + } + + } + + void FixPointers() const override + { + for (OrderList *list : OrderList::Iterate()) { + SlObject(list, GetOrderListDescription()); + } + } +}; + +SaveLoadTable GetOrderBackupDescription() +{ + static const SaveLoad _order_backup_desc[] = { + SLE_VAR(OrderBackup, user, SLE_UINT32), + SLE_VAR(OrderBackup, tile, SLE_UINT32), + SLE_VAR(OrderBackup, group, SLE_UINT16), + SLE_CONDVAR(OrderBackup, service_interval, SLE_FILE_U32 | SLE_VAR_U16, SL_MIN_VERSION, SLV_192), + SLE_CONDVAR(OrderBackup, service_interval, SLE_UINT16, SLV_192, SL_MAX_VERSION), + SLE_SSTR(OrderBackup, name, SLE_STR), + SLE_CONDREF(OrderBackup, clone, REF_VEHICLE, SLV_192, SL_MAX_VERSION), + SLE_VAR(OrderBackup, cur_real_order_index, SLE_FILE_U8 | SLE_VAR_U16), + SLE_CONDVAR(OrderBackup, cur_implicit_order_index, SLE_FILE_U8 | SLE_VAR_U16, SLV_176, SL_MAX_VERSION), + SLE_CONDVAR(OrderBackup, current_order_time, SLE_UINT32, SLV_176, SL_MAX_VERSION), + SLE_CONDVAR(OrderBackup, lateness_counter, SLE_INT32, SLV_176, SL_MAX_VERSION), + SLE_CONDVAR(OrderBackup, timetable_start, SLE_INT32, SLV_176, SL_MAX_VERSION), + SLE_CONDVAR(OrderBackup, vehicle_flags, SLE_FILE_U8 | SLE_VAR_U16, SLV_176, SLV_180), + SLE_CONDVAR(OrderBackup, vehicle_flags, SLE_UINT16, SLV_180, SL_MAX_VERSION), + SLE_REF(OrderBackup, orders, REF_ORDER), + }; + + return _order_backup_desc; +} + +struct BKORChunkHandler : ChunkHandler { + BKORChunkHandler() : ChunkHandler('BKOR', CH_TABLE) {} + + void Save() const override + { + const SaveLoadTable slt = GetOrderBackupDescription(); + SlTableHeader(slt); + + /* We only save this when we're a network server + * as we want this information on our clients. For + * normal games this information isn't needed. */ + if (!_networking || !_network_server) return; + + for (OrderBackup *ob : OrderBackup::Iterate()) { + SlSetArrayIndex(ob->index); + SlObject(ob, slt); + } + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(GetOrderBackupDescription(), _order_backup_sl_compat); + + int index; + + while ((index = SlIterateArray()) != -1) { + /* set num_orders to 0 so it's a valid OrderList */ + OrderBackup *ob = new (index) OrderBackup(); + SlObject(ob, slt); + if (ob->cur_real_order_index == 0xFF) ob->cur_real_order_index = INVALID_VEH_ORDER_ID; + if (ob->cur_implicit_order_index == 0xFF) ob->cur_implicit_order_index = INVALID_VEH_ORDER_ID; + } + } + + void FixPointers() const override + { + for (OrderBackup *ob : OrderBackup::Iterate()) { + SlObject(ob, GetOrderBackupDescription()); + } + } +}; + +static const BKORChunkHandler BKOR; +static const ORDRChunkHandler ORDR; +static const ORDLChunkHandler ORDL; +static const ChunkHandlerRef order_chunk_handlers[] = { + BKOR, + ORDR, + ORDL, +}; + +extern const ChunkHandlerTable _order_chunk_handlers(order_chunk_handlers); + +} diff --git a/src/saveload/upstream/saveload.cpp b/src/saveload/upstream/saveload.cpp new file mode 100644 index 0000000000..a4cef44d66 --- /dev/null +++ b/src/saveload/upstream/saveload.cpp @@ -0,0 +1,2053 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** + * @file saveload.cpp + * All actions handling saving and loading goes on in this file. The general actions + * are as follows for saving a game (loading is analogous): + *
    + *
  1. initialize the writer by creating a temporary memory-buffer for it + *
  2. go through all to-be saved elements, each 'chunk' (#ChunkHandler) prefixed by a label + *
  3. use their description array (#SaveLoad) to know what elements to save and in what version + * of the game it was active (used when loading) + *
  4. write all data byte-by-byte to the temporary buffer so it is endian-safe + *
  5. when the buffer is full; flush it to the output (eg save to file) (_sl.buf, _sl.bufp, _sl.bufe) + *
  6. repeat this until everything is done, and flush any remaining output to file + *
+ */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "../../debug.h" +#include "../../string_func.h" +#include "../../strings_func.h" +#include "../../core/bitmath_func.hpp" +#include "../../vehicle_base.h" +#include "../../station_base.h" +#include "../../linkgraph/linkgraph.h" +#include "../../linkgraph/linkgraphjob.h" +#include "../../town.h" +#include "../../roadstop_base.h" +#include "../../autoreplace_base.h" + +#include +#include +#include +#include +#include +#include + +#include "../../safeguards.h" + +StringID RemapOldStringID(StringID s); +std::string CopyFromOldName(StringID id); + +namespace upstream_sl { + +/** What are we currently doing? */ +enum SaveLoadAction { + SLA_LOAD, ///< loading + SLA_SAVE, ///< saving + SLA_PTRS, ///< fixing pointers + SLA_NULL, ///< null all pointers (on loading error) + SLA_LOAD_CHECK, ///< partial loading into #_load_check_data +}; + +enum NeedLength { + NL_NONE = 0, ///< not working in NeedLength mode + NL_WANTLENGTH = 1, ///< writing length and data + NL_CALCLENGTH = 2, ///< need to calculate the length +}; + +/** The saveload struct, containing reader-writer functions, buffer, version, etc. */ +struct SaveLoadParams { + SaveLoadAction action; ///< are we doing a save or a load atm. + NeedLength need_length; ///< working in NeedLength (Autolength) mode? + byte block_mode; ///< ??? + + size_t obj_len; ///< the length of the current object we are busy with + int array_index, last_array_index; ///< in the case of an array, the current and last positions + bool expect_table_header; ///< In the case of a table, if the header is saved/loaded. +}; + +static SaveLoadParams _sl; ///< Parameters used for/at saveload. + +static const std::vector &ChunkHandlers() +{ + /* These define the chunks */ + extern const ChunkHandlerTable _gamelog_chunk_handlers; + extern const ChunkHandlerTable _map_chunk_handlers; + extern const ChunkHandlerTable _misc_chunk_handlers; + //extern const ChunkHandlerTable _name_chunk_handlers; + extern const ChunkHandlerTable _cheat_chunk_handlers; + extern const ChunkHandlerTable _setting_chunk_handlers; + extern const ChunkHandlerTable _company_chunk_handlers; + extern const ChunkHandlerTable _engine_chunk_handlers; + extern const ChunkHandlerTable _veh_chunk_handlers; + //extern const ChunkHandlerTable _waypoint_chunk_handlers; + extern const ChunkHandlerTable _depot_chunk_handlers; + extern const ChunkHandlerTable _order_chunk_handlers; + extern const ChunkHandlerTable _town_chunk_handlers; + extern const ChunkHandlerTable _sign_chunk_handlers; + extern const ChunkHandlerTable _station_chunk_handlers; + extern const ChunkHandlerTable _industry_chunk_handlers; + extern const ChunkHandlerTable _economy_chunk_handlers; + extern const ChunkHandlerTable _subsidy_chunk_handlers; + extern const ChunkHandlerTable _cargomonitor_chunk_handlers; + extern const ChunkHandlerTable _goal_chunk_handlers; + extern const ChunkHandlerTable _story_page_chunk_handlers; + extern const ChunkHandlerTable _ai_chunk_handlers; + extern const ChunkHandlerTable _game_chunk_handlers; + extern const ChunkHandlerTable _animated_tile_chunk_handlers; + extern const ChunkHandlerTable _newgrf_chunk_handlers; + extern const ChunkHandlerTable _group_chunk_handlers; + extern const ChunkHandlerTable _cargopacket_chunk_handlers; + extern const ChunkHandlerTable _autoreplace_chunk_handlers; + extern const ChunkHandlerTable _labelmaps_chunk_handlers; + extern const ChunkHandlerTable _linkgraph_chunk_handlers; + extern const ChunkHandlerTable _airport_chunk_handlers; + extern const ChunkHandlerTable _object_chunk_handlers; + extern const ChunkHandlerTable _persistent_storage_chunk_handlers; + + /** List of all chunks in a savegame. */ + static const ChunkHandlerTable _chunk_handler_tables[] = { + _gamelog_chunk_handlers, + _map_chunk_handlers, + _misc_chunk_handlers, + //_name_chunk_handlers, + _cheat_chunk_handlers, + _setting_chunk_handlers, + _veh_chunk_handlers, + //_waypoint_chunk_handlers, + _depot_chunk_handlers, + _order_chunk_handlers, + _industry_chunk_handlers, + _economy_chunk_handlers, + _subsidy_chunk_handlers, + _cargomonitor_chunk_handlers, + _goal_chunk_handlers, + _story_page_chunk_handlers, + _engine_chunk_handlers, + _town_chunk_handlers, + _sign_chunk_handlers, + _station_chunk_handlers, + _company_chunk_handlers, + _ai_chunk_handlers, + _game_chunk_handlers, + _animated_tile_chunk_handlers, + _newgrf_chunk_handlers, + _group_chunk_handlers, + _cargopacket_chunk_handlers, + _autoreplace_chunk_handlers, + _labelmaps_chunk_handlers, + _linkgraph_chunk_handlers, + _airport_chunk_handlers, + _object_chunk_handlers, + _persistent_storage_chunk_handlers, + }; + + static std::vector _chunk_handlers; + + if (_chunk_handlers.empty()) { + for (auto &chunk_handler_table : _chunk_handler_tables) { + for (auto &chunk_handler : chunk_handler_table) { + _chunk_handlers.push_back(chunk_handler); + } + } + } + + return _chunk_handlers; +} + +/** Null all pointers (convert index -> nullptr) */ +void SlNullPointers() +{ + _sl.action = SLA_NULL; + + /* We don't want any savegame conversion code to run + * during NULLing; especially those that try to get + * pointers from other pools. */ + _sl_version = SAVEGAME_VERSION; + + for (const ChunkHandler &ch : ChunkHandlers()) { + DEBUG(sl, 3, "Nulling pointers for %c%c%c%c", ch.id >> 24, ch.id >> 16, ch.id >> 8, ch.id); + ch.FixPointers(); + } + + assert(_sl.action == SLA_NULL); +} + +/** + * Read in the header descriptor of an object or an array. + * If the highest bit is set (7), then the index is bigger than 127 + * elements, so use the next byte to read in the real value. + * The actual value is then both bytes added with the first shifted + * 8 bits to the left, and dropping the highest bit (which only indicated a big index). + * x = ((x & 0x7F) << 8) + SlReadByte(); + * @return Return the value of the index + */ +static uint SlReadSimpleGamma() +{ + uint i = SlReadByte(); + if (HasBit(i, 7)) { + i &= ~0x80; + if (HasBit(i, 6)) { + i &= ~0x40; + if (HasBit(i, 5)) { + i &= ~0x20; + if (HasBit(i, 4)) { + i &= ~0x10; + if (HasBit(i, 3)) { + SlErrorCorrupt("Unsupported gamma"); + } + i = SlReadByte(); // 32 bits only. + } + i = (i << 8) | SlReadByte(); + } + i = (i << 8) | SlReadByte(); + } + i = (i << 8) | SlReadByte(); + } + return i; +} + +/** + * Write the header descriptor of an object or an array. + * If the element is bigger than 127, use 2 bytes for saving + * and use the highest byte of the first written one as a notice + * that the length consists of 2 bytes, etc.. like this: + * 0xxxxxxx + * 10xxxxxx xxxxxxxx + * 110xxxxx xxxxxxxx xxxxxxxx + * 1110xxxx xxxxxxxx xxxxxxxx xxxxxxxx + * 11110--- xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx + * We could extend the scheme ad infinum to support arbitrarily + * large chunks, but as sizeof(size_t) == 4 is still very common + * we don't support anything above 32 bits. That's why in the last + * case the 3 most significant bits are unused. + * @param i Index being written + */ + +static void SlWriteSimpleGamma(size_t i) +{ + if (i >= (1 << 7)) { + if (i >= (1 << 14)) { + if (i >= (1 << 21)) { + if (i >= (1 << 28)) { + assert(i <= UINT32_MAX); // We can only support 32 bits for now. + SlWriteByte((byte)(0xF0)); + SlWriteByte((byte)(i >> 24)); + } else { + SlWriteByte((byte)(0xE0 | (i >> 24))); + } + SlWriteByte((byte)(i >> 16)); + } else { + SlWriteByte((byte)(0xC0 | (i >> 16))); + } + SlWriteByte((byte)(i >> 8)); + } else { + SlWriteByte((byte)(0x80 | (i >> 8))); + } + } + SlWriteByte((byte)i); +} + +/** Return how many bytes used to encode a gamma value */ +static inline uint SlGetGammaLength(size_t i) +{ + return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21)) + (i >= (1 << 28)); +} + +static inline uint SlReadSparseIndex() +{ + return SlReadSimpleGamma(); +} + +static inline void SlWriteSparseIndex(uint index) +{ + SlWriteSimpleGamma(index); +} + +static inline uint SlReadArrayLength() +{ + return SlReadSimpleGamma(); +} + +static inline void SlWriteArrayLength(size_t length) +{ + SlWriteSimpleGamma(length); +} + +static inline uint SlGetArrayLength(size_t length) +{ + return SlGetGammaLength(length); +} + +/** + * Return the type as saved/loaded inside the savegame. + */ +static uint8 GetSavegameFileType(const SaveLoad &sld) +{ + switch (sld.cmd) { + case SL_VAR: + return GetVarFileType(sld.conv); break; + + case SL_STR: + case SL_STDSTR: + case SL_ARR: + case SL_VECTOR: + case SL_DEQUE: + return GetVarFileType(sld.conv) | SLE_FILE_HAS_LENGTH_FIELD; break; + + case SL_REF: + return IsSavegameVersionBefore(SLV_69) ? SLE_FILE_U16 : SLE_FILE_U32; + + case SL_REFLIST: + case SL_REFDEQUE: + case SL_REFVEC: + return (IsSavegameVersionBefore(SLV_69) ? SLE_FILE_U16 : SLE_FILE_U32) | SLE_FILE_HAS_LENGTH_FIELD; + + case SL_SAVEBYTE: + return SLE_FILE_U8; + + case SL_STRUCT: + case SL_STRUCTLIST: + return SLE_FILE_STRUCT | SLE_FILE_HAS_LENGTH_FIELD; + + default: NOT_REACHED(); + } +} + +/** + * Return the size in bytes of a certain type of normal/atomic variable + * as it appears in memory. See VarTypes + * @param conv VarType type of variable that is used for calculating the size + * @return Return the size of this type in bytes + */ +static inline uint SlCalcConvMemLen(VarType conv) +{ + static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0}; + + switch (GetVarMemType(conv)) { + case SLE_VAR_STRB: + case SLE_VAR_STR: + case SLE_VAR_STRQ: + return SlReadArrayLength(); + + default: + uint8 type = GetVarMemType(conv) >> 4; + assert(type < lengthof(conv_mem_size)); + return conv_mem_size[type]; + } +} + +/** + * Return the size in bytes of a certain type of normal/atomic variable + * as it appears in a saved game. See VarTypes + * @param conv VarType type of variable that is used for calculating the size + * @return Return the size of this type in bytes + */ +static inline byte SlCalcConvFileLen(VarType conv) +{ + static const byte conv_file_size[] = {0, 1, 1, 2, 2, 4, 4, 8, 8, 2}; + + uint8 type = GetVarFileType(conv); + assert(type < lengthof(conv_file_size)); + return conv_file_size[type]; +} + +/** Return the size in bytes of a reference (pointer) */ +static inline size_t SlCalcRefLen() +{ + return IsSavegameVersionBefore(SLV_69) ? 2 : 4; +} + +void SlSetArrayIndex(uint index) +{ + _sl.need_length = NL_WANTLENGTH; + _sl.array_index = index; +} + +static size_t _next_offs; + +/** + * Iterate through the elements of an array and read the whole thing + * @return The index of the object, or -1 if we have reached the end of current block + */ +int SlIterateArray() +{ + int index; + + /* After reading in the whole array inside the loop + * we must have read in all the data, so we must be at end of current block. */ + if (_next_offs != 0 && SlGetBytesRead() != _next_offs) SlErrorCorrupt("Invalid chunk size"); + + for (;;) { + uint length = SlReadArrayLength(); + if (length == 0) { + assert(!_sl.expect_table_header); + _next_offs = 0; + return -1; + } + + _sl.obj_len = --length; + _next_offs = SlGetBytesRead() + length; + + if (_sl.expect_table_header) { + _sl.expect_table_header = false; + return INT32_MAX; + } + + switch (_sl.block_mode) { + case CH_SPARSE_TABLE: + case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break; + case CH_TABLE: + case CH_ARRAY: index = _sl.array_index++; break; + default: + DEBUG(sl, 0, "SlIterateArray error"); + return -1; // error + } + + if (length != 0) return index; + } +} + +/** + * Skip an array or sparse array + */ +void SlSkipArray() +{ + while (SlIterateArray() != -1) { + SlSkipBytes(_next_offs - SlGetBytesRead()); + } +} + +/** + * Sets the length of either a RIFF object or the number of items in an array. + * This lets us load an object or an array of arbitrary size + * @param length The length of the sought object/array + */ +void SlSetLength(size_t length) +{ + assert(_sl.action == SLA_SAVE); + + switch (_sl.need_length) { + case NL_WANTLENGTH: + _sl.need_length = NL_NONE; + if ((_sl.block_mode == CH_TABLE || _sl.block_mode == CH_SPARSE_TABLE) && _sl.expect_table_header) { + _sl.expect_table_header = false; + SlWriteArrayLength(length + 1); + break; + } + + switch (_sl.block_mode) { + case CH_RIFF: + /* Ugly encoding of >16M RIFF chunks + * The lower 24 bits are normal + * The uppermost 4 bits are bits 24:27 */ + assert(length < (1 << 28)); + SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28))); + break; + case CH_TABLE: + case CH_ARRAY: + assert(_sl.last_array_index <= _sl.array_index); + while (++_sl.last_array_index <= _sl.array_index) { + SlWriteArrayLength(1); + } + SlWriteArrayLength(length + 1); + break; + case CH_SPARSE_TABLE: + case CH_SPARSE_ARRAY: + SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index)); // Also include length of sparse index. + SlWriteSparseIndex(_sl.array_index); + break; + default: NOT_REACHED(); + } + break; + + case NL_CALCLENGTH: + _sl.obj_len += (int)length; + break; + + default: NOT_REACHED(); + } +} + +/** + * Save/Load bytes. These do not need to be converted to Little/Big Endian + * so directly write them or read them to/from file + * @param ptr The source or destination of the object being manipulated + * @param length number of bytes this fast CopyBytes lasts + */ +static void SlCopyBytes(void *ptr, size_t length) +{ + byte *p = (byte *)ptr; + + switch (_sl.action) { + case SLA_LOAD_CHECK: + case SLA_LOAD: + for (; length != 0; length--) *p++ = SlReadByte(); + break; + case SLA_SAVE: + for (; length != 0; length--) SlWriteByte(*p++); + break; + default: NOT_REACHED(); + } +} + +/** Get the length of the current object */ +size_t SlGetFieldLength() +{ + return _sl.obj_len; +} + +/** + * Return a signed-long version of the value of a setting + * @param ptr pointer to the variable + * @param conv type of variable, can be a non-clean + * type, eg one with other flags because it is parsed + * @return returns the value of the pointer-setting + */ +int64 ReadValue(const void *ptr, VarType conv) +{ + switch (GetVarMemType(conv)) { + case SLE_VAR_BL: return (*(const bool *)ptr != 0); + case SLE_VAR_I8: return *(const int8 *)ptr; + case SLE_VAR_U8: return *(const byte *)ptr; + case SLE_VAR_I16: return *(const int16 *)ptr; + case SLE_VAR_U16: return *(const uint16*)ptr; + case SLE_VAR_I32: return *(const int32 *)ptr; + case SLE_VAR_U32: return *(const uint32*)ptr; + case SLE_VAR_I64: return *(const int64 *)ptr; + case SLE_VAR_U64: return *(const uint64*)ptr; + case SLE_VAR_NULL:return 0; + default: NOT_REACHED(); + } +} + +/** + * Write the value of a setting + * @param ptr pointer to the variable + * @param conv type of variable, can be a non-clean type, eg + * with other flags. It is parsed upon read + * @param val the new value being given to the variable + */ +void WriteValue(void *ptr, VarType conv, int64 val) +{ + switch (GetVarMemType(conv)) { + case SLE_VAR_BL: *(bool *)ptr = (val != 0); break; + case SLE_VAR_I8: *(int8 *)ptr = val; break; + case SLE_VAR_U8: *(byte *)ptr = val; break; + case SLE_VAR_I16: *(int16 *)ptr = val; break; + case SLE_VAR_U16: *(uint16*)ptr = val; break; + case SLE_VAR_I32: *(int32 *)ptr = val; break; + case SLE_VAR_U32: *(uint32*)ptr = val; break; + case SLE_VAR_I64: *(int64 *)ptr = val; break; + case SLE_VAR_U64: *(uint64*)ptr = val; break; + case SLE_VAR_NAME: *reinterpret_cast(ptr) = CopyFromOldName(val); break; + case SLE_VAR_NULL: break; + default: NOT_REACHED(); + } +} + +/** + * Handle all conversion and typechecking of variables here. + * In the case of saving, read in the actual value from the struct + * and then write them to file, endian safely. Loading a value + * goes exactly the opposite way + * @param ptr The object being filled/read + * @param conv VarType type of the current element of the struct + */ +static void SlSaveLoadConv(void *ptr, VarType conv) +{ + switch (_sl.action) { + case SLA_SAVE: { + int64 x = ReadValue(ptr, conv); + + /* Write the value to the file and check if its value is in the desired range */ + switch (GetVarFileType(conv)) { + case SLE_FILE_I8: assert(x >= -128 && x <= 127); SlWriteByte(x);break; + case SLE_FILE_U8: assert(x >= 0 && x <= 255); SlWriteByte(x);break; + case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break; + case SLE_FILE_STRINGID: + case SLE_FILE_U16:assert(x >= 0 && x <= 65535); SlWriteUint16(x);break; + case SLE_FILE_I32: + case SLE_FILE_U32: SlWriteUint32((uint32)x);break; + case SLE_FILE_I64: + case SLE_FILE_U64: SlWriteUint64(x);break; + default: NOT_REACHED(); + } + break; + } + case SLA_LOAD_CHECK: + case SLA_LOAD: { + int64 x; + /* Read a value from the file */ + switch (GetVarFileType(conv)) { + case SLE_FILE_I8: x = (int8 )SlReadByte(); break; + case SLE_FILE_U8: x = (byte )SlReadByte(); break; + case SLE_FILE_I16: x = (int16 )SlReadUint16(); break; + case SLE_FILE_U16: x = (uint16)SlReadUint16(); break; + case SLE_FILE_I32: x = (int32 )SlReadUint32(); break; + case SLE_FILE_U32: x = (uint32)SlReadUint32(); break; + case SLE_FILE_I64: x = (int64 )SlReadUint64(); break; + case SLE_FILE_U64: x = (uint64)SlReadUint64(); break; + case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break; + default: NOT_REACHED(); + } + + /* Write The value to the struct. These ARE endian safe. */ + WriteValue(ptr, conv, x); + break; + } + case SLA_PTRS: break; + case SLA_NULL: break; + default: NOT_REACHED(); + } +} + +/** + * Calculate the net length of a string. This is in almost all cases + * just strlen(), but if the string is not properly terminated, we'll + * resort to the maximum length of the buffer. + * @param ptr pointer to the stringbuffer + * @param length maximum length of the string (buffer). If -1 we don't care + * about a maximum length, but take string length as it is. + * @return return the net length of the string + */ +static inline size_t SlCalcNetStringLen(const char *ptr, size_t length) +{ + if (ptr == nullptr) return 0; + return std::min(strlen(ptr), length - 1); +} + +/** + * Calculate the gross length of the string that it + * will occupy in the savegame. This includes the real length, returned + * by SlCalcNetStringLen and the length that the index will occupy. + * @param ptr pointer to the stringbuffer + * @param length maximum length of the string (buffer size, etc.) + * @param conv type of data been used + * @return return the gross length of the string + */ +static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv) +{ + size_t len; + const char *str; + + switch (GetVarMemType(conv)) { + default: NOT_REACHED(); + case SLE_VAR_STR: + case SLE_VAR_STRQ: + str = *(const char * const *)ptr; + len = SIZE_MAX; + break; + case SLE_VAR_STRB: + str = (const char *)ptr; + len = length; + break; + } + + len = SlCalcNetStringLen(str, len); + return len + SlGetArrayLength(len); // also include the length of the index +} + +/** + * Calculate the gross length of the string that it + * will occupy in the savegame. This includes the real length, returned + * by SlCalcNetStringLen and the length that the index will occupy. + * @param ptr Pointer to the \c std::string. + * @return The gross length of the string. + */ +static inline size_t SlCalcStdStringLen(const void *ptr) +{ + const std::string *str = reinterpret_cast(ptr); + + size_t len = str->length(); + return len + SlGetArrayLength(len); // also include the length of the index +} + +/** + * Save/Load a string. + * @param ptr the string being manipulated + * @param length of the string (full length) + * @param conv must be SLE_FILE_STRING + */ +static void SlString(void *ptr, size_t length, VarType conv) +{ + switch (_sl.action) { + case SLA_SAVE: { + size_t len; + switch (GetVarMemType(conv)) { + default: NOT_REACHED(); + case SLE_VAR_STRB: + len = SlCalcNetStringLen((char *)ptr, length); + break; + case SLE_VAR_STR: + case SLE_VAR_STRQ: + ptr = *(char **)ptr; + len = SlCalcNetStringLen((char *)ptr, SIZE_MAX); + break; + } + + SlWriteArrayLength(len); + SlCopyBytes(ptr, len); + break; + } + case SLA_LOAD_CHECK: + case SLA_LOAD: { + size_t len = SlReadArrayLength(); + + switch (GetVarMemType(conv)) { + default: NOT_REACHED(); + case SLE_VAR_NULL: + SlSkipBytes(len); + return; + case SLE_VAR_STRB: + if (len >= length) { + DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating"); + SlCopyBytes(ptr, length); + SlSkipBytes(len - length); + len = length - 1; + } else { + SlCopyBytes(ptr, len); + } + break; + case SLE_VAR_STR: + case SLE_VAR_STRQ: // Malloc'd string, free previous incarnation, and allocate + free(*(char **)ptr); + if (len == 0) { + *(char **)ptr = nullptr; + return; + } else { + *(char **)ptr = MallocT(len + 1); // terminating '\0' + ptr = *(char **)ptr; + SlCopyBytes(ptr, len); + } + break; + } + + ((char *)ptr)[len] = '\0'; // properly terminate the string + StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK; + if ((conv & SLF_ALLOW_CONTROL) != 0) { + settings = settings | SVS_ALLOW_CONTROL_CODE; + if (IsSavegameVersionBefore(SLV_169)) { + str_fix_scc_encoded((char *)ptr, (char *)ptr + len); + } + } + if ((conv & SLF_ALLOW_NEWLINE) != 0) { + settings = settings | SVS_ALLOW_NEWLINE; + } + StrMakeValidInPlace((char *)ptr, (char *)ptr + len, settings); + break; + } + case SLA_PTRS: break; + case SLA_NULL: break; + default: NOT_REACHED(); + } +} + +/** + * Save/Load a \c std::string. + * @param ptr the string being manipulated + * @param conv must be SLE_FILE_STRING + */ +static void SlStdString(void *ptr, VarType conv) +{ + std::string *str = reinterpret_cast(ptr); + + switch (_sl.action) { + case SLA_SAVE: { + size_t len = str->length(); + SlWriteArrayLength(len); + SlCopyBytes(const_cast(static_cast(str->c_str())), len); + break; + } + + case SLA_LOAD_CHECK: + case SLA_LOAD: { + size_t len = SlReadArrayLength(); + if (GetVarMemType(conv) == SLE_VAR_NULL) { + SlSkipBytes(len); + return; + } + + char *buf = AllocaM(char, len + 1); + SlCopyBytes(buf, len); + buf[len] = '\0'; // properly terminate the string + + StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK; + if ((conv & SLF_ALLOW_CONTROL) != 0) { + settings = settings | SVS_ALLOW_CONTROL_CODE; + if (IsSavegameVersionBefore(SLV_169)) { + str_fix_scc_encoded(buf, buf + len); + } + } + if ((conv & SLF_ALLOW_NEWLINE) != 0) { + settings = settings | SVS_ALLOW_NEWLINE; + } + + StrMakeValidInPlace(buf, buf + len, settings); + + // Store sanitized string. + str->assign(buf); + } + + case SLA_PTRS: break; + case SLA_NULL: break; + default: NOT_REACHED(); + } +} + +/** + * Internal function to save/Load a list of SL_VARs. + * SlCopy() and SlArray() are very similar, with the exception of the header. + * This function represents the common part. + * @param object The object being manipulated. + * @param length The length of the object in elements + * @param conv VarType type of the items. + */ +static void SlCopyInternal(void *object, size_t length, VarType conv) +{ + if (GetVarMemType(conv) == SLE_VAR_NULL) { + assert(_sl.action != SLA_SAVE); // Use SL_NULL if you want to write null-bytes + SlSkipBytes(length * SlCalcConvFileLen(conv)); + return; + } + + /* NOTICE - handle some buggy stuff, in really old versions everything was saved + * as a byte-type. So detect this, and adjust object size accordingly */ + if (_sl.action != SLA_SAVE && _sl_version == 0) { + /* all objects except difficulty settings */ + if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID || + conv == SLE_INT32 || conv == SLE_UINT32) { + SlCopyBytes(object, length * SlCalcConvFileLen(conv)); + return; + } + /* used for conversion of Money 32bit->64bit */ + if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) { + for (uint i = 0; i < length; i++) { + ((int64*)object)[i] = (int32)BSWAP32(SlReadUint32()); + } + return; + } + } + + /* If the size of elements is 1 byte both in file and memory, no special + * conversion is needed, use specialized copy-copy function to speed up things */ + if (conv == SLE_INT8 || conv == SLE_UINT8) { + SlCopyBytes(object, length); + } else { + byte *a = (byte*)object; + byte mem_size = SlCalcConvMemLen(conv); + + for (; length != 0; length --) { + SlSaveLoadConv(a, conv); + a += mem_size; // get size + } + } +} + +/** + * Copy a list of SL_VARs to/from a savegame. + * These entries are copied as-is, and you as caller have to make sure things + * like length-fields are calculated correctly. + * @param object The object being manipulated. + * @param length The length of the object in elements + * @param conv VarType type of the items. + */ +void SlCopy(void *object, size_t length, VarType conv) +{ + if (_sl.action == SLA_PTRS || _sl.action == SLA_NULL) return; + + /* Automatically calculate the length? */ + if (_sl.need_length != NL_NONE) { + SlSetLength(length * SlCalcConvFileLen(conv)); + /* Determine length only? */ + if (_sl.need_length == NL_CALCLENGTH) return; + } + + SlCopyInternal(object, length, conv); +} + +/** + * Return the size in bytes of a certain type of atomic array + * @param length The length of the array counted in elements + * @param conv VarType type of the variable that is used in calculating the size + */ +static inline size_t SlCalcArrayLen(size_t length, VarType conv) +{ + return SlCalcConvFileLen(conv) * length + SlGetArrayLength(length); +} + +/** + * Save/Load the length of the array followed by the array of SL_VAR elements. + * @param array The array being manipulated + * @param length The length of the array in elements + * @param conv VarType type of the atomic array (int, byte, uint64, etc.) + */ +static void SlArray(void *array, size_t length, VarType conv) +{ + switch (_sl.action) { + case SLA_SAVE: + SlWriteArrayLength(length); + SlCopyInternal(array, length, conv); + return; + + case SLA_LOAD_CHECK: + case SLA_LOAD: { + if (!IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) { + size_t sv_length = SlReadArrayLength(); + if (GetVarMemType(conv) == SLE_VAR_NULL) { + /* We don't know this field, so we assume the length in the savegame is correct. */ + length = sv_length; + } else if (sv_length != length) { + /* If the SLE_ARR changes size, a savegame bump is required + * and the developer should have written conversion lines. + * Error out to make this more visible. */ + SlErrorCorrupt("Fixed-length array is of wrong length"); + } + } + + SlCopyInternal(array, length, conv); + return; + } + + case SLA_PTRS: + case SLA_NULL: + return; + + default: + NOT_REACHED(); + } +} + +/** + * Pointers cannot be saved to a savegame, so this functions gets + * the index of the item, and if not available, it hussles with + * pointers (looks really bad :() + * Remember that a nullptr item has value 0, and all + * indices have +1, so vehicle 0 is saved as index 1. + * @param obj The object that we want to get the index of + * @param rt SLRefType type of the object the index is being sought of + * @return Return the pointer converted to an index of the type pointed to + */ +static size_t ReferenceToInt(const void *obj, SLRefType rt) +{ + assert(_sl.action == SLA_SAVE); + + if (obj == nullptr) return 0; + + switch (rt) { + case REF_VEHICLE_OLD: // Old vehicles we save as new ones + case REF_VEHICLE: return ((const Vehicle*)obj)->index + 1; + case REF_STATION: return ((const Station*)obj)->index + 1; + case REF_TOWN: return ((const Town*)obj)->index + 1; + case REF_ORDER: return ((const Order*)obj)->index + 1; + case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1; + case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1; + case REF_CARGO_PACKET: return ((const CargoPacket*)obj)->index + 1; + case REF_ORDERLIST: return ((const OrderList*)obj)->index + 1; + case REF_STORAGE: return ((const PersistentStorage*)obj)->index + 1; + case REF_LINK_GRAPH: return ((const LinkGraph*)obj)->index + 1; + case REF_LINK_GRAPH_JOB: return ((const LinkGraphJob*)obj)->index + 1; + default: NOT_REACHED(); + } +} + +/** + * Pointers cannot be loaded from a savegame, so this function + * gets the index from the savegame and returns the appropriate + * pointer from the already loaded base. + * Remember that an index of 0 is a nullptr pointer so all indices + * are +1 so vehicle 0 is saved as 1. + * @param index The index that is being converted to a pointer + * @param rt SLRefType type of the object the pointer is sought of + * @return Return the index converted to a pointer of any type + */ +static void *IntToReference(size_t index, SLRefType rt) +{ + static_assert(sizeof(size_t) <= sizeof(void *)); + + assert(_sl.action == SLA_PTRS); + + /* After version 4.3 REF_VEHICLE_OLD is saved as REF_VEHICLE, + * and should be loaded like that */ + if (rt == REF_VEHICLE_OLD && !IsSavegameVersionBefore(SLV_4, 4)) { + rt = REF_VEHICLE; + } + + /* No need to look up nullptr pointers, just return immediately */ + if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return nullptr; + + /* Correct index. Old vehicles were saved differently: + * invalid vehicle was 0xFFFF, now we use 0x0000 for everything invalid. */ + if (rt != REF_VEHICLE_OLD) index--; + + switch (rt) { + case REF_ORDERLIST: + if (OrderList::IsValidID(index)) return OrderList::Get(index); + SlErrorCorrupt("Referencing invalid OrderList"); + + case REF_ORDER: + if (Order::IsValidID(index)) return Order::Get(index); + /* in old versions, invalid order was used to mark end of order list */ + if (IsSavegameVersionBefore(SLV_5, 2)) return nullptr; + SlErrorCorrupt("Referencing invalid Order"); + + case REF_VEHICLE_OLD: + case REF_VEHICLE: + if (Vehicle::IsValidID(index)) return Vehicle::Get(index); + SlErrorCorrupt("Referencing invalid Vehicle"); + + case REF_STATION: + if (Station::IsValidID(index)) return Station::Get(index); + SlErrorCorrupt("Referencing invalid Station"); + + case REF_TOWN: + if (Town::IsValidID(index)) return Town::Get(index); + SlErrorCorrupt("Referencing invalid Town"); + + case REF_ROADSTOPS: + if (RoadStop::IsValidID(index)) return RoadStop::Get(index); + SlErrorCorrupt("Referencing invalid RoadStop"); + + case REF_ENGINE_RENEWS: + if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index); + SlErrorCorrupt("Referencing invalid EngineRenew"); + + case REF_CARGO_PACKET: + if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index); + SlErrorCorrupt("Referencing invalid CargoPacket"); + + case REF_STORAGE: + if (PersistentStorage::IsValidID(index)) return PersistentStorage::Get(index); + SlErrorCorrupt("Referencing invalid PersistentStorage"); + + case REF_LINK_GRAPH: + if (LinkGraph::IsValidID(index)) return LinkGraph::Get(index); + SlErrorCorrupt("Referencing invalid LinkGraph"); + + case REF_LINK_GRAPH_JOB: + if (LinkGraphJob::IsValidID(index)) return LinkGraphJob::Get(index); + SlErrorCorrupt("Referencing invalid LinkGraphJob"); + + default: NOT_REACHED(); + } +} + +/** + * Handle conversion for references. + * @param ptr The object being filled/read. + * @param conv VarType type of the current element of the struct. + */ +void SlSaveLoadRef(void *ptr, VarType conv) +{ + switch (_sl.action) { + case SLA_SAVE: + SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv)); + break; + case SLA_LOAD_CHECK: + case SLA_LOAD: + *(size_t *)ptr = IsSavegameVersionBefore(SLV_69) ? SlReadUint16() : SlReadUint32(); + break; + case SLA_PTRS: + *(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv); + break; + case SLA_NULL: + *(void **)ptr = nullptr; + break; + default: NOT_REACHED(); + } +} + +/** + * Template class to help with list-like types. + */ +template typename Tstorage, typename Tvar, typename Tallocator = std::allocator> +class SlStorageHelper { + typedef Tstorage SlStorageT; +public: + /** + * Internal templated helper to return the size in bytes of a list-like type. + * @param storage The storage to find the size of + * @param conv VarType type of variable that is used for calculating the size + * @param cmd The SaveLoadType ware are saving/loading. + */ + static size_t SlCalcLen(const void *storage, VarType conv, SaveLoadType cmd = SL_VAR) + { + assert(cmd == SL_VAR || cmd == SL_REF); + + const SlStorageT *list = static_cast(storage); + + int type_size = SlGetArrayLength(list->size()); + int item_size = SlCalcConvFileLen(cmd == SL_VAR ? conv : (VarType)SLE_FILE_U32); + return list->size() * item_size + type_size; + } + + static void SlSaveLoadMember(SaveLoadType cmd, Tvar *item, VarType conv) + { + switch (cmd) { + case SL_VAR: SlSaveLoadConv(item, conv); break; + case SL_REF: SlSaveLoadRef(item, conv); break; + default: + NOT_REACHED(); + } + } + + /** + * Internal templated helper to save/load a list-like type. + * @param storage The storage being manipulated. + * @param conv VarType type of variable that is used for calculating the size. + * @param cmd The SaveLoadType ware are saving/loading. + */ + static void SlSaveLoad(void *storage, VarType conv, SaveLoadType cmd = SL_VAR) + { + assert(cmd == SL_VAR || cmd == SL_REF); + + SlStorageT *list = static_cast(storage); + + switch (_sl.action) { + case SLA_SAVE: + SlWriteArrayLength(list->size()); + + for (auto &item : *list) { + SlSaveLoadMember(cmd, &item, conv); + } + break; + + case SLA_LOAD_CHECK: + case SLA_LOAD: { + size_t length; + switch (cmd) { + case SL_VAR: length = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? SlReadUint32() : SlReadArrayLength(); break; + case SL_REF: length = IsSavegameVersionBefore(SLV_69) ? SlReadUint16() : IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? SlReadUint32() : SlReadArrayLength(); break; + default: NOT_REACHED(); + } + + /* Load each value and push to the end of the storage. */ + for (size_t i = 0; i < length; i++) { + Tvar &data = list->emplace_back(); + SlSaveLoadMember(cmd, &data, conv); + } + break; + } + + case SLA_PTRS: + for (auto &item : *list) { + SlSaveLoadMember(cmd, &item, conv); + } + break; + + case SLA_NULL: + list->clear(); + break; + + default: NOT_REACHED(); + } + } +}; + +/** + * Return the size in bytes of a list. + * @param list The std::list to find the size of. + * @param conv VarType type of variable that is used for calculating the size. + */ +static inline size_t SlCalcRefListLen(const void *list, VarType conv) +{ + return SlStorageHelper::SlCalcLen(list, conv, SL_REF); +} + +/** + * Return the size in bytes of a deque. + * @param list The std::list to find the size of. + * @param conv VarType type of variable that is used for calculating the size. + */ +static inline size_t SlCalcRefDequeLen(const void *list, VarType conv) +{ + return SlStorageHelper::SlCalcLen(list, conv, SL_REF); +} + +/** + * Return the size in bytes of a vector. + * @param list The std::list to find the size of. + * @param conv VarType type of variable that is used for calculating the size. + */ +static inline size_t SlCalcRefVectorLen(const void *list, VarType conv) +{ + return SlStorageHelper::SlCalcLen(list, conv, SL_REF); +} + +/** + * Save/Load a list. + * @param list The list being manipulated. + * @param conv VarType type of variable that is used for calculating the size. + */ +static void SlRefList(void *list, VarType conv) +{ + /* Automatically calculate the length? */ + if (_sl.need_length != NL_NONE) { + SlSetLength(SlCalcRefListLen(list, conv)); + /* Determine length only? */ + if (_sl.need_length == NL_CALCLENGTH) return; + } + + SlStorageHelper::SlSaveLoad(list, conv, SL_REF); +} + +/** + * Save/Load a deque. + * @param list The list being manipulated. + * @param conv VarType type of variable that is used for calculating the size. + */ +static void SlRefDeque(void *list, VarType conv) +{ + /* Automatically calculate the length? */ + if (_sl.need_length != NL_NONE) { + SlSetLength(SlCalcRefDequeLen(list, conv)); + /* Determine length only? */ + if (_sl.need_length == NL_CALCLENGTH) return; + } + + SlStorageHelper::SlSaveLoad(list, conv, SL_REF); +} + +/** + * Save/Load a deque. + * @param list The list being manipulated. + * @param conv VarType type of variable that is used for calculating the size. + */ +static void SlRefVector(void *list, VarType conv) +{ + /* Automatically calculate the length? */ + if (_sl.need_length != NL_NONE) { + SlSetLength(SlCalcRefVectorLen(list, conv)); + /* Determine length only? */ + if (_sl.need_length == NL_CALCLENGTH) return; + } + + SlStorageHelper::SlSaveLoad(list, conv, SL_REF); +} + +/** + * Return the size in bytes of a std::deque. + * @param deque The std::deque to find the size of + * @param conv VarType type of variable that is used for calculating the size + */ +static inline size_t SlCalcDequeLen(const void *deque, VarType conv) +{ + switch (GetVarMemType(conv)) { + case SLE_VAR_BL: return SlStorageHelper::SlCalcLen(deque, conv); + case SLE_VAR_I8: return SlStorageHelper::SlCalcLen(deque, conv); + case SLE_VAR_U8: return SlStorageHelper::SlCalcLen(deque, conv); + case SLE_VAR_I16: return SlStorageHelper::SlCalcLen(deque, conv); + case SLE_VAR_U16: return SlStorageHelper::SlCalcLen(deque, conv); + case SLE_VAR_I32: return SlStorageHelper::SlCalcLen(deque, conv); + case SLE_VAR_U32: return SlStorageHelper::SlCalcLen(deque, conv); + case SLE_VAR_I64: return SlStorageHelper::SlCalcLen(deque, conv); + case SLE_VAR_U64: return SlStorageHelper::SlCalcLen(deque, conv); + default: NOT_REACHED(); + } +} + +/** + * Save/load a std::deque. + * @param deque The std::deque being manipulated + * @param conv VarType type of variable that is used for calculating the size + */ +static void SlDeque(void *deque, VarType conv) +{ + switch (GetVarMemType(conv)) { + case SLE_VAR_BL: SlStorageHelper::SlSaveLoad(deque, conv); break; + case SLE_VAR_I8: SlStorageHelper::SlSaveLoad(deque, conv); break; + case SLE_VAR_U8: SlStorageHelper::SlSaveLoad(deque, conv); break; + case SLE_VAR_I16: SlStorageHelper::SlSaveLoad(deque, conv); break; + case SLE_VAR_U16: SlStorageHelper::SlSaveLoad(deque, conv); break; + case SLE_VAR_I32: SlStorageHelper::SlSaveLoad(deque, conv); break; + case SLE_VAR_U32: SlStorageHelper::SlSaveLoad(deque, conv); break; + case SLE_VAR_I64: SlStorageHelper::SlSaveLoad(deque, conv); break; + case SLE_VAR_U64: SlStorageHelper::SlSaveLoad(deque, conv); break; + default: NOT_REACHED(); + } +} + +/** + * Return the size in bytes of a std::vector. + * @param vector The std::vector to find the size of + * @param conv VarType type of variable that is used for calculating the size + */ +static inline size_t SlCalcVectorLen(const void *vector, VarType conv) +{ + switch (GetVarMemType(conv)) { + case SLE_VAR_BL: NOT_REACHED(); // Not supported + case SLE_VAR_I8: return SlStorageHelper::SlCalcLen(vector, conv); + case SLE_VAR_U8: return SlStorageHelper::SlCalcLen(vector, conv); + case SLE_VAR_I16: return SlStorageHelper::SlCalcLen(vector, conv); + case SLE_VAR_U16: return SlStorageHelper::SlCalcLen(vector, conv); + case SLE_VAR_I32: return SlStorageHelper::SlCalcLen(vector, conv); + case SLE_VAR_U32: return SlStorageHelper::SlCalcLen(vector, conv); + case SLE_VAR_I64: return SlStorageHelper::SlCalcLen(vector, conv); + case SLE_VAR_U64: return SlStorageHelper::SlCalcLen(vector, conv); + default: NOT_REACHED(); + } +} + +/** + * Save/load a std::vector. + * @param vector The std::vector being manipulated + * @param conv VarType type of variable that is used for calculating the size + */ +static void SlVector(void *vector, VarType conv) +{ + switch (GetVarMemType(conv)) { + case SLE_VAR_BL: NOT_REACHED(); // Not supported + case SLE_VAR_I8: SlStorageHelper::SlSaveLoad(vector, conv); break; + case SLE_VAR_U8: SlStorageHelper::SlSaveLoad(vector, conv); break; + case SLE_VAR_I16: SlStorageHelper::SlSaveLoad(vector, conv); break; + case SLE_VAR_U16: SlStorageHelper::SlSaveLoad(vector, conv); break; + case SLE_VAR_I32: SlStorageHelper::SlSaveLoad(vector, conv); break; + case SLE_VAR_U32: SlStorageHelper::SlSaveLoad(vector, conv); break; + case SLE_VAR_I64: SlStorageHelper::SlSaveLoad(vector, conv); break; + case SLE_VAR_U64: SlStorageHelper::SlSaveLoad(vector, conv); break; + default: NOT_REACHED(); + } +} + +/** Are we going to save this object or not? */ +static inline bool SlIsObjectValidInSavegame(const SaveLoad &sld) +{ + return (_sl_version >= sld.version_from && _sl_version < sld.version_to); +} + +/** + * Calculate the size of the table header. + * @param slt The SaveLoad table with objects to save/load. + * @return size of given object. + */ +static size_t SlCalcTableHeader(const SaveLoadTable &slt) +{ + size_t length = 0; + + for (auto &sld : slt) { + if (!SlIsObjectValidInSavegame(sld)) continue; + + length += SlCalcConvFileLen(SLE_UINT8); + length += SlCalcStdStringLen(&sld.name); + } + + length += SlCalcConvFileLen(SLE_UINT8); // End-of-list entry. + + for (auto &sld : slt) { + if (!SlIsObjectValidInSavegame(sld)) continue; + if (sld.cmd == SL_STRUCTLIST || sld.cmd == SL_STRUCT) { + length += SlCalcTableHeader(sld.handler->GetDescription()); + } + } + + return length; +} + +/** + * Calculate the size of an object. + * @param object to be measured. + * @param slt The SaveLoad table with objects to save/load. + * @return size of given object. + */ +size_t SlCalcObjLength(const void *object, const SaveLoadTable &slt) +{ + size_t length = 0; + + /* Need to determine the length and write a length tag. */ + for (auto &sld : slt) { + length += SlCalcObjMemberLength(object, sld); + } + return length; +} + +size_t SlCalcObjMemberLength(const void *object, const SaveLoad &sld) +{ + assert(_sl.action == SLA_SAVE); + + if (!SlIsObjectValidInSavegame(sld)) return 0; + + switch (sld.cmd) { + case SL_VAR: return SlCalcConvFileLen(sld.conv); + case SL_REF: return SlCalcRefLen(); + case SL_ARR: return SlCalcArrayLen(sld.length, sld.conv); + case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld.length, sld.conv); + case SL_REFLIST: return SlCalcRefListLen(GetVariableAddress(object, sld), sld.conv); + case SL_REFDEQUE: return SlCalcRefDequeLen(GetVariableAddress(object, sld), sld.conv); + case SL_REFVEC: return SlCalcRefVectorLen(GetVariableAddress(object, sld), sld.conv); + case SL_DEQUE: return SlCalcDequeLen(GetVariableAddress(object, sld), sld.conv); + case SL_VECTOR: return SlCalcVectorLen(GetVariableAddress(object, sld), sld.conv); + case SL_STDSTR: return SlCalcStdStringLen(GetVariableAddress(object, sld)); + case SL_SAVEBYTE: return 1; // a byte is logically of size 1 + case SL_NULL: return SlCalcConvFileLen(sld.conv) * sld.length; + + case SL_STRUCT: + case SL_STRUCTLIST: { + 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; + + if (sld.cmd == SL_STRUCT) { + length += SlGetArrayLength(1); + } + + return length; + } + + default: NOT_REACHED(); + } + return 0; +} + +/** + * Check whether the variable size of the variable in the saveload configuration + * matches with the actual variable size. + * @param sld The saveload configuration to test. + */ +[[maybe_unused]] static bool IsVariableSizeRight(const SaveLoad &sld) +{ + if (GetVarMemType(sld.conv) == SLE_VAR_NULL) return true; + + switch (sld.cmd) { + case SL_VAR: + switch (GetVarMemType(sld.conv)) { + case SLE_VAR_BL: + return sld.size == sizeof(bool); + case SLE_VAR_I8: + case SLE_VAR_U8: + return sld.size == sizeof(int8); + case SLE_VAR_I16: + case SLE_VAR_U16: + return sld.size == sizeof(int16); + case SLE_VAR_I32: + case SLE_VAR_U32: + return sld.size == sizeof(int32); + case SLE_VAR_I64: + case SLE_VAR_U64: + return sld.size == sizeof(int64); + case SLE_VAR_NAME: + return sld.size == sizeof(std::string); + default: + return sld.size == sizeof(void *); + } + case SL_REF: + /* These should all be pointer sized. */ + return sld.size == sizeof(void *); + + case SL_STR: + /* These should be pointer sized, or fixed array. */ + return sld.size == sizeof(void *) || sld.size == sld.length; + + case SL_STDSTR: + /* These should be all pointers to std::string. */ + return sld.size == sizeof(std::string); + + default: + return true; + } +} + +static bool SlObjectMember(void *object, const SaveLoad &sld) +{ + assert_msg(IsVariableSizeRight(sld), "%s, size: %u, length: %u, cmd: %u, conv: 0x%02X", sld.name.c_str(), (uint) sld.size, sld.length, sld.cmd, sld.conv); + + if (!SlIsObjectValidInSavegame(sld)) return false; + + VarType conv = GB(sld.conv, 0, 8); + switch (sld.cmd) { + case SL_VAR: + case SL_REF: + case SL_ARR: + case SL_STR: + case SL_REFLIST: + case SL_REFDEQUE: + case SL_REFVEC: + case SL_DEQUE: + case SL_VECTOR: + case SL_STDSTR: { + void *ptr = GetVariableAddress(object, sld); + + switch (sld.cmd) { + case SL_VAR: SlSaveLoadConv(ptr, conv); break; + case SL_REF: SlSaveLoadRef(ptr, conv); break; + case SL_ARR: SlArray(ptr, sld.length, conv); break; + case SL_STR: SlString(ptr, sld.length, sld.conv); break; + case SL_REFLIST: SlRefList(ptr, conv); break; + case SL_REFDEQUE: SlRefDeque(ptr, conv); break; + case SL_REFVEC: SlRefVector(ptr, conv); break; + case SL_DEQUE: SlDeque(ptr, conv); break; + case SL_VECTOR: SlVector(ptr, conv); break; + case SL_STDSTR: SlStdString(ptr, sld.conv); break; + default: NOT_REACHED(); + } + break; + } + + /* 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_SAVEBYTE: { + void *ptr = GetVariableAddress(object, sld); + + switch (_sl.action) { + case SLA_SAVE: SlWriteByte(*(uint8 *)ptr); break; + case SLA_LOAD_CHECK: + case SLA_LOAD: + case SLA_PTRS: + case SLA_NULL: break; + default: NOT_REACHED(); + } + break; + } + + case SL_NULL: { + assert(GetVarMemType(sld.conv) == SLE_VAR_NULL); + + switch (_sl.action) { + case SLA_LOAD_CHECK: + case SLA_LOAD: SlSkipBytes(SlCalcConvFileLen(sld.conv) * sld.length); break; + case SLA_SAVE: for (int i = 0; i < SlCalcConvFileLen(sld.conv) * sld.length; i++) SlWriteByte(0); break; + case SLA_PTRS: + case SLA_NULL: break; + default: NOT_REACHED(); + } + break; + } + + case SL_STRUCT: + case SL_STRUCTLIST: + switch (_sl.action) { + case SLA_SAVE: { + if (sld.cmd == SL_STRUCT) { + /* Store in the savegame if this struct was written or not. */ + SlSetStructListLength(SlCalcObjMemberLength(object, sld) > SlGetArrayLength(1) ? 1 : 0); + } + sld.handler->Save(object); + break; + } + + case SLA_LOAD_CHECK: { + if (sld.cmd == SL_STRUCT && !IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) { + SlGetStructListLength(1); + } + sld.handler->LoadCheck(object); + break; + } + + case SLA_LOAD: { + if (sld.cmd == SL_STRUCT && !IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) { + SlGetStructListLength(1); + } + sld.handler->Load(object); + break; + } + + case SLA_PTRS: + sld.handler->FixPointers(object); + break; + + case SLA_NULL: break; + default: NOT_REACHED(); + } + break; + + default: NOT_REACHED(); + } + return true; +} + +/** + * Set the length of this list. + * @param The length of the list. + */ +void SlSetStructListLength(size_t length) +{ + /* Automatically calculate the length? */ + if (_sl.need_length != NL_NONE) { + SlSetLength(SlGetArrayLength(length)); + if (_sl.need_length == NL_CALCLENGTH) return; + } + + SlWriteArrayLength(length); +} + +/** + * Get the length of this list; if it exceeds the limit, error out. + * @param limit The maximum size the list can be. + * @return The length of the list. + */ +size_t SlGetStructListLength(size_t limit) +{ + size_t length = SlReadArrayLength(); + if (length > limit) SlErrorCorrupt("List exceeds storage size"); + + return length; +} + +/** + * Main SaveLoad function. + * @param object The object that is being saved or loaded. + * @param slt The SaveLoad table with objects to save/load. + */ +void SlObject(void *object, const SaveLoadTable &slt) +{ + /* Automatically calculate the length? */ + if (_sl.need_length != NL_NONE) { + SlSetLength(SlCalcObjLength(object, slt)); + if (_sl.need_length == NL_CALCLENGTH) return; + } + + for (auto &sld : slt) { + SlObjectMember(object, sld); + } +} + +/** + * Handler that is assigned when there is a struct read in the savegame which + * is not known to the code. This means we are going to skip it. + */ +class SlSkipHandler : public SaveLoadHandler { + void Save(void *object) const override + { + NOT_REACHED(); + } + + void Load(void *object) const override + { + size_t length = SlGetStructListLength(UINT32_MAX); + for (; length > 0; length--) { + SlObject(object, this->GetLoadDescription()); + } + } + + void LoadCheck(void *object) const override + { + this->Load(object); + } + + virtual SaveLoadTable GetDescription() const override + { + return {}; + } + + virtual SaveLoadCompatTable GetCompatDescription() const override + { + NOT_REACHED(); + } +}; + +/** + * Save or Load a table header. + * @note a table-header can never contain more than 65535 fields. + * @param slt The SaveLoad table with objects to save/load. + * @return When loading, the ordered SaveLoad array to use; otherwise an empty list. + */ +std::vector SlTableHeader(const SaveLoadTable &slt) +{ + /* You can only use SlTableHeader if you are a CH_TABLE. */ + assert(_sl.block_mode == CH_TABLE || _sl.block_mode == CH_SPARSE_TABLE); + + switch (_sl.action) { + case SLA_LOAD_CHECK: + case SLA_LOAD: { + std::vector saveloads; + + /* Build a key lookup mapping based on the available fields. */ + std::map key_lookup; + for (auto &sld : slt) { + if (!SlIsObjectValidInSavegame(sld)) continue; + + /* Check that there is only one active SaveLoad for a given name. */ + assert(key_lookup.find(sld.name) == key_lookup.end()); + key_lookup[sld.name] = &sld; + } + + while (true) { + uint8 type; + SlSaveLoadConv(&type, SLE_UINT8); + if (type == SLE_FILE_END) break; + + std::string key; + SlStdString(&key, SLE_STR); + + auto sld_it = key_lookup.find(key); + if (sld_it == key_lookup.end()) { + /* SLA_LOADCHECK triggers this debug statement a lot and is perfectly normal. */ + DEBUG(sl, _sl.action == SLA_LOAD ? 2 : 6, "Field '%s' of type 0x%02X not found, skipping", key.c_str(), type); + + std::shared_ptr handler = nullptr; + SaveLoadType slt; + switch (type & SLE_FILE_TYPE_MASK) { + case SLE_FILE_STRING: + /* Strings are always marked with SLE_FILE_HAS_LENGTH_FIELD, as they are a list of chars. */ + slt = SL_STR; + break; + + case SLE_FILE_STRUCT: + /* Structs are always marked with SLE_FILE_HAS_LENGTH_FIELD as SL_STRUCT is seen as a list of 0/1 in length. */ + slt = SL_STRUCTLIST; + handler = std::make_shared(); + break; + + default: + slt = (type & SLE_FILE_HAS_LENGTH_FIELD) ? SL_ARR : SL_VAR; + break; + } + + /* We don't know this field, so read to nothing. */ + saveloads.push_back({key, slt, ((VarType)type & SLE_FILE_TYPE_MASK) | SLE_VAR_NULL, 1, SL_MIN_VERSION, SL_MAX_VERSION, 0, nullptr, 0, handler}); + continue; + } + + /* Validate the type of the field. If it is changed, the + * savegame should have been bumped so we know how to do the + * conversion. If this error triggers, that clearly didn't + * happen and this is a friendly poke to the developer to bump + * the savegame version and add conversion code. */ + uint8 correct_type = GetSavegameFileType(*sld_it->second); + if (correct_type != type) { + DEBUG(sl, 1, "Field type for '%s' was expected to be 0x%02X but 0x%02X was found", key.c_str(), correct_type, type); + SlErrorCorrupt("Field type is different than expected"); + } + saveloads.push_back(*sld_it->second); + } + + for (auto &sld : saveloads) { + if (sld.cmd == SL_STRUCTLIST || sld.cmd == SL_STRUCT) { + sld.handler->load_description = SlTableHeader(sld.handler->GetDescription()); + } + } + + return saveloads; + } + + case SLA_SAVE: { + /* Automatically calculate the length? */ + if (_sl.need_length != NL_NONE) { + SlSetLength(SlCalcTableHeader(slt)); + if (_sl.need_length == NL_CALCLENGTH) break; + } + + for (auto &sld : slt) { + if (!SlIsObjectValidInSavegame(sld)) continue; + /* Make sure we are not storing empty keys. */ + assert(!sld.name.empty()); + + uint8 type = GetSavegameFileType(sld); + assert(type != SLE_FILE_END); + + SlSaveLoadConv(&type, SLE_UINT8); + SlStdString(const_cast(&sld.name), SLE_STR); + } + + /* Add an end-of-header marker. */ + uint8 type = SLE_FILE_END; + SlSaveLoadConv(&type, SLE_UINT8); + + /* After the table, write down any sub-tables we might have. */ + for (auto &sld : slt) { + if (!SlIsObjectValidInSavegame(sld)) continue; + if (sld.cmd == SL_STRUCTLIST || sld.cmd == SL_STRUCT) { + /* SlCalcTableHeader already looks in sub-lists, so avoid the length being added twice. */ + NeedLength old_need_length = _sl.need_length; + _sl.need_length = NL_NONE; + + SlTableHeader(sld.handler->GetDescription()); + + _sl.need_length = old_need_length; + } + } + + break; + } + + default: NOT_REACHED(); + } + + return std::vector(); +} + +/** + * Load a table header in a savegame compatible way. If the savegame was made + * before table headers were added, it will fall back to the + * SaveLoadCompatTable for the order of fields while loading. + * + * @note You only have to call this function if the chunk existed as a + * non-table type before converting it to a table. New chunks created as + * table can call SlTableHeader() directly. + * + * @param slt The SaveLoad table with objects to save/load. + * @param slct The SaveLoadCompat table the original order of the fields. + * @return When loading, the ordered SaveLoad array to use; otherwise an empty list. + */ +std::vector SlCompatTableHeader(const SaveLoadTable &slt, const SaveLoadCompatTable &slct) +{ + assert(_sl.action == SLA_LOAD || _sl.action == SLA_LOAD_CHECK); + /* CH_TABLE / CH_SPARSE_TABLE always have a header. */ + if (_sl.block_mode == CH_TABLE || _sl.block_mode == CH_SPARSE_TABLE) return SlTableHeader(slt); + + std::vector saveloads; + + /* Build a key lookup mapping based on the available fields. */ + std::map> key_lookup; + for (auto &sld : slt) { + /* All entries should have a name; otherwise the entry should just be removed. */ + assert(!sld.name.empty()); + + key_lookup[sld.name].push_back(&sld); + } + + for (auto &slc : slct) { + if (slc.name.empty()) { + /* In old savegames there can be data we no longer care for. We + * skip this by simply reading the amount of bytes indicated and + * send those to /dev/null. */ + saveloads.push_back({"", SL_NULL, SLE_FILE_U8 | SLE_VAR_NULL, slc.length, slc.version_from, slc.version_to, 0, nullptr, 0, nullptr}); + } else { + auto sld_it = key_lookup.find(slc.name); + /* If this branch triggers, it means that an entry in the + * SaveLoadCompat list is not mentioned in the SaveLoad list. Did + * you rename a field in one and not in the other? */ + if (sld_it == key_lookup.end()) { + /* This isn't an assert, as that leaves no information what + * field was to blame. This way at least we have breadcrumbs. */ + DEBUG(sl, 0, "internal error: saveload compatibility field '%s' not found", slc.name.c_str()); + SlErrorCorrupt("Internal error with savegame compatibility"); + } + for (auto &sld : sld_it->second) { + saveloads.push_back(*sld); + } + } + } + + for (auto &sld : saveloads) { + if (!SlIsObjectValidInSavegame(sld)) continue; + if (sld.cmd == SL_STRUCTLIST || sld.cmd == SL_STRUCT) { + sld.handler->load_description = SlCompatTableHeader(sld.handler->GetDescription(), sld.handler->GetCompatDescription()); + } + } + + return saveloads; +} + +/** + * Save or Load (a list of) global variables. + * @param slt The SaveLoad table with objects to save/load. + */ +void SlGlobList(const SaveLoadTable &slt) +{ + SlObject(nullptr, slt); +} + +/** + * Do something of which I have no idea what it is :P + * @param proc The callback procedure that is called + * @param arg The variable that will be used for the callback procedure + */ +void SlAutolength(AutolengthProc *proc, void *arg) +{ + // removed + NOT_REACHED(); +} + +void ChunkHandler::LoadCheck(size_t len) const +{ + switch (_sl.block_mode) { + case CH_TABLE: + case CH_SPARSE_TABLE: + SlTableHeader({}); + FALLTHROUGH; + case CH_ARRAY: + case CH_SPARSE_ARRAY: + SlSkipArray(); + break; + case CH_RIFF: + SlSkipBytes(len); + break; + default: + NOT_REACHED(); + } +} + +/** + * Load a chunk of data (eg vehicles, stations, etc.) + * @param ch The chunkhandler that will be used for the operation + */ +static void SlLoadChunk(const ChunkHandler &ch) +{ + byte m = SlReadByte(); + size_t len; + size_t endoffs; + + _sl.block_mode = m & CH_TYPE_MASK; + _sl.obj_len = 0; + _sl.expect_table_header = (_sl.block_mode == CH_TABLE || _sl.block_mode == CH_SPARSE_TABLE); + + /* The header should always be at the start. Read the length; the + * Load() should as first action process the header. */ + if (_sl.expect_table_header) { + SlIterateArray(); + } + + switch (_sl.block_mode) { + case CH_TABLE: + case CH_ARRAY: + _sl.array_index = 0; + ch.Load(); + if (_next_offs != 0) SlErrorCorrupt("Invalid array length"); + break; + case CH_SPARSE_TABLE: + case CH_SPARSE_ARRAY: + ch.Load(); + if (_next_offs != 0) SlErrorCorrupt("Invalid array length"); + break; + case CH_RIFF: + /* Read length */ + len = (SlReadByte() << 16) | ((m >> 4) << 24); + len += SlReadUint16(); + _sl.obj_len = len; + endoffs = SlGetBytesRead() + len; + ch.Load(); + if (SlGetBytesRead() != endoffs) SlErrorCorrupt("Invalid chunk size"); + break; + default: + SlErrorCorrupt("Invalid chunk type"); + break; + } + + if (_sl.expect_table_header) SlErrorCorrupt("Table chunk without header"); +} + +/** + * Load a chunk of data for checking savegames. + * If the chunkhandler is nullptr, the chunk is skipped. + * @param ch The chunkhandler that will be used for the operation + */ +static void SlLoadCheckChunk(const ChunkHandler &ch) +{ + byte m = SlReadByte(); + size_t len; + size_t endoffs; + + _sl.block_mode = m & CH_TYPE_MASK; + _sl.obj_len = 0; + _sl.expect_table_header = (_sl.block_mode == CH_TABLE || _sl.block_mode == CH_SPARSE_TABLE); + + /* The header should always be at the start. Read the length; the + * LoadCheck() should as first action process the header. */ + if (_sl.expect_table_header) { + SlIterateArray(); + } + + switch (_sl.block_mode) { + case CH_TABLE: + case CH_ARRAY: + _sl.array_index = 0; + ch.LoadCheck(); + break; + case CH_SPARSE_TABLE: + case CH_SPARSE_ARRAY: + ch.LoadCheck(); + break; + case CH_RIFF: + /* Read length */ + len = (SlReadByte() << 16) | ((m >> 4) << 24); + len += SlReadUint16(); + _sl.obj_len = len; + endoffs = SlGetBytesRead() + len; + ch.LoadCheck(len); + if (SlGetBytesRead() != endoffs) SlErrorCorrupt("Invalid chunk size"); + break; + default: + SlErrorCorrupt("Invalid chunk type"); + break; + } + + if (_sl.expect_table_header) SlErrorCorrupt("Table chunk without header"); +} + +/** + * Find the ChunkHandler that will be used for processing the found + * chunk in the savegame or in memory + * @param id the chunk in question + * @return returns the appropriate chunkhandler + */ +static const ChunkHandler *SlFindChunkHandler(uint32 id) +{ + for (const ChunkHandler &ch : ChunkHandlers()) if (ch.id == id) return &ch; + return nullptr; +} + +/** Load all chunks */ +void SlLoadChunks() +{ + _sl.action = SLA_LOAD; + + uint32 id; + const ChunkHandler *ch; + + for (id = SlReadUint32(); id != 0; id = SlReadUint32()) { + DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id); + + ch = SlFindChunkHandler(id); + if (ch == nullptr) SlErrorCorrupt("Unknown chunk type"); + SlLoadChunk(*ch); + } +} + +/** Load all chunks for savegame checking */ +void SlLoadCheckChunks() +{ + _sl.action = SLA_LOAD_CHECK; + + uint32 id; + const ChunkHandler *ch; + + for (id = SlReadUint32(); id != 0; id = SlReadUint32()) { + DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id); + + ch = SlFindChunkHandler(id); + if (ch == nullptr) SlErrorCorrupt("Unknown chunk type"); + SlLoadCheckChunk(*ch); + } +} + +/** Fix all pointers (convert index -> pointer) */ +void SlFixPointers() +{ + _sl.action = SLA_PTRS; + + for (const ChunkHandler &ch : ChunkHandlers()) { + DEBUG(sl, 3, "Fixing pointers for %c%c%c%c", ch.id >> 24, ch.id >> 16, ch.id >> 8, ch.id); + ch.FixPointers(); + } + + assert(_sl.action == SLA_PTRS); +} + +SaveLoadTable SaveLoadHandler::GetLoadDescription() const +{ + assert(this->load_description.has_value()); + return *this->load_description; +} + +} diff --git a/src/saveload/upstream/saveload.h b/src/saveload/upstream/saveload.h new file mode 100644 index 0000000000..b7fc9fbd2d --- /dev/null +++ b/src/saveload/upstream/saveload.h @@ -0,0 +1,830 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file saveload.h Functions/types related to saving and loading games. */ + +#ifndef UPSTREAM_SAVELOAD_H +#define UPSTREAM_SAVELOAD_H + +#include "../saveload_common.h" +#include "../../fileio_type.h" +#include "../../fios.h" +#include "../../strings_type.h" +#include "../../core/span_type.hpp" +#include +#include +#include + +extern SaveLoadVersion _sl_version; +extern byte _sl_minor_version; +extern const SaveLoadVersion SAVEGAME_VERSION; + +namespace upstream_sl { + +typedef void AutolengthProc(void *arg); + +/** Type of a chunk. */ +enum ChunkType { + CH_RIFF = 0, + CH_ARRAY = 1, + CH_SPARSE_ARRAY = 2, + CH_TABLE = 3, + CH_SPARSE_TABLE = 4, + + CH_TYPE_MASK = 0xf, ///< All ChunkType values have to be within this mask. + CH_READONLY, ///< Chunk is never saved. +}; + +/** Handlers and description of chunk. */ +struct ChunkHandler { + uint32 id; ///< Unique ID (4 letters). + ChunkType type; ///< Type of the chunk. @see ChunkType + + ChunkHandler(uint32 id, ChunkType type) : id(id), type(type) {} + + virtual ~ChunkHandler() {} + + /** + * Save the chunk. + * Must be overridden, unless Chunk type is CH_READONLY. + */ + virtual void Save() const { NOT_REACHED(); } + + /** + * Load the chunk. + * Must be overridden. + */ + virtual void Load() const = 0; + + /** + * Fix the pointers. + * Pointers are saved using the index of the pointed object. + * On load, pointers are filled with indices and need to be fixed to point to the real object. + * Must be overridden if the chunk saves any pointer. + */ + virtual void FixPointers() const {} + + /** + * Load the chunk for game preview. + * Default implementation just skips the data. + * @param len Number of bytes to skip. + */ + virtual void LoadCheck(size_t len = 0) const; +}; + +/** A reference to ChunkHandler. */ +using ChunkHandlerRef = std::reference_wrapper; + +/** A table of ChunkHandler entries. */ +using ChunkHandlerTable = span; + +/** A table of SaveLoadCompat entries. */ +using SaveLoadCompatTable = span; + +/** Handler for saving/loading an object to/from disk. */ +class SaveLoadHandler { +public: + std::optional> load_description; + + 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; + + /** + * Get the pre-header description of the fields in the savegame. + */ + virtual SaveLoadCompatTable GetCompatDescription() const = 0; + + /** + * Get the description for how to load the chunk. Depending on the + * savegame version this can either use the headers in the savegame or + * fall back to backwards compatibility and uses hard-coded headers. + */ + SaveLoadTable GetLoadDescription() const; +}; + +/** + * 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; } + SaveLoadCompatTable GetCompatDescription() const override { return static_cast(this)->compat_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. + REF_VEHICLE = 1, ///< Load/save a reference to a vehicle. + REF_STATION = 2, ///< Load/save a reference to a station. + REF_TOWN = 3, ///< Load/save a reference to a town. + REF_VEHICLE_OLD = 4, ///< Load/save an old-style reference to a vehicle (for pre-4.4 savegames). + REF_ROADSTOPS = 5, ///< Load/save a reference to a bus/truck stop. + REF_ENGINE_RENEWS = 6, ///< Load/save a reference to an engine renewal (autoreplace). + REF_CARGO_PACKET = 7, ///< Load/save a reference to a cargo packet. + REF_ORDERLIST = 8, ///< Load/save a reference to an orderlist. + REF_STORAGE = 9, ///< Load/save a reference to a persistent storage. + REF_LINK_GRAPH = 10, ///< Load/save a reference to a link graph. + REF_LINK_GRAPH_JOB = 11, ///< Load/save a reference to a link graph job. +}; + +/** + * VarTypes is the general bitmasked magic type that tells us + * certain characteristics about the variable it refers to. For example + * SLE_FILE_* gives the size(type) as it would be in the savegame and + * SLE_VAR_* the size(type) as it is in memory during runtime. These are + * the first 8 bits (0-3 SLE_FILE, 4-7 SLE_VAR). + * Bits 8-15 are reserved for various flags as explained below + */ +enum VarTypes { + /* 4 bits allocated a maximum of 16 types for NumberType. + * NOTE: the SLE_FILE_NNN values are stored in the savegame! */ + SLE_FILE_END = 0, ///< Used to mark end-of-header in tables. + SLE_FILE_I8 = 1, + SLE_FILE_U8 = 2, + SLE_FILE_I16 = 3, + SLE_FILE_U16 = 4, + SLE_FILE_I32 = 5, + SLE_FILE_U32 = 6, + SLE_FILE_I64 = 7, + SLE_FILE_U64 = 8, + SLE_FILE_STRINGID = 9, ///< StringID offset into strings-array + SLE_FILE_STRING = 10, + SLE_FILE_STRUCT = 11, + /* 4 more possible file-primitives */ + + SLE_FILE_TYPE_MASK = 0xf, ///< Mask to get the file-type (and not any flags). + SLE_FILE_HAS_LENGTH_FIELD = 1 << 4, ///< Bit stored in savegame to indicate field has a length field for each entry. + + /* 4 bits allocated a maximum of 16 types for NumberType */ + SLE_VAR_BL = 0 << 4, + SLE_VAR_I8 = 1 << 4, + SLE_VAR_U8 = 2 << 4, + SLE_VAR_I16 = 3 << 4, + SLE_VAR_U16 = 4 << 4, + SLE_VAR_I32 = 5 << 4, + SLE_VAR_U32 = 6 << 4, + SLE_VAR_I64 = 7 << 4, + SLE_VAR_U64 = 8 << 4, + SLE_VAR_NULL = 9 << 4, ///< useful to write zeros in savegame. + SLE_VAR_STRB = 10 << 4, ///< string (with pre-allocated buffer) + SLE_VAR_STR = 12 << 4, ///< string pointer + SLE_VAR_STRQ = 13 << 4, ///< string pointer enclosed in quotes + SLE_VAR_NAME = 14 << 4, ///< old custom name to be converted to a char pointer + /* 1 more possible memory-primitives */ + + /* Shortcut values */ + SLE_VAR_CHAR = SLE_VAR_I8, + + /* Default combinations of variables. As savegames change, so can variables + * and thus it is possible that the saved value and internal size do not + * match and you need to specify custom combo. The defaults are listed here */ + SLE_BOOL = SLE_FILE_I8 | SLE_VAR_BL, + SLE_INT8 = SLE_FILE_I8 | SLE_VAR_I8, + SLE_UINT8 = SLE_FILE_U8 | SLE_VAR_U8, + SLE_INT16 = SLE_FILE_I16 | SLE_VAR_I16, + SLE_UINT16 = SLE_FILE_U16 | SLE_VAR_U16, + SLE_INT32 = SLE_FILE_I32 | SLE_VAR_I32, + SLE_UINT32 = SLE_FILE_U32 | SLE_VAR_U32, + SLE_INT64 = SLE_FILE_I64 | SLE_VAR_I64, + SLE_UINT64 = SLE_FILE_U64 | SLE_VAR_U64, + SLE_CHAR = SLE_FILE_I8 | SLE_VAR_CHAR, + SLE_STRINGID = SLE_FILE_STRINGID | SLE_VAR_U32, + SLE_STRINGBUF = SLE_FILE_STRING | SLE_VAR_STRB, + SLE_STRING = SLE_FILE_STRING | SLE_VAR_STR, + SLE_STRINGQUOTE = SLE_FILE_STRING | SLE_VAR_STRQ, + SLE_NAME = SLE_FILE_STRINGID | SLE_VAR_NAME, + + /* Shortcut values */ + SLE_UINT = SLE_UINT32, + SLE_INT = SLE_INT32, + SLE_STRB = SLE_STRINGBUF, + SLE_STR = SLE_STRING, + SLE_STRQ = SLE_STRINGQUOTE, + + /* 8 bits allocated for a maximum of 8 flags + * Flags directing saving/loading of a variable */ + SLF_ALLOW_CONTROL = 1 << 8, ///< Allow control codes in the strings. + SLF_ALLOW_NEWLINE = 1 << 9, ///< Allow new lines in the strings. +}; + +typedef uint32 VarType; + +/** Type of data saved. */ +enum SaveLoadType : byte { + SL_VAR = 0, ///< Save/load a variable. + SL_REF = 1, ///< Save/load a reference. + SL_STRUCT = 2, ///< Save/load a struct. + + SL_STR = 3, ///< Save/load a string. + SL_STDSTR = 4, ///< Save/load a \c std::string. + + SL_ARR = 5, ///< Save/load a fixed-size array of #SL_VAR elements. + SL_DEQUE = 6, ///< Save/load a deque of #SL_VAR elements. + SL_VECTOR = 7, ///< Save/load a vector of #SL_VAR elements. + SL_REFLIST = 8, ///< Save/load a list of #SL_REF elements. + SL_STRUCTLIST = 9, ///< Save/load a list of structs. + + SL_SAVEBYTE = 10, ///< Save (but not load) a byte. + SL_NULL = 11, ///< Save null-bytes and load to nowhere. + + SL_REFDEQUE, ///< Save/load a deque of #SL_REF elements. + SL_REFVEC, ///< Save/load a vector of #SL_REF elements. +}; + +typedef void *SaveLoadAddrProc(void *base, size_t extra); + +/** SaveLoad type struct. Do NOT use this directly but use the SLE_ macros defined just below! */ +struct SaveLoad { + std::string name; ///< Name of this field (optional, used for tables). + SaveLoadType cmd; ///< The action to take with the saved/loaded type, All types need different action. + VarType conv; ///< Type of the variable to be saved; this field combines both FileVarType and MemVarType. + uint16 length; ///< (Conditional) length of the variable (eg. arrays) (max array size is 65536 elements). + SaveLoadVersion version_from; ///< Save/load the variable starting from this savegame version. + SaveLoadVersion version_to; ///< Save/load the variable before this savegame version. + 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. + std::shared_ptr handler; ///< Custom handler for Save/Load procs. +}; + +/** + * SaveLoad information for backwards compatibility. + * + * At SLV_SETTINGS_NAME a new method of keeping track of fields in a savegame + * was added, where the order of fields is no longer important. For older + * savegames we still need to know the correct order. This struct is the glue + * to make that happen. + */ +struct SaveLoadCompat { + std::string name; ///< Name of the field. + uint16 length; ///< Length of the NULL field. + SaveLoadVersion version_from; ///< Save/load the variable starting from this savegame version. + SaveLoadVersion version_to; ///< Save/load the variable before this savegame version. +}; + +/** + * Storage of simple variables, references (pointers), and arrays. + * @param cmd Load/save type. @see SaveLoadType + * @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. + * @param type Storage of the data in memory and in the savegame. + * @param from First savegame version that has the field. + * @param to Last savegame version that has the field. + * @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) SaveLoad {#variable, 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} +#define SLE_GENERAL2(cmd, base, name, variable, type, length, from, to, extra) SaveLoad {name, 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. + * @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. + * @param type Storage of the data in memory and in the savegame. + * @param from First savegame version that has the field. + * @param to Last savegame version that has the field. + */ +#define SLE_CONDVAR(base, variable, type, from, to) SLE_GENERAL(SL_VAR, base, variable, type, 0, from, to, 0) +#define SLE_CONDVAR2(base, name, variable, type, from, to) SLE_GENERAL2(SL_VAR, base, name, variable, type, 0, from, to, 0) + +/** + * Storage of a reference in some savegame versions. + * @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. + * @param type Type of the reference, a value from #SLRefType. + * @param from First savegame version that has the field. + * @param to Last savegame version that has the field. + */ +#define SLE_CONDREF(base, variable, type, from, to) SLE_GENERAL(SL_REF, base, variable, type, 0, from, to, 0) + +/** + * Storage of a fixed-size array of #SL_VAR elements in some savegame versions. + * @param base Name of the class or struct containing the array. + * @param variable Name of the variable in the class or struct referenced by \a base. + * @param type Storage of the data in memory and in the savegame. + * @param length Number of elements in the array. + * @param from First savegame version that has the array. + * @param to Last savegame version that has the array. + */ +#define SLE_CONDARR(base, variable, type, length, from, to) SLE_GENERAL(SL_ARR, base, variable, type, length, from, to, 0) + +/** + * Storage of a string in some savegame versions. + * @param base Name of the class or struct containing the string. + * @param variable Name of the variable in the class or struct referenced by \a base. + * @param type Storage of the data in memory and in the savegame. + * @param length Number of elements in the string (only used for fixed size buffers). + * @param from First savegame version that has the string. + * @param to Last savegame version that has the string. + */ +#define SLE_CONDSTR(base, variable, type, length, from, to) SLE_GENERAL(SL_STR, base, variable, type, length, from, to, 0) + +/** + * Storage of a \c std::string in some savegame versions. + * @param base Name of the class or struct containing the string. + * @param variable Name of the variable in the class or struct referenced by \a base. + * @param type Storage of the data in memory and in the savegame. + * @param from First savegame version that has the string. + * @param to Last savegame version that has the string. + */ +#define SLE_CONDSSTR(base, variable, type, from, to) SLE_GENERAL(SL_STDSTR, base, variable, type, 0, from, to, 0) + +/** + * Storage of a list of #SL_REF elements in some savegame versions. + * @param base Name of the class or struct containing the list. + * @param variable Name of the variable in the class or struct referenced by \a base. + * @param type Storage of the data in memory and in the savegame. + * @param from First savegame version that has the list. + * @param to Last savegame version that has the list. + */ +#define SLE_CONDREFLIST(base, variable, type, from, to) SLE_GENERAL(SL_REFLIST, base, variable, type, 0, from, to, 0) + +/** + * Storage of a deque of #SL_REF elements in some savegame versions. + * @param base Name of the class or struct containing the list. + * @param variable Name of the variable in the class or struct referenced by \a base. + * @param type Storage of the data in memory and in the savegame. + * @param from First savegame version that has the list. + * @param to Last savegame version that has the list. + */ +#define SLE_CONDREFDEQUE(base, variable, type, from, to) SLE_GENERAL(SL_REFDEQUE, base, variable, type, 0, from, to, 0) + +/** + * Storage of a vector of #SL_REF elements in some savegame versions. + * @param base Name of the class or struct containing the list. + * @param variable Name of the variable in the class or struct referenced by \a base. + * @param type Storage of the data in memory and in the savegame. + * @param from First savegame version that has the list. + * @param to Last savegame version that has the list. + */ +#define SLE_CONDREFVEC(base, variable, type, from, to) SLE_GENERAL(SL_REFVEC, base, variable, type, 0, from, to, 0) + +/** + * Storage of a deque of #SL_VAR elements in some savegame versions. + * @param base Name of the class or struct containing the list. + * @param variable Name of the variable in the class or struct referenced by \a base. + * @param type Storage of the data in memory and in the savegame. + * @param from First savegame version that has the list. + * @param to Last savegame version that has the list. + */ +#define SLE_CONDDEQUE(base, variable, type, from, to) SLE_GENERAL(SL_DEQUE, base, variable, type, 0, from, to, 0) + +/** + * Storage of a variable in every version of a savegame. + * @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. + * @param type Storage of the data in memory and in the savegame. + */ +#define SLE_VAR(base, variable, type) SLE_CONDVAR(base, variable, type, SL_MIN_VERSION, SL_MAX_VERSION) +#define SLE_VAR2(base, name, variable, type) SLE_CONDVAR2(base, name, variable, type, SL_MIN_VERSION, SL_MAX_VERSION) + +/** + * Storage of a reference in every version of a savegame. + * @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. + * @param type Type of the reference, a value from #SLRefType. + */ +#define SLE_REF(base, variable, type) SLE_CONDREF(base, variable, type, SL_MIN_VERSION, SL_MAX_VERSION) + +/** + * Storage of fixed-size array of #SL_VAR elements in every version of a savegame. + * @param base Name of the class or struct containing the array. + * @param variable Name of the variable in the class or struct referenced by \a base. + * @param type Storage of the data in memory and in the savegame. + * @param length Number of elements in the array. + */ +#define SLE_ARR(base, variable, type, length) SLE_CONDARR(base, variable, type, length, SL_MIN_VERSION, SL_MAX_VERSION) + +/** + * Storage of a string in every savegame version. + * @param base Name of the class or struct containing the string. + * @param variable Name of the variable in the class or struct referenced by \a base. + * @param type Storage of the data in memory and in the savegame. + * @param length Number of elements in the string (only used for fixed size buffers). + */ +#define SLE_STR(base, variable, type, length) SLE_CONDSTR(base, variable, type, length, SL_MIN_VERSION, SL_MAX_VERSION) + +/** + * Storage of a \c std::string in every savegame version. + * @param base Name of the class or struct containing the string. + * @param variable Name of the variable in the class or struct referenced by \a base. + * @param type Storage of the data in memory and in the savegame. + */ +#define SLE_SSTR(base, variable, type) SLE_CONDSSTR(base, variable, type, SL_MIN_VERSION, SL_MAX_VERSION) + +/** + * Storage of a list of #SL_REF elements in every savegame version. + * @param base Name of the class or struct containing the list. + * @param variable Name of the variable in the class or struct referenced by \a base. + * @param type Storage of the data in memory and in the savegame. + */ +#define SLE_REFLIST(base, variable, type) SLE_CONDREFLIST(base, variable, type, SL_MIN_VERSION, SL_MAX_VERSION) + +/** + * Storage of a deque of #SL_REF elements in every savegame version. + * @param base Name of the class or struct containing the list. + * @param variable Name of the variable in the class or struct referenced by \a base. + * @param type Storage of the data in memory and in the savegame. + */ +#define SLE_REFDEQUE(base, variable, type) SLE_CONDREFDEQUE(base, variable, type, SL_MIN_VERSION, SL_MAX_VERSION) + +/** + * Storage of a vector of #SL_REF elements in every savegame version. + * @param base Name of the class or struct containing the list. + * @param variable Name of the variable in the class or struct referenced by \a base. + * @param type Storage of the data in memory and in the savegame. + */ +#define SLE_REFVEC(base, variable, type) SLE_CONDREFVEC(base, variable, type, SL_MIN_VERSION, SL_MAX_VERSION) + +/** + * 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. + * @param name The name of the field. + * @param cmd Load/save type. @see SaveLoadType + * @param variable Name of the global variable. + * @param type Storage of the data in memory and in the savegame. + * @param from First savegame version that has the field. + * @param to Last savegame version that has the field. + * @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(name, cmd, variable, type, length, from, to, extra) SaveLoad {name, 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. + * @param name The name of the field. + * @param variable Name of the global variable. + * @param type Storage of the data in memory and in the savegame. + * @param from First savegame version that has the field. + * @param to Last savegame version that has the field. + */ +#define SLEG_CONDVAR(name, variable, type, from, to) SLEG_GENERAL(name, SL_VAR, variable, type, 0, from, to, 0) + +/** + * Storage of a global reference in some savegame versions. + * @param name The name of the field. + * @param variable Name of the global variable. + * @param type Storage of the data in memory and in the savegame. + * @param from First savegame version that has the field. + * @param to Last savegame version that has the field. + */ +#define SLEG_CONDREF(name, variable, type, from, to) SLEG_GENERAL(name, SL_REF, variable, type, 0, from, to, 0) + +/** + * Storage of a global fixed-size array of #SL_VAR elements in some savegame versions. + * @param name The name of the field. + * @param variable Name of the global variable. + * @param type Storage of the data in memory and in the savegame. + * @param length Number of elements in the array. + * @param from First savegame version that has the array. + * @param to Last savegame version that has the array. + */ +#define SLEG_CONDARR(name, variable, type, length, from, to) SLEG_GENERAL(name, SL_ARR, variable, type, length, from, to, 0) + +/** + * Storage of a global string in some savegame versions. + * @param name The name of the field. + * @param variable Name of the global variable. + * @param type Storage of the data in memory and in the savegame. + * @param length Number of elements in the string (only used for fixed size buffers). + * @param from First savegame version that has the string. + * @param to Last savegame version that has the string. + */ +#define SLEG_CONDSTR(name, variable, type, length, from, to) SLEG_GENERAL(name, SL_STR, variable, type, length, from, to, 0) + +/** + * Storage of a global \c std::string in some savegame versions. + * @param name The name of the field. + * @param variable Name of the global variable. + * @param type Storage of the data in memory and in the savegame. + * @param from First savegame version that has the string. + * @param to Last savegame version that has the string. + */ +#define SLEG_CONDSSTR(name, variable, type, from, to) SLEG_GENERAL(name, SL_STDSTR, variable, type, 0, from, to, 0) + +/** + * Storage of a structs in some savegame versions. + * @param name The name of the field. + * @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(name, handler, from, to) SaveLoad {name, SL_STRUCT, 0, 0, from, to, 0, nullptr, 0, std::make_shared()} + +/** + * Storage of a global reference list in some savegame versions. + * @param name The name of the field. + * @param variable Name of the global variable. + * @param type Storage of the data in memory and in the savegame. + * @param from First savegame version that has the list. + * @param to Last savegame version that has the list. + */ +#define SLEG_CONDREFLIST(name, variable, type, from, to) SLEG_GENERAL(name, SL_REFLIST, variable, type, 0, from, to, 0) + +/** + * Storage of a global reference deque in some savegame versions. + * @param name The name of the field. + * @param variable Name of the global variable. + * @param type Storage of the data in memory and in the savegame. + * @param from First savegame version that has the list. + * @param to Last savegame version that has the list. + */ +#define SLEG_CONDREFDEQUE(name, variable, type, from, to) SLEG_GENERAL(name, SL_REFDEQUE, variable, type, 0, from, to, 0) + +/** + * Storage of a global reference vector in some savegame versions. + * @param name The name of the field. + * @param variable Name of the global variable. + * @param type Storage of the data in memory and in the savegame. + * @param from First savegame version that has the list. + * @param to Last savegame version that has the list. + */ +#define SLEG_CONDREFVEC(name, variable, type, from, to) SLEG_GENERAL(name, SL_REFVEC, variable, type, 0, from, to, 0) + +/** + * Storage of a global vector of #SL_VAR elements in some savegame versions. + * @param name The name of the field. + * @param variable Name of the global variable. + * @param type Storage of the data in memory and in the savegame. + * @param from First savegame version that has the list. + * @param to Last savegame version that has the list. + */ +#define SLEG_CONDVECTOR(name, variable, type, from, to) SLEG_GENERAL(name, SL_VECTOR, variable, type, 0, from, to, 0) + +/** + * Storage of a list of structs in some savegame versions. + * @param name The name of the field. + * @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(name, handler, from, to) SaveLoad {name, SL_STRUCTLIST, 0, 0, from, to, 0, nullptr, 0, std::make_shared()} + +/** + * Storage of a global variable in every savegame version. + * @param name The name of the field. + * @param variable Name of the global variable. + * @param type Storage of the data in memory and in the savegame. + */ +#define SLEG_VAR(name, variable, type) SLEG_CONDVAR(name, variable, type, SL_MIN_VERSION, SL_MAX_VERSION) + +/** + * Storage of a global reference in every savegame version. + * @param name The name of the field. + * @param variable Name of the global variable. + * @param type Storage of the data in memory and in the savegame. + */ +#define SLEG_REF(name, variable, type) SLEG_CONDREF(name, variable, type, SL_MIN_VERSION, SL_MAX_VERSION) + +/** + * Storage of a global fixed-size array of #SL_VAR elements in every savegame version. + * @param name The name of the field. + * @param variable Name of the global variable. + * @param type Storage of the data in memory and in the savegame. + */ +#define SLEG_ARR(name, variable, type) SLEG_CONDARR(name, variable, type, lengthof(variable), SL_MIN_VERSION, SL_MAX_VERSION) + +/** + * Storage of a global string in every savegame version. + * @param name The name of the field. + * @param variable Name of the global variable. + * @param type Storage of the data in memory and in the savegame. + */ +#define SLEG_STR(name, variable, type) SLEG_CONDSTR(name, variable, type, sizeof(variable), SL_MIN_VERSION, SL_MAX_VERSION) + +/** + * Storage of a global \c std::string in every savegame version. + * @param name The name of the field. + * @param variable Name of the global variable. + * @param type Storage of the data in memory and in the savegame. + */ +#define SLEG_SSTR(name, variable, type) SLEG_CONDSSTR(name, variable, type, SL_MIN_VERSION, SL_MAX_VERSION) + +/** + * Storage of a structs in every savegame version. + * @param name The name of the field. + * @param handler SaveLoadHandler for the structs. + */ +#define SLEG_STRUCT(name, handler) SLEG_CONDSTRUCT(name, handler, SL_MIN_VERSION, SL_MAX_VERSION) + +/** + * Storage of a global reference list in every savegame version. + * @param name The name of the field. + * @param variable Name of the global variable. + * @param type Storage of the data in memory and in the savegame. + */ +#define SLEG_REFLIST(name, variable, type) SLEG_CONDREFLIST(name, variable, type, SL_MIN_VERSION, SL_MAX_VERSION) + +/** + * Storage of a global reference deque in every savegame version. + * @param name The name of the field. + * @param variable Name of the global variable. + * @param type Storage of the data in memory and in the savegame. + */ +#define SLEG_REFDEQUE(name, variable, type) SLEG_CONDREFDEQUE(name, variable, type, SL_MIN_VERSION, SL_MAX_VERSION) + +/** + * Storage of a global vector of #SL_VAR elements in every savegame version. + * @param name The name of the field. + * @param variable Name of the global variable. + * @param type Storage of the data in memory and in the savegame. + */ +#define SLEG_VECTOR(name, variable, type) SLEG_CONDVECTOR(name, variable, type, SL_MIN_VERSION, SL_MAX_VERSION) + +/** + * Storage of a list of structs in every savegame version. + * @param name The name of the field. + * @param handler SaveLoadHandler for the list of structs. + */ +#define SLEG_STRUCTLIST(name, handler) SLEG_CONDSTRUCTLIST(name, handler, SL_MIN_VERSION, SL_MAX_VERSION) + +/** + * Field name where the real SaveLoad can be located. + * @param name The name of the field. + */ +#define SLC_VAR(name) {name, 0, SL_MIN_VERSION, SL_MAX_VERSION} + +/** + * Empty space in every savegame version. + * @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 SLC_NULL(length, from, to) {{}, length, from, to} + +/** End marker of compat variables save or load. */ +#define SLC_END() {{}, 0, SL_MIN_VERSION, SL_MIN_VERSION} + +/** + * Checks whether the savegame is below \a major.\a minor. + * @param major Major number of the version to check against. + * @param minor Minor number of the version to check against. If \a minor is 0 or not specified, only the major number is checked. + * @return Savegame version is earlier than the specified version. + */ +static inline bool IsSavegameVersionBefore(SaveLoadVersion major, byte minor = 0) +{ + return _sl_version < major || (minor > 0 && _sl_version == major && _sl_minor_version < minor); +} + +/** + * Checks whether the savegame is below or at \a major. This should be used to repair data from existing + * savegames which is no longer corrupted in new savegames, but for which otherwise no savegame + * bump is required. + * @param major Major number of the version to check against. + * @return Savegame version is at most the specified version. + */ +static inline bool IsSavegameVersionBeforeOrAt(SaveLoadVersion major) +{ + return _sl_version <= major; +} + +/** + * Checks if some version from/to combination falls within the range of the + * active savegame version. + * @param version_from Inclusive savegame version lower bound. + * @param version_to Exclusive savegame version upper bound. SL_MAX_VERSION if no upper bound. + * @return Active savegame version falls within the given range. + */ +static inline bool SlIsObjectCurrentlyValid(SaveLoadVersion version_from, SaveLoadVersion version_to) +{ + return version_from <= SAVEGAME_VERSION && SAVEGAME_VERSION < version_to; +} + +/** + * Get the NumberType of a setting. This describes the integer type + * as it is represented in memory + * @param type VarType holding information about the variable-type + * @return the SLE_VAR_* part of a variable-type description + */ +static inline VarType GetVarMemType(VarType type) +{ + return type & 0xF0; // GB(type, 4, 4) << 4; +} + +/** + * Get the FileType of a setting. This describes the integer type + * as it is represented in a savegame/file + * @param type VarType holding information about the file-type + * @return the SLE_FILE_* part of a variable-type description + */ +static inline VarType GetVarFileType(VarType type) +{ + return type & 0xF; // GB(type, 0, 4); +} + +/** + * Check if the given saveload type is a numeric type. + * @param conv the type to check + * @return True if it's a numeric type. + */ +static inline bool IsNumericType(VarType conv) +{ + return GetVarMemType(conv) <= SLE_VAR_U64; +} + +/** + * Get the address of the variable. Null-variables don't have an address, + * everything else has a callback function that returns the address based + * on the saveload data and the current object for non-globals. + */ +static inline void *GetVariableAddress(const void *object, const SaveLoad &sld) +{ + /* Entry is a null-variable, mostly used to read old savegames etc. */ + if (GetVarMemType(sld.conv) == SLE_VAR_NULL) { + assert(sld.address_proc == nullptr); + return nullptr; + } + + /* Everything else should be a non-null pointer. */ + assert(sld.address_proc != nullptr); + return sld.address_proc(const_cast(object), sld.extra_data); +} + +int64 ReadValue(const void *ptr, VarType conv); +void WriteValue(void *ptr, VarType conv, int64 val); + +void SlSetArrayIndex(uint index); +int SlIterateArray(); + +void SlSetStructListLength(size_t length); +size_t SlGetStructListLength(size_t limit); + +void SlAutolength(AutolengthProc *proc, void *arg); +size_t SlGetFieldLength(); +void SlSetLength(size_t length); +size_t SlCalcObjMemberLength(const void *object, const SaveLoad &sld); +size_t SlCalcObjLength(const void *object, const SaveLoadTable &slt); + +void SlGlobList(const SaveLoadTable &slt); +void SlCopy(void *object, size_t length, VarType conv); +std::vector SlTableHeader(const SaveLoadTable &slt); +std::vector SlCompatTableHeader(const SaveLoadTable &slt, const SaveLoadCompatTable &slct); +void SlObject(void *object, const SaveLoadTable &slt); + +} + +#endif /* UPSTREAM_SAVELOAD_H */ diff --git a/src/saveload/upstream/settings_sl.cpp b/src/saveload/upstream/settings_sl.cpp new file mode 100644 index 0000000000..fca6bc846d --- /dev/null +++ b/src/saveload/upstream/settings_sl.cpp @@ -0,0 +1,228 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file settings_sl.cpp Handles the saveload part of the settings. */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "debug.h" +#include "compat/settings_sl_compat.h" + +#include "../../settings_type.h" +#include "../../settings_internal.h" +#include "../../network/network.h" +#include "../../fios.h" + +#include "../../safeguards.h" + +const SettingTable &GetSettingsTableInternal(); + +namespace upstream_sl { + +/** + * Get the SaveLoad description for the SettingTable. + * @param settings SettingDesc struct containing all information. + * @param is_loading True iff the SaveLoad table is for loading. + * @return Vector with SaveLoad entries for the SettingTable. + */ +static std::vector GetSettingsDesc(bool is_loading) +{ + std::vector saveloads; + for (auto &sd : GetSettingsTableInternal()) { + if (sd->flags & SF_NOT_IN_SAVE) continue; + if (sd->patx_name != nullptr) continue; + if (!sd->save.ext_feature_test.IsFeaturePresent(_sl_version, sd->save.version_from, sd->save.version_to)) continue; + + VarType new_type = 0; + switch (sd->save.conv & 0x0F) { + case ::SLE_FILE_I8: + new_type |= SLE_FILE_I8; + break; + case ::SLE_FILE_U8: + new_type |= SLE_FILE_U8; + break; + case ::SLE_FILE_I16: + new_type |= SLE_FILE_I16; + break; + case ::SLE_FILE_U16: + new_type |= SLE_FILE_U16; + break; + case ::SLE_FILE_I32: + new_type |= SLE_FILE_I32; + break; + case ::SLE_FILE_U32: + new_type |= SLE_FILE_U32; + break; + case ::SLE_FILE_I64: + new_type |= SLE_FILE_I64; + break; + case ::SLE_FILE_U64: + new_type |= SLE_FILE_U64; + break; + case ::SLE_FILE_STRINGID: + new_type |= SLE_FILE_STRINGID; + break; + case ::SLE_FILE_STRING: + new_type |= SLE_FILE_STRING; + break; + default: + error("Unexpected save conv for %s: 0x%02X", sd->name, sd->save.conv); + } + switch (sd->save.conv & 0xF0) { + case ::SLE_VAR_BL: + new_type |= SLE_VAR_BL; + break; + case ::SLE_VAR_I8: + new_type |= SLE_VAR_I8; + break; + case ::SLE_VAR_U8: + new_type |= SLE_VAR_U8; + break; + case ::SLE_VAR_I16: + new_type |= SLE_VAR_I16; + break; + case ::SLE_VAR_U16: + new_type |= SLE_VAR_U16; + break; + case ::SLE_VAR_I32: + new_type |= SLE_VAR_I32; + break; + case ::SLE_VAR_U32: + new_type |= SLE_VAR_U32; + break; + case ::SLE_VAR_I64: + new_type |= SLE_VAR_I64; + break; + case ::SLE_VAR_U64: + new_type |= SLE_VAR_U64; + break; + case ::SLE_VAR_NULL: + new_type |= SLE_VAR_NULL; + break; + case ::SLE_VAR_STRB: + new_type |= SLE_VAR_STRB; + break; + case ::SLE_VAR_STR: + new_type |= SLE_VAR_STR; + break; + case ::SLE_VAR_STRQ: + new_type |= SLE_VAR_STRQ; + break; + default: + error("Unexpected save conv for %s: 0x%02X", sd->name, sd->save.conv); + } + + if (strcmp(sd->name, "economy.town_growth_rate") == 0) { + SB(new_type, 0, 4, SLE_FILE_U8); + } + + SaveLoadType new_cmd; + switch (sd->save.cmd) { + case ::SL_VAR: + new_cmd = SL_VAR; + break; + case ::SL_STR: + new_cmd = SL_STR; + break; + case ::SL_STDSTR: + new_cmd = SL_STDSTR; + break; + default: + error("Unexpected save cmd for %s: %u", sd->name, sd->save.cmd); + } + + if (is_loading && (sd->flags & SF_NO_NETWORK_SYNC) && _networking && !_network_server) { + if (IsSavegameVersionBefore(SLV_TABLE_CHUNKS)) { + /* We don't want to read this setting, so we do need to skip over it. */ + saveloads.push_back({sd->name, new_cmd, GetVarFileType(new_type) | SLE_VAR_NULL, sd->save.length, SL_MIN_VERSION, SL_MAX_VERSION, 0, nullptr, 0, nullptr}); + } + continue; + } + + SaveLoadAddrProc *address_proc = [](void *base, size_t extra) -> void* { + return const_cast((const byte *)base + (ptrdiff_t)extra); + }; + saveloads.push_back({sd->name, new_cmd, new_type, sd->save.length, SL_MIN_VERSION, SL_MAX_VERSION, sd->save.size, address_proc, reinterpret_cast(sd->save.address), nullptr}); + } + + return saveloads; +} + +/** + * Save and load handler for settings + * @param settings SettingDesc struct containing all information + * @param object can be either nullptr in which case we load global variables or + * a pointer to a struct which is getting saved + */ +static void LoadSettings(void *object, const SaveLoadCompatTable &slct) +{ + const std::vector slt = SlCompatTableHeader(GetSettingsDesc(true), slct); + + if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() == -1) return; + SlObject(object, slt); + if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many settings entries"); + + /* Ensure all IntSettings are valid (min/max could have changed between versions etc). */ + for (auto &sd : GetSettingsTableInternal()) { + if (sd->flags & SF_NOT_IN_SAVE) continue; + if ((sd->flags & SF_NO_NETWORK_SYNC) && _networking && !_network_server) continue; + if (!sd->save.ext_feature_test.IsFeaturePresent(SAVEGAME_VERSION, sd->save.version_from, sd->save.version_to)) continue; + + if (sd->IsIntSetting()) { + const IntSettingDesc *int_setting = sd->AsIntSetting(); + int_setting->MakeValueValidAndWrite(object, int_setting->Read(object)); + } + } +} + +/** + * Save and load handler for settings + * @param settings SettingDesc struct containing all information + * @param object can be either nullptr in which case we load global variables or + * a pointer to a struct which is getting saved + */ +static void SaveSettings(void *object) +{ + const std::vector slt = GetSettingsDesc(false); + + SlTableHeader(slt); + + SlSetArrayIndex(0); + SlObject(object, slt); +} + +struct PATSChunkHandler : ChunkHandler { + PATSChunkHandler() : ChunkHandler('PATS', CH_TABLE) {} + + void Load() const override + { + /* Copy over default setting since some might not get loaded in + * a networking environment. This ensures for example that the local + * currency setting stays when joining a network-server */ + LoadSettings(&_settings_game, _settings_sl_compat); + } + + void LoadCheck(size_t) const override + { + LoadSettings(&_load_check_data.settings, _settings_sl_compat); + } + + void Save() const override + { + SaveSettings(&_settings_game); + } +}; + +static const PATSChunkHandler PATS; +static const ChunkHandlerRef setting_chunk_handlers[] = { + PATS, +}; + +extern const ChunkHandlerTable _setting_chunk_handlers(setting_chunk_handlers); + +} diff --git a/src/saveload/upstream/signs_sl.cpp b/src/saveload/upstream/signs_sl.cpp new file mode 100644 index 0000000000..10b458d2f2 --- /dev/null +++ b/src/saveload/upstream/signs_sl.cpp @@ -0,0 +1,81 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file signs_sl.cpp Code handling saving and loading of economy data */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "compat/signs_sl_compat.h" + +#include "../../signs_base.h" +#include "../../fios.h" + +#include "../../safeguards.h" + +namespace upstream_sl { + +/** Description of a sign within the savegame. */ +static const SaveLoad _sign_desc[] = { + SLE_CONDVAR(Sign, name, SLE_NAME, SL_MIN_VERSION, SLV_84), + SLE_CONDSSTR(Sign, name, SLE_STR | SLF_ALLOW_CONTROL, SLV_84, SL_MAX_VERSION), + SLE_CONDVAR(Sign, x, SLE_FILE_I16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_5), + SLE_CONDVAR(Sign, y, SLE_FILE_I16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_5), + SLE_CONDVAR(Sign, x, SLE_INT32, SLV_5, SL_MAX_VERSION), + SLE_CONDVAR(Sign, y, SLE_INT32, SLV_5, SL_MAX_VERSION), + SLE_CONDVAR(Sign, owner, SLE_UINT8, SLV_6, SL_MAX_VERSION), + SLE_CONDVAR(Sign, z, SLE_FILE_U8 | SLE_VAR_I32, SL_MIN_VERSION, SLV_164), + SLE_CONDVAR(Sign, z, SLE_INT32, SLV_164, SL_MAX_VERSION), +}; + +struct SIGNChunkHandler : ChunkHandler { + SIGNChunkHandler() : ChunkHandler('SIGN', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_sign_desc); + + for (Sign *si : Sign::Iterate()) { + SlSetArrayIndex(si->index); + SlObject(si, _sign_desc); + } + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_sign_desc, _sign_sl_compat); + + int index; + while ((index = SlIterateArray()) != -1) { + Sign *si = new (index) Sign(); + SlObject(si, slt); + /* Before version 6.1, signs didn't have owner. + * Before version 83, invalid signs were determined by si->str == 0. + * Before version 103, owner could be a bankrupted company. + * - we can't use IsValidCompany() now, so this is fixed in AfterLoadGame() + * All signs that were saved are valid (including those with just 'Sign' and INVALID_OWNER). + * - so set owner to OWNER_NONE if needed (signs from pre-version 6.1 would be lost) */ + if (IsSavegameVersionBefore(SLV_6, 1) || (IsSavegameVersionBefore(SLV_83) && si->owner == INVALID_OWNER)) { + si->owner = OWNER_NONE; + } + + /* Signs placed in scenario editor shall now be OWNER_DEITY */ + if (IsSavegameVersionBefore(SLV_171) && si->owner == OWNER_NONE && SaveLoadFileTypeIsScenario()) { + si->owner = OWNER_DEITY; + } + } + } +}; + +static const SIGNChunkHandler SIGN; +static const ChunkHandlerRef sign_chunk_handlers[] = { + SIGN, +}; + +extern const ChunkHandlerTable _sign_chunk_handlers(sign_chunk_handlers); + +} diff --git a/src/saveload/upstream/station_sl.cpp b/src/saveload/upstream/station_sl.cpp new file mode 100644 index 0000000000..e8154ed9cf --- /dev/null +++ b/src/saveload/upstream/station_sl.cpp @@ -0,0 +1,531 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file station_sl.cpp Code handling saving and loading of stations. */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "compat/station_sl_compat.h" + +#include "../../station_base.h" +#include "../../waypoint_base.h" +#include "../../roadstop_base.h" +#include "../../vehicle_base.h" +#include "../../newgrf_station.h" + +#include "table/strings.h" + +#include "../../safeguards.h" + +namespace upstream_sl { + +static const SaveLoad _roadstop_desc[] = { + SLE_VAR(RoadStop, xy, SLE_UINT32), + SLE_VAR(RoadStop, status, SLE_UINT8), + SLE_REF(RoadStop, next, REF_ROADSTOPS), +}; + +static uint16 _waiting_acceptance; +static uint32 _old_num_flows; +static uint16 _cargo_source; +static uint32 _cargo_source_xy; +static uint8 _cargo_days; +static Money _cargo_feeder_share; + +CargoPacketList _packets; +uint32 _old_num_dests; + +struct FlowSaveLoad { + FlowSaveLoad() : source(0), via(0), share(0), restricted(false) {} + StationID source; + StationID via; + uint32 share; + bool restricted; +}; + +typedef std::pair StationCargoPair; + +static OldPersistentStorage _old_st_persistent_storage; +static byte _old_last_vehicle_type; + +/** + * Swap the temporary packets with the packets without specific destination in + * the given goods entry. Assert that at least one of those is empty. + * @param ge Goods entry to swap with. + */ +static void SwapPackets(GoodsEntry *ge) +{ + StationCargoPacketMap &ge_packets = const_cast(*ge->cargo.Packets()); + + if (_packets.empty()) { + std::map::iterator it(ge_packets.find(INVALID_STATION)); + if (it == ge_packets.end()) { + return; + } else { + it->second.swap(_packets); + } + } else { + assert(ge_packets[INVALID_STATION].empty()); + ge_packets[INVALID_STATION].swap(_packets); + } +} + +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), + }; + inline const static SaveLoadCompatTable compat_description = _station_spec_list_sl_compat; + + void Save(BaseStation *bst) const override + { + SlSetStructListLength(bst->num_specs); + for (uint i = 0; i < bst->num_specs; i++) { + SlObject(&bst->speclist[i], this->GetDescription()); + } + } + + void Load(BaseStation *bst) const override + { + if (!IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) { + bst->num_specs = (uint8)SlGetStructListLength(UINT8_MAX); + } + + if (bst->num_specs != 0) { + /* Allocate speclist memory when loading a game */ + bst->speclist = CallocT(bst->num_specs); + for (uint i = 0; i < bst->num_specs; i++) { + SlObject(&bst->speclist[i], this->GetLoadDescription()); + } + } + } +}; + +class SlStationCargo : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_VAR(StationCargoPair, first, SLE_UINT16), + SLE_REFDEQUE(StationCargoPair, second, REF_CARGO_PACKET), + }; + inline const static SaveLoadCompatTable compat_description = _station_cargo_sl_compat; + + void Save(GoodsEntry *ge) const override + { + // removed + NOT_REACHED(); + } + + void Load(GoodsEntry *ge) const override + { + size_t num_dests = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? _old_num_dests : SlGetStructListLength(UINT32_MAX); + + StationCargoPair pair; + for (uint j = 0; j < num_dests; ++j) { + SlObject(&pair, this->GetLoadDescription()); + 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), + }; + inline const static SaveLoadCompatTable compat_description = _station_flow_sl_compat; + + void Save(GoodsEntry *ge) const override + { + // removed + NOT_REACHED(); + } + + void Load(GoodsEntry *ge) const override + { + size_t num_flows = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? _old_num_flows : SlGetStructListLength(UINT32_MAX); + + FlowSaveLoad flow; + FlowStat *fs = nullptr; + StationID prev_source = INVALID_STATION; + for (uint32 j = 0; j < num_flows; ++j) { + SlObject(&flow, this->GetLoadDescription()); + if (fs == nullptr || prev_source != flow.source) { + fs = &(*(ge->flows.insert(ge->flows.end(), FlowStat(flow.source, flow.via, flow.share, flow.restricted)))); + } 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", _waiting_acceptance, SLE_UINT16, SL_MIN_VERSION, SLV_68), + SLE_CONDVAR(GoodsEntry, status, SLE_UINT8, SLV_68, SL_MAX_VERSION), + SLE_VAR(GoodsEntry, time_since_pickup, SLE_UINT8), + SLE_VAR(GoodsEntry, rating, SLE_UINT8), + SLEG_CONDVAR("cargo_source", _cargo_source, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_7), + SLEG_CONDVAR("cargo_source", _cargo_source, SLE_UINT16, SLV_7, SLV_68), + SLEG_CONDVAR("cargo_source_xy", _cargo_source_xy, SLE_UINT32, SLV_44, SLV_68), + SLEG_CONDVAR("cargo_days", _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", _cargo_feeder_share, SLE_FILE_U32 | SLE_VAR_I64, SLV_14, SLV_65), + SLEG_CONDVAR("cargo_feeder_share", _cargo_feeder_share, SLE_INT64, SLV_65, SLV_68), + SLE_CONDVAR(GoodsEntry, amount_fract, SLE_UINT8, SLV_150, SL_MAX_VERSION), + SLEG_CONDREFDEQUE("packets", _packets, REF_CARGO_PACKET, SLV_68, SLV_183), + SLEG_CONDVAR("old_num_dests", _old_num_dests, SLE_UINT32, SLV_183, SLV_SAVELOAD_LIST_LENGTH), + SLE_CONDVAR(GoodsEntry, cargo.reserved_count, SLE_UINT, SLV_181, SL_MAX_VERSION), + SLE_CONDVAR(GoodsEntry, link_graph, SLE_UINT16, SLV_183, SL_MAX_VERSION), + SLE_CONDVAR(GoodsEntry, node, SLE_UINT16, SLV_183, SL_MAX_VERSION), + SLEG_CONDVAR("old_num_flows", _old_num_flows, SLE_UINT32, SLV_183, SLV_SAVELOAD_LIST_LENGTH), + SLE_CONDVAR(GoodsEntry, max_waiting_cargo, SLE_UINT32, SLV_183, SL_MAX_VERSION), + SLEG_CONDSTRUCTLIST("flow", SlStationFlow, SLV_183, SL_MAX_VERSION), + SLEG_CONDSTRUCTLIST("cargo", SlStationCargo, SLV_183, SL_MAX_VERSION), + }; +#if defined(_MSC_VER) && (_MSC_VER == 1915 || _MSC_VER == 1916) + return description; + } +#endif + inline const static SaveLoadCompatTable compat_description = _station_goods_sl_compat; + + /** + * Get the number of cargoes used by this savegame version. + * @return The number of cargoes used by this savegame version. + */ + size_t GetNumCargo() const + { + if (IsSavegameVersionBefore(SLV_55)) return 12; + if (IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES)) return 32; + if (IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) return NUM_CARGO; + /* Read from the savegame how long the list is. */ + return SlGetStructListLength(NUM_CARGO); + } + + void Save(BaseStation *bst) const override + { + Station *st = Station::From(bst); + + SlSetStructListLength(NUM_CARGO); + + for (CargoID i = 0; i < NUM_CARGO; i++) { + 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)); + } + + size_t num_cargo = this->GetNumCargo(); + for (CargoID i = 0; i < num_cargo; i++) { + GoodsEntry *ge = &st->goods[i]; + SlObject(ge, this->GetLoadDescription()); + if (IsSavegameVersionBefore(SLV_183)) { + SwapPackets(ge); + } + if (IsSavegameVersionBefore(SLV_68)) { + SB(ge->status, GoodsEntry::GES_ACCEPTANCE, 1, HasBit(_waiting_acceptance, 15)); + if (GB(_waiting_acceptance, 0, 12) != 0) { + /* In old versions, enroute_from used 0xFF as INVALID_STATION */ + StationID source = (IsSavegameVersionBefore(SLV_7) && _cargo_source == 0xFF) ? INVALID_STATION : _cargo_source; + + /* Make sure we can allocate the CargoPacket. This is safe + * as there can only be ~64k stations and 32 cargoes in these + * savegame versions. As the CargoPacketPool has more than + * 16 million entries; it fits by an order of magnitude. */ + assert(CargoPacket::CanAllocateItem()); + + /* Don't construct the packet with station here, because that'll fail with old savegames */ + CargoPacket *cp = new CargoPacket(GB(_waiting_acceptance, 0, 12), _cargo_days, source, _cargo_source_xy, _cargo_source_xy, _cargo_feeder_share); + ge->cargo.Append(cp, INVALID_STATION); + SB(ge->status, GoodsEntry::GES_RATING, 1, 1); + } + } + } + } + + 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()); + } + } + } +}; + +/** + * 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_STR(BaseStation, name, SLE_STR | SLF_ALLOW_CONTROL, 0), + 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_CONDVAR(BaseStation, num_specs, SLE_UINT8, SL_MIN_VERSION, SLV_SAVELOAD_LIST_LENGTH), + }; + inline const static SaveLoadCompatTable compat_description = _station_base_sl_compat; + + void Save(BaseStation *bst) const override + { + SlObject(bst, this->GetDescription()); + } + + void Load(BaseStation *bst) const override + { + SlObject(bst, this->GetLoadDescription()); + } + + void FixPointers(BaseStation *bst) const override + { + SlObject(bst, this->GetDescription()); + } +}; + +/** + * SaveLoad handler for a normal station (read: not a waypoint). + */ +class SlStationNormal : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLEG_STRUCT("base", 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_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("storage", _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), + SLEG_VAR("last_vehicle_type", _old_last_vehicle_type, SLE_UINT8), + SLE_VAR(Station, had_vehicle_of_type, SLE_UINT8), + SLE_REFVEC(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("goods", SlStationGoods), + }; + inline const static SaveLoadCompatTable compat_description = _station_normal_sl_compat; + + void Save(BaseStation *bst) const + { + if ((bst->facilities & FACIL_WAYPOINT) != 0) return; + SlObject(bst, this->GetDescription()); + } + + void Load(BaseStation *bst) const + { + if ((bst->facilities & FACIL_WAYPOINT) != 0) return; + SlObject(bst, this->GetLoadDescription()); + + for (CargoID i = 0; i < NUM_CARGO; i++) { + Station::From(bst)->goods[i].last_vehicle_type = _old_last_vehicle_type; + } + } + + void FixPointers(BaseStation *bst) const + { + if ((bst->facilities & FACIL_WAYPOINT) != 0) return; + SlObject(bst, this->GetDescription()); + } +}; + +class SlStationWaypoint : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLEG_STRUCT("base", 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), + }; + inline const static SaveLoadCompatTable compat_description = _station_waypoint_sl_compat; + + void Save(BaseStation *bst) const + { + if ((bst->facilities & FACIL_WAYPOINT) == 0) return; + SlObject(bst, this->GetDescription()); + } + + void Load(BaseStation *bst) const + { + if ((bst->facilities & FACIL_WAYPOINT) == 0) return; + SlObject(bst, this->GetLoadDescription()); + } + + void FixPointers(BaseStation *bst) const + { + if ((bst->facilities & FACIL_WAYPOINT) == 0) return; + SlObject(bst, this->GetDescription()); + } +}; + +static const SaveLoad _station_desc[] = { + SLE_SAVEBYTE(BaseStation, facilities), + SLEG_STRUCT("normal", SlStationNormal), + SLEG_STRUCT("waypoint", SlStationWaypoint), + SLEG_CONDSTRUCTLIST("speclist", SlStationSpecList, SLV_27, SL_MAX_VERSION), +}; + +struct STNNChunkHandler : ChunkHandler { + STNNChunkHandler() : ChunkHandler('STNN', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_station_desc); + + /* Write the stations */ + for (BaseStation *st : BaseStation::Iterate()) { + SlSetArrayIndex(st->index); + SlObject(st, _station_desc); + } + } + + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_station_desc, _station_sl_compat); + + _old_num_flows = 0; + + int index; + while ((index = SlIterateArray()) != -1) { + bool waypoint = (SlReadByte() & FACIL_WAYPOINT) != 0; + + BaseStation *bst = waypoint ? (BaseStation *)new (index) Waypoint() : new (index) Station(); + SlObject(bst, slt); + } + } + + void FixPointers() const override + { + /* 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()) { + SlObject(bst, _station_desc); + } + } +}; + +struct ROADChunkHandler : ChunkHandler { + ROADChunkHandler() : ChunkHandler('ROAD', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_roadstop_desc); + + for (RoadStop *rs : RoadStop::Iterate()) { + SlSetArrayIndex(rs->index); + SlObject(rs, _roadstop_desc); + } + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_roadstop_desc, _roadstop_sl_compat); + + int index; + + while ((index = SlIterateArray()) != -1) { + RoadStop *rs = new (index) RoadStop(INVALID_TILE); + + SlObject(rs, slt); + } + } + + void FixPointers() const override + { + for (RoadStop *rs : RoadStop::Iterate()) { + SlObject(rs, _roadstop_desc); + } + } +}; + +static const STNNChunkHandler STNN; +static const ROADChunkHandler ROAD; +static const ChunkHandlerRef station_chunk_handlers[] = { + STNN, + ROAD, +}; + +extern const ChunkHandlerTable _station_chunk_handlers(station_chunk_handlers); + +} diff --git a/src/saveload/upstream/storage_sl.cpp b/src/saveload/upstream/storage_sl.cpp new file mode 100644 index 0000000000..ac817a9454 --- /dev/null +++ b/src/saveload/upstream/storage_sl.cpp @@ -0,0 +1,65 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file storage_sl.cpp Code handling saving and loading of persistent storages. */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "compat/storage_sl_compat.h" + +#include "../../newgrf_storage.h" + +#include "../../safeguards.h" + +namespace upstream_sl { + +/** Description of the data to save and load in #PersistentStorage. */ +static const SaveLoad _storage_desc[] = { + SLE_CONDVAR(PersistentStorage, grfid, SLE_UINT32, SLV_6, SL_MAX_VERSION), + SLE_CONDARR(PersistentStorage, storage, SLE_UINT32, 16, SLV_161, SLV_EXTEND_PERSISTENT_STORAGE), + SLE_CONDARR(PersistentStorage, storage, SLE_UINT32, 256, SLV_EXTEND_PERSISTENT_STORAGE, SL_MAX_VERSION), +}; + +/** Persistent storage data. */ +struct PSACChunkHandler : ChunkHandler { + PSACChunkHandler() : ChunkHandler('PSAC', CH_TABLE) {} + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_storage_desc, _storage_sl_compat); + + int index; + + while ((index = SlIterateArray()) != -1) { + assert(PersistentStorage::CanAllocateItem()); + PersistentStorage *ps = new (index) PersistentStorage(0, 0, 0); + SlObject(ps, slt); + } + } + + void Save() const override + { + SlTableHeader(_storage_desc); + + /* Write the industries */ + for (PersistentStorage *ps : PersistentStorage::Iterate()) { + ps->ClearChanges(); + SlSetArrayIndex(ps->index); + SlObject(ps, _storage_desc); + } + } +}; + +static const PSACChunkHandler PSAC; +static const ChunkHandlerRef persistent_storage_chunk_handlers[] = { + PSAC, +}; + +extern const ChunkHandlerTable _persistent_storage_chunk_handlers(persistent_storage_chunk_handlers); + +} diff --git a/src/saveload/upstream/story_sl.cpp b/src/saveload/upstream/story_sl.cpp new file mode 100644 index 0000000000..3380c9df75 --- /dev/null +++ b/src/saveload/upstream/story_sl.cpp @@ -0,0 +1,115 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file story_sl.cpp Code handling saving and loading of story pages */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "compat/story_sl_compat.h" + +#include "../../story_base.h" + +#include "../../safeguards.h" + +namespace upstream_sl { + +static const SaveLoad _story_page_elements_desc[] = { + SLE_CONDVAR(StoryPageElement, sort_value, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_185), + SLE_CONDVAR(StoryPageElement, sort_value, SLE_UINT32, SLV_185, SL_MAX_VERSION), + SLE_VAR(StoryPageElement, page, SLE_UINT16), + SLE_CONDVAR(StoryPageElement, type, SLE_FILE_U16 | SLE_VAR_U8, SL_MIN_VERSION, SLV_185), + SLE_CONDVAR(StoryPageElement, type, SLE_UINT8, SLV_185, SL_MAX_VERSION), + SLE_VAR(StoryPageElement, referenced_id, SLE_UINT32), + SLE_STR(StoryPageElement, text, SLE_STR | SLF_ALLOW_CONTROL, 0), +}; + +struct STPEChunkHandler : ChunkHandler { + STPEChunkHandler() : ChunkHandler('STPE', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_story_page_elements_desc); + + for (StoryPageElement *s : StoryPageElement::Iterate()) { + SlSetArrayIndex(s->index); + SlObject(s, _story_page_elements_desc); + } + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_story_page_elements_desc, _story_page_elements_sl_compat); + + int index; + uint32 max_sort_value = 0; + while ((index = SlIterateArray()) != -1) { + StoryPageElement *s = new (index) StoryPageElement(); + SlObject(s, slt); + if (s->sort_value > max_sort_value) { + max_sort_value = s->sort_value; + } + } + /* Update the next sort value, so that the next + * created page is shown after all existing pages. + */ + _story_page_element_next_sort_value = max_sort_value + 1; + } +}; + +static const SaveLoad _story_pages_desc[] = { + SLE_CONDVAR(StoryPage, sort_value, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_185), + SLE_CONDVAR(StoryPage, sort_value, SLE_UINT32, SLV_185, SL_MAX_VERSION), + SLE_VAR(StoryPage, date, SLE_UINT32), + SLE_CONDVAR(StoryPage, company, SLE_FILE_U16 | SLE_VAR_U8, SL_MIN_VERSION, SLV_185), + SLE_CONDVAR(StoryPage, company, SLE_UINT8, SLV_185, SL_MAX_VERSION), + SLE_STR(StoryPage, title, SLE_STR | SLF_ALLOW_CONTROL, 0), +}; + +struct STPAChunkHandler : ChunkHandler { + STPAChunkHandler() : ChunkHandler('STPA', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_story_pages_desc); + + for (StoryPage *s : StoryPage::Iterate()) { + SlSetArrayIndex(s->index); + SlObject(s, _story_pages_desc); + } + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_story_pages_desc, _story_pages_sl_compat); + + int index; + uint32 max_sort_value = 0; + while ((index = SlIterateArray()) != -1) { + StoryPage *s = new (index) StoryPage(); + SlObject(s, slt); + if (s->sort_value > max_sort_value) { + max_sort_value = s->sort_value; + } + } + /* Update the next sort value, so that the next + * created page is shown after all existing pages. + */ + _story_page_next_sort_value = max_sort_value + 1; + } +}; + +static const STPEChunkHandler STPE; +static const STPAChunkHandler STPA; +static const ChunkHandlerRef story_page_chunk_handlers[] = { + STPE, + STPA, +}; + +extern const ChunkHandlerTable _story_page_chunk_handlers(story_page_chunk_handlers); + +} diff --git a/src/saveload/upstream/subsidy_sl.cpp b/src/saveload/upstream/subsidy_sl.cpp new file mode 100644 index 0000000000..88dfb7d8d7 --- /dev/null +++ b/src/saveload/upstream/subsidy_sl.cpp @@ -0,0 +1,66 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file subsidy_sl.cpp Code handling saving and loading of subsidies */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "compat/subsidy_sl_compat.h" + +#include "../../subsidy_base.h" + +#include "../../safeguards.h" + +namespace upstream_sl { + +static const SaveLoad _subsidies_desc[] = { + SLE_VAR(Subsidy, cargo_type, SLE_UINT8), + SLE_CONDVAR(Subsidy, remaining, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_CUSTOM_SUBSIDY_DURATION), + SLE_CONDVAR(Subsidy, remaining, SLE_UINT16, SLV_CUSTOM_SUBSIDY_DURATION, SL_MAX_VERSION), + SLE_CONDVAR(Subsidy, awarded, SLE_UINT8, SLV_125, SL_MAX_VERSION), + SLE_CONDVAR(Subsidy, src_type, SLE_UINT8, SLV_125, SL_MAX_VERSION), + SLE_CONDVAR(Subsidy, dst_type, SLE_UINT8, SLV_125, SL_MAX_VERSION), + SLE_CONDVAR(Subsidy, src, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_5), + SLE_CONDVAR(Subsidy, src, SLE_UINT16, SLV_5, SL_MAX_VERSION), + SLE_CONDVAR(Subsidy, dst, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_5), + SLE_CONDVAR(Subsidy, dst, SLE_UINT16, SLV_5, SL_MAX_VERSION), +}; + +struct SUBSChunkHandler : ChunkHandler { + SUBSChunkHandler() : ChunkHandler('SUBS', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_subsidies_desc); + + for (Subsidy *s : Subsidy::Iterate()) { + SlSetArrayIndex(s->index); + SlObject(s, _subsidies_desc); + } + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_subsidies_desc, _subsidies_sl_compat); + + int index; + while ((index = SlIterateArray()) != -1) { + Subsidy *s = new (index) Subsidy(); + SlObject(s, slt); + } + } +}; + +static const SUBSChunkHandler SUBS; +static const ChunkHandlerRef subsidy_chunk_handlers[] = { + SUBS, +}; + +extern const ChunkHandlerTable _subsidy_chunk_handlers(subsidy_chunk_handlers); + +} diff --git a/src/saveload/upstream/town_sl.cpp b/src/saveload/upstream/town_sl.cpp new file mode 100644 index 0000000000..839a55062e --- /dev/null +++ b/src/saveload/upstream/town_sl.cpp @@ -0,0 +1,238 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file town_sl.cpp Code handling saving and loading of towns and houses */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "compat/town_sl_compat.h" + +#include "newgrf_sl.h" +#include "../../newgrf_house.h" +#include "../../town.h" +#include "../../landscape.h" +#include "../../subsidy_func.h" +#include "../../strings_func.h" +#include "../../tilematrix_type.hpp" + +#include "../../safeguards.h" + +namespace upstream_sl { + +typedef TileMatrix AcceptanceMatrix; + +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), + }; + inline const static SaveLoadCompatTable compat_description = _town_supplied_sl_compat; + + /** + * Get the number of cargoes used by this savegame version. + * @return The number of cargoes used by this savegame version. + */ + size_t GetNumCargo() const + { + if (IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES)) return 32; + if (IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) return NUM_CARGO; + /* Read from the savegame how long the list is. */ + return SlGetStructListLength(NUM_CARGO); + } + + void Save(Town *t) const override + { + SlSetStructListLength(NUM_CARGO); + for (CargoID i = 0; i < NUM_CARGO; i++) { + SlObject(&t->supplied[i], this->GetDescription()); + } + } + + void Load(Town *t) const override + { + size_t num_cargo = this->GetNumCargo(); + for (CargoID i = 0; i < num_cargo; i++) { + SlObject(&t->supplied[i], this->GetLoadDescription()); + } + } +}; + +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), + }; + inline const static SaveLoadCompatTable compat_description = _town_received_sl_compat; + + void Save(Town *t) const override + { + SlSetStructListLength(NUM_TE); + for (size_t i = TE_BEGIN; i < TE_END; i++) { + SlObject(&t->received[i], this->GetDescription()); + } + } + + void Load(Town *t) const override + { + size_t length = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? (size_t)TE_END : SlGetStructListLength(TE_END); + for (size_t i = 0; i < length; i++) { + SlObject(&t->received[i], this->GetLoadDescription()); + } + } +}; + +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), + }; + inline const static SaveLoadCompatTable compat_description = _town_acceptance_matrix_sl_compat; + + void Load(Town *t) const override + { + /* Discard now unused acceptance matrix. */ + AcceptanceMatrix dummy; + SlObject(&dummy, this->GetLoadDescription()); + 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), + + SLE_CONDVAR(Town, townnamegrfid, SLE_UINT32, SLV_66, SL_MAX_VERSION), + SLE_VAR(Town, townnametype, SLE_UINT16), + SLE_VAR(Town, townnameparts, SLE_UINT32), + SLE_CONDSTR(Town, name, SLE_STR | SLF_ALLOW_CONTROL, 0, SLV_84, SL_MAX_VERSION), + + SLE_VAR(Town, flags, SLE_UINT8), + SLE_CONDVAR(Town, statues, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_104), + SLE_CONDVAR(Town, statues, SLE_UINT16, SLV_104, SL_MAX_VERSION), + + SLE_CONDVAR(Town, have_ratings, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_104), + SLE_CONDVAR(Town, have_ratings, SLE_UINT16, SLV_104, SL_MAX_VERSION), + SLE_CONDARR(Town, ratings, SLE_INT16, 8, SL_MIN_VERSION, SLV_104), + SLE_CONDARR(Town, ratings, SLE_INT16, MAX_COMPANIES, SLV_104, SL_MAX_VERSION), + SLE_CONDARR(Town, unwanted, SLE_INT8, 8, SLV_4, SLV_104), + SLE_CONDARR(Town, unwanted, SLE_INT8, MAX_COMPANIES, SLV_104, SL_MAX_VERSION), + + SLE_CONDVAR(Town, supplied[CT_PASSENGERS].old_max, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9), + SLE_CONDVAR(Town, supplied[CT_PASSENGERS].old_max, SLE_UINT32, SLV_9, SLV_165), + SLE_CONDVAR(Town, supplied[CT_MAIL].old_max, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9), + SLE_CONDVAR(Town, supplied[CT_MAIL].old_max, SLE_UINT32, SLV_9, SLV_165), + SLE_CONDVAR(Town, supplied[CT_PASSENGERS].new_max, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9), + SLE_CONDVAR(Town, supplied[CT_PASSENGERS].new_max, SLE_UINT32, SLV_9, SLV_165), + SLE_CONDVAR(Town, supplied[CT_MAIL].new_max, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9), + SLE_CONDVAR(Town, supplied[CT_MAIL].new_max, SLE_UINT32, SLV_9, SLV_165), + SLE_CONDVAR(Town, supplied[CT_PASSENGERS].old_act, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9), + SLE_CONDVAR(Town, supplied[CT_PASSENGERS].old_act, SLE_UINT32, SLV_9, SLV_165), + SLE_CONDVAR(Town, supplied[CT_MAIL].old_act, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9), + SLE_CONDVAR(Town, supplied[CT_MAIL].old_act, SLE_UINT32, SLV_9, SLV_165), + SLE_CONDVAR(Town, supplied[CT_PASSENGERS].new_act, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9), + SLE_CONDVAR(Town, supplied[CT_PASSENGERS].new_act, SLE_UINT32, SLV_9, SLV_165), + SLE_CONDVAR(Town, supplied[CT_MAIL].new_act, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9), + SLE_CONDVAR(Town, supplied[CT_MAIL].new_act, SLE_UINT32, SLV_9, SLV_165), + + SLE_CONDVAR(Town, received[TE_FOOD].old_act, SLE_UINT16, SL_MIN_VERSION, SLV_165), + SLE_CONDVAR(Town, received[TE_WATER].old_act, SLE_UINT16, SL_MIN_VERSION, SLV_165), + SLE_CONDVAR(Town, received[TE_FOOD].new_act, SLE_UINT16, SL_MIN_VERSION, SLV_165), + SLE_CONDVAR(Town, received[TE_WATER].new_act, SLE_UINT16, SL_MIN_VERSION, SLV_165), + + SLE_CONDARR(Town, goal, SLE_UINT32, NUM_TE, SLV_165, SL_MAX_VERSION), + + SLE_CONDSSTR(Town, text, SLE_STR | SLF_ALLOW_CONTROL, SLV_168, SL_MAX_VERSION), + + SLE_CONDVAR(Town, time_until_rebuild, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_54), + SLE_CONDVAR(Town, time_until_rebuild, SLE_UINT16, SLV_54, SL_MAX_VERSION), + SLE_CONDVAR(Town, grow_counter, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_54), + SLE_CONDVAR(Town, grow_counter, SLE_UINT16, SLV_54, SL_MAX_VERSION), + SLE_CONDVAR(Town, growth_rate, SLE_FILE_U8 | SLE_VAR_I16, SL_MIN_VERSION, SLV_54), + SLE_CONDVAR(Town, growth_rate, SLE_FILE_I16 | SLE_VAR_U16, SLV_54, SLV_165), + SLE_CONDVAR(Town, growth_rate, SLE_UINT16, SLV_165, SL_MAX_VERSION), + + SLE_VAR(Town, fund_buildings_months, SLE_UINT8), + SLE_VAR(Town, road_build_months, SLE_UINT8), + + SLE_CONDVAR(Town, exclusivity, SLE_UINT8, SLV_2, SL_MAX_VERSION), + SLE_CONDVAR(Town, exclusive_counter, SLE_UINT8, SLV_2, SL_MAX_VERSION), + + SLE_CONDVAR(Town, larger_town, SLE_BOOL, SLV_56, SL_MAX_VERSION), + SLE_CONDVAR(Town, layout, SLE_UINT8, SLV_113, SL_MAX_VERSION), + + SLE_CONDREFLIST(Town, psa_list, REF_STORAGE, SLV_161, SL_MAX_VERSION), + + SLEG_CONDSTRUCTLIST("supplied", SlTownSupplied, SLV_165, SL_MAX_VERSION), + SLEG_CONDSTRUCTLIST("received", SlTownReceived, SLV_165, SL_MAX_VERSION), + SLEG_CONDSTRUCTLIST("acceptance_matrix", SlTownAcceptanceMatrix, SLV_166, SLV_REMOVE_TOWN_CARGO_CACHE), +}; + +struct HIDSChunkHandler : NewGRFMappingChunkHandler { + HIDSChunkHandler() : NewGRFMappingChunkHandler('HIDS', _house_mngr) {} +}; + +struct CITYChunkHandler : ChunkHandler { + CITYChunkHandler() : ChunkHandler('CITY', CH_TABLE) {} + + void Save() const override + { + SlTableHeader(_town_desc); + + for (Town *t : Town::Iterate()) { + SlSetArrayIndex(t->index); + SlObject(t, _town_desc); + } + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_town_desc, _town_sl_compat); + + int index; + + while ((index = SlIterateArray()) != -1) { + Town *t = new (index) Town(); + SlObject(t, slt); + + 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"); + } + } + } + + void FixPointers() const override + { + if (IsSavegameVersionBefore(SLV_161)) return; + + for (Town *t : Town::Iterate()) { + SlObject(t, _town_desc); + } + } +}; + +static const HIDSChunkHandler HIDS; +static const CITYChunkHandler CITY; +static const ChunkHandlerRef town_chunk_handlers[] = { + HIDS, + CITY, +}; + +extern const ChunkHandlerTable _town_chunk_handlers(town_chunk_handlers); + +} diff --git a/src/saveload/upstream/vehicle_sl.cpp b/src/saveload/upstream/vehicle_sl.cpp new file mode 100644 index 0000000000..a21ca05e3d --- /dev/null +++ b/src/saveload/upstream/vehicle_sl.cpp @@ -0,0 +1,547 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file vehicle_sl.cpp Code handling saving and loading of vehicles */ + +#include "../../stdafx.h" + +#include "saveload.h" +#include "compat/vehicle_sl_compat.h" + +#include "../../vehicle_func.h" +#include "../../train.h" +#include "../../roadveh.h" +#include "../../ship.h" +#include "../../aircraft.h" +#include "../../station_base.h" +#include "../../effectvehicle_base.h" +#include "../../company_base.h" +#include "../../company_func.h" +#include "../../disaster_vehicle.h" + +#include + +#include "../../safeguards.h" + +void AfterLoadVehicles(bool part_of_load); +bool TrainController(Train *v, Vehicle *nomove, bool reverse = true); // From train_cmd.cpp +void ReverseTrainDirection(Train *v); +void ReverseTrainSwapVeh(Train *v, int l, int r); + +namespace upstream_sl { + +static uint8 _cargo_days; +static uint16 _cargo_source; +static uint32 _cargo_source_xy; +static uint16 _cargo_count; +static uint16 _cargo_paid_for; +static Money _cargo_feeder_share; +static uint32 _cargo_loaded_at_xy; + +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_CONDSTR(Vehicle, name, SLE_STR | SLF_ALLOW_CONTROL, 0, 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, 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_VAR(Vehicle, spritenum, SLE_UINT8), + SLE_VAR(Vehicle, engine_type, SLE_UINT16), + 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, cargo_type, SLE_UINT8), + SLE_CONDVAR(Vehicle, cargo_subtype, SLE_UINT8, SLV_35, SL_MAX_VERSION), + SLEG_CONDVAR("cargo_days", _cargo_days, SLE_UINT8, SL_MIN_VERSION, SLV_68), + SLEG_CONDVAR("cargo_source", _cargo_source, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_7), + SLEG_CONDVAR("cargo_source", _cargo_source, SLE_UINT16, SLV_7, SLV_68), + SLEG_CONDVAR("cargo_source_xy", _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), + SLEG_CONDVAR("cargo_count", _cargo_count, SLE_UINT16, SL_MIN_VERSION, SLV_68), + SLE_CONDREFDEQUE(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_VAR(Vehicle, day_counter, SLE_UINT8), + SLE_VAR(Vehicle, tick_counter, SLE_UINT8), + SLE_CONDVAR(Vehicle, running_ticks, SLE_FILE_U8 | SLE_VAR_U16, SLV_88, SL_MAX_VERSION), + + SLE_VAR(Vehicle, cur_implicit_order_index, SLE_FILE_U8 | SLE_VAR_U16), + SLE_CONDVAR(Vehicle, cur_real_order_index, SLE_FILE_U8 | SLE_VAR_U16, SLV_158, SL_MAX_VERSION), + + /* 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), + + /* 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_FILE_U8 | SLE_VAR_U16, 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), + + /* Timetable in current order */ + SLE_CONDVAR(Vehicle, current_order.wait_time, SLE_FILE_U16 | SLE_VAR_U32, SLV_67, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, current_order.travel_time, SLE_FILE_U16 | SLE_VAR_U32, 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_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), + SLEG_CONDVAR("cargo_paid_for", _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, 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", _cargo_feeder_share, SLE_FILE_I32 | SLE_VAR_I64, SLV_51, SLV_65), + SLEG_CONDVAR("cargo_feeder_share", _cargo_feeder_share, SLE_INT64, SLV_65, SLV_68), + SLEG_CONDVAR("cargo_loaded_at_xy", _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, 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_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), + }; +#if defined(_MSC_VER) && (_MSC_VER == 1915 || _MSC_VER == 1916) + return description; + } +#endif + inline const static SaveLoadCompatTable compat_description = _vehicle_common_sl_compat; + + void Save(Vehicle *v) const override + { + SlObject(v, this->GetDescription()); + } + + void Load(Vehicle *v) const override + { + SlObject(v, this->GetLoadDescription()); + } + + void FixPointers(Vehicle *v) const override + { + SlObject(v, this->GetDescription()); + } +}; + +class SlVehicleTrain : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLEG_STRUCT("common", SlVehicleCommon), + SLE_VAR(Train, crash_anim_pos, SLE_UINT16), + SLE_VAR(Train, force_proceed, SLE_UINT8), + SLE_VAR(Train, railtype, SLE_UINT8), + SLE_VAR(Train, track, SLE_UINT8), + + SLE_CONDVAR(Train, flags, SLE_FILE_U8 | SLE_VAR_U32, SLV_2, SLV_100), + SLE_CONDVAR(Train, flags, SLE_FILE_U16 | SLE_VAR_U32, SLV_100, SL_MAX_VERSION), + SLE_CONDVAR(Train, wait_counter, SLE_UINT16, SLV_136, SL_MAX_VERSION), + SLE_CONDVAR(Train, gv_flags, SLE_UINT16, SLV_139, SL_MAX_VERSION), + }; + inline const static SaveLoadCompatTable compat_description = _vehicle_train_sl_compat; + + void Save(Vehicle *v) const override + { + if (v->type != VEH_TRAIN) return; + SlObject(v, this->GetDescription()); + } + + void Load(Vehicle *v) const override + { + if (v->type != VEH_TRAIN) return; + SlObject(v, this->GetLoadDescription()); + if (v->cur_real_order_index == 0xFF) v->cur_real_order_index = INVALID_VEH_ORDER_ID; + if (v->cur_implicit_order_index == 0xFF) v->cur_implicit_order_index = INVALID_VEH_ORDER_ID; + } + + void FixPointers(Vehicle *v) const override + { + if (v->type != VEH_TRAIN) return; + SlObject(v, this->GetDescription()); + } +}; + +class SlVehicleRoadVeh : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLEG_STRUCT("common", SlVehicleCommon), + SLE_VAR(RoadVehicle, state, SLE_UINT8), + SLE_VAR(RoadVehicle, frame, SLE_UINT8), + SLE_VAR(RoadVehicle, blocked_ctr, SLE_UINT16), + SLE_VAR(RoadVehicle, overtaking, SLE_UINT8), + SLE_VAR(RoadVehicle, overtaking_ctr, SLE_UINT8), + SLE_VAR(RoadVehicle, crashed_ctr, SLE_UINT16), + SLE_VAR(RoadVehicle, reverse_ctr, SLE_UINT8), + SLE_CONDDEQUE(RoadVehicle, path.td, SLE_UINT8, SLV_ROADVEH_PATH_CACHE, SL_MAX_VERSION), + SLE_CONDDEQUE(RoadVehicle, path.tile, SLE_UINT32, SLV_ROADVEH_PATH_CACHE, SL_MAX_VERSION), + SLE_CONDVAR(RoadVehicle, gv_flags, SLE_UINT16, SLV_139, SL_MAX_VERSION), + }; + inline const static SaveLoadCompatTable compat_description = _vehicle_roadveh_sl_compat; + + void Save(Vehicle *v) const override + { + if (v->type != VEH_ROAD) return; + SlObject(v, this->GetDescription()); + } + + void Load(Vehicle *v) const override + { + if (v->type != VEH_ROAD) return; + SlObject(v, this->GetLoadDescription()); + } + + void FixPointers(Vehicle *v) const override + { + if (v->type != VEH_ROAD) return; + SlObject(v, this->GetDescription()); + } +}; + +class SlVehicleShip : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLEG_STRUCT("common", 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), + }; + inline const static SaveLoadCompatTable compat_description = _vehicle_ship_sl_compat; + + void Save(Vehicle *v) const override + { + if (v->type != VEH_SHIP) return; + SlObject(v, this->GetDescription()); + } + + void Load(Vehicle *v) const override + { + if (v->type != VEH_SHIP) return; + SlObject(v, this->GetLoadDescription()); + } + + void FixPointers(Vehicle *v) const override + { + if (v->type != VEH_SHIP) return; + SlObject(v, this->GetDescription()); + } +}; + +class SlVehicleAircraft : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLEG_STRUCT("common", SlVehicleCommon), + SLE_VAR(Aircraft, crashed_counter, SLE_UINT16), + SLE_VAR(Aircraft, pos, SLE_UINT8), + + SLE_CONDVAR(Aircraft, targetairport, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_5), + SLE_CONDVAR(Aircraft, targetairport, SLE_UINT16, SLV_5, SL_MAX_VERSION), + + SLE_VAR(Aircraft, state, SLE_UINT8), + + SLE_CONDVAR(Aircraft, previous_pos, SLE_UINT8, SLV_2, SL_MAX_VERSION), + SLE_CONDVAR(Aircraft, last_direction, SLE_UINT8, SLV_2, SL_MAX_VERSION), + SLE_CONDVAR(Aircraft, number_consecutive_turns, SLE_UINT8, SLV_2, SL_MAX_VERSION), + + SLE_CONDVAR(Aircraft, turn_counter, SLE_UINT8, SLV_136, SL_MAX_VERSION), + SLE_CONDVAR(Aircraft, flags, SLE_UINT8, SLV_167, SL_MAX_VERSION), + }; + inline const static SaveLoadCompatTable compat_description = _vehicle_aircraft_sl_compat; + + void Save(Vehicle *v) const override + { + if (v->type != VEH_AIRCRAFT) return; + SlObject(v, this->GetDescription()); + } + + void Load(Vehicle *v) const override + { + if (v->type != VEH_AIRCRAFT) return; + SlObject(v, this->GetLoadDescription()); + } + + void FixPointers(Vehicle *v) const override + { + if (v->type != VEH_AIRCRAFT) return; + SlObject(v, this->GetDescription()); + } +}; + +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), + SLE_CONDVAR(Vehicle, 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_VAR2(Vehicle, "sprite_cache.sprite_seq.seq[0].sprite", sprite_seq.seq[0].sprite, SLE_FILE_U16 | SLE_VAR_U32), + SLE_VAR(Vehicle, progress, SLE_UINT8), + SLE_VAR(Vehicle, vehstatus, SLE_UINT8), + + SLE_VAR(EffectVehicle, animation_state, SLE_UINT16), + SLE_VAR(EffectVehicle, animation_substate, SLE_UINT8), + + SLE_CONDVAR(Vehicle, spritenum, SLE_UINT8, SLV_2, SL_MAX_VERSION), + }; + inline const static SaveLoadCompatTable compat_description = _vehicle_effect_sl_compat; + + void Save(Vehicle *v) const override + { + if (v->type != VEH_EFFECT) return; + SlObject(v, this->GetDescription()); + } + + void Load(Vehicle *v) const override + { + if (v->type != VEH_EFFECT) return; + SlObject(v, this->GetLoadDescription()); + } + + void FixPointers(Vehicle *v) const override + { + if (v->type != VEH_EFFECT) return; + SlObject(v, this->GetDescription()); + } +}; + +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_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_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_VAR2(Vehicle, "sprite_cache.sprite_seq.seq[0].sprite", 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), + }; +#if defined(_MSC_VER) && (_MSC_VER == 1915 || _MSC_VER == 1916) + return description; + } +#endif + inline const static SaveLoadCompatTable compat_description = _vehicle_disaster_sl_compat; + + void Save(Vehicle *v) const override + { + if (v->type != VEH_DISASTER) return; + SlObject(v, this->GetDescription()); + } + + void Load(Vehicle *v) const override + { + if (v->type != VEH_DISASTER) return; + SlObject(v, this->GetLoadDescription()); + } + + void FixPointers(Vehicle *v) const override + { + if (v->type != VEH_DISASTER) return; + SlObject(v, this->GetDescription()); + } +}; + +const static SaveLoad _vehicle_desc[] = { + SLE_SAVEBYTE(Vehicle, type), + SLEG_STRUCT("train", SlVehicleTrain), + SLEG_STRUCT("roadveh", SlVehicleRoadVeh), + SLEG_STRUCT("ship", SlVehicleShip), + SLEG_STRUCT("aircraft", SlVehicleAircraft), + SLEG_STRUCT("effect", SlVehicleEffect), + SLEG_STRUCT("disaster", SlVehicleDisaster), +}; + +struct VEHSChunkHandler : ChunkHandler { + VEHSChunkHandler() : ChunkHandler('VEHS', CH_SPARSE_TABLE) {} + + void Save() const override + { + SlTableHeader(_vehicle_desc); + + /* Write the vehicles */ + for (Vehicle *v : Vehicle::Iterate()) { + SlSetArrayIndex(v->index); + SlObject(v, _vehicle_desc); + } + } + + void Load() const override + { + const std::vector slt = SlCompatTableHeader(_vehicle_desc, _vehicle_sl_compat); + + int index; + + _cargo_count = 0; + + while ((index = SlIterateArray()) != -1) { + Vehicle *v; + VehicleType vtype = (VehicleType)SlReadByte(); + + switch (vtype) { + case VEH_TRAIN: v = new (index) Train(); break; + case VEH_ROAD: v = new (index) RoadVehicle(); break; + case VEH_SHIP: v = new (index) Ship(); break; + case VEH_AIRCRAFT: v = new (index) Aircraft(); break; + case VEH_EFFECT: v = new (index) EffectVehicle(); break; + case VEH_DISASTER: v = new (index) DisasterVehicle(); break; + case VEH_INVALID: // Savegame shouldn't contain invalid vehicles + default: SlErrorCorrupt("Invalid vehicle type"); + } + + SlObject(v, slt); + + if (_cargo_count != 0 && IsCompanyBuildableVehicleType(v) && CargoPacket::CanAllocateItem()) { + /* Don't construct the packet with station here, because that'll fail with old savegames */ + CargoPacket *cp = new CargoPacket(_cargo_count, _cargo_days, _cargo_source, _cargo_source_xy, _cargo_loaded_at_xy, _cargo_feeder_share); + v->cargo.Append(cp); + } + +#if 0 + /* Old savegames used 'last_station_visited = 0xFF' */ + if (IsSavegameVersionBefore(SLV_5) && v->last_station_visited == 0xFF) { + v->last_station_visited = INVALID_STATION; + } + + if (IsSavegameVersionBefore(SLV_182)) v->last_loading_station = INVALID_STATION; + + if (IsSavegameVersionBefore(SLV_5)) { + /* Convert the current_order.type (which is a mix of type and flags, because + * in those versions, they both were 4 bits big) to type and flags */ + v->current_order.flags = GB(v->current_order.type, 4, 4); + v->current_order.type &= 0x0F; + } + + /* Advanced vehicle lists got added */ + if (IsSavegameVersionBefore(SLV_60)) v->group_id = DEFAULT_GROUP; +#endif + } + } + + void FixPointers() const override + { + for (Vehicle *v : Vehicle::Iterate()) { + SlObject(v, _vehicle_desc); + } + } +}; + +static const VEHSChunkHandler VEHS; +static const ChunkHandlerRef veh_chunk_handlers[] = { + VEHS, +}; + +extern const ChunkHandlerTable _veh_chunk_handlers(veh_chunk_handlers); + +} diff --git a/src/settings.cpp b/src/settings.cpp index 6a240e0ee1..143eb5e2c4 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -84,6 +84,8 @@ #define HAS_TRUETYPE_FONT #endif +#include "saveload/saveload.h" + #include "table/strings.h" #include "table/settings.h" @@ -3028,3 +3030,8 @@ void SetupTimeSettings() { _settings_time = (_game_mode == GM_MENU || _settings_client.gui.override_time_settings) ? _settings_client.gui : _settings_game.game_time; } + +const SettingTable &GetSettingsTableInternal() +{ + return _settings; +} diff --git a/src/settings_internal.h b/src/settings_internal.h index 76481b6c95..117affd840 100644 --- a/src/settings_internal.h +++ b/src/settings_internal.h @@ -10,7 +10,7 @@ #ifndef SETTINGS_INTERNAL_H #define SETTINGS_INTERNAL_H -#include "saveload/saveload.h" +#include "saveload/saveload_types.h" enum SettingFlag : uint32 { SF_NONE = 0, diff --git a/src/tbtr_template_vehicle.h b/src/tbtr_template_vehicle.h index 0914a0aff7..3ec272e247 100644 --- a/src/tbtr_template_vehicle.h +++ b/src/tbtr_template_vehicle.h @@ -27,7 +27,7 @@ #include "sortlist_type.h" -#include "saveload/saveload.h" +#include "saveload/saveload_common.h" #include "zoom_func.h" diff --git a/src/vehicle_base.h b/src/vehicle_base.h index 34ff5f1f06..313a549405 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -25,7 +25,7 @@ #include "newgrf_cache_check.h" #include "landscape.h" #include "network/network.h" -#include "saveload/saveload.h" +#include "saveload/saveload_common.h" #include #include #include @@ -240,6 +240,11 @@ extern void FixOldVehicles(); struct GRFFile; +namespace upstream_sl { + class SlVehicleCommon; + class SlVehicleDisaster; +} + /** %Vehicle data structure. */ struct Vehicle : VehiclePool::PoolItem<&_vehicle_pool>, BaseVehicle, BaseConsist { private: @@ -258,6 +263,9 @@ public: 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 + friend upstream_sl::SlVehicleCommon; + friend upstream_sl::SlVehicleDisaster; + static void PreCleanPool(); TileIndex tile; ///< Current tile index