diff --git a/src/gamelog.h b/src/gamelog.h index d9e0dd529e..cfa6c626a2 100644 --- a/src/gamelog.h +++ b/src/gamelog.h @@ -13,7 +13,7 @@ #include "newgrf_config.h" /** The actions we log. */ -enum GamelogActionType { +enum GamelogActionType : uint8 { GLAT_START, ///< Game created GLAT_LOAD, ///< Game loaded GLAT_GRF, ///< GRF changed diff --git a/src/gamelog_internal.h b/src/gamelog_internal.h index 2b5c6ed0a1..fb7c88e48c 100644 --- a/src/gamelog_internal.h +++ b/src/gamelog_internal.h @@ -13,7 +13,7 @@ #include "gamelog.h" /** Type of logged change */ -enum GamelogChangeType { +enum GamelogChangeType : uint8 { GLCT_MODE, ///< Scenario editor x Game, different landscape GLCT_REVISION, ///< Changed game revision string GLCT_OLDVER, ///< Loaded from savegame without logged data diff --git a/src/saveload/gamelog_sl.cpp b/src/saveload/gamelog_sl.cpp index 6569954f87..9f7f4f140d 100644 --- a/src/saveload/gamelog_sl.cpp +++ b/src/saveload/gamelog_sl.cpp @@ -15,147 +15,317 @@ #include "../safeguards.h" -static const SaveLoad _glog_action_desc[] = { + +class SlGamelogMode : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_VAR(LoggedChange, mode.mode, SLE_UINT8), + SLE_VAR(LoggedChange, mode.landscape, SLE_UINT8), + }; + + void GenericSaveLoad(LoggedChange *lc) const + { + if (lc->ct != GLCT_MODE) return; + SlObject(lc, this->GetDescription()); + } + + void Save(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } + void Load(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } + void LoadCheck(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } +}; + +class SlGamelogRevision : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_ARR(LoggedChange, revision.text, SLE_UINT8, GAMELOG_REVISION_LENGTH), + SLE_VAR(LoggedChange, revision.newgrf, SLE_UINT32), + SLE_VAR(LoggedChange, revision.slver, SLE_UINT16), + SLE_VAR(LoggedChange, revision.modified, SLE_UINT8), + }; + + void GenericSaveLoad(LoggedChange *lc) const + { + if (lc->ct != GLCT_REVISION) return; + SlObject(lc, this->GetDescription()); + } + + void Save(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } + void Load(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } + void LoadCheck(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } +}; + +class SlGamelogOldver : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_VAR(LoggedChange, oldver.type, SLE_UINT32), + SLE_VAR(LoggedChange, oldver.version, SLE_UINT32), + }; + + void GenericSaveLoad(LoggedChange *lc) const + { + if (lc->ct != GLCT_OLDVER) return; + SlObject(lc, this->GetDescription()); + } + + void Save(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } + void Load(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } + void LoadCheck(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } +}; + +class SlGamelogSetting : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_STR(LoggedChange, setting.name, SLE_STR, 128), + SLE_VAR(LoggedChange, setting.oldval, SLE_INT32), + SLE_VAR(LoggedChange, setting.newval, SLE_INT32), + }; + + void GenericSaveLoad(LoggedChange *lc) const + { + if (lc->ct != GLCT_SETTING) return; + SlObject(lc, this->GetDescription()); + } + + void Save(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } + void Load(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } + void LoadCheck(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } +}; + +class SlGamelogGrfadd : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_VAR(LoggedChange, grfadd.grfid, SLE_UINT32 ), + SLE_ARR(LoggedChange, grfadd.md5sum, SLE_UINT8, 16), + }; + + void GenericSaveLoad(LoggedChange *lc) const + { + if (lc->ct != GLCT_GRFADD) return; + SlObject(lc, this->GetDescription()); + } + + void Save(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } + void Load(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } + void LoadCheck(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } +}; + +class SlGamelogGrfrem : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_VAR(LoggedChange, grfrem.grfid, SLE_UINT32), + }; + + void GenericSaveLoad(LoggedChange *lc) const + { + if (lc->ct != GLCT_GRFREM) return; + SlObject(lc, this->GetDescription()); + } + + void Save(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } + void Load(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } + void LoadCheck(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } +}; + +class SlGamelogGrfcompat : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_VAR(LoggedChange, grfcompat.grfid, SLE_UINT32 ), + SLE_ARR(LoggedChange, grfcompat.md5sum, SLE_UINT8, 16), + }; + + void GenericSaveLoad(LoggedChange *lc) const + { + if (lc->ct != GLCT_GRFCOMPAT) return; + SlObject(lc, this->GetDescription()); + } + + void Save(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } + void Load(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } + void LoadCheck(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } +}; + +class SlGamelogGrfparam : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_VAR(LoggedChange, grfparam.grfid, SLE_UINT32), + }; + + void GenericSaveLoad(LoggedChange *lc) const + { + if (lc->ct != GLCT_GRFPARAM) return; + SlObject(lc, this->GetDescription()); + } + + void Save(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } + void Load(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } + void LoadCheck(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } +}; + +class SlGamelogGrfmove : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_VAR(LoggedChange, grfmove.grfid, SLE_UINT32), + SLE_VAR(LoggedChange, grfmove.offset, SLE_INT32), + }; + + void GenericSaveLoad(LoggedChange *lc) const + { + if (lc->ct != GLCT_GRFMOVE) return; + SlObject(lc, this->GetDescription()); + } + + void Save(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } + void Load(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } + void LoadCheck(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } +}; + +class SlGamelogGrfbug : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_VAR(LoggedChange, grfbug.data, SLE_UINT64), + SLE_VAR(LoggedChange, grfbug.grfid, SLE_UINT32), + SLE_VAR(LoggedChange, grfbug.bug, SLE_UINT8), + }; + + void GenericSaveLoad(LoggedChange *lc) const + { + if (lc->ct != GLCT_GRFBUG) return; + SlObject(lc, this->GetDescription()); + } + + void Save(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } + void Load(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } + void LoadCheck(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } +}; + +static bool _is_emergency_save = true; + +class SlGamelogEmergency : public DefaultSaveLoadHandler { +public: + /* We need to store something, so store a "true" value. */ + inline static const SaveLoad description[] = { + SLEG_CONDVAR(_is_emergency_save, SLE_BOOL, SLV_RIFF_TO_ARRAY, SL_MAX_VERSION), + }; + + void GenericSaveLoad(LoggedChange *lc) const + { + if (lc->ct != GLCT_EMERGENCY) return; + + _is_emergency_save = true; + SlObject(lc, this->GetDescription()); + } + + void Save(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } + void Load(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } + void LoadCheck(LoggedChange *lc) const override { this->GenericSaveLoad(lc); } +}; + +class SlGamelogAction : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_SAVEBYTE(LoggedChange, ct), + SLEG_STRUCT(SlGamelogMode), + SLEG_STRUCT(SlGamelogRevision), + SLEG_STRUCT(SlGamelogOldver), + SLEG_STRUCT(SlGamelogSetting), + SLEG_STRUCT(SlGamelogGrfadd), + SLEG_STRUCT(SlGamelogGrfrem), + SLEG_STRUCT(SlGamelogGrfcompat), + SLEG_STRUCT(SlGamelogGrfparam), + SLEG_STRUCT(SlGamelogGrfmove), + SLEG_STRUCT(SlGamelogGrfbug), + SLEG_STRUCT(SlGamelogEmergency), + }; + + void Save(LoggedAction *la) const override + { + SlSetStructListLength(la->changes); + + const LoggedChange *lcend = &la->change[la->changes]; + for (LoggedChange *lc = la->change; lc != lcend; lc++) { + assert((uint)lc->ct < GLCT_END); + SlObject(lc, this->GetDescription()); + } + } + + void Load(LoggedAction *la) const override + { + if (IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY)) { + byte type; + while ((type = SlReadByte()) != GLCT_NONE) { + if (type >= GLCT_END) SlErrorCorrupt("Invalid gamelog change type"); + GamelogChangeType ct = (GamelogChangeType)type; + + la->change = ReallocT(la->change, la->changes + 1); + + LoggedChange *lc = &la->change[la->changes++]; + memset(lc, 0, sizeof(*lc)); + lc->ct = ct; + + SlObject(lc, this->GetDescription()); + } + return; + } + + size_t length = SlGetStructListLength(UINT32_MAX); + la->change = ReallocT(la->change, length); + + for (size_t i = 0; i < length; i++) { + LoggedChange *lc = &la->change[i]; + memset(lc, 0, sizeof(*lc)); + + lc->ct = (GamelogChangeType)SlReadByte(); + SlObject(lc, this->GetDescription()); + } + } + + void LoadCheck(LoggedAction *la) const override { this->Load(la); } +}; + +static const SaveLoad _gamelog_desc[] = { + SLE_CONDVAR(LoggedAction, at, SLE_UINT8, SLV_RIFF_TO_ARRAY, SL_MAX_VERSION), SLE_VAR(LoggedAction, tick, SLE_UINT16), + SLEG_STRUCTLIST(SlGamelogAction), }; -static const SaveLoad _glog_mode_desc[] = { - SLE_VAR(LoggedChange, mode.mode, SLE_UINT8), - SLE_VAR(LoggedChange, mode.landscape, SLE_UINT8), -}; - -static const SaveLoad _glog_revision_desc[] = { - SLE_ARR(LoggedChange, revision.text, SLE_UINT8, GAMELOG_REVISION_LENGTH), - SLE_VAR(LoggedChange, revision.newgrf, SLE_UINT32), - SLE_VAR(LoggedChange, revision.slver, SLE_UINT16), - SLE_VAR(LoggedChange, revision.modified, SLE_UINT8), -}; - -static const SaveLoad _glog_oldver_desc[] = { - SLE_VAR(LoggedChange, oldver.type, SLE_UINT32), - SLE_VAR(LoggedChange, oldver.version, SLE_UINT32), -}; - -static const SaveLoad _glog_setting_desc[] = { - SLE_STR(LoggedChange, setting.name, SLE_STR, 128), - SLE_VAR(LoggedChange, setting.oldval, SLE_INT32), - SLE_VAR(LoggedChange, setting.newval, SLE_INT32), -}; - -static const SaveLoad _glog_grfadd_desc[] = { - SLE_VAR(LoggedChange, grfadd.grfid, SLE_UINT32 ), - SLE_ARR(LoggedChange, grfadd.md5sum, SLE_UINT8, 16), -}; - -static const SaveLoad _glog_grfrem_desc[] = { - SLE_VAR(LoggedChange, grfrem.grfid, SLE_UINT32), -}; - -static const SaveLoad _glog_grfcompat_desc[] = { - SLE_VAR(LoggedChange, grfcompat.grfid, SLE_UINT32 ), - SLE_ARR(LoggedChange, grfcompat.md5sum, SLE_UINT8, 16), -}; - -static const SaveLoad _glog_grfparam_desc[] = { - SLE_VAR(LoggedChange, grfparam.grfid, SLE_UINT32), -}; - -static const SaveLoad _glog_grfmove_desc[] = { - SLE_VAR(LoggedChange, grfmove.grfid, SLE_UINT32), - SLE_VAR(LoggedChange, grfmove.offset, SLE_INT32), -}; - -static const SaveLoad _glog_grfbug_desc[] = { - SLE_VAR(LoggedChange, grfbug.data, SLE_UINT64), - SLE_VAR(LoggedChange, grfbug.grfid, SLE_UINT32), - SLE_VAR(LoggedChange, grfbug.bug, SLE_UINT8), -}; - -static const SaveLoad _glog_emergency_desc[] = { - SLE_CONDNULL(0, SL_MIN_VERSION, SL_MIN_VERSION), // Just an empty list, to keep the rest of the code easier. -}; - -static const SaveLoadTable _glog_desc[] = { - _glog_mode_desc, - _glog_revision_desc, - _glog_oldver_desc, - _glog_setting_desc, - _glog_grfadd_desc, - _glog_grfrem_desc, - _glog_grfcompat_desc, - _glog_grfparam_desc, - _glog_grfmove_desc, - _glog_grfbug_desc, - _glog_emergency_desc, -}; - -static_assert(lengthof(_glog_desc) == GLCT_END); - static void Load_GLOG_common(LoggedAction *&gamelog_action, uint &gamelog_actions) { assert(gamelog_action == nullptr); assert(gamelog_actions == 0); - byte type; - while ((type = SlReadByte()) != GLAT_NONE) { - if (type >= GLAT_END) SlErrorCorrupt("Invalid gamelog action type"); - GamelogActionType at = (GamelogActionType)type; + if (IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY)) { + byte type; + while ((type = SlReadByte()) != GLAT_NONE) { + if (type >= GLAT_END) SlErrorCorrupt("Invalid gamelog action type"); + gamelog_action = ReallocT(gamelog_action, gamelog_actions + 1); + LoggedAction *la = &gamelog_action[gamelog_actions++]; + memset(la, 0, sizeof(*la)); + + la->at = (GamelogActionType)type; + SlObject(la, _gamelog_desc); + } + return; + } + + while (SlIterateArray() != -1) { gamelog_action = ReallocT(gamelog_action, gamelog_actions + 1); LoggedAction *la = &gamelog_action[gamelog_actions++]; + memset(la, 0, sizeof(*la)); - la->at = at; - - SlObject(la, _glog_action_desc); // has to be saved after 'DATE'! - la->change = nullptr; - la->changes = 0; - - while ((type = SlReadByte()) != GLCT_NONE) { - if (type >= GLCT_END) SlErrorCorrupt("Invalid gamelog change type"); - GamelogChangeType ct = (GamelogChangeType)type; - - la->change = ReallocT(la->change, la->changes + 1); - - LoggedChange *lc = &la->change[la->changes++]; - /* for SLE_STR, pointer has to be valid! so make it nullptr */ - memset(lc, 0, sizeof(*lc)); - lc->ct = ct; - - SlObject(lc, _glog_desc[ct]); - } + SlObject(la, _gamelog_desc); } } static void Save_GLOG() { const LoggedAction *laend = &_gamelog_action[_gamelog_actions]; - size_t length = 0; - for (const LoggedAction *la = _gamelog_action; la != laend; la++) { - const LoggedChange *lcend = &la->change[la->changes]; - for (LoggedChange *lc = la->change; lc != lcend; lc++) { - assert((uint)lc->ct < lengthof(_glog_desc)); - length += SlCalcObjLength(lc, _glog_desc[lc->ct]) + 1; - } - length += 4; + uint i = 0; + for (LoggedAction *la = _gamelog_action; la != laend; la++, i++) { + SlSetArrayIndex(i); + SlObject(la, _gamelog_desc); } - length++; - - SlSetLength(length); - - for (LoggedAction *la = _gamelog_action; la != laend; la++) { - SlWriteByte(la->at); - SlObject(la, _glog_action_desc); - - const LoggedChange *lcend = &la->change[la->changes]; - for (LoggedChange *lc = la->change; lc != lcend; lc++) { - SlWriteByte(lc->ct); - assert((uint)lc->ct < GLCT_END); - SlObject(lc, _glog_desc[lc->ct]); - } - SlWriteByte(GLCT_NONE); - } - SlWriteByte(GLAT_NONE); } static void Load_GLOG() @@ -169,7 +339,7 @@ static void Check_GLOG() } static const ChunkHandler gamelog_chunk_handlers[] = { - { 'GLOG', Save_GLOG, Load_GLOG, nullptr, Check_GLOG, CH_RIFF } + { 'GLOG', Save_GLOG, Load_GLOG, nullptr, Check_GLOG, CH_ARRAY } }; extern const ChunkHandlerTable _gamelog_chunk_handlers(gamelog_chunk_handlers);