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