OpenTTD Source 20260311-master-g511d3794ce
industry_sl.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "../stdafx.h"
11
12#include "saveload.h"
14
15#include "../industry.h"
16#include "newgrf_sl.h"
17
18#include "../safeguards.h"
19
20static OldPersistentStorage _old_ind_persistent_storage;
21
22class SlIndustryAcceptedHistory : public DefaultSaveLoadHandler<SlIndustryAcceptedHistory, Industry::AcceptedCargo> {
23public:
24 static inline const SaveLoad description[] = {
25 SLE_VAR(Industry::AcceptedHistory, accepted, SLE_UINT16),
26 SLE_VAR(Industry::AcceptedHistory, waiting, SLE_UINT16),
27 };
28 static inline const SaveLoadCompatTable compat_description = _industry_produced_history_sl_compat;
29
30 void Save(Industry::AcceptedCargo *a) const override
31 {
32 if (!IsValidCargoType(a->cargo) || a->history == nullptr) {
33 /* Don't save any history if cargo slot isn't used. */
35 return;
36 }
37
39
40 for (auto &h : *a->history) {
41 SlObject(&h, this->GetDescription());
42 }
43 }
44
45 void Load(Industry::AcceptedCargo *a) const override
46 {
47 size_t len = SlGetStructListLength(UINT32_MAX);
48 if (len == 0) return;
49
50 auto &history = a->GetOrCreateHistory();
51 for (auto &h : history) {
52 if (--len > history.size()) break; // unsigned so wraps after hitting zero.
53 SlObject(&h, this->GetLoadDescription());
54 }
55 }
56};
57
58class SlIndustryAccepted : public VectorSaveLoadHandler<SlIndustryAccepted, Industry, Industry::AcceptedCargo, INDUSTRY_NUM_INPUTS> {
59public:
60 static inline const SaveLoad description[] = {
61 SLE_VAR(Industry::AcceptedCargo, cargo, SLE_UINT8),
62 SLE_VAR(Industry::AcceptedCargo, waiting, SLE_UINT16),
63 SLE_VAR(Industry::AcceptedCargo, last_accepted, SLE_INT32),
66 };
67 static inline const SaveLoadCompatTable compat_description = _industry_accepts_sl_compat;
68
69 std::vector<Industry::AcceptedCargo> &GetVector(Industry *i) const override { return i->accepted; }
70
73 static inline std::array<CargoType, INDUSTRY_NUM_INPUTS> old_cargo;
74 static inline std::array<uint16_t, INDUSTRY_NUM_INPUTS> old_waiting;
75 static inline std::array<TimerGameEconomy::Date, INDUSTRY_NUM_INPUTS> old_last_accepted;
77
78 static void ResetOldStructure()
79 {
80 SlIndustryAccepted::old_cargo.fill(INVALID_CARGO);
82 SlIndustryAccepted::old_last_accepted.fill(TimerGameEconomy::Date{});
83 }
84};
85
86class SlIndustryProducedHistory : public DefaultSaveLoadHandler<SlIndustryProducedHistory, Industry::ProducedCargo> {
87public:
88 static inline const SaveLoad description[] = {
89 SLE_VAR(Industry::ProducedHistory, production, SLE_UINT16),
90 SLE_VAR(Industry::ProducedHistory, transported, SLE_UINT16),
91 };
92 static inline const SaveLoadCompatTable compat_description = _industry_produced_history_sl_compat;
93
94 void Save(Industry::ProducedCargo *p) const override
95 {
96 if (!IsValidCargoType(p->cargo)) {
97 /* Don't save any history if cargo slot isn't used. */
99 return;
100 }
101
103
104 for (auto &h : p->history) {
105 SlObject(&h, this->GetDescription());
106 }
107 }
108
109 void Load(Industry::ProducedCargo *p) const override
110 {
111 size_t len = SlGetStructListLength(p->history.size());
112
113 for (auto &h : p->history) {
114 if (--len > p->history.size()) break; // unsigned so wraps after hitting zero.
115 SlObject(&h, this->GetLoadDescription());
116 }
117 }
118};
119
120class SlIndustryProduced : public VectorSaveLoadHandler<SlIndustryProduced, Industry, Industry::ProducedCargo, INDUSTRY_NUM_OUTPUTS> {
121public:
122 static inline const SaveLoad description[] = {
123 SLE_VAR(Industry::ProducedCargo, cargo, SLE_UINT8),
124 SLE_VAR(Industry::ProducedCargo, waiting, SLE_UINT16),
125 SLE_VAR(Industry::ProducedCargo, rate, SLE_UINT8),
127 };
128 static inline const SaveLoadCompatTable compat_description = _industry_produced_sl_compat;
129
130 std::vector<Industry::ProducedCargo> &GetVector(Industry *i) const override { return i->produced; }
131
134 static inline std::array<CargoType, INDUSTRY_NUM_OUTPUTS> old_cargo;
135 static inline std::array<uint16_t, INDUSTRY_NUM_OUTPUTS> old_waiting;
136 static inline std::array<uint8_t, INDUSTRY_NUM_OUTPUTS> old_rate;
137 static inline std::array<uint16_t, INDUSTRY_NUM_OUTPUTS> old_this_month_production;
138 static inline std::array<uint16_t, INDUSTRY_NUM_OUTPUTS> old_this_month_transported;
139 static inline std::array<uint16_t, INDUSTRY_NUM_OUTPUTS> old_last_month_production;
140 static inline std::array<uint16_t, INDUSTRY_NUM_OUTPUTS> old_last_month_transported;
142
143 static void ResetOldStructure()
144 {
145 SlIndustryProduced::old_cargo.fill(INVALID_CARGO);
152 }
153};
154
155static const SaveLoad _industry_desc[] = {
156 SLE_CONDVAR(Industry, location.tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6),
157 SLE_CONDVAR(Industry, location.tile, SLE_UINT32, SLV_6, SL_MAX_VERSION),
158 SLE_VAR(Industry, location.w, SLE_FILE_U8 | SLE_VAR_U16),
159 SLE_VAR(Industry, location.h, SLE_FILE_U8 | SLE_VAR_U16),
160 SLE_REF(Industry, town, REF_TOWN),
172 SLE_VAR(Industry, prod_level, SLE_UINT8),
181
182 SLE_VAR(Industry, counter, SLE_UINT16),
183
184 SLE_VAR(Industry, type, SLE_UINT8),
185 SLE_VAR(Industry, owner, SLE_UINT8),
186 SLE_VAR(Industry, random_colour, SLE_UINT8),
187 SLE_CONDVAR(Industry, last_prod_year, SLE_FILE_U8 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31),
188 SLE_CONDVAR(Industry, last_prod_year, SLE_INT32, SLV_31, SL_MAX_VERSION),
189 SLE_VAR(Industry, was_cargo_delivered, SLE_UINT8),
191
192 SLE_CONDVAR(Industry, founder, SLE_UINT8, SLV_70, SL_MAX_VERSION),
193 SLE_CONDVAR(Industry, construction_date, SLE_INT32, SLV_70, SL_MAX_VERSION),
194 SLE_CONDVAR(Industry, construction_type, SLE_UINT8, SLV_70, SL_MAX_VERSION),
197 SLE_CONDVAR(Industry, selected_layout, SLE_UINT8, SLV_73, SL_MAX_VERSION),
198 SLE_CONDVAR(Industry, exclusive_supplier, SLE_UINT8, SLV_GS_INDUSTRY_CONTROL, SL_MAX_VERSION),
199 SLE_CONDVAR(Industry, exclusive_consumer, SLE_UINT8, SLV_GS_INDUSTRY_CONTROL, SL_MAX_VERSION),
200
201 SLEG_CONDARR("storage", _old_ind_persistent_storage.storage, SLE_UINT32, 16, SLV_76, SLV_161),
203
204 SLE_CONDVAR(Industry, random, SLE_UINT16, SLV_82, SL_MAX_VERSION),
206
208
211};
212
213struct INDYChunkHandler : ChunkHandler {
214 INDYChunkHandler() : ChunkHandler('INDY', CH_TABLE) {}
215
216 void Save() const override
217 {
218 SlTableHeader(_industry_desc);
219
220 /* Write the industries */
221 for (Industry *ind : Industry::Iterate()) {
222 SlSetArrayIndex(ind->index);
223 SlObject(ind, _industry_desc);
224 }
225 }
226
227 void LoadMoveAcceptsProduced(Industry *i, uint inputs, uint outputs) const
228 {
229 i->accepted.reserve(inputs);
230 for (uint j = 0; j != inputs; ++j) {
231 auto &a = i->accepted.emplace_back();
233 a.waiting = SlIndustryAccepted::old_waiting[j];
234 a.last_accepted = SlIndustryAccepted::old_last_accepted[j];
235 }
236
237 i->produced.reserve(outputs);
238 for (uint j = 0; j != outputs; ++j) {
239 auto &p = i->produced.emplace_back();
241 p.waiting = SlIndustryProduced::old_waiting[j];
243 p.history[THIS_MONTH].production = SlIndustryProduced::old_this_month_production[j];
244 p.history[THIS_MONTH].transported = SlIndustryProduced::old_this_month_transported[j];
245 p.history[LAST_MONTH].production = SlIndustryProduced::old_last_month_production[j];
246 p.history[LAST_MONTH].transported = SlIndustryProduced::old_last_month_transported[j];
247 }
248 }
249
250 void Load() const override
251 {
252 const std::vector<SaveLoad> slt = SlCompatTableHeader(_industry_desc, _industry_sl_compat);
253
254 int index;
255
256 SlIndustryAccepted::ResetOldStructure();
257 SlIndustryProduced::ResetOldStructure();
258
259 while ((index = SlIterateArray()) != -1) {
260 Industry *i = Industry::CreateAtIndex(IndustryID(index));
261 SlObject(i, slt);
262
263 /* Before savegame version 161, persistent storages were not stored in a pool. */
265 /* Store the old persistent storage. The GRFID will be added later. */
268 std::copy(std::begin(_old_ind_persistent_storage.storage), std::end(_old_ind_persistent_storage.storage), std::begin(i->psa->storage));
269 }
273 LoadMoveAcceptsProduced(i, INDUSTRY_NUM_INPUTS, INDUSTRY_NUM_OUTPUTS);
274 }
275
277 /* The last month has always been recorded. */
278 size_t oldest_valid = LAST_MONTH;
280 /* History was extended but we did not keep track of valid history, so assume it from the oldest non-zero value. */
281 for (const auto &p : i->produced) {
282 if (!IsValidCargoType(p.cargo)) continue;
283 for (size_t n = LAST_MONTH; n < std::size(p.history); ++n) {
284 if (p.history[n].production == 0 && p.history[n].transported == 0) continue;
285 oldest_valid = std::max(oldest_valid, n);
286 }
287 }
288 }
289 /* Set mask bits up to and including the oldest valid record. */
290 i->valid_history = (std::numeric_limits<uint64_t>::max() >> (std::numeric_limits<uint64_t>::digits - (oldest_valid + 1 - LAST_MONTH))) << LAST_MONTH;
291 }
292
293 Industry::industries[i->type].insert(i->index);
294 }
295 }
296
297 void FixPointers() const override
298 {
299 for (Industry *i : Industry::Iterate()) {
300 SlObject(i, _industry_desc);
301 }
302 }
303};
304
305struct IIDSChunkHandler : NewGRFMappingChunkHandler {
306 IIDSChunkHandler() : NewGRFMappingChunkHandler('IIDS', _industry_mngr) {}
307};
308
309struct TIDSChunkHandler : NewGRFMappingChunkHandler {
310 TIDSChunkHandler() : NewGRFMappingChunkHandler('TIDS', _industile_mngr) {}
311};
312
315 SLEG_VAR("wanted_inds", _industry_builder.wanted_inds, SLE_UINT32),
316};
317
319struct IBLDChunkHandler : ChunkHandler {
320 IBLDChunkHandler() : ChunkHandler('IBLD', CH_TABLE) {}
321
322 void Save() const override
323 {
325
326 SlSetArrayIndex(0);
328 }
329
330 void Load() const override
331 {
333
335 SlGlobList(slt);
336 if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many IBLD entries");
337 }
338};
339
342 SLE_VAR(IndustryTypeBuildData, probability, SLE_UINT32),
343 SLE_VAR(IndustryTypeBuildData, min_number, SLE_UINT8),
344 SLE_VAR(IndustryTypeBuildData, target_count, SLE_UINT16),
345 SLE_VAR(IndustryTypeBuildData, max_wait, SLE_UINT16),
346 SLE_VAR(IndustryTypeBuildData, wait_count, SLE_UINT16),
347};
348
350struct ITBLChunkHandler : ChunkHandler {
351 ITBLChunkHandler() : ChunkHandler('ITBL', CH_TABLE) {}
352
353 void Save() const override
354 {
356
357 for (int i = 0; i < NUM_INDUSTRYTYPES; i++) {
358 SlSetArrayIndex(i);
360 }
361 }
362
363 void Load() const override
364 {
366
367 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
368 _industry_builder.builddata[it].Reset();
369 }
370 int index;
371 while ((index = SlIterateArray()) != -1) {
372 if ((uint)index >= NUM_INDUSTRYTYPES) SlErrorCorrupt("Too many industry builder datas");
373 SlObject(_industry_builder.builddata + index, slt);
374 }
375 }
376};
377
378static const INDYChunkHandler INDY;
379static const IIDSChunkHandler IIDS;
380static const TIDSChunkHandler TIDS;
381static const IBLDChunkHandler IBLD;
382static const ITBLChunkHandler ITBL;
383static const ChunkHandlerRef industry_chunk_handlers[] = {
384 INDY,
385 IIDS,
386 TIDS,
387 IBLD,
388 ITBL,
389};
390
391extern const ChunkHandlerTable _industry_chunk_handlers(industry_chunk_handlers);
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:108
Default handler for saving/loading an object to/from disk.
Definition saveload.h:603
SaveLoadTable GetLoadDescription() const
Get the description for how to load the chunk.
void Load(Industry::AcceptedCargo *a) const override
Load the object from disk.
void Save(Industry::AcceptedCargo *a) const override
Save the object to disk.
static std::array< uint16_t, INDUSTRY_NUM_INPUTS > old_waiting
std::vector< Industry::AcceptedCargo > & GetVector(Industry *i) const override
Get instance of vector to load/save.
static std::array< CargoType, INDUSTRY_NUM_INPUTS > old_cargo
static std::array< TimerGameEconomy::Date, INDUSTRY_NUM_INPUTS > old_last_accepted
void Save(Industry::ProducedCargo *p) const override
Save the object to disk.
void Load(Industry::ProducedCargo *p) const override
Load the object from disk.
static std::array< uint16_t, INDUSTRY_NUM_OUTPUTS > old_last_month_production
static std::array< uint16_t, INDUSTRY_NUM_OUTPUTS > old_this_month_transported
std::vector< Industry::ProducedCargo > & GetVector(Industry *i) const override
Get instance of vector to load/save.
static std::array< CargoType, INDUSTRY_NUM_OUTPUTS > old_cargo
static std::array< uint16_t, INDUSTRY_NUM_OUTPUTS > old_last_month_transported
static std::array< uint16_t, INDUSTRY_NUM_OUTPUTS > old_waiting
static std::array< uint16_t, INDUSTRY_NUM_OUTPUTS > old_this_month_production
static std::array< uint8_t, INDUSTRY_NUM_OUTPUTS > old_rate
Default handler for saving/loading a vector to/from disk.
Definition saveload.h:1409
Base of all industries.
IndustryBuildData _industry_builder
In-game manager of industries.
static const SaveLoad _industrytype_builder_desc[]
Description of the data to save and load in IndustryTypeBuildData.
static const SaveLoad _industry_builder_desc[]
Description of the data to save and load in IndustryBuildData.
Loading of industry chunks before table headers were added.
const SaveLoadCompat _industry_sl_compat[]
Original field order for _industry_desc.
const SaveLoadCompat _industry_builder_sl_compat[]
Original field order for _industry_builder_desc.
const SaveLoadCompat _industrytype_builder_sl_compat[]
Original field order for _industrytype_builder_desc.
static const int INDUSTRY_ORIGINAL_NUM_INPUTS
Original number of accepted cargo types.
static const int INDUSTRY_NUM_OUTPUTS
Number of cargo types an industry can produce.
static const int INDUSTRY_NUM_INPUTS
Number of cargo types an industry can accept.
static const IndustryType NUM_INDUSTRYTYPES
total number of industry types, new and old; limited to 240 because we need some special ids like IT_...
static const int INDUSTRY_ORIGINAL_NUM_OUTPUTS
Original number of produced cargo types.
@ GSF_INVALID
An invalid spec feature.
Definition newgrf.h:102
Code handling saving and loading of NewGRF mappings.
A number of safeguards to prevent using unsafe methods.
std::vector< SaveLoad > SlCompatTableHeader(const SaveLoadTable &slt, const SaveLoadCompatTable &slct)
Load a table header in a savegame compatible way.
size_t SlGetStructListLength(size_t limit)
Get the length of this list; if it exceeds the limit, error out.
int SlIterateArray()
Iterate through the elements of an array and read the whole thing.
Definition saveload.cpp:686
void SlErrorCorrupt(const std::string &msg)
Error handler for corrupt savegames.
Definition saveload.cpp:369
void SlObject(void *object, const SaveLoadTable &slt)
Main SaveLoad function.
std::vector< SaveLoad > SlTableHeader(const SaveLoadTable &slt)
Save or Load a table header.
void SlGlobList(const SaveLoadTable &slt)
Save or Load (a list of) global variables.
void SlSetStructListLength(size_t length)
Set the length of this list.
Functions/types related to saving and loading games.
#define SLEG_CONDARR(name, variable, type, length, from, to)
Storage of a global fixed-size array of SL_VAR elements in some savegame versions.
Definition saveload.h:1169
#define SLEG_STRUCTLIST(name, handler)
Storage of a list of structs in every savegame version.
Definition saveload.h:1280
#define SLEG_CONDVAR(name, variable, type, from, to)
Storage of a global variable in some savegame versions.
Definition saveload.h:1148
@ SLF_ALLOW_CONTROL
Allow control codes in the strings.
Definition saveload.h:726
std::reference_wrapper< const ChunkHandler > ChunkHandlerRef
A reference to ChunkHandler.
Definition saveload.h:527
@ REF_TOWN
Load/save a reference to a town.
Definition saveload.h:642
@ REF_STATION
Load/save a reference to a station.
Definition saveload.h:641
@ REF_STORAGE
Load/save a reference to a persistent storage.
Definition saveload.h:648
std::span< const ChunkHandlerRef > ChunkHandlerTable
A table of ChunkHandler entries.
Definition saveload.h:530
#define SLEG_VAR(name, variable, type)
Storage of a global variable in every savegame version.
Definition saveload.h:1225
#define SLE_REF(base, variable, type)
Storage of a reference in every version of a savegame.
Definition saveload.h:1058
std::span< const struct SaveLoadCompat > SaveLoadCompatTable
A table of SaveLoadCompat entries.
Definition saveload.h:536
#define SLE_CONDSSTR(base, variable, type, from, to)
Storage of a std::string in some savegame versions.
Definition saveload.h:972
#define SLE_CONDVAR(base, variable, type, from, to)
Storage of a variable in some savegame versions.
Definition saveload.h:907
bool IsSavegameVersionBefore(SaveLoadVersion major, uint8_t minor=0)
Checks whether the savegame is below major.
Definition saveload.h:1302
@ SLV_INDUSTRY_TEXT
289 PR#8576 v1.11.0-RC1 Additional GS text for industries.
Definition saveload.h:326
@ SLV_SERVE_NEUTRAL_INDUSTRIES
210 PR#7234 Company stations can serve industries with attached neutral stations.
Definition saveload.h:296
@ SLV_73
73 10903
Definition saveload.h:130
@ SLV_EXTEND_INDUSTRY_CARGO_SLOTS
202 PR#6867 Increase industry cargo slots to 16 in, 16 out
Definition saveload.h:286
@ SLV_6
6.0 1721 6.1 1768
Definition saveload.h:46
@ SLV_INDUSTRY_NUM_VALID_HISTORY
356 PR#14416 Store number of valid history records for industries.
Definition saveload.h:407
@ SLV_RIFF_TO_ARRAY
294 PR#9375 Changed many CH_RIFF chunks to CH_ARRAY chunks.
Definition saveload.h:332
@ SL_MAX_VERSION
Highest possible saveload version.
Definition saveload.h:418
@ SLV_GS_INDUSTRY_CONTROL
287 PR#7912 and PR#8115 GS industry control.
Definition saveload.h:324
@ SL_MIN_VERSION
First savegame version.
Definition saveload.h:31
@ SLV_PRODUCTION_HISTORY
343 PR#10541 Industry production history.
Definition saveload.h:391
@ SLV_76
76 11139
Definition saveload.h:134
@ SLV_78
78 11176
Definition saveload.h:136
@ SLV_161
161 22567
Definition saveload.h:236
@ SLV_INDUSTRY_CARGO_REORGANISE
315 PR#10853 Industry accepts/produced data reorganised.
Definition saveload.h:358
@ SLV_INDUSTRY_ACCEPTED_HISTORY
357 PR#14321 Add per-industry history of cargo delivered and waiting.
Definition saveload.h:408
@ SLV_82
82 11410
Definition saveload.h:141
@ SLV_70
70 10541
Definition saveload.h:127
@ SLV_31
31 5999
Definition saveload.h:80
#define SLE_CONDREF(base, variable, type, from, to)
Storage of a reference in some savegame versions.
Definition saveload.h:928
#define SLEG_CONDSTRUCTLIST(name, handler, from, to)
Storage of a list of structs in some savegame versions.
Definition saveload.h:1217
#define SLE_VAR(base, variable, type)
Storage of a variable in every version of a savegame.
Definition saveload.h:1041
Definition of base types and functions in a cross-platform compatible way.
Industry builder.
void Load() const override
Load the chunk.
void Save() const override
Save the chunk.
void Save() const override
Save the chunk.
void Load() const override
Load the chunk.
void FixPointers() const override
Fix the pointers.
Industry-type build data.
void Load() const override
Load the chunk.
void Save() const override
Save the chunk.
Data for managing the number of industries of a single industry type.
Definition industry.h:292
CargoType cargo
Cargo type.
Definition industry.h:86
HistoryData< AcceptedHistory > & GetOrCreateHistory()
Get history data, creating it if necessary.
Definition industry.h:96
std::unique_ptr< HistoryData< AcceptedHistory > > history
History of accepted and waiting cargo.
Definition industry.h:90
CargoType cargo
Cargo type.
Definition industry.h:74
HistoryData< ProducedHistory > history
History of cargo produced and transported for this month and 24 previous months.
Definition industry.h:77
Defines the internal data of a functional industry.
Definition industry.h:62
IndustryType type
type of industry.
Definition industry.h:115
PersistentStorage * psa
Persistent storage for NewGRF industries.
Definition industry.h:136
ValidHistoryMask valid_history
Mask of valid history records.
Definition industry.h:109
ProducedCargoes produced
produced cargo slots
Definition industry.h:110
AcceptedCargoes accepted
accepted cargo slots
Definition industry.h:111
static std::array< FlatSet< IndustryID >, NUM_INDUSTRYTYPES > industries
List of industries of each type.
Definition industry.h:277
StorageType storage
Memory for the storage array.
static Pool::IterateWrapper< Industry > Iterate(size_t from=0)
static T * CreateAtIndex(IndustryID index, Targs &&... args)
SaveLoad type struct.
Definition saveload.h:756
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > > TileIndex
The index/ID of a Tile.
Definition tile_type.h:92