/* * This file is part of OpenTTD. * 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. * 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. * 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 . */ /** @file settings_sl.cpp Handles the saveload part of the settings. */ #include "../stdafx.h" #include "saveload.h" #include "debug.h" #include "compat/settings_sl_compat.h" #include "../settings_type.h" #include "../settings_internal.h" #include "../network/network.h" #include "../fios.h" #include "../load_check.h" #include "../safeguards.h" namespace upstream_sl { /** * Get the SaveLoad description for the SettingTable. * @param settings SettingDesc struct containing all information. * @param is_loading True iff the SaveLoad table is for loading. * @return Vector with SaveLoad entries for the SettingTable. */ static std::vector GetSettingsDesc(bool is_loading) { std::vector saveloads; for (auto &sd : IterateSettingTables(GetSaveLoadSettingsTables())) { if (sd->flags & SF_NOT_IN_SAVE) continue; if (is_loading && !SlXvIsFeaturePresent(XSLFI_TABLE_PATS) && (sd->flags & SF_PATCH)) continue; if (!sd->save.ext_feature_test.IsFeaturePresent(_sl_version, sd->save.version_from, sd->save.version_to)) continue; VarType new_type = 0; switch (sd->save.conv & 0x0F) { case ::SLE_FILE_I8: new_type |= SLE_FILE_I8; break; case ::SLE_FILE_U8: new_type |= SLE_FILE_U8; break; case ::SLE_FILE_I16: new_type |= SLE_FILE_I16; break; case ::SLE_FILE_U16: new_type |= SLE_FILE_U16; break; case ::SLE_FILE_I32: new_type |= SLE_FILE_I32; break; case ::SLE_FILE_U32: new_type |= SLE_FILE_U32; break; case ::SLE_FILE_I64: new_type |= SLE_FILE_I64; break; case ::SLE_FILE_U64: new_type |= SLE_FILE_U64; break; case ::SLE_FILE_STRINGID: new_type |= SLE_FILE_STRINGID; break; case ::SLE_FILE_STRING: new_type |= SLE_FILE_STRING; break; default: error("Unexpected save conv for %s: 0x%02X", sd->name, sd->save.conv); } switch (sd->save.conv & 0xF0) { case ::SLE_VAR_BL: new_type |= SLE_VAR_BL; break; case ::SLE_VAR_I8: new_type |= SLE_VAR_I8; break; case ::SLE_VAR_U8: new_type |= SLE_VAR_U8; break; case ::SLE_VAR_I16: new_type |= SLE_VAR_I16; break; case ::SLE_VAR_U16: new_type |= SLE_VAR_U16; break; case ::SLE_VAR_I32: new_type |= SLE_VAR_I32; break; case ::SLE_VAR_U32: new_type |= SLE_VAR_U32; break; case ::SLE_VAR_I64: new_type |= SLE_VAR_I64; break; case ::SLE_VAR_U64: new_type |= SLE_VAR_U64; break; case ::SLE_VAR_NULL: new_type |= SLE_VAR_NULL; break; case ::SLE_VAR_STRB: new_type |= SLE_VAR_STRB; break; case ::SLE_VAR_STR: new_type |= SLE_VAR_STR; break; case ::SLE_VAR_STRQ: new_type |= SLE_VAR_STRQ; break; default: error("Unexpected save conv for %s: 0x%02X", sd->name, sd->save.conv); } /* economy.town_growth_rate is int8_t here, but uint8_t in upstream saves */ if (is_loading && !SlXvIsFeaturePresent(XSLFI_TABLE_PATS) && strcmp(sd->name, "economy.town_growth_rate") == 0) { SB(new_type, 0, 4, SLE_FILE_U8); } SaveLoadType new_cmd; switch (sd->save.cmd) { case ::SL_VAR: new_cmd = SL_VAR; break; case ::SL_STR: new_cmd = SL_STR; break; case ::SL_STDSTR: new_cmd = SL_STDSTR; break; default: error("Unexpected save cmd for %s: %u", sd->name, sd->save.cmd); } if (is_loading && (sd->flags & SF_NO_NETWORK_SYNC) && _networking && !_network_server) { if (IsSavegameVersionBefore(SLV_TABLE_CHUNKS)) { /* We don't want to read this setting, so we do need to skip over it. */ saveloads.push_back({sd->name, new_cmd, GetVarFileType(new_type) | SLE_VAR_NULL, sd->save.length, SL_MIN_VERSION, SL_MAX_VERSION, 0, nullptr, 0, nullptr}); } continue; } SaveLoadAddrProc *address_proc = [](void *base, size_t extra) -> void* { return const_cast((const byte *)base + (ptrdiff_t)extra); }; saveloads.push_back({sd->name, new_cmd, new_type, sd->save.length, SL_MIN_VERSION, SL_MAX_VERSION, sd->save.size, address_proc, reinterpret_cast(sd->save.address), nullptr}); } return saveloads; } /** * Save and load handler for settings * @param settings SettingDesc struct containing all information * @param object can be either nullptr in which case we load global variables or * a pointer to a struct which is getting saved */ static void LoadSettings(void *object, const SaveLoadCompatTable &slct) { const std::vector slt = SlCompatTableHeader(GetSettingsDesc(true), slct); if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() == -1) return; SlObject(object, slt); if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many settings entries"); /* Ensure all IntSettings are valid (min/max could have changed between versions etc). */ for (auto &sd : IterateSettingTables(GetSaveLoadSettingsTables())) { if (sd->flags & SF_NOT_IN_SAVE) continue; if ((sd->flags & SF_NO_NETWORK_SYNC) && _networking && !_network_server) continue; if (!sd->save.ext_feature_test.IsFeaturePresent(_sl_xv_feature_static_versions, MAX_LOAD_SAVEGAME_VERSION, sd->save.version_from, sd->save.version_to)) continue; if (sd->IsIntSetting()) { const IntSettingDesc *int_setting = sd->AsIntSetting(); int_setting->MakeValueValidAndWrite(object, int_setting->Read(object)); } } } /** * Save and load handler for settings * @param settings SettingDesc struct containing all information * @param object can be either nullptr in which case we load global variables or * a pointer to a struct which is getting saved */ static void SaveSettings(void *object) { const std::vector slt = GetSettingsDesc(false); SlTableHeader(slt); SlSetArrayIndex(0); SlObject(object, slt); } struct PATSChunkHandler : ChunkHandler { PATSChunkHandler() : ChunkHandler('PATS', CH_TABLE) {} void Load() const override { /* Settings were previously reset to their defaults, so any settings missing in the savegame * are their default, and not "value of last game". AfterLoad might still fix * up values to become non-default, depending on the saveload version. */ LoadSettings(&_settings_game, _settings_sl_compat); } void LoadCheck(size_t) const override { LoadSettings(&_load_check_data.settings, _settings_sl_compat); } void Save() const override { SaveSettings(&_settings_game); } }; static const PATSChunkHandler PATS; static const ChunkHandlerRef setting_chunk_handlers[] = { PATS, }; extern const ChunkHandlerTable _setting_chunk_handlers(setting_chunk_handlers); }