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 gamelog_sl.cpp Code handling saving and loading of gamelog data */
9 
10 #include "../stdafx.h"
11 
12 #include "saveload.h"
13 #include "compat/gamelog_sl_compat.h"
14 
15 #include "../gamelog_internal.h"
16 #include "../fios.h"
17 
18 #include "../safeguards.h"
19 
20 
21 class SlGamelogMode : public DefaultSaveLoadHandler<SlGamelogMode, LoggedChange> {
22 public:
23 	inline static const SaveLoad description[] = {
24 		SLE_VAR(LoggedChange, mode.mode,         SLE_UINT8),
25 		SLE_VAR(LoggedChange, mode.landscape,    SLE_UINT8),
26 	};
27 	inline const static SaveLoadCompatTable compat_description = _gamelog_mode_sl_compat;
28 
Save(LoggedChange * lc) const29 	void Save(LoggedChange *lc) const override
30 	{
31 		if (lc->ct != GLCT_MODE) return;
32 		SlObject(lc, this->GetDescription());
33 	}
34 
Load(LoggedChange * lc) const35 	void Load(LoggedChange *lc) const override
36 	{
37 		if (lc->ct != GLCT_MODE) return;
38 		SlObject(lc, this->GetLoadDescription());
39 	}
40 
LoadCheck(LoggedChange * lc) const41 	void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
42 };
43 
44 class SlGamelogRevision : public DefaultSaveLoadHandler<SlGamelogRevision, LoggedChange> {
45 public:
46 	inline static const SaveLoad description[] = {
47 		SLE_ARR(LoggedChange, revision.text,     SLE_UINT8,  GAMELOG_REVISION_LENGTH),
48 		SLE_VAR(LoggedChange, revision.newgrf,   SLE_UINT32),
49 		SLE_VAR(LoggedChange, revision.slver,    SLE_UINT16),
50 		SLE_VAR(LoggedChange, revision.modified, SLE_UINT8),
51 	};
52 	inline const static SaveLoadCompatTable compat_description = _gamelog_revision_sl_compat;
53 
Save(LoggedChange * lc) const54 	void Save(LoggedChange *lc) const override
55 	{
56 		if (lc->ct != GLCT_REVISION) return;
57 		SlObject(lc, this->GetDescription());
58 	}
59 
Load(LoggedChange * lc) const60 	void Load(LoggedChange *lc) const override
61 	{
62 		if (lc->ct != GLCT_REVISION) return;
63 		SlObject(lc, this->GetLoadDescription());
64 	}
65 
LoadCheck(LoggedChange * lc) const66 	void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
67 };
68 
69 class SlGamelogOldver : public DefaultSaveLoadHandler<SlGamelogOldver, LoggedChange> {
70 public:
71 	inline static const SaveLoad description[] = {
72 		SLE_VAR(LoggedChange, oldver.type,       SLE_UINT32),
73 		SLE_VAR(LoggedChange, oldver.version,    SLE_UINT32),
74 	};
75 	inline const static SaveLoadCompatTable compat_description = _gamelog_oldver_sl_compat;
76 
Save(LoggedChange * lc) const77 	void Save(LoggedChange *lc) const override
78 	{
79 		if (lc->ct != GLCT_OLDVER) return;
80 		SlObject(lc, this->GetDescription());
81 	}
82 
Load(LoggedChange * lc) const83 	void Load(LoggedChange *lc) const override
84 	{
85 		if (lc->ct != GLCT_OLDVER) return;
86 		SlObject(lc, this->GetLoadDescription());
87 	}
88 
LoadCheck(LoggedChange * lc) const89 	void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
90 };
91 
92 class SlGamelogSetting : public DefaultSaveLoadHandler<SlGamelogSetting, LoggedChange> {
93 public:
94 	inline static const SaveLoad description[] = {
95 		SLE_STR(LoggedChange, setting.name,      SLE_STR,    128),
96 		SLE_VAR(LoggedChange, setting.oldval,    SLE_INT32),
97 		SLE_VAR(LoggedChange, setting.newval,    SLE_INT32),
98 	};
99 	inline const static SaveLoadCompatTable compat_description = _gamelog_setting_sl_compat;
100 
Save(LoggedChange * lc) const101 	void Save(LoggedChange *lc) const override
102 	{
103 		if (lc->ct != GLCT_SETTING) return;
104 		SlObject(lc, this->GetDescription());
105 	}
106 
Load(LoggedChange * lc) const107 	void Load(LoggedChange *lc) const override
108 	{
109 		if (lc->ct != GLCT_SETTING) return;
110 		SlObject(lc, this->GetLoadDescription());
111 	}
112 
LoadCheck(LoggedChange * lc) const113 	void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
114 };
115 
116 class SlGamelogGrfadd : public DefaultSaveLoadHandler<SlGamelogGrfadd, LoggedChange> {
117 public:
118 	inline static const SaveLoad description[] = {
119 		SLE_VAR(LoggedChange, grfadd.grfid,      SLE_UINT32    ),
120 		SLE_ARR(LoggedChange, grfadd.md5sum,     SLE_UINT8,  16),
121 	};
122 	inline const static SaveLoadCompatTable compat_description = _gamelog_grfadd_sl_compat;
123 
Save(LoggedChange * lc) const124 	void Save(LoggedChange *lc) const override
125 	{
126 		if (lc->ct != GLCT_GRFADD) return;
127 		SlObject(lc, this->GetDescription());
128 	}
129 
Load(LoggedChange * lc) const130 	void Load(LoggedChange *lc) const override
131 	{
132 		if (lc->ct != GLCT_GRFADD) return;
133 		SlObject(lc, this->GetLoadDescription());
134 	}
135 
LoadCheck(LoggedChange * lc) const136 	void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
137 };
138 
139 class SlGamelogGrfrem : public DefaultSaveLoadHandler<SlGamelogGrfrem, LoggedChange> {
140 public:
141 	inline static const SaveLoad description[] = {
142 		SLE_VAR(LoggedChange, grfrem.grfid,      SLE_UINT32),
143 	};
144 	inline const static SaveLoadCompatTable compat_description = _gamelog_grfrem_sl_compat;
145 
Save(LoggedChange * lc) const146 	void Save(LoggedChange *lc) const override
147 	{
148 		if (lc->ct != GLCT_GRFREM) return;
149 		SlObject(lc, this->GetDescription());
150 	}
151 
Load(LoggedChange * lc) const152 	void Load(LoggedChange *lc) const override
153 	{
154 		if (lc->ct != GLCT_GRFREM) return;
155 		SlObject(lc, this->GetLoadDescription());
156 	}
157 
LoadCheck(LoggedChange * lc) const158 	void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
159 };
160 
161 class SlGamelogGrfcompat : public DefaultSaveLoadHandler<SlGamelogGrfcompat, LoggedChange> {
162 public:
163 	inline static const SaveLoad description[] = {
164 		SLE_VAR(LoggedChange, grfcompat.grfid,   SLE_UINT32    ),
165 		SLE_ARR(LoggedChange, grfcompat.md5sum,  SLE_UINT8,  16),
166 	};
167 	inline const static SaveLoadCompatTable compat_description = _gamelog_grfcompat_sl_compat;
168 
Save(LoggedChange * lc) const169 	void Save(LoggedChange *lc) const override
170 	{
171 		if (lc->ct != GLCT_GRFCOMPAT) return;
172 		SlObject(lc, this->GetDescription());
173 	}
174 
Load(LoggedChange * lc) const175 	void Load(LoggedChange *lc) const override
176 	{
177 		if (lc->ct != GLCT_GRFCOMPAT) return;
178 		SlObject(lc, this->GetLoadDescription());
179 	}
180 
LoadCheck(LoggedChange * lc) const181 	void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
182 };
183 
184 class SlGamelogGrfparam : public DefaultSaveLoadHandler<SlGamelogGrfparam, LoggedChange> {
185 public:
186 	inline static const SaveLoad description[] = {
187 		SLE_VAR(LoggedChange, grfparam.grfid,    SLE_UINT32),
188 	};
189 	inline const static SaveLoadCompatTable compat_description = _gamelog_grfparam_sl_compat;
190 
Save(LoggedChange * lc) const191 	void Save(LoggedChange *lc) const override
192 	{
193 		if (lc->ct != GLCT_GRFPARAM) return;
194 		SlObject(lc, this->GetDescription());
195 	}
196 
Load(LoggedChange * lc) const197 	void Load(LoggedChange *lc) const override
198 	{
199 		if (lc->ct != GLCT_GRFPARAM) return;
200 		SlObject(lc, this->GetLoadDescription());
201 	}
202 
LoadCheck(LoggedChange * lc) const203 	void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
204 };
205 
206 class SlGamelogGrfmove : public DefaultSaveLoadHandler<SlGamelogGrfmove, LoggedChange> {
207 public:
208 	inline static const SaveLoad description[] = {
209 		SLE_VAR(LoggedChange, grfmove.grfid,     SLE_UINT32),
210 		SLE_VAR(LoggedChange, grfmove.offset,    SLE_INT32),
211 	};
212 	inline const static SaveLoadCompatTable compat_description = _gamelog_grfmove_sl_compat;
213 
Save(LoggedChange * lc) const214 	void Save(LoggedChange *lc) const override
215 	{
216 		if (lc->ct != GLCT_GRFMOVE) return;
217 		SlObject(lc, this->GetDescription());
218 	}
219 
Load(LoggedChange * lc) const220 	void Load(LoggedChange *lc) const override
221 	{
222 		if (lc->ct != GLCT_GRFMOVE) return;
223 		SlObject(lc, this->GetLoadDescription());
224 	}
225 
LoadCheck(LoggedChange * lc) const226 	void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
227 };
228 
229 class SlGamelogGrfbug : public DefaultSaveLoadHandler<SlGamelogGrfbug, LoggedChange> {
230 public:
231 	inline static const SaveLoad description[] = {
232 		SLE_VAR(LoggedChange, grfbug.data,       SLE_UINT64),
233 		SLE_VAR(LoggedChange, grfbug.grfid,      SLE_UINT32),
234 		SLE_VAR(LoggedChange, grfbug.bug,        SLE_UINT8),
235 	};
236 	inline const static SaveLoadCompatTable compat_description = _gamelog_grfbug_sl_compat;
237 
Save(LoggedChange * lc) const238 	void Save(LoggedChange *lc) const override
239 	{
240 		if (lc->ct != GLCT_GRFBUG) return;
241 		SlObject(lc, this->GetDescription());
242 	}
243 
Load(LoggedChange * lc) const244 	void Load(LoggedChange *lc) const override
245 	{
246 		if (lc->ct != GLCT_GRFBUG) return;
247 		SlObject(lc, this->GetLoadDescription());
248 	}
249 
LoadCheck(LoggedChange * lc) const250 	void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
251 };
252 
253 static bool _is_emergency_save = true;
254 
255 class SlGamelogEmergency : public DefaultSaveLoadHandler<SlGamelogEmergency, LoggedChange> {
256 public:
257 	/* We need to store something, so store a "true" value. */
258 	inline static const SaveLoad description[] = {
259 		SLEG_CONDVAR("is_emergency_save", _is_emergency_save, SLE_BOOL, SLV_RIFF_TO_ARRAY, SL_MAX_VERSION),
260 	};
261 	inline const static SaveLoadCompatTable compat_description = _gamelog_emergency_sl_compat;
262 
Save(LoggedChange * lc) const263 	void Save(LoggedChange *lc) const override
264 	{
265 		if (lc->ct != GLCT_EMERGENCY) return;
266 
267 		_is_emergency_save = true;
268 		SlObject(lc, this->GetDescription());
269 	}
270 
Load(LoggedChange * lc) const271 	void Load(LoggedChange *lc) const override
272 	{
273 		if (lc->ct != GLCT_EMERGENCY) return;
274 
275 		SlObject(lc, this->GetLoadDescription());
276 	}
277 
LoadCheck(LoggedChange * lc) const278 	void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
279 };
280 
281 class SlGamelogAction : public DefaultSaveLoadHandler<SlGamelogAction, LoggedAction> {
282 public:
283 	inline static const SaveLoad description[] = {
284 		SLE_SAVEBYTE(LoggedChange, ct),
285 		SLEG_STRUCT("mode", SlGamelogMode),
286 		SLEG_STRUCT("revision", SlGamelogRevision),
287 		SLEG_STRUCT("oldver", SlGamelogOldver),
288 		SLEG_STRUCT("setting", SlGamelogSetting),
289 		SLEG_STRUCT("grfadd", SlGamelogGrfadd),
290 		SLEG_STRUCT("grfrem", SlGamelogGrfrem),
291 		SLEG_STRUCT("grfcompat", SlGamelogGrfcompat),
292 		SLEG_STRUCT("grfparam", SlGamelogGrfparam),
293 		SLEG_STRUCT("grfmove", SlGamelogGrfmove),
294 		SLEG_STRUCT("grfbug", SlGamelogGrfbug),
295 		SLEG_STRUCT("emergency", SlGamelogEmergency),
296 	};
297 	inline const static SaveLoadCompatTable compat_description = _gamelog_action_sl_compat;
298 
Save(LoggedAction * la) const299 	void Save(LoggedAction *la) const override
300 	{
301 		SlSetStructListLength(la->changes);
302 
303 		const LoggedChange *lcend = &la->change[la->changes];
304 		for (LoggedChange *lc = la->change; lc != lcend; lc++) {
305 			assert((uint)lc->ct < GLCT_END);
306 			SlObject(lc, this->GetDescription());
307 		}
308 	}
309 
Load(LoggedAction * la) const310 	void Load(LoggedAction *la) const override
311 	{
312 		if (IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY)) {
313 			byte type;
314 			while ((type = SlReadByte()) != GLCT_NONE) {
315 				if (type >= GLCT_END) SlErrorCorrupt("Invalid gamelog change type");
316 				GamelogChangeType ct = (GamelogChangeType)type;
317 
318 				la->change = ReallocT(la->change, la->changes + 1);
319 
320 				LoggedChange *lc = &la->change[la->changes++];
321 				memset(lc, 0, sizeof(*lc));
322 				lc->ct = ct;
323 
324 				SlObject(lc, this->GetLoadDescription());
325 			}
326 			return;
327 		}
328 
329 		size_t length = SlGetStructListLength(UINT32_MAX);
330 		la->change = ReallocT(la->change, length);
331 
332 		for (size_t i = 0; i < length; i++) {
333 			LoggedChange *lc = &la->change[i];
334 			memset(lc, 0, sizeof(*lc));
335 
336 			lc->ct = (GamelogChangeType)SlReadByte();
337 			SlObject(lc, this->GetLoadDescription());
338 		}
339 	}
340 
LoadCheck(LoggedAction * la) const341 	void LoadCheck(LoggedAction *la) const override { this->Load(la); }
342 };
343 
344 static const SaveLoad _gamelog_desc[] = {
345 	SLE_CONDVAR(LoggedAction, at,            SLE_UINT8,   SLV_RIFF_TO_ARRAY, SL_MAX_VERSION),
346 	SLE_VAR(LoggedAction, tick,              SLE_UINT16),
347 	SLEG_STRUCTLIST("action", SlGamelogAction),
348 };
349 
350 struct GLOGChunkHandler : ChunkHandler {
GLOGChunkHandlerGLOGChunkHandler351 	GLOGChunkHandler() : ChunkHandler('GLOG', CH_TABLE) {}
352 
LoadCommonGLOGChunkHandler353 	void LoadCommon(LoggedAction *&gamelog_action, uint &gamelog_actions) const
354 	{
355 		assert(gamelog_action == nullptr);
356 		assert(gamelog_actions == 0);
357 
358 		const std::vector<SaveLoad> slt = SlCompatTableHeader(_gamelog_desc, _gamelog_sl_compat);
359 
360 		if (IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY)) {
361 			byte type;
362 			while ((type = SlReadByte()) != GLAT_NONE) {
363 				if (type >= GLAT_END) SlErrorCorrupt("Invalid gamelog action type");
364 
365 				gamelog_action = ReallocT(gamelog_action, gamelog_actions + 1);
366 				LoggedAction *la = &gamelog_action[gamelog_actions++];
367 				memset(la, 0, sizeof(*la));
368 
369 				la->at = (GamelogActionType)type;
370 				SlObject(la, slt);
371 			}
372 			return;
373 		}
374 
375 		while (SlIterateArray() != -1) {
376 			gamelog_action = ReallocT(gamelog_action, gamelog_actions + 1);
377 			LoggedAction *la = &gamelog_action[gamelog_actions++];
378 			memset(la, 0, sizeof(*la));
379 
380 			SlObject(la, slt);
381 		}
382 	}
383 
SaveGLOGChunkHandler384 	void Save() const override
385 	{
386 		SlTableHeader(_gamelog_desc);
387 
388 		const LoggedAction *laend = &_gamelog_action[_gamelog_actions];
389 
390 		uint i = 0;
391 		for (LoggedAction *la = _gamelog_action; la != laend; la++, i++) {
392 			SlSetArrayIndex(i);
393 			SlObject(la, _gamelog_desc);
394 		}
395 	}
396 
LoadGLOGChunkHandler397 	void Load() const override
398 	{
399 		this->LoadCommon(_gamelog_action, _gamelog_actions);
400 	}
401 
LoadCheckGLOGChunkHandler402 	void LoadCheck(size_t) const override
403 	{
404 		this->LoadCommon(_load_check_data.gamelog_action, _load_check_data.gamelog_actions);
405 	}
406 };
407 
408 static const GLOGChunkHandler GLOG;
409 static const ChunkHandlerRef gamelog_chunk_handlers[] = {
410 	GLOG,
411 };
412 
413 extern const ChunkHandlerTable _gamelog_chunk_handlers(gamelog_chunk_handlers);
414