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 cargomonitor_sl.cpp Code handling saving and loading of Cargo monitoring. */
9 
10 #include "../stdafx.h"
11 
12 #include "saveload.h"
13 #include "compat/cargomonitor_sl_compat.h"
14 
15 #include "../cargomonitor.h"
16 
17 #include "../safeguards.h"
18 
19 /** Temporary storage of cargo monitoring data for loading or saving it. */
20 struct TempStorage {
21 	CargoMonitorID number;
22 	uint32 amount;
23 };
24 
25 /** Description of the #TempStorage structure for the purpose of load and save. */
26 static const SaveLoad _cargomonitor_pair_desc[] = {
27 	SLE_VAR(TempStorage, number, SLE_UINT32),
28 	SLE_VAR(TempStorage, amount, SLE_UINT32),
29 };
30 
FixupCargoMonitor(CargoMonitorID number)31 static CargoMonitorID FixupCargoMonitor(CargoMonitorID number)
32 {
33 	/* Between SLV_EXTEND_CARGOTYPES and SLV_FIX_CARGO_MONITOR, the
34 	 * CargoMonitorID structure had insufficient packing for more
35 	 * than 32 cargo types. Here we have to shuffle bits to account
36 	 * for the change.
37 	 * Company moved from bits 24-31 to 25-28.
38 	 * Cargo type increased from bits 19-23 to 19-24.
39 	 */
40 	SB(number, 25, 4, GB(number, 24, 4));
41 	SB(number, 29, 3, 0);
42 	ClrBit(number, 24);
43 	return number;
44 }
45 
46 /** #_cargo_deliveries monitoring map. */
47 struct CMDLChunkHandler : ChunkHandler {
CMDLChunkHandlerCMDLChunkHandler48 	CMDLChunkHandler() : ChunkHandler('CMDL', CH_TABLE) {}
49 
SaveCMDLChunkHandler50 	void Save() const override
51 	{
52 		SlTableHeader(_cargomonitor_pair_desc);
53 
54 		TempStorage storage;
55 
56 		int i = 0;
57 		CargoMonitorMap::const_iterator iter = _cargo_deliveries.begin();
58 		while (iter != _cargo_deliveries.end()) {
59 			storage.number = iter->first;
60 			storage.amount = iter->second;
61 
62 			SlSetArrayIndex(i);
63 			SlObject(&storage, _cargomonitor_pair_desc);
64 
65 			i++;
66 			iter++;
67 		}
68 	}
69 
LoadCMDLChunkHandler70 	void Load() const override
71 	{
72 		const std::vector<SaveLoad> slt = SlCompatTableHeader(_cargomonitor_pair_desc, _cargomonitor_pair_sl_compat);
73 
74 		TempStorage storage;
75 		bool fix = IsSavegameVersionBefore(SLV_FIX_CARGO_MONITOR);
76 
77 		ClearCargoDeliveryMonitoring();
78 		for (;;) {
79 			if (SlIterateArray() < 0) break;
80 			SlObject(&storage, slt);
81 
82 			if (fix) storage.number = FixupCargoMonitor(storage.number);
83 
84 			std::pair<CargoMonitorID, uint32> p(storage.number, storage.amount);
85 			_cargo_deliveries.insert(p);
86 		}
87 	}
88 };
89 
90 /** #_cargo_pickups monitoring map. */
91 struct CMPUChunkHandler : ChunkHandler {
CMPUChunkHandlerCMPUChunkHandler92 	CMPUChunkHandler() : ChunkHandler('CMPU', CH_TABLE) {}
93 
SaveCMPUChunkHandler94 	void Save() const override
95 	{
96 		SlTableHeader(_cargomonitor_pair_desc);
97 
98 		TempStorage storage;
99 
100 		int i = 0;
101 		CargoMonitorMap::const_iterator iter = _cargo_pickups.begin();
102 		while (iter != _cargo_pickups.end()) {
103 			storage.number = iter->first;
104 			storage.amount = iter->second;
105 
106 			SlSetArrayIndex(i);
107 			SlObject(&storage, _cargomonitor_pair_desc);
108 
109 			i++;
110 			iter++;
111 		}
112 	}
113 
LoadCMPUChunkHandler114 	void Load() const override
115 	{
116 		const std::vector<SaveLoad> slt = SlCompatTableHeader(_cargomonitor_pair_desc, _cargomonitor_pair_sl_compat);
117 
118 		TempStorage storage;
119 		bool fix = IsSavegameVersionBefore(SLV_FIX_CARGO_MONITOR);
120 
121 		ClearCargoPickupMonitoring();
122 		for (;;) {
123 			if (SlIterateArray() < 0) break;
124 			SlObject(&storage, slt);
125 
126 			if (fix) storage.number = FixupCargoMonitor(storage.number);
127 
128 			std::pair<CargoMonitorID, uint32> p(storage.number, storage.amount);
129 			_cargo_pickups.insert(p);
130 		}
131 	}
132 };
133 
134 /** Chunk definition of the cargomonitoring maps. */
135 static const CMDLChunkHandler CMDL;
136 static const CMPUChunkHandler CMPU;
137 static const ChunkHandlerRef cargomonitor_chunk_handlers[] = {
138 	CMDL,
139 	CMPU,
140 };
141 
142 extern const ChunkHandlerTable _cargomonitor_chunk_handlers(cargomonitor_chunk_handlers);
143