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 
8 /** @file order_sl.cpp Code handling saving and loading of orders */
9 
10 #include "../stdafx.h"
11 
12 #include "saveload.h"
13 #include "compat/order_sl_compat.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 
22 /**
23  * Converts this order from an old savegame's version;
24  * it moves all bits to the new location.
25  */
ConvertFromOldSavegame()26 void Order::ConvertFromOldSavegame()
27 {
28 	uint8 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 */
34 		this->SetNonStopType((old_flags & 8) ? ONSF_NO_STOP_AT_ANY_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS);
35 	} else {
36 		this->SetNonStopType((old_flags & 8) ? ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS : ONSF_STOP_EVERYWHERE);
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
48 			this->SetLoadType(OLFB_NO_LOAD);
49 		} else if ((old_flags & 4) == 0) { // !OFB_FULL_LOAD
50 			this->SetLoadType(OLF_LOAD_IF_POSSIBLE);
51 		} else {
52 			/* old OTTD versions stored full_load_any in config file - assume it was enabled when loading */
53 			this->SetLoadType(_settings_client.gui.sg_full_load_any || IsSavegameVersionBefore(SLV_22) ? OLF_FULL_LOAD_ANY : OLFB_FULL_LOAD);
54 		}
55 
56 		if (this->IsType(OT_GOTO_STATION)) this->SetStopLocation(OSL_PLATFORM_FAR_END);
57 
58 		/* Finally fix the unload flags */
59 		if ((old_flags & 1) != 0) { // OFB_TRANSFER
60 			this->SetUnloadType(OUFB_TRANSFER);
61 		} else if ((old_flags & 2) != 0) { // OFB_UNLOAD
62 			this->SetUnloadType(OUFB_UNLOAD);
63 		} else {
64 			this->SetUnloadType(OUF_UNLOAD_IF_POSSIBLE);
65 		}
66 	} else {
67 		/* Then the depot action flags */
68 		this->SetDepotActionType(((old_flags & 6) == 4) ? ODATFB_HALT : ODATF_SERVICE_ONLY);
69 
70 		/* Finally fix the depot type flags */
71 		uint t = ((old_flags & 6) == 6) ? ODTFB_SERVICE : ODTF_MANUAL;
72 		if ((old_flags & 2) != 0) t |= ODTFB_PART_OF_ORDERS;
73 		this->SetDepotOrderType((OrderDepotTypeFlags)t);
74 	}
75 }
76 
77 /**
78  * Unpacks a order from savegames with version 4 and lower
79  * @param packed packed order
80  * @return unpacked order
81  */
UnpackVersion4Order(uint16 packed)82 static Order UnpackVersion4Order(uint16 packed)
83 {
84 	return Order(GB(packed, 8, 8) << 16 | GB(packed, 4, 4) << 8 | GB(packed, 0, 4));
85 }
86 
87 /**
88  * Unpacks a order from savegames made with TTD(Patch)
89  * @param packed packed order
90  * @return unpacked order
91  */
UnpackOldOrder(uint16 packed)92 Order UnpackOldOrder(uint16 packed)
93 {
94 	Order order = UnpackVersion4Order(packed);
95 
96 	/*
97 	 * Sanity check
98 	 * TTD stores invalid orders as OT_NOTHING with non-zero flags/station
99 	 */
100 	if (order.IsType(OT_NOTHING) && packed != 0) order.MakeDummy();
101 
102 	return order;
103 }
104 
GetOrderDescription()105 SaveLoadTable GetOrderDescription()
106 {
107 	static const SaveLoad _order_desc[] = {
108 		     SLE_VAR(Order, type,           SLE_UINT8),
109 		     SLE_VAR(Order, flags,          SLE_UINT8),
110 		     SLE_VAR(Order, dest,           SLE_UINT16),
111 		     SLE_REF(Order, next,           REF_ORDER),
112 		 SLE_CONDVAR(Order, refit_cargo,    SLE_UINT8,   SLV_36, SL_MAX_VERSION),
113 		 SLE_CONDVAR(Order, wait_time,      SLE_UINT16,  SLV_67, SL_MAX_VERSION),
114 		 SLE_CONDVAR(Order, travel_time,    SLE_UINT16,  SLV_67, SL_MAX_VERSION),
115 		 SLE_CONDVAR(Order, max_speed,      SLE_UINT16, SLV_172, SL_MAX_VERSION),
116 	};
117 
118 	return _order_desc;
119 }
120 
121 struct ORDRChunkHandler : ChunkHandler {
ORDRChunkHandlerORDRChunkHandler122 	ORDRChunkHandler() : ChunkHandler('ORDR', CH_TABLE) {}
123 
SaveORDRChunkHandler124 	void Save() const override
125 	{
126 		const SaveLoadTable slt = GetOrderDescription();
127 		SlTableHeader(slt);
128 
129 		for (Order *order : Order::Iterate()) {
130 			SlSetArrayIndex(order->index);
131 			SlObject(order, slt);
132 		}
133 	}
134 
LoadORDRChunkHandler135 	void Load() const override
136 	{
137 		if (IsSavegameVersionBefore(SLV_5, 2)) {
138 			/* Version older than 5.2 did not have a ->next pointer. Convert them
139 			 * (in the old days, the orderlist was 5000 items big) */
140 			size_t len = SlGetFieldLength();
141 
142 			if (IsSavegameVersionBefore(SLV_5)) {
143 				/* Pre-version 5 had another layout for orders
144 				 * (uint16 instead of uint32) */
145 				len /= sizeof(uint16);
146 				uint16 *orders = MallocT<uint16>(len + 1);
147 
148 				SlCopy(orders, len, SLE_UINT16);
149 
150 				for (size_t i = 0; i < len; ++i) {
151 					Order *o = new (i) Order();
152 					o->AssignOrder(UnpackVersion4Order(orders[i]));
153 				}
154 
155 				free(orders);
156 			} else if (IsSavegameVersionBefore(SLV_5, 2)) {
157 				len /= sizeof(uint32);
158 				uint32 *orders = MallocT<uint32>(len + 1);
159 
160 				SlCopy(orders, len, SLE_UINT32);
161 
162 				for (size_t i = 0; i < len; ++i) {
163 					new (i) Order(orders[i]);
164 				}
165 
166 				free(orders);
167 			}
168 
169 			/* Update all the next pointer */
170 			for (Order *o : Order::Iterate()) {
171 				size_t order_index = o->index;
172 				/* Delete invalid orders */
173 				if (o->IsType(OT_NOTHING)) {
174 					delete o;
175 					continue;
176 				}
177 				/* The orders were built like this:
178 				 * While the order is valid, set the previous will get its next pointer set */
179 				Order *prev = Order::GetIfValid(order_index - 1);
180 				if (prev != nullptr) prev->next = o;
181 			}
182 		} else {
183 			const std::vector<SaveLoad> slt = SlCompatTableHeader(GetOrderDescription(), _order_sl_compat);
184 
185 			int index;
186 
187 			while ((index = SlIterateArray()) != -1) {
188 				Order *order = new (index) Order();
189 				SlObject(order, slt);
190 			}
191 		}
192 	}
193 
FixPointersORDRChunkHandler194 	void FixPointers() const override
195 	{
196 		/* Orders from old savegames have pointers corrected in Load_ORDR */
197 		if (IsSavegameVersionBefore(SLV_5, 2)) return;
198 
199 		for (Order *o : Order::Iterate()) {
200 			SlObject(o, GetOrderDescription());
201 		}
202 	}
203 };
204 
GetOrderListDescription()205 SaveLoadTable GetOrderListDescription()
206 {
207 	static const SaveLoad _orderlist_desc[] = {
208 		SLE_REF(OrderList, first,              REF_ORDER),
209 	};
210 
211 	return _orderlist_desc;
212 }
213 
214 struct ORDLChunkHandler : ChunkHandler {
ORDLChunkHandlerORDLChunkHandler215 	ORDLChunkHandler() : ChunkHandler('ORDL', CH_TABLE) {}
216 
SaveORDLChunkHandler217 	void Save() const override
218 	{
219 		const SaveLoadTable slt = GetOrderListDescription();
220 		SlTableHeader(slt);
221 
222 		for (OrderList *list : OrderList::Iterate()) {
223 			SlSetArrayIndex(list->index);
224 			SlObject(list, slt);
225 		}
226 	}
227 
LoadORDLChunkHandler228 	void Load() const override
229 	{
230 		const std::vector<SaveLoad> slt = SlCompatTableHeader(GetOrderListDescription(), _orderlist_sl_compat);
231 
232 		int index;
233 
234 		while ((index = SlIterateArray()) != -1) {
235 			/* set num_orders to 0 so it's a valid OrderList */
236 			OrderList *list = new (index) OrderList(0);
237 			SlObject(list, slt);
238 		}
239 
240 	}
241 
FixPointersORDLChunkHandler242 	void FixPointers() const override
243 	{
244 		for (OrderList *list : OrderList::Iterate()) {
245 			SlObject(list, GetOrderListDescription());
246 		}
247 	}
248 };
249 
GetOrderBackupDescription()250 SaveLoadTable GetOrderBackupDescription()
251 {
252 	static const SaveLoad _order_backup_desc[] = {
253 		     SLE_VAR(OrderBackup, user,                     SLE_UINT32),
254 		     SLE_VAR(OrderBackup, tile,                     SLE_UINT32),
255 		     SLE_VAR(OrderBackup, group,                    SLE_UINT16),
256 		 SLE_CONDVAR(OrderBackup, service_interval,         SLE_FILE_U32 | SLE_VAR_U16,  SL_MIN_VERSION, SLV_192),
257 		 SLE_CONDVAR(OrderBackup, service_interval,         SLE_UINT16,                SLV_192, SL_MAX_VERSION),
258 		    SLE_SSTR(OrderBackup, name,                     SLE_STR),
259 		 SLE_CONDREF(OrderBackup, clone,                    REF_VEHICLE,               SLV_192, SL_MAX_VERSION),
260 		     SLE_VAR(OrderBackup, cur_real_order_index,     SLE_UINT8),
261 		 SLE_CONDVAR(OrderBackup, cur_implicit_order_index, SLE_UINT8,                 SLV_176, SL_MAX_VERSION),
262 		 SLE_CONDVAR(OrderBackup, current_order_time,       SLE_UINT32,                SLV_176, SL_MAX_VERSION),
263 		 SLE_CONDVAR(OrderBackup, lateness_counter,         SLE_INT32,                 SLV_176, SL_MAX_VERSION),
264 		 SLE_CONDVAR(OrderBackup, timetable_start,          SLE_INT32,                 SLV_176, SL_MAX_VERSION),
265 		 SLE_CONDVAR(OrderBackup, vehicle_flags,            SLE_FILE_U8 | SLE_VAR_U16, SLV_176, SLV_180),
266 		 SLE_CONDVAR(OrderBackup, vehicle_flags,            SLE_UINT16,                SLV_180, SL_MAX_VERSION),
267 		     SLE_REF(OrderBackup, orders,                   REF_ORDER),
268 	};
269 
270 	return _order_backup_desc;
271 }
272 
273 struct BKORChunkHandler : ChunkHandler {
BKORChunkHandlerBKORChunkHandler274 	BKORChunkHandler() : ChunkHandler('BKOR', CH_TABLE) {}
275 
SaveBKORChunkHandler276 	void Save() const override
277 	{
278 		const SaveLoadTable slt = GetOrderBackupDescription();
279 		SlTableHeader(slt);
280 
281 		/* We only save this when we're a network server
282 		 * as we want this information on our clients. For
283 		 * normal games this information isn't needed. */
284 		if (!_networking || !_network_server) return;
285 
286 		for (OrderBackup *ob : OrderBackup::Iterate()) {
287 			SlSetArrayIndex(ob->index);
288 			SlObject(ob, slt);
289 		}
290 	}
291 
LoadBKORChunkHandler292 	void Load() const override
293 	{
294 		const std::vector<SaveLoad> slt = SlCompatTableHeader(GetOrderBackupDescription(), _order_backup_sl_compat);
295 
296 		int index;
297 
298 		while ((index = SlIterateArray()) != -1) {
299 			/* set num_orders to 0 so it's a valid OrderList */
300 			OrderBackup *ob = new (index) OrderBackup();
301 			SlObject(ob, slt);
302 		}
303 	}
304 
FixPointersBKORChunkHandler305 	void FixPointers() const override
306 	{
307 		for (OrderBackup *ob : OrderBackup::Iterate()) {
308 			SlObject(ob, GetOrderBackupDescription());
309 		}
310 	}
311 };
312 
313 static const BKORChunkHandler BKOR;
314 static const ORDRChunkHandler ORDR;
315 static const ORDLChunkHandler ORDL;
316 static const ChunkHandlerRef order_chunk_handlers[] = {
317 	BKOR,
318 	ORDR,
319 	ORDL,
320 };
321 
322 extern const ChunkHandlerTable _order_chunk_handlers(order_chunk_handlers);
323