OpenTTD Source 20241224-master-gf74b0cf984
station_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 <http://www.gnu.org/licenses/>.
6 */
7
10#include "../stdafx.h"
11
12#include "saveload.h"
14
15#include "../station_base.h"
16#include "../waypoint_base.h"
17#include "../roadstop_base.h"
18#include "../vehicle_base.h"
19#include "../newgrf_station.h"
20#include "../newgrf_roadstop.h"
21#include "../timer/timer_game_calendar.h"
22
23#include "table/strings.h"
24
25#include "../safeguards.h"
26
32{
33 if (!o->IsType(OT_GOTO_STATION)) return;
34
35 const Station *st = Station::Get(o->GetDestination());
36 if ((st->had_vehicle_of_type & HVOT_WAYPOINT) == 0) return;
37
39}
40
46{
47 /* Buoy orders become waypoint orders */
48 for (OrderList *ol : OrderList::Iterate()) {
49 VehicleType vt = ol->GetFirstSharedVehicle()->type;
50 if (vt != VEH_SHIP && vt != VEH_TRAIN) continue;
51
52 for (Order *o = ol->GetFirstOrder(); o != nullptr; o = o->next) UpdateWaypointOrder(o);
53 }
54
55 for (Vehicle *v : Vehicle::Iterate()) {
56 VehicleType vt = v->type;
57 if (vt != VEH_SHIP && vt != VEH_TRAIN) continue;
58
59 UpdateWaypointOrder(&v->current_order);
60 }
61
62 /* Now make the stations waypoints */
63 for (Station *st : Station::Iterate()) {
64 if ((st->had_vehicle_of_type & HVOT_WAYPOINT) == 0) continue;
65
66 StationID index = st->index;
67 TileIndex xy = st->xy;
68 Town *town = st->town;
69 StringID string_id = st->string_id;
70 std::string name = st->name;
71 TimerGameCalendar::Date build_date = st->build_date;
72 /* TTDPatch could use "buoys with rail station" for rail waypoints */
73 bool train = st->train_station.tile != INVALID_TILE;
74 TileArea train_st = st->train_station;
75
76 /* Delete the station, so we can make it a real waypoint. */
77 delete st;
78
79 /* Stations and waypoints are in the same pool, so if a station
80 * is deleted there must be place for a Waypoint. */
82 Waypoint *wp = new (index) Waypoint(xy);
83 wp->town = town;
84 wp->string_id = train ? STR_SV_STNAME_WAYPOINT : STR_SV_STNAME_BUOY;
85 wp->name = name;
86 wp->delete_ctr = 0; // Just reset delete counter for once.
87 wp->build_date = build_date;
88 wp->owner = train ? GetTileOwner(xy) : OWNER_NONE;
89
90 if (IsInsideBS(string_id, STR_SV_STNAME_BUOY, 9)) wp->town_cn = string_id - STR_SV_STNAME_BUOY;
91
92 if (train) {
93 /* When we make a rail waypoint of the station, convert the map as well. */
94 for (TileIndex t : train_st) {
95 Tile tile(t);
96 if (!IsTileType(tile, MP_STATION) || GetStationIndex(tile) != index) continue;
97
98 SB(tile.m6(), 3, 3, STATION_WAYPOINT);
99 wp->rect.BeforeAddTile(t, StationRect::ADD_FORCE);
100 }
101
102 wp->train_station = train_st;
103 wp->facilities |= FACIL_TRAIN;
104 } else if (IsBuoyTile(xy) && GetStationIndex(xy) == index) {
105 wp->rect.BeforeAddTile(xy, StationRect::ADD_FORCE);
106 wp->facilities |= FACIL_DOCK;
107 }
108 }
109}
110
111void AfterLoadStations()
112{
113 /* Update the speclists of all stations to point to the currently loaded custom stations. */
114 for (BaseStation *st : BaseStation::Iterate()) {
115 for (auto &sm : GetStationSpecList<StationSpec>(st)) {
116 if (sm.grfid == 0) continue;
117 sm.spec = StationClass::GetByGrf(sm.grfid, sm.localidx);
118 }
119 for (auto &sm : GetStationSpecList<RoadStopSpec>(st)) {
120 if (sm.grfid == 0) continue;
121 sm.spec = RoadStopClass::GetByGrf(sm.grfid, sm.localidx);
122 }
123
124 if (Station::IsExpected(st)) {
125 Station *sta = Station::From(st);
126 for (const RoadStop *rs = sta->bus_stops; rs != nullptr; rs = rs->next) sta->bus_station.Add(rs->xy);
127 for (const RoadStop *rs = sta->truck_stops; rs != nullptr; rs = rs->next) sta->truck_station.Add(rs->xy);
128 }
129
131 RoadStopUpdateCachedTriggers(st);
132 }
133}
134
139{
140 /* First construct the drive through entries */
141 for (RoadStop *rs : RoadStop::Iterate()) {
142 if (IsDriveThroughStopTile(rs->xy)) rs->MakeDriveThrough();
143 }
144 /* And then rebuild the data in those entries */
145 for (RoadStop *rs : RoadStop::Iterate()) {
146 if (!HasBit(rs->status, RoadStop::RSSFB_BASE_ENTRY)) continue;
147
148 rs->GetEntry(DIAGDIR_NE)->Rebuild(rs);
149 rs->GetEntry(DIAGDIR_NW)->Rebuild(rs);
150 }
151}
152
153static const SaveLoad _roadstop_desc[] = {
154 SLE_VAR(RoadStop, xy, SLE_UINT32),
155 SLE_VAR(RoadStop, status, SLE_UINT8),
157};
158
159static uint16_t _waiting_acceptance;
160static uint32_t _old_num_flows;
161static uint16_t _cargo_source;
162static uint32_t _cargo_source_xy;
163static uint8_t _cargo_periods;
164static Money _cargo_feeder_share;
165
166std::list<CargoPacket *> _packets;
167uint32_t _old_num_dests;
168
170 FlowSaveLoad() : source(0), via(0), share(0), restricted(false) {}
171 StationID source;
172 StationID via;
173 uint32_t share;
174 bool restricted;
175};
176
177typedef std::pair<const StationID, std::list<CargoPacket *> > StationCargoPair;
178
179static OldPersistentStorage _old_st_persistent_storage;
180
186static void SwapPackets(GoodsEntry *ge)
187{
188 StationCargoPacketMap &ge_packets = const_cast<StationCargoPacketMap &>(*ge->cargo.Packets());
189
190 if (_packets.empty()) {
191 std::map<StationID, std::list<CargoPacket *> >::iterator it(ge_packets.find(INVALID_STATION));
192 if (it == ge_packets.end()) {
193 return;
194 } else {
195 it->second.swap(_packets);
196 }
197 } else {
198 assert(ge_packets[INVALID_STATION].empty());
199 ge_packets[INVALID_STATION].swap(_packets);
200 }
201}
202
203template <typename T>
204class SlStationSpecList : public VectorSaveLoadHandler<SlStationSpecList<T>, BaseStation, SpecMapping<T>> {
205public:
206 inline static const SaveLoad description[] = {
207 SLE_CONDVAR(SpecMapping<T>, grfid, SLE_UINT32, SLV_27, SL_MAX_VERSION),
208 SLE_CONDVAR(SpecMapping<T>, localidx, SLE_FILE_U8 | SLE_VAR_U16, SLV_27, SLV_EXTEND_ENTITY_MAPPING),
210 };
211 inline const static SaveLoadCompatTable compat_description = _station_spec_list_sl_compat;
212
213 static inline uint8_t last_num_specs;
214
215 std::vector<SpecMapping<T>> &GetVector(BaseStation *bst) const override { return GetStationSpecList<T>(bst); }
216
217 size_t GetLength() const override
218 {
220 }
221};
222
223/* Instantiate SlStationSpecList classes. */
224template class SlStationSpecList<StationSpec>;
226
228public:
229 inline static const SaveLoad description[] = {
230 SLE_VAR(StationCargoPair, first, SLE_UINT16),
231 SLE_REFLIST(StationCargoPair, second, REF_CARGO_PACKET),
232 };
233 inline const static SaveLoadCompatTable compat_description = _station_cargo_sl_compat;
234
235 void Save(GoodsEntry *ge) const override
236 {
238 for (StationCargoPacketMap::ConstMapIterator it(ge->cargo.Packets()->begin()); it != ge->cargo.Packets()->end(); ++it) {
239 SlObject(const_cast<StationCargoPacketMap::value_type *>(&(*it)), this->GetDescription());
240 }
241 }
242
243 void Load(GoodsEntry *ge) const override
244 {
245 size_t num_dests = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? _old_num_dests : SlGetStructListLength(UINT32_MAX);
246
247 StationCargoPair pair;
248 for (uint j = 0; j < num_dests; ++j) {
249 SlObject(&pair, this->GetLoadDescription());
250 const_cast<StationCargoPacketMap &>(*(ge->cargo.Packets()))[pair.first].swap(pair.second);
251 assert(pair.second.empty());
252 }
253 }
254
255 void FixPointers(GoodsEntry *ge) const override
256 {
257 for (StationCargoPacketMap::ConstMapIterator it = ge->cargo.Packets()->begin(); it != ge->cargo.Packets()->end(); ++it) {
258 SlObject(const_cast<StationCargoPair *>(&(*it)), this->GetDescription());
259 }
260 }
261};
262
264public:
265 inline static const SaveLoad description[] = {
266 SLE_VAR(FlowSaveLoad, source, SLE_UINT16),
267 SLE_VAR(FlowSaveLoad, via, SLE_UINT16),
268 SLE_VAR(FlowSaveLoad, share, SLE_UINT32),
269 SLE_CONDVAR(FlowSaveLoad, restricted, SLE_BOOL, SLV_187, SL_MAX_VERSION),
270 };
271 inline const static SaveLoadCompatTable compat_description = _station_flow_sl_compat;
272
273 void Save(GoodsEntry *ge) const override
274 {
275 size_t num_flows = 0;
276 for (const auto &it : ge->flows) {
277 num_flows += it.second.GetShares()->size();
278 }
279 SlSetStructListLength(num_flows);
280
281 for (const auto &outer_it : ge->flows) {
282 const FlowStat::SharesMap *shares = outer_it.second.GetShares();
283 uint32_t sum_shares = 0;
284 FlowSaveLoad flow;
285 flow.source = outer_it.first;
286 for (auto &inner_it : *shares) {
287 flow.via = inner_it.second;
288 flow.share = inner_it.first - sum_shares;
289 flow.restricted = inner_it.first > outer_it.second.GetUnrestricted();
290 sum_shares = inner_it.first;
291 assert(flow.share > 0);
292 SlObject(&flow, this->GetDescription());
293 }
294 }
295 }
296
297 void Load(GoodsEntry *ge) const override
298 {
299 size_t num_flows = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? _old_num_flows : SlGetStructListLength(UINT32_MAX);
300
301 FlowSaveLoad flow;
302 FlowStat *fs = nullptr;
303 StationID prev_source = INVALID_STATION;
304 for (uint32_t j = 0; j < num_flows; ++j) {
305 SlObject(&flow, this->GetLoadDescription());
306 if (fs == nullptr || prev_source != flow.source) {
307 fs = &(ge->flows.emplace(flow.source, FlowStat(flow.via, flow.share, flow.restricted))).first->second;
308 } else {
309 fs->AppendShare(flow.via, flow.share, flow.restricted);
310 }
311 prev_source = flow.source;
312 }
313 }
314};
315
316class SlStationGoods : public DefaultSaveLoadHandler<SlStationGoods, BaseStation> {
317public:
318 inline static const SaveLoad description[] = {
319 SLEG_CONDVAR("waiting_acceptance", _waiting_acceptance, SLE_UINT16, SL_MIN_VERSION, SLV_68),
320 SLE_CONDVAR(GoodsEntry, status, SLE_UINT8, SLV_68, SL_MAX_VERSION),
321 SLE_VAR(GoodsEntry, time_since_pickup, SLE_UINT8),
322 SLE_VAR(GoodsEntry, rating, SLE_UINT8),
323 SLEG_CONDVAR("cargo_source", _cargo_source, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_7),
324 SLEG_CONDVAR("cargo_source", _cargo_source, SLE_UINT16, SLV_7, SLV_68),
325 SLEG_CONDVAR("cargo_source_xy", _cargo_source_xy, SLE_UINT32, SLV_44, SLV_68),
326 SLEG_CONDVAR("cargo_days", _cargo_periods, SLE_UINT8, SL_MIN_VERSION, SLV_68),
327 SLE_VAR(GoodsEntry, last_speed, SLE_UINT8),
328 SLE_VAR(GoodsEntry, last_age, SLE_UINT8),
329 SLEG_CONDVAR("cargo_feeder_share", _cargo_feeder_share, SLE_FILE_U32 | SLE_VAR_I64, SLV_14, SLV_65),
330 SLEG_CONDVAR("cargo_feeder_share", _cargo_feeder_share, SLE_INT64, SLV_65, SLV_68),
331 SLE_CONDVAR(GoodsEntry, amount_fract, SLE_UINT8, SLV_150, SL_MAX_VERSION),
332 SLEG_CONDREFLIST("packets", _packets, REF_CARGO_PACKET, SLV_68, SLV_183),
333 SLEG_CONDVAR("old_num_dests", _old_num_dests, SLE_UINT32, SLV_183, SLV_SAVELOAD_LIST_LENGTH),
334 SLE_CONDVAR(GoodsEntry, cargo.reserved_count, SLE_UINT, SLV_181, SL_MAX_VERSION),
335 SLE_CONDVAR(GoodsEntry, link_graph, SLE_UINT16, SLV_183, SL_MAX_VERSION),
336 SLE_CONDVAR(GoodsEntry, node, SLE_UINT16, SLV_183, SL_MAX_VERSION),
337 SLEG_CONDVAR("old_num_flows", _old_num_flows, SLE_UINT32, SLV_183, SLV_SAVELOAD_LIST_LENGTH),
338 SLE_CONDVAR(GoodsEntry, max_waiting_cargo, SLE_UINT32, SLV_183, SL_MAX_VERSION),
341 };
342
343 inline const static SaveLoadCompatTable compat_description = _station_goods_sl_compat;
344
349 size_t GetNumCargo() const
350 {
351 if (IsSavegameVersionBefore(SLV_55)) return 12;
354 /* Read from the savegame how long the list is. */
356 }
357
358 void Save(BaseStation *bst) const override
359 {
360 Station *st = Station::From(bst);
361
363
364 for (GoodsEntry &ge : st->goods) {
365 SlObject(&ge, this->GetDescription());
366 }
367 }
368
369 void Load(BaseStation *bst) const override
370 {
371 Station *st = Station::From(bst);
372
373 /* Before savegame version 161, persistent storages were not stored in a pool. */
375 /* Store the old persistent storage. The GRFID will be added later. */
377 st->airport.psa = new PersistentStorage(0, 0, 0);
378 std::copy(std::begin(_old_st_persistent_storage.storage), std::end(_old_st_persistent_storage.storage), std::begin(st->airport.psa->storage));
379 }
380
381 auto end = std::next(std::begin(st->goods), std::min(this->GetNumCargo(), std::size(st->goods)));
382 for (auto it = std::begin(st->goods); it != end; ++it) {
383 GoodsEntry &ge = *it;
384 SlObject(&ge, this->GetLoadDescription());
386 SwapPackets(&ge);
387 }
389 AssignBit(ge.status, GoodsEntry::GES_ACCEPTANCE, HasBit(_waiting_acceptance, 15));
390 if (GB(_waiting_acceptance, 0, 12) != 0) {
391 /* In old versions, enroute_from used 0xFF as INVALID_STATION */
392 StationID source = (IsSavegameVersionBefore(SLV_7) && _cargo_source == 0xFF) ? INVALID_STATION : _cargo_source;
393
394 /* Make sure we can allocate the CargoPacket. This is safe
395 * as there can only be ~64k stations and 32 cargoes in these
396 * savegame versions. As the CargoPacketPool has more than
397 * 16 million entries; it fits by an order of magnitude. */
399
400 /* Don't construct the packet with station here, because that'll fail with old savegames */
401 CargoPacket *cp = new CargoPacket(GB(_waiting_acceptance, 0, 12), _cargo_periods, source, _cargo_source_xy, _cargo_feeder_share);
402 ge.cargo.Append(cp, INVALID_STATION);
404 }
405 }
406 }
407 }
408
409 void FixPointers(BaseStation *bst) const override
410 {
411 Station *st = Station::From(bst);
412
414 auto end = std::next(std::begin(st->goods), std::min(num_cargo, std::size(st->goods)));
415 for (auto it = std::begin(st->goods); it != end; ++it) {
416 GoodsEntry &ge = *it;
418 SwapPackets(&ge); // We have to swap back again to be in the format pre-183 expects.
419 SlObject(&ge, this->GetDescription());
420 SwapPackets(&ge);
421 } else {
422 SlObject(&ge, this->GetDescription());
423 }
424 }
425 }
426};
427
428static const SaveLoad _old_station_desc[] = {
429 SLE_CONDVAR(Station, xy, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6),
430 SLE_CONDVAR(Station, xy, SLE_UINT32, SLV_6, SL_MAX_VERSION),
431 SLE_CONDVAR(Station, train_station.tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6),
432 SLE_CONDVAR(Station, train_station.tile, SLE_UINT32, SLV_6, SL_MAX_VERSION),
433 SLE_CONDVAR(Station, airport.tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6),
434 SLE_CONDVAR(Station, airport.tile, SLE_UINT32, SLV_6, SL_MAX_VERSION),
435 SLE_REF(Station, town, REF_TOWN),
436 SLE_VAR(Station, train_station.w, SLE_FILE_U8 | SLE_VAR_U16),
437 SLE_CONDVAR(Station, train_station.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_2, SL_MAX_VERSION),
438
439 SLE_VAR(Station, string_id, SLE_STRINGID),
441 SLE_CONDVAR(Station, indtype, SLE_UINT8, SLV_103, SL_MAX_VERSION),
442 SLE_CONDVAR(Station, had_vehicle_of_type, SLE_FILE_U16 | SLE_VAR_U8, SL_MIN_VERSION, SLV_122),
443 SLE_CONDVAR(Station, had_vehicle_of_type, SLE_UINT8, SLV_122, SL_MAX_VERSION),
444
445 SLE_VAR(Station, time_since_load, SLE_UINT8),
446 SLE_VAR(Station, time_since_unload, SLE_UINT8),
447 SLE_VAR(Station, delete_ctr, SLE_UINT8),
448 SLE_VAR(Station, owner, SLE_UINT8),
449 SLE_VAR(Station, facilities, SLE_UINT8),
450 SLE_VAR(Station, airport.type, SLE_UINT8),
451 SLE_CONDVAR(Station, airport.flags, SLE_VAR_U64 | SLE_FILE_U16, SL_MIN_VERSION, SLV_3),
452 SLE_CONDVAR(Station, airport.flags, SLE_VAR_U64 | SLE_FILE_U32, SLV_3, SLV_46),
453 SLE_CONDVAR(Station, airport.flags, SLE_UINT64, SLV_46, SL_MAX_VERSION),
454
455 SLE_CONDVAR(Station, last_vehicle_type, SLE_UINT8, SLV_26, SL_MAX_VERSION),
456
457 SLE_CONDVAR(Station, build_date, SLE_FILE_U16 | SLE_VAR_I32, SLV_3, SLV_31),
458 SLE_CONDVAR(Station, build_date, SLE_INT32, SLV_31, SL_MAX_VERSION),
459
462
463 /* Used by newstations for graphic variations */
464 SLE_CONDVAR(Station, random_bits, SLE_UINT16, SLV_27, SL_MAX_VERSION),
465 SLE_CONDVAR(Station, waiting_triggers, SLE_UINT8, SLV_27, SL_MAX_VERSION),
467
469
472};
473
476
477 void Load() const override
478 {
479 const std::vector<SaveLoad> slt = SlCompatTableHeader(_old_station_desc, _old_station_sl_compat);
480
481 _cargo_source_xy = 0;
482 _cargo_periods = 0;
483 _cargo_feeder_share = 0;
484
485 int index;
486 while ((index = SlIterateArray()) != -1) {
487 Station *st = new (index) Station();
488
489 _waiting_acceptance = 0;
490 SlObject(st, slt);
491 }
492 }
493
494 void FixPointers() const override
495 {
496 /* From SLV_123 we store stations in STNN; before that in STNS. So do not
497 * fix pointers when the version is SLV_123 or up, as that would fix
498 * pointers twice: once in STNN chunk and once here. */
499 if (!IsSavegameVersionBefore(SLV_123)) return;
500
501 for (Station *st : Station::Iterate()) {
502 SlObject(st, _old_station_desc);
503 }
504 }
505};
506
507class SlRoadStopTileData : public VectorSaveLoadHandler<SlRoadStopTileData, BaseStation, RoadStopTileData> {
508public:
509 inline static const SaveLoad description[] = {
510 SLE_VAR(RoadStopTileData, tile, SLE_UINT32),
511 SLE_VAR(RoadStopTileData, random_bits, SLE_UINT8),
512 SLE_VAR(RoadStopTileData, animation_frame, SLE_UINT8),
513 };
514 inline const static SaveLoadCompatTable compat_description = {};
515
516 std::vector<RoadStopTileData> &GetVector(BaseStation *bst) const override { return bst->custom_roadstop_tile_data; }
517};
518
523class SlStationBase : public DefaultSaveLoadHandler<SlStationBase, BaseStation> {
524public:
525 inline static const SaveLoad description[] = {
526 SLE_VAR(BaseStation, xy, SLE_UINT32),
528 SLE_VAR(BaseStation, string_id, SLE_STRINGID),
529 SLE_SSTR(BaseStation, name, SLE_STR | SLF_ALLOW_CONTROL),
530 SLE_VAR(BaseStation, delete_ctr, SLE_UINT8),
531 SLE_VAR(BaseStation, owner, SLE_UINT8),
532 SLE_VAR(BaseStation, facilities, SLE_UINT8),
533 SLE_VAR(BaseStation, build_date, SLE_INT32),
534
535 /* Used by newstations for graphic variations */
536 SLE_VAR(BaseStation, random_bits, SLE_UINT16),
537 SLE_VAR(BaseStation, waiting_triggers, SLE_UINT8),
539 };
540 inline const static SaveLoadCompatTable compat_description = _station_base_sl_compat;
541
542 void Save(BaseStation *bst) const override
543 {
544 SlObject(bst, this->GetDescription());
545 }
546
547 void Load(BaseStation *bst) const override
548 {
549 SlObject(bst, this->GetLoadDescription());
550 }
551
552 void FixPointers(BaseStation *bst) const override
553 {
554 SlObject(bst, this->GetDescription());
555 }
556};
557
561class SlStationNormal : public DefaultSaveLoadHandler<SlStationNormal, BaseStation> {
562public:
563 inline static const SaveLoad description[] = {
564 SLEG_STRUCT("base", SlStationBase),
565 SLE_VAR(Station, train_station.tile, SLE_UINT32),
566 SLE_VAR(Station, train_station.w, SLE_FILE_U8 | SLE_VAR_U16),
567 SLE_VAR(Station, train_station.h, SLE_FILE_U8 | SLE_VAR_U16),
568
569 SLE_REF(Station, bus_stops, REF_ROADSTOPS),
570 SLE_REF(Station, truck_stops, REF_ROADSTOPS),
571 SLE_CONDVAR(Station, ship_station.tile, SLE_UINT32, SLV_MULTITILE_DOCKS, SL_MAX_VERSION),
572 SLE_CONDVAR(Station, ship_station.w, SLE_FILE_U8 | SLE_VAR_U16, SLV_MULTITILE_DOCKS, SL_MAX_VERSION),
573 SLE_CONDVAR(Station, ship_station.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_MULTITILE_DOCKS, SL_MAX_VERSION),
574 SLE_CONDVAR(Station, docking_station.tile, SLE_UINT32, SLV_MULTITILE_DOCKS, SL_MAX_VERSION),
575 SLE_CONDVAR(Station, docking_station.w, SLE_FILE_U8 | SLE_VAR_U16, SLV_MULTITILE_DOCKS, SL_MAX_VERSION),
576 SLE_CONDVAR(Station, docking_station.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_MULTITILE_DOCKS, SL_MAX_VERSION),
577 SLE_VAR(Station, airport.tile, SLE_UINT32),
578 SLE_CONDVAR(Station, airport.w, SLE_FILE_U8 | SLE_VAR_U16, SLV_140, SL_MAX_VERSION),
579 SLE_CONDVAR(Station, airport.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_140, SL_MAX_VERSION),
580 SLE_VAR(Station, airport.type, SLE_UINT8),
581 SLE_CONDVAR(Station, airport.layout, SLE_UINT8, SLV_145, SL_MAX_VERSION),
582 SLE_VAR(Station, airport.flags, SLE_UINT64),
583 SLE_CONDVAR(Station, airport.rotation, SLE_UINT8, SLV_145, SL_MAX_VERSION),
584 SLEG_CONDARR("storage", _old_st_persistent_storage.storage, SLE_UINT32, 16, SLV_145, SLV_161),
586
587 SLE_VAR(Station, indtype, SLE_UINT8),
588
589 SLE_VAR(Station, time_since_load, SLE_UINT8),
590 SLE_VAR(Station, time_since_unload, SLE_UINT8),
591 SLE_VAR(Station, last_vehicle_type, SLE_UINT8),
592 SLE_VAR(Station, had_vehicle_of_type, SLE_UINT8),
593 SLE_REFLIST(Station, loading_vehicles, REF_VEHICLE),
594 SLE_CONDVAR(Station, always_accepted, SLE_FILE_U32 | SLE_VAR_U64, SLV_127, SLV_EXTEND_CARGOTYPES),
595 SLE_CONDVAR(Station, always_accepted, SLE_UINT64, SLV_EXTEND_CARGOTYPES, SL_MAX_VERSION),
598 };
599 inline const static SaveLoadCompatTable compat_description = _station_normal_sl_compat;
600
601 void Save(BaseStation *bst) const override
602 {
603 if ((bst->facilities & FACIL_WAYPOINT) != 0) return;
604 SlObject(bst, this->GetDescription());
605 }
606
607 void Load(BaseStation *bst) const override
608 {
609 if ((bst->facilities & FACIL_WAYPOINT) != 0) return;
610 SlObject(bst, this->GetLoadDescription());
611 }
612
613 void FixPointers(BaseStation *bst) const override
614 {
615 if ((bst->facilities & FACIL_WAYPOINT) != 0) return;
616 SlObject(bst, this->GetDescription());
617 }
618};
619
620class SlStationWaypoint : public DefaultSaveLoadHandler<SlStationWaypoint, BaseStation> {
621public:
622 inline static const SaveLoad description[] = {
623 SLEG_STRUCT("base", SlStationBase),
624 SLE_VAR(Waypoint, town_cn, SLE_UINT16),
625
626 SLE_CONDVAR(Waypoint, train_station.tile, SLE_UINT32, SLV_124, SL_MAX_VERSION),
627 SLE_CONDVAR(Waypoint, train_station.w, SLE_FILE_U8 | SLE_VAR_U16, SLV_124, SL_MAX_VERSION),
628 SLE_CONDVAR(Waypoint, train_station.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_124, SL_MAX_VERSION),
629 SLE_CONDVAR(Waypoint, waypoint_flags, SLE_UINT16, SLV_ROAD_WAYPOINTS, SL_MAX_VERSION),
630 SLE_CONDVAR(Waypoint, road_waypoint_area.tile, SLE_UINT32, SLV_ROAD_WAYPOINTS, SL_MAX_VERSION),
631 SLE_CONDVAR(Waypoint, road_waypoint_area.w, SLE_FILE_U8 | SLE_VAR_U16, SLV_ROAD_WAYPOINTS, SL_MAX_VERSION),
632 SLE_CONDVAR(Waypoint, road_waypoint_area.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_ROAD_WAYPOINTS, SL_MAX_VERSION),
633 };
634 inline const static SaveLoadCompatTable compat_description = _station_waypoint_sl_compat;
635
636 void Save(BaseStation *bst) const override
637 {
638 if ((bst->facilities & FACIL_WAYPOINT) == 0) return;
639 SlObject(bst, this->GetDescription());
640 }
641
642 void Load(BaseStation *bst) const override
643 {
644 if ((bst->facilities & FACIL_WAYPOINT) == 0) return;
645 SlObject(bst, this->GetLoadDescription());
646 }
647
648 void FixPointers(BaseStation *bst) const override
649 {
650 if ((bst->facilities & FACIL_WAYPOINT) == 0) return;
651 SlObject(bst, this->GetDescription());
652 }
653};
654
655static const SaveLoad _station_desc[] = {
656 SLE_SAVEBYTE(BaseStation, facilities),
657 SLEG_STRUCT("normal", SlStationNormal),
658 SLEG_STRUCT("waypoint", SlStationWaypoint),
662};
663
665 STNNChunkHandler() : ChunkHandler('STNN', CH_TABLE) {}
666
667 void Save() const override
668 {
669 SlTableHeader(_station_desc);
670
671 /* Write the stations */
672 for (BaseStation *st : BaseStation::Iterate()) {
673 SlSetArrayIndex(st->index);
674 SlObject(st, _station_desc);
675 }
676 }
677
678
679 void Load() const override
680 {
681 const std::vector<SaveLoad> slt = SlCompatTableHeader(_station_desc, _station_sl_compat);
682
683 _old_num_flows = 0;
684
685 int index;
686 while ((index = SlIterateArray()) != -1) {
687 bool waypoint = (SlReadByte() & FACIL_WAYPOINT) != 0;
688
689 BaseStation *bst = waypoint ? (BaseStation *)new (index) Waypoint() : new (index) Station();
690 SlObject(bst, slt);
691 }
692 }
693
694 void FixPointers() const override
695 {
696 /* From SLV_123 we store stations in STNN; before that in STNS. So do not
697 * fix pointers when the version is below SLV_123, as that would fix
698 * pointers twice: once in STNS chunk and once here. */
699 if (IsSavegameVersionBefore(SLV_123)) return;
700
701 for (BaseStation *bst : BaseStation::Iterate()) {
702 SlObject(bst, _station_desc);
703 }
704 }
705};
706
708 ROADChunkHandler() : ChunkHandler('ROAD', CH_TABLE) {}
709
710 void Save() const override
711 {
712 SlTableHeader(_roadstop_desc);
713
714 for (RoadStop *rs : RoadStop::Iterate()) {
715 SlSetArrayIndex(rs->index);
716 SlObject(rs, _roadstop_desc);
717 }
718 }
719
720 void Load() const override
721 {
722 const std::vector<SaveLoad> slt = SlCompatTableHeader(_roadstop_desc, _roadstop_sl_compat);
723
724 int index;
725
726 while ((index = SlIterateArray()) != -1) {
727 RoadStop *rs = new (index) RoadStop(INVALID_TILE);
728
729 SlObject(rs, slt);
730 }
731 }
732
733 void FixPointers() const override
734 {
735 for (RoadStop *rs : RoadStop::Iterate()) {
736 SlObject(rs, _roadstop_desc);
737 }
738 }
739};
740
741static const STNSChunkHandler STNS;
742static const STNNChunkHandler STNN;
743static const ROADChunkHandler ROAD;
744static const ChunkHandlerRef station_chunk_handlers[] = {
745 STNS,
746 STNN,
747 ROAD,
748};
749
750extern const ChunkHandlerTable _station_chunk_handlers(station_chunk_handlers);
std::vector< SpecMapping< T > > & GetStationSpecList(BaseStation *bst)
Get spec mapping list for each supported custom spec type.
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T AssignBit(T &x, const uint8_t y, bool value)
Assigns a bit in a variable.
constexpr T SB(T &x, const uint8_t s, const uint8_t n, const U d)
Set n bits in x starting at bit s to d.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
debug_inline static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
static const CargoID NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:74
const Tcont * Packets() const
Returns a pointer to the cargo packet list (so you can iterate over it etc).
Default handler for saving/loading an object to/from disk.
Definition saveload.h:581
SaveLoadTable GetDescription() const override
Definition saveload.h:583
Flow statistics telling how much flow should be sent along a link.
void AppendShare(StationID st, uint flow, bool restricted=false)
Add some flow to the end of the shares map.
Hand-rolled multimap as map of lists.
Definition multimap.hpp:281
size_t MapSize() const
Count the number of ranges with equal keys in this MultiMap.
Definition multimap.hpp:347
static const Tspec * GetByGrf(uint32_t grfid, uint16_t local_id)
Retrieve a spec by GRF location.
SaveLoadTable GetLoadDescription() const
Get the description for how to load the chunk.
std::vector< RoadStopTileData > & GetVector(BaseStation *bst) const override
Get instance of vector to load/save.
SaveLoad handler for the BaseStation, which all other stations / waypoints make use of.
size_t GetNumCargo() const
Get the number of cargoes used by this savegame version.
SaveLoad handler for a normal station (read: not a waypoint).
size_t GetLength() const override
Get number of elements to load into vector.
static uint8_t last_num_specs
Number of specs of the last loaded station.
std::vector< SpecMapping< T > > & GetVector(BaseStation *bst) const override
Get instance of vector to load/save.
void Append(CargoPacket *cp, StationID next)
Appends the given cargo packet to the range of packets with the same next station.
Wrapper class to abstract away the way the tiles are stored.
Definition map_func.h:25
debug_inline uint8_t & m6()
General purpose.
Definition map_func.h:173
Default handler for saving/loading a vector to/from disk.
Definition saveload.h:1365
@ OWNER_NONE
The tile has no ownership.
@ DIAGDIR_NE
Northeast, upper right on your monitor.
@ DIAGDIR_NW
Northwest.
constexpr bool IsInsideBS(const T x, const size_t base, const size_t size)
Checks if a value is between a window started at some base point.
void StationUpdateCachedTriggers(BaseStation *st)
Update the cached animation trigger bitmask for a station.
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:659
uint8_t SlReadByte()
Wrapper for reading a byte from the buffer.
Definition saveload.cpp:392
void SlObject(void *object, const SaveLoadTable &slt)
Main SaveLoad function.
std::vector< SaveLoad > SlTableHeader(const SaveLoadTable &slt)
Save or Load a table header.
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:1130
#define SLEG_STRUCTLIST(name, handler)
Storage of a list of structs in every savegame version.
Definition saveload.h:1241
@ SLF_ALLOW_CONTROL
Allow control codes in the strings.
Definition saveload.h:688
#define SLEG_CONDVAR(name, variable, type, from, to)
Storage of a global variable in some savegame versions.
Definition saveload.h:1109
@ CH_READONLY
Chunk is never saved.
Definition saveload.h:459
std::reference_wrapper< const ChunkHandler > ChunkHandlerRef
A reference to ChunkHandler.
Definition saveload.h:509
#define SLEG_CONDREFLIST(name, variable, type, from, to)
Storage of a global reference list in some savegame versions.
Definition saveload.h:1159
std::span< const ChunkHandlerRef > ChunkHandlerTable
A table of ChunkHandler entries.
Definition saveload.h:512
#define SLE_SAVEBYTE(base, variable)
Only write byte during saving; never read it during loading.
Definition saveload.h:1083
#define SLE_REF(base, variable, type)
Storage of a reference in every version of a savegame.
Definition saveload.h:1019
#define SLE_CONDREFLIST(base, variable, type, from, to)
Storage of a list of SL_REF elements in some savegame versions.
Definition saveload.h:954
#define SLE_REFLIST(base, variable, type)
Storage of a list of SL_REF elements in every savegame version.
Definition saveload.h:1063
std::span< const struct SaveLoadCompat > SaveLoadCompatTable
A table of SaveLoadCompat entries.
Definition saveload.h:518
#define SLEG_STRUCT(name, handler)
Storage of a structs in every savegame version.
Definition saveload.h:1218
#define SLE_CONDSSTR(base, variable, type, from, to)
Storage of a std::string in some savegame versions.
Definition saveload.h:933
#define SLE_CONDVAR(base, variable, type, from, to)
Storage of a variable in some savegame versions.
Definition saveload.h:868
bool IsSavegameVersionBefore(SaveLoadVersion major, uint8_t minor=0)
Checks whether the savegame is below major.
Definition saveload.h:1263
#define SLE_SSTR(base, variable, type)
Storage of a std::string in every savegame version.
Definition saveload.h:1046
@ SLV_150
150 20857
Definition saveload.h:223
@ SLV_84
84 11822
Definition saveload.h:143
@ SLV_26
26 4466
Definition saveload.h:74
@ SLV_ROAD_WAYPOINTS
338 PR#12572 Road waypoints
Definition saveload.h:385
@ SLV_103
103 14598
Definition saveload.h:166
@ SLV_44
44 8144
Definition saveload.h:95
@ SLV_6
6.0 1721 6.1 1768
Definition saveload.h:46
@ SLV_181
181 25012
Definition saveload.h:260
@ SLV_EXTEND_CARGOTYPES
199 PR#6802 Extend cargotypes to 64
Definition saveload.h:282
@ SLV_SAVELOAD_LIST_LENGTH
293 PR#9374 Consistency in list length with SL_STRUCT / SL_STRUCTLIST / SL_DEQUE / SL_REFLIST.
Definition saveload.h:331
@ SLV_65
65 10210
Definition saveload.h:121
@ SLV_123
123 16909
Definition saveload.h:190
@ SLV_46
46 8705
Definition saveload.h:98
@ SLV_122
122 16855
Definition saveload.h:189
@ SLV_140
140 19382
Definition saveload.h:211
@ SLV_MULTITILE_DOCKS
216 PR#7380 Multiple docks per station.
Definition saveload.h:303
@ SL_MAX_VERSION
Highest possible saveload version.
Definition saveload.h:399
@ SL_MIN_VERSION
First savegame version.
Definition saveload.h:31
@ SLV_3
3.x lost
Definition saveload.h:36
@ SLV_145
145 20376
Definition saveload.h:217
@ SLV_57
57 9691
Definition saveload.h:111
@ SLV_68
68 10266
Definition saveload.h:124
@ SLV_NEWGRF_ROAD_STOPS
303 PR#10144 NewGRF road stops.
Definition saveload.h:343
@ SLV_2
2.0 0.3.0 2.1 0.3.1, 0.3.2
Definition saveload.h:34
@ SLV_187
187 25899 Linkgraph - restricted flows
Definition saveload.h:267
@ SLV_27
27 4757
Definition saveload.h:75
@ SLV_127
127 17439
Definition saveload.h:195
@ SLV_14
14.0 2441
Definition saveload.h:57
@ SLV_55
55 9638
Definition saveload.h:109
@ SLV_161
161 22567
Definition saveload.h:236
@ SLV_7
7.0 1770
Definition saveload.h:48
@ SLV_124
124 16993
Definition saveload.h:191
@ SLV_183
183 25363 Cargodist
Definition saveload.h:262
@ SLV_31
31 5999
Definition saveload.h:80
@ SLV_EXTEND_ENTITY_MAPPING
311 PR#10672 Extend entity mapping range.
Definition saveload.h:353
@ SLV_ROAD_STOP_TILE_DATA
340 PR#12883 Move storage of road stop tile data, also save for road waypoints.
Definition saveload.h:388
#define SLE_CONDREF(base, variable, type, from, to)
Storage of a reference in some savegame versions.
Definition saveload.h:889
@ REF_TOWN
Load/save a reference to a town.
Definition saveload.h:604
@ REF_CARGO_PACKET
Load/save a reference to a cargo packet.
Definition saveload.h:608
@ REF_STORAGE
Load/save a reference to a persistent storage.
Definition saveload.h:610
@ REF_VEHICLE
Load/save a reference to a vehicle.
Definition saveload.h:602
@ REF_ROADSTOPS
Load/save a reference to a bus/truck stop.
Definition saveload.h:606
#define SLEG_CONDSTRUCTLIST(name, handler, from, to)
Storage of a list of structs in some savegame versions.
Definition saveload.h:1178
#define SLE_VAR(base, variable, type)
Storage of a variable in every version of a savegame.
Definition saveload.h:1002
bool IsDriveThroughStopTile(Tile t)
Is tile t a drive through road stop station or waypoint?
StationID GetStationIndex(Tile t)
Get StationID from a tile.
Definition station_map.h:28
bool IsBuoyTile(Tile t)
Is tile t a buoy tile?
static void UpdateWaypointOrder(Order *o)
Update the buoy orders to be waypoint orders.
void MoveBuoysToWaypoints()
Perform all steps to upgrade from the old station buoys to the new version that uses waypoints.
void AfterLoadRoadStops()
(Re)building of road stop caches after loading a savegame.
static void SwapPackets(GoodsEntry *ge)
Swap the temporary packets with the packets without specific destination in the given goods entry.
Loading of station chunks before table headers were added.
const SaveLoadCompat _station_base_sl_compat[]
Original field order for SlStationBase.
const SaveLoadCompat _roadstop_sl_compat[]
Original field order for _roadstop_desc.
const SaveLoadCompat _station_sl_compat[]
Original field order for _station_desc.
const SaveLoadCompat _station_cargo_sl_compat[]
Original field order for SlStationCargo.
const SaveLoadCompat _station_goods_sl_compat[]
Original field order for SlStationGoods.
const SaveLoadCompat _station_flow_sl_compat[]
Original field order for SlStationFlow.
const SaveLoadCompat _station_waypoint_sl_compat[]
Original field order for SlStationWaypoint.
const SaveLoadCompat _station_normal_sl_compat[]
Original field order for SlStationNormal.
const SaveLoadCompat _old_station_sl_compat[]
Original field order for _old_station_desc.
const SaveLoadCompat _station_spec_list_sl_compat[]
Original field order for SlStationSpecList.
@ HVOT_WAYPOINT
Station is a waypoint (NewGRF only!)
@ FACIL_DOCK
Station with a dock.
@ FACIL_AIRPORT
Station with an airport.
@ FACIL_WAYPOINT
Station is a waypoint.
@ FACIL_TRAIN
Station with train station.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
PersistentStorage * psa
Persistent storage for NewGRF airports.
Base class for all station-ish types.
StationFacility facilities
The facilities that this station has.
StringID string_id
Default name (town area) of station.
TileArea train_station
Tile area the train 'station' part covers.
Owner owner
The owner of this station.
uint8_t delete_ctr
Delete counter. If greater than 0 then it is decremented until it reaches 0; the waypoint is then is ...
StationRect rect
NOSAVE: Station spread out rectangle maintained by StationRect::xxx() functions.
Town * town
The town this station is associated with.
std::vector< RoadStopTileData > custom_roadstop_tile_data
List of custom road stop tile data.
TimerGameCalendar::Date build_date
Date of construction.
std::string name
Custom name.
Container for cargo from the same location and time.
Definition cargopacket.h:40
Handlers and description of chunk.
Definition saveload.h:463
Stores station stats for a single cargo.
FlowStatMap flows
Planned flows through this station.
@ GES_ACCEPTANCE
Set when the station accepts the cargo currently for final deliveries.
@ GES_RATING
This indicates whether a cargo has a rating at the station.
StationCargoList cargo
The cargo packets of cargo waiting in this station.
uint8_t status
Status of this cargo, see GoodsEntryStatus.
Shared order list linking together the linked list of orders and the list of vehicles sharing this or...
Definition order_base.h:259
DestinationID GetDestination() const
Gets the destination of this order.
Definition order_base.h:103
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition order_base.h:70
void MakeGoToWaypoint(StationID destination)
Makes this order a Go To Waypoint order.
Order * next
Pointer to next order. If nullptr, end of list.
Definition order_base.h:59
Represents the covered area of e.g.
void Add(TileIndex to_add)
Add a single tile to a tile area; enlarge if needed.
Definition tilearea.cpp:43
Class for persistent storage of data.
StorageType storage
Memory for the storage array.
Class for pooled persistent storage of data.
Tindex index
Index of this pool item.
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
void FixPointers() const override
Fix the pointers.
void Load() const override
Load the chunk.
void Save() const override
Save the chunk.
Road stop specification.
A Stop for a Road Vehicle.
@ RSSFB_BASE_ENTRY
Non-zero when the entries on this road stop are the primary, i.e. the ones to delete.
void FixPointers() const override
Fix the pointers.
void Save() const override
Save the chunk.
void Load() const override
Load the chunk.
void Load() const override
Load the chunk.
void FixPointers() const override
Fix the pointers.
SaveLoad type struct.
Definition saveload.h:717
static bool IsExpected(const BaseStation *st)
Helper for checking whether the given station is of this type.
static Pool::IterateWrapper< Station > Iterate(size_t from=0)
Returns an iterable ensemble of all valid stations of type T.
static Station * Get(size_t index)
Gets station with given index.
static Station * From(BaseStation *st)
Converts a BaseStation to SpecializedStation with type checking.
Station specification.
Station data structure.
RoadStop * bus_stops
All the road stops.
GoodsEntry goods[NUM_CARGO]
Goods at this station.
TileArea bus_station
Tile area the bus 'station' part covers.
Airport airport
Tile area the airport covers.
TileArea truck_station
Tile area the truck 'station' part covers.
RoadStop * truck_stops
All the truck stops.
Town data structure.
Definition town.h:54
std::string name
Custom town name. If empty, the town was not renamed and uses the generated name.
Definition town.h:63
Vehicle data structure.
Representation of a waypoint.
uint16_t town_cn
The N-1th waypoint for this town (consecutive number)
Owner GetTileOwner(Tile tile)
Returns the owner of a tile.
Definition tile_map.h:178
static debug_inline bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition tile_map.h:150
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:95
@ MP_STATION
A tile of a station.
Definition tile_type.h:53
VehicleType
Available vehicle types.
@ VEH_SHIP
Ship vehicle type.
@ VEH_TRAIN
Train vehicle type.