OpenTTD Source 20260206-master-g4d4e37dbf1
order_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 "saveload_internal.h"
16#include "../order_backup.h"
17#include "../settings_type.h"
18#include "../network/network.h"
19
20#include "../safeguards.h"
21
27{
28 uint8_t old_flags = this->flags;
29 this->flags = 0;
30
31 /* First handle non-stop - use value from savegame if possible, else use value from config file */
32 if (_settings_client.gui.sg_new_nonstop || (IsSavegameVersionBefore(SLV_22) && _savegame_type != SGT_TTO && _savegame_type != SGT_TTD && _settings_client.gui.new_nonstop)) {
33 /* OFB_NON_STOP */
35 } else {
36 this->SetNonStopType((old_flags & 8) ? OrderNonStopFlag::NoIntermediate : OrderNonStopFlags{});
37 }
38
39 switch (this->GetType()) {
40 /* Only a few types need the other savegame conversions. */
41 case OT_GOTO_DEPOT: case OT_GOTO_STATION: case OT_LOADING: break;
42 default: return;
43 }
44
45 if (this->GetType() != OT_GOTO_DEPOT) {
46 /* Then the load flags */
47 if ((old_flags & 2) != 0) { // OFB_UNLOAD
49 } else if ((old_flags & 4) == 0) { // !OFB_FULL_LOAD
51 } else {
52 /* old OTTD versions stored full_load_any in config file - assume it was enabled when loading */
54 }
55
56 if (this->IsType(OT_GOTO_STATION)) this->SetStopLocation(OrderStopLocation::FarEnd);
57
58 /* Finally fix the unload flags */
59 if ((old_flags & 1) != 0) { // OFB_TRANSFER
61 } else if ((old_flags & 2) != 0) { // OFB_UNLOAD
63 } else {
65 }
66 } else {
67 /* Then the depot action flags */
68 OrderDepotActionFlags action_flags{};
69 if ((old_flags & 6) == 4) action_flags.Set(OrderDepotActionFlag::Halt);
70 this->SetDepotActionType(action_flags);
71
72 /* Finally fix the depot type flags */
73 OrderDepotTypeFlags type_flags{};
74 if ((old_flags & 6) == 6) type_flags.Set(OrderDepotTypeFlag::Service);
75 if ((old_flags & 2) != 0) type_flags.Set(OrderDepotTypeFlag::PartOfOrders);
76 this->SetDepotOrderType(type_flags);
77 }
78}
79
85static Order UnpackVersion4Order(uint16_t packed)
86{
87 return Order(GB(packed, 0, 4), GB(packed, 4, 4), GB(packed, 8, 8));
88}
89
95Order UnpackOldOrder(uint16_t packed)
96{
97 Order order = UnpackVersion4Order(packed);
98
99 /*
100 * Sanity check
101 * TTD stores invalid orders as OT_NOTHING with non-zero flags/station
102 */
103 if (order.IsType(OT_NOTHING) && packed != 0) order.MakeDummy();
104
105 return order;
106}
107
109static std::vector<OldOrderSaveLoadItem> _old_order_saveload_pool;
110
115{
117 _old_order_saveload_pool.shrink_to_fit();
118}
119
126{
127 if (ref_index == 0) return nullptr;
128 assert(ref_index <= _old_order_saveload_pool.size());
129 return &_old_order_saveload_pool[ref_index - 1];
130}
131
138{
139 assert(pool_index < UINT32_MAX);
140 if (pool_index >= _old_order_saveload_pool.size()) _old_order_saveload_pool.resize(pool_index + 1);
141 return _old_order_saveload_pool[pool_index];
142}
143
145{
146 static const SaveLoad _order_desc[] = {
147 SLE_VARNAME(OldOrderSaveLoadItem, order.type, "type", SLE_UINT8),
148 SLE_VARNAME(OldOrderSaveLoadItem, order.flags, "flags", SLE_UINT8),
149 SLE_VARNAME(OldOrderSaveLoadItem, order.dest, "dest", SLE_UINT16),
150 SLE_CONDVARNAME(OldOrderSaveLoadItem, next, "next", SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_69),
151 SLE_CONDVARNAME(OldOrderSaveLoadItem, next, "next", SLE_UINT32, SLV_69, SL_MAX_VERSION),
152 SLE_CONDVARNAME(OldOrderSaveLoadItem, order.refit_cargo, "refit_cargo", SLE_UINT8, SLV_36, SL_MAX_VERSION),
153 SLE_CONDVARNAME(OldOrderSaveLoadItem, order.wait_time, "wait_time", SLE_UINT16, SLV_67, SL_MAX_VERSION),
154 SLE_CONDVARNAME(OldOrderSaveLoadItem, order.travel_time, "travel_time", SLE_UINT16, SLV_67, SL_MAX_VERSION),
155 SLE_CONDVARNAME(OldOrderSaveLoadItem, order.max_speed, "max_speed", SLE_UINT16, SLV_172, SL_MAX_VERSION),
156 };
157
158 return _order_desc;
159}
160
161struct ORDRChunkHandler : ChunkHandler {
162 ORDRChunkHandler() : ChunkHandler('ORDR', CH_READONLY) {}
163
164 void Load() const override
165 {
167 /* Version older than 5.2 did not have a ->next pointer. Convert them
168 * (in the old days, the orderlist was 5000 items big) */
169 size_t len = SlGetFieldLength();
170
172 /* Pre-version 5 had another layout for orders
173 * (uint16_t instead of uint32_t) */
174 len /= sizeof(uint16_t);
175 std::vector<uint16_t> orders(len);
176
177 SlCopy(&orders[0], len, SLE_UINT16);
178
179 for (size_t i = 0; i < len; ++i) {
180 auto &item = AllocateOldOrder(i);
181 item.order.AssignOrder(UnpackVersion4Order(orders[i]));
182 }
183 } else if (IsSavegameVersionBefore(SLV_5, 2)) {
184 len /= sizeof(uint32_t);
185 std::vector<uint32_t> orders(len);
186
187 SlCopy(&orders[0], len, SLE_UINT32);
188
189 for (size_t i = 0; i < len; ++i) {
190 auto &item = AllocateOldOrder(i);
191 item.order = Order(GB(orders[i], 0, 8), GB(orders[i], 8, 8), GB(orders[i], 16, 16));
192 }
193 }
194
195 /* Update all the next pointer. The orders were built like this:
196 * While the order is valid, the previous order will get its next pointer set */
197 for (uint32_t num = 1; const OldOrderSaveLoadItem &item : _old_order_saveload_pool) {
198 if (!item.order.IsType(OT_NOTHING) && num > 1) {
199 OldOrderSaveLoadItem *prev = GetOldOrder(num - 1);
200 if (prev != nullptr) prev->next = num;
201 }
202 ++num;
203 }
204 } else {
205 const std::vector<SaveLoad> slt = SlCompatTableHeader(GetOrderDescription(), _order_sl_compat);
206
207 int index;
208
209 while ((index = SlIterateArray()) != -1) {
210 auto &item = AllocateOldOrder(index);
211 SlObject(&item, slt);
212 }
213 }
214 }
215};
216
217template <typename T>
218class SlOrders : public VectorSaveLoadHandler<SlOrders<T>, T, Order> {
219public:
220 static inline const SaveLoad description[] = {
221 SLE_VAR(Order, type, SLE_UINT8),
222 SLE_VAR(Order, flags, SLE_UINT8),
223 SLE_VAR(Order, dest, SLE_UINT16),
224 SLE_VAR(Order, refit_cargo, SLE_UINT8),
225 SLE_VAR(Order, wait_time, SLE_UINT16),
226 SLE_VAR(Order, travel_time, SLE_UINT16),
227 SLE_VAR(Order, max_speed, SLE_UINT16),
228 };
229 static inline const SaveLoadCompatTable compat_description = {};
230
231 std::vector<Order> &GetVector(T *container) const override { return container->orders; }
232
233 void LoadCheck(T *container) const override { this->Load(container); }
234};
235
236/* Instantiate SlOrders classes. */
237template class SlOrders<OrderList>;
238template class SlOrders<OrderBackup>;
239
241{
242 static const SaveLoad _orderlist_desc[] = {
243 SLE_CONDVARNAME(OrderList, old_order_index, "first", SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_69),
244 SLE_CONDVARNAME(OrderList, old_order_index, "first", SLE_UINT32, SLV_69, SLV_ORDERS_OWNED_BY_ORDERLIST),
246 };
247
248 return _orderlist_desc;
249}
250
251struct ORDLChunkHandler : ChunkHandler {
252 ORDLChunkHandler() : ChunkHandler('ORDL', CH_TABLE) {}
253
254 void Save() const override
255 {
256 const SaveLoadTable slt = GetOrderListDescription();
257 SlTableHeader(slt);
258
259 for (OrderList *list : OrderList::Iterate()) {
260 SlSetArrayIndex(list->index);
261 SlObject(list, slt);
262 }
263 }
264
265 void Load() const override
266 {
267 const std::vector<SaveLoad> slt = SlCompatTableHeader(GetOrderListDescription(), _orderlist_sl_compat);
268
269 int index;
270
271 while ((index = SlIterateArray()) != -1) {
272 OrderList *list = OrderList::CreateAtIndex(OrderListID(index));
273 SlObject(list, slt);
274 }
275
276 }
277
278 void FixPointers() const override
279 {
281
282 for (OrderList *list : OrderList::Iterate()) {
283 SlObject(list, GetOrderListDescription());
284
285 if (migrate_orders) {
286 std::vector<Order> orders;
287 for (OldOrderSaveLoadItem *old_order = GetOldOrder(list->old_order_index); old_order != nullptr; old_order = GetOldOrder(old_order->next)) {
288 orders.push_back(std::move(old_order->order));
289 }
290 list->orders = std::move(orders);
291 }
292 }
293 }
294};
295
297{
298 static const SaveLoad _order_backup_desc[] = {
299 SLE_VAR(OrderBackup, user, SLE_UINT32),
300 SLE_VAR(OrderBackup, tile, SLE_UINT32),
301 SLE_VAR(OrderBackup, group, SLE_UINT16),
302 SLE_CONDVAR(OrderBackup, service_interval, SLE_FILE_U32 | SLE_VAR_U16, SL_MIN_VERSION, SLV_192),
304 SLE_SSTR(OrderBackup, name, SLE_STR),
312 SLE_CONDVAR(OrderBackup, vehicle_flags, SLE_FILE_U8 | SLE_VAR_U16, SLV_176, SLV_180),
314 SLE_CONDVARNAME(OrderBackup, old_order_index, "orders", SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_69),
315 SLE_CONDVARNAME(OrderBackup, old_order_index, "orders", SLE_UINT32, SLV_69, SLV_ORDERS_OWNED_BY_ORDERLIST),
316 SLEG_CONDSTRUCTLIST("orders", SlOrders<OrderBackup>, SLV_ORDERS_OWNED_BY_ORDERLIST, SL_MAX_VERSION),
317 };
318
319 return _order_backup_desc;
320}
321
322struct BKORChunkHandler : ChunkHandler {
323 BKORChunkHandler() : ChunkHandler('BKOR', CH_TABLE) {}
324
325 void Save() const override
326 {
327 const SaveLoadTable slt = GetOrderBackupDescription();
328 SlTableHeader(slt);
329
330 /* We only save this when we're a network server
331 * as we want this information on our clients. For
332 * normal games this information isn't needed. */
333 if (!_networking || !_network_server) return;
334
335 for (OrderBackup *ob : OrderBackup::Iterate()) {
336 SlSetArrayIndex(ob->index);
337 SlObject(ob, slt);
338 }
339 }
340
341 void Load() const override
342 {
343 const std::vector<SaveLoad> slt = SlCompatTableHeader(GetOrderBackupDescription(), _order_backup_sl_compat);
344
345 int index;
346
347 while ((index = SlIterateArray()) != -1) {
348 /* set num_orders to 0 so it's a valid OrderList */
350 SlObject(ob, slt);
351 }
352 }
353
354 void FixPointers() const override
355 {
357
358 for (OrderBackup *ob : OrderBackup::Iterate()) {
359 SlObject(ob, GetOrderBackupDescription());
360
361 if (migrate_orders) {
362 std::vector<Order> orders;
363 for (OldOrderSaveLoadItem *old_order = GetOldOrder(ob->old_order_index); old_order != nullptr; old_order = GetOldOrder(old_order->next)) {
364 orders.push_back(std::move(old_order->order));
365 }
366 ob->orders = std::move(orders);
367 }
368 }
369 }
370};
371
372static const BKORChunkHandler BKOR;
373static const ORDRChunkHandler ORDR;
374static const ORDLChunkHandler ORDL;
375static const ChunkHandlerRef order_chunk_handlers[] = {
376 BKOR,
377 ORDR,
378 ORDL,
379};
380
381extern const ChunkHandlerTable _order_chunk_handlers(order_chunk_handlers);
static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
constexpr Timpl & Set()
Set all bits.
std::vector< Order > & GetVector(T *container) const override
Get instance of vector to load/save.
Definition order_sl.cpp:231
void LoadCheck(T *container) const override
Similar to load, but used only to validate savegames.
Definition order_sl.cpp:233
Default handler for saving/loading a vector to/from disk.
Definition saveload.h:1403
void Load(T *object) const override
Definition saveload.h:1429
SavegameType _savegame_type
type of savegame we are loading
Definition saveload.cpp:77
bool _networking
are we in networking mode?
Definition network.cpp:66
bool _network_server
network-server is active
Definition network.cpp:67
Basic functions/variables used all over the place.
@ Order
Something wrong with the order, e.g. invalid or duplicate entries, too few entries.
Definition news_type.h:54
Functions related to order backups.
PoolID< uint8_t, struct OrderBackupIDTag, 255, 0xFF > OrderBackupID
Unique identifier for an order backup.
static std::vector< OldOrderSaveLoadItem > _old_order_saveload_pool
Temporary storage for conversion from old order pool.
Definition order_sl.cpp:109
Order UnpackOldOrder(uint16_t packed)
Unpacks a order from savegames made with TTD(Patch).
Definition order_sl.cpp:95
static Order UnpackVersion4Order(uint16_t packed)
Unpacks a order from savegames with version 4 and lower.
Definition order_sl.cpp:85
void ClearOldOrders()
Clear all old orders.
Definition order_sl.cpp:114
OldOrderSaveLoadItem & AllocateOldOrder(size_t pool_index)
Allocate an old order with the given pool index.
Definition order_sl.cpp:137
OldOrderSaveLoadItem * GetOldOrder(size_t ref_index)
Get a pointer to an old order with the given reference index.
Definition order_sl.cpp:125
Loading of order chunks before table headers were added.
const SaveLoadCompat _order_sl_compat[]
Original field order for _order_desc.
const SaveLoadCompat _orderlist_sl_compat[]
Original field order for _orderlist_desc.
const SaveLoadCompat _order_backup_sl_compat[]
Original field order for _order_backup_desc.
@ Transfer
Transfer all cargo onto the platform.
Definition order_type.h:70
@ UnloadIfPossible
Unload all cargo that the station accepts.
Definition order_type.h:68
@ Unload
Force unloading all cargo onto the platform, possibly not getting paid.
Definition order_type.h:69
@ FarEnd
Stop at the far end of the platform.
Definition order_type.h:100
@ NoDestination
The vehicle will stop at any station it passes except the destination, aka via.
Definition order_type.h:89
@ NoIntermediate
The vehicle will not stop at any stations it passes except the destination, aka non-stop.
Definition order_type.h:88
@ FullLoad
Full load all cargoes of the consist.
Definition order_type.h:79
@ NoLoad
Do not load anything.
Definition order_type.h:81
@ FullLoadAny
Full load a single cargo of the consist.
Definition order_type.h:80
@ LoadIfPossible
Load as long as there is cargo that fits in the train.
Definition order_type.h:78
@ Halt
Service the vehicle and then halt it.
Definition order_type.h:118
@ PartOfOrders
This depot order is because of a regular order.
Definition order_type.h:109
@ Service
This depot order is because of the servicing limit.
Definition order_type.h:108
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.
int SlIterateArray()
Iterate through the elements of an array and read the whole thing.
Definition saveload.cpp:677
void SlCopy(void *object, size_t length, VarType conv)
Copy a list of SL_VARs to/from a savegame.
size_t SlGetFieldLength()
Get the length of the current object.
Definition saveload.cpp:800
void SlObject(void *object, const SaveLoadTable &slt)
Main SaveLoad function.
std::vector< SaveLoad > SlTableHeader(const SaveLoadTable &slt)
Save or Load a table header.
Functions/types related to saving and loading games.
@ SGT_TTD
TTD savegame (can be detected incorrectly).
Definition saveload.h:441
@ SGT_TTO
TTO savegame.
Definition saveload.h:445
#define SLE_VARNAME(base, variable, name, type)
Storage of a variable in every version of a savegame.
Definition saveload.h:1047
std::reference_wrapper< const ChunkHandler > ChunkHandlerRef
A reference to ChunkHandler.
Definition saveload.h:526
@ REF_VEHICLE
Load/save a reference to a vehicle.
Definition saveload.h:637
std::span< const ChunkHandlerRef > ChunkHandlerTable
A table of ChunkHandler entries.
Definition saveload.h:529
std::span< const struct SaveLoadCompat > SaveLoadCompatTable
A table of SaveLoadCompat entries.
Definition saveload.h:535
#define SLE_CONDVAR(base, variable, type, from, to)
Storage of a variable in some savegame versions.
Definition saveload.h:904
bool IsSavegameVersionBefore(SaveLoadVersion major, uint8_t minor=0)
Checks whether the savegame is below major.
Definition saveload.h:1299
#define SLE_SSTR(base, variable, type)
Storage of a std::string in every savegame version.
Definition saveload.h:1082
@ SLV_69
69 10319
Definition saveload.h:125
@ SLV_172
172 23947
Definition saveload.h:249
@ SLV_67
67 10236
Definition saveload.h:123
@ SLV_36
36 6624
Definition saveload.h:86
@ SLV_180
180 24998 1.3.x
Definition saveload.h:259
@ SLV_176
176 24446
Definition saveload.h:254
@ SL_MAX_VERSION
Highest possible saveload version.
Definition saveload.h:418
@ SL_MIN_VERSION
First savegame version.
Definition saveload.h:31
@ SLV_22
22 3726
Definition saveload.h:69
@ SLV_192
192 26700 FS#6066 Fix saving of order backups
Definition saveload.h:274
@ SLV_TIMETABLE_START_TICKS_FIX
322 PR#11557 Fix for missing convert timetable start from a date to ticks.
Definition saveload.h:366
@ SLV_ORDERS_OWNED_BY_ORDERLIST
354 PR#13948 Orders stored in OrderList, pool removed.
Definition saveload.h:404
@ SLV_5
5.0 1429 5.1 1440 5.2 1525 0.3.6
Definition saveload.h:43
#define SLE_CONDREF(base, variable, type, from, to)
Storage of a reference in some savegame versions.
Definition saveload.h:925
std::span< const struct SaveLoad > SaveLoadTable
A table of SaveLoad entries.
Definition saveload.h:532
#define SLEG_CONDSTRUCTLIST(name, handler, from, to)
Storage of a list of structs in some savegame versions.
Definition saveload.h:1214
@ CH_READONLY
Chunk is never saved.
Definition saveload.h:476
#define SLE_VAR(base, variable, type)
Storage of a variable in every version of a savegame.
Definition saveload.h:1038
#define SLE_CONDVARNAME(base, variable, name, type, from, to)
Storage of a variable in some savegame versions.
Definition saveload.h:915
Declaration of functions used in more save/load files.
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
Types related to global configuration settings.
Definition of base types and functions in a cross-platform compatible way.
void Save() const override
Save the chunk.
Definition order_sl.cpp:325
void Load() const override
Load the chunk.
Definition order_sl.cpp:341
void FixPointers() const override
Fix the pointers.
Definition order_sl.cpp:354
std::string name
Name of vehicle.
TimerGameTick::Ticks current_order_time
How many ticks have passed since this order started.
VehicleOrderID cur_real_order_index
The index to the current real (non-implicit) order.
VehicleFlags vehicle_flags
Used for gradual loading and other miscellaneous things (.
VehicleOrderID cur_implicit_order_index
The index to the current implicit order.
TimerGameTick::TickCounter timetable_start
At what tick of TimerGameTick::counter the vehicle should start its timetable.
TimerGameTick::Ticks lateness_counter
How many ticks late (or early if negative) this vehicle is.
uint16_t service_interval
The interval for (automatic) servicing; either in days or %.
void FixPointers() const override
Fix the pointers.
Definition order_sl.cpp:278
void Save() const override
Save the chunk.
Definition order_sl.cpp:254
void Load() const override
Load the chunk.
Definition order_sl.cpp:265
void Load() const override
Load the chunk.
Definition order_sl.cpp:164
Compatibility struct to allow saveload of pool-based orders.
Definition order_base.h:258
uint32_t next
The next order index (1-based).
Definition order_base.h:260
Data for backing up an order of a vehicle so it can be restored after a vehicle is rebuilt in the sam...
OrderBackup(OrderBackupID index)
Create an order backup for savegame loading.
const Vehicle * clone
Vehicle this vehicle was a clone of.
friend SaveLoadTable GetOrderBackupDescription()
Saving and loading of order backups.
Definition order_sl.cpp:296
TileIndex tile
Tile of the depot where the order was changed.
uint32_t user
The user that requested the backup.
GroupID group
The group the vehicle was part of.
Shared order list linking together the linked list of orders and the list of vehicles sharing this or...
Definition order_base.h:274
friend SaveLoadTable GetOrderListDescription()
Saving and loading of order lists.
Definition order_sl.cpp:240
OrderList(OrderListID index)
Default constructor producing an invalid order list.
Definition order_base.h:293
void ConvertFromOldSavegame()
Converts this order from an old savegame's version; it moves all bits to the new location.
Definition order_sl.cpp:26
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition order_base.h:66
void SetNonStopType(OrderNonStopFlags non_stop_type)
Set whether we must stop at stations or not.
Definition order_base.h:167
OrderType GetType() const
Get the type of order of this order.
Definition order_base.h:72
void SetDepotOrderType(OrderDepotTypeFlags depot_order_type)
Set the cause to go to the depot.
Definition order_base.h:171
void SetStopLocation(OrderStopLocation stop_location)
Set where we must stop at the platform.
Definition order_base.h:169
void MakeDummy()
Makes this order a Dummy order.
uint8_t flags
Load/unload types, depot order/action types.
Definition order_base.h:48
friend SaveLoadTable GetOrderDescription()
Saving and loading of orders.
Definition order_sl.cpp:144
void SetDepotActionType(OrderDepotActionFlags depot_service_type)
Set what we are going to do in the depot.
Definition order_base.h:173
void SetUnloadType(OrderUnloadType unload_type)
Set how the consist must be unloaded.
Definition order_base.h:165
void SetLoadType(OrderLoadType load_type)
Set how the consist must be loaded.
Definition order_base.h:163
static Pool::IterateWrapper< OrderList > Iterate(size_t from=0)
static T * CreateAtIndex(OrderListID index, Targs &&... args)
SaveLoad type struct.
Definition saveload.h:753