Move upstream saveload to src/saveload/, move jgrpp saveload to src/sl/

Leave afterload in src/saveload/
pull/532/head
Jonathan G Rennison 12 months ago
parent 3c9ce6f9a5
commit ac2f9a21e8

@ -20,6 +20,7 @@ add_subdirectory(network)
add_subdirectory(os)
add_subdirectory(pathfinder)
add_subdirectory(saveload)
add_subdirectory(sl)
add_subdirectory(sound)
add_subdirectory(spriteloader)
add_subdirectory(table)

@ -18,7 +18,7 @@
#include "vehicle_type.h"
#include "company_type.h"
#include "core/multimap.hpp"
#include "saveload/saveload_common.h"
#include "sl/saveload_common.h"
#include <deque>
/** Unique identifier for a single cargo packet. */

@ -13,7 +13,7 @@
#include "company_base.h"
#include "company_func.h"
#include "date_func.h"
#include "saveload/saveload.h"
#include "sl/saveload.h"
#include "textbuf_gui.h"
#include "window_gui.h"
#include "string_func.h"

@ -12,7 +12,7 @@
#include "debug.h"
#include "engine_func.h"
#include "landscape.h"
#include "saveload/saveload.h"
#include "sl/saveload.h"
#include "network/core/game_info.h"
#include "network/network.h"
#include "network/network_func.h"

@ -20,7 +20,7 @@
#include "music/music_driver.hpp"
#include "sound/sound_driver.hpp"
#include "video/video_driver.hpp"
#include "saveload/saveload.h"
#include "sl/saveload.h"
#include "screenshot.h"
#include "gfx_func.h"
#include "network/network.h"

@ -17,7 +17,7 @@
#include "vehicle_base.h"
#include "rail_gui.h"
#include "linkgraph/linkgraph.h"
#include "saveload/saveload.h"
#include "sl/saveload.h"
#include "newgrf_profiling.h"
#include "console_func.h"
#include "debug.h"

@ -8,7 +8,7 @@
/** @file fios_gui.cpp GUIs for loading/saving games, scenarios, heightmaps, ... */
#include "stdafx.h"
#include "saveload/saveload.h"
#include "sl/saveload.h"
#include "error.h"
#include "gui.h"
#include "gfx_func.h"

@ -8,7 +8,7 @@
/** @file gamelog.cpp Definition of functions used for logging of important changes in the game */
#include "stdafx.h"
#include "saveload/saveload.h"
#include "sl/saveload.h"
#include "string_func.h"
#include "settings_type.h"
#include "gamelog_internal.h"

@ -21,7 +21,7 @@
#include "water.h"
#include "video/video_driver.hpp"
#include "tilehighlight_func.h"
#include "saveload/saveload.h"
#include "sl/saveload.h"
#include "void_map.h"
#include "town.h"
#include "newgrf.h"

@ -25,7 +25,7 @@
#include "town.h"
#include "core/geometry_func.hpp"
#include "core/random_func.hpp"
#include "saveload/saveload.h"
#include "sl/saveload.h"
#include "progress.h"
#include "error.h"
#include "newgrf_townname.h"

@ -12,7 +12,7 @@
#include "clear_map.h"
#include "void_map.h"
#include "error.h"
#include "saveload/saveload.h"
#include "sl/saveload.h"
#include "bmp.h"
#include "gfx_func.h"
#include "fios.h"

@ -30,7 +30,7 @@
#include "company_func.h"
#include "tunnelbridge_map.h"
#include "pathfinder/npf/aystar.h"
#include "saveload/saveload.h"
#include "sl/saveload.h"
#include "framerate_type.h"
#include "town.h"
#include "3rdparty/cpp-btree/btree_set.h"

@ -16,7 +16,7 @@
#include "../station_base.h"
#include "../cargotype.h"
#include "../date_func.h"
#include "../saveload/saveload_common.h"
#include "../sl/saveload_common.h"
#include "linkgraph_type.h"
#include "../3rdparty/cpp-btree/btree_map.h"
#include <utility>

@ -34,7 +34,7 @@
#include "error.h"
#include "news_gui.h"
#include "saveload/saveload.h"
#include "sl/saveload.h"
#include "widgets/main_widget.h"

@ -9,8 +9,8 @@
#include "../stdafx.h"
#include "network_gui.h"
#include "../saveload/saveload.h"
#include "../saveload/saveload_filter.h"
#include "../sl/saveload.h"
#include "../sl/saveload_filter.h"
#include "../command_func.h"
#include "../console_func.h"
#include "../strings_func.h"

@ -18,8 +18,8 @@
#include "../console_func.h"
#include "../company_base.h"
#include "../command_func.h"
#include "../saveload/saveload.h"
#include "../saveload/saveload_filter.h"
#include "../sl/saveload.h"
#include "../sl/saveload_filter.h"
#include "../station_base.h"
#include "../genworld.h"
#include "../company_func.h"

@ -20,7 +20,7 @@
#include "gui.h"
#include "base_media_base.h"
#include "saveload/saveload.h"
#include "sl/saveload.h"
#include "company_func.h"
#include "command_func.h"
#include "news_func.h"

@ -16,7 +16,7 @@
#include "vehicle_type.h"
#include "base_consist.h"
#include "order_base.h"
#include "saveload/saveload_common.h"
#include "sl/saveload_common.h"
/** Unique identifier for an order backup. */
typedef uint8 OrderBackupID;

@ -20,7 +20,7 @@
#include "date_type.h"
#include "schdispatch.h"
#include "gfx_type.h"
#include "saveload/saveload_common.h"
#include "sl/saveload_common.h"
#include <memory>
#include <vector>

@ -11,7 +11,7 @@
#include "../../crashlog.h"
#include "../../string_func.h"
#include "../../gamelog.h"
#include "../../saveload/saveload.h"
#include "../../sl/saveload.h"
#include "../../thread.h"
#include "../../screenshot.h"
#include "../../debug.h"

@ -12,7 +12,7 @@
#include "../../crashlog_bfd.h"
#include "../../string_func.h"
#include "../../gamelog.h"
#include "../../saveload/saveload.h"
#include "../../sl/saveload.h"
#include <errno.h>
#include <signal.h>

@ -17,7 +17,7 @@
#include "../../fileio_func.h"
#include "../../strings_func.h"
#include "../../gamelog.h"
#include "../../saveload/saveload.h"
#include "../../sl/saveload.h"
#include "../../video/video_driver.hpp"
#include "../../screenshot.h"
#include "../../debug.h"

@ -1,4 +1,4 @@
add_subdirectory(upstream)
add_subdirectory(compat)
add_files(
afterload.cpp
@ -6,17 +6,13 @@ add_files(
airport_sl.cpp
animated_tile_sl.cpp
autoreplace_sl.cpp
bridge_signal_sl.cpp
cargomonitor_sl.cpp
cargopacket_sl.cpp
cheat_sl.cpp
company_sl.cpp
debug_sl.cpp
depot_sl.cpp
economy_sl.cpp
engine_sl.cpp
extended_ver_sl.cpp
extended_ver_sl.h
game_sl.cpp
gamelog_sl.cpp
goal_sl.cpp
@ -29,33 +25,16 @@ add_files(
misc_sl.cpp
newgrf_sl.cpp
newgrf_sl.h
newsignals_sl.cpp
object_sl.cpp
oldloader.cpp
oldloader.h
oldloader_sl.cpp
order_sl.cpp
plans_sl.cpp
saveload.cpp
saveload.h
saveload_buffer.h
saveload_common.h
saveload_filter.h
saveload_internal.h
saveload_types.h
signal_sl.cpp
settings_sl.cpp
signs_sl.cpp
station_sl.cpp
storage_sl.cpp
strings_sl.cpp
story_sl.cpp
subsidy_sl.cpp
tbtr_template_replacement_sl.cpp
tbtr_template_veh_sl.cpp
town_sl.cpp
tracerestrict_sl.cpp
train_speed_adaptation.cpp
tunnel_sl.cpp
vehicle_sl.cpp
waypoint_sl.cpp
)

@ -75,7 +75,7 @@
#include "../timer/timer_game_tick.h"
#include "saveload_internal.h"
#include "../sl/saveload_internal.h"
#include <signal.h>
#include <algorithm>

@ -8,9 +8,12 @@
/** @file ai_sl.cpp Handles the saveload part of the AIs */
#include "../stdafx.h"
#include "../company_base.h"
#include "../debug.h"
#include "saveload.h"
#include "compat/ai_sl_compat.h"
#include "../company_base.h"
#include "../string_func.h"
#include "../ai/ai.hpp"
@ -20,16 +23,18 @@
#include "../safeguards.h"
namespace upstream_sl {
static std::string _ai_saveload_name;
static int _ai_saveload_version;
static std::string _ai_saveload_settings;
static bool _ai_saveload_is_random;
static const SaveLoad _ai_company[] = {
SLEG_SSTR(_ai_saveload_name, SLE_STR),
SLEG_SSTR(_ai_saveload_settings, SLE_STR),
SLEG_CONDVAR(_ai_saveload_version, SLE_UINT32, SLV_108, SL_MAX_VERSION),
SLEG_CONDVAR(_ai_saveload_is_random, SLE_BOOL, SLV_136, SL_MAX_VERSION),
static const SaveLoad _ai_company_desc[] = {
SLEG_SSTR("name", _ai_saveload_name, SLE_STR),
SLEG_SSTR("settings", _ai_saveload_settings, SLE_STR),
SLEG_CONDVAR("version", _ai_saveload_version, SLE_UINT32, SLV_108, SL_MAX_VERSION),
SLEG_CONDVAR("is_random", _ai_saveload_is_random, SLE_BOOL, SLV_136, SL_MAX_VERSION),
};
static void SaveReal_AIPL(int *index_ptr)
@ -49,76 +54,87 @@ static void SaveReal_AIPL(int *index_ptr)
_ai_saveload_is_random = config->IsRandom();
_ai_saveload_settings = config->SettingsToString();
SlObject(nullptr, _ai_company);
SlObject(nullptr, _ai_company_desc);
/* If the AI was active, store its data too */
if (Company::IsValidAiID(index)) AI::Save(index);
}
static void Load_AIPL()
{
/* Free all current data */
for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
AIConfig::GetConfig(c, AIConfig::SSS_FORCE_GAME)->Change(nullptr);
}
CompanyID index;
while ((index = (CompanyID)SlIterateArray()) != (CompanyID)-1) {
if (index >= MAX_COMPANIES) SlErrorCorrupt("Too many AI configs");
struct AIPLChunkHandler : ChunkHandler {
AIPLChunkHandler() : ChunkHandler('AIPL', CH_TABLE) {}
_ai_saveload_is_random = false;
_ai_saveload_version = -1;
SlObject(nullptr, _ai_company);
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_ai_company_desc, _ai_company_sl_compat);
if (_game_mode == GM_MENU || (_networking && !_network_server)) {
if (Company::IsValidAiID(index)) AIInstance::LoadEmpty();
continue;
/* Free all current data */
for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
AIConfig::GetConfig(c, AIConfig::SSS_FORCE_GAME)->Change(nullptr);
}
AIConfig *config = AIConfig::GetConfig(index, AIConfig::SSS_FORCE_GAME);
if (_ai_saveload_name.empty()) {
/* A random AI. */
config->Change(nullptr, -1, false, true);
} else {
config->Change(_ai_saveload_name.c_str(), _ai_saveload_version, false, _ai_saveload_is_random);
if (!config->HasScript()) {
/* No version of the AI available that can load the data. Try to load the
* latest version of the AI instead. */
config->Change(_ai_saveload_name.c_str(), -1, false, _ai_saveload_is_random);
CompanyID index;
while ((index = (CompanyID)SlIterateArray()) != (CompanyID)-1) {
if (index >= MAX_COMPANIES) SlErrorCorrupt("Too many AI configs");
_ai_saveload_is_random = false;
_ai_saveload_version = -1;
SlObject(nullptr, slt);
if (_game_mode == GM_MENU || (_networking && !_network_server)) {
if (Company::IsValidAiID(index)) AIInstance::LoadEmpty();
continue;
}
AIConfig *config = AIConfig::GetConfig(index, AIConfig::SSS_FORCE_GAME);
if (_ai_saveload_name.empty()) {
/* A random AI. */
config->Change(nullptr, -1, false, true);
} else {
config->Change(_ai_saveload_name.c_str(), _ai_saveload_version, false, _ai_saveload_is_random);
if (!config->HasScript()) {
if (_ai_saveload_name.compare("%_dummy") != 0) {
DEBUG(script, 0, "The savegame has an AI by the name '%s', version %d which is no longer available.", _ai_saveload_name.c_str(), _ai_saveload_version);
DEBUG(script, 0, "A random other AI will be loaded in its place.");
/* No version of the AI available that can load the data. Try to load the
* latest version of the AI instead. */
config->Change(_ai_saveload_name.c_str(), -1, false, _ai_saveload_is_random);
if (!config->HasScript()) {
if (_ai_saveload_name.compare("%_dummy") != 0) {
DEBUG(script, 0, "The savegame has an AI by the name '%s', version %u which is no longer available.", _ai_saveload_name.c_str(), _ai_saveload_version);
DEBUG(script, 0, "A random other AI will be loaded in its place.");
} else {
DEBUG(script, 0, "The savegame had no AIs available at the time of saving.");
DEBUG(script, 0, "A random available AI will be loaded now.");
}
} else {
DEBUG(script, 0, "The savegame had no AIs available at the time of saving.");
DEBUG(script, 0, "A random available AI will be loaded now.");
DEBUG(script, 0, "The savegame has an AI by the name '%s', version %u which is no longer available.", _ai_saveload_name.c_str(), _ai_saveload_version);
DEBUG(script, 0, "The latest version of that AI has been loaded instead, but it'll not get the savegame data as it's incompatible.");
}
} else {
DEBUG(script, 0, "The savegame has an AI by the name '%s', version %d which is no longer available.", _ai_saveload_name.c_str(), _ai_saveload_version);
DEBUG(script, 0, "The latest version of that AI has been loaded instead, but it'll not get the savegame data as it's incompatible.");
/* Make sure the AI doesn't get the saveload data, as it was not the
* writer of the saveload data in the first place */
_ai_saveload_version = -1;
}
/* Make sure the AI doesn't get the saveload data, as it was not the
* writer of the saveload data in the first place */
_ai_saveload_version = -1;
}
}
config->StringToSettings(_ai_saveload_settings);
config->StringToSettings(_ai_saveload_settings);
/* Load the AI saved data */
if (Company::IsValidAiID(index)) config->SetToLoadData(AIInstance::Load(_ai_saveload_version));
/* Load the AI saved data */
if (Company::IsValidAiID(index)) config->SetToLoadData(AIInstance::Load(_ai_saveload_version));
}
}
}
static void Save_AIPL()
{
for (int i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
SlSetArrayIndex(i);
SlAutolength((AutolengthProc *)SaveReal_AIPL, &i);
void Save() const override
{
SlTableHeader(_ai_company_desc);
for (int i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
SlSetArrayIndex(i);
SlAutolength((AutolengthProc *)SaveReal_AIPL, &i);
}
}
}
};
static const ChunkHandler ai_chunk_handlers[] = {
{ 'AIPL', Save_AIPL, Load_AIPL, nullptr, nullptr, CH_ARRAY },
static const AIPLChunkHandler AIPL;
static const ChunkHandlerRef ai_chunk_handlers[] = {
AIPL,
};
extern const ChunkHandlerTable _ai_chunk_handlers(ai_chunk_handlers);
}

@ -14,29 +14,23 @@
#include "../safeguards.h"
static void Save_APID()
{
Save_NewGRFMapping(_airport_mngr);
}
static void Load_APID()
{
Load_NewGRFMapping(_airport_mngr);
}
namespace upstream_sl {
static void Save_ATID()
{
Save_NewGRFMapping(_airporttile_mngr);
}
struct APIDChunkHandler : NewGRFMappingChunkHandler {
APIDChunkHandler() : NewGRFMappingChunkHandler('APID', _airport_mngr) {}
};
static void Load_ATID()
{
Load_NewGRFMapping(_airporttile_mngr);
}
struct ATIDChunkHandler : NewGRFMappingChunkHandler {
ATIDChunkHandler() : NewGRFMappingChunkHandler('ATID', _airporttile_mngr) {}
};
static const ChunkHandler airport_chunk_handlers[] = {
{ 'ATID', Save_ATID, Load_ATID, nullptr, nullptr, CH_ARRAY },
{ 'APID', Save_APID, Load_APID, nullptr, nullptr, CH_ARRAY },
static const ATIDChunkHandler ATID;
static const APIDChunkHandler APID;
static const ChunkHandlerRef airport_chunk_handlers[] = {
ATID,
APID,
};
extern const ChunkHandlerTable _airport_chunk_handlers(airport_chunk_handlers);
}

@ -8,73 +8,77 @@
/** @file animated_tile_sl.cpp Code handling saving and loading of animated tiles */
#include "../stdafx.h"
#include "../animated_tile.h"
#include "saveload.h"
#include "compat/animated_tile_sl_compat.h"
#include "../tile_type.h"
#include "../animated_tile.h"
#include "../core/alloc_func.hpp"
#include "../core/smallvec_type.hpp"
#include "saveload.h"
#include "../safeguards.h"
/**
* Save the ANIT chunk.
*/
static void Save_ANIT()
{
uint count = 0;
for (const auto &it : _animated_tiles) {
if (!it.second.pending_deletion) count++;
}
SlSetLength(count * 5);
for (const auto &it : _animated_tiles) {
if (it.second.pending_deletion) continue;
SlWriteUint32(it.first);
SlWriteByte(it.second.speed);
namespace upstream_sl {
static std::vector <TileIndex> _tmp_animated_tiles;
static const SaveLoad _animated_tile_desc[] = {
SLEG_VECTOR("tiles", _tmp_animated_tiles, SLE_UINT32),
};
struct ANITChunkHandler : ChunkHandler {
ANITChunkHandler() : ChunkHandler('ANIT', CH_TABLE) {}
void Save() const override
{
// removed
NOT_REACHED();
}
}
/**
* Load the ANIT chunk; the chunk containing the animated tiles.
*/
static void Load_ANIT()
{
/* Before version 80 we did NOT have a variable length animated tile table */
if (IsSavegameVersionBefore(SLV_80)) {
/* In pre version 6, we has 16bit per tile, now we have 32bit per tile, convert it ;) */
TileIndex anim_list[256];
SlArray(anim_list, 256, IsSavegameVersionBefore(SLV_6) ? (SLE_FILE_U16 | SLE_VAR_U32) : SLE_UINT32);
for (int i = 0; i < 256; i++) {
if (anim_list[i] == 0) break;
_animated_tiles[anim_list[i]] = {};
void Load() const override
{
/* Before version 80 we did NOT have a variable length animated tile table */
if (IsSavegameVersionBefore(SLV_80)) {
/* In pre version 6, we has 16bit per tile, now we have 32bit per tile, convert it ;) */
TileIndex anim_list[256];
SlCopy(anim_list, 256, IsSavegameVersionBefore(SLV_6) ? (SLE_FILE_U16 | SLE_VAR_U32) : SLE_UINT32);
for (int i = 0; i < 256; i++) {
if (anim_list[i] == 0) break;
_animated_tiles[anim_list[i]] = {};
}
return;
}
return;
}
_animated_tiles.clear();
if (SlXvIsFeaturePresent(XSLFI_ANIMATED_TILE_EXTRA)) {
uint count = (uint)SlGetFieldLength() / 5;
for (uint i = 0; i < count; i++) {
TileIndex tile = SlReadUint32();
AnimatedTileInfo info = {};
info.speed = SlReadByte();
_animated_tiles[tile] = info;
if (IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY)) {
size_t count = SlGetFieldLength() / sizeof(uint32);
_animated_tiles.clear();
for (uint i = 0; i < count; i++) {
_animated_tiles[SlReadUint32()] = {};
}
return;
}
} else {
uint count = (uint)SlGetFieldLength() / 4;
for (uint i = 0; i < count; i++) {
_animated_tiles[SlReadUint32()] = {};
const std::vector<SaveLoad> slt = SlCompatTableHeader(_animated_tile_desc, _animated_tile_sl_compat);
if (SlIterateArray() == -1) return;
SlGlobList(slt);
if (SlIterateArray() != -1) SlErrorCorrupt("Too many ANIT entries");
for (TileIndex t : _tmp_animated_tiles) {
_animated_tiles[t] = {};
}
_tmp_animated_tiles.clear();
}
}
};
/**
* "Definition" imported by the saveload code to be able to load and save
* the animated tile table.
*/
static const ChunkHandler animated_tile_chunk_handlers[] = {
{ 'ANIT', Save_ANIT, Load_ANIT, nullptr, nullptr, CH_RIFF },
static const ANITChunkHandler ANIT;
static const ChunkHandlerRef animated_tile_chunk_handlers[] = {
ANIT,
};
extern const ChunkHandlerTable _animated_tile_chunk_handlers(animated_tile_chunk_handlers);
}

@ -8,12 +8,16 @@
/** @file autoreplace_sl.cpp Code handling saving and loading of autoreplace rules */
#include "../stdafx.h"
#include "../autoreplace_base.h"
#include "saveload.h"
#include "compat/autoreplace_sl_compat.h"
#include "../autoreplace_base.h"
#include "../safeguards.h"
namespace upstream_sl {
static const SaveLoad _engine_renew_desc[] = {
SLE_VAR(EngineRenew, from, SLE_UINT16),
SLE_VAR(EngineRenew, to, SLE_UINT16),
@ -23,40 +27,51 @@ static const SaveLoad _engine_renew_desc[] = {
SLE_CONDVAR(EngineRenew, replace_when_old, SLE_BOOL, SLV_175, SL_MAX_VERSION),
};
static void Save_ERNW()
{
for (EngineRenew *er : EngineRenew::Iterate()) {
SlSetArrayIndex(er->index);
SlObject(er, _engine_renew_desc);
struct ERNWChunkHandler : ChunkHandler {
ERNWChunkHandler() : ChunkHandler('ERNW', CH_TABLE) {}
void Save() const override
{
SlTableHeader(_engine_renew_desc);
for (EngineRenew *er : EngineRenew::Iterate()) {
SlSetArrayIndex(er->index);
SlObject(er, _engine_renew_desc);
}
}
}
static void Load_ERNW()
{
int index;
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_engine_renew_desc, _engine_renew_sl_compat);
while ((index = SlIterateArray()) != -1) {
EngineRenew *er = new (index) EngineRenew();
SlObject(er, _engine_renew_desc);
int index;
/* Advanced vehicle lists, ungrouped vehicles got added */
if (IsSavegameVersionBefore(SLV_60)) {
er->group_id = ALL_GROUP;
} else if (IsSavegameVersionBefore(SLV_71)) {
if (er->group_id == DEFAULT_GROUP) er->group_id = ALL_GROUP;
while ((index = SlIterateArray()) != -1) {
EngineRenew *er = new (index) EngineRenew();
SlObject(er, slt);
/* Advanced vehicle lists, ungrouped vehicles got added */
if (IsSavegameVersionBefore(SLV_60)) {
er->group_id = ALL_GROUP;
} else if (IsSavegameVersionBefore(SLV_71)) {
if (er->group_id == DEFAULT_GROUP) er->group_id = ALL_GROUP;
}
}
}
}
static void Ptrs_ERNW()
{
for (EngineRenew *er : EngineRenew::Iterate()) {
SlObject(er, _engine_renew_desc);
void FixPointers() const override
{
for (EngineRenew *er : EngineRenew::Iterate()) {
SlObject(er, _engine_renew_desc);
}
}
}
};
static const ChunkHandler autoreplace_chunk_handlers[] = {
{ 'ERNW', Save_ERNW, Load_ERNW, Ptrs_ERNW, nullptr, CH_ARRAY },
static const ERNWChunkHandler ERNW;
static const ChunkHandlerRef autoreplace_chunk_handlers[] = {
ERNW,
};
extern const ChunkHandlerTable _autoreplace_chunk_handlers(autoreplace_chunk_handlers);
}

@ -8,12 +8,16 @@
/** @file cargomonitor_sl.cpp Code handling saving and loading of Cargo monitoring. */
#include "../stdafx.h"
#include "../cargomonitor.h"
#include "saveload.h"
#include "compat/cargomonitor_sl_compat.h"
#include "../cargomonitor.h"
#include "../safeguards.h"
namespace upstream_sl {
/** Temporary storage of cargo monitoring data for loading or saving it. */
struct TempStorage {
CargoMonitorID number;
@ -41,85 +45,102 @@ static CargoMonitorID FixupCargoMonitor(CargoMonitorID number)
return number;
}
/** Save the #_cargo_deliveries monitoring map. */
static void SaveDelivery()
{
TempStorage storage;
/** #_cargo_deliveries monitoring map. */
struct CMDLChunkHandler : ChunkHandler {
CMDLChunkHandler() : ChunkHandler('CMDL', CH_TABLE) {}
void Save() const override
{
SlTableHeader(_cargomonitor_pair_desc);
int i = 0;
CargoMonitorMap::const_iterator iter = _cargo_deliveries.begin();
while (iter != _cargo_deliveries.end()) {
storage.number = iter->first;
storage.amount = iter->second;
TempStorage storage;
SlSetArrayIndex(i);
SlObject(&storage, _cargomonitor_pair_desc);
int i = 0;
CargoMonitorMap::const_iterator iter = _cargo_deliveries.begin();
while (iter != _cargo_deliveries.end()) {
storage.number = iter->first;
storage.amount = iter->second;
i++;
iter++;
SlSetArrayIndex(i);
SlObject(&storage, _cargomonitor_pair_desc);
i++;
iter++;
}
}
}
/** Load the #_cargo_deliveries monitoring map. */
static void LoadDelivery()
{
TempStorage storage;
bool fix = IsSavegameVersionBefore(SLV_FIX_CARGO_MONITOR);
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_cargomonitor_pair_desc, _cargomonitor_pair_sl_compat);
ClearCargoDeliveryMonitoring();
for (;;) {
if (SlIterateArray() < 0) break;
SlObject(&storage, _cargomonitor_pair_desc);
TempStorage storage;
bool fix = IsSavegameVersionBefore(SLV_FIX_CARGO_MONITOR);
if (fix) storage.number = FixupCargoMonitor(storage.number);
ClearCargoDeliveryMonitoring();
for (;;) {
if (SlIterateArray() < 0) break;
SlObject(&storage, slt);
std::pair<CargoMonitorID, uint32> p(storage.number, storage.amount);
_cargo_deliveries.insert(p);
if (fix) storage.number = FixupCargoMonitor(storage.number);
std::pair<CargoMonitorID, uint32> p(storage.number, storage.amount);
_cargo_deliveries.insert(p);
}
}
}
};
/** #_cargo_pickups monitoring map. */
struct CMPUChunkHandler : ChunkHandler {
CMPUChunkHandler() : ChunkHandler('CMPU', CH_TABLE) {}
/** Save the #_cargo_pickups monitoring map. */
static void SavePickup()
{
TempStorage storage;
void Save() const override
{
SlTableHeader(_cargomonitor_pair_desc);
TempStorage storage;
int i = 0;
CargoMonitorMap::const_iterator iter = _cargo_pickups.begin();
while (iter != _cargo_pickups.end()) {
storage.number = iter->first;
storage.amount = iter->second;
int i = 0;
CargoMonitorMap::const_iterator iter = _cargo_pickups.begin();
while (iter != _cargo_pickups.end()) {
storage.number = iter->first;
storage.amount = iter->second;
SlSetArrayIndex(i);
SlObject(&storage, _cargomonitor_pair_desc);
SlSetArrayIndex(i);
SlObject(&storage, _cargomonitor_pair_desc);
i++;
iter++;
i++;
iter++;
}
}
}
/** Load the #_cargo_pickups monitoring map. */
static void LoadPickup()
{
TempStorage storage;
bool fix = IsSavegameVersionBefore(SLV_FIX_CARGO_MONITOR);
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_cargomonitor_pair_desc, _cargomonitor_pair_sl_compat);
ClearCargoPickupMonitoring();
for (;;) {
if (SlIterateArray() < 0) break;
SlObject(&storage, _cargomonitor_pair_desc);
TempStorage storage;
bool fix = IsSavegameVersionBefore(SLV_FIX_CARGO_MONITOR);
if (fix) storage.number = FixupCargoMonitor(storage.number);
ClearCargoPickupMonitoring();
for (;;) {
if (SlIterateArray() < 0) break;
SlObject(&storage, slt);
std::pair<CargoMonitorID, uint32> p(storage.number, storage.amount);
_cargo_pickups.insert(p);
if (fix) storage.number = FixupCargoMonitor(storage.number);
std::pair<CargoMonitorID, uint32> p(storage.number, storage.amount);
_cargo_pickups.insert(p);
}
}
}
};
/** Chunk definition of the cargomonitoring maps. */
static const ChunkHandler cargomonitor_chunk_handlers[] = {
{ 'CMDL', SaveDelivery, LoadDelivery, nullptr, nullptr, CH_ARRAY },
{ 'CMPU', SavePickup, LoadPickup, nullptr, nullptr, CH_ARRAY },
static const CMDLChunkHandler CMDL;
static const CMPUChunkHandler CMPU;
static const ChunkHandlerRef cargomonitor_chunk_handlers[] = {
CMDL,
CMPU,
};
extern const ChunkHandlerTable _cargomonitor_chunk_handlers(cargomonitor_chunk_handlers);
}

@ -8,100 +8,16 @@
/** @file cargopacket_sl.cpp Code handling saving and loading of cargo packets */
#include "../stdafx.h"
#include "../vehicle_base.h"
#include "../station_base.h"
#include "../scope_info.h"
#include "../3rdparty/cpp-btree/btree_map.h"
#include "saveload.h"
#include "compat/cargopacket_sl_compat.h"
#include "../safeguards.h"
extern btree::btree_map<uint64, Money> _cargo_packet_deferred_payments;
/**
* Savegame conversion for cargopackets.
*/
/* static */ void CargoPacket::AfterLoad()
{
if (IsSavegameVersionBefore(SLV_44)) {
/* If we remove a station while cargo from it is still en route, payment calculation will assume
* 0, 0 to be the source of the cargo, resulting in very high payments usually. v->source_xy
* stores the coordinates, preserving them even if the station is removed. However, if a game is loaded
* where this situation exists, the cargo-source information is lost. in this case, we set the source
* to the current tile of the vehicle to prevent excessive profits
*/
for (const Vehicle *v : Vehicle::Iterate()) {
const CargoPacketList *packets = v->cargo.Packets();
for (VehicleCargoList::ConstIterator it(packets->begin()); it != packets->end(); it++) {
CargoPacket *cp = *it;
cp->source_xy = Station::IsValidID(cp->source) ? Station::Get(cp->source)->xy : v->tile;
cp->loaded_at_xy = cp->source_xy;
}
}
/* Store position of the station where the goods come from, so there
* are no very high payments when stations get removed. However, if the
* station where the goods came from is already removed, the source
* information is lost. In that case we set it to the position of this
* station */
for (Station *st : Station::Iterate()) {
for (CargoID c = 0; c < NUM_CARGO; c++) {
GoodsEntry *ge = &st->goods[c];
const StationCargoPacketMap *packets = ge->cargo.Packets();
for (StationCargoList::ConstIterator it(packets->begin()); it != packets->end(); it++) {
CargoPacket *cp = *it;
cp->source_xy = Station::IsValidID(cp->source) ? Station::Get(cp->source)->xy : st->xy;
cp->loaded_at_xy = cp->source_xy;
}
}
}
}
if (IsSavegameVersionBefore(SLV_120)) {
/* CargoPacket's source should be either INVALID_STATION or a valid station */
for (CargoPacket *cp : CargoPacket::Iterate()) {
if (!Station::IsValidID(cp->source)) cp->source = INVALID_STATION;
}
}
if (!IsSavegameVersionBefore(SLV_68)) {
/* Only since version 68 we have cargo packets. Savegames from before used
* 'new CargoPacket' + cargolist.Append so their caches are already
* correct and do not need rebuilding. */
for (Vehicle *v : Vehicle::Iterate()) v->cargo.InvalidateCache();
#include "../vehicle_base.h"
#include "../station_base.h"
for (Station *st : Station::Iterate()) {
for (CargoID c = 0; c < NUM_CARGO; c++) st->goods[c].cargo.InvalidateCache();
}
}
#include "../safeguards.h"
if (IsSavegameVersionBefore(SLV_181)) {
for (Vehicle *v : Vehicle::Iterate()) v->cargo.KeepAll();
}
}
/**
* Savegame conversion for cargopackets.
*/
/* static */ void CargoPacket::PostVehiclesAfterLoad()
{
if (SlXvIsFeaturePresent(XSLFI_CHILLPP)) {
extern std::map<VehicleID, CargoPacketList> _veh_cpp_packets;
for (auto &iter : _veh_cpp_packets) {
if (iter.second.empty()) continue;
Vehicle *v = Vehicle::Get(iter.first);
Station *st = Station::Get(v->First()->last_station_visited);
assert_msg(st != nullptr, "%s", scope_dumper().VehicleInfo(v));
for (CargoPacket *cp : iter.second) {
st->goods[v->cargo_type].cargo.AfterLoadIncreaseReservationCount(cp->count);
v->cargo.Append(cp, VehicleCargoList::MTA_LOAD);
}
}
_veh_cpp_packets.clear();
}
}
namespace upstream_sl {
/**
* Wrapper function to get the CargoPacket's internal structure while
@ -111,85 +27,50 @@ extern btree::btree_map<uint64, Money> _cargo_packet_deferred_payments;
SaveLoadTable GetCargoPacketDesc()
{
static const SaveLoad _cargopacket_desc[] = {
SLE_VAR(CargoPacket, source, SLE_UINT16),
SLE_VAR(CargoPacket, source_xy, SLE_UINT32),
SLE_VAR(CargoPacket, loaded_at_xy, SLE_UINT32),
SLE_VAR(CargoPacket, count, SLE_UINT16),
SLE_CONDVAR_X(CargoPacket, days_in_transit, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_MORE_CARGO_AGE, 0, 0)),
SLE_CONDVAR_X(CargoPacket, days_in_transit, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_MORE_CARGO_AGE)),
SLE_VAR(CargoPacket, feeder_share, SLE_INT64),
SLE_CONDVAR(CargoPacket, source_type, SLE_UINT8, SLV_125, SL_MAX_VERSION),
SLE_CONDVAR(CargoPacket, source_id, SLE_UINT16, SLV_125, SL_MAX_VERSION),
/* Used to be paid_for, but that got changed. */
SLE_CONDNULL(1, SL_MIN_VERSION, SLV_121),
SLE_VAR(CargoPacket, source, SLE_UINT16),
SLE_VAR(CargoPacket, source_xy, SLE_UINT32),
SLE_VAR(CargoPacket, loaded_at_xy, SLE_UINT32),
SLE_VAR(CargoPacket, count, SLE_UINT16),
SLE_CONDVAR(CargoPacket, days_in_transit, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_MORE_CARGO_AGE),
SLE_CONDVAR(CargoPacket, days_in_transit, SLE_UINT16, SLV_MORE_CARGO_AGE, SL_MAX_VERSION),
SLE_VAR(CargoPacket, feeder_share, SLE_INT64),
SLE_CONDVAR(CargoPacket, source_type, SLE_UINT8, SLV_125, SL_MAX_VERSION),
SLE_CONDVAR(CargoPacket, source_id, SLE_UINT16, SLV_125, SL_MAX_VERSION),
};
return _cargopacket_desc;
}
/**
* Save the cargo packets.
*/
static void Save_CAPA()
{
std::vector<SaveLoad> filtered_packet_desc = SlFilterObject(GetCargoPacketDesc());
for (CargoPacket *cp : CargoPacket::Iterate()) {
SlSetArrayIndex(cp->index);
SlObjectSaveFiltered(cp, filtered_packet_desc);
}
}
struct CAPAChunkHandler : ChunkHandler {
CAPAChunkHandler() : ChunkHandler('CAPA', CH_TABLE) {}
/**
* Load the cargo packets.
*/
static void Load_CAPA()
{
std::vector<SaveLoad> filtered_packet_desc = SlFilterObject(GetCargoPacketDesc());
int index;
while ((index = SlIterateArray()) != -1) {
CargoPacket *cp = new (index) CargoPacket();
SlObjectLoadFiltered(cp, filtered_packet_desc);
void Save() const override
{
SlTableHeader(GetCargoPacketDesc());
for (CargoPacket *cp : CargoPacket::Iterate()) {
SlSetArrayIndex(cp->index);
SlObject(cp, GetCargoPacketDesc());
}
}
}
/**
* Save cargo packet deferred payments.
*/
void Save_CPDP()
{
SlSetLength(16 * _cargo_packet_deferred_payments.size());
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(GetCargoPacketDesc(), _cargopacket_sl_compat);
for (auto &it : _cargo_packet_deferred_payments) {
SlWriteUint64(it.first);
SlWriteUint64(it.second);
}
}
int index;
/**
* Load cargo packet deferred payments.
*/
void Load_CPDP()
{
uint count = static_cast<uint>(SlGetFieldLength() / 16);
uint last_cargo_packet_id = std::numeric_limits<uint32_t>::max();
for (uint i = 0; i < count; i++) {
uint64 k = SlReadUint64();
uint64 v = SlReadUint64();
_cargo_packet_deferred_payments[k] = v;
if (k >> 32 != last_cargo_packet_id) {
last_cargo_packet_id = k >> 32;
CargoPacket::Get(last_cargo_packet_id)->flags |= CargoPacket::CPF_HAS_DEFERRED_PAYMENT;
while ((index = SlIterateArray()) != -1) {
CargoPacket *cp = new (index) CargoPacket();
SlObject(cp, slt);
}
}
}
};
/** Chunk handlers related to cargo packets. */
static const ChunkHandler cargopacket_chunk_handlers[] = {
{ 'CAPA', Save_CAPA, Load_CAPA, nullptr, nullptr, CH_ARRAY },
{ 'CPDP', Save_CPDP, Load_CPDP, nullptr, nullptr, CH_RIFF },
static const CAPAChunkHandler CAPA;
static const ChunkHandlerRef cargopacket_chunk_handlers[] = {
CAPA,
};
extern const ChunkHandlerTable _cargopacket_chunk_handlers(cargopacket_chunk_handlers);
}

@ -8,29 +8,15 @@
/** @file cheat_sl.cpp Code handling saving and loading of cheats */
#include "../stdafx.h"
#include "../cheat_type.h"
#include "../debug.h"
#include "saveload.h"
#include "compat/cheat_sl_compat.h"
#include <map>
#include <string>
#include "../cheat_type.h"
#include "../safeguards.h"
extern std::map<std::string, Cheat> _unknown_cheats;
struct ExtraCheatNameDesc {
const char *name;
Cheat *cht;
};
static ExtraCheatNameDesc _extra_cheat_descs[] = {
{ "inflation_cost", &_extra_cheats.inflation_cost },
{ "inflation_income", &_extra_cheats.inflation_income },
{ "station_rating", &_extra_cheats.station_rating },
{ "town_rating", &_extra_cheats.town_rating },
};
namespace upstream_sl {
static const SaveLoad _cheats_desc[] = {
SLE_VAR(Cheats, magic_bulldozer.been_used, SLE_BOOL),
@ -41,146 +27,60 @@ static const SaveLoad _cheats_desc[] = {
SLE_VAR(Cheats, money.value, SLE_BOOL),
SLE_VAR(Cheats, crossing_tunnels.been_used, SLE_BOOL),
SLE_VAR(Cheats, crossing_tunnels.value, SLE_BOOL),
SLE_NULL(1),
SLE_NULL(1), // Needs to be two NULL fields. See Load_CHTS().
SLE_VAR(Cheats, no_jetcrash.been_used, SLE_BOOL),
SLE_VAR(Cheats, no_jetcrash.value, SLE_BOOL),
SLE_NULL(1),
SLE_NULL(1), // Needs to be two NULL fields. See Load_CHTS().
SLE_VAR(Cheats, change_date.been_used, SLE_BOOL),
SLE_VAR(Cheats, change_date.value, SLE_BOOL),
SLE_VAR(Cheats, setup_prod.been_used, SLE_BOOL),
SLE_VAR(Cheats, setup_prod.value, SLE_BOOL),
SLE_NULL(1),
SLE_NULL(1), // Needs to be two NULL fields. See Load_CHTS().
SLE_VAR(Cheats, edit_max_hl.been_used, SLE_BOOL),
SLE_VAR(Cheats, edit_max_hl.value, SLE_BOOL),
};
/**
* Save the cheat values.
*/
static void Save_CHTS()
{
SlSetLength(std::size(_cheats_desc));
SlObject(&_cheats, _cheats_desc);
}
/**
* Load the cheat values.
*/
static void Load_CHTS()
{
size_t count = SlGetFieldLength();
std::vector<SaveLoad> slt;
/* Cheats were added over the years without a savegame bump. They are
* stored as 2 SLE_BOOLs per entry. "count" indicates how many SLE_BOOLs
* are stored for this savegame. So read only "count" SLE_BOOLs (and in
* result "count / 2" cheats). */
for (auto &sld : _cheats_desc) {
count--;
slt.push_back(sld);
if (count == 0) break;
}
struct CHTSChunkHandler : ChunkHandler {
CHTSChunkHandler() : ChunkHandler('CHTS', CH_TABLE) {}
SlObject(&_cheats, slt);
}
void Save() const override
{
SlTableHeader(_cheats_desc);
/**
* Load the extra cheat values.
*/
static void Load_CHTX()
{
struct CheatsExtLoad {
char name[256];
Cheat cht;
};
static const SaveLoad _cheats_ext_load_desc[] = {
SLE_STR(CheatsExtLoad, name, SLE_STRB, 256),
SLE_VAR(CheatsExtLoad, cht.been_used, SLE_BOOL),
SLE_VAR(CheatsExtLoad, cht.value, SLE_BOOL),
};
CheatsExtLoad current_cheat;
uint32 chunk_flags = SlReadUint32();
// flags are not in use yet, reserve for future expansion
if (chunk_flags != 0) SlErrorCorruptFmt("CHTX chunk: unknown chunk header flags: 0x%X", chunk_flags);
uint32 cheat_count = SlReadUint32();
for (uint32 i = 0; i < cheat_count; i++) {
SlObject(&current_cheat, _cheats_ext_load_desc);
bool found = false;
for (uint j = 0; j < lengthof(_extra_cheat_descs); j++) {
const ExtraCheatNameDesc &desc = _extra_cheat_descs[j];
if (strcmp(desc.name, current_cheat.name) == 0) {
*(desc.cht) = current_cheat.cht;
found = true;
break;
}
}
if (!found) {
DEBUG(sl, 1, "CHTX chunk: Could not find cheat: '%s'", current_cheat.name);
_unknown_cheats[current_cheat.name] = current_cheat.cht;
}
SlSetArrayIndex(0);
SlObject(&_cheats, _cheats_desc);
}
}
/**
* Save the extra cheat values.
*/
static void Save_CHTX()
{
struct CheatsExtSave {
const char *name;
Cheat cht;
};
static const SaveLoad _cheats_ext_save_desc[] = {
SLE_STR(CheatsExtSave, name, SLE_STR, 0),
SLE_VAR(CheatsExtSave, cht.been_used, SLE_BOOL),
SLE_VAR(CheatsExtSave, cht.value, SLE_BOOL),
};
SlAutolength([](void *) {
SlWriteUint32(0); // flags
SlWriteUint32((uint32)(lengthof(_extra_cheat_descs) + _unknown_cheats.size())); // cheat count
for (uint j = 0; j < lengthof(_extra_cheat_descs); j++) {
CheatsExtSave save = { _extra_cheat_descs[j].name, *(_extra_cheat_descs[j].cht) };
SlObject(&save, _cheats_ext_save_desc);
}
for (const auto &iter : _unknown_cheats) {
CheatsExtSave save = { iter.first.c_str(), iter.second };
SlObject(&save, _cheats_ext_save_desc);
}
}, nullptr);
}
void Load() const override
{
std::vector<SaveLoad> slt = SlCompatTableHeader(_cheats_desc, _cheats_sl_compat);
/**
* Internal structure used in SaveSettingsPatx() and SaveSettingsPlyx()
*/
struct SettingsExtSave {
uint32 flags;
const char *name;
uint32 setting_length;
};
if (IsSavegameVersionBefore(SLV_TABLE_CHUNKS)) {
size_t count = SlGetFieldLength();
std::vector<SaveLoad> oslt;
static const SaveLoad _settings_ext_save_desc[] = {
SLE_VAR(SettingsExtSave, flags, SLE_UINT32),
SLE_STR(SettingsExtSave, name, SLE_STR, 0),
SLE_VAR(SettingsExtSave, setting_length, SLE_UINT32),
};
/* Cheats were added over the years without a savegame bump. They are
* stored as 2 SLE_BOOLs per entry. "count" indicates how many SLE_BOOLs
* are stored for this savegame. So read only "count" SLE_BOOLs (and in
* result "count / 2" cheats). */
for (auto &sld : slt) {
count--;
oslt.push_back(sld);
if (count == 0) break;
}
slt = oslt;
}
/** Chunk handlers related to cheats. */
static const ChunkHandler cheat_chunk_handlers[] = {
{ 'CHTS', Save_CHTS, Load_CHTS, nullptr, nullptr, CH_RIFF },
{ 'CHTX', Save_CHTX, Load_CHTX, nullptr, nullptr, CH_RIFF },
if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() == -1) return;
SlObject(&_cheats, slt);
if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many CHTS entries");
}
};
static const CHTSChunkHandler CHTS;
static const ChunkHandlerRef cheat_chunk_handlers[] = {
CHTS,
};
extern const ChunkHandlerTable _cheat_chunk_handlers(cheat_chunk_handlers);
}

@ -8,241 +8,227 @@
/** @file company_sl.cpp Code handling saving and loading of company data */
#include "../stdafx.h"
#include "saveload.h"
#include "compat/company_sl_compat.h"
#include "../company_func.h"
#include "../company_manager_face.h"
#include "../fios.h"
#include "../tunnelbridge_map.h"
#include "../tunnelbridge.h"
#include "../station_base.h"
#include "../settings_func.h"
#include "../strings_func.h"
#include "../network/network.h"
#include "../network/network_func.h"
#include "../network/network_server.h"
#include "../3rdparty/randombytes/randombytes.h"
#include "../3rdparty/monocypher/monocypher.h"
#include "saveload.h"
#include "saveload_buffer.h"
#include "table/strings.h"
#include "../safeguards.h"
/**
* Converts an old company manager's face format to the new company manager's face format
*
* Meaning of the bits in the old face (some bits are used in several times):
* - 4 and 5: chin
* - 6 to 9: eyebrows
* - 10 to 13: nose
* - 13 to 15: lips (also moustache for males)
* - 16 to 19: hair
* - 20 to 22: eye colour
* - 20 to 27: tie, ear rings etc.
* - 28 to 30: glasses
* - 19, 26 and 27: race (bit 27 set and bit 19 equal to bit 26 = black, otherwise white)
* - 31: gender (0 = male, 1 = female)
*
* @param face the face in the old format
* @return the face in the new format
*/
CompanyManagerFace ConvertFromOldCompanyManagerFace(uint32 face)
{
CompanyManagerFace cmf = 0;
GenderEthnicity ge = GE_WM;
if (HasBit(face, 31)) SetBit(ge, GENDER_FEMALE);
if (HasBit(face, 27) && (HasBit(face, 26) == HasBit(face, 19))) SetBit(ge, ETHNICITY_BLACK);
SetCompanyManagerFaceBits(cmf, CMFV_GEN_ETHN, ge, ge);
SetCompanyManagerFaceBits(cmf, CMFV_HAS_GLASSES, ge, GB(face, 28, 3) <= 1);
SetCompanyManagerFaceBits(cmf, CMFV_EYE_COLOUR, ge, HasBit(ge, ETHNICITY_BLACK) ? 0 : ClampU(GB(face, 20, 3), 5, 7) - 5);
SetCompanyManagerFaceBits(cmf, CMFV_CHIN, ge, ScaleCompanyManagerFaceValue(CMFV_CHIN, ge, GB(face, 4, 2)));
SetCompanyManagerFaceBits(cmf, CMFV_EYEBROWS, ge, ScaleCompanyManagerFaceValue(CMFV_EYEBROWS, ge, GB(face, 6, 4)));
SetCompanyManagerFaceBits(cmf, CMFV_HAIR, ge, ScaleCompanyManagerFaceValue(CMFV_HAIR, ge, GB(face, 16, 4)));
SetCompanyManagerFaceBits(cmf, CMFV_JACKET, ge, ScaleCompanyManagerFaceValue(CMFV_JACKET, ge, GB(face, 20, 2)));
SetCompanyManagerFaceBits(cmf, CMFV_COLLAR, ge, ScaleCompanyManagerFaceValue(CMFV_COLLAR, ge, GB(face, 22, 2)));
SetCompanyManagerFaceBits(cmf, CMFV_GLASSES, ge, GB(face, 28, 1));
uint lips = GB(face, 10, 4);
if (!HasBit(ge, GENDER_FEMALE) && lips < 4) {
SetCompanyManagerFaceBits(cmf, CMFV_HAS_MOUSTACHE, ge, true);
SetCompanyManagerFaceBits(cmf, CMFV_MOUSTACHE, ge, std::max(lips, 1U) - 1);
} else {
if (!HasBit(ge, GENDER_FEMALE)) {
lips = lips * 15 / 16;
lips -= 3;
if (HasBit(ge, ETHNICITY_BLACK) && lips > 8) lips = 0;
} else {
lips = ScaleCompanyManagerFaceValue(CMFV_LIPS, ge, lips);
}
SetCompanyManagerFaceBits(cmf, CMFV_LIPS, ge, lips);
void SetDefaultCompanySettings(CompanyID cid);
namespace upstream_sl {
/* We do need to read this single value, as the bigger it gets, the more data is stored */
struct CompanyOldAI {
uint8 num_build_rec;
};
class SlCompanyOldAIBuildRec : public DefaultSaveLoadHandler<SlCompanyOldAIBuildRec, CompanyOldAI> {
public:
inline static const SaveLoad description[] = {{}}; // Needed to keep DefaultSaveLoadHandler happy.
inline const static SaveLoadCompatTable compat_description = _company_old_ai_buildrec_compat;
uint nose = GB(face, 13, 3);
if (ge == GE_WF) {
nose = (nose * 3 >> 3) * 3 >> 2; // There is 'hole' in the nose sprites for females
} else {
nose = ScaleCompanyManagerFaceValue(CMFV_NOSE, ge, nose);
SaveLoadTable GetDescription() const override { return {}; }
void Load(CompanyOldAI *old_ai) const override
{
for (int i = 0; i != old_ai->num_build_rec; i++) {
SlObject(nullptr, this->GetLoadDescription());
}
SetCompanyManagerFaceBits(cmf, CMFV_NOSE, ge, nose);
}
uint tie_earring = GB(face, 24, 4);
if (!HasBit(ge, GENDER_FEMALE) || tie_earring < 3) { // Not all females have an earring
if (HasBit(ge, GENDER_FEMALE)) SetCompanyManagerFaceBits(cmf, CMFV_HAS_TIE_EARRING, ge, true);
SetCompanyManagerFaceBits(cmf, CMFV_TIE_EARRING, ge, HasBit(ge, GENDER_FEMALE) ? tie_earring : ScaleCompanyManagerFaceValue(CMFV_TIE_EARRING, ge, tie_earring / 2));
void LoadCheck(CompanyOldAI *old_ai) const override { this->Load(old_ai); }
};
class SlCompanyOldAI : public DefaultSaveLoadHandler<SlCompanyOldAI, CompanyProperties> {
public:
inline static const SaveLoad description[] = {
SLE_CONDVAR(CompanyOldAI, num_build_rec, SLE_UINT8, SL_MIN_VERSION, SLV_107),
SLEG_STRUCTLIST("buildrec", SlCompanyOldAIBuildRec),
};
inline const static SaveLoadCompatTable compat_description = _company_old_ai_compat;
void Load(CompanyProperties *c) const override
{
if (!c->is_ai) return;
CompanyOldAI old_ai;
SlObject(&old_ai, this->GetLoadDescription());
}
return cmf;
}
void LoadCheck(CompanyProperties *c) const override { this->Load(c); }
};
/** Rebuilding of company statistics after loading a savegame. */
void AfterLoadCompanyStats()
{
/* Reset infrastructure statistics to zero. */
for (Company *c : Company::Iterate()) MemSetT(&c->infrastructure, 0);
class SlCompanySettings : public DefaultSaveLoadHandler<SlCompanySettings, CompanyProperties> {
public:
inline static const SaveLoad description[] = {
/* Engine renewal settings */
SLE_CONDREF(CompanyProperties, engine_renew_list, REF_ENGINE_RENEWS, SLV_19, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, settings.engine_renew, SLE_BOOL, SLV_16, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, settings.engine_renew_months, SLE_INT16, SLV_16, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, settings.engine_renew_money, SLE_UINT32, SLV_16, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, settings.renew_keep_length, SLE_BOOL, SLV_2, SL_MAX_VERSION),
/* Default vehicle settings */
SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_ispercent, SLE_BOOL, SLV_120, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_trains, SLE_UINT16, SLV_120, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_roadveh, SLE_UINT16, SLV_120, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_aircraft, SLE_UINT16, SLV_120, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_ships, SLE_UINT16, SLV_120, SL_MAX_VERSION),
};
inline const static SaveLoadCompatTable compat_description = _company_settings_compat;
void Save(CompanyProperties *c) const override
{
SlObject(c, this->GetDescription());
}
void Load(CompanyProperties *c) const override
{
SlObject(c, this->GetLoadDescription());
}
void FixPointers(CompanyProperties *c) const override
{
SlObject(c, this->GetDescription());
}
void LoadCheck(CompanyProperties *c) const override { this->Load(c); }
};
class SlCompanyEconomy : public DefaultSaveLoadHandler<SlCompanyEconomy, CompanyProperties> {
public:
inline static const SaveLoad description[] = {
SLE_CONDVAR(CompanyEconomyEntry, income, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_2),
SLE_CONDVAR(CompanyEconomyEntry, income, SLE_INT64, SLV_2, SL_MAX_VERSION),
SLE_CONDVAR(CompanyEconomyEntry, expenses, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_2),
SLE_CONDVAR(CompanyEconomyEntry, expenses, SLE_INT64, SLV_2, SL_MAX_VERSION),
SLE_CONDVAR(CompanyEconomyEntry, company_value, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_2),
SLE_CONDVAR(CompanyEconomyEntry, company_value, SLE_INT64, SLV_2, SL_MAX_VERSION),
SLE_CONDVAR(CompanyEconomyEntry, delivered_cargo[NUM_CARGO - 1], SLE_INT32, SL_MIN_VERSION, SLV_170),
SLE_CONDARR(CompanyEconomyEntry, delivered_cargo, SLE_UINT32, 32, SLV_170, SLV_EXTEND_CARGOTYPES),
SLE_CONDARR(CompanyEconomyEntry, delivered_cargo, SLE_UINT32, NUM_CARGO, SLV_EXTEND_CARGOTYPES, SL_MAX_VERSION),
SLE_VAR(CompanyEconomyEntry, performance_history, SLE_INT32),
};
inline const static SaveLoadCompatTable compat_description = _company_economy_compat;
void Save(CompanyProperties *c) const override
{
SlObject(&c->cur_economy, this->GetDescription());
}
void Load(CompanyProperties *c) const override
{
SlObject(&c->cur_economy, this->GetLoadDescription());
}
/* Collect airport count. */
for (const Station *st : Station::Iterate()) {
if ((st->facilities & FACIL_AIRPORT) && Company::IsValidID(st->owner)) {
Company::Get(st->owner)->infrastructure.airport++;
void FixPointers(CompanyProperties *c) const override
{
SlObject(&c->cur_economy, this->GetDescription());
}
void LoadCheck(CompanyProperties *c) const override { this->Load(c); }
};
class SlCompanyOldEconomy : public SlCompanyEconomy {
public:
void Save(CompanyProperties *c) const override
{
SlSetStructListLength(c->num_valid_stat_ent);
for (int i = 0; i < c->num_valid_stat_ent; i++) {
SlObject(&c->old_economy[i], this->GetDescription());
}
}
Company *c;
for (TileIndex tile = 0; tile < MapSize(); tile++) {
switch (GetTileType(tile)) {
case MP_RAILWAY:
c = Company::GetIfValid(GetTileOwner(tile));
if (c != nullptr) {
uint pieces = 1;
if (IsPlainRail(tile)) {
TrackBits bits = GetTrackBits(tile);
if (bits == TRACK_BIT_HORZ || bits == TRACK_BIT_VERT) {
c->infrastructure.rail[GetSecondaryRailType(tile)]++;
} else {
pieces = CountBits(bits);
if (TracksOverlap(bits)) pieces *= pieces;
}
}
c->infrastructure.rail[GetRailType(tile)] += pieces;
if (HasSignals(tile)) c->infrastructure.signal += CountBits(GetPresentSignals(tile));
}
break;
void Load(CompanyProperties *c) const override
{
if (!IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) {
c->num_valid_stat_ent = (uint8)SlGetStructListLength(UINT8_MAX);
}
if (c->num_valid_stat_ent > lengthof(c->old_economy)) SlErrorCorrupt("Too many old economy entries");
case MP_ROAD: {
if (IsLevelCrossing(tile)) {
c = Company::GetIfValid(GetTileOwner(tile));
if (c != nullptr) c->infrastructure.rail[GetRailType(tile)] += LEVELCROSSING_TRACKBIT_FACTOR;
}
for (int i = 0; i < c->num_valid_stat_ent; i++) {
SlObject(&c->old_economy[i], this->GetLoadDescription());
}
}
/* Iterate all present road types as each can have a different owner. */
for (RoadTramType rtt : _roadtramtypes) {
RoadType rt = GetRoadType(tile, rtt);
if (rt == INVALID_ROADTYPE) continue;
c = Company::GetIfValid(IsRoadDepot(tile) ? GetTileOwner(tile) : GetRoadOwner(tile, rtt));
/* A level crossings and depots have two road bits. */
if (c != nullptr) c->infrastructure.road[rt] += IsNormalRoad(tile) ? CountBits(GetRoadBits(tile, rtt)) : 2;
}
break;
}
void LoadCheck(CompanyProperties *c) const override { this->Load(c); }
};
case MP_STATION:
c = Company::GetIfValid(GetTileOwner(tile));
if (c != nullptr && GetStationType(tile) != STATION_AIRPORT && !IsBuoy(tile)) c->infrastructure.station++;
switch (GetStationType(tile)) {
case STATION_RAIL:
case STATION_WAYPOINT:
if (c != nullptr && !IsStationTileBlocked(tile)) c->infrastructure.rail[GetRailType(tile)]++;
break;
case STATION_BUS:
case STATION_TRUCK:
case STATION_ROADWAYPOINT: {
/* Iterate all present road types as each can have a different owner. */
for (RoadTramType rtt : _roadtramtypes) {
RoadType rt = GetRoadType(tile, rtt);
if (rt == INVALID_ROADTYPE) continue;
c = Company::GetIfValid(GetRoadOwner(tile, rtt));
if (c != nullptr) c->infrastructure.road[rt] += 2; // A road stop has two road bits.
}
break;
}
case STATION_DOCK:
case STATION_BUOY:
if (GetWaterClass(tile) == WATER_CLASS_CANAL) {
if (c != nullptr) c->infrastructure.water++;
}
break;
default:
break;
}
break;
case MP_WATER:
if (IsShipDepot(tile) || IsLock(tile)) {
c = Company::GetIfValid(GetTileOwner(tile));
if (c != nullptr) {
if (IsShipDepot(tile)) c->infrastructure.water += LOCK_DEPOT_TILE_FACTOR;
if (IsLock(tile) && GetLockPart(tile) == LOCK_PART_MIDDLE) {
/* The middle tile specifies the owner of the lock. */
c->infrastructure.water += 3 * LOCK_DEPOT_TILE_FACTOR; // the middle tile specifies the owner of the
break; // do not count the middle tile as canal
}
}
}
FALLTHROUGH;
class SlCompanyLiveries : public DefaultSaveLoadHandler<SlCompanyLiveries, CompanyProperties> {
public:
inline static const SaveLoad description[] = {
SLE_CONDVAR(Livery, in_use, SLE_UINT8, SLV_34, SL_MAX_VERSION),
SLE_CONDVAR(Livery, colour1, SLE_UINT8, SLV_34, SL_MAX_VERSION),
SLE_CONDVAR(Livery, colour2, SLE_UINT8, SLV_34, SL_MAX_VERSION),
};
inline const static SaveLoadCompatTable compat_description = _company_liveries_compat;
/**
* Get the number of liveries used by this savegame version.
* @return The number of liveries used by this savegame version.
*/
size_t GetNumLiveries() const
{
if (IsSavegameVersionBefore(SLV_63)) return LS_END - 4;
if (IsSavegameVersionBefore(SLV_85)) return LS_END - 2;
if (IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) return LS_END;
/* Read from the savegame how long the list is. */
return SlGetStructListLength(LS_END);
}
case MP_OBJECT:
if (GetWaterClass(tile) == WATER_CLASS_CANAL) {
c = Company::GetIfValid(GetTileOwner(tile));
if (c != nullptr) c->infrastructure.water++;
}
break;
case MP_TUNNELBRIDGE: {
/* Only count the tunnel/bridge if we're on the western end tile. */
if (GetTunnelBridgeDirection(tile) < DIAGDIR_SW) {
TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
/* Count each tunnel/bridge TUNNELBRIDGE_TRACKBIT_FACTOR times to simulate
* the higher structural maintenance needs, and don't forget the end tiles. */
const uint middle_len = GetTunnelBridgeLength(tile, other_end) * TUNNELBRIDGE_TRACKBIT_FACTOR;
switch (GetTunnelBridgeTransportType(tile)) {
case TRANSPORT_RAIL:
AddRailTunnelBridgeInfrastructure(tile, other_end);
break;
case TRANSPORT_ROAD: {
AddRoadTunnelBridgeInfrastructure(tile, other_end);
break;
}
case TRANSPORT_WATER:
c = Company::GetIfValid(GetTileOwner(tile));
if (c != nullptr) c->infrastructure.water += middle_len + (2 * TUNNELBRIDGE_TRACKBIT_FACTOR);
break;
default:
break;
}
void Save(CompanyProperties *c) const override
{
SlSetStructListLength(LS_END);
for (int i = 0; i < LS_END; i++) {
SlObject(&c->livery[i], this->GetDescription());
}
}
void Load(CompanyProperties *c) const override
{
size_t num_liveries = this->GetNumLiveries();
bool update_in_use = IsSavegameVersionBefore(SLV_GROUP_LIVERIES);
for (size_t i = 0; i < num_liveries; i++) {
SlObject(&c->livery[i], this->GetLoadDescription());
if (update_in_use && i != LS_DEFAULT) {
if (c->livery[i].in_use == 0) {
c->livery[i].colour1 = c->livery[LS_DEFAULT].colour1;
c->livery[i].colour2 = c->livery[LS_DEFAULT].colour2;
} else {
c->livery[i].in_use = 3;
}
break;
}
}
default:
break;
if (IsSavegameVersionBefore(SLV_85)) {
/* We want to insert some liveries somewhere in between. This means some have to be moved. */
memmove(&c->livery[LS_FREIGHT_WAGON], &c->livery[LS_PASSENGER_WAGON_MONORAIL], (LS_END - LS_FREIGHT_WAGON) * sizeof(c->livery[0]));
c->livery[LS_PASSENGER_WAGON_MONORAIL] = c->livery[LS_MONORAIL];
c->livery[LS_PASSENGER_WAGON_MAGLEV] = c->livery[LS_MAGLEV];
}
}
}
if (IsSavegameVersionBefore(SLV_63)) {
/* Copy bus/truck liveries over to trams */
c->livery[LS_PASSENGER_TRAM] = c->livery[LS_BUS];
c->livery[LS_FREIGHT_TRAM] = c->livery[LS_TRUCK];
}
}
void LoadCheck(CompanyProperties *c) const override { this->Load(c); }
};
/* Save/load of companies */
static const SaveLoad _company_desc[] = {
@ -265,11 +251,8 @@ static const SaveLoad _company_desc[] = {
SLE_VAR(CompanyProperties, colour, SLE_UINT8),
SLE_VAR(CompanyProperties, money_fraction, SLE_UINT8),
SLE_CONDNULL(1, SL_MIN_VERSION, SLV_58), ///< avail_railtypes
SLE_VAR(CompanyProperties, block_preview, SLE_UINT8),
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_94), ///< cargo_types
SLE_CONDNULL(4, SLV_94, SLV_170), ///< cargo_types
SLE_CONDVAR(CompanyProperties, location_of_HQ, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6),
SLE_CONDVAR(CompanyProperties, location_of_HQ, SLE_UINT32, SLV_6, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, last_build_coordinate, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6),
@ -279,11 +262,9 @@ static const SaveLoad _company_desc[] = {
SLE_ARR(CompanyProperties, share_owners, SLE_UINT8, 4),
SLE_VAR(CompanyProperties, num_valid_stat_ent, SLE_UINT8),
SLE_CONDVAR(CompanyProperties, num_valid_stat_ent, SLE_UINT8, SL_MIN_VERSION, SLV_SAVELOAD_LIST_LENGTH),
SLE_VAR(CompanyProperties, months_of_bankruptcy, SLE_UINT8),
SLE_CONDVAR_X(CompanyProperties, bankrupt_last_asked, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_BANKRUPTCY_EXTRA)),
SLE_CONDVAR_X(CompanyProperties, bankrupt_flags, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_BANKRUPTCY_EXTRA, 2)),
SLE_CONDVAR(CompanyProperties, bankrupt_asked, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_104),
SLE_CONDVAR(CompanyProperties, bankrupt_asked, SLE_UINT16, SLV_104, SL_MAX_VERSION),
SLE_VAR(CompanyProperties, bankrupt_timeout, SLE_INT16),
@ -292,412 +273,91 @@ static const SaveLoad _company_desc[] = {
/* yearly expenses was changed to 64-bit in savegame version 2. */
SLE_CONDARR(CompanyProperties, yearly_expenses, SLE_FILE_I32 | SLE_VAR_I64, 3 * 13, SL_MIN_VERSION, SLV_2),
SLE_CONDARR_X(CompanyProperties, yearly_expenses, SLE_INT64, 3 * 13, SLV_2, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_INFRA_SHARING, 0, 0)),
SLE_CONDARR_X(CompanyProperties, yearly_expenses, SLE_INT64, 3 * 15, SLV_2, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_INFRA_SHARING)),
SLE_CONDARR(CompanyProperties, yearly_expenses, SLE_INT64, 3 * 13, SLV_2, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, is_ai, SLE_BOOL, SLV_2, SL_MAX_VERSION),
SLE_CONDNULL(1, SLV_107, SLV_112), ///< is_noai
SLE_CONDNULL(1, SLV_4, SLV_100),
SLE_CONDVAR(CompanyProperties, terraform_limit, SLE_UINT32, SLV_156, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, clear_limit, SLE_UINT32, SLV_156, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, tree_limit, SLE_UINT32, SLV_175, SL_MAX_VERSION),
SLE_CONDVAR_X(CompanyProperties, purchase_land_limit, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_BUY_LAND_RATE_LIMIT)),
SLE_CONDVAR_X(CompanyProperties, build_object_limit, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_BUILD_OBJECT_RATE_LIMIT)),
SLEG_STRUCT("settings", SlCompanySettings),
SLEG_CONDSTRUCT("old_ai", SlCompanyOldAI, SL_MIN_VERSION, SLV_107),
SLEG_STRUCT("cur_economy", SlCompanyEconomy),
SLEG_STRUCTLIST("old_economy", SlCompanyOldEconomy),
SLEG_CONDSTRUCTLIST("liveries", SlCompanyLiveries, SLV_34, SL_MAX_VERSION),
};
static const SaveLoad _company_settings_desc[] = {
/* Engine renewal settings */
SLE_CONDNULL(512, SLV_16, SLV_19),
SLE_CONDREF(Company, engine_renew_list, REF_ENGINE_RENEWS, SLV_19, SL_MAX_VERSION),
SLE_CONDVAR(Company, settings.engine_renew, SLE_BOOL, SLV_16, SL_MAX_VERSION),
SLE_CONDVAR(Company, settings.engine_renew_months, SLE_INT16, SLV_16, SL_MAX_VERSION),
SLE_CONDVAR(Company, settings.engine_renew_money, SLE_UINT32, SLV_16, SL_MAX_VERSION),
SLE_CONDVAR(Company, settings.renew_keep_length, SLE_BOOL, SLV_2, SL_MAX_VERSION),
/* Default vehicle settings */
SLE_CONDVAR(Company, settings.vehicle.servint_ispercent, SLE_BOOL, SLV_120, SL_MAX_VERSION),
SLE_CONDVAR(Company, settings.vehicle.servint_trains, SLE_UINT16, SLV_120, SL_MAX_VERSION),
SLE_CONDVAR(Company, settings.vehicle.servint_roadveh, SLE_UINT16, SLV_120, SL_MAX_VERSION),
SLE_CONDVAR(Company, settings.vehicle.servint_aircraft, SLE_UINT16, SLV_120, SL_MAX_VERSION),
SLE_CONDVAR(Company, settings.vehicle.servint_ships, SLE_UINT16, SLV_120, SL_MAX_VERSION),
SLE_CONDVAR_X(Company, settings.vehicle.auto_timetable_by_default, SLE_BOOL, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_AUTO_TIMETABLE, 2, 2)),
SLE_CONDNULL(63, SLV_2, SLV_144), // old reserved space
};
struct PLYRChunkHandler : ChunkHandler {
PLYRChunkHandler() : ChunkHandler('PLYR', CH_TABLE) {}
static const SaveLoad _company_settings_skip_desc[] = {
/* Engine renewal settings */
SLE_CONDNULL(512, SLV_16, SLV_19),
SLE_CONDNULL(2, SLV_19, SLV_69), // engine_renew_list
SLE_CONDNULL(4, SLV_69, SL_MAX_VERSION), // engine_renew_list
SLE_CONDNULL(1, SLV_16, SL_MAX_VERSION), // settings.engine_renew
SLE_CONDNULL(2, SLV_16, SL_MAX_VERSION), // settings.engine_renew_months
SLE_CONDNULL(4, SLV_16, SL_MAX_VERSION), // settings.engine_renew_money
SLE_CONDNULL(1, SLV_2, SL_MAX_VERSION), // settings.renew_keep_length
/* Default vehicle settings */
SLE_CONDNULL(1, SLV_120, SL_MAX_VERSION), // settings.vehicle.servint_ispercent
SLE_CONDNULL(2, SLV_120, SL_MAX_VERSION), // settings.vehicle.servint_trains
SLE_CONDNULL(2, SLV_120, SL_MAX_VERSION), // settings.vehicle.servint_roadveh
SLE_CONDNULL(2, SLV_120, SL_MAX_VERSION), // settings.vehicle.servint_aircraft
SLE_CONDNULL(2, SLV_120, SL_MAX_VERSION), // settings.vehicle.servint_ships
SLE_CONDNULL_X(1, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_AUTO_TIMETABLE, 2, 2)), // settings.vehicle.auto_timetable_by_default
SLE_CONDNULL(63, SLV_2, SLV_144), // old reserved space
};
static const SaveLoad _company_economy_desc[] = {
/* these were changed to 64-bit in savegame format 2 */
SLE_CONDVAR(CompanyEconomyEntry, income, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_2),
SLE_CONDVAR(CompanyEconomyEntry, income, SLE_INT64, SLV_2, SL_MAX_VERSION),
SLE_CONDVAR(CompanyEconomyEntry, expenses, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_2),
SLE_CONDVAR(CompanyEconomyEntry, expenses, SLE_INT64, SLV_2, SL_MAX_VERSION),
SLE_CONDVAR(CompanyEconomyEntry, company_value, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_2),
SLE_CONDVAR(CompanyEconomyEntry, company_value, SLE_INT64, SLV_2, SL_MAX_VERSION),
SLE_CONDVAR(CompanyEconomyEntry, delivered_cargo[NUM_CARGO - 1], SLE_INT32, SL_MIN_VERSION, SLV_170),
SLE_CONDARR(CompanyEconomyEntry, delivered_cargo, SLE_UINT32, 32, SLV_170, SLV_EXTEND_CARGOTYPES),
SLE_CONDARR(CompanyEconomyEntry, delivered_cargo, SLE_UINT32, NUM_CARGO, SLV_EXTEND_CARGOTYPES, SL_MAX_VERSION),
SLE_VAR(CompanyEconomyEntry, performance_history, SLE_INT32),
};
void Save() const override
{
SlTableHeader(_company_desc);
/* We do need to read this single value, as the bigger it gets, the more data is stored */
struct CompanyOldAI {
uint8 num_build_rec;
};
static const SaveLoad _company_ai_desc[] = {
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_107),
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_13),
SLE_CONDNULL(4, SLV_13, SLV_107),
SLE_CONDNULL(8, SL_MIN_VERSION, SLV_107),
SLE_CONDVAR(CompanyOldAI, num_build_rec, SLE_UINT8, SL_MIN_VERSION, SLV_107),
SLE_CONDNULL(3, SL_MIN_VERSION, SLV_107),
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_6),
SLE_CONDNULL(4, SLV_6, SLV_107),
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_6),
SLE_CONDNULL(4, SLV_6, SLV_107),
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_107),
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_6),
SLE_CONDNULL(4, SLV_6, SLV_107),
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_6),
SLE_CONDNULL(4, SLV_6, SLV_107),
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_107),
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_69),
SLE_CONDNULL(4, SLV_69, SLV_107),
SLE_CONDNULL(18, SL_MIN_VERSION, SLV_107),
SLE_CONDNULL(20, SL_MIN_VERSION, SLV_107),
SLE_CONDNULL(32, SL_MIN_VERSION, SLV_107),
SLE_CONDNULL(64, SLV_2, SLV_107),
};
static const SaveLoad _company_ai_build_rec_desc[] = {
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_6),
SLE_CONDNULL(4, SLV_6, SLV_107),
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_6),
SLE_CONDNULL(4, SLV_6, SLV_107),
SLE_CONDNULL(8, SL_MIN_VERSION, SLV_107),
};
static const SaveLoad _company_livery_desc[] = {
SLE_CONDVAR(Livery, in_use, SLE_UINT8, SLV_34, SL_MAX_VERSION),
SLE_CONDVAR(Livery, colour1, SLE_UINT8, SLV_34, SL_MAX_VERSION),
SLE_CONDVAR(Livery, colour2, SLE_UINT8, SLV_34, SL_MAX_VERSION),
};
static void SaveLoad_PLYR_common(Company *c, CompanyProperties *cprops)
{
int i;
SlObject(cprops, _company_desc);
if (c != nullptr) {
SlObject(c, _company_settings_desc);
} else {
char nothing;
SlObject(&nothing, _company_settings_skip_desc);
}
/* Keep backwards compatible for savegames, so load the old AI block */
if (IsSavegameVersionBefore(SLV_107) && cprops->is_ai) {
CompanyOldAI old_ai;
char nothing;
SlObject(&old_ai, _company_ai_desc);
for (i = 0; i != old_ai.num_build_rec; i++) {
SlObject(&nothing, _company_ai_build_rec_desc);
for (Company *c : Company::Iterate()) {
SlSetArrayIndex(c->index);
SlObject(c, _company_desc);
}
}
/* Write economy */
SlObject(&cprops->cur_economy, _company_economy_desc);
/* Write old economy entries. */
if (cprops->num_valid_stat_ent > lengthof(cprops->old_economy)) SlErrorCorrupt("Too many old economy entries");
for (i = 0; i < cprops->num_valid_stat_ent; i++) {
SlObject(&cprops->old_economy[i], _company_economy_desc);
}
/* Write each livery entry. */
int num_liveries = IsSavegameVersionBefore(SLV_63) ? LS_END - 4 : (IsSavegameVersionBefore(SLV_85) ? LS_END - 2: LS_END);
bool update_in_use = IsSavegameVersionBefore(SLV_GROUP_LIVERIES);
if (c != nullptr) {
for (i = 0; i < num_liveries; i++) {
SlObject(&c->livery[i], _company_livery_desc);
if (update_in_use && i != LS_DEFAULT) {
if (c->livery[i].in_use == 0) {
c->livery[i].colour1 = c->livery[LS_DEFAULT].colour1;
c->livery[i].colour2 = c->livery[LS_DEFAULT].colour2;
} else {
c->livery[i].in_use = 3;
}
}
}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_company_desc, _company_sl_compat);
if (num_liveries < LS_END) {
/* We want to insert some liveries somewhere in between. This means some have to be moved. */
memmove(&c->livery[LS_FREIGHT_WAGON], &c->livery[LS_PASSENGER_WAGON_MONORAIL], (LS_END - LS_FREIGHT_WAGON) * sizeof(c->livery[0]));
c->livery[LS_PASSENGER_WAGON_MONORAIL] = c->livery[LS_MONORAIL];
c->livery[LS_PASSENGER_WAGON_MAGLEV] = c->livery[LS_MAGLEV];
}
if (num_liveries == LS_END - 4) {
/* Copy bus/truck liveries over to trams */
c->livery[LS_PASSENGER_TRAM] = c->livery[LS_BUS];
c->livery[LS_FREIGHT_TRAM] = c->livery[LS_TRUCK];
}
} else {
/* Skip liveries */
Livery dummy_livery;
for (i = 0; i < num_liveries; i++) {
SlObject(&dummy_livery, _company_livery_desc);
int index;
while ((index = SlIterateArray()) != -1) {
Company *c = new (index) Company();
SetDefaultCompanySettings(c->index);
SlObject((CompanyProperties *)c, slt);
_company_colours[index] = (Colours)c->colour;
}
}
}
static void SaveLoad_PLYR(Company *c)
{
SaveLoad_PLYR_common(c, c);
}
static void Save_PLYR()
{
for (Company *c : Company::Iterate()) {
SlSetArrayIndex(c->index);
SlAutolength((AutolengthProc*)SaveLoad_PLYR, c);
}
}
void LoadCheck(size_t) const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_company_desc, _company_sl_compat);
static void Load_PLYR()
{
int index;
while ((index = SlIterateArray()) != -1) {
Company *c = new (index) Company();
SetDefaultCompanySettings(c->index);
SaveLoad_PLYR(c);
_company_colours[index] = (Colours)c->colour;
// settings moved from game settings to company settings
if (SlXvIsFeaturePresent(XSLFI_AUTO_TIMETABLE, 1, 2)) {
c->settings.auto_timetable_separation_rate = _settings_game.order.old_timetable_separation_rate;
}
if (SlXvIsFeaturePresent(XSLFI_AUTO_TIMETABLE, 1, 3)) {
c->settings.vehicle.auto_separation_by_default = _settings_game.order.old_timetable_separation;
}
}
}
int index;
while ((index = SlIterateArray()) != -1) {
CompanyProperties *cprops = new CompanyProperties();
SlObject(cprops, slt);
static void Check_PLYR()
{
int index;
while ((index = SlIterateArray()) != -1) {
CompanyProperties *cprops = new CompanyProperties();
SaveLoad_PLYR_common(nullptr, cprops);
/* We do not load old custom names */
if (IsSavegameVersionBefore(SLV_84)) {
if (GetStringTab(cprops->name_1) == TEXT_TAB_OLD_CUSTOM) {
cprops->name_1 = STR_GAME_SAVELOAD_NOT_AVAILABLE;
}
/* We do not load old custom names */
if (IsSavegameVersionBefore(SLV_84)) {
if (GetStringTab(cprops->name_1) == TEXT_TAB_OLD_CUSTOM) {
cprops->name_1 = STR_GAME_SAVELOAD_NOT_AVAILABLE;
}
if (GetStringTab(cprops->president_name_1) == TEXT_TAB_OLD_CUSTOM) {
cprops->president_name_1 = STR_GAME_SAVELOAD_NOT_AVAILABLE;
if (GetStringTab(cprops->president_name_1) == TEXT_TAB_OLD_CUSTOM) {
cprops->president_name_1 = STR_GAME_SAVELOAD_NOT_AVAILABLE;
}
}
}
if (cprops->name.empty() && !IsInsideMM(cprops->name_1, SPECSTR_COMPANY_NAME_START, SPECSTR_COMPANY_NAME_LAST + 1) &&
if (cprops->name.empty() && !IsInsideMM(cprops->name_1, SPECSTR_COMPANY_NAME_START, SPECSTR_COMPANY_NAME_LAST + 1) &&
cprops->name_1 != STR_GAME_SAVELOAD_NOT_AVAILABLE && cprops->name_1 != STR_SV_UNNAMED &&
cprops->name_1 != SPECSTR_ANDCO_NAME && cprops->name_1 != SPECSTR_PRESIDENT_NAME &&
cprops->name_1 != SPECSTR_SILLY_NAME) {
cprops->name_1 = STR_GAME_SAVELOAD_NOT_AVAILABLE;
}
if (!_load_check_data.companies.Insert(index, cprops)) delete cprops;
}
}
static void Ptrs_PLYR()
{
for (Company *c : Company::Iterate()) {
SlObject(c, _company_settings_desc);
}
}
extern void LoadSettingsPlyx(bool skip);
extern void SaveSettingsPlyx();
static void Load_PLYX()
{
LoadSettingsPlyx(false);
}
static void Check_PLYX()
{
LoadSettingsPlyx(true);
}
static void Save_PLYX()
{
SaveSettingsPlyx();
}
static void Load_PLYP()
{
size_t size = SlGetFieldLength();
CompanyMask invalid_mask = 0;
if (SlXvIsFeaturePresent(XSLFI_COMPANY_PW, 2)) {
if (size <= 2) return;
invalid_mask = SlReadUint16();
size -= 2;
}
if (size <= 16 + 24 + 16 || (_networking && !_network_server)) {
SlSkipBytes(size);
return;
}
if (!_network_server) {
extern CompanyMask _saved_PLYP_invalid_mask;
extern std::vector<uint8> _saved_PLYP_data;
_saved_PLYP_invalid_mask = invalid_mask;
_saved_PLYP_data.resize(size);
ReadBuffer::GetCurrent()->CopyBytes(_saved_PLYP_data.data(), _saved_PLYP_data.size());
return;
}
uint8 token[16];
ReadBuffer::GetCurrent()->CopyBytes(token, 16);
if (memcmp(token, _network_company_password_storage_token, 16) != 0) {
DEBUG(sl, 2, "Skipping encrypted company passwords");
SlSkipBytes(size - 16);
return;
}
uint8 nonce[24];
uint8 mac[16];
ReadBuffer::GetCurrent()->CopyBytes(nonce, 24);
ReadBuffer::GetCurrent()->CopyBytes(mac, 16);
std::vector<uint8> buffer(size - 16 - 24 - 16);
ReadBuffer::GetCurrent()->CopyBytes(buffer.data(), buffer.size());
if (crypto_unlock(buffer.data(), _network_company_password_storage_key, nonce, mac, buffer.data(), buffer.size()) == 0) {
SlLoadFromBuffer(buffer.data(), buffer.size(), [invalid_mask]() {
_network_company_server_id.resize(SlReadUint32());
ReadBuffer::GetCurrent()->CopyBytes((uint8 *)_network_company_server_id.data(), _network_company_server_id.size());
while (true) {
uint16 cid = SlReadUint16();
if (cid >= MAX_COMPANIES) break;
std::string password;
password.resize(SlReadUint32());
ReadBuffer::GetCurrent()->CopyBytes((uint8 *)password.data(), password.size());
if (!HasBit(invalid_mask, cid)) {
NetworkServerSetCompanyPassword((CompanyID)cid, password, true);
}
cprops->name_1 = STR_GAME_SAVELOAD_NOT_AVAILABLE;
}
ReadBuffer::GetCurrent()->SkipBytes(SlReadByte()); // Skip padding
});
DEBUG(sl, 2, "Decrypted company passwords");
} else {
DEBUG(sl, 2, "Failed to decrypt company passwords");
}
}
static void Save_PLYP()
{
if ((_networking && !_network_server) || IsNetworkServerSave()) {
SlSetLength(0);
return;
}
if (!_network_server) {
extern CompanyMask _saved_PLYP_invalid_mask;
extern std::vector<uint8> _saved_PLYP_data;
if (_saved_PLYP_data.empty()) {
SlSetLength(0);
} else {
SlSetLength(2 + _saved_PLYP_data.size());
SlWriteUint16(_saved_PLYP_invalid_mask);
MemoryDumper::GetCurrent()->CopyBytes((const uint8 *)_saved_PLYP_data.data(), _saved_PLYP_data.size());
if (!_load_check_data.companies.Insert(index, cprops)) delete cprops;
}
return;
}
uint8 nonce[24]; /* Use only once per key: random */
if (randombytes(nonce, 24) < 0) {
/* Can't get a random nonce, just give up */
SlSetLength(0);
return;
}
std::vector<byte> buffer = SlSaveToVector([](void *) {
SlWriteUint32((uint32)_network_company_server_id.size());
MemoryDumper::GetCurrent()->CopyBytes((const uint8 *)_network_company_server_id.data(), _network_company_server_id.size());
for (const Company *c : Company::Iterate()) {
SlWriteUint16(c->index);
const std::string &password = _network_company_states[c->index].password;
SlWriteUint32((uint32)password.size());
MemoryDumper::GetCurrent()->CopyBytes((const uint8 *)password.data(), password.size());
void FixPointers() const override
{
for (Company *c : Company::Iterate()) {
SlObject((CompanyProperties *)c, _company_desc);
}
}
};
SlWriteUint16(0xFFFF);
/* Add some random length padding to not make it too obvious from the length whether passwords are set or not */
uint8 padding[256];
if (randombytes(padding, 256) >= 0) {
SlWriteByte(padding[0]);
MemoryDumper::GetCurrent()->CopyBytes(padding + 1, padding[0]);
} else {
SlWriteByte(0);
}
}, nullptr);
uint8 mac[16]; /* Message authentication code */
/* Encrypt in place */
crypto_lock(mac, buffer.data(), _network_company_password_storage_key, nonce, buffer.data(), buffer.size());
SlSetLength(2 + 16 + 24 + 16 + buffer.size());
SlWriteUint16(0); // Invalid mask
MemoryDumper::GetCurrent()->CopyBytes(_network_company_password_storage_token, 16);
MemoryDumper::GetCurrent()->CopyBytes(nonce, 24);
MemoryDumper::GetCurrent()->CopyBytes(mac, 16);
MemoryDumper::GetCurrent()->CopyBytes(buffer.data(), buffer.size());
}
static const ChunkHandler company_chunk_handlers[] = {
{ 'PLYR', Save_PLYR, Load_PLYR, Ptrs_PLYR, Check_PLYR, CH_ARRAY },
{ 'PLYX', Save_PLYX, Load_PLYX, nullptr, Check_PLYX, CH_RIFF },
{ 'PLYP', Save_PLYP, Load_PLYP, nullptr, nullptr, CH_RIFF },
static const PLYRChunkHandler PLYR;
static const ChunkHandlerRef company_chunk_handlers[] = {
PLYR,
};
extern const ChunkHandlerTable _company_chunk_handlers(company_chunk_handlers);
}

@ -8,57 +8,71 @@
/** @file depot_sl.cpp Code handling saving and loading of depots */
#include "../stdafx.h"
#include "../depot_base.h"
#include "../town.h"
#include "saveload.h"
#include "compat/depot_sl_compat.h"
#include "../depot_base.h"
#include "../town.h"
#include "../safeguards.h"
namespace upstream_sl {
static TownID _town_index;
static const SaveLoad _depot_desc[] = {
SLE_CONDVAR(Depot, xy, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6),
SLE_CONDVAR(Depot, xy, SLE_UINT32, SLV_6, SL_MAX_VERSION),
SLEG_CONDVAR(_town_index, SLE_UINT16, SL_MIN_VERSION, SLV_141),
SLEG_CONDVAR("town_index", _town_index, SLE_UINT16, SL_MIN_VERSION, SLV_141),
SLE_CONDREF(Depot, town, REF_TOWN, SLV_141, SL_MAX_VERSION),
SLE_CONDVAR(Depot, town_cn, SLE_UINT16, SLV_141, SL_MAX_VERSION),
SLE_CONDSTR(Depot, name, SLE_STR, 0, SLV_141, SL_MAX_VERSION),
SLE_CONDVAR(Depot, build_date, SLE_INT32, SLV_142, SL_MAX_VERSION),
SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SPRINGPP, 5)),
};
static void Save_DEPT()
{
for (Depot *depot : Depot::Iterate()) {
SlSetArrayIndex(depot->index);
SlObject(depot, _depot_desc);
struct DEPTChunkHandler : ChunkHandler {
DEPTChunkHandler() : ChunkHandler('DEPT', CH_TABLE) {}
void Save() const override
{
SlTableHeader(_depot_desc);
for (Depot *depot : Depot::Iterate()) {
SlSetArrayIndex(depot->index);
SlObject(depot, _depot_desc);
}
}
}
static void Load_DEPT()
{
int index;
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_depot_desc, _depot_sl_compat);
int index;
while ((index = SlIterateArray()) != -1) {
Depot *depot = new (index) Depot();
SlObject(depot, _depot_desc);
while ((index = SlIterateArray()) != -1) {
Depot *depot = new (index) Depot();
SlObject(depot, slt);
/* Set the town 'pointer' so we can restore it later. */
if (IsSavegameVersionBefore(SLV_141)) depot->town = (Town *)(size_t)_town_index;
/* Set the town 'pointer' so we can restore it later. */
if (IsSavegameVersionBefore(SLV_141)) depot->town = (Town *)(size_t)_town_index;
}
}
}
static void Ptrs_DEPT()
{
for (Depot *depot : Depot::Iterate()) {
SlObject(depot, _depot_desc);
if (IsSavegameVersionBefore(SLV_141)) depot->town = Town::Get((size_t)depot->town);
void FixPointers() const override
{
for (Depot *depot : Depot::Iterate()) {
SlObject(depot, _depot_desc);
if (IsSavegameVersionBefore(SLV_141)) depot->town = Town::Get((size_t)depot->town);
}
}
}
};
static const ChunkHandler depot_chunk_handlers[] = {
{ 'DEPT', Save_DEPT, Load_DEPT, Ptrs_DEPT, nullptr, CH_ARRAY },
static const DEPTChunkHandler DEPT;
static const ChunkHandlerRef depot_chunk_handlers[] = {
DEPT,
};
extern const ChunkHandlerTable _depot_chunk_handlers(depot_chunk_handlers);
}

@ -8,34 +8,18 @@
/** @file economy_sl.cpp Code handling saving and loading of economy data */
#include "../stdafx.h"
#include "../economy_func.h"
#include "../economy_base.h"
#include "saveload.h"
#include "compat/economy_sl_compat.h"
#include "../safeguards.h"
#include "../economy_func.h"
#include "../economy_base.h"
/** Prices in pre 126 savegames */
static void Load_PRIC()
{
/* Old games store 49 base prices, very old games store them as int32 */
int vt = IsSavegameVersionBefore(SLV_65) ? SLE_FILE_I32 : SLE_FILE_I64;
SlArray(nullptr, 49, vt | SLE_VAR_NULL);
SlArray(nullptr, 49, SLE_FILE_U16 | SLE_VAR_NULL);
}
#include "../safeguards.h"
/** Cargo payment rates in pre 126 savegames */
static void Load_CAPR()
{
uint num_cargo = IsSavegameVersionBefore(SLV_55) ? 12 : IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO;
int vt = IsSavegameVersionBefore(SLV_65) ? SLE_FILE_I32 : SLE_FILE_I64;
SlArray(nullptr, num_cargo, vt | SLE_VAR_NULL);
SlArray(nullptr, num_cargo, SLE_FILE_U16 | SLE_VAR_NULL);
}
namespace upstream_sl {
static const SaveLoad _economy_desc[] = {
SLE_CONDNULL(4, SL_MIN_VERSION, SLV_65), // max_loan
SLE_CONDNULL(8, SLV_65, SLV_144), // max_loan
SLE_CONDVAR(Economy, old_max_loan_unround, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_65),
SLE_CONDVAR(Economy, old_max_loan_unround, SLE_INT64, SLV_65, SLV_126),
SLE_CONDVAR(Economy, old_max_loan_unround_fract, SLE_UINT16, SLV_70, SLV_126),
@ -46,60 +30,80 @@ static const SaveLoad _economy_desc[] = {
SLE_VAR(Economy, infl_amount, SLE_UINT8),
SLE_VAR(Economy, infl_amount_pr, SLE_UINT8),
SLE_CONDVAR(Economy, industry_daily_change_counter, SLE_UINT32, SLV_102, SL_MAX_VERSION),
SLE_CONDNULL_X(8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP)),
};
/** Economy variables */
static void Save_ECMY()
{
SlObject(&_economy, _economy_desc);
}
struct ECMYChunkHandler : ChunkHandler {
ECMYChunkHandler() : ChunkHandler('ECMY', CH_TABLE) {}
/** Economy variables */
static void Load_ECMY()
{
SlObject(&_economy, _economy_desc);
StartupIndustryDailyChanges(IsSavegameVersionBefore(SLV_102)); // old savegames will need to be initialized
}
void Save() const override
{
SlTableHeader(_economy_desc);
SlSetArrayIndex(0);
SlObject(&_economy, _economy_desc);
}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_economy_desc, _economy_sl_compat);
if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() == -1) return;
SlObject(&_economy, slt);
if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many ECMY entries");
StartupIndustryDailyChanges(IsSavegameVersionBefore(SLV_102)); // old savegames will need to be initialized
}
};
static const SaveLoad _cargopayment_desc[] = {
SLE_REF(CargoPayment, front, REF_VEHICLE),
SLE_VAR(CargoPayment, route_profit, SLE_INT64),
SLE_VAR(CargoPayment, visual_profit, SLE_INT64),
SLE_CONDVAR_X(CargoPayment, visual_transfer, SLE_INT64, SLV_181, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_OR, XSLFI_CHILLPP)),
SLE_CONDVAR(CargoPayment, visual_transfer, SLE_INT64, SLV_181, SL_MAX_VERSION),
};
static void Save_CAPY()
{
for (CargoPayment *cp : CargoPayment::Iterate()) {
SlSetArrayIndex(cp->index);
SlObject(cp, _cargopayment_desc);
}
}
struct CAPYChunkHandler : ChunkHandler {
CAPYChunkHandler() : ChunkHandler('CAPY', CH_TABLE) {}
static void Load_CAPY()
{
int index;
void Save() const override
{
SlTableHeader(_cargopayment_desc);
while ((index = SlIterateArray()) != -1) {
CargoPayment *cp = new (index) CargoPayment();
SlObject(cp, _cargopayment_desc);
for (CargoPayment *cp : CargoPayment::Iterate()) {
SlSetArrayIndex(cp->index);
SlObject(cp, _cargopayment_desc);
}
}
}
static void Ptrs_CAPY()
{
for (CargoPayment *cp : CargoPayment::Iterate()) {
SlObject(cp, _cargopayment_desc);
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_cargopayment_desc, _cargopayment_sl_compat);
int index;
while ((index = SlIterateArray()) != -1) {
CargoPayment *cp = new (index) CargoPayment();
SlObject(cp, slt);
}
}
}
void FixPointers() const override
{
for (CargoPayment *cp : CargoPayment::Iterate()) {
SlObject(cp, _cargopayment_desc);
}
}
};
static const ChunkHandler economy_chunk_handlers[] = {
{ 'CAPY', Save_CAPY, Load_CAPY, Ptrs_CAPY, nullptr, CH_ARRAY },
{ 'PRIC', nullptr, Load_PRIC, nullptr, nullptr, CH_RIFF },
{ 'CAPR', nullptr, Load_CAPR, nullptr, nullptr, CH_RIFF },
{ 'ECMY', Save_ECMY, Load_ECMY, nullptr, nullptr, CH_RIFF },
static const CAPYChunkHandler CAPY;
static const ECMYChunkHandler ECMY;
static const ChunkHandlerRef economy_chunk_handlers[] = {
CAPY,
ECMY,
};
extern const ChunkHandlerTable _economy_chunk_handlers(economy_chunk_handlers);
}

@ -8,14 +8,20 @@
/** @file engine_sl.cpp Code handling saving and loading of engines */
#include "../stdafx.h"
#include "saveload_internal.h"
#include "saveload.h"
#include "compat/engine_sl_compat.h"
#include "../engine_base.h"
#include "../engine_func.h"
#include "../string_func.h"
#include <vector>
#include "../safeguards.h"
Engine *GetTempDataEngine(EngineID index);
namespace upstream_sl {
static const SaveLoad _engine_desc[] = {
SLE_CONDVAR(Engine, intro_date, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31),
SLE_CONDVAR(Engine, intro_date, SLE_INT32, SLV_31, SL_MAX_VERSION),
@ -29,142 +35,51 @@ static const SaveLoad _engine_desc[] = {
SLE_VAR(Engine, duration_phase_1, SLE_UINT16),
SLE_VAR(Engine, duration_phase_2, SLE_UINT16),
SLE_VAR(Engine, duration_phase_3, SLE_UINT16),
SLE_CONDNULL(1, SL_MIN_VERSION, SLV_121),
SLE_VAR(Engine, flags, SLE_UINT8),
SLE_CONDNULL(1, SL_MIN_VERSION, SLV_179), // old preview_company_rank
SLE_CONDVAR(Engine, preview_asked, SLE_UINT16, SLV_179, SL_MAX_VERSION),
SLE_CONDVAR(Engine, preview_company, SLE_UINT8, SLV_179, SL_MAX_VERSION),
SLE_VAR(Engine, preview_wait, SLE_UINT8),
SLE_CONDNULL(1, SL_MIN_VERSION, SLV_45),
SLE_CONDVAR(Engine, company_avail, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_104),
SLE_CONDVAR(Engine, company_avail, SLE_UINT16, SLV_104, SL_MAX_VERSION),
SLE_CONDVAR(Engine, company_hidden, SLE_UINT16, SLV_193, SL_MAX_VERSION),
SLE_CONDSTR(Engine, name, SLE_STR, 0, SLV_84, SL_MAX_VERSION),
SLE_CONDNULL(16, SLV_2, SLV_144), // old reserved space
SLE_CONDSTR(Engine, name, SLE_STR, 0, SLV_84, SL_MAX_VERSION),
};
static std::vector<Engine*> _temp_engine;
/**
* Allocate an Engine structure, but not using the pools.
* The allocated Engine must be freed using FreeEngine;
* @return Allocated engine.
*/
static Engine* CallocEngine()
{
uint8 *zero = CallocT<uint8>(sizeof(Engine));
Engine *engine = new (zero) Engine();
return engine;
}
/**
* Deallocate an Engine constructed by CallocEngine.
* @param e Engine to free.
*/
static void FreeEngine(Engine *e)
{
if (e != nullptr) {
e->~Engine();
free(e);
}
}
Engine *GetTempDataEngine(EngineID index)
{
if (index < _temp_engine.size()) {
return _temp_engine[index];
} else if (index == _temp_engine.size()) {
_temp_engine.push_back(CallocEngine());
return _temp_engine[index];
} else {
NOT_REACHED();
}
}
struct ENGNChunkHandler : ChunkHandler {
ENGNChunkHandler() : ChunkHandler('ENGN', CH_TABLE) {}
static void Save_ENGN()
{
for (Engine *e : Engine::Iterate()) {
SlSetArrayIndex(e->index);
SlObject(e, _engine_desc);
}
}
void Save() const override
{
SlTableHeader(_engine_desc);
static void Load_ENGN()
{
/* As engine data is loaded before engines are initialized we need to load
* this information into a temporary array. This is then copied into the
* engine pool after processing NewGRFs by CopyTempEngineData(). */
int index;
while ((index = SlIterateArray()) != -1) {
Engine *e = GetTempDataEngine(index);
SlObject(e, _engine_desc);
if (IsSavegameVersionBefore(SLV_179)) {
/* preview_company_rank was replaced with preview_company and preview_asked.
* Just cancel any previews. */
e->flags &= ~4; // ENGINE_OFFER_WINDOW_OPEN
e->preview_company = INVALID_COMPANY;
e->preview_asked = MAX_UVALUE(CompanyMask);
for (Engine *e : Engine::Iterate()) {
SlSetArrayIndex(e->index);
SlObject(e, _engine_desc);
}
}
}
/**
* Copy data from temporary engine array into the real engine pool.
*/
void CopyTempEngineData()
{
for (Engine *e : Engine::Iterate()) {
if (e->index >= _temp_engine.size()) break;
const Engine *se = GetTempDataEngine(e->index);
e->intro_date = se->intro_date;
e->age = se->age;
e->reliability = se->reliability;
e->reliability_spd_dec = se->reliability_spd_dec;
e->reliability_start = se->reliability_start;
e->reliability_max = se->reliability_max;
e->reliability_final = se->reliability_final;
e->duration_phase_1 = se->duration_phase_1;
e->duration_phase_2 = se->duration_phase_2;
e->duration_phase_3 = se->duration_phase_3;
e->flags = se->flags;
e->preview_asked = se->preview_asked;
e->preview_company = se->preview_company;
e->preview_wait = se->preview_wait;
e->company_avail = se->company_avail;
e->company_hidden = se->company_hidden;
e->name = se->name;
}
ResetTempEngineData();
}
void ResetTempEngineData()
{
/* Get rid of temporary data */
for (std::vector<Engine*>::iterator it = _temp_engine.begin(); it != _temp_engine.end(); ++it) {
FreeEngine(*it);
}
_temp_engine.clear();
}
static void Load_ENGS()
{
/* Load old separate String ID list into a temporary array. This
* was always 256 entries. */
StringID names[256];
SlArray(names, lengthof(names), SLE_STRINGID);
/* Copy each string into the temporary engine array. */
for (EngineID engine = 0; engine < lengthof(names); engine++) {
Engine *e = GetTempDataEngine(engine);
e->name = CopyFromOldName(names[engine]);
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_engine_desc, _engine_sl_compat);
/* As engine data is loaded before engines are initialized we need to load
* this information into a temporary array. This is then copied into the
* engine pool after processing NewGRFs by CopyTempEngineData(). */
int index;
while ((index = SlIterateArray()) != -1) {
Engine *e = GetTempDataEngine(index);
SlObject(e, slt);
if (IsSavegameVersionBefore(SLV_179)) {
/* preview_company_rank was replaced with preview_company and preview_asked.
* Just cancel any previews. */
e->flags &= ~4; // ENGINE_OFFER_WINDOW_OPEN
e->preview_company = INVALID_COMPANY;
e->preview_asked = MAX_UVALUE(CompanyMask);
}
}
}
}
};
/** Save and load the mapping between the engine id in the pool, and the grf file it came from. */
static const SaveLoad _engine_id_mapping_desc[] = {
@ -174,35 +89,41 @@ static const SaveLoad _engine_id_mapping_desc[] = {
SLE_VAR(EngineIDMapping, substitute_id, SLE_UINT8),
};
static void Save_EIDS()
{
uint index = 0;
for (EngineIDMapping &eid : _engine_mngr) {
SlSetArrayIndex(index);
SlObject(&eid, _engine_id_mapping_desc);
index++;
}
}
struct EIDSChunkHandler : ChunkHandler {
EIDSChunkHandler() : ChunkHandler('EIDS', CH_TABLE) {}
static void Load_EIDS()
{
_engine_mngr.clear();
void Save() const override
{
SlTableHeader(_engine_id_mapping_desc);
while (SlIterateArray() != -1) {
EngineIDMapping *eid = &_engine_mngr.emplace_back();
SlObject(eid, _engine_id_mapping_desc);
uint index = 0;
for (EngineIDMapping &eid : _engine_mngr) {
SlSetArrayIndex(index);
SlObject(&eid, _engine_id_mapping_desc);
index++;
}
}
}
void AfterLoadEngines()
{
AnalyseEngineCallbacks();
}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_engine_id_mapping_desc, _engine_id_mapping_sl_compat);
_engine_mngr.clear();
static const ChunkHandler engine_chunk_handlers[] = {
{ 'EIDS', Save_EIDS, Load_EIDS, nullptr, nullptr, CH_ARRAY },
{ 'ENGN', Save_ENGN, Load_ENGN, nullptr, nullptr, CH_ARRAY },
{ 'ENGS', nullptr, Load_ENGS, nullptr, nullptr, CH_RIFF },
while (SlIterateArray() != -1) {
EngineIDMapping *eid = &_engine_mngr.emplace_back();
SlObject(eid, slt);
}
}
};
static const EIDSChunkHandler EIDS;
static const ENGNChunkHandler ENGN;
static const ChunkHandlerRef engine_chunk_handlers[] = {
EIDS,
ENGN,
};
extern const ChunkHandlerTable _engine_chunk_handlers(engine_chunk_handlers);
}

@ -9,9 +9,11 @@
#include "../stdafx.h"
#include "../debug.h"
#include "saveload.h"
#include "../string_func.h"
#include "compat/game_sl_compat.h"
#include "../string_func.h"
#include "../game/game.hpp"
#include "../game/game_config.hpp"
#include "../network/network.h"
@ -20,16 +22,20 @@
#include "../safeguards.h"
extern GameStrings *_current_data;
namespace upstream_sl {
static std::string _game_saveload_name;
static int _game_saveload_version;
static std::string _game_saveload_settings;
static bool _game_saveload_is_random;
static const SaveLoad _game_script[] = {
SLEG_SSTR(_game_saveload_name, SLE_STR),
SLEG_SSTR(_game_saveload_settings, SLE_STR),
SLEG_VAR(_game_saveload_version, SLE_UINT32),
SLEG_VAR(_game_saveload_is_random, SLE_BOOL),
static const SaveLoad _game_script_desc[] = {
SLEG_SSTR("name", _game_saveload_name, SLE_STR),
SLEG_SSTR("settings", _game_saveload_settings, SLE_STR),
SLEG_VAR("version", _game_saveload_version, SLE_UINT32),
SLEG_VAR("is_random", _game_saveload_is_random, SLE_BOOL),
};
static void SaveReal_GSDT(int *index_ptr)
@ -48,133 +54,156 @@ static void SaveReal_GSDT(int *index_ptr)
_game_saveload_is_random = config->IsRandom();
_game_saveload_settings = config->SettingsToString();
SlObject(nullptr, _game_script);
SlObject(nullptr, _game_script_desc);
Game::Save();
}
static void Load_GSDT()
{
/* Free all current data */
GameConfig::GetConfig(GameConfig::SSS_FORCE_GAME)->Change(nullptr);
struct GSDTChunkHandler : ChunkHandler {
GSDTChunkHandler() : ChunkHandler('GSDT', CH_TABLE) {}
if ((CompanyID)SlIterateArray() == (CompanyID)-1) return;
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_game_script_desc, _game_script_sl_compat);
_game_saveload_version = -1;
SlObject(nullptr, _game_script);
/* Free all current data */
GameConfig::GetConfig(GameConfig::SSS_FORCE_GAME)->Change(nullptr);
if (_game_mode == GM_MENU || (_networking && !_network_server)) {
GameInstance::LoadEmpty();
if ((CompanyID)SlIterateArray() != (CompanyID)-1) SlErrorCorrupt("Too many GameScript configs");
return;
}
if (SlIterateArray() == -1) return;
GameConfig *config = GameConfig::GetConfig(GameConfig::SSS_FORCE_GAME);
if (!_game_saveload_name.empty()) {
config->Change(_game_saveload_name.c_str(), _game_saveload_version, false, _game_saveload_is_random);
if (!config->HasScript()) {
/* No version of the GameScript available that can load the data. Try to load the
* latest version of the GameScript instead. */
config->Change(_game_saveload_name.c_str(), -1, false, _game_saveload_is_random);
_game_saveload_version = -1;
SlObject(nullptr, slt);
if (_game_mode == GM_MENU || (_networking && !_network_server)) {
GameInstance::LoadEmpty();
if (SlIterateArray() != -1) SlErrorCorrupt("Too many GameScript configs");
return;
}
GameConfig *config = GameConfig::GetConfig(GameConfig::SSS_FORCE_GAME);
if (!_game_saveload_name.empty()) {
config->Change(_game_saveload_name.c_str(), _game_saveload_version, false, _game_saveload_is_random);
if (!config->HasScript()) {
if (_game_saveload_name.compare("%_dummy") != 0) {
DEBUG(script, 0, "The savegame has an GameScript by the name '%s', version %d which is no longer available.", _game_saveload_name.c_str(), _game_saveload_version);
DEBUG(script, 0, "This game will continue to run without GameScript.");
/* No version of the GameScript available that can load the data. Try to load the
* latest version of the GameScript instead. */
config->Change(_game_saveload_name.c_str(), -1, false, _game_saveload_is_random);
if (!config->HasScript()) {
if (_game_saveload_name.compare("%_dummy") != 0) {
DEBUG(script, 0, "The savegame has an GameScript by the name '%s', version %u which is no longer available.", _game_saveload_name.c_str(), _game_saveload_version);
DEBUG(script, 0, "This game will continue to run without GameScript.");
} else {
DEBUG(script, 0, "The savegame had no GameScript available at the time of saving.");
DEBUG(script, 0, "This game will continue to run without GameScript.");
}
} else {
DEBUG(script, 0, "The savegame had no GameScript available at the time of saving.");
DEBUG(script, 0, "This game will continue to run without GameScript.");
DEBUG(script, 0, "The savegame has an GameScript by the name '%s', version %u which is no longer available.", _game_saveload_name.c_str(), _game_saveload_version);
DEBUG(script, 0, "The latest version of that GameScript has been loaded instead, but it'll not get the savegame data as it's incompatible.");
}
} else {
DEBUG(script, 0, "The savegame has an GameScript by the name '%s', version %d which is no longer available.", _game_saveload_name.c_str(), _game_saveload_version);
DEBUG(script, 0, "The latest version of that GameScript has been loaded instead, but it'll not get the savegame data as it's incompatible.");
/* Make sure the GameScript doesn't get the saveload data, as it was not the
* writer of the saveload data in the first place */
_game_saveload_version = -1;
}
/* Make sure the GameScript doesn't get the saveload data, as it was not the
* writer of the saveload data in the first place */
_game_saveload_version = -1;
}
}
config->StringToSettings(_game_saveload_settings);
config->StringToSettings(_game_saveload_settings);
/* Load the GameScript saved data */
config->SetToLoadData(GameInstance::Load(_game_saveload_version));
/* Load the GameScript saved data */
config->SetToLoadData(GameInstance::Load(_game_saveload_version));
if ((CompanyID)SlIterateArray() != (CompanyID)-1) SlErrorCorrupt("Too many GameScript configs");
}
static void Save_GSDT()
{
SlSetArrayIndex(0);
SlAutolength((AutolengthProc *)SaveReal_GSDT, nullptr);
}
if (SlIterateArray() != -1) SlErrorCorrupt("Too many GameScript configs");
}
extern GameStrings *_current_data;
void Save() const override
{
SlTableHeader(_game_script_desc);
SlSetArrayIndex(0);
SlAutolength((AutolengthProc *)SaveReal_GSDT, nullptr);
}
};
static std::string _game_saveload_string;
static uint _game_saveload_strings;
static uint32 _game_saveload_strings;
class SlGameLanguageString : public DefaultSaveLoadHandler<SlGameLanguageString, LanguageStrings> {
public:
inline static const SaveLoad description[] = {
SLEG_SSTR("string", _game_saveload_string, SLE_STR | SLF_ALLOW_CONTROL),
};
inline const static SaveLoadCompatTable compat_description = _game_language_string_sl_compat;
void Save(LanguageStrings *ls) const override
{
SlSetStructListLength(ls->lines.size());
for (const auto &string : ls->lines) {
_game_saveload_string = string;
SlObject(nullptr, this->GetDescription());
}
}
static const SaveLoad _game_language_header[] = {
SLEG_SSTR(_game_saveload_string, SLE_STR),
SLEG_VAR(_game_saveload_strings, SLE_UINT32),
};
void Load(LanguageStrings *ls) const override
{
uint32 length = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? _game_saveload_strings : (uint32)SlGetStructListLength(UINT32_MAX);
static const SaveLoad _game_language_string[] = {
SLEG_SSTR(_game_saveload_string, SLE_STR | SLF_ALLOW_CONTROL),
for (uint32 i = 0; i < length; i++) {
SlObject(nullptr, this->GetLoadDescription());
ls->lines.emplace_back(_game_saveload_string);
}
}
};
static void SaveReal_GSTR(const LanguageStrings *ls)
{
_game_saveload_string = ls->language.c_str();
_game_saveload_strings = (uint)ls->lines.size();
static const SaveLoad _game_language_desc[] = {
SLE_SSTR(LanguageStrings, language, SLE_STR),
SLEG_CONDVAR("count", _game_saveload_strings, SLE_UINT32, SL_MIN_VERSION, SLV_SAVELOAD_LIST_LENGTH),
SLEG_STRUCTLIST("strings", SlGameLanguageString),
};
SlObject(nullptr, _game_language_header);
for (const auto &i : ls->lines) {
_game_saveload_string = i.c_str();
SlObject(nullptr, _game_language_string);
}
}
struct GSTRChunkHandler : ChunkHandler {
GSTRChunkHandler() : ChunkHandler('GSTR', CH_TABLE) {}
static void Load_GSTR()
{
delete _current_data;
_current_data = new GameStrings();
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_game_language_desc, _game_language_sl_compat);
while (SlIterateArray() != -1) {
_game_saveload_string.clear();
SlObject(nullptr, _game_language_header);
delete _current_data;
_current_data = new GameStrings();
LanguageStrings ls(_game_saveload_string);
for (uint i = 0; i < _game_saveload_strings; i++) {
SlObject(nullptr, _game_language_string);
ls.lines.emplace_back(_game_saveload_string);
while (SlIterateArray() != -1) {
LanguageStrings ls;
SlObject(&ls, slt);
_current_data->raw_strings.push_back(std::move(ls));
}
_current_data->raw_strings.push_back(std::move(ls));
}
/* If there were no strings in the savegame, set GameStrings to nullptr */
if (_current_data->raw_strings.size() == 0) {
delete _current_data;
_current_data = nullptr;
return;
}
/* If there were no strings in the savegame, set GameStrings to nullptr */
if (_current_data->raw_strings.size() == 0) {
delete _current_data;
_current_data = nullptr;
return;
_current_data->Compile();
ReconsiderGameScriptLanguage();
}
_current_data->Compile();
ReconsiderGameScriptLanguage();
}
void Save() const override
{
SlTableHeader(_game_language_desc);
static void Save_GSTR()
{
if (_current_data == nullptr) return;
if (_current_data == nullptr) return;
for (uint i = 0; i < _current_data->raw_strings.size(); i++) {
SlSetArrayIndex(i);
SlAutolength((AutolengthProc *)SaveReal_GSTR, &_current_data->raw_strings[i]);
for (uint i = 0; i < _current_data->raw_strings.size(); i++) {
SlSetArrayIndex(i);
SlObject(&_current_data->raw_strings[i], _game_language_desc);
}
}
}
};
static const ChunkHandler game_chunk_handlers[] = {
{ 'GSTR', Save_GSTR, Load_GSTR, nullptr, nullptr, CH_ARRAY },
{ 'GSDT', Save_GSDT, Load_GSDT, nullptr, nullptr, CH_ARRAY },
static const GSTRChunkHandler GSTR;
static const GSDTChunkHandler GSDT;
static const ChunkHandlerRef game_chunk_handlers[] = {
GSTR,
GSDT,
};
extern const ChunkHandlerTable _game_chunk_handlers(game_chunk_handlers);
}

@ -8,176 +8,421 @@
/** @file gamelog_sl.cpp Code handling saving and loading of gamelog data */
#include "../stdafx.h"
#include "saveload.h"
#include "compat/gamelog_sl_compat.h"
#include "../gamelog_internal.h"
#include "../fios.h"
#include "../string_func.h"
#include "saveload.h"
#include "../safeguards.h"
static const SaveLoad _glog_action_desc[] = {
SLE_CONDVAR_X(LoggedAction, tick, SLE_FILE_U16 | SLE_VAR_U64, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_U64_TICK_COUNTER, 0, 0)),
SLE_CONDVAR_X(LoggedAction, tick, SLE_UINT64, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_U64_TICK_COUNTER)),
};
namespace upstream_sl {
static const SaveLoad _glog_mode_desc[] = {
SLE_VAR(LoggedChange, mode.mode, SLE_UINT8),
SLE_VAR(LoggedChange, mode.landscape, SLE_UINT8),
class SlGamelogMode : public DefaultSaveLoadHandler<SlGamelogMode, LoggedChange> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(LoggedChange, mode.mode, SLE_UINT8),
SLE_VAR(LoggedChange, mode.landscape, SLE_UINT8),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_mode_sl_compat;
void Save(LoggedChange *lc) const override
{
if (lc->ct != GLCT_MODE) return;
SlObject(lc, this->GetDescription());
}
void Load(LoggedChange *lc) const override
{
if (lc->ct != GLCT_MODE) return;
SlObject(lc, this->GetLoadDescription());
}
void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
};
static char old_revision_text[GAMELOG_REVISION_LENGTH];
static std::string revision_test;
class SlGamelogRevision : public DefaultSaveLoadHandler<SlGamelogRevision, LoggedChange> {
public:
inline static const SaveLoad description[] = {
SLEG_CONDARR("revision.text", old_revision_text, SLE_UINT8, GAMELOG_REVISION_LENGTH, SL_MIN_VERSION, SLV_STRING_GAMELOG),
SLEG_CONDSSTR("revision.text", revision_test, SLE_STR, SLV_STRING_GAMELOG, SL_MAX_VERSION),
SLE_VAR(LoggedChange, revision.newgrf, SLE_UINT32),
SLE_VAR(LoggedChange, revision.slver, SLE_UINT16),
SLE_VAR(LoggedChange, revision.modified, SLE_UINT8),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_revision_sl_compat;
void Save(LoggedChange *lc) const override
{
if (lc->ct != GLCT_REVISION) return;
SlObject(lc, this->GetDescription());
}
static const SaveLoad _glog_revision_desc[] = {
SLEG_CONDARR_X(old_revision_text, SLE_UINT8, GAMELOG_REVISION_LENGTH, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_EXTENDED_GAMELOG, 0, 0)),
SLE_CONDSTR_X(LoggedChange, revision.text, SLE_STR, 0, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_EXTENDED_GAMELOG)),
SLE_VAR(LoggedChange, revision.newgrf, SLE_UINT32),
SLE_VAR(LoggedChange, revision.slver, SLE_UINT16),
SLE_VAR(LoggedChange, revision.modified, SLE_UINT8),
};
void Load(LoggedChange *lc) const override
{
if (lc->ct != GLCT_REVISION) return;
SlObject(lc, this->GetLoadDescription());
if (IsSavegameVersionBefore(SLV_STRING_GAMELOG)) {
lc->revision.text = stredup(old_revision_text, lastof(old_revision_text));
} else {
lc->revision.text = stredup(revision_test.c_str());
}
}
static const SaveLoad _glog_oldver_desc[] = {
SLE_VAR(LoggedChange, oldver.type, SLE_UINT32),
SLE_VAR(LoggedChange, oldver.version, SLE_UINT32),
void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
};
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),
};
class SlGamelogOldver : public DefaultSaveLoadHandler<SlGamelogOldver, LoggedChange> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(LoggedChange, oldver.type, SLE_UINT32),
SLE_VAR(LoggedChange, oldver.version, SLE_UINT32),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_oldver_sl_compat;
void Save(LoggedChange *lc) const override
{
if (lc->ct != GLCT_OLDVER) return;
SlObject(lc, this->GetDescription());
}
static const SaveLoad _glog_grfadd_desc[] = {
SLE_VAR(LoggedChange, grfadd.grfid, SLE_UINT32 ),
SLE_ARR(LoggedChange, grfadd.md5sum, SLE_UINT8, 16),
void Load(LoggedChange *lc) const override
{
if (lc->ct != GLCT_OLDVER) return;
SlObject(lc, this->GetLoadDescription());
}
void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
};
static const SaveLoad _glog_grfrem_desc[] = {
SLE_VAR(LoggedChange, grfrem.grfid, SLE_UINT32),
class SlGamelogSetting : public DefaultSaveLoadHandler<SlGamelogSetting, LoggedChange> {
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),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_setting_sl_compat;
void Save(LoggedChange *lc) const override
{
if (lc->ct != GLCT_SETTING) return;
SlObject(lc, this->GetDescription());
}
void Load(LoggedChange *lc) const override
{
if (lc->ct != GLCT_SETTING) return;
SlObject(lc, this->GetLoadDescription());
}
void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
};
static const SaveLoad _glog_grfcompat_desc[] = {
SLE_VAR(LoggedChange, grfcompat.grfid, SLE_UINT32 ),
SLE_ARR(LoggedChange, grfcompat.md5sum, SLE_UINT8, 16),
class SlGamelogGrfadd : public DefaultSaveLoadHandler<SlGamelogGrfadd, LoggedChange> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(LoggedChange, grfadd.grfid, SLE_UINT32 ),
SLE_ARR(LoggedChange, grfadd.md5sum, SLE_UINT8, 16),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_grfadd_sl_compat;
void Save(LoggedChange *lc) const override
{
if (lc->ct != GLCT_GRFADD) return;
SlObject(lc, this->GetDescription());
}
void Load(LoggedChange *lc) const override
{
if (lc->ct != GLCT_GRFADD) return;
SlObject(lc, this->GetLoadDescription());
}
void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
};
static const SaveLoad _glog_grfparam_desc[] = {
SLE_VAR(LoggedChange, grfparam.grfid, SLE_UINT32),
class SlGamelogGrfrem : public DefaultSaveLoadHandler<SlGamelogGrfrem, LoggedChange> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(LoggedChange, grfrem.grfid, SLE_UINT32),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_grfrem_sl_compat;
void Save(LoggedChange *lc) const override
{
if (lc->ct != GLCT_GRFREM) return;
SlObject(lc, this->GetDescription());
}
void Load(LoggedChange *lc) const override
{
if (lc->ct != GLCT_GRFREM) return;
SlObject(lc, this->GetLoadDescription());
}
void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
};
static const SaveLoad _glog_grfmove_desc[] = {
SLE_VAR(LoggedChange, grfmove.grfid, SLE_UINT32),
SLE_VAR(LoggedChange, grfmove.offset, SLE_INT32),
class SlGamelogGrfcompat : public DefaultSaveLoadHandler<SlGamelogGrfcompat, LoggedChange> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(LoggedChange, grfcompat.grfid, SLE_UINT32 ),
SLE_ARR(LoggedChange, grfcompat.md5sum, SLE_UINT8, 16),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_grfcompat_sl_compat;
void Save(LoggedChange *lc) const override
{
if (lc->ct != GLCT_GRFCOMPAT) return;
SlObject(lc, this->GetDescription());
}
void Load(LoggedChange *lc) const override
{
if (lc->ct != GLCT_GRFCOMPAT) return;
SlObject(lc, this->GetLoadDescription());
}
void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
};
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),
class SlGamelogGrfparam : public DefaultSaveLoadHandler<SlGamelogGrfparam, LoggedChange> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(LoggedChange, grfparam.grfid, SLE_UINT32),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_grfparam_sl_compat;
void Save(LoggedChange *lc) const override
{
if (lc->ct != GLCT_GRFPARAM) return;
SlObject(lc, this->GetDescription());
}
void Load(LoggedChange *lc) const override
{
if (lc->ct != GLCT_GRFPARAM) return;
SlObject(lc, this->GetLoadDescription());
}
void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
};
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.
class SlGamelogGrfmove : public DefaultSaveLoadHandler<SlGamelogGrfmove, LoggedChange> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(LoggedChange, grfmove.grfid, SLE_UINT32),
SLE_VAR(LoggedChange, grfmove.offset, SLE_INT32),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_grfmove_sl_compat;
void Save(LoggedChange *lc) const override
{
if (lc->ct != GLCT_GRFMOVE) return;
SlObject(lc, this->GetDescription());
}
void Load(LoggedChange *lc) const override
{
if (lc->ct != GLCT_GRFMOVE) return;
SlObject(lc, this->GetLoadDescription());
}
void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
};
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,
class SlGamelogGrfbug : public DefaultSaveLoadHandler<SlGamelogGrfbug, LoggedChange> {
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),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_grfbug_sl_compat;
void Save(LoggedChange *lc) const override
{
if (lc->ct != GLCT_GRFBUG) return;
SlObject(lc, this->GetDescription());
}
void Load(LoggedChange *lc) const override
{
if (lc->ct != GLCT_GRFBUG) return;
SlObject(lc, this->GetLoadDescription());
}
void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
};
static_assert(lengthof(_glog_desc) == GLCT_END);
static bool _is_emergency_save = true;
static void Load_GLOG_common(LoggedAction *&gamelog_action, uint &gamelog_actions)
{
assert(gamelog_action == nullptr);
assert(gamelog_actions == 0);
class SlGamelogEmergency : public DefaultSaveLoadHandler<SlGamelogEmergency, LoggedChange> {
public:
/* We need to store something, so store a "true" value. */
inline static const SaveLoad description[] = {
SLEG_CONDVAR("is_emergency_save", _is_emergency_save, SLE_BOOL, SLV_RIFF_TO_ARRAY, SL_MAX_VERSION),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_emergency_sl_compat;
byte type;
while ((type = SlReadByte()) != GLAT_NONE) {
if (type >= GLAT_END) SlErrorCorrupt("Invalid gamelog action type");
GamelogActionType at = (GamelogActionType)type;
void Save(LoggedChange *lc) const override
{
if (lc->ct != GLCT_EMERGENCY) return;
gamelog_action = ReallocT(gamelog_action, gamelog_actions + 1);
LoggedAction *la = &gamelog_action[gamelog_actions++];
_is_emergency_save = true;
SlObject(lc, this->GetDescription());
}
la->at = at;
void Load(LoggedChange *lc) const override
{
if (lc->ct != GLCT_EMERGENCY) return;
SlObject(la, _glog_action_desc); // has to be saved after 'DATE'!
la->change = nullptr;
la->changes = 0;
SlObject(lc, this->GetLoadDescription());
}
while ((type = SlReadByte()) != GLCT_NONE) {
if (type >= GLCT_END) SlErrorCorrupt("Invalid gamelog change type");
GamelogChangeType ct = (GamelogChangeType)type;
void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
};
la->change = ReallocT(la->change, la->changes + 1);
class SlGamelogAction : public DefaultSaveLoadHandler<SlGamelogAction, LoggedAction> {
public:
inline static const SaveLoad description[] = {
SLE_SAVEBYTE(LoggedChange, ct),
SLEG_STRUCT("mode", SlGamelogMode),
SLEG_STRUCT("revision", SlGamelogRevision),
SLEG_STRUCT("oldver", SlGamelogOldver),
SLEG_STRUCT("setting", SlGamelogSetting),
SLEG_STRUCT("grfadd", SlGamelogGrfadd),
SLEG_STRUCT("grfrem", SlGamelogGrfrem),
SLEG_STRUCT("grfcompat", SlGamelogGrfcompat),
SLEG_STRUCT("grfparam", SlGamelogGrfparam),
SLEG_STRUCT("grfmove", SlGamelogGrfmove),
SLEG_STRUCT("grfbug", SlGamelogGrfbug),
SLEG_STRUCT("emergency", SlGamelogEmergency),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_action_sl_compat;
void Save(LoggedAction *la) const override
{
SlSetStructListLength(la->changes);
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;
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;
SlObject(lc, _glog_desc[ct]);
if (ct == GLCT_REVISION && SlXvIsFeatureMissing(XSLFI_EXTENDED_GAMELOG)) {
lc->revision.text = stredup(old_revision_text, lastof(old_revision_text));
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->GetLoadDescription());
}
return;
}
size_t length = SlGetStructListLength(UINT32_MAX);
la->change = ReallocT(la->change, length);
la->changes = (uint32)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->GetLoadDescription());
}
}
}
static void Save_GLOG()
{
const LoggedAction *laend = &_gamelog_action[_gamelog_actions];
size_t length = 0;
void LoadCheck(LoggedAction *la) const override { this->Load(la); }
};
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;
static const SaveLoad _gamelog_desc[] = {
SLE_CONDVAR(LoggedAction, at, SLE_UINT8, SLV_RIFF_TO_ARRAY, SL_MAX_VERSION),
SLE_CONDVAR(LoggedAction, tick, SLE_FILE_U16 | SLE_VAR_U64, SL_MIN_VERSION, SLV_U64_TICK_COUNTER),
SLE_CONDVAR(LoggedAction, tick, SLE_UINT64, SLV_U64_TICK_COUNTER, SL_MAX_VERSION),
SLEG_STRUCTLIST("action", SlGamelogAction),
};
struct GLOGChunkHandler : ChunkHandler {
GLOGChunkHandler() : ChunkHandler('GLOG', CH_TABLE) {}
void LoadCommon(LoggedAction *&gamelog_action, uint &gamelog_actions) const
{
assert(gamelog_action == nullptr);
assert(gamelog_actions == 0);
const std::vector<SaveLoad> slt = SlCompatTableHeader(_gamelog_desc, _gamelog_sl_compat);
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, slt);
}
return;
}
while (SlIterateArray() != -1) {
gamelog_action = ReallocT(gamelog_action, gamelog_actions + 1);
LoggedAction *la = &gamelog_action[gamelog_actions++];
memset(la, 0, sizeof(*la));
SlObject(la, slt);
}
length += 10;
}
length++;
SlSetLength(length);
void Save() const override
{
SlTableHeader(_gamelog_desc);
for (LoggedAction *la = _gamelog_action; la != laend; la++) {
SlWriteByte(la->at);
SlObject(la, _glog_action_desc);
const LoggedAction *laend = &_gamelog_action[_gamelog_actions];
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]);
uint i = 0;
for (LoggedAction *la = _gamelog_action; la != laend; la++, i++) {
SlSetArrayIndex(i);
SlObject(la, _gamelog_desc);
}
SlWriteByte(GLCT_NONE);
}
SlWriteByte(GLAT_NONE);
}
static void Load_GLOG()
{
Load_GLOG_common(_gamelog_action, _gamelog_actions);
}
void Load() const override
{
this->LoadCommon(_gamelog_action, _gamelog_actions);
}
static void Check_GLOG()
{
Load_GLOG_common(_load_check_data.gamelog_action, _load_check_data.gamelog_actions);
}
void LoadCheck(size_t) const override
{
this->LoadCommon(_load_check_data.gamelog_action, _load_check_data.gamelog_actions);
}
};
static const ChunkHandler gamelog_chunk_handlers[] = {
{ 'GLOG', Save_GLOG, Load_GLOG, nullptr, Check_GLOG, CH_RIFF }
static const GLOGChunkHandler GLOG;
static const ChunkHandlerRef gamelog_chunk_handlers[] = {
GLOG,
};
extern const ChunkHandlerTable _gamelog_chunk_handlers(gamelog_chunk_handlers);
}

@ -8,12 +8,16 @@
/** @file goal_sl.cpp Code handling saving and loading of goals */
#include "../stdafx.h"
#include "../goal_base.h"
#include "saveload.h"
#include "compat/goal_sl_compat.h"
#include "../goal_base.h"
#include "../safeguards.h"
namespace upstream_sl {
static const SaveLoad _goals_desc[] = {
SLE_VAR(Goal, company, SLE_FILE_U16 | SLE_VAR_U8),
SLE_VAR(Goal, type, SLE_FILE_U16 | SLE_VAR_U8),
@ -23,25 +27,36 @@ static const SaveLoad _goals_desc[] = {
SLE_CONDVAR(Goal, completed, SLE_BOOL, SLV_182, SL_MAX_VERSION),
};
static void Save_GOAL()
{
for (Goal *s : Goal::Iterate()) {
SlSetArrayIndex(s->index);
SlObject(s, _goals_desc);
struct GOALChunkHandler : ChunkHandler {
GOALChunkHandler() : ChunkHandler('GOAL', CH_TABLE) {}
void Save() const override
{
SlTableHeader(_goals_desc);
for (Goal *s : Goal::Iterate()) {
SlSetArrayIndex(s->index);
SlObject(s, _goals_desc);
}
}
}
static void Load_GOAL()
{
int index;
while ((index = SlIterateArray()) != -1) {
Goal *s = new (index) Goal();
SlObject(s, _goals_desc);
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_goals_desc, _goals_sl_compat);
int index;
while ((index = SlIterateArray()) != -1) {
Goal *s = new (index) Goal();
SlObject(s, slt);
}
}
}
};
static const ChunkHandler goal_chunk_handlers[] = {
{ 'GOAL', Save_GOAL, Load_GOAL, nullptr, nullptr, CH_ARRAY },
static const GOALChunkHandler GOAL;
static const ChunkHandlerRef goal_chunk_handlers[] = {
GOAL,
};
extern const ChunkHandlerTable _goal_chunk_handlers(goal_chunk_handlers);
}

@ -12,13 +12,15 @@
#include "../company_base.h"
#include "saveload.h"
#include "compat/group_sl_compat.h"
#include "../safeguards.h"
namespace upstream_sl {
static const SaveLoad _group_desc[] = {
SLE_CONDVAR(Group, name, SLE_NAME, SL_MIN_VERSION, SLV_84),
SLE_CONDSSTR(Group, name, SLE_STR | SLF_ALLOW_CONTROL, SLV_84, SL_MAX_VERSION),
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_164), // num_vehicle
SLE_VAR(Group, owner, SLE_UINT8),
SLE_VAR(Group, vehicle_type, SLE_UINT8),
SLE_VAR(Group, flags, SLE_UINT8),
@ -28,35 +30,46 @@ static const SaveLoad _group_desc[] = {
SLE_CONDVAR(Group, parent, SLE_UINT16, SLV_189, SL_MAX_VERSION),
};
static void Save_GRPS()
{
for (Group *g : Group::Iterate()) {
SlSetArrayIndex(g->index);
SlObject(g, _group_desc);
struct GRPSChunkHandler : ChunkHandler {
GRPSChunkHandler() : ChunkHandler('GRPS', CH_TABLE) {}
void Save() const override
{
SlTableHeader(_group_desc);
for (Group *g : Group::Iterate()) {
SlSetArrayIndex(g->index);
SlObject(g, _group_desc);
}
}
}
static void Load_GRPS()
{
int index;
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_group_desc, _group_sl_compat);
while ((index = SlIterateArray()) != -1) {
Group *g = new (index) Group();
SlObject(g, _group_desc);
int index;
if (IsSavegameVersionBefore(SLV_189)) g->parent = INVALID_GROUP;
while ((index = SlIterateArray()) != -1) {
Group *g = new (index) Group();
SlObject(g, slt);
if (IsSavegameVersionBefore(SLV_GROUP_LIVERIES)) {
const Company *c = Company::Get(g->owner);
g->livery.colour1 = c->livery[LS_DEFAULT].colour1;
g->livery.colour2 = c->livery[LS_DEFAULT].colour2;
if (IsSavegameVersionBefore(SLV_189)) g->parent = INVALID_GROUP;
if (IsSavegameVersionBefore(SLV_GROUP_LIVERIES)) {
const Company *c = Company::Get(g->owner);
g->livery.colour1 = c->livery[LS_DEFAULT].colour1;
g->livery.colour2 = c->livery[LS_DEFAULT].colour2;
}
}
}
}
};
static const ChunkHandler group_chunk_handlers[] = {
{ 'GRPS', Save_GRPS, Load_GRPS, nullptr, nullptr, CH_ARRAY },
static const GRPSChunkHandler GRPS;
static const ChunkHandlerRef group_chunk_handlers[] = {
GRPS,
};
extern const ChunkHandlerTable _group_chunk_handlers(group_chunk_handlers);
}

@ -8,13 +8,134 @@
/** @file industry_sl.cpp Code handling saving and loading of industries */
#include "../stdafx.h"
#include "../industry.h"
#include "saveload.h"
#include "compat/industry_sl_compat.h"
#include "../industry.h"
#include "newgrf_sl.h"
#include "../safeguards.h"
namespace upstream_sl {
static const int THIS_MONTH = 0;
static const int LAST_MONTH = 1;
struct ProducedHistory {
uint16_t production; ///< Total produced
uint16_t transported; ///< Total transported
uint8_t PctTransported() const
{
if (this->production == 0) return 0;
return ClampTo<uint8_t>(this->transported * 256 / this->production);
}
};
struct ProducedCargo {
CargoID cargo; ///< Cargo type
uint16_t waiting; ///< Amount of cargo produced
uint8_t rate; ///< Production rate
std::array<ProducedHistory, 2> history; ///< History of cargo produced and transported
};
struct AcceptedCargo {
CargoID cargo; ///< Cargo type
uint16_t waiting; ///< Amount of cargo waiting to processed
Date last_accepted; ///< Last day cargo was accepted by this industry
};
class SlIndustryAccepted : public DefaultSaveLoadHandler<SlIndustryAccepted, Industry> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(AcceptedCargo, cargo, SLE_UINT8),
SLE_VAR(AcceptedCargo, waiting, SLE_UINT16),
SLE_VAR(AcceptedCargo, last_accepted, SLE_INT32),
};
inline const static SaveLoadCompatTable compat_description = {};
void Save(Industry *i) const override
{
NOT_REACHED();
}
void Load(Industry *i) const override
{
size_t len = SlGetStructListLength(INDUSTRY_NUM_INPUTS);
for (size_t j = 0; j < len; j++) {
AcceptedCargo a = {};
SlObject(&a, this->GetDescription());
if (j < INDUSTRY_NUM_INPUTS) {
i->accepts_cargo[j] = a.cargo;
i->incoming_cargo_waiting[j] = a.waiting;
i->last_cargo_accepted_at[j] = a.last_accepted;
}
}
}
};
class SlIndustryProducedHistory : public DefaultSaveLoadHandler<SlIndustryProducedHistory, ProducedCargo> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(ProducedHistory, production, SLE_UINT16),
SLE_VAR(ProducedHistory, transported, SLE_UINT16),
};
inline const static SaveLoadCompatTable compat_description = {};
void Save(ProducedCargo *p) const override
{
NOT_REACHED();
}
void Load(ProducedCargo *p) const override
{
size_t len = SlGetStructListLength(p->history.size());
for (auto &h : p->history) {
if (--len > p->history.size()) break; // unsigned so wraps after hitting zero.
SlObject(&h, this->GetDescription());
}
}
};
class SlIndustryProduced : public DefaultSaveLoadHandler<SlIndustryProduced, Industry> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(ProducedCargo, cargo, SLE_UINT8),
SLE_VAR(ProducedCargo, waiting, SLE_UINT16),
SLE_VAR(ProducedCargo, rate, SLE_UINT8),
SLEG_STRUCTLIST("history", SlIndustryProducedHistory),
};
inline const static SaveLoadCompatTable compat_description = {};
void Save(Industry *i) const override
{
NOT_REACHED();
}
void Load(Industry *i) const override
{
size_t len = SlGetStructListLength(INDUSTRY_NUM_OUTPUTS);
for (size_t j = 0; j < len; j++) {
ProducedCargo p = {};
SlObject(&p, this->GetDescription());
if (j < INDUSTRY_NUM_OUTPUTS) {
i->produced_cargo[j] = p.cargo;
i->produced_cargo_waiting[j] = p.waiting;
i->production_rate[j] = p.rate;
i->this_month_production[j] = p.history[THIS_MONTH].production;
i->this_month_transported[j] = p.history[THIS_MONTH].transported;
i->last_month_production[j] = p.history[LAST_MONTH].production;
i->last_month_transported[j] = p.history[LAST_MONTH].transported;
i->last_month_pct_transported[j] = p.history[LAST_MONTH].PctTransported();
}
}
}
};
static OldPersistentStorage _old_ind_persistent_storage;
static const SaveLoad _industry_desc[] = {
@ -24,29 +145,27 @@ static const SaveLoad _industry_desc[] = {
SLE_VAR(Industry, location.h, SLE_FILE_U8 | SLE_VAR_U16),
SLE_REF(Industry, town, REF_TOWN),
SLE_CONDREF(Industry, neutral_station, REF_STATION, SLV_SERVE_NEUTRAL_INDUSTRIES, SL_MAX_VERSION),
SLE_CONDNULL( 2, SL_MIN_VERSION, SLV_61), ///< used to be industry's produced_cargo
SLE_CONDARR(Industry, produced_cargo, SLE_UINT8, 2, SLV_78, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, produced_cargo, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDARR(Industry, produced_cargo, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLE_CONDARR(Industry, incoming_cargo_waiting, SLE_UINT16, 3, SLV_70, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, incoming_cargo_waiting, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDARR(Industry, incoming_cargo_waiting, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLE_CONDARR(Industry, produced_cargo_waiting, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, produced_cargo_waiting, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDARR(Industry, produced_cargo_waiting, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLE_CONDARR(Industry, production_rate, SLE_UINT8, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, production_rate, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDNULL( 3, SL_MIN_VERSION, SLV_61), ///< used to be industry's accepts_cargo
SLE_CONDARR(Industry, production_rate, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLE_CONDARR(Industry, accepts_cargo, SLE_UINT8, 3, SLV_78, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, accepts_cargo, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDARR(Industry, accepts_cargo, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLE_VAR(Industry, prod_level, SLE_UINT8),
SLE_CONDARR(Industry, this_month_production, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, this_month_production, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDARR(Industry, this_month_production, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLE_CONDARR(Industry, this_month_transported, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, this_month_transported, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDARR(Industry, this_month_transported, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLE_CONDARR(Industry, last_month_pct_transported, SLE_UINT8, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, last_month_pct_transported, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDARR(Industry, last_month_pct_transported, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLE_CONDARR(Industry, last_month_production, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, last_month_production, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDARR(Industry, last_month_production, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLE_CONDARR(Industry, last_month_transported, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, last_month_transported, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDARR(Industry, last_month_transported, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLE_VAR(Industry, counter, SLE_UINT16),
@ -62,88 +181,100 @@ static const SaveLoad _industry_desc[] = {
SLE_CONDVAR(Industry, construction_date, SLE_INT32, SLV_70, SL_MAX_VERSION),
SLE_CONDVAR(Industry, construction_type, SLE_UINT8, SLV_70, SL_MAX_VERSION),
SLE_CONDVAR(Industry, last_cargo_accepted_at[0], SLE_INT32, SLV_70, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, last_cargo_accepted_at, SLE_INT32, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDARR(Industry, last_cargo_accepted_at, SLE_INT32, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLE_CONDVAR(Industry, selected_layout, SLE_UINT8, SLV_73, SL_MAX_VERSION),
SLE_CONDVAR(Industry, exclusive_supplier, SLE_UINT8, SLV_GS_INDUSTRY_CONTROL, SL_MAX_VERSION),
SLE_CONDVAR(Industry, exclusive_consumer, SLE_UINT8, SLV_GS_INDUSTRY_CONTROL, SL_MAX_VERSION),
SLEG_CONDARR(_old_ind_persistent_storage.storage, SLE_UINT32, 16, SLV_76, SLV_161),
SLEG_CONDARR("storage", _old_ind_persistent_storage.storage, SLE_UINT32, 16, SLV_76, SLV_161),
SLE_CONDREF(Industry, psa, REF_STORAGE, SLV_161, SL_MAX_VERSION),
SLE_CONDNULL(1, SLV_82, SLV_197), // random_triggers
SLE_CONDVAR(Industry, random, SLE_UINT16, SLV_82, SL_MAX_VERSION),
SLE_CONDSSTR(Industry, text, SLE_STR | SLF_ALLOW_CONTROL, SLV_INDUSTRY_TEXT, SL_MAX_VERSION),
SLE_CONDNULL(32, SLV_2, SLV_144), // old reserved space
SLEG_CONDSTRUCTLIST("accepted", SlIndustryAccepted, SLV_INDUSTRY_CARGO_REORGANISE, SL_MAX_VERSION),
SLEG_CONDSTRUCTLIST("produced", SlIndustryProduced, SLV_INDUSTRY_CARGO_REORGANISE, SL_MAX_VERSION),
};
static void Save_INDY()
{
/* Write the industries */
for (Industry *ind : Industry::Iterate()) {
SlSetArrayIndex(ind->index);
SlObject(ind, _industry_desc);
}
}
struct INDYChunkHandler : ChunkHandler {
INDYChunkHandler() : ChunkHandler('INDY', CH_TABLE) {}
static void Save_IIDS()
{
Save_NewGRFMapping(_industry_mngr);
}
void Save() const override
{
SlTableHeader(_industry_desc);
static void Save_TIDS()
{
Save_NewGRFMapping(_industile_mngr);
}
/* Write the industries */
for (Industry *ind : Industry::Iterate()) {
SlSetArrayIndex(ind->index);
SlObject(ind, _industry_desc);
}
}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_industry_desc, _industry_sl_compat);
static void Load_INDY()
{
int index;
int index;
Industry::ResetIndustryCounts();
Industry::ResetIndustryCounts();
while ((index = SlIterateArray()) != -1) {
Industry *i = new (index) Industry();
SlObject(i, _industry_desc);
while ((index = SlIterateArray()) != -1) {
Industry *i = new (index) Industry();
SlObject(i, slt);
/* Before savegame version 161, persistent storages were not stored in a pool. */
if (IsSavegameVersionBefore(SLV_161) && !IsSavegameVersionBefore(SLV_76)) {
/* Store the old persistent storage. The GRFID will be added later. */
assert(PersistentStorage::CanAllocateItem());
i->psa = new PersistentStorage(0, 0, 0);
memcpy(i->psa->storage, _old_ind_persistent_storage.storage, sizeof(_old_ind_persistent_storage.storage));
/* Before savegame version 161, persistent storages were not stored in a pool. */
if (IsSavegameVersionBefore(SLV_161) && !IsSavegameVersionBefore(SLV_76)) {
/* Store the old persistent storage. The GRFID will be added later. */
assert(PersistentStorage::CanAllocateItem());
i->psa = new PersistentStorage(0, 0, 0);
memcpy(i->psa->storage, _old_ind_persistent_storage.storage, sizeof(_old_ind_persistent_storage.storage));
}
Industry::IncIndustryTypeCount(i->type);
}
Industry::IncIndustryTypeCount(i->type);
}
}
static void Load_IIDS()
{
Load_NewGRFMapping(_industry_mngr);
}
void FixPointers() const override
{
for (Industry *i : Industry::Iterate()) {
SlObject(i, _industry_desc);
}
}
};
static void Load_TIDS()
{
Load_NewGRFMapping(_industile_mngr);
}
struct IIDSChunkHandler : NewGRFMappingChunkHandler {
IIDSChunkHandler() : NewGRFMappingChunkHandler('IIDS', _industry_mngr) {}
};
static void Ptrs_INDY()
{
for (Industry *i : Industry::Iterate()) {
SlObject(i, _industry_desc);
}
}
struct TIDSChunkHandler : NewGRFMappingChunkHandler {
TIDSChunkHandler() : NewGRFMappingChunkHandler('TIDS', _industile_mngr) {}
};
/** Description of the data to save and load in #IndustryBuildData. */
static const SaveLoad _industry_builder_desc[] = {
SLEG_VAR(_industry_builder.wanted_inds, SLE_UINT32),
SLEG_VAR("wanted_inds", _industry_builder.wanted_inds, SLE_UINT32),
};
/** Load/save industry builder. */
static void LoadSave_IBLD()
{
SlGlobList(_industry_builder_desc);
}
/** Industry builder. */
struct IBLDChunkHandler : ChunkHandler {
IBLDChunkHandler() : ChunkHandler('IBLD', CH_TABLE) {}
void Save() const override
{
SlTableHeader(_industry_builder_desc);
SlSetArrayIndex(0);
SlGlobList(_industry_builder_desc);
}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_industry_builder_desc, _industry_builder_sl_compat);
if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() == -1) return;
SlGlobList(slt);
if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many IBLD entries");
}
};
/** Description of the data to save and load in #IndustryTypeBuildData. */
static const SaveLoad _industrytype_builder_desc[] = {
@ -154,34 +285,48 @@ static const SaveLoad _industrytype_builder_desc[] = {
SLE_VAR(IndustryTypeBuildData, wait_count, SLE_UINT16),
};
/** Save industry-type build data. */
static void Save_ITBL()
{
for (int i = 0; i < NUM_INDUSTRYTYPES; i++) {
SlSetArrayIndex(i);
SlObject(_industry_builder.builddata + i, _industrytype_builder_desc);
}
}
/** Industry-type build data. */
struct ITBLChunkHandler : ChunkHandler {
ITBLChunkHandler() : ChunkHandler('ITBL', CH_TABLE) {}
void Save() const override
{
SlTableHeader(_industrytype_builder_desc);
/** Load industry-type build data. */
static void Load_ITBL()
{
for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
_industry_builder.builddata[it].Reset();
for (int i = 0; i < NUM_INDUSTRYTYPES; i++) {
SlSetArrayIndex(i);
SlObject(_industry_builder.builddata + i, _industrytype_builder_desc);
}
}
int index;
while ((index = SlIterateArray()) != -1) {
if ((uint)index >= NUM_INDUSTRYTYPES) SlErrorCorrupt("Too many industry builder datas");
SlObject(_industry_builder.builddata + index, _industrytype_builder_desc);
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_industrytype_builder_desc, _industrytype_builder_sl_compat);
for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
_industry_builder.builddata[it].Reset();
}
int index;
while ((index = SlIterateArray()) != -1) {
if ((uint)index >= NUM_INDUSTRYTYPES) SlErrorCorrupt("Too many industry builder datas");
SlObject(_industry_builder.builddata + index, slt);
}
}
}
};
static const ChunkHandler industry_chunk_handlers[] = {
{ 'INDY', Save_INDY, Load_INDY, Ptrs_INDY, nullptr, CH_ARRAY },
{ 'IIDS', Save_IIDS, Load_IIDS, nullptr, nullptr, CH_ARRAY },
{ 'TIDS', Save_TIDS, Load_TIDS, nullptr, nullptr, CH_ARRAY },
{ 'IBLD', LoadSave_IBLD, LoadSave_IBLD, nullptr, nullptr, CH_RIFF },
{ 'ITBL', Save_ITBL, Load_ITBL, nullptr, nullptr, CH_ARRAY },
static const INDYChunkHandler INDY;
static const IIDSChunkHandler IIDS;
static const TIDSChunkHandler TIDS;
static const IBLDChunkHandler IBLD;
static const ITBLChunkHandler ITBL;
static const ChunkHandlerRef industry_chunk_handlers[] = {
INDY,
IIDS,
TIDS,
IBLD,
ITBL,
};
extern const ChunkHandlerTable _industry_chunk_handlers(industry_chunk_handlers);
}

@ -8,94 +8,20 @@
/** @file labelmaps_sl.cpp Code handling saving and loading of rail type label mappings */
#include "../stdafx.h"
#include "../station_map.h"
#include "../tunnelbridge_map.h"
#include "saveload.h"
#include "saveload_internal.h"
#include "../safeguards.h"
#include "compat/labelmaps_sl_compat.h"
std::vector<RailTypeLabel> _railtype_list;
/**
* Test if any saved rail type labels are different to the currently loaded
* rail types, which therefore requires conversion.
* @return true if (and only if) conversion due to rail type changes is needed.
*/
static bool NeedRailTypeConversion()
{
for (uint i = 0; i < _railtype_list.size(); i++) {
if ((RailType)i < RAILTYPE_END) {
const RailtypeInfo *rti = GetRailTypeInfo((RailType)i);
if (rti->label != _railtype_list[i]) return true;
} else {
if (_railtype_list[i] != 0) return true;
}
}
/* No rail type conversion is necessary */
return false;
}
void AfterLoadLabelMaps()
{
if (NeedRailTypeConversion()) {
RailType railtype_conversion_map[RAILTYPE_END];
for (uint i = 0; i < _railtype_list.size(); i++) {
RailType r = GetRailTypeByLabel(_railtype_list[i]);
if (r == INVALID_RAILTYPE) r = RAILTYPE_BEGIN;
#include "../station_map.h"
#include "../tunnelbridge_map.h"
railtype_conversion_map[i] = r;
}
for (uint i = (uint)_railtype_list.size(); i < RAILTYPE_END; i++) {
railtype_conversion_map[i] = RAILTYPE_RAIL;
}
#include "../safeguards.h"
auto convert = [&](TileIndex t) {
SetRailType(t, railtype_conversion_map[GetRailType(t)]);
RailType secondary = GetTileSecondaryRailTypeIfValid(t);
if (secondary != INVALID_RAILTYPE) SetSecondaryRailType(t, railtype_conversion_map[secondary]);
};
for (TileIndex t = 0; t < MapSize(); t++) {
switch (GetTileType(t)) {
case MP_RAILWAY:
convert(t);
break;
case MP_ROAD:
if (IsLevelCrossing(t)) {
convert(t);
}
break;
case MP_STATION:
if (HasStationRail(t)) {
convert(t);
}
break;
case MP_TUNNELBRIDGE:
if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) {
convert(t);
}
break;
default:
break;
}
}
}
void ResetLabelMaps();
ResetLabelMaps();
}
extern std::vector<RailTypeLabel> _railtype_list;
void ResetLabelMaps()
{
_railtype_list.clear();
}
namespace upstream_sl {
/** Container for a label for SaveLoad system */
struct LabelObject {
@ -106,33 +32,43 @@ static const SaveLoad _label_object_desc[] = {
SLE_VAR(LabelObject, label, SLE_UINT32),
};
static void Save_RAIL()
{
LabelObject lo;
struct RAILChunkHandler : ChunkHandler {
RAILChunkHandler() : ChunkHandler('RAIL', CH_TABLE) {}
void Save() const override
{
SlTableHeader(_label_object_desc);
LabelObject lo;
for (RailType r = RAILTYPE_BEGIN; r != RAILTYPE_END; r++) {
lo.label = GetRailTypeInfo(r)->label;
for (RailType r = RAILTYPE_BEGIN; r != RAILTYPE_END; r++) {
lo.label = GetRailTypeInfo(r)->label;
SlSetArrayIndex(r);
SlObject(&lo, _label_object_desc);
SlSetArrayIndex(r);
SlObject(&lo, _label_object_desc);
}
}
}
static void Load_RAIL()
{
ResetLabelMaps();
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_label_object_desc, _label_object_sl_compat);
LabelObject lo;
ResetLabelMaps();
while (SlIterateArray() != -1) {
SlObject(&lo, _label_object_desc);
_railtype_list.push_back((RailTypeLabel)lo.label);
LabelObject lo;
while (SlIterateArray() != -1) {
SlObject(&lo, slt);
_railtype_list.push_back((RailTypeLabel)lo.label);
}
}
}
};
static const ChunkHandler labelmaps_chunk_handlers[] = {
{ 'RAIL', Save_RAIL, Load_RAIL, nullptr, nullptr, CH_ARRAY },
static const RAILChunkHandler RAIL;
static const ChunkHandlerRef labelmaps_chunk_handlers[] = {
RAIL,
};
extern const ChunkHandlerTable _labelmaps_chunk_handlers(labelmaps_chunk_handlers);
}

@ -6,23 +6,91 @@
*/
/** @file league_sl.cpp Code handling saving and loading of league tables */
#include "../stdafx.h"
#include "saveload.h"
extern SaveLoadVersion _sl_xv_upstream_version;
#include "../league_base.h"
#include "../safeguards.h"
namespace upstream_sl {
static const SaveLoad _league_table_elements_desc[] = {
SLE_VAR(LeagueTableElement, table, SLE_UINT8),
SLE_CONDVAR(LeagueTableElement, rating, SLE_FILE_U64 | SLE_VAR_I64, SL_MIN_VERSION, SLV_LINKGRAPH_EDGES),
SLE_CONDVAR(LeagueTableElement, rating, SLE_INT64, SLV_LINKGRAPH_EDGES, SL_MAX_VERSION),
SLE_VAR(LeagueTableElement, company, SLE_UINT8),
SLE_SSTR(LeagueTableElement, text, SLE_STR | SLF_ALLOW_CONTROL),
SLE_SSTR(LeagueTableElement, score, SLE_STR | SLF_ALLOW_CONTROL),
SLE_VAR(LeagueTableElement, link.type, SLE_UINT8),
SLE_VAR(LeagueTableElement, link.target, SLE_UINT32),
};
struct LEAEChunkHandler : ChunkHandler {
LEAEChunkHandler() : ChunkHandler('LEAE', CH_TABLE) {}
void Save() const override
{
SlTableHeader(_league_table_elements_desc);
for (LeagueTableElement *lte : LeagueTableElement::Iterate()) {
SlSetArrayIndex(lte->index);
SlObject(lte, _league_table_elements_desc);
}
}
void Load() const override
{
const std::vector<SaveLoad> slt = SlTableHeader(_league_table_elements_desc);
int index;
while ((index = SlIterateArray()) != -1) {
LeagueTableElement *lte = new (index) LeagueTableElement();
SlObject(lte, slt);
}
}
};
static const SaveLoad _league_tables_desc[] = {
SLE_SSTR(LeagueTable, title, SLE_STR | SLF_ALLOW_CONTROL),
SLE_SSTR(LeagueTable, header, SLE_STR | SLF_ALLOW_CONTROL),
SLE_SSTR(LeagueTable, footer, SLE_STR | SLF_ALLOW_CONTROL),
};
struct LEATChunkHandler : ChunkHandler {
LEATChunkHandler() : ChunkHandler('LEAT', CH_TABLE) {}
struct GetLeagueChunkLoadInfo
{
static SaveLoadVersion GetLoadVersion()
void Save() const override
{
return _sl_xv_upstream_version != SL_MIN_VERSION ? _sl_xv_upstream_version : SLV_MULTITRACK_LEVEL_CROSSINGS;
SlTableHeader(_league_tables_desc);
for (LeagueTable *lt : LeagueTable::Iterate()) {
SlSetArrayIndex(lt->index);
SlObject(lt, _league_tables_desc);
}
}
void Load() const override
{
const std::vector<SaveLoad> slt = SlTableHeader(_league_tables_desc);
int index;
while ((index = SlIterateArray()) != -1) {
LeagueTable *lt = new (index) LeagueTable();
SlObject(lt, slt);
}
}
};
static const ChunkHandler league_chunk_handlers[] = {
MakeUpstreamChunkHandler<'LEAE', GetLeagueChunkLoadInfo>(),
MakeUpstreamChunkHandler<'LEAT', GetLeagueChunkLoadInfo>(),
static const LEAEChunkHandler LEAE;
static const LEATChunkHandler LEAT;
static const ChunkHandlerRef league_chunk_handlers[] = {
LEAE,
LEAT,
};
extern const ChunkHandlerTable _league_chunk_handlers(league_chunk_handlers);
}

@ -8,21 +8,115 @@
/** @file linkgraph_sl.cpp Code handling saving and loading of link graphs */
#include "../stdafx.h"
#include "saveload.h"
#include "compat/linkgraph_sl_compat.h"
#include "../linkgraph/linkgraph.h"
#include "../linkgraph/linkgraphjob.h"
#include "../linkgraph/linkgraphschedule.h"
#include "../network/network.h"
#include "../settings_internal.h"
#include "saveload.h"
#include "../safeguards.h"
namespace upstream_sl {
typedef LinkGraph::BaseNode Node;
typedef LinkGraph::BaseEdge Edge;
const SettingDesc *GetSettingDescription(uint index);
static uint16 _num_nodes;
static LinkGraph *_linkgraph; ///< Contains the current linkgraph being saved/loaded.
static NodeID _linkgraph_from; ///< Contains the current "from" node being saved/loaded.
static NodeID _edge_dest_node;
static NodeID _edge_next_edge;
class SlLinkgraphEdge : public DefaultSaveLoadHandler<SlLinkgraphEdge, Node> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(Edge, capacity, SLE_UINT32),
SLE_VAR(Edge, usage, SLE_UINT32),
SLE_CONDVAR(Edge, travel_time_sum, SLE_UINT64, SLV_LINKGRAPH_TRAVEL_TIME, SL_MAX_VERSION),
SLE_VAR(Edge, last_unrestricted_update, SLE_INT32),
SLE_CONDVAR(Edge, last_restricted_update, SLE_INT32, SLV_187, SL_MAX_VERSION),
SLEG_VAR("dest_node", _edge_dest_node, SLE_UINT16),
SLEG_CONDVAR("next_edge", _edge_next_edge, SLE_UINT16, SL_MIN_VERSION, SLV_LINKGRAPH_EDGES),
};
inline const static SaveLoadCompatTable compat_description = _linkgraph_edge_sl_compat;
void Save(Node *bn) const override
{
NOT_REACHED();
}
void Load(Node *bn) const override
{
uint16 max_size = _linkgraph->Size();
if (IsSavegameVersionBefore(SLV_191)) {
NOT_REACHED();
}
if (IsSavegameVersionBefore(SLV_LINKGRAPH_EDGES)) {
size_t used_size = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? max_size : SlGetStructListLength(UINT16_MAX);
/* ... but as that wasted a lot of space we save a sparse matrix now. */
for (NodeID to = _linkgraph_from; to != INVALID_NODE; to = _edge_next_edge) {
if (used_size == 0) SlErrorCorrupt("Link graph structure overflow");
used_size--;
if (to >= max_size) SlErrorCorrupt("Link graph structure overflow");
SlObject(&_linkgraph->edges[std::make_pair(_linkgraph_from, to)], this->GetLoadDescription());
}
if (!IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) && used_size > 0) SlErrorCorrupt("Corrupted link graph");
} else {
/* Edge data is now a simple vector and not any kind of matrix. */
size_t size = SlGetStructListLength(UINT16_MAX);
for (size_t i = 0; i < size; i++) {
Edge edge;
SlObject(&edge, this->GetLoadDescription());
if (_edge_dest_node >= max_size) SlErrorCorrupt("Link graph structure overflow");
_linkgraph->edges[std::make_pair(_linkgraph_from, _edge_dest_node)] = edge;
}
}
}
};
class SlLinkgraphNode : public DefaultSaveLoadHandler<SlLinkgraphNode, LinkGraph> {
public:
inline static const SaveLoad description[] = {
SLE_CONDVAR(Node, xy, SLE_UINT32, SLV_191, SL_MAX_VERSION),
SLE_VAR(Node, supply, SLE_UINT32),
SLE_VAR(Node, demand, SLE_UINT32),
SLE_VAR(Node, station, SLE_UINT16),
SLE_VAR(Node, last_update, SLE_INT32),
SLEG_STRUCTLIST("edges", SlLinkgraphEdge),
};
inline const static SaveLoadCompatTable compat_description = _linkgraph_node_sl_compat;
void Save(LinkGraph *lg) const override
{
_linkgraph = lg;
SlSetStructListLength(lg->Size());
for (NodeID from = 0; from < lg->Size(); ++from) {
_linkgraph_from = from;
SlObject(&lg->nodes[from], this->GetDescription());
}
}
void Load(LinkGraph *lg) const override
{
_linkgraph = lg;
uint16 length = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? _num_nodes : (uint16)SlGetStructListLength(UINT16_MAX);
lg->Init(length);
for (NodeID from = 0; from < length; ++from) {
_linkgraph_from = from;
SlObject(&lg->nodes[from], this->GetLoadDescription());
}
}
};
/**
* Get a SaveLoad array for a link graph.
@ -32,18 +126,36 @@ SaveLoadTable GetLinkGraphDesc()
{
static const SaveLoad link_graph_desc[] = {
SLE_VAR(LinkGraph, last_compression, SLE_INT32),
SLEG_VAR(_num_nodes, SLE_UINT16),
SLEG_CONDVAR("num_nodes", _num_nodes, SLE_UINT16, SL_MIN_VERSION, SLV_SAVELOAD_LIST_LENGTH),
SLE_VAR(LinkGraph, cargo, SLE_UINT8),
SLEG_STRUCTLIST("nodes", SlLinkgraphNode),
};
return link_graph_desc;
}
void GetLinkGraphJobDayLengthScaleAfterLoad(LinkGraphJob *lgj)
{
lgj->join_date_ticks *= DAY_TICKS;
lgj->join_date_ticks += LinkGraphSchedule::SPAWN_JOIN_TICK;
lgj->start_date_ticks = lgj->join_date_ticks - (lgj->Settings().recalc_time * DAY_TICKS);
}
/**
* Proxy to reuse LinkGraph to save/load a LinkGraphJob.
* One of the members of a LinkGraphJob is a LinkGraph, but SLEG_STRUCT()
* doesn't allow us to select a member. So instead, we add a bit of glue to
* accept a LinkGraphJob, get the LinkGraph, and use that to call the
* save/load routines for a regular LinkGraph.
*/
class SlLinkgraphJobProxy : public DefaultSaveLoadHandler<SlLinkgraphJobProxy, LinkGraphJob> {
public:
inline static const SaveLoad description[] = {{}}; // Needed to keep DefaultSaveLoadHandler happy.
SaveLoadTable GetDescription() const override { return GetLinkGraphDesc(); }
inline const static SaveLoadCompatTable compat_description = _linkgraph_sl_compat;
void Save(LinkGraphJob *lgj) const override
{
SlObject(const_cast<LinkGraph *>(&lgj->Graph()), this->GetDescription());
}
void Load(LinkGraphJob *lgj) const override
{
SlObject(const_cast<LinkGraph *>(&lgj->Graph()), this->GetLoadDescription());
}
};
/**
* Get a SaveLoad array for a link graph job. The settings struct is derived from
@ -56,43 +168,24 @@ void GetLinkGraphJobDayLengthScaleAfterLoad(LinkGraphJob *lgj)
*/
SaveLoadTable GetLinkGraphJobDesc()
{
static std::vector<SaveLoad> saveloads;
static const char *prefix = "linkgraph.";
/* Build the SaveLoad array on first call and don't touch it later on */
if (saveloads.size() == 0) {
size_t offset_gamesettings = cpp_offsetof(GameSettings, linkgraph);
size_t offset_component = cpp_offsetof(LinkGraphJob, settings);
size_t prefixlen = strlen(prefix);
int setting = 0;
const SettingDesc *desc = GetSettingDescription(setting);
while (desc != nullptr) {
if (desc->name != nullptr && strncmp(desc->name, prefix, prefixlen) == 0) {
SaveLoad sl = desc->save;
if (GetVarMemType(sl.conv) != SLE_VAR_NULL) {
char *&address = reinterpret_cast<char *&>(sl.address);
address -= offset_gamesettings;
address += offset_component;
}
saveloads.push_back(sl);
}
desc = GetSettingDescription(++setting);
}
const SaveLoad job_desc[] = {
SLE_VAR(LinkGraphJob, join_date_ticks, SLE_INT32),
SLE_CONDVAR_X(LinkGraphJob, start_date_ticks, SLE_INT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_LINKGRAPH_DAY_SCALE)),
SLE_VAR(LinkGraphJob, link_graph.index, SLE_UINT16),
};
for (auto &sld : job_desc) {
saveloads.push_back(sld);
}
}
static const SaveLoad job_desc[] = {
SLE_VAR2(LinkGraphJob, "linkgraph.recalc_interval", settings.recalc_interval, SLE_UINT16),
SLE_VAR2(LinkGraphJob, "linkgraph.recalc_time", settings.recalc_time, SLE_UINT16),
SLE_VAR2(LinkGraphJob, "linkgraph.distribution_pax", settings.distribution_pax, SLE_UINT8),
SLE_VAR2(LinkGraphJob, "linkgraph.distribution_mail", settings.distribution_mail, SLE_UINT8),
SLE_VAR2(LinkGraphJob, "linkgraph.distribution_armoured", settings.distribution_armoured, SLE_UINT8),
SLE_VAR2(LinkGraphJob, "linkgraph.distribution_default", settings.distribution_default, SLE_UINT8),
SLE_VAR2(LinkGraphJob, "linkgraph.accuracy", settings.accuracy, SLE_UINT8),
SLE_VAR2(LinkGraphJob, "linkgraph.demand_distance", settings.demand_distance, SLE_UINT8),
SLE_VAR2(LinkGraphJob, "linkgraph.demand_size", settings.demand_size, SLE_UINT8),
SLE_VAR2(LinkGraphJob, "linkgraph.short_path_saturation", settings.short_path_saturation, SLE_UINT8),
SLE_VAR2(LinkGraphJob, "join_date", join_date_ticks, SLE_INT32),
SLE_VAR(LinkGraphJob, link_graph.index, SLE_UINT16),
SLEG_STRUCT("linkgraph", SlLinkgraphJobProxy),
};
return saveloads;
return job_desc;
}
/**
@ -108,190 +201,6 @@ SaveLoadTable GetLinkGraphScheduleDesc()
return schedule_desc;
}
/* Edges and nodes are saved in the correct order, so we don't need to save their IDs. */
/**
* SaveLoad desc for a link graph node.
*/
static const SaveLoad _node_desc[] = {
SLE_CONDVAR(Node, xy, SLE_UINT32, SLV_191, SL_MAX_VERSION),
SLE_VAR(Node, supply, SLE_UINT32),
SLE_VAR(Node, demand, SLE_UINT32),
SLE_VAR(Node, station, SLE_UINT16),
SLE_VAR(Node, last_update, SLE_INT32),
};
/**
* SaveLoad desc for a link graph edge.
*/
static const SaveLoad _edge_desc[] = {
SLE_CONDNULL(4, SL_MIN_VERSION, SLV_191), // distance
SLE_VAR(Edge, capacity, SLE_UINT32),
SLE_VAR(Edge, usage, SLE_UINT32),
SLE_CONDVAR_X(Edge, travel_time_sum, SLE_UINT64, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_LINKGRAPH_TRAVEL_TIME)),
SLE_VAR(Edge, last_unrestricted_update, SLE_INT32),
SLE_CONDVAR(Edge, last_restricted_update, SLE_INT32, SLV_187, SL_MAX_VERSION),
SLE_CONDVAR_X(Edge, last_aircraft_update, SLE_INT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_LINKGRAPH_AIRCRAFT)),
// SLE_VAR(Edge, next_edge, SLE_UINT16), // Removed since XSLFI_LINKGRAPH_SPARSE_EDGES
};
std::vector<SaveLoad> _filtered_node_desc;
std::vector<SaveLoad> _filtered_edge_desc;
std::vector<SaveLoad> _filtered_job_desc;
static void FilterDescs()
{
_filtered_node_desc = SlFilterObject(_node_desc);
_filtered_edge_desc = SlFilterObject(_edge_desc);
_filtered_job_desc = SlFilterObject(GetLinkGraphJobDesc());
}
/**
* Save a link graph.
* @param lg Link graph to be saved or loaded.
*/
void Save_LinkGraph(LinkGraph &lg)
{
uint16 size = lg.Size();
auto edge_iter = lg.edges.begin();
auto edge_end = lg.edges.end();
for (NodeID from = 0; from < size; ++from) {
Node *node = &lg.nodes[from];
SlObjectSaveFiltered(node, _filtered_node_desc);
while (edge_iter != edge_end && edge_iter->first.first == from) {
SlWriteUint16(edge_iter->first.second);
Edge *edge = &edge_iter->second;
SlObjectSaveFiltered(edge, _filtered_edge_desc);
++edge_iter;
}
SlWriteUint16(INVALID_NODE);
}
}
/**
* Load a link graph.
* @param lg Link graph to be saved or loaded.
*/
void Load_LinkGraph(LinkGraph &lg)
{
uint size = lg.Size();
if (SlXvIsFeaturePresent(XSLFI_LINKGRAPH_SPARSE_EDGES)) {
for (NodeID from = 0; from < size; ++from) {
Node *node = &lg.nodes[from];
SlObjectLoadFiltered(node, _filtered_node_desc);
while (true) {
NodeID to = SlReadUint16();
if (to == INVALID_NODE) break;
SlObjectLoadFiltered(&lg.edges[std::make_pair(from, to)], _filtered_edge_desc);
}
}
} else if (IsSavegameVersionBefore(SLV_191)) {
std::vector<Edge> temp_edges;
std::vector<NodeID> temp_next_edges;
temp_edges.resize(size);
temp_next_edges.resize(size);
for (NodeID from = 0; from < size; ++from) {
Node *node = &lg.nodes[from];
SlObjectLoadFiltered(node, _filtered_node_desc);
/* We used to save the full matrix ... */
for (NodeID to = 0; to < size; ++to) {
SlObjectLoadFiltered(&temp_edges[to], _filtered_edge_desc);
temp_next_edges[to] = SlReadUint16();
}
for (NodeID to = from; to != INVALID_NODE; to = temp_next_edges[to]) {
lg.edges[std::make_pair(from, to)] = temp_edges[to];
}
}
} else {
for (NodeID from = 0; from < size; ++from) {
Node *node = &lg.nodes[from];
SlObjectLoadFiltered(node, _filtered_node_desc);
/* ... but as that wasted a lot of space we save a sparse matrix now. */
for (NodeID to = from; to != INVALID_NODE;) {
if (to >= size) SlErrorCorrupt("Link graph structure overflow");
SlObjectLoadFiltered(&lg.edges[std::make_pair(from, to)], _filtered_edge_desc);
to = SlReadUint16();
}
}
}
}
/**
* Save a link graph job.
* @param lgj LinkGraphJob to be saved.
*/
static void DoSave_LGRJ(LinkGraphJob *lgj)
{
SlObjectSaveFiltered(lgj, _filtered_job_desc);
_num_nodes = lgj->Size();
SlObjectSaveFiltered(const_cast<LinkGraph *>(&lgj->Graph()), GetLinkGraphDesc()); // GetLinkGraphDesc has no conditionals
Save_LinkGraph(const_cast<LinkGraph &>(lgj->Graph()));
}
/**
* Save a link graph.
* @param lg LinkGraph to be saved.
*/
static void DoSave_LGRP(LinkGraph *lg)
{
_num_nodes = lg->Size();
SlObjectSaveFiltered(lg, GetLinkGraphDesc()); // GetLinkGraphDesc has no conditionals
Save_LinkGraph(*lg);
}
/**
* Load all link graphs.
*/
static void Load_LGRP()
{
FilterDescs();
int index;
while ((index = SlIterateArray()) != -1) {
if (!LinkGraph::CanAllocateItem()) {
/* Impossible as they have been present in previous game. */
NOT_REACHED();
}
LinkGraph *lg = new (index) LinkGraph();
SlObjectLoadFiltered(lg, GetLinkGraphDesc()); // GetLinkGraphDesc has no conditionals
lg->Init(_num_nodes);
Load_LinkGraph(*lg);
}
}
/**
* Load all link graph jobs.
*/
static void Load_LGRJ()
{
FilterDescs();
int index;
while ((index = SlIterateArray()) != -1) {
if (!LinkGraphJob::CanAllocateItem()) {
/* Impossible as they have been present in previous game. */
NOT_REACHED();
}
LinkGraphJob *lgj = new (index) LinkGraphJob();
SlObjectLoadFiltered(lgj, _filtered_job_desc);
if (SlXvIsFeatureMissing(XSLFI_LINKGRAPH_DAY_SCALE)) {
extern void GetLinkGraphJobDayLengthScaleAfterLoad(LinkGraphJob *lgj);
GetLinkGraphJobDayLengthScaleAfterLoad(lgj);
}
LinkGraph &lg = const_cast<LinkGraph &>(lgj->Graph());
SlObjectLoadFiltered(&lg, GetLinkGraphDesc()); // GetLinkGraphDesc has no conditionals
lg.Init(_num_nodes);
Load_LinkGraph(lg);
}
}
/**
* Load the link graph schedule.
*/
static void Load_LGRS()
{
SlObject(&LinkGraphSchedule::instance, GetLinkGraphScheduleDesc());
}
/**
* Spawn the threads for running link graph calculations.
* Has to be done after loading as the cargo classes might have changed.
@ -314,6 +223,9 @@ void AfterLoadLinkGraphs()
}
}
}
for (LinkGraphJob *lgj : LinkGraphJob::Iterate()) {
GetLinkGraphJobDayLengthScaleAfterLoad(lgj);
}
LinkGraphSchedule::instance.SpawnAll();
@ -323,49 +235,99 @@ void AfterLoadLinkGraphs()
}
/**
* Save all link graphs.
* All link graphs.
*/
static void Save_LGRP()
{
FilterDescs();
for (LinkGraph *lg : LinkGraph::Iterate()) {
SlSetArrayIndex(lg->index);
SlAutolength((AutolengthProc*)DoSave_LGRP, lg);
struct LGRPChunkHandler : ChunkHandler {
LGRPChunkHandler() : ChunkHandler('LGRP', CH_TABLE) {}
void Save() const override
{
SlTableHeader(GetLinkGraphDesc());
for (LinkGraph *lg : LinkGraph::Iterate()) {
SlSetArrayIndex(lg->index);
SlObject(lg, GetLinkGraphDesc());
}
}
}
/**
* Save all link graph jobs.
*/
static void Save_LGRJ()
{
FilterDescs();
for (LinkGraphJob *lgj : LinkGraphJob::Iterate()) {
SlSetArrayIndex(lgj->index);
SlAutolength((AutolengthProc*)DoSave_LGRJ, lgj);
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(GetLinkGraphDesc(), _linkgraph_sl_compat);
int index;
while ((index = SlIterateArray()) != -1) {
LinkGraph *lg = new (index) LinkGraph();
SlObject(lg, slt);
}
}
}
};
/**
* Save the link graph schedule.
* All link graph jobs.
*/
static void Save_LGRS()
{
SlObject(&LinkGraphSchedule::instance, GetLinkGraphScheduleDesc());
}
struct LGRJChunkHandler : ChunkHandler {
LGRJChunkHandler() : ChunkHandler('LGRJ', CH_TABLE) {}
void Save() const override
{
SlTableHeader(GetLinkGraphJobDesc());
for (LinkGraphJob *lgj : LinkGraphJob::Iterate()) {
SlSetArrayIndex(lgj->index);
SlObject(lgj, GetLinkGraphJobDesc());
}
}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(GetLinkGraphJobDesc(), _linkgraph_job_sl_compat);
int index;
while ((index = SlIterateArray()) != -1) {
LinkGraphJob *lgj = new (index) LinkGraphJob();
SlObject(lgj, slt);
}
}
};
/**
* Substitute pointers in link graph schedule.
* Link graph schedule.
*/
static void Ptrs_LGRS()
{
SlObject(&LinkGraphSchedule::instance, GetLinkGraphScheduleDesc());
}
struct LGRSChunkHandler : ChunkHandler {
LGRSChunkHandler() : ChunkHandler('LGRS', CH_TABLE) {}
static const ChunkHandler linkgraph_chunk_handlers[] = {
{ 'LGRP', Save_LGRP, Load_LGRP, nullptr, nullptr, CH_ARRAY },
{ 'LGRJ', Save_LGRJ, Load_LGRJ, nullptr, nullptr, CH_ARRAY },
{ 'LGRS', Save_LGRS, Load_LGRS, Ptrs_LGRS, nullptr, CH_RIFF }
void Save() const override
{
SlTableHeader(GetLinkGraphScheduleDesc());
SlSetArrayIndex(0);
SlObject(&LinkGraphSchedule::instance, GetLinkGraphScheduleDesc());
}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(GetLinkGraphScheduleDesc(), _linkgraph_schedule_sl_compat);
if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() == -1) return;
SlObject(&LinkGraphSchedule::instance, slt);
if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many LGRS entries");
}
void FixPointers() const override
{
SlObject(&LinkGraphSchedule::instance, GetLinkGraphScheduleDesc());
}
};
static const LGRPChunkHandler LGRP;
static const LGRJChunkHandler LGRJ;
static const LGRSChunkHandler LGRS;
static const ChunkHandlerRef linkgraph_chunk_handlers[] = {
LGRP,
LGRJ,
LGRS,
};
extern const ChunkHandlerTable _linkgraph_chunk_handlers(linkgraph_chunk_handlers);
}

@ -8,413 +8,378 @@
/** @file map_sl.cpp Code handling saving and loading of map */
#include "../stdafx.h"
#include "saveload.h"
#include "compat/map_sl_compat.h"
#include "../map_func.h"
#include "../core/bitmath_func.hpp"
#include "../core/endian_func.hpp"
#include "../core/endian_type.hpp"
#include "../fios.h"
#include <array>
#include "saveload.h"
#include "saveload_buffer.h"
#include "../safeguards.h"
namespace upstream_sl {
static uint32 _map_dim_x;
static uint32 _map_dim_y;
extern bool _sl_maybe_chillpp;
static const SaveLoad _map_dimensions[] = {
SLEG_CONDVAR(_map_dim_x, SLE_UINT32, SLV_6, SL_MAX_VERSION),
SLEG_CONDVAR(_map_dim_y, SLE_UINT32, SLV_6, SL_MAX_VERSION),
static const SaveLoad _map_desc[] = {
SLEG_CONDVAR("dim_x", _map_dim_x, SLE_UINT32, SLV_6, SL_MAX_VERSION),
SLEG_CONDVAR("dim_y", _map_dim_y, SLE_UINT32, SLV_6, SL_MAX_VERSION),
};
static void Save_MAPS()
{
_map_dim_x = MapSizeX();
_map_dim_y = MapSizeY();
SlGlobList(_map_dimensions);
}
struct MAPSChunkHandler : ChunkHandler {
MAPSChunkHandler() : ChunkHandler('MAPS', CH_TABLE) {}
static void Load_MAPS()
{
SlGlobList(_map_dimensions);
if (!ValidateMapSize(_map_dim_x, _map_dim_y)) {
SlErrorCorruptFmt("Invalid map size: %u x %u", _map_dim_x, _map_dim_y);
}
AllocateMap(_map_dim_x, _map_dim_y);
}
void Save() const override
{
SlTableHeader(_map_desc);
static void Check_MAPS()
{
SlGlobList(_map_dimensions);
_load_check_data.map_size_x = _map_dim_x;
_load_check_data.map_size_y = _map_dim_y;
}
_map_dim_x = MapSizeX();
_map_dim_y = MapSizeY();
static const uint MAP_SL_BUF_SIZE = 4096;
SlSetArrayIndex(0);
SlGlobList(_map_desc);
}
static void Load_MAPT()
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_map_desc, _map_sl_compat);
for (TileIndex i = 0; i != size;) {
SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].type = buf[j];
}
}
if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() == -1) return;
SlGlobList(slt);
if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many MAPS entries");
static void Check_MAPH_common()
{
if (_sl_maybe_chillpp && (SlGetFieldLength() == 0 || SlGetFieldLength() == (size_t)_map_dim_x * (size_t)_map_dim_y * 2)) {
_sl_maybe_chillpp = false;
extern void SlXvChillPPSpecialSavegameVersions();
SlXvChillPPSpecialSavegameVersions();
AllocateMap(_map_dim_x, _map_dim_y);
}
}
static void Check_MAPH()
{
Check_MAPH_common();
SlSkipBytes(SlGetFieldLength());
}
void LoadCheck(size_t) const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_map_desc, _map_sl_compat);
static void Load_MAPH()
{
Check_MAPH_common();
if (SlXvIsFeaturePresent(XSLFI_CHILLPP)) {
if (SlGetFieldLength() != 0) {
_sl_xv_feature_versions[XSLFI_HEIGHT_8_BIT] = 2;
std::array<uint16, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() == -1) return;
SlGlobList(slt);
if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many MAPS entries");
for (TileIndex i = 0; i != size;) {
SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT16);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].height = buf[j];
}
}
return;
_load_check_data.map_size_x = _map_dim_x;
_load_check_data.map_size_y = _map_dim_y;
}
};
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
static const uint MAP_SL_BUF_SIZE = 4096;
for (TileIndex i = 0; i != size;) {
SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].height = buf[j];
}
}
struct MAPTChunkHandler : ChunkHandler {
MAPTChunkHandler() : ChunkHandler('MAPT', CH_RIFF) {}
static void Load_MAP1()
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
void Load() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
for (TileIndex i = 0; i != size;) {
SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m1 = buf[j];
for (TileIndex i = 0; i != size;) {
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].type = buf[j];
}
}
}
static void Load_MAP2()
{
std::array<uint16, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
for (TileIndex i = 0; i != size;) {
SlArray(buf.data(), MAP_SL_BUF_SIZE,
/* In those versions the m2 was 8 bits */
IsSavegameVersionBefore(SLV_5) ? SLE_FILE_U8 | SLE_VAR_U16 : SLE_UINT16
);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m2 = buf[j];
void Save() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
SlSetLength(size);
for (TileIndex i = 0; i != size;) {
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].type;
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
}
}
}
};
struct MAPHChunkHandler : ChunkHandler {
MAPHChunkHandler() : ChunkHandler('MAPH', CH_RIFF) {}
static void Load_MAP3()
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
void Load() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
for (TileIndex i = 0; i != size;) {
SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m3 = buf[j];
for (TileIndex i = 0; i != size;) {
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].height = buf[j];
}
}
}
static void Load_MAP4()
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
void Save() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
for (TileIndex i = 0; i != size;) {
SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m4 = buf[j];
SlSetLength(size);
for (TileIndex i = 0; i != size;) {
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].height;
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
}
}
}
};
struct MAPOChunkHandler : ChunkHandler {
MAPOChunkHandler() : ChunkHandler('MAPO', CH_RIFF) {}
static void Load_MAP5()
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
void Load() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
for (TileIndex i = 0; i != size;) {
SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m5 = buf[j];
for (TileIndex i = 0; i != size;) {
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m1 = buf[j];
}
}
}
static void Load_MAP6()
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
void Save() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
if (IsSavegameVersionBefore(SLV_42)) {
SlSetLength(size);
for (TileIndex i = 0; i != size;) {
/* 1024, otherwise we overflow on 64x64 maps! */
SlArray(buf.data(), 1024, SLE_UINT8);
for (uint j = 0; j != 1024; j++) {
_me[i++].m6 = GB(buf[j], 0, 2);
_me[i++].m6 = GB(buf[j], 2, 2);
_me[i++].m6 = GB(buf[j], 4, 2);
_me[i++].m6 = GB(buf[j], 6, 2);
}
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m1;
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
}
} else {
}
};
struct MAP2ChunkHandler : ChunkHandler {
MAP2ChunkHandler() : ChunkHandler('MAP2', CH_RIFF) {}
void Load() const override
{
std::array<uint16, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
for (TileIndex i = 0; i != size;) {
SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _me[i++].m6 = buf[j];
SlCopy(buf.data(), MAP_SL_BUF_SIZE,
/* In those versions the m2 was 8 bits */
IsSavegameVersionBefore(SLV_5) ? SLE_FILE_U8 | SLE_VAR_U16 : SLE_UINT16
);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m2 = buf[j];
}
}
}
static void Load_MAP7()
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
void Save() const override
{
std::array<uint16, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
for (TileIndex i = 0; i != size;) {
SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _me[i++].m7 = buf[j];
SlSetLength(size * sizeof(uint16));
for (TileIndex i = 0; i != size;) {
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m2;
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT16);
}
}
}
};
static void Load_MAP8()
{
std::array<uint16, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
struct M3LOChunkHandler : ChunkHandler {
M3LOChunkHandler() : ChunkHandler('M3LO', CH_RIFF) {}
for (TileIndex i = 0; i != size;) {
SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT16);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _me[i++].m8 = buf[j];
}
}
void Load() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
static void Load_WMAP()
{
static_assert(sizeof(Tile) == 8);
static_assert(sizeof(TileExtended) == 4);
assert(_sl_xv_feature_versions[XSLFI_WHOLE_MAP_CHUNK] == 1 || _sl_xv_feature_versions[XSLFI_WHOLE_MAP_CHUNK] == 2);
ReadBuffer *reader = ReadBuffer::GetCurrent();
const TileIndex size = MapSize();
#if TTD_ENDIAN == TTD_LITTLE_ENDIAN
reader->CopyBytes((byte *) _m, size * 8);
#else
for (TileIndex i = 0; i != size; i++) {
reader->CheckBytes(8);
_m[i].type = reader->RawReadByte();
_m[i].height = reader->RawReadByte();
uint16 m2 = reader->RawReadByte();
m2 |= ((uint16) reader->RawReadByte()) << 8;
_m[i].m2 = m2;
_m[i].m1 = reader->RawReadByte();
_m[i].m3 = reader->RawReadByte();
_m[i].m4 = reader->RawReadByte();
_m[i].m5 = reader->RawReadByte();
for (TileIndex i = 0; i != size;) {
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m3 = buf[j];
}
}
#endif
if (_sl_xv_feature_versions[XSLFI_WHOLE_MAP_CHUNK] == 1) {
for (TileIndex i = 0; i != size; i++) {
reader->CheckBytes(2);
_me[i].m6 = reader->RawReadByte();
_me[i].m7 = reader->RawReadByte();
}
} else if (_sl_xv_feature_versions[XSLFI_WHOLE_MAP_CHUNK] == 2) {
#if TTD_ENDIAN == TTD_LITTLE_ENDIAN
reader->CopyBytes((byte *) _me, size * 4);
#else
for (TileIndex i = 0; i != size; i++) {
reader->CheckBytes(4);
_me[i].m6 = reader->RawReadByte();
_me[i].m7 = reader->RawReadByte();
uint16 m8 = reader->RawReadByte();
m8 |= ((uint16) reader->RawReadByte()) << 8;
_me[i].m8 = m8;
void Save() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
SlSetLength(size);
for (TileIndex i = 0; i != size;) {
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m3;
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
}
#endif
} else {
NOT_REACHED();
}
}
};
static void Save_WMAP()
{
static_assert(sizeof(Tile) == 8);
static_assert(sizeof(TileExtended) == 4);
assert(_sl_xv_feature_versions[XSLFI_WHOLE_MAP_CHUNK] == 2);
MemoryDumper *dumper = MemoryDumper::GetCurrent();
const TileIndex size = MapSize();
SlSetLength(size * 12);
#if TTD_ENDIAN == TTD_LITTLE_ENDIAN
dumper->CopyBytes((byte *) _m, size * 8);
dumper->CopyBytes((byte *) _me, size * 4);
#else
for (TileIndex i = 0; i != size; i++) {
dumper->CheckBytes(8);
dumper->RawWriteByte(_m[i].type);
dumper->RawWriteByte(_m[i].height);
dumper->RawWriteByte(GB(_m[i].m2, 0, 8));
dumper->RawWriteByte(GB(_m[i].m2, 8, 8));
dumper->RawWriteByte(_m[i].m1);
dumper->RawWriteByte(_m[i].m3);
dumper->RawWriteByte(_m[i].m4);
dumper->RawWriteByte(_m[i].m5);
}
for (TileIndex i = 0; i != size; i++) {
dumper->CheckBytes(4);
dumper->RawWriteByte(_me[i].m6);
dumper->RawWriteByte(_me[i].m7);
dumper->RawWriteByte(GB(_me[i].m8, 0, 8));
dumper->RawWriteByte(GB(_me[i].m8, 8, 8));
struct M3HIChunkHandler : ChunkHandler {
M3HIChunkHandler() : ChunkHandler('M3HI', CH_RIFF) {}
void Load() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
for (TileIndex i = 0; i != size;) {
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m4 = buf[j];
}
}
#endif
}
struct MAPT {
typedef uint8 FieldT;
static const FieldT &GetField(TileIndex t) { return _m[t].type; }
};
void Save() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
struct MAPH {
typedef uint8 FieldT;
static const FieldT &GetField(TileIndex t) { return _m[t].height; }
SlSetLength(size);
for (TileIndex i = 0; i != size;) {
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m4;
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
}
}
};
struct MAP1 {
typedef uint8 FieldT;
static const FieldT &GetField(TileIndex t) { return _m[t].m1; }
};
struct MAP5ChunkHandler : ChunkHandler {
MAP5ChunkHandler() : ChunkHandler('MAP5', CH_RIFF) {}
struct MAP2 {
typedef uint16 FieldT;
static const FieldT &GetField(TileIndex t) { return _m[t].m2; }
};
void Load() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
struct MAP3 {
typedef uint8 FieldT;
static const FieldT &GetField(TileIndex t) { return _m[t].m3; }
};
for (TileIndex i = 0; i != size;) {
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m5 = buf[j];
}
}
struct MAP4 {
typedef uint8 FieldT;
static const FieldT &GetField(TileIndex t) { return _m[t].m4; }
};
void Save() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
struct MAP5 {
typedef uint8 FieldT;
static const FieldT &GetField(TileIndex t) { return _m[t].m5; }
SlSetLength(size);
for (TileIndex i = 0; i != size;) {
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m5;
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
}
}
};
struct MAP6 {
typedef uint8 FieldT;
static const FieldT &GetField(TileIndex t) { return _me[t].m6; }
};
struct MAPEChunkHandler : ChunkHandler {
MAPEChunkHandler() : ChunkHandler('MAPE', CH_RIFF) {}
struct MAP7 {
typedef uint8 FieldT;
static const FieldT &GetField(TileIndex t) { return _me[t].m7; }
};
void Load() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
struct MAP8 {
typedef uint16 FieldT;
static const FieldT &GetField(TileIndex t) { return _me[t].m8; }
};
if (IsSavegameVersionBefore(SLV_42)) {
for (TileIndex i = 0; i != size;) {
/* 1024, otherwise we overflow on 64x64 maps! */
SlCopy(buf.data(), 1024, SLE_UINT8);
for (uint j = 0; j != 1024; j++) {
_me[i++].m6 = GB(buf[j], 0, 2);
_me[i++].m6 = GB(buf[j], 2, 2);
_me[i++].m6 = GB(buf[j], 4, 2);
_me[i++].m6 = GB(buf[j], 6, 2);
}
}
} else {
for (TileIndex i = 0; i != size;) {
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _me[i++].m6 = buf[j];
}
}
}
template <typename T>
struct MAP_VarType {};
void Save() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
template <>
struct MAP_VarType<uint8>
{
static const VarType var_type = SLE_UINT8;
SlSetLength(size);
for (TileIndex i = 0; i != size;) {
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _me[i++].m6;
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
}
}
};
template <>
struct MAP_VarType<uint16>
{
static const VarType var_type = SLE_UINT16;
};
struct MAP7ChunkHandler : ChunkHandler {
MAP7ChunkHandler() : ChunkHandler('MAP7', CH_RIFF) {}
void Load() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
template <typename T>
static void Save_MAP()
{
assert(_sl_xv_feature_versions[XSLFI_WHOLE_MAP_CHUNK] == 0);
for (TileIndex i = 0; i != size;) {
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _me[i++].m7 = buf[j];
}
}
std::array<typename T::FieldT, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
void Save() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
SlSetLength(size * sizeof(typename T::FieldT));
for (TileIndex i = 0; i != size;) {
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = T::GetField(i++);
SlArray(buf.data(), MAP_SL_BUF_SIZE, MAP_VarType<typename T::FieldT>::var_type);
SlSetLength(size);
for (TileIndex i = 0; i != size;) {
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _me[i++].m7;
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
}
}
}
};
static ChunkSaveLoadSpecialOpResult Special_WMAP(uint32 chunk_id, ChunkSaveLoadSpecialOp op)
{
switch (op) {
case CSLSO_SHOULD_SAVE_CHUNK:
if (_sl_xv_feature_versions[XSLFI_WHOLE_MAP_CHUNK] == 0) return CSLSOR_DONT_SAVE_CHUNK;
break;
struct MAP8ChunkHandler : ChunkHandler {
MAP8ChunkHandler() : ChunkHandler('MAP8', CH_RIFF) {}
default:
break;
void Load() const override
{
std::array<uint16, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
for (TileIndex i = 0; i != size;) {
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT16);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _me[i++].m8 = buf[j];
}
}
return CSLSOR_NONE;
}
static ChunkSaveLoadSpecialOpResult Special_MAP_Chunks(uint32 chunk_id, ChunkSaveLoadSpecialOp op)
{
switch (op) {
case CSLSO_SHOULD_SAVE_CHUNK:
if (_sl_xv_feature_versions[XSLFI_WHOLE_MAP_CHUNK] != 0) return CSLSOR_DONT_SAVE_CHUNK;
break;
void Save() const override
{
std::array<uint16, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
default:
break;
SlSetLength(size * sizeof(uint16));
for (TileIndex i = 0; i != size;) {
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _me[i++].m8;
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT16);
}
}
return CSLSOR_NONE;
}
};
static const ChunkHandler map_chunk_handlers[] = {
{ 'MAPS', Save_MAPS, Load_MAPS, nullptr, Check_MAPS, CH_RIFF },
{ 'MAPT', Save_MAP<MAPT>, Load_MAPT, nullptr, nullptr, CH_RIFF, Special_MAP_Chunks },
{ 'MAPH', Save_MAP<MAPH>, Load_MAPH, nullptr, Check_MAPH, CH_RIFF, Special_MAP_Chunks },
{ 'MAPO', Save_MAP<MAP1>, Load_MAP1, nullptr, nullptr, CH_RIFF, Special_MAP_Chunks },
{ 'MAP2', Save_MAP<MAP2>, Load_MAP2, nullptr, nullptr, CH_RIFF, Special_MAP_Chunks },
{ 'M3LO', Save_MAP<MAP3>, Load_MAP3, nullptr, nullptr, CH_RIFF, Special_MAP_Chunks },
{ 'M3HI', Save_MAP<MAP4>, Load_MAP4, nullptr, nullptr, CH_RIFF, Special_MAP_Chunks },
{ 'MAP5', Save_MAP<MAP5>, Load_MAP5, nullptr, nullptr, CH_RIFF, Special_MAP_Chunks },
{ 'MAPE', Save_MAP<MAP6>, Load_MAP6, nullptr, nullptr, CH_RIFF, Special_MAP_Chunks },
{ 'MAP7', Save_MAP<MAP7>, Load_MAP7, nullptr, nullptr, CH_RIFF, Special_MAP_Chunks },
{ 'MAP8', Save_MAP<MAP8>, Load_MAP8, nullptr, nullptr, CH_RIFF, Special_MAP_Chunks },
{ 'WMAP', Save_WMAP, Load_WMAP, nullptr, nullptr, CH_RIFF, Special_WMAP },
static const MAPSChunkHandler MAPS;
static const MAPTChunkHandler MAPT;
static const MAPHChunkHandler MAPH;
static const MAPOChunkHandler MAPO;
static const MAP2ChunkHandler MAP2;
static const M3LOChunkHandler M3LO;
static const M3HIChunkHandler M3HI;
static const MAP5ChunkHandler MAP5;
static const MAPEChunkHandler MAPE;
static const MAP7ChunkHandler MAP7;
static const MAP8ChunkHandler MAP8;
static const ChunkHandlerRef map_chunk_handlers[] = {
MAPS,
MAPT,
MAPH,
MAPO,
MAP2,
M3LO,
M3HI,
MAP5,
MAPE,
MAP7,
MAP8,
};
extern const ChunkHandlerTable _map_chunk_handlers(map_chunk_handlers);
}

@ -8,6 +8,10 @@
/** @file misc_sl.cpp Saving and loading of things that didn't fit anywhere else */
#include "../stdafx.h"
#include "saveload.h"
#include "compat/misc_sl_compat.h"
#include "../date_func.h"
#include "../zoom_func.h"
#include "../window_gui.h"
@ -16,171 +20,128 @@
#include "../gfx_func.h"
#include "../core/random_func.hpp"
#include "../fios.h"
#include "../road_type.h"
#include "../core/checksum_func.hpp"
#include "../event_logs.h"
#include "../timer/timer.h"
#include "../timer/timer_game_tick.h"
#include "saveload.h"
#include "../safeguards.h"
extern TileIndex _cur_tileloop_tile;
extern TileIndex _aux_tileloop_tile;
extern uint16 _disaster_delay;
extern byte _trees_tick_ctr;
extern uint64 _aspect_cfg_hash;
/* Keep track of current game position */
int _saved_scrollpos_x;
int _saved_scrollpos_y;
ZoomLevel _saved_scrollpos_zoom;
void SaveViewportBeforeSaveGame()
{
const Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
if (w != nullptr) {
_saved_scrollpos_x = w->viewport->scrollpos_x;
_saved_scrollpos_y = w->viewport->scrollpos_y;
_saved_scrollpos_zoom = w->viewport->zoom;
}
}
void ResetViewportAfterLoadGame()
{
Window *w = GetMainWindow();
w->viewport->scrollpos_x = _saved_scrollpos_x;
w->viewport->scrollpos_y = _saved_scrollpos_y;
w->viewport->dest_scrollpos_x = _saved_scrollpos_x;
w->viewport->dest_scrollpos_y = _saved_scrollpos_y;
Viewport *vp = w->viewport;
vp->zoom = std::min(_saved_scrollpos_zoom, ZOOM_LVL_MAX);
vp->virtual_width = ScaleByZoom(vp->width, vp->zoom);
vp->virtual_height = ScaleByZoom(vp->height, vp->zoom);
/* If zoom_max is ZOOM_LVL_MIN then the setting has not been loaded yet, therefore all levels are allowed. */
if (_settings_client.gui.zoom_max != ZOOM_LVL_MIN) {
/* Ensure zoom level is allowed */
while (vp->zoom < _settings_client.gui.zoom_min) DoZoomInOutWindow(ZOOM_OUT, w);
while (vp->zoom > _settings_client.gui.zoom_max) DoZoomInOutWindow(ZOOM_IN, w);
}
extern int _saved_scrollpos_x;
extern int _saved_scrollpos_y;
extern ZoomLevel _saved_scrollpos_zoom;
DoZoomInOutWindow(ZOOM_NONE, w); // update button status
MarkWholeScreenDirty();
}
byte _age_cargo_skip_counter; ///< Skip aging of cargo? Used before savegame version 162.
extern byte _age_cargo_skip_counter; ///< Skip aging of cargo? Used before savegame version 162.
extern TimeoutTimer<TimerGameTick> _new_competitor_timeout;
namespace upstream_sl {
static const SaveLoad _date_desc[] = {
SLEG_CONDVAR(_date, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31),
SLEG_CONDVAR(_date, SLE_INT32, SLV_31, SL_MAX_VERSION),
SLEG_VAR(_date_fract, SLE_UINT16),
SLEG_CONDVAR_X(_tick_counter, SLE_FILE_U16 | SLE_VAR_U64, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_U64_TICK_COUNTER, 0, 0)),
SLEG_CONDVAR_X(_tick_counter, SLE_UINT64, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_U64_TICK_COUNTER)),
SLEG_CONDVAR_X(_tick_skip_counter, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_VARIABLE_DAY_LENGTH)),
SLEG_CONDVAR_X(_scaled_tick_counter, SLE_UINT64, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_VARIABLE_DAY_LENGTH, 3)),
SLEG_CONDVAR_X(_scaled_date_ticks_offset, SLE_INT64, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_VARIABLE_DAY_LENGTH, 3)),
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_157), // _vehicle_id_ctr_day
SLEG_CONDVAR(_age_cargo_skip_counter, SLE_UINT8, SL_MIN_VERSION, SLV_162),
SLE_CONDNULL(1, SL_MIN_VERSION, SLV_46),
SLEG_CONDVAR(_cur_tileloop_tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6),
SLEG_CONDVAR(_cur_tileloop_tile, SLE_UINT32, SLV_6, SL_MAX_VERSION),
SLEG_VAR(_disaster_delay, SLE_UINT16),
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_120),
SLEG_VAR(_random.state[0], SLE_UINT32),
SLEG_VAR(_random.state[1], SLE_UINT32),
SLEG_CONDVAR_X(_state_checksum.state, SLE_UINT64, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_STATE_CHECKSUM)),
SLE_CONDNULL(1, SL_MIN_VERSION, SLV_10),
SLE_CONDNULL(4, SLV_10, SLV_120),
SLEG_VAR(_cur_company_tick_index, SLE_FILE_U8 | SLE_VAR_U32),
SLEG_CONDVAR(_new_competitor_timeout.period, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_109),
SLEG_CONDVAR_X(_new_competitor_timeout.period, SLE_UINT32, SLV_109, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_AI_START_DATE, 0, 0)),
SLEG_VAR(_trees_tick_ctr, SLE_UINT8),
SLEG_CONDVAR(_pause_mode, SLE_UINT8, SLV_4, SL_MAX_VERSION),
SLEG_CONDVAR_X(_game_events_overall, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_GAME_EVENTS)),
SLEG_CONDVAR_X(_road_layout_change_counter, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ROAD_LAYOUT_CHANGE_CTR)),
SLE_CONDNULL_X(1, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_REALISTIC_TRAIN_BRAKING, 4, 6)), // _extra_aspects
SLEG_CONDVAR_X(_aspect_cfg_hash, SLE_UINT64, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_REALISTIC_TRAIN_BRAKING, 7)),
SLEG_CONDVAR_X(_aux_tileloop_tile, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_AUX_TILE_LOOP)),
SLE_CONDNULL(4, SLV_11, SLV_120),
SLEG_CONDVAR_X(_new_competitor_timeout.period, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_AI_START_DATE)),
SLEG_CONDVAR_X(_new_competitor_timeout.storage.elapsed, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_AI_START_DATE)),
SLEG_CONDVAR_X(_new_competitor_timeout.fired, SLE_BOOL, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_AI_START_DATE)),
SLEG_CONDVAR("date", _date, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31),
SLEG_CONDVAR("date", _date, SLE_INT32, SLV_31, SL_MAX_VERSION),
SLEG_VAR("date_fract", _date_fract, SLE_UINT16),
SLEG_CONDVAR("tick_counter", _tick_counter, SLE_FILE_U16 | SLE_VAR_U64, SL_MIN_VERSION, SLV_U64_TICK_COUNTER),
SLEG_CONDVAR("tick_counter", _tick_counter, SLE_UINT64, SLV_U64_TICK_COUNTER, SL_MAX_VERSION),
SLEG_CONDVAR("age_cargo_skip_counter", _age_cargo_skip_counter, SLE_UINT8, SL_MIN_VERSION, SLV_162),
SLEG_CONDVAR("cur_tileloop_tile", _cur_tileloop_tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6),
SLEG_CONDVAR("cur_tileloop_tile", _cur_tileloop_tile, SLE_UINT32, SLV_6, SL_MAX_VERSION),
SLEG_VAR("next_disaster_start", _disaster_delay, SLE_UINT16),
SLEG_VAR("random_state[0]", _random.state[0], SLE_UINT32),
SLEG_VAR("random_state[1]", _random.state[1], SLE_UINT32),
SLEG_VAR("company_tick_counter", _cur_company_tick_index, SLE_FILE_U8 | SLE_VAR_U32),
SLEG_VAR("trees_tick_counter", _trees_tick_ctr, SLE_UINT8),
SLEG_CONDVAR("pause_mode", _pause_mode, SLE_UINT8, SLV_4, SL_MAX_VERSION),
/* For older savegames, we load the current value as the "period"; afterload will set the "fired" and "elapsed". */
SLEG_CONDVAR("next_competitor_start", _new_competitor_timeout.period, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_109),
SLEG_CONDVAR("next_competitor_start", _new_competitor_timeout.period, SLE_UINT32, SLV_109, SLV_AI_START_DATE),
SLEG_CONDVAR("competitors_interval", _new_competitor_timeout.period, SLE_UINT32, SLV_AI_START_DATE, SL_MAX_VERSION),
SLEG_CONDVAR("competitors_interval_elapsed", _new_competitor_timeout.storage.elapsed, SLE_UINT32, SLV_AI_START_DATE, SL_MAX_VERSION),
SLEG_CONDVAR("competitors_interval_fired", _new_competitor_timeout.fired, SLE_BOOL, SLV_AI_START_DATE, SL_MAX_VERSION),
};
static const SaveLoad _date_check_desc[] = {
SLEG_CONDVAR(_load_check_data.current_date, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31),
SLEG_CONDVAR(_load_check_data.current_date, SLE_INT32, SLV_31, SL_MAX_VERSION),
SLE_NULL(2), // _date_fract
SLE_CONDNULL_X(2, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_U64_TICK_COUNTER, 0, 0)), // _tick_counter
SLE_CONDNULL_X(8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_U64_TICK_COUNTER)), // _tick_counter
SLE_CONDNULL_X(1, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_VARIABLE_DAY_LENGTH)), // _tick_skip_counter
SLE_CONDNULL_X(8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_VARIABLE_DAY_LENGTH, 3)), // _scaled_tick_counter
SLE_CONDNULL_X(8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_VARIABLE_DAY_LENGTH, 3)), // _scaled_date_ticks_offset
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_157), // _vehicle_id_ctr_day
SLE_CONDNULL(1, SL_MIN_VERSION, SLV_162), // _age_cargo_skip_counter
SLE_CONDNULL(1, SL_MIN_VERSION, SLV_46),
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_6), // _cur_tileloop_tile
SLE_CONDNULL(4, SLV_6, SL_MAX_VERSION), // _cur_tileloop_tile
SLE_NULL(2), // _disaster_delay
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_120),
SLE_NULL(4), // _random.state[0]
SLE_NULL(4), // _random.state[1]
SLE_CONDNULL_X(8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_STATE_CHECKSUM)), // _state_checksum.state
SLE_CONDNULL(1, SL_MIN_VERSION, SLV_10),
SLE_CONDNULL(4, SLV_10, SLV_120),
SLE_NULL(1), // _cur_company_tick_index
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_109), // _new_competitor_timeout.period
SLE_CONDNULL_X(4, SLV_109, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_AI_START_DATE, 0, 0)), // _new_competitor_timeout.period
SLE_NULL(1), // _trees_tick_ctr
SLE_CONDNULL(1, SLV_4, SL_MAX_VERSION), // _pause_mode
SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_GAME_EVENTS)), // _game_events_overall
SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ROAD_LAYOUT_CHANGE_CTR)), // _road_layout_change_counter
SLE_CONDNULL_X(1, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_REALISTIC_TRAIN_BRAKING, 4, 6)), // _extra_aspects
SLE_CONDNULL_X(8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_REALISTIC_TRAIN_BRAKING, 7)), // _aspect_cfg_hash
SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_AUX_TILE_LOOP)), // _aux_tileloop_tile
SLE_CONDNULL(4, SLV_11, SLV_120),
SLE_CONDNULL_X(9, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_AI_START_DATE)), // _new_competitor_timeout
SLEG_CONDVAR("date", _load_check_data.current_date, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31),
SLEG_CONDVAR("date", _load_check_data.current_date, SLE_INT32, SLV_31, SL_MAX_VERSION),
};
/* Save load date related variables as well as persistent tick counters
* XXX: currently some unrelated stuff is just put here */
static void SaveLoad_DATE()
{
SlGlobList(_date_desc);
SetScaledTickVariables();
}
struct DATEChunkHandler : ChunkHandler {
DATEChunkHandler() : ChunkHandler('DATE', CH_TABLE) {}
static void Check_DATE()
{
SlGlobList(_date_check_desc);
if (IsSavegameVersionBefore(SLV_31)) {
_load_check_data.current_date += DAYS_TILL_ORIGINAL_BASE_YEAR;
void Save() const override
{
SlTableHeader(_date_desc);
SlSetArrayIndex(0);
SlGlobList(_date_desc);
}
void LoadCommon(const SaveLoadTable &slt, const SaveLoadCompatTable &slct) const
{
const std::vector<SaveLoad> oslt = SlCompatTableHeader(slt, slct);
if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() == -1) return;
SlGlobList(oslt);
if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many DATE entries");
}
void Load() const override
{
this->LoadCommon(_date_desc, _date_sl_compat);
}
}
void LoadCheck(size_t) const override
{
this->LoadCommon(_date_check_desc, _date_check_sl_compat);
if (IsSavegameVersionBefore(SLV_31)) {
_load_check_data.current_date += DAYS_TILL_ORIGINAL_BASE_YEAR;
}
}
};
static const SaveLoad _view_desc[] = {
SLEG_CONDVAR(_saved_scrollpos_x, SLE_FILE_I16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_6),
SLEG_CONDVAR(_saved_scrollpos_x, SLE_INT32, SLV_6, SL_MAX_VERSION),
SLEG_CONDVAR(_saved_scrollpos_y, SLE_FILE_I16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_6),
SLEG_CONDVAR(_saved_scrollpos_y, SLE_INT32, SLV_6, SL_MAX_VERSION),
SLEG_VAR(_saved_scrollpos_zoom, SLE_UINT8),
SLEG_CONDVAR("x", _saved_scrollpos_x, SLE_FILE_I16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_6),
SLEG_CONDVAR("x", _saved_scrollpos_x, SLE_INT32, SLV_6, SL_MAX_VERSION),
SLEG_CONDVAR("y", _saved_scrollpos_y, SLE_FILE_I16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_6),
SLEG_CONDVAR("y", _saved_scrollpos_y, SLE_INT32, SLV_6, SL_MAX_VERSION),
SLEG_VAR("zoom", _saved_scrollpos_zoom, SLE_UINT8),
};
static void SaveLoad_VIEW()
{
SlGlobList(_view_desc);
}
struct VIEWChunkHandler : ChunkHandler {
VIEWChunkHandler() : ChunkHandler('VIEW', CH_TABLE) {}
void Save() const override
{
SlTableHeader(_view_desc);
static const ChunkHandler misc_chunk_handlers[] = {
{ 'DATE', SaveLoad_DATE, SaveLoad_DATE, nullptr, Check_DATE, CH_RIFF },
{ 'VIEW', SaveLoad_VIEW, SaveLoad_VIEW, nullptr, nullptr, CH_RIFF },
SlSetArrayIndex(0);
SlGlobList(_view_desc);
}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_view_desc, _view_sl_compat);
if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() == -1) return;
SlGlobList(slt);
if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many DATE entries");
}
};
static const DATEChunkHandler DATE;
static const VIEWChunkHandler VIEW;
static const ChunkHandlerRef misc_chunk_handlers[] = {
DATE,
VIEW,
};
extern const ChunkHandlerTable _misc_chunk_handlers(misc_chunk_handlers);
}

@ -8,63 +8,55 @@
/** @file newgrf_sl.cpp Code handling saving and loading of newgrf config */
#include "../stdafx.h"
#include "../fios.h"
#include "../string_func.h"
#include "saveload.h"
#include "compat/newgrf_sl_compat.h"
#include "newgrf_sl.h"
#include "../fios.h"
#include "../safeguards.h"
namespace upstream_sl {
/** Save and load the mapping between a spec and the NewGRF it came from. */
static const SaveLoad _newgrf_mapping_desc_old[] = {
static const SaveLoad _newgrf_mapping_desc[] = {
SLE_VAR(EntityIDMapping, grfid, SLE_UINT32),
SLE_VAR(EntityIDMapping, entity_id, SLE_FILE_U8 | SLE_VAR_U16),
SLE_VAR(EntityIDMapping, substitute_id, SLE_FILE_U8 | SLE_VAR_U16),
};
static const SaveLoad _newgrf_mapping_desc_new[] = {
SLE_VAR(EntityIDMapping, grfid, SLE_UINT32),
SLE_VAR(EntityIDMapping, entity_id, SLE_UINT16),
SLE_VAR(EntityIDMapping, substitute_id, SLE_UINT16),
SLE_CONDVAR(EntityIDMapping, entity_id, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_EXTEND_ENTITY_MAPPING),
SLE_CONDVAR(EntityIDMapping, entity_id, SLE_UINT16, SLV_EXTEND_ENTITY_MAPPING, SL_MAX_VERSION),
SLE_CONDVAR(EntityIDMapping, substitute_id, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_EXTEND_ENTITY_MAPPING),
SLE_CONDVAR(EntityIDMapping, substitute_id, SLE_UINT16, SLV_EXTEND_ENTITY_MAPPING, SL_MAX_VERSION),
};
/**
* Save a GRF ID + local id -> OpenTTD's id mapping.
* @param mapping The mapping to save.
*/
void Save_NewGRFMapping(const OverrideManagerBase &mapping)
void NewGRFMappingChunkHandler::Save() const
{
for (uint i = 0; i < mapping.GetMaxMapping(); i++) {
if (mapping.mappings[i].grfid == 0 &&
mapping.mappings[i].entity_id == 0) continue;
SlSetArrayIndex(i);
SlSetLength(4 + 2 + 2);
SlObjectSaveFiltered(const_cast<EntityIDMapping *>(&mapping.mappings[i]), _newgrf_mapping_desc_new); // _newgrf_mapping_desc_new has no conditionals
}
// removed
NOT_REACHED();
}
/**
* Load a GRF ID + local id -> OpenTTD's id mapping.
* @param mapping The mapping to load.
*/
void Load_NewGRFMapping(OverrideManagerBase &mapping)
void NewGRFMappingChunkHandler::Load() const
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_newgrf_mapping_desc, _newgrf_mapping_sl_compat);
/* Clear the current mapping stored.
* This will create the manager if ever it is not yet done */
mapping.ResetMapping();
uint max_id = mapping.GetMaxMapping();
this->mapping.ResetMapping();
SaveLoadTable slt = SlXvIsFeaturePresent(XSLFI_NEWGRF_ENTITY_EXTRA) ? SaveLoadTable(_newgrf_mapping_desc_new) : SaveLoadTable(_newgrf_mapping_desc_old);
uint max_id = this->mapping.GetMaxMapping();
int index;
while ((index = SlIterateArray()) != -1) {
if (unlikely((uint)index >= max_id)) SlErrorCorrupt("Too many NewGRF entity mappings");
SlObjectLoadFiltered(&mapping.mappings[index], slt); // _newgrf_mapping_desc_old/_newgrf_mapping_desc_new has no conditionals
if ((uint)index >= max_id) SlErrorCorrupt("Too many NewGRF entity mappings");
SlObject(&this->mapping.mappings[index], slt);
}
}
static std::string _grf_name;
static const SaveLoad _grfconfig_desc[] = {
SLE_SSTR(GRFConfig, filename, SLE_STR),
@ -74,60 +66,66 @@ static const SaveLoad _grfconfig_desc[] = {
SLE_ARR(GRFConfig, param, SLE_UINT32, 0x80),
SLE_VAR(GRFConfig, num_params, SLE_UINT8),
SLE_CONDVAR(GRFConfig, palette, SLE_UINT8, SLV_101, SL_MAX_VERSION),
SLEG_CONDSSTR_X(_grf_name, 0, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_NEWGRF_INFO_EXTRA)),
};
static void Save_NGRF()
{
int index = 0;
struct NGRFChunkHandler : ChunkHandler {
NGRFChunkHandler() : ChunkHandler('NGRF', CH_TABLE) {}
for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) {
if (HasBit(c->flags, GCF_STATIC) || HasBit(c->flags, GCF_INIT_ONLY)) continue;
SlSetArrayIndex(index++);
_grf_name = str_strip_all_scc(GetDefaultLangGRFStringFromGRFText(c->name));
SlObject(c, _grfconfig_desc);
void Save() const override
{
SlTableHeader(_grfconfig_desc);
int index = 0;
for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) {
if (HasBit(c->flags, GCF_STATIC) || HasBit(c->flags, GCF_INIT_ONLY)) continue;
SlSetArrayIndex(index++);
SlObject(c, _grfconfig_desc);
}
}
}
static void Load_NGRF_common(GRFConfig *&grfconfig)
{
ClearGRFConfigList(&grfconfig);
while (SlIterateArray() != -1) {
GRFConfig *c = new GRFConfig();
SlObject(c, _grfconfig_desc);
if (SlXvIsFeaturePresent(XSLFI_NEWGRF_INFO_EXTRA)) {
AddGRFTextToList(c->name, 0x7F, c->ident.grfid, false, _grf_name.c_str());
void LoadCommon(GRFConfig *&grfconfig) const
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_grfconfig_desc, _grfconfig_sl_compat);
ClearGRFConfigList(&grfconfig);
while (SlIterateArray() != -1) {
GRFConfig *c = new GRFConfig();
SlObject(c, slt);
if (IsSavegameVersionBefore(SLV_101)) c->SetSuitablePalette();
AppendToGRFConfigList(&grfconfig, c);
}
if (IsSavegameVersionBefore(SLV_101)) c->SetSuitablePalette();
AppendToGRFConfigList(&grfconfig, c);
}
}
static void Load_NGRF()
{
Load_NGRF_common(_grfconfig);
void Load() const override
{
this->LoadCommon(_grfconfig);
if (_game_mode == GM_MENU) {
/* Intro game must not have NewGRF. */
if (_grfconfig != nullptr) SlErrorCorrupt("The intro game must not use NewGRF");
if (_game_mode == GM_MENU) {
/* Intro game must not have NewGRF. */
if (_grfconfig != nullptr) SlErrorCorrupt("The intro game must not use NewGRF");
/* Activate intro NewGRFs (townnames) */
ResetGRFConfig(false);
} else {
/* Append static NewGRF configuration */
AppendStaticGRFConfigs(&_grfconfig);
/* Activate intro NewGRFs (townnames) */
ResetGRFConfig(false);
} else {
/* Append static NewGRF configuration */
AppendStaticGRFConfigs(&_grfconfig);
}
}
}
static void Check_NGRF()
{
Load_NGRF_common(_load_check_data.grfconfig);
}
void LoadCheck(size_t) const override
{
this->LoadCommon(_load_check_data.grfconfig);
}
};
static const ChunkHandler newgrf_chunk_handlers[] = {
{ 'NGRF', Save_NGRF, Load_NGRF, nullptr, Check_NGRF, CH_ARRAY }
static const NGRFChunkHandler NGRF;
static const ChunkHandlerRef newgrf_chunk_handlers[] = {
NGRF,
};
extern const ChunkHandlerTable _newgrf_chunk_handlers(newgrf_chunk_handlers);
}

@ -7,12 +7,21 @@
/** @file newgrf_sl.h Code handling saving and loading of NewGRF mappings. */
#ifndef SAVELOAD_NEWGRF_SL_H
#define SAVELOAD_NEWGRF_SL_H
#ifndef SAVELOAD_UPSTREAM_NEWGRF_SL_H
#define SAVELOAD_UPSTREAM_NEWGRF_SL_H
#include "../newgrf_commons.h"
void Save_NewGRFMapping(const OverrideManagerBase &mapping);
void Load_NewGRFMapping(OverrideManagerBase &mapping);
namespace upstream_sl {
#endif /* SAVELOAD_NEWGRF_SL_H */
struct NewGRFMappingChunkHandler : ChunkHandler {
OverrideManagerBase &mapping;
NewGRFMappingChunkHandler(uint32 id, OverrideManagerBase &mapping) : ChunkHandler(id, CH_TABLE), mapping(mapping) {}
void Save() const override;
void Load() const override;
};
}
#endif /* SAVELOAD_UPSTREAM_NEWGRF_SL_H */

@ -8,14 +8,18 @@
/** @file object_sl.cpp Code handling saving and loading of objects */
#include "../stdafx.h"
#include "../object_base.h"
#include "../object_map.h"
#include "saveload.h"
#include "compat/object_sl_compat.h"
#include "../object_base.h"
#include "../object_map.h"
#include "newgrf_sl.h"
#include "../safeguards.h"
namespace upstream_sl {
static const SaveLoad _object_desc[] = {
SLE_VAR(Object, location.tile, SLE_UINT32),
SLE_VAR(Object, location.w, SLE_FILE_U8 | SLE_VAR_U16),
@ -27,48 +31,54 @@ static const SaveLoad _object_desc[] = {
SLE_CONDVAR(Object, type, SLE_UINT16, SLV_186, SL_MAX_VERSION),
};
static void Save_OBJS()
{
/* Write the objects */
for (Object *o : Object::Iterate()) {
SlSetArrayIndex(o->index);
SlObject(o, _object_desc);
}
}
struct OBJSChunkHandler : ChunkHandler {
OBJSChunkHandler() : ChunkHandler('OBJS', CH_TABLE) {}
void Save() const override
{
SlTableHeader(_object_desc);
static void Load_OBJS()
{
int index;
while ((index = SlIterateArray()) != -1) {
Object *o = new (index) Object();
SlObject(o, _object_desc);
/* Write the objects */
for (Object *o : Object::Iterate()) {
SlSetArrayIndex(o->index);
SlObject(o, _object_desc);
}
}
}
static void Ptrs_OBJS()
{
for (Object *o : Object::Iterate()) {
SlObject(o, _object_desc);
if (IsSavegameVersionBefore(SLV_148) && !IsTileType(o->location.tile, MP_OBJECT)) {
/* Due to a small bug stale objects could remain. */
delete o;
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_object_desc, _object_sl_compat);
int index;
while ((index = SlIterateArray()) != -1) {
Object *o = new (index) Object();
SlObject(o, slt);
}
}
}
static void Save_OBID()
{
Save_NewGRFMapping(_object_mngr);
}
void FixPointers() const override
{
for (Object *o : Object::Iterate()) {
SlObject(o, _object_desc);
if (IsSavegameVersionBefore(SLV_148) && !IsTileType(o->location.tile, MP_OBJECT)) {
/* Due to a small bug stale objects could remain. */
delete o;
}
}
}
};
static void Load_OBID()
{
Load_NewGRFMapping(_object_mngr);
}
struct OBIDChunkHandler : NewGRFMappingChunkHandler {
OBIDChunkHandler() : NewGRFMappingChunkHandler('OBID', _object_mngr) {}
};
static const ChunkHandler object_chunk_handlers[] = {
{ 'OBID', Save_OBID, Load_OBID, nullptr, nullptr, CH_ARRAY },
{ 'OBJS', Save_OBJS, Load_OBJS, Ptrs_OBJS, nullptr, CH_ARRAY },
static const OBIDChunkHandler OBID;
static const OBJSChunkHandler OBJS;
static const ChunkHandlerRef object_chunk_handlers[] = {
OBID,
OBJS,
};
extern const ChunkHandlerTable _object_chunk_handlers(object_chunk_handlers);
}

@ -8,72 +8,18 @@
/** @file order_sl.cpp Code handling saving and loading of orders */
#include "../stdafx.h"
#include "saveload.h"
#include "compat/order_sl_compat.h"
#include "../order_backup.h"
#include "../order_base.h"
#include "../settings_type.h"
#include "../network/network.h"
#include "saveload_internal.h"
#include "../safeguards.h"
static uint32 _jokerpp_separation_mode;
std::vector<OrderList *> _jokerpp_auto_separation;
std::vector<OrderList *> _jokerpp_non_auto_separation;
/**
* Converts this order from an old savegame's version;
* it moves all bits to the new location.
*/
void Order::ConvertFromOldSavegame()
{
uint8 old_flags = this->flags;
this->flags = 0;
/* First handle non-stop - use value from savegame if possible, else use value from config file */
if (_settings_client.gui.sg_new_nonstop || (IsSavegameVersionBefore(SLV_22) && _savegame_type != SGT_TTO && _savegame_type != SGT_TTD && (_settings_client.gui.new_nonstop || _settings_game.order.nonstop_only))) {
/* OFB_NON_STOP */
this->SetNonStopType((old_flags & 8) ? ONSF_NO_STOP_AT_ANY_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS);
} else {
this->SetNonStopType((old_flags & 8) ? ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS : ONSF_STOP_EVERYWHERE);
}
switch (this->GetType()) {
/* Only a few types need the other savegame conversions. */
case OT_GOTO_DEPOT: case OT_GOTO_STATION: case OT_LOADING: break;
default: return;
}
if (this->GetType() != OT_GOTO_DEPOT) {
/* Then the load flags */
if ((old_flags & 2) != 0) { // OFB_UNLOAD
this->SetLoadType(OLFB_NO_LOAD);
} else if ((old_flags & 4) == 0) { // !OFB_FULL_LOAD
this->SetLoadType(OLF_LOAD_IF_POSSIBLE);
} else {
/* old OTTD versions stored full_load_any in config file - assume it was enabled when loading */
this->SetLoadType(_settings_client.gui.sg_full_load_any || IsSavegameVersionBefore(SLV_22) ? OLF_FULL_LOAD_ANY : OLFB_FULL_LOAD);
}
if (this->IsType(OT_GOTO_STATION)) this->SetStopLocation(OSL_PLATFORM_FAR_END);
/* Finally fix the unload flags */
if ((old_flags & 1) != 0) { // OFB_TRANSFER
this->SetUnloadType(OUFB_TRANSFER);
} else if ((old_flags & 2) != 0) { // OFB_UNLOAD
this->SetUnloadType(OUFB_UNLOAD);
} else {
this->SetUnloadType(OUF_UNLOAD_IF_POSSIBLE);
}
} else {
/* Then the depot action flags */
this->SetDepotActionType(((old_flags & 6) == 4) ? ODATFB_HALT : ODATF_SERVICE_ONLY);
/* Finally fix the depot type flags */
uint t = ((old_flags & 6) == 6) ? ODTFB_SERVICE : ODTF_MANUAL;
if ((old_flags & 2) != 0) t |= ODTFB_PART_OF_ORDERS;
this->SetDepotOrderType((OrderDepotTypeFlags)t);
}
}
namespace upstream_sl {
/**
* Unpacks a order from savegames with version 4 and lower
@ -82,17 +28,7 @@ void Order::ConvertFromOldSavegame()
*/
static Order UnpackVersion4Order(uint16 packed)
{
return Order(((uint64) GB(packed, 8, 8)) << 24 | ((uint64) GB(packed, 4, 4)) << 8 | ((uint64) GB(packed, 0, 4)));
}
/**
* Unpacks a order from savegames with version 5.1 and lower
* @param packed packed order
* @return unpacked order
*/
static Order UnpackVersion5Order(uint32 packed)
{
return Order(((uint64) GB(packed, 16, 16)) << 24 | ((uint64) GB(packed, 8, 8)) << 8 | ((uint64) GB(packed, 0, 8)));
return Order(GB(packed, 8, 8) << 16 | GB(packed, 4, 4) << 8 | GB(packed, 0, 4));
}
/**
@ -117,221 +53,146 @@ SaveLoadTable GetOrderDescription()
{
static const SaveLoad _order_desc[] = {
SLE_VAR(Order, type, SLE_UINT8),
SLE_CONDVAR_X(Order, flags, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ORDER_FLAGS_EXTRA, 0, 0)),
SLE_CONDVAR_X(Order, flags, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ORDER_FLAGS_EXTRA, 1)),
SLE_CONDNULL_X(1, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SPRINGPP)),
SLE_VAR(Order, flags, SLE_FILE_U8 | SLE_VAR_U16),
SLE_VAR(Order, dest, SLE_UINT16),
SLE_REF(Order, next, REF_ORDER),
SLE_CONDVAR(Order, refit_cargo, SLE_UINT8, SLV_36, SL_MAX_VERSION),
SLE_CONDNULL(1, SLV_36, SLV_182), // refit_subtype
SLE_CONDVAR_X(Order, occupancy, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ORDER_OCCUPANCY)),
SLE_CONDVAR_X(Order, wait_time, SLE_FILE_U16 | SLE_VAR_U32, SLV_67, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLE_EXTRA, 0, 5)),
SLE_CONDVAR_X(Order, wait_time, SLE_UINT32, SLV_67, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLE_EXTRA, 6)),
SLE_CONDVAR_X(Order, travel_time, SLE_FILE_U16 | SLE_VAR_U32, SLV_67, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLE_EXTRA, 0, 5)),
SLE_CONDVAR_X(Order, travel_time, SLE_UINT32, SLV_67, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLE_EXTRA, 6)),
SLE_CONDVAR(Order, wait_time, SLE_FILE_U16 | SLE_VAR_U32, SLV_67, SL_MAX_VERSION),
SLE_CONDVAR(Order, travel_time, SLE_FILE_U16 | SLE_VAR_U32, SLV_67, SL_MAX_VERSION),
SLE_CONDVAR(Order, max_speed, SLE_UINT16, SLV_172, SL_MAX_VERSION),
SLE_CONDNULL_X(1, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_MORE_COND_ORDERS, 1, 6)), // jump_counter
/* Leftover from the minor savegame version stuff
* We will never use those free bytes, but we have to keep this line to allow loading of old savegames */
SLE_CONDNULL(10, SLV_5, SLV_36),
};
return _order_desc;
}
static std::vector<SaveLoad> _filtered_desc;
struct ORDRChunkHandler : ChunkHandler {
ORDRChunkHandler() : ChunkHandler('ORDR', CH_TABLE) {}
static void Save_ORDR()
{
_filtered_desc = SlFilterObject(GetOrderDescription());
for (Order *order : Order::Iterate()) {
SlSetArrayIndex(order->index);
SlObjectSaveFiltered(order, _filtered_desc);
void Save() const override
{
const SaveLoadTable slt = GetOrderDescription();
SlTableHeader(slt);
for (Order *order : Order::Iterate()) {
SlSetArrayIndex(order->index);
SlObject(order, slt);
}
}
}
static void Load_ORDR()
{
if (IsSavegameVersionBefore(SLV_5, 2)) {
/* Version older than 5.2 did not have a ->next pointer. Convert them
* (in the old days, the orderlist was 5000 items big) */
size_t len = SlGetFieldLength();
if (IsSavegameVersionBefore(SLV_5)) {
/* Pre-version 5 had another layout for orders
* (uint16 instead of uint32) */
len /= sizeof(uint16);
uint16 *orders = MallocT<uint16>(len + 1);
SlArray(orders, len, SLE_UINT16);
for (size_t i = 0; i < len; ++i) {
Order *o = new (i) Order();
o->AssignOrder(UnpackVersion4Order(orders[i]));
}
void Load() const override
{
if (IsSavegameVersionBefore(SLV_5, 2)) {
/* Version older than 5.2 did not have a ->next pointer. Convert them
* (in the old days, the orderlist was 5000 items big) */
size_t len = SlGetFieldLength();
free(orders);
} else if (IsSavegameVersionBefore(SLV_5, 2)) {
len /= sizeof(uint32);
uint32 *orders = MallocT<uint32>(len + 1);
if (IsSavegameVersionBefore(SLV_5)) {
/* Pre-version 5 had another layout for orders
* (uint16 instead of uint32) */
len /= sizeof(uint16);
uint16 *orders = MallocT<uint16>(len + 1);
SlArray(orders, len, SLE_UINT32);
SlCopy(orders, len, SLE_UINT16);
for (size_t i = 0; i < len; ++i) {
Order *o = new (i) Order();
o->AssignOrder(UnpackVersion5Order(orders[i]));
}
for (size_t i = 0; i < len; ++i) {
Order *o = new (i) Order();
o->AssignOrder(UnpackVersion4Order(orders[i]));
}
free(orders);
}
free(orders);
} else if (IsSavegameVersionBefore(SLV_5, 2)) {
len /= sizeof(uint32);
uint32 *orders = MallocT<uint32>(len + 1);
/* Update all the next pointer */
for (Order *o : Order::Iterate()) {
size_t order_index = o->index;
/* Delete invalid orders */
if (o->IsType(OT_NOTHING)) {
delete o;
continue;
}
/* The orders were built like this:
* While the order is valid, set the previous will get its next pointer set */
Order *prev = Order::GetIfValid(order_index - 1);
if (prev != nullptr) prev->next = o;
}
} else {
_filtered_desc = SlFilterObject(GetOrderDescription());
int index;
SlCopy(orders, len, SLE_UINT32);
while ((index = SlIterateArray()) != -1) {
Order *order = new (index) Order();
SlObjectLoadFiltered(order, _filtered_desc);
}
}
}
for (size_t i = 0; i < len; ++i) {
new (i) Order(orders[i]);
}
const SaveLoadTable GetOrderExtraInfoDescription()
{
static const SaveLoad _order_extra_info_desc[] = {
SLE_CONDARR_X(OrderExtraInfo, cargo_type_flags, SLE_UINT8, 32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CARGO_TYPE_ORDERS, 1, 2)),
SLE_CONDARR_X(OrderExtraInfo, cargo_type_flags, SLE_UINT8, NUM_CARGO, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CARGO_TYPE_ORDERS, 3)),
SLE_CONDVAR_X(OrderExtraInfo, xflags, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLE_EXTRA)),
SLE_CONDVAR_X(OrderExtraInfo, xdata, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ORDER_EXTRA_DATA)),
SLE_CONDVAR_X(OrderExtraInfo, dispatch_index, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SCHEDULED_DISPATCH, 3)),
SLE_CONDVAR_X(OrderExtraInfo, colour, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ORDER_EXTRA_DATA, 2)),
};
free(orders);
}
return _order_extra_info_desc;
}
/* Update all the next pointer */
for (Order *o : Order::Iterate()) {
size_t order_index = o->index;
/* Delete invalid orders */
if (o->IsType(OT_NOTHING)) {
delete o;
continue;
}
/* The orders were built like this:
* While the order is valid, set the previous will get its next pointer set */
Order *prev = Order::GetIfValid(order_index - 1);
if (prev != nullptr) prev->next = o;
}
} else {
const std::vector<SaveLoad> slt = SlCompatTableHeader(GetOrderDescription(), _order_sl_compat);
void Save_ORDX()
{
_filtered_desc = SlFilterObject(GetOrderExtraInfoDescription());
for (Order *order : Order::Iterate()) {
if (order->extra) {
SlSetArrayIndex(order->index);
SlObjectSaveFiltered(order->extra.get(), _filtered_desc);
}
}
}
int index;
void Load_ORDX()
{
_filtered_desc = SlFilterObject(GetOrderExtraInfoDescription());
int index;
while ((index = SlIterateArray()) != -1) {
Order *order = Order::GetIfValid(index);
assert(order != nullptr);
order->AllocExtraInfo();
SlObjectLoadFiltered(order->extra.get(), _filtered_desc);
while ((index = SlIterateArray()) != -1) {
Order *order = new (index) Order();
SlObject(order, slt);
}
}
}
}
static void Ptrs_ORDR()
{
/* Orders from old savegames have pointers corrected in Load_ORDR */
if (IsSavegameVersionBefore(SLV_5, 2)) return;
void FixPointers() const override
{
/* Orders from old savegames have pointers corrected in Load_ORDR */
if (IsSavegameVersionBefore(SLV_5, 2)) return;
for (Order *o : Order::Iterate()) {
SlObject(o, GetOrderDescription());
for (Order *o : Order::Iterate()) {
SlObject(o, GetOrderDescription());
}
}
}
SaveLoadTable GetDispatchScheduleDescription()
{
static const SaveLoad _order_extra_info_desc[] = {
SLE_VARVEC(DispatchSchedule, scheduled_dispatch, SLE_UINT32),
SLE_VAR(DispatchSchedule, scheduled_dispatch_duration, SLE_UINT32),
SLE_VAR(DispatchSchedule, scheduled_dispatch_start_date, SLE_INT32),
SLE_VAR(DispatchSchedule, scheduled_dispatch_start_full_date_fract, SLE_UINT16),
SLE_VAR(DispatchSchedule, scheduled_dispatch_last_dispatch, SLE_INT32),
SLE_VAR(DispatchSchedule, scheduled_dispatch_max_delay, SLE_INT32),
SLE_CONDSSTR_X(DispatchSchedule, name, 0, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SCHEDULED_DISPATCH, 4)),
};
return _order_extra_info_desc;
}
};
SaveLoadTable GetOrderListDescription()
{
static const SaveLoad _orderlist_desc[] = {
SLE_REF(OrderList, first, REF_ORDER),
SLEG_CONDVAR_X(_jokerpp_separation_mode, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP)),
SLE_CONDNULL_X(21, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP)),
SLE_REF(OrderList, first, REF_ORDER),
};
return _orderlist_desc;
}
static void Save_ORDL()
{
for (OrderList *list : OrderList::Iterate()) {
SlSetArrayIndex(list->index);
SlAutolength([](void *data) {
OrderList *list = static_cast<OrderList *>(data);
SlObject(list, GetOrderListDescription());
SlWriteUint32(list->GetScheduledDispatchScheduleCount());
for (DispatchSchedule &ds : list->GetScheduledDispatchScheduleSet()) {
SlObject(&ds, GetDispatchScheduleDescription());
}
}, list);
}
}
struct ORDLChunkHandler : ChunkHandler {
ORDLChunkHandler() : ChunkHandler('ORDL', CH_TABLE) {}
static void Load_ORDL()
{
_jokerpp_auto_separation.clear();
_jokerpp_non_auto_separation.clear();
int index;
while ((index = SlIterateArray()) != -1) {
/* set num_orders to 0 so it's a valid OrderList */
OrderList *list = new (index) OrderList(0);
SlObject(list, GetOrderListDescription());
if (SlXvIsFeaturePresent(XSLFI_JOKERPP)) {
if (_jokerpp_separation_mode == 0) {
_jokerpp_auto_separation.push_back(list);
} else {
_jokerpp_non_auto_separation.push_back(list);
}
void Save() const override
{
const SaveLoadTable slt = GetOrderListDescription();
SlTableHeader(slt);
for (OrderList *list : OrderList::Iterate()) {
SlSetArrayIndex(list->index);
SlObject(list, slt);
}
if (SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH)) {
uint count = SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH, 3) ? SlReadUint32() : 1;
list->GetScheduledDispatchScheduleSet().resize(count);
for (DispatchSchedule &ds : list->GetScheduledDispatchScheduleSet()) {
SlObject(&ds, GetDispatchScheduleDescription());
}
}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(GetOrderListDescription(), _orderlist_sl_compat);
int index;
while ((index = SlIterateArray()) != -1) {
/* set num_orders to 0 so it's a valid OrderList */
OrderList *list = new (index) OrderList(0);
SlObject(list, slt);
}
}
}
void Ptrs_ORDL()
{
for (OrderList *list : OrderList::Iterate()) {
SlObject(list, GetOrderListDescription());
list->ReindexOrderList();
void FixPointers() const override
{
for (OrderList *list : OrderList::Iterate()) {
SlObject(list, GetOrderListDescription());
}
}
}
};
SaveLoadTable GetOrderBackupDescription()
{
@ -341,76 +202,72 @@ SaveLoadTable GetOrderBackupDescription()
SLE_VAR(OrderBackup, group, SLE_UINT16),
SLE_CONDVAR(OrderBackup, service_interval, SLE_FILE_U32 | SLE_VAR_U16, SL_MIN_VERSION, SLV_192),
SLE_CONDVAR(OrderBackup, service_interval, SLE_UINT16, SLV_192, SL_MAX_VERSION),
SLE_STR(OrderBackup, name, SLE_STR, 0),
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_192), // clone (2 bytes of pointer, i.e. garbage)
SLE_SSTR(OrderBackup, name, SLE_STR),
SLE_CONDREF(OrderBackup, clone, REF_VEHICLE, SLV_192, SL_MAX_VERSION),
SLE_VAR(OrderBackup, cur_real_order_index, SLE_VEHORDERID),
SLE_CONDVAR(OrderBackup, cur_implicit_order_index, SLE_VEHORDERID, SLV_176, SL_MAX_VERSION),
SLE_CONDVAR_X(OrderBackup, cur_timetable_order_index, SLE_VEHORDERID, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLE_EXTRA)),
SLE_VAR(OrderBackup, cur_real_order_index, SLE_FILE_U8 | SLE_VAR_U16),
SLE_CONDVAR(OrderBackup, cur_implicit_order_index, SLE_FILE_U8 | SLE_VAR_U16, SLV_176, SL_MAX_VERSION),
SLE_CONDVAR(OrderBackup, current_order_time, SLE_UINT32, SLV_176, SL_MAX_VERSION),
SLE_CONDVAR(OrderBackup, lateness_counter, SLE_INT32, SLV_176, SL_MAX_VERSION),
SLE_CONDVAR(OrderBackup, timetable_start, SLE_INT32, SLV_176, SL_MAX_VERSION),
SLE_CONDVAR_X(OrderBackup,timetable_start_subticks, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLES_START_TICKS, 2)),
SLE_CONDVAR(OrderBackup, vehicle_flags, SLE_FILE_U8 | SLE_VAR_U32, SLV_176, SLV_180),
SLE_CONDVAR_X(OrderBackup, vehicle_flags, SLE_FILE_U16 | SLE_VAR_U32, SLV_180, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_VEHICLE_FLAGS_EXTRA, 0, 0)),
SLE_CONDVAR_X(OrderBackup, vehicle_flags, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_VEHICLE_FLAGS_EXTRA, 1)),
SLE_CONDVAR(OrderBackup, vehicle_flags, SLE_FILE_U8 | SLE_VAR_U32, SLV_176, SLV_180),
SLE_CONDVAR(OrderBackup, vehicle_flags, SLE_FILE_U16 | SLE_VAR_U32, SLV_180, SL_MAX_VERSION),
SLE_REF(OrderBackup, orders, REF_ORDER),
SLE_CONDNULL_X(18, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SCHEDULED_DISPATCH, 2, 2)),
};
return _order_backup_desc;
}
void Save_BKOR()
{
/* We only save this when we're a network server
* as we want this information on our clients. For
* normal games this information isn't needed. */
if (!_networking || !_network_server) return;
for (OrderBackup *ob : OrderBackup::Iterate()) {
SlSetArrayIndex(ob->index);
SlAutolength([](void *data) {
OrderBackup *ob = static_cast<OrderBackup *>(data);
SlObject(ob, GetOrderBackupDescription());
SlWriteUint32((uint)ob->dispatch_schedules.size());
for (DispatchSchedule &ds : ob->dispatch_schedules) {
SlObject(&ds, GetDispatchScheduleDescription());
}
}, ob);
struct BKORChunkHandler : ChunkHandler {
BKORChunkHandler() : ChunkHandler('BKOR', CH_TABLE) {}
void Save() const override
{
const SaveLoadTable slt = GetOrderBackupDescription();
SlTableHeader(slt);
/* We only save this when we're a network server
* as we want this information on our clients. For
* normal games this information isn't needed. */
if (!_networking || !_network_server) return;
for (OrderBackup *ob : OrderBackup::Iterate()) {
SlSetArrayIndex(ob->index);
SlObject(ob, slt);
}
}
}
void Load_BKOR()
{
int index;
while ((index = SlIterateArray()) != -1) {
/* set num_orders to 0 so it's a valid OrderList */
OrderBackup *ob = new (index) OrderBackup();
SlObject(ob, GetOrderBackupDescription());
if (SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH, 3)) {
uint count = SlReadUint32();
ob->dispatch_schedules.resize(count);
for (DispatchSchedule &ds : ob->dispatch_schedules) {
SlObject(&ds, GetDispatchScheduleDescription());
}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(GetOrderBackupDescription(), _order_backup_sl_compat);
int index;
while ((index = SlIterateArray()) != -1) {
/* set num_orders to 0 so it's a valid OrderList */
OrderBackup *ob = new (index) OrderBackup();
SlObject(ob, slt);
if (ob->cur_real_order_index == 0xFF) ob->cur_real_order_index = INVALID_VEH_ORDER_ID;
if (ob->cur_implicit_order_index == 0xFF) ob->cur_implicit_order_index = INVALID_VEH_ORDER_ID;
}
}
}
static void Ptrs_BKOR()
{
for (OrderBackup *ob : OrderBackup::Iterate()) {
SlObject(ob, GetOrderBackupDescription());
void FixPointers() const override
{
for (OrderBackup *ob : OrderBackup::Iterate()) {
SlObject(ob, GetOrderBackupDescription());
}
}
}
};
static const ChunkHandler order_chunk_handlers[] = {
{ 'BKOR', Save_BKOR, Load_BKOR, Ptrs_BKOR, nullptr, CH_ARRAY },
{ 'ORDR', Save_ORDR, Load_ORDR, Ptrs_ORDR, nullptr, CH_ARRAY },
{ 'ORDL', Save_ORDL, Load_ORDL, Ptrs_ORDL, nullptr, CH_ARRAY },
{ 'ORDX', Save_ORDX, Load_ORDX, nullptr, nullptr, CH_SPARSE_ARRAY },
static const BKORChunkHandler BKOR;
static const ORDRChunkHandler ORDR;
static const ORDLChunkHandler ORDL;
static const ChunkHandlerRef order_chunk_handlers[] = {
BKOR,
ORDR,
ORDL,
};
extern const ChunkHandlerTable _order_chunk_handlers(order_chunk_handlers);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -7,18 +7,18 @@
/** @file settings_sl.cpp Handles the saveload part of the settings. */
#include "../../stdafx.h"
#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 "../settings_type.h"
#include "../settings_internal.h"
#include "../network/network.h"
#include "../fios.h"
#include "../../safeguards.h"
#include "../safeguards.h"
const SettingTable &GetSettingsTableInternal();

@ -8,13 +8,17 @@
/** @file signs_sl.cpp Code handling saving and loading of economy data */
#include "../stdafx.h"
#include "../signs_base.h"
#include "../fios.h"
#include "saveload.h"
#include "compat/signs_sl_compat.h"
#include "../signs_base.h"
#include "../fios.h"
#include "../safeguards.h"
namespace upstream_sl {
/** Description of a sign within the savegame. */
static const SaveLoad _sign_desc[] = {
SLE_CONDVAR(Sign, name, SLE_NAME, SL_MIN_VERSION, SLV_84),
@ -24,46 +28,54 @@ static const SaveLoad _sign_desc[] = {
SLE_CONDVAR(Sign, x, SLE_INT32, SLV_5, SL_MAX_VERSION),
SLE_CONDVAR(Sign, y, SLE_INT32, SLV_5, SL_MAX_VERSION),
SLE_CONDVAR(Sign, owner, SLE_UINT8, SLV_6, SL_MAX_VERSION),
SLE_CONDVAR_X(Sign, z, SLE_FILE_U8 | SLE_VAR_I32, SL_MIN_VERSION, SLV_164, SlXvFeatureTest(XSLFTO_AND, XSLFI_ZPOS_32_BIT, 0, 0)),
SLE_CONDVAR_X(Sign, z, SLE_INT32, SLV_164, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_OR, XSLFI_ZPOS_32_BIT)),
SLE_CONDVAR(Sign, z, SLE_FILE_U8 | SLE_VAR_I32, SL_MIN_VERSION, SLV_164),
SLE_CONDVAR(Sign, z, SLE_INT32, SLV_164, SL_MAX_VERSION),
};
/** Save all signs */
static void Save_SIGN()
{
for (Sign *si : Sign::Iterate()) {
SlSetArrayIndex(si->index);
SlObject(si, _sign_desc);
}
}
struct SIGNChunkHandler : ChunkHandler {
SIGNChunkHandler() : ChunkHandler('SIGN', CH_TABLE) {}
/** Load all signs */
static void Load_SIGN()
{
int index;
while ((index = SlIterateArray()) != -1) {
Sign *si = new (index) Sign();
SlObject(si, _sign_desc);
/* Before version 6.1, signs didn't have owner.
* Before version 83, invalid signs were determined by si->str == 0.
* Before version 103, owner could be a bankrupted company.
* - we can't use IsValidCompany() now, so this is fixed in AfterLoadGame()
* All signs that were saved are valid (including those with just 'Sign' and INVALID_OWNER).
* - so set owner to OWNER_NONE if needed (signs from pre-version 6.1 would be lost) */
if (IsSavegameVersionBefore(SLV_6, 1) || (IsSavegameVersionBefore(SLV_83) && si->owner == INVALID_OWNER)) {
si->owner = OWNER_NONE;
void Save() const override
{
SlTableHeader(_sign_desc);
for (Sign *si : Sign::Iterate()) {
SlSetArrayIndex(si->index);
SlObject(si, _sign_desc);
}
}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_sign_desc, _sign_sl_compat);
int index;
while ((index = SlIterateArray()) != -1) {
Sign *si = new (index) Sign();
SlObject(si, slt);
/* Before version 6.1, signs didn't have owner.
* Before version 83, invalid signs were determined by si->str == 0.
* Before version 103, owner could be a bankrupted company.
* - we can't use IsValidCompany() now, so this is fixed in AfterLoadGame()
* All signs that were saved are valid (including those with just 'Sign' and INVALID_OWNER).
* - so set owner to OWNER_NONE if needed (signs from pre-version 6.1 would be lost) */
if (IsSavegameVersionBefore(SLV_6, 1) || (IsSavegameVersionBefore(SLV_83) && si->owner == INVALID_OWNER)) {
si->owner = OWNER_NONE;
}
/* Signs placed in scenario editor shall now be OWNER_DEITY */
if (IsSavegameVersionBefore(SLV_171) && si->owner == OWNER_NONE && _file_to_saveload.abstract_ftype == FT_SCENARIO) {
si->owner = OWNER_DEITY;
/* Signs placed in scenario editor shall now be OWNER_DEITY */
if (IsSavegameVersionBefore(SLV_171) && si->owner == OWNER_NONE && SaveLoadFileTypeIsScenario()) {
si->owner = OWNER_DEITY;
}
}
}
}
};
/** Chunk handlers related to signs. */
static const ChunkHandler sign_chunk_handlers[] = {
{ 'SIGN', Save_SIGN, Load_SIGN, nullptr, nullptr, CH_ARRAY },
static const SIGNChunkHandler SIGN;
static const ChunkHandlerRef sign_chunk_handlers[] = {
SIGN,
};
extern const ChunkHandlerTable _sign_chunk_handlers(sign_chunk_handlers);
}

File diff suppressed because it is too large Load Diff

@ -8,11 +8,16 @@
/** @file storage_sl.cpp Code handling saving and loading of persistent storages. */
#include "../stdafx.h"
#include "../newgrf_storage.h"
#include "saveload.h"
#include "compat/storage_sl_compat.h"
#include "../newgrf_storage.h"
#include "../safeguards.h"
namespace upstream_sl {
/** Description of the data to save and load in #PersistentStorage. */
static const SaveLoad _storage_desc[] = {
SLE_CONDVAR(PersistentStorage, grfid, SLE_UINT32, SLV_6, SL_MAX_VERSION),
@ -20,32 +25,41 @@ static const SaveLoad _storage_desc[] = {
SLE_CONDARR(PersistentStorage, storage, SLE_UINT32, 256, SLV_EXTEND_PERSISTENT_STORAGE, SL_MAX_VERSION),
};
/** Load persistent storage data. */
static void Load_PSAC()
{
int index;
/** Persistent storage data. */
struct PSACChunkHandler : ChunkHandler {
PSACChunkHandler() : ChunkHandler('PSAC', CH_TABLE) {}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_storage_desc, _storage_sl_compat);
int index;
while ((index = SlIterateArray()) != -1) {
assert(PersistentStorage::CanAllocateItem());
PersistentStorage *ps = new (index) PersistentStorage(0, 0, 0);
SlObject(ps, _storage_desc);
while ((index = SlIterateArray()) != -1) {
assert(PersistentStorage::CanAllocateItem());
PersistentStorage *ps = new (index) PersistentStorage(0, 0, 0);
SlObject(ps, slt);
}
}
}
/** Save persistent storage data. */
static void Save_PSAC()
{
/* Write the industries */
for (PersistentStorage *ps : PersistentStorage::Iterate()) {
ps->ClearChanges();
SlSetArrayIndex(ps->index);
SlObject(ps, _storage_desc);
void Save() const override
{
SlTableHeader(_storage_desc);
/* Write the industries */
for (PersistentStorage *ps : PersistentStorage::Iterate()) {
ps->ClearChanges();
SlSetArrayIndex(ps->index);
SlObject(ps, _storage_desc);
}
}
}
};
/** Chunk handler for persistent storages. */
static const ChunkHandler persistent_storage_chunk_handlers[] = {
{ 'PSAC', Save_PSAC, Load_PSAC, nullptr, nullptr, CH_ARRAY },
static const PSACChunkHandler PSAC;
static const ChunkHandlerRef persistent_storage_chunk_handlers[] = {
PSAC,
};
extern const ChunkHandlerTable _persistent_storage_chunk_handlers(persistent_storage_chunk_handlers);
}

@ -8,23 +8,15 @@
/** @file story_sl.cpp Code handling saving and loading of story pages */
#include "../stdafx.h"
#include "../story_base.h"
#include "saveload.h"
#include "compat/story_sl_compat.h"
#include "../story_base.h"
#include "../safeguards.h"
/** Called after load to trash broken pages. */
void AfterLoadStoryBook()
{
if (IsSavegameVersionBefore(SLV_185)) {
/* Trash all story pages and page elements because
* they were saved with wrong data types.
*/
_story_page_element_pool.CleanPool();
_story_page_pool.CleanPool();
}
}
namespace upstream_sl {
static const SaveLoad _story_page_elements_desc[] = {
SLE_CONDVAR(StoryPageElement, sort_value, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_185),
@ -36,30 +28,38 @@ static const SaveLoad _story_page_elements_desc[] = {
SLE_SSTR(StoryPageElement, text, SLE_STR | SLF_ALLOW_CONTROL),
};
static void Save_STORY_PAGE_ELEMENT()
{
for (StoryPageElement *s : StoryPageElement::Iterate()) {
SlSetArrayIndex(s->index);
SlObject(s, _story_page_elements_desc);
struct STPEChunkHandler : ChunkHandler {
STPEChunkHandler() : ChunkHandler('STPE', CH_TABLE) {}
void Save() const override
{
SlTableHeader(_story_page_elements_desc);
for (StoryPageElement *s : StoryPageElement::Iterate()) {
SlSetArrayIndex(s->index);
SlObject(s, _story_page_elements_desc);
}
}
}
static void Load_STORY_PAGE_ELEMENT()
{
int index;
uint32 max_sort_value = 0;
while ((index = SlIterateArray()) != -1) {
StoryPageElement *s = new (index) StoryPageElement();
SlObject(s, _story_page_elements_desc);
if (s->sort_value > max_sort_value) {
max_sort_value = s->sort_value;
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_story_page_elements_desc, _story_page_elements_sl_compat);
int index;
uint32 max_sort_value = 0;
while ((index = SlIterateArray()) != -1) {
StoryPageElement *s = new (index) StoryPageElement();
SlObject(s, slt);
if (s->sort_value > max_sort_value) {
max_sort_value = s->sort_value;
}
}
/* Update the next sort value, so that the next
* created page is shown after all existing pages.
*/
_story_page_element_next_sort_value = max_sort_value + 1;
}
/* Update the next sort value, so that the next
* created page is shown after all existing pages.
*/
_story_page_element_next_sort_value = max_sort_value + 1;
}
};
static const SaveLoad _story_pages_desc[] = {
SLE_CONDVAR(StoryPage, sort_value, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_185),
@ -70,34 +70,46 @@ static const SaveLoad _story_pages_desc[] = {
SLE_SSTR(StoryPage, title, SLE_STR | SLF_ALLOW_CONTROL),
};
static void Save_STORY_PAGE()
{
for (StoryPage *s : StoryPage::Iterate()) {
SlSetArrayIndex(s->index);
SlObject(s, _story_pages_desc);
struct STPAChunkHandler : ChunkHandler {
STPAChunkHandler() : ChunkHandler('STPA', CH_TABLE) {}
void Save() const override
{
SlTableHeader(_story_pages_desc);
for (StoryPage *s : StoryPage::Iterate()) {
SlSetArrayIndex(s->index);
SlObject(s, _story_pages_desc);
}
}
}
static void Load_STORY_PAGE()
{
int index;
uint32 max_sort_value = 0;
while ((index = SlIterateArray()) != -1) {
StoryPage *s = new (index) StoryPage();
SlObject(s, _story_pages_desc);
if (s->sort_value > max_sort_value) {
max_sort_value = s->sort_value;
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_story_pages_desc, _story_pages_sl_compat);
int index;
uint32 max_sort_value = 0;
while ((index = SlIterateArray()) != -1) {
StoryPage *s = new (index) StoryPage();
SlObject(s, slt);
if (s->sort_value > max_sort_value) {
max_sort_value = s->sort_value;
}
}
/* Update the next sort value, so that the next
* created page is shown after all existing pages.
*/
_story_page_next_sort_value = max_sort_value + 1;
}
/* Update the next sort value, so that the next
* created page is shown after all existing pages.
*/
_story_page_next_sort_value = max_sort_value + 1;
}
};
static const ChunkHandler story_page_chunk_handlers[] = {
{ 'STPE', Save_STORY_PAGE_ELEMENT, Load_STORY_PAGE_ELEMENT, nullptr, nullptr, CH_ARRAY },
{ 'STPA', Save_STORY_PAGE, Load_STORY_PAGE, nullptr, nullptr, CH_ARRAY },
static const STPEChunkHandler STPE;
static const STPAChunkHandler STPA;
static const ChunkHandlerRef story_page_chunk_handlers[] = {
STPE,
STPA,
};
extern const ChunkHandlerTable _story_page_chunk_handlers(story_page_chunk_handlers);
}

@ -8,12 +8,16 @@
/** @file subsidy_sl.cpp Code handling saving and loading of subsidies */
#include "../stdafx.h"
#include "../subsidy_base.h"
#include "saveload.h"
#include "compat/subsidy_sl_compat.h"
#include "../subsidy_base.h"
#include "../safeguards.h"
namespace upstream_sl {
static const SaveLoad _subsidies_desc[] = {
SLE_VAR(Subsidy, cargo_type, SLE_UINT8),
SLE_CONDVAR(Subsidy, remaining, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_CUSTOM_SUBSIDY_DURATION),
@ -27,25 +31,36 @@ static const SaveLoad _subsidies_desc[] = {
SLE_CONDVAR(Subsidy, dst, SLE_UINT16, SLV_5, SL_MAX_VERSION),
};
static void Save_SUBS()
{
for (Subsidy *s : Subsidy::Iterate()) {
SlSetArrayIndex(s->index);
SlObject(s, _subsidies_desc);
struct SUBSChunkHandler : ChunkHandler {
SUBSChunkHandler() : ChunkHandler('SUBS', CH_TABLE) {}
void Save() const override
{
SlTableHeader(_subsidies_desc);
for (Subsidy *s : Subsidy::Iterate()) {
SlSetArrayIndex(s->index);
SlObject(s, _subsidies_desc);
}
}
}
static void Load_SUBS()
{
int index;
while ((index = SlIterateArray()) != -1) {
Subsidy *s = new (index) Subsidy();
SlObject(s, _subsidies_desc);
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_subsidies_desc, _subsidies_sl_compat);
int index;
while ((index = SlIterateArray()) != -1) {
Subsidy *s = new (index) Subsidy();
SlObject(s, slt);
}
}
}
};
static const ChunkHandler subsidy_chunk_handlers[] = {
{ 'SUBS', Save_SUBS, Load_SUBS, nullptr, nullptr, CH_ARRAY },
static const SUBSChunkHandler SUBS;
static const ChunkHandlerRef subsidy_chunk_handlers[] = {
SUBS,
};
extern const ChunkHandlerTable _subsidy_chunk_handlers(subsidy_chunk_handlers);
}

@ -8,238 +8,169 @@
/** @file town_sl.cpp Code handling saving and loading of towns and houses */
#include "../stdafx.h"
#include "saveload.h"
#include "compat/town_sl_compat.h"
#include "newgrf_sl.h"
#include "../newgrf_house.h"
#include "../town.h"
#include "../landscape.h"
#include "../subsidy_func.h"
#include "../strings_func.h"
#include "../network/network.h"
#include "saveload.h"
#include "newgrf_sl.h"
#include "../tilematrix_type.hpp"
#include "../safeguards.h"
static bool _town_zone_radii_no_update = false;
namespace upstream_sl {
extern bool IsGetTownZonesCallbackHandlerPresent();
typedef TileMatrix<CargoTypes, 4> AcceptanceMatrix;
HouseID SLGetCleanHouseType(TileIndex t, bool old_map_position)
{
if (old_map_position && SlXvIsFeatureMissing(XSLFI_MORE_HOUSES)) {
return _m[t].m4 | (GB(_m[t].m3, 6, 1) << 8);
} else {
return GetCleanHouseType(t);
class SlTownSupplied : public DefaultSaveLoadHandler<SlTownSupplied, Town> {
public:
inline static const SaveLoad description[] = {
SLE_CONDVAR(TransportedCargoStat<uint32>, old_max, SLE_UINT32, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint32>, new_max, SLE_UINT32, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint32>, old_act, SLE_UINT32, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint32>, new_act, SLE_UINT32, SLV_165, SL_MAX_VERSION),
};
inline const static SaveLoadCompatTable compat_description = _town_supplied_sl_compat;
/**
* Get the number of cargoes used by this savegame version.
* @return The number of cargoes used by this savegame version.
*/
size_t GetNumCargo() const
{
if (IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES)) return 32;
if (IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) return NUM_CARGO;
/* Read from the savegame how long the list is. */
return SlGetStructListLength(NUM_CARGO);
}
void Save(Town *t) const override
{
SlSetStructListLength(NUM_CARGO);
for (CargoID i = 0; i < NUM_CARGO; i++) {
SlObject(&t->supplied[i], this->GetDescription());
}
}
}
/**
* Rebuild all the cached variables of towns.
*/
void RebuildTownCaches(bool cargo_update_required, bool old_map_position)
{
InitializeBuildingCounts();
RebuildTownKdtree();
/* Reset town population and num_houses */
for (Town *town : Town::Iterate()) {
town->cache.population = 0;
town->cache.num_houses = 0;
void Load(Town *t) const override
{
size_t num_cargo = this->GetNumCargo();
for (size_t i = 0; i < num_cargo; i++) {
SlObject(&t->supplied[i], this->GetLoadDescription());
}
}
};
for (TileIndex t = 0; t < MapSize(); t++) {
if (!IsTileType(t, MP_HOUSE)) continue;
HouseID house_id = GetTranslatedHouseID(SLGetCleanHouseType(t, old_map_position));
Town *town = Town::GetByTile(t);
IncreaseBuildingCount(town, house_id);
if (IsHouseCompleted(t)) town->cache.population += HouseSpec::Get(house_id)->population;
/* Increase the number of houses for every house, but only once. */
if (GetHouseNorthPart(house_id) == 0) town->cache.num_houses++;
}
class SlTownReceived : public DefaultSaveLoadHandler<SlTownReceived, Town> {
public:
inline static const SaveLoad description[] = {
SLE_CONDVAR(TransportedCargoStat<uint16>, old_max, SLE_UINT16, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint16>, new_max, SLE_UINT16, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint16>, old_act, SLE_UINT16, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint16>, new_act, SLE_UINT16, SLV_165, SL_MAX_VERSION),
};
inline const static SaveLoadCompatTable compat_description = _town_received_sl_compat;
if (!_town_zone_radii_no_update) {
/* Update the population and num_house dependent values */
for (Town *town : Town::Iterate()) {
UpdateTownRadius(town);
void Save(Town *t) const override
{
SlSetStructListLength(NUM_TE);
for (size_t i = TE_BEGIN; i < TE_END; i++) {
SlObject(&t->received[i], this->GetDescription());
}
}
}
static void CheckMultiTileHouseTypes(bool &cargo_update_required, bool old_map_position, bool translate_house_types)
{
auto get_clean_house_type = [&](TileIndex t) -> HouseID {
HouseID type = SLGetCleanHouseType(t, old_map_position);
if (translate_house_types) type = GetTranslatedHouseID(type);
return type;
};
/* Check for cases when a NewGRF has set a wrong house substitute type. */
for (TileIndex t = 0; t < MapSize(); t++) {
if (!IsTileType(t, MP_HOUSE)) continue;
HouseID house_type = get_clean_house_type(t);
TileIndex north_tile = t + GetHouseNorthPart(house_type); // modifies 'house_type'!
if (t == north_tile) {
const HouseSpec *hs = HouseSpec::Get(house_type);
bool valid_house = true;
if (hs->building_flags & TILE_SIZE_2x1) {
TileIndex tile = t + TileDiffXY(1, 0);
if (!IsTileType(tile, MP_HOUSE) || get_clean_house_type(tile) != house_type + 1) valid_house = false;
} else if (hs->building_flags & TILE_SIZE_1x2) {
TileIndex tile = t + TileDiffXY(0, 1);
if (!IsTileType(tile, MP_HOUSE) || get_clean_house_type(tile) != house_type + 1) valid_house = false;
} else if (hs->building_flags & TILE_SIZE_2x2) {
TileIndex tile = t + TileDiffXY(0, 1);
if (!IsTileType(tile, MP_HOUSE) || get_clean_house_type(tile) != house_type + 1) valid_house = false;
tile = t + TileDiffXY(1, 0);
if (!IsTileType(tile, MP_HOUSE) || get_clean_house_type(tile) != house_type + 2) valid_house = false;
tile = t + TileDiffXY(1, 1);
if (!IsTileType(tile, MP_HOUSE) || get_clean_house_type(tile) != house_type + 3) valid_house = false;
}
/* If not all tiles of this house are present remove the house.
* The other tiles will get removed later in this loop because
* their north tile is not the correct type anymore. */
if (!valid_house) {
DoClearSquare(t);
cargo_update_required = true;
}
} else if (!IsTileType(north_tile, MP_HOUSE) || get_clean_house_type(north_tile) != house_type) {
/* This tile should be part of a multi-tile building but the
* north tile of this house isn't on the map. */
DoClearSquare(t);
cargo_update_required = true;
void Load(Town *t) const override
{
size_t length = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? (size_t)TE_END : SlGetStructListLength(TE_END);
for (size_t i = 0; i < length; i++) {
SlObject(&t->received[i], this->GetLoadDescription());
}
}
}
};
/**
* Check and update town and house values.
*
* Checked are the HouseIDs. Updated are the
* town population the number of houses per
* town, the town radius and the max passengers
* of the town.
*/
void UpdateHousesAndTowns(bool cargo_update_required, bool old_map_position)
{
auto get_clean_house_type = [&](TileIndex t) -> HouseID {
return SLGetCleanHouseType(t, old_map_position);
class SlTownAcceptanceMatrix : public DefaultSaveLoadHandler<SlTownAcceptanceMatrix, Town> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(AcceptanceMatrix, area.tile, SLE_UINT32),
SLE_VAR(AcceptanceMatrix, area.w, SLE_UINT16),
SLE_VAR(AcceptanceMatrix, area.h, SLE_UINT16),
};
for (TileIndex t = 0; t < MapSize(); t++) {
if (!IsTileType(t, MP_HOUSE)) continue;
HouseID house_id = get_clean_house_type(t);
if (!HouseSpec::Get(house_id)->enabled && house_id >= NEW_HOUSE_OFFSET) {
/* The specs for this type of house are not available any more, so
* replace it with the substitute original house type. */
house_id = _house_mngr.GetSubstituteID(house_id);
if (old_map_position && SlXvIsFeatureMissing(XSLFI_MORE_HOUSES)) {
_m[t].m4 = GB(house_id, 0, 8);
SB(_m[t].m3, 6, 1, GB(house_id, 8, 1));
} else {
SetHouseType(t, house_id);
}
cargo_update_required = true;
inline const static SaveLoadCompatTable compat_description = _town_acceptance_matrix_sl_compat;
void Load(Town *t) const override
{
/* Discard now unused acceptance matrix. */
AcceptanceMatrix dummy;
SlObject(&dummy, this->GetLoadDescription());
if (dummy.area.w != 0) {
uint arr_len = dummy.area.w / AcceptanceMatrix::GRID * dummy.area.h / AcceptanceMatrix::GRID;
SlSkipBytes(4 * arr_len);
}
}
};
CheckMultiTileHouseTypes(cargo_update_required, old_map_position, false);
if (cargo_update_required || SlXvIsFeatureMissing(XSLFI_MORE_HOUSES, 2)) CheckMultiTileHouseTypes(cargo_update_required, old_map_position, true);
RebuildTownCaches(cargo_update_required, old_map_position);
}
/** Save and load of towns. */
static const SaveLoad _town_desc[] = {
SLE_CONDVAR(Town, xy, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6),
SLE_CONDVAR(Town, xy, SLE_UINT32, SLV_6, SL_MAX_VERSION),
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_3), ///< population, no longer in use
SLE_CONDNULL(4, SLV_3, SLV_85), ///< population, no longer in use
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_92), ///< num_houses, no longer in use
SLE_CONDVAR(Town, townnamegrfid, SLE_UINT32, SLV_66, SL_MAX_VERSION),
SLE_VAR(Town, townnametype, SLE_UINT16),
SLE_VAR(Town, townnameparts, SLE_UINT32),
SLE_CONDSTR(Town, name, SLE_STR | SLF_ALLOW_CONTROL, 0, SLV_84, SL_MAX_VERSION),
SLE_VAR(Town, flags, SLE_UINT8),
SLE_CONDVAR_X(Town, church_count, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TOWN_MULTI_BUILDING)),
SLE_CONDVAR_X(Town, stadium_count, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TOWN_MULTI_BUILDING)),
SLE_CONDVAR(Town, statues, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_104),
SLE_CONDVAR(Town, statues, SLE_UINT16, SLV_104, SL_MAX_VERSION),
SLE_CONDNULL(1, SL_MIN_VERSION, SLV_2), ///< sort_index, no longer in use
SLE_CONDVAR(Town, have_ratings, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_104),
SLE_CONDVAR(Town, have_ratings, SLE_UINT16, SLV_104, SL_MAX_VERSION),
SLE_CONDARR(Town, ratings, SLE_INT16, 8, SL_MIN_VERSION, SLV_104),
SLE_CONDARR(Town, ratings, SLE_INT16, MAX_COMPANIES, SLV_104, SL_MAX_VERSION),
SLE_CONDNULL_X(MAX_COMPANIES, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SPRINGPP)),
/* failed bribe attempts are stored since savegame format 4 */
SLE_CONDARR(Town, unwanted, SLE_INT8, 8, SLV_4, SLV_104),
SLE_CONDARR(Town, unwanted, SLE_INT8, MAX_COMPANIES, SLV_104, SL_MAX_VERSION),
SLE_CONDVAR(Town, supplied[CT_PASSENGERS].old_max, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
SLE_CONDVAR(Town, supplied[CT_MAIL].old_max, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
SLE_CONDVAR(Town, supplied[CT_PASSENGERS].new_max, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
SLE_CONDVAR(Town, supplied[CT_MAIL].new_max, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
SLE_CONDVAR(Town, supplied[CT_PASSENGERS].old_act, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
SLE_CONDVAR(Town, supplied[CT_MAIL].old_act, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
SLE_CONDVAR(Town, supplied[CT_PASSENGERS].new_act, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
SLE_CONDVAR(Town, supplied[CT_MAIL].new_act, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)),
SLE_CONDVAR(Town, supplied[CT_PASSENGERS].old_max, SLE_UINT32, SLV_9, SLV_165),
SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)),
SLE_CONDVAR(Town, supplied[CT_MAIL].old_max, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
SLE_CONDVAR(Town, supplied[CT_MAIL].old_max, SLE_UINT32, SLV_9, SLV_165),
SLE_CONDNULL_X(8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)),
SLE_CONDVAR(Town, supplied[CT_PASSENGERS].new_max, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
SLE_CONDVAR(Town, supplied[CT_PASSENGERS].new_max, SLE_UINT32, SLV_9, SLV_165),
SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)),
SLE_CONDVAR(Town, supplied[CT_MAIL].new_max, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
SLE_CONDVAR(Town, supplied[CT_MAIL].new_max, SLE_UINT32, SLV_9, SLV_165),
SLE_CONDNULL_X(8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)),
SLE_CONDVAR(Town, supplied[CT_PASSENGERS].old_act, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
SLE_CONDVAR(Town, supplied[CT_PASSENGERS].old_act, SLE_UINT32, SLV_9, SLV_165),
SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)),
SLE_CONDVAR(Town, supplied[CT_MAIL].old_act, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
SLE_CONDVAR(Town, supplied[CT_MAIL].old_act, SLE_UINT32, SLV_9, SLV_165),
SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)),
SLE_CONDVAR(Town, supplied[CT_PASSENGERS].new_act, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
SLE_CONDVAR(Town, supplied[CT_PASSENGERS].new_act, SLE_UINT32, SLV_9, SLV_165),
SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)),
SLE_CONDVAR(Town, supplied[CT_MAIL].new_act, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
SLE_CONDVAR(Town, supplied[CT_MAIL].new_act, SLE_UINT32, SLV_9, SLV_165),
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_164), ///< pct_pass_transported / pct_mail_transported, now computed on the fly
SLE_CONDNULL_X(3, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)),
SLE_CONDVAR(Town, received[TE_FOOD].old_act, SLE_UINT16, SL_MIN_VERSION, SLV_165),
SLE_CONDVAR(Town, received[TE_WATER].old_act, SLE_UINT16, SL_MIN_VERSION, SLV_165),
SLE_CONDNULL_X(2, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)),
SLE_CONDVAR(Town, received[TE_FOOD].new_act, SLE_UINT16, SL_MIN_VERSION, SLV_165),
SLE_CONDVAR(Town, received[TE_WATER].new_act, SLE_UINT16, SL_MIN_VERSION, SLV_165),
SLE_CONDNULL_X(2, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)),
SLE_CONDARR(Town, goal, SLE_UINT32, NUM_TE, SLV_165, SL_MAX_VERSION),
SLE_CONDSSTR(Town, text, SLE_STR | SLF_ALLOW_CONTROL, SLV_168, SL_MAX_VERSION),
SLE_CONDVAR(Town, time_until_rebuild, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_54),
SLE_CONDVAR(Town, grow_counter, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_54),
SLE_CONDVAR(Town, growth_rate, SLE_FILE_U8 | SLE_VAR_I16, SL_MIN_VERSION, SLV_54),
SLE_CONDNULL_X(2, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP)),
SLE_CONDVAR(Town, time_until_rebuild, SLE_UINT16, SLV_54, SL_MAX_VERSION),
SLE_CONDNULL_X(2, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP, SL_JOKER_1_26)),
SLE_CONDVAR(Town, grow_counter, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_54),
SLE_CONDVAR(Town, grow_counter, SLE_UINT16, SLV_54, SL_MAX_VERSION),
SLE_CONDVAR(Town, growth_rate, SLE_FILE_U8 | SLE_VAR_I16, SL_MIN_VERSION, SLV_54),
SLE_CONDVAR(Town, growth_rate, SLE_FILE_I16 | SLE_VAR_U16, SLV_54, SLV_165),
SLE_CONDNULL_X(2, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP, SL_JOKER_1_26)),
SLE_CONDVAR(Town, growth_rate, SLE_UINT16, SLV_165, SL_MAX_VERSION),
SLE_VAR(Town, fund_buildings_months, SLE_UINT8),
SLE_VAR(Town, road_build_months, SLE_UINT8),
SLE_CONDVAR(Town, exclusivity, SLE_UINT8, SLV_2, SL_MAX_VERSION),
SLE_CONDNULL_X(1, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)),
SLE_CONDVAR(Town, exclusive_counter, SLE_UINT8, SLV_2, SL_MAX_VERSION),
SLE_CONDVAR(Town, larger_town, SLE_BOOL, SLV_56, SL_MAX_VERSION),
@ -247,193 +178,61 @@ static const SaveLoad _town_desc[] = {
SLE_CONDREFLIST(Town, psa_list, REF_STORAGE, SLV_161, SL_MAX_VERSION),
SLE_CONDNULL(4, SLV_166, SLV_EXTEND_CARGOTYPES), ///< cargo_produced, no longer in use
SLE_CONDNULL(8, SLV_EXTEND_CARGOTYPES, SLV_REMOVE_TOWN_CARGO_CACHE), ///< cargo_produced, no longer in use
SLE_CONDNULL(30, SLV_2, SLV_REMOVE_TOWN_CARGO_CACHE), ///< old reserved space
SLE_CONDVAR_X(Town, override_flags, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TOWN_SETTING_OVERRIDE)),
SLE_CONDVAR_X(Town, override_values, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TOWN_SETTING_OVERRIDE)),
SLE_CONDVAR_X(Town, build_tunnels, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TOWN_SETTING_OVERRIDE)),
SLE_CONDVAR_X(Town, max_road_slope, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TOWN_SETTING_OVERRIDE)),
};
static const SaveLoad _town_supplied_desc[] = {
SLE_CONDVAR(TransportedCargoStat<uint32>, old_max, SLE_UINT32, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint32>, new_max, SLE_UINT32, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint32>, old_act, SLE_UINT32, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint32>, new_act, SLE_UINT32, SLV_165, SL_MAX_VERSION),
};
static const SaveLoad _town_received_desc[] = {
SLE_CONDVAR(TransportedCargoStat<uint16>, old_max, SLE_UINT16, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint16>, new_max, SLE_UINT16, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint16>, old_act, SLE_UINT16, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint16>, new_act, SLE_UINT16, SLV_165, SL_MAX_VERSION),
SLEG_CONDSTRUCTLIST("supplied", SlTownSupplied, SLV_165, SL_MAX_VERSION),
SLEG_CONDSTRUCTLIST("received", SlTownReceived, SLV_165, SL_MAX_VERSION),
SLEG_CONDSTRUCTLIST("acceptance_matrix", SlTownAcceptanceMatrix, SLV_166, SLV_REMOVE_TOWN_CARGO_CACHE),
};
static const SaveLoad _town_received_desc_spp[] = {
SLE_CONDVAR(TransportedCargoStat<uint16>, old_max, SLE_FILE_U32 | SLE_VAR_U16, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint16>, new_max, SLE_FILE_U32 | SLE_VAR_U16, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint16>, old_act, SLE_FILE_U32 | SLE_VAR_U16, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint16>, new_act, SLE_FILE_U32 | SLE_VAR_U16, SLV_165, SL_MAX_VERSION),
struct HIDSChunkHandler : NewGRFMappingChunkHandler {
HIDSChunkHandler() : NewGRFMappingChunkHandler('HIDS', _house_mngr) {}
};
std::vector<SaveLoad> _filtered_town_desc;
std::vector<SaveLoad> _filtered_town_supplied_desc;
std::vector<SaveLoad> _filtered_town_received_desc;
static void SetupDescs_TOWN()
{
_filtered_town_desc = SlFilterObject(_town_desc);
_filtered_town_supplied_desc = SlFilterObject(_town_supplied_desc);
_filtered_town_received_desc = SlFilterObject(_town_received_desc);
}
static void Save_HIDS()
{
Save_NewGRFMapping(_house_mngr);
}
static void Load_HIDS()
{
Load_NewGRFMapping(_house_mngr);
}
static void RealSave_Town(Town *t)
{
SlObjectSaveFiltered(t, _filtered_town_desc);
for (CargoID i = 0; i < NUM_CARGO; i++) {
SlObjectSaveFiltered(&t->supplied[i], _filtered_town_supplied_desc);
}
for (int i = TE_BEGIN; i < NUM_TE; i++) {
SlObjectSaveFiltered(&t->received[i], _filtered_town_received_desc);
}
}
static void Save_TOWN()
{
SetupDescs_TOWN();
for (Town *t : Town::Iterate()) {
SlSetArrayIndex(t->index);
SlAutolength((AutolengthProc*)RealSave_Town, t);
}
}
static void Load_TOWN()
{
SetupDescs_TOWN();
int index;
uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO;
while ((index = SlIterateArray()) != -1) {
Town *t = new (index) Town();
SlObjectLoadFiltered(t, _filtered_town_desc);
for (CargoID i = 0; i < num_cargo; i++) {
SlObjectLoadFiltered(&t->supplied[i], _filtered_town_supplied_desc);
}
if (SlXvIsFeaturePresent(XSLFI_SPRINGPP)) {
for (int i = TE_BEGIN; i < NUM_TE; i++) {
SlObject(&t->received[i], _town_received_desc_spp);
}
} else {
for (int i = TE_BEGIN; i < NUM_TE; i++) {
SlObjectLoadFiltered(&t->received[i], _filtered_town_received_desc);
}
}
struct CITYChunkHandler : ChunkHandler {
CITYChunkHandler() : ChunkHandler('CITY', CH_TABLE) {}
if (t->townnamegrfid == 0 && !IsInsideMM(t->townnametype, SPECSTR_TOWNNAME_START, SPECSTR_TOWNNAME_LAST + 1) && GetStringTab(t->townnametype) != TEXT_TAB_OLD_CUSTOM) {
SlErrorCorrupt("Invalid town name generator");
}
void Save() const override
{
SlTableHeader(_town_desc);
if ((!IsSavegameVersionBefore(SLV_166) && IsSavegameVersionBefore(SLV_REMOVE_TOWN_CARGO_CACHE)) || SlXvIsFeaturePresent(XSLFI_TOWN_CARGO_MATRIX)) {
SlSkipBytes(4); // tile
uint16 w = SlReadUint16();
uint16 h = SlReadUint16();
if (w != 0) {
SlSkipBytes((SlXvIsFeaturePresent(XSLFI_TOWN_CARGO_MATRIX) ? 8 : 4) * ((uint)(w / 4) * (uint)(h / 4)));
}
for (Town *t : Town::Iterate()) {
SlSetArrayIndex(t->index);
SlObject(t, _town_desc);
}
}
}
/** Fix pointers when loading town data. */
static void Ptrs_TOWN()
{
/* Don't run when savegame version lower than 161. */
if (IsSavegameVersionBefore(SLV_161)) return;
SetupDescs_TOWN();
for (Town *t : Town::Iterate()) {
SlObjectPtrOrNullFiltered(t, _filtered_town_desc);
}
}
void SlResetTNNC()
{
_town_zone_radii_no_update = false;
}
void Save_TNNC()
{
assert(_sl_xv_feature_versions[XSLFI_TNNC_CHUNK] != 0);
if (!IsNetworkServerSave() || !IsGetTownZonesCallbackHandlerPresent()) {
SlSetLength(0);
return;
}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_town_desc, _town_sl_compat);
SlSetLength(4 + (Town::GetNumItems() * (1 + lengthof(TownCache::squared_town_zone_radius)) * 4));
int index;
SlWriteUint32((uint32)Town::GetNumItems());
while ((index = SlIterateArray()) != -1) {
Town *t = new (index) Town();
SlObject(t, slt);
for (const Town *t : Town::Iterate()) {
SlWriteUint32(t->index);
for (uint i = 0; i < lengthof(TownCache::squared_town_zone_radius); i++) {
SlWriteUint32(t->cache.squared_town_zone_radius[i]);
if (t->townnamegrfid == 0 && !IsInsideMM(t->townnametype, SPECSTR_TOWNNAME_START, SPECSTR_TOWNNAME_LAST + 1) && GetStringTab(t->townnametype) != TEXT_TAB_OLD_CUSTOM) {
SlErrorCorrupt("Invalid town name generator");
}
}
}
}
void Load_TNNC()
{
if (SlGetFieldLength() == 0) return;
if (!_networking || _network_server) {
SlSkipBytes(SlGetFieldLength());
return;
}
void FixPointers() const override
{
if (IsSavegameVersionBefore(SLV_161)) return;
_town_zone_radii_no_update = true;
const uint32 count = SlReadUint32();
for (uint32 idx = 0; idx < count; idx++) {
Town *t = Town::Get(SlReadUint32());
for (uint i = 0; i < lengthof(TownCache::squared_town_zone_radius); i++) {
t->cache.squared_town_zone_radius[i] = SlReadUint32();
for (Town *t : Town::Iterate()) {
SlObject(t, _town_desc);
}
}
}
static ChunkSaveLoadSpecialOpResult Special_TNNC(uint32 chunk_id, ChunkSaveLoadSpecialOp op)
{
switch (op) {
case CSLSO_SHOULD_SAVE_CHUNK:
if (_sl_xv_feature_versions[XSLFI_TNNC_CHUNK] == 0) return CSLSOR_DONT_SAVE_CHUNK;
break;
default:
break;
}
return CSLSOR_NONE;
}
};
/** Chunk handler for towns. */
static const ChunkHandler town_chunk_handlers[] = {
{ 'HIDS', Save_HIDS, Load_HIDS, nullptr, nullptr, CH_ARRAY },
{ 'CITY', Save_TOWN, Load_TOWN, Ptrs_TOWN, nullptr, CH_ARRAY },
{ 'TNNC', Save_TNNC, Load_TNNC, nullptr, nullptr, CH_RIFF, Special_TNNC },
static const HIDSChunkHandler HIDS;
static const CITYChunkHandler CITY;
static const ChunkHandlerRef town_chunk_handlers[] = {
HIDS,
CITY,
};
extern const ChunkHandlerTable _town_chunk_handlers(town_chunk_handlers);
}

@ -1,140 +0,0 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
/** @file ai_sl.cpp Handles the saveload part of the AIs */
#include "../../stdafx.h"
#include "../../debug.h"
#include "saveload.h"
#include "compat/ai_sl_compat.h"
#include "../../company_base.h"
#include "../../string_func.h"
#include "../../ai/ai.hpp"
#include "../../ai/ai_config.hpp"
#include "../../network/network.h"
#include "../../ai/ai_instance.hpp"
#include "../../safeguards.h"
namespace upstream_sl {
static std::string _ai_saveload_name;
static int _ai_saveload_version;
static std::string _ai_saveload_settings;
static bool _ai_saveload_is_random;
static const SaveLoad _ai_company_desc[] = {
SLEG_SSTR("name", _ai_saveload_name, SLE_STR),
SLEG_SSTR("settings", _ai_saveload_settings, SLE_STR),
SLEG_CONDVAR("version", _ai_saveload_version, SLE_UINT32, SLV_108, SL_MAX_VERSION),
SLEG_CONDVAR("is_random", _ai_saveload_is_random, SLE_BOOL, SLV_136, SL_MAX_VERSION),
};
static void SaveReal_AIPL(int *index_ptr)
{
CompanyID index = (CompanyID)*index_ptr;
AIConfig *config = AIConfig::GetConfig(index);
if (config->HasScript()) {
_ai_saveload_name = config->GetName();
_ai_saveload_version = config->GetVersion();
} else {
/* No AI is configured for this so store an empty string as name. */
_ai_saveload_name.clear();
_ai_saveload_version = -1;
}
_ai_saveload_is_random = config->IsRandom();
_ai_saveload_settings = config->SettingsToString();
SlObject(nullptr, _ai_company_desc);
/* If the AI was active, store its data too */
if (Company::IsValidAiID(index)) AI::Save(index);
}
struct AIPLChunkHandler : ChunkHandler {
AIPLChunkHandler() : ChunkHandler('AIPL', CH_TABLE) {}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_ai_company_desc, _ai_company_sl_compat);
/* Free all current data */
for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
AIConfig::GetConfig(c, AIConfig::SSS_FORCE_GAME)->Change(nullptr);
}
CompanyID index;
while ((index = (CompanyID)SlIterateArray()) != (CompanyID)-1) {
if (index >= MAX_COMPANIES) SlErrorCorrupt("Too many AI configs");
_ai_saveload_is_random = false;
_ai_saveload_version = -1;
SlObject(nullptr, slt);
if (_game_mode == GM_MENU || (_networking && !_network_server)) {
if (Company::IsValidAiID(index)) AIInstance::LoadEmpty();
continue;
}
AIConfig *config = AIConfig::GetConfig(index, AIConfig::SSS_FORCE_GAME);
if (_ai_saveload_name.empty()) {
/* A random AI. */
config->Change(nullptr, -1, false, true);
} else {
config->Change(_ai_saveload_name.c_str(), _ai_saveload_version, false, _ai_saveload_is_random);
if (!config->HasScript()) {
/* No version of the AI available that can load the data. Try to load the
* latest version of the AI instead. */
config->Change(_ai_saveload_name.c_str(), -1, false, _ai_saveload_is_random);
if (!config->HasScript()) {
if (_ai_saveload_name.compare("%_dummy") != 0) {
DEBUG(script, 0, "The savegame has an AI by the name '%s', version %u which is no longer available.", _ai_saveload_name.c_str(), _ai_saveload_version);
DEBUG(script, 0, "A random other AI will be loaded in its place.");
} else {
DEBUG(script, 0, "The savegame had no AIs available at the time of saving.");
DEBUG(script, 0, "A random available AI will be loaded now.");
}
} else {
DEBUG(script, 0, "The savegame has an AI by the name '%s', version %u which is no longer available.", _ai_saveload_name.c_str(), _ai_saveload_version);
DEBUG(script, 0, "The latest version of that AI has been loaded instead, but it'll not get the savegame data as it's incompatible.");
}
/* Make sure the AI doesn't get the saveload data, as it was not the
* writer of the saveload data in the first place */
_ai_saveload_version = -1;
}
}
config->StringToSettings(_ai_saveload_settings);
/* Load the AI saved data */
if (Company::IsValidAiID(index)) config->SetToLoadData(AIInstance::Load(_ai_saveload_version));
}
}
void Save() const override
{
SlTableHeader(_ai_company_desc);
for (int i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
SlSetArrayIndex(i);
SlAutolength((AutolengthProc *)SaveReal_AIPL, &i);
}
}
};
static const AIPLChunkHandler AIPL;
static const ChunkHandlerRef ai_chunk_handlers[] = {
AIPL,
};
extern const ChunkHandlerTable _ai_chunk_handlers(ai_chunk_handlers);
}

@ -1,84 +0,0 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
/** @file animated_tile_sl.cpp Code handling saving and loading of animated tiles */
#include "../../stdafx.h"
#include "saveload.h"
#include "compat/animated_tile_sl_compat.h"
#include "../../tile_type.h"
#include "../../animated_tile.h"
#include "../../core/alloc_func.hpp"
#include "../../core/smallvec_type.hpp"
#include "../../safeguards.h"
namespace upstream_sl {
static std::vector <TileIndex> _tmp_animated_tiles;
static const SaveLoad _animated_tile_desc[] = {
SLEG_VECTOR("tiles", _tmp_animated_tiles, SLE_UINT32),
};
struct ANITChunkHandler : ChunkHandler {
ANITChunkHandler() : ChunkHandler('ANIT', CH_TABLE) {}
void Save() const override
{
// removed
NOT_REACHED();
}
void Load() const override
{
/* Before version 80 we did NOT have a variable length animated tile table */
if (IsSavegameVersionBefore(SLV_80)) {
/* In pre version 6, we has 16bit per tile, now we have 32bit per tile, convert it ;) */
TileIndex anim_list[256];
SlCopy(anim_list, 256, IsSavegameVersionBefore(SLV_6) ? (SLE_FILE_U16 | SLE_VAR_U32) : SLE_UINT32);
for (int i = 0; i < 256; i++) {
if (anim_list[i] == 0) break;
_animated_tiles[anim_list[i]] = {};
}
return;
}
if (IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY)) {
size_t count = SlGetFieldLength() / sizeof(uint32);
_animated_tiles.clear();
for (uint i = 0; i < count; i++) {
_animated_tiles[SlReadUint32()] = {};
}
return;
}
const std::vector<SaveLoad> slt = SlCompatTableHeader(_animated_tile_desc, _animated_tile_sl_compat);
if (SlIterateArray() == -1) return;
SlGlobList(slt);
if (SlIterateArray() != -1) SlErrorCorrupt("Too many ANIT entries");
for (TileIndex t : _tmp_animated_tiles) {
_animated_tiles[t] = {};
}
_tmp_animated_tiles.clear();
}
};
static const ANITChunkHandler ANIT;
static const ChunkHandlerRef animated_tile_chunk_handlers[] = {
ANIT,
};
extern const ChunkHandlerTable _animated_tile_chunk_handlers(animated_tile_chunk_handlers);
}

@ -1,77 +0,0 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
/** @file autoreplace_sl.cpp Code handling saving and loading of autoreplace rules */
#include "../../stdafx.h"
#include "saveload.h"
#include "compat/autoreplace_sl_compat.h"
#include "../../autoreplace_base.h"
#include "../../safeguards.h"
namespace upstream_sl {
static const SaveLoad _engine_renew_desc[] = {
SLE_VAR(EngineRenew, from, SLE_UINT16),
SLE_VAR(EngineRenew, to, SLE_UINT16),
SLE_REF(EngineRenew, next, REF_ENGINE_RENEWS),
SLE_CONDVAR(EngineRenew, group_id, SLE_UINT16, SLV_60, SL_MAX_VERSION),
SLE_CONDVAR(EngineRenew, replace_when_old, SLE_BOOL, SLV_175, SL_MAX_VERSION),
};
struct ERNWChunkHandler : ChunkHandler {
ERNWChunkHandler() : ChunkHandler('ERNW', CH_TABLE) {}
void Save() const override
{
SlTableHeader(_engine_renew_desc);
for (EngineRenew *er : EngineRenew::Iterate()) {
SlSetArrayIndex(er->index);
SlObject(er, _engine_renew_desc);
}
}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_engine_renew_desc, _engine_renew_sl_compat);
int index;
while ((index = SlIterateArray()) != -1) {
EngineRenew *er = new (index) EngineRenew();
SlObject(er, slt);
/* Advanced vehicle lists, ungrouped vehicles got added */
if (IsSavegameVersionBefore(SLV_60)) {
er->group_id = ALL_GROUP;
} else if (IsSavegameVersionBefore(SLV_71)) {
if (er->group_id == DEFAULT_GROUP) er->group_id = ALL_GROUP;
}
}
}
void FixPointers() const override
{
for (EngineRenew *er : EngineRenew::Iterate()) {
SlObject(er, _engine_renew_desc);
}
}
};
static const ERNWChunkHandler ERNW;
static const ChunkHandlerRef autoreplace_chunk_handlers[] = {
ERNW,
};
extern const ChunkHandlerTable _autoreplace_chunk_handlers(autoreplace_chunk_handlers);
}

@ -1,146 +0,0 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
/** @file cargomonitor_sl.cpp Code handling saving and loading of Cargo monitoring. */
#include "../../stdafx.h"
#include "saveload.h"
#include "compat/cargomonitor_sl_compat.h"
#include "../../cargomonitor.h"
#include "../../safeguards.h"
namespace upstream_sl {
/** Temporary storage of cargo monitoring data for loading or saving it. */
struct TempStorage {
CargoMonitorID number;
uint32 amount;
};
/** Description of the #TempStorage structure for the purpose of load and save. */
static const SaveLoad _cargomonitor_pair_desc[] = {
SLE_VAR(TempStorage, number, SLE_UINT32),
SLE_VAR(TempStorage, amount, SLE_UINT32),
};
static CargoMonitorID FixupCargoMonitor(CargoMonitorID number)
{
/* Between SLV_EXTEND_CARGOTYPES and SLV_FIX_CARGO_MONITOR, the
* CargoMonitorID structure had insufficient packing for more
* than 32 cargo types. Here we have to shuffle bits to account
* for the change.
* Company moved from bits 24-31 to 25-28.
* Cargo type increased from bits 19-23 to 19-24.
*/
SB(number, 25, 4, GB(number, 24, 4));
SB(number, 29, 3, 0);
ClrBit(number, 24);
return number;
}
/** #_cargo_deliveries monitoring map. */
struct CMDLChunkHandler : ChunkHandler {
CMDLChunkHandler() : ChunkHandler('CMDL', CH_TABLE) {}
void Save() const override
{
SlTableHeader(_cargomonitor_pair_desc);
TempStorage storage;
int i = 0;
CargoMonitorMap::const_iterator iter = _cargo_deliveries.begin();
while (iter != _cargo_deliveries.end()) {
storage.number = iter->first;
storage.amount = iter->second;
SlSetArrayIndex(i);
SlObject(&storage, _cargomonitor_pair_desc);
i++;
iter++;
}
}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_cargomonitor_pair_desc, _cargomonitor_pair_sl_compat);
TempStorage storage;
bool fix = IsSavegameVersionBefore(SLV_FIX_CARGO_MONITOR);
ClearCargoDeliveryMonitoring();
for (;;) {
if (SlIterateArray() < 0) break;
SlObject(&storage, slt);
if (fix) storage.number = FixupCargoMonitor(storage.number);
std::pair<CargoMonitorID, uint32> p(storage.number, storage.amount);
_cargo_deliveries.insert(p);
}
}
};
/** #_cargo_pickups monitoring map. */
struct CMPUChunkHandler : ChunkHandler {
CMPUChunkHandler() : ChunkHandler('CMPU', CH_TABLE) {}
void Save() const override
{
SlTableHeader(_cargomonitor_pair_desc);
TempStorage storage;
int i = 0;
CargoMonitorMap::const_iterator iter = _cargo_pickups.begin();
while (iter != _cargo_pickups.end()) {
storage.number = iter->first;
storage.amount = iter->second;
SlSetArrayIndex(i);
SlObject(&storage, _cargomonitor_pair_desc);
i++;
iter++;
}
}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_cargomonitor_pair_desc, _cargomonitor_pair_sl_compat);
TempStorage storage;
bool fix = IsSavegameVersionBefore(SLV_FIX_CARGO_MONITOR);
ClearCargoPickupMonitoring();
for (;;) {
if (SlIterateArray() < 0) break;
SlObject(&storage, slt);
if (fix) storage.number = FixupCargoMonitor(storage.number);
std::pair<CargoMonitorID, uint32> p(storage.number, storage.amount);
_cargo_pickups.insert(p);
}
}
};
/** Chunk definition of the cargomonitoring maps. */
static const CMDLChunkHandler CMDL;
static const CMPUChunkHandler CMPU;
static const ChunkHandlerRef cargomonitor_chunk_handlers[] = {
CMDL,
CMPU,
};
extern const ChunkHandlerTable _cargomonitor_chunk_handlers(cargomonitor_chunk_handlers);
}

@ -1,76 +0,0 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
/** @file cargopacket_sl.cpp Code handling saving and loading of cargo packets */
#include "../../stdafx.h"
#include "saveload.h"
#include "compat/cargopacket_sl_compat.h"
#include "../../vehicle_base.h"
#include "../../station_base.h"
#include "../../safeguards.h"
namespace upstream_sl {
/**
* Wrapper function to get the CargoPacket's internal structure while
* some of the variables itself are private.
* @return the saveload description for CargoPackets.
*/
SaveLoadTable GetCargoPacketDesc()
{
static const SaveLoad _cargopacket_desc[] = {
SLE_VAR(CargoPacket, source, SLE_UINT16),
SLE_VAR(CargoPacket, source_xy, SLE_UINT32),
SLE_VAR(CargoPacket, loaded_at_xy, SLE_UINT32),
SLE_VAR(CargoPacket, count, SLE_UINT16),
SLE_CONDVAR(CargoPacket, days_in_transit, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_MORE_CARGO_AGE),
SLE_CONDVAR(CargoPacket, days_in_transit, SLE_UINT16, SLV_MORE_CARGO_AGE, SL_MAX_VERSION),
SLE_VAR(CargoPacket, feeder_share, SLE_INT64),
SLE_CONDVAR(CargoPacket, source_type, SLE_UINT8, SLV_125, SL_MAX_VERSION),
SLE_CONDVAR(CargoPacket, source_id, SLE_UINT16, SLV_125, SL_MAX_VERSION),
};
return _cargopacket_desc;
}
struct CAPAChunkHandler : ChunkHandler {
CAPAChunkHandler() : ChunkHandler('CAPA', CH_TABLE) {}
void Save() const override
{
SlTableHeader(GetCargoPacketDesc());
for (CargoPacket *cp : CargoPacket::Iterate()) {
SlSetArrayIndex(cp->index);
SlObject(cp, GetCargoPacketDesc());
}
}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(GetCargoPacketDesc(), _cargopacket_sl_compat);
int index;
while ((index = SlIterateArray()) != -1) {
CargoPacket *cp = new (index) CargoPacket();
SlObject(cp, slt);
}
}
};
static const CAPAChunkHandler CAPA;
static const ChunkHandlerRef cargopacket_chunk_handlers[] = {
CAPA,
};
extern const ChunkHandlerTable _cargopacket_chunk_handlers(cargopacket_chunk_handlers);
}

@ -1,86 +0,0 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
/** @file cheat_sl.cpp Code handling saving and loading of cheats */
#include "../../stdafx.h"
#include "saveload.h"
#include "compat/cheat_sl_compat.h"
#include "../../cheat_type.h"
#include "../../safeguards.h"
namespace upstream_sl {
static const SaveLoad _cheats_desc[] = {
SLE_VAR(Cheats, magic_bulldozer.been_used, SLE_BOOL),
SLE_VAR(Cheats, magic_bulldozer.value, SLE_BOOL),
SLE_VAR(Cheats, switch_company.been_used, SLE_BOOL),
SLE_VAR(Cheats, switch_company.value, SLE_BOOL),
SLE_VAR(Cheats, money.been_used, SLE_BOOL),
SLE_VAR(Cheats, money.value, SLE_BOOL),
SLE_VAR(Cheats, crossing_tunnels.been_used, SLE_BOOL),
SLE_VAR(Cheats, crossing_tunnels.value, SLE_BOOL),
SLE_VAR(Cheats, no_jetcrash.been_used, SLE_BOOL),
SLE_VAR(Cheats, no_jetcrash.value, SLE_BOOL),
SLE_VAR(Cheats, change_date.been_used, SLE_BOOL),
SLE_VAR(Cheats, change_date.value, SLE_BOOL),
SLE_VAR(Cheats, setup_prod.been_used, SLE_BOOL),
SLE_VAR(Cheats, setup_prod.value, SLE_BOOL),
SLE_VAR(Cheats, edit_max_hl.been_used, SLE_BOOL),
SLE_VAR(Cheats, edit_max_hl.value, SLE_BOOL),
};
struct CHTSChunkHandler : ChunkHandler {
CHTSChunkHandler() : ChunkHandler('CHTS', CH_TABLE) {}
void Save() const override
{
SlTableHeader(_cheats_desc);
SlSetArrayIndex(0);
SlObject(&_cheats, _cheats_desc);
}
void Load() const override
{
std::vector<SaveLoad> slt = SlCompatTableHeader(_cheats_desc, _cheats_sl_compat);
if (IsSavegameVersionBefore(SLV_TABLE_CHUNKS)) {
size_t count = SlGetFieldLength();
std::vector<SaveLoad> oslt;
/* Cheats were added over the years without a savegame bump. They are
* stored as 2 SLE_BOOLs per entry. "count" indicates how many SLE_BOOLs
* are stored for this savegame. So read only "count" SLE_BOOLs (and in
* result "count / 2" cheats). */
for (auto &sld : slt) {
count--;
oslt.push_back(sld);
if (count == 0) break;
}
slt = oslt;
}
if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() == -1) return;
SlObject(&_cheats, slt);
if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many CHTS entries");
}
};
static const CHTSChunkHandler CHTS;
static const ChunkHandlerRef cheat_chunk_handlers[] = {
CHTS,
};
extern const ChunkHandlerTable _cheat_chunk_handlers(cheat_chunk_handlers);
}

@ -1,363 +0,0 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
/** @file company_sl.cpp Code handling saving and loading of company data */
#include "../../stdafx.h"
#include "saveload.h"
#include "compat/company_sl_compat.h"
#include "../../company_func.h"
#include "../../company_manager_face.h"
#include "../../fios.h"
#include "../../tunnelbridge_map.h"
#include "../../tunnelbridge.h"
#include "../../station_base.h"
#include "../../strings_func.h"
#include "table/strings.h"
#include "../../safeguards.h"
void SetDefaultCompanySettings(CompanyID cid);
namespace upstream_sl {
/* We do need to read this single value, as the bigger it gets, the more data is stored */
struct CompanyOldAI {
uint8 num_build_rec;
};
class SlCompanyOldAIBuildRec : public DefaultSaveLoadHandler<SlCompanyOldAIBuildRec, CompanyOldAI> {
public:
inline static const SaveLoad description[] = {{}}; // Needed to keep DefaultSaveLoadHandler happy.
inline const static SaveLoadCompatTable compat_description = _company_old_ai_buildrec_compat;
SaveLoadTable GetDescription() const override { return {}; }
void Load(CompanyOldAI *old_ai) const override
{
for (int i = 0; i != old_ai->num_build_rec; i++) {
SlObject(nullptr, this->GetLoadDescription());
}
}
void LoadCheck(CompanyOldAI *old_ai) const override { this->Load(old_ai); }
};
class SlCompanyOldAI : public DefaultSaveLoadHandler<SlCompanyOldAI, CompanyProperties> {
public:
inline static const SaveLoad description[] = {
SLE_CONDVAR(CompanyOldAI, num_build_rec, SLE_UINT8, SL_MIN_VERSION, SLV_107),
SLEG_STRUCTLIST("buildrec", SlCompanyOldAIBuildRec),
};
inline const static SaveLoadCompatTable compat_description = _company_old_ai_compat;
void Load(CompanyProperties *c) const override
{
if (!c->is_ai) return;
CompanyOldAI old_ai;
SlObject(&old_ai, this->GetLoadDescription());
}
void LoadCheck(CompanyProperties *c) const override { this->Load(c); }
};
class SlCompanySettings : public DefaultSaveLoadHandler<SlCompanySettings, CompanyProperties> {
public:
inline static const SaveLoad description[] = {
/* Engine renewal settings */
SLE_CONDREF(CompanyProperties, engine_renew_list, REF_ENGINE_RENEWS, SLV_19, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, settings.engine_renew, SLE_BOOL, SLV_16, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, settings.engine_renew_months, SLE_INT16, SLV_16, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, settings.engine_renew_money, SLE_UINT32, SLV_16, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, settings.renew_keep_length, SLE_BOOL, SLV_2, SL_MAX_VERSION),
/* Default vehicle settings */
SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_ispercent, SLE_BOOL, SLV_120, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_trains, SLE_UINT16, SLV_120, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_roadveh, SLE_UINT16, SLV_120, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_aircraft, SLE_UINT16, SLV_120, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_ships, SLE_UINT16, SLV_120, SL_MAX_VERSION),
};
inline const static SaveLoadCompatTable compat_description = _company_settings_compat;
void Save(CompanyProperties *c) const override
{
SlObject(c, this->GetDescription());
}
void Load(CompanyProperties *c) const override
{
SlObject(c, this->GetLoadDescription());
}
void FixPointers(CompanyProperties *c) const override
{
SlObject(c, this->GetDescription());
}
void LoadCheck(CompanyProperties *c) const override { this->Load(c); }
};
class SlCompanyEconomy : public DefaultSaveLoadHandler<SlCompanyEconomy, CompanyProperties> {
public:
inline static const SaveLoad description[] = {
SLE_CONDVAR(CompanyEconomyEntry, income, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_2),
SLE_CONDVAR(CompanyEconomyEntry, income, SLE_INT64, SLV_2, SL_MAX_VERSION),
SLE_CONDVAR(CompanyEconomyEntry, expenses, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_2),
SLE_CONDVAR(CompanyEconomyEntry, expenses, SLE_INT64, SLV_2, SL_MAX_VERSION),
SLE_CONDVAR(CompanyEconomyEntry, company_value, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_2),
SLE_CONDVAR(CompanyEconomyEntry, company_value, SLE_INT64, SLV_2, SL_MAX_VERSION),
SLE_CONDVAR(CompanyEconomyEntry, delivered_cargo[NUM_CARGO - 1], SLE_INT32, SL_MIN_VERSION, SLV_170),
SLE_CONDARR(CompanyEconomyEntry, delivered_cargo, SLE_UINT32, 32, SLV_170, SLV_EXTEND_CARGOTYPES),
SLE_CONDARR(CompanyEconomyEntry, delivered_cargo, SLE_UINT32, NUM_CARGO, SLV_EXTEND_CARGOTYPES, SL_MAX_VERSION),
SLE_VAR(CompanyEconomyEntry, performance_history, SLE_INT32),
};
inline const static SaveLoadCompatTable compat_description = _company_economy_compat;
void Save(CompanyProperties *c) const override
{
SlObject(&c->cur_economy, this->GetDescription());
}
void Load(CompanyProperties *c) const override
{
SlObject(&c->cur_economy, this->GetLoadDescription());
}
void FixPointers(CompanyProperties *c) const override
{
SlObject(&c->cur_economy, this->GetDescription());
}
void LoadCheck(CompanyProperties *c) const override { this->Load(c); }
};
class SlCompanyOldEconomy : public SlCompanyEconomy {
public:
void Save(CompanyProperties *c) const override
{
SlSetStructListLength(c->num_valid_stat_ent);
for (int i = 0; i < c->num_valid_stat_ent; i++) {
SlObject(&c->old_economy[i], this->GetDescription());
}
}
void Load(CompanyProperties *c) const override
{
if (!IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) {
c->num_valid_stat_ent = (uint8)SlGetStructListLength(UINT8_MAX);
}
if (c->num_valid_stat_ent > lengthof(c->old_economy)) SlErrorCorrupt("Too many old economy entries");
for (int i = 0; i < c->num_valid_stat_ent; i++) {
SlObject(&c->old_economy[i], this->GetLoadDescription());
}
}
void LoadCheck(CompanyProperties *c) const override { this->Load(c); }
};
class SlCompanyLiveries : public DefaultSaveLoadHandler<SlCompanyLiveries, CompanyProperties> {
public:
inline static const SaveLoad description[] = {
SLE_CONDVAR(Livery, in_use, SLE_UINT8, SLV_34, SL_MAX_VERSION),
SLE_CONDVAR(Livery, colour1, SLE_UINT8, SLV_34, SL_MAX_VERSION),
SLE_CONDVAR(Livery, colour2, SLE_UINT8, SLV_34, SL_MAX_VERSION),
};
inline const static SaveLoadCompatTable compat_description = _company_liveries_compat;
/**
* Get the number of liveries used by this savegame version.
* @return The number of liveries used by this savegame version.
*/
size_t GetNumLiveries() const
{
if (IsSavegameVersionBefore(SLV_63)) return LS_END - 4;
if (IsSavegameVersionBefore(SLV_85)) return LS_END - 2;
if (IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) return LS_END;
/* Read from the savegame how long the list is. */
return SlGetStructListLength(LS_END);
}
void Save(CompanyProperties *c) const override
{
SlSetStructListLength(LS_END);
for (int i = 0; i < LS_END; i++) {
SlObject(&c->livery[i], this->GetDescription());
}
}
void Load(CompanyProperties *c) const override
{
size_t num_liveries = this->GetNumLiveries();
bool update_in_use = IsSavegameVersionBefore(SLV_GROUP_LIVERIES);
for (size_t i = 0; i < num_liveries; i++) {
SlObject(&c->livery[i], this->GetLoadDescription());
if (update_in_use && i != LS_DEFAULT) {
if (c->livery[i].in_use == 0) {
c->livery[i].colour1 = c->livery[LS_DEFAULT].colour1;
c->livery[i].colour2 = c->livery[LS_DEFAULT].colour2;
} else {
c->livery[i].in_use = 3;
}
}
}
if (IsSavegameVersionBefore(SLV_85)) {
/* We want to insert some liveries somewhere in between. This means some have to be moved. */
memmove(&c->livery[LS_FREIGHT_WAGON], &c->livery[LS_PASSENGER_WAGON_MONORAIL], (LS_END - LS_FREIGHT_WAGON) * sizeof(c->livery[0]));
c->livery[LS_PASSENGER_WAGON_MONORAIL] = c->livery[LS_MONORAIL];
c->livery[LS_PASSENGER_WAGON_MAGLEV] = c->livery[LS_MAGLEV];
}
if (IsSavegameVersionBefore(SLV_63)) {
/* Copy bus/truck liveries over to trams */
c->livery[LS_PASSENGER_TRAM] = c->livery[LS_BUS];
c->livery[LS_FREIGHT_TRAM] = c->livery[LS_TRUCK];
}
}
void LoadCheck(CompanyProperties *c) const override { this->Load(c); }
};
/* Save/load of companies */
static const SaveLoad _company_desc[] = {
SLE_VAR(CompanyProperties, name_2, SLE_UINT32),
SLE_VAR(CompanyProperties, name_1, SLE_STRINGID),
SLE_CONDSSTR(CompanyProperties, name, SLE_STR | SLF_ALLOW_CONTROL, SLV_84, SL_MAX_VERSION),
SLE_VAR(CompanyProperties, president_name_1, SLE_STRINGID),
SLE_VAR(CompanyProperties, president_name_2, SLE_UINT32),
SLE_CONDSSTR(CompanyProperties, president_name, SLE_STR | SLF_ALLOW_CONTROL, SLV_84, SL_MAX_VERSION),
SLE_VAR(CompanyProperties, face, SLE_UINT32),
/* money was changed to a 64 bit field in savegame version 1. */
SLE_CONDVAR(CompanyProperties, money, SLE_VAR_I64 | SLE_FILE_I32, SL_MIN_VERSION, SLV_1),
SLE_CONDVAR(CompanyProperties, money, SLE_INT64, SLV_1, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, current_loan, SLE_VAR_I64 | SLE_FILE_I32, SL_MIN_VERSION, SLV_65),
SLE_CONDVAR(CompanyProperties, current_loan, SLE_INT64, SLV_65, SL_MAX_VERSION),
SLE_VAR(CompanyProperties, colour, SLE_UINT8),
SLE_VAR(CompanyProperties, money_fraction, SLE_UINT8),
SLE_VAR(CompanyProperties, block_preview, SLE_UINT8),
SLE_CONDVAR(CompanyProperties, location_of_HQ, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6),
SLE_CONDVAR(CompanyProperties, location_of_HQ, SLE_UINT32, SLV_6, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, last_build_coordinate, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6),
SLE_CONDVAR(CompanyProperties, last_build_coordinate, SLE_UINT32, SLV_6, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, inaugurated_year, SLE_FILE_U8 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31),
SLE_CONDVAR(CompanyProperties, inaugurated_year, SLE_INT32, SLV_31, SL_MAX_VERSION),
SLE_ARR(CompanyProperties, share_owners, SLE_UINT8, 4),
SLE_CONDVAR(CompanyProperties, num_valid_stat_ent, SLE_UINT8, SL_MIN_VERSION, SLV_SAVELOAD_LIST_LENGTH),
SLE_VAR(CompanyProperties, months_of_bankruptcy, SLE_UINT8),
SLE_CONDVAR(CompanyProperties, bankrupt_asked, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_104),
SLE_CONDVAR(CompanyProperties, bankrupt_asked, SLE_UINT16, SLV_104, SL_MAX_VERSION),
SLE_VAR(CompanyProperties, bankrupt_timeout, SLE_INT16),
SLE_CONDVAR(CompanyProperties, bankrupt_value, SLE_VAR_I64 | SLE_FILE_I32, SL_MIN_VERSION, SLV_65),
SLE_CONDVAR(CompanyProperties, bankrupt_value, SLE_INT64, SLV_65, SL_MAX_VERSION),
/* yearly expenses was changed to 64-bit in savegame version 2. */
SLE_CONDARR(CompanyProperties, yearly_expenses, SLE_FILE_I32 | SLE_VAR_I64, 3 * 13, SL_MIN_VERSION, SLV_2),
SLE_CONDARR(CompanyProperties, yearly_expenses, SLE_INT64, 3 * 13, SLV_2, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, is_ai, SLE_BOOL, SLV_2, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, terraform_limit, SLE_UINT32, SLV_156, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, clear_limit, SLE_UINT32, SLV_156, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, tree_limit, SLE_UINT32, SLV_175, SL_MAX_VERSION),
SLEG_STRUCT("settings", SlCompanySettings),
SLEG_CONDSTRUCT("old_ai", SlCompanyOldAI, SL_MIN_VERSION, SLV_107),
SLEG_STRUCT("cur_economy", SlCompanyEconomy),
SLEG_STRUCTLIST("old_economy", SlCompanyOldEconomy),
SLEG_CONDSTRUCTLIST("liveries", SlCompanyLiveries, SLV_34, SL_MAX_VERSION),
};
struct PLYRChunkHandler : ChunkHandler {
PLYRChunkHandler() : ChunkHandler('PLYR', CH_TABLE) {}
void Save() const override
{
SlTableHeader(_company_desc);
for (Company *c : Company::Iterate()) {
SlSetArrayIndex(c->index);
SlObject(c, _company_desc);
}
}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_company_desc, _company_sl_compat);
int index;
while ((index = SlIterateArray()) != -1) {
Company *c = new (index) Company();
SetDefaultCompanySettings(c->index);
SlObject((CompanyProperties *)c, slt);
_company_colours[index] = (Colours)c->colour;
}
}
void LoadCheck(size_t) const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_company_desc, _company_sl_compat);
int index;
while ((index = SlIterateArray()) != -1) {
CompanyProperties *cprops = new CompanyProperties();
SlObject(cprops, slt);
/* We do not load old custom names */
if (IsSavegameVersionBefore(SLV_84)) {
if (GetStringTab(cprops->name_1) == TEXT_TAB_OLD_CUSTOM) {
cprops->name_1 = STR_GAME_SAVELOAD_NOT_AVAILABLE;
}
if (GetStringTab(cprops->president_name_1) == TEXT_TAB_OLD_CUSTOM) {
cprops->president_name_1 = STR_GAME_SAVELOAD_NOT_AVAILABLE;
}
}
if (cprops->name.empty() && !IsInsideMM(cprops->name_1, SPECSTR_COMPANY_NAME_START, SPECSTR_COMPANY_NAME_LAST + 1) &&
cprops->name_1 != STR_GAME_SAVELOAD_NOT_AVAILABLE && cprops->name_1 != STR_SV_UNNAMED &&
cprops->name_1 != SPECSTR_ANDCO_NAME && cprops->name_1 != SPECSTR_PRESIDENT_NAME &&
cprops->name_1 != SPECSTR_SILLY_NAME) {
cprops->name_1 = STR_GAME_SAVELOAD_NOT_AVAILABLE;
}
if (!_load_check_data.companies.Insert(index, cprops)) delete cprops;
}
}
void FixPointers() const override
{
for (Company *c : Company::Iterate()) {
SlObject((CompanyProperties *)c, _company_desc);
}
}
};
static const PLYRChunkHandler PLYR;
static const ChunkHandlerRef company_chunk_handlers[] = {
PLYR,
};
extern const ChunkHandlerTable _company_chunk_handlers(company_chunk_handlers);
}

@ -1,109 +0,0 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
/** @file economy_sl.cpp Code handling saving and loading of economy data */
#include "../../stdafx.h"
#include "saveload.h"
#include "compat/economy_sl_compat.h"
#include "../../economy_func.h"
#include "../../economy_base.h"
#include "../../safeguards.h"
namespace upstream_sl {
static const SaveLoad _economy_desc[] = {
SLE_CONDVAR(Economy, old_max_loan_unround, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_65),
SLE_CONDVAR(Economy, old_max_loan_unround, SLE_INT64, SLV_65, SLV_126),
SLE_CONDVAR(Economy, old_max_loan_unround_fract, SLE_UINT16, SLV_70, SLV_126),
SLE_CONDVAR(Economy, inflation_prices, SLE_UINT64, SLV_126, SL_MAX_VERSION),
SLE_CONDVAR(Economy, inflation_payment, SLE_UINT64, SLV_126, SL_MAX_VERSION),
SLE_VAR(Economy, fluct, SLE_INT16),
SLE_VAR(Economy, interest_rate, SLE_UINT8),
SLE_VAR(Economy, infl_amount, SLE_UINT8),
SLE_VAR(Economy, infl_amount_pr, SLE_UINT8),
SLE_CONDVAR(Economy, industry_daily_change_counter, SLE_UINT32, SLV_102, SL_MAX_VERSION),
};
/** Economy variables */
struct ECMYChunkHandler : ChunkHandler {
ECMYChunkHandler() : ChunkHandler('ECMY', CH_TABLE) {}
void Save() const override
{
SlTableHeader(_economy_desc);
SlSetArrayIndex(0);
SlObject(&_economy, _economy_desc);
}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_economy_desc, _economy_sl_compat);
if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() == -1) return;
SlObject(&_economy, slt);
if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many ECMY entries");
StartupIndustryDailyChanges(IsSavegameVersionBefore(SLV_102)); // old savegames will need to be initialized
}
};
static const SaveLoad _cargopayment_desc[] = {
SLE_REF(CargoPayment, front, REF_VEHICLE),
SLE_VAR(CargoPayment, route_profit, SLE_INT64),
SLE_VAR(CargoPayment, visual_profit, SLE_INT64),
SLE_CONDVAR(CargoPayment, visual_transfer, SLE_INT64, SLV_181, SL_MAX_VERSION),
};
struct CAPYChunkHandler : ChunkHandler {
CAPYChunkHandler() : ChunkHandler('CAPY', CH_TABLE) {}
void Save() const override
{
SlTableHeader(_cargopayment_desc);
for (CargoPayment *cp : CargoPayment::Iterate()) {
SlSetArrayIndex(cp->index);
SlObject(cp, _cargopayment_desc);
}
}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_cargopayment_desc, _cargopayment_sl_compat);
int index;
while ((index = SlIterateArray()) != -1) {
CargoPayment *cp = new (index) CargoPayment();
SlObject(cp, slt);
}
}
void FixPointers() const override
{
for (CargoPayment *cp : CargoPayment::Iterate()) {
SlObject(cp, _cargopayment_desc);
}
}
};
static const CAPYChunkHandler CAPY;
static const ECMYChunkHandler ECMY;
static const ChunkHandlerRef economy_chunk_handlers[] = {
CAPY,
ECMY,
};
extern const ChunkHandlerTable _economy_chunk_handlers(economy_chunk_handlers);
}

@ -1,129 +0,0 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
/** @file engine_sl.cpp Code handling saving and loading of engines */
#include "../../stdafx.h"
#include "saveload.h"
#include "compat/engine_sl_compat.h"
#include "../../engine_base.h"
#include "../../string_func.h"
#include <vector>
#include "../../safeguards.h"
Engine *GetTempDataEngine(EngineID index);
namespace upstream_sl {
static const SaveLoad _engine_desc[] = {
SLE_CONDVAR(Engine, intro_date, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31),
SLE_CONDVAR(Engine, intro_date, SLE_INT32, SLV_31, SL_MAX_VERSION),
SLE_CONDVAR(Engine, age, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31),
SLE_CONDVAR(Engine, age, SLE_INT32, SLV_31, SL_MAX_VERSION),
SLE_VAR(Engine, reliability, SLE_UINT16),
SLE_VAR(Engine, reliability_spd_dec, SLE_UINT16),
SLE_VAR(Engine, reliability_start, SLE_UINT16),
SLE_VAR(Engine, reliability_max, SLE_UINT16),
SLE_VAR(Engine, reliability_final, SLE_UINT16),
SLE_VAR(Engine, duration_phase_1, SLE_UINT16),
SLE_VAR(Engine, duration_phase_2, SLE_UINT16),
SLE_VAR(Engine, duration_phase_3, SLE_UINT16),
SLE_VAR(Engine, flags, SLE_UINT8),
SLE_CONDVAR(Engine, preview_asked, SLE_UINT16, SLV_179, SL_MAX_VERSION),
SLE_CONDVAR(Engine, preview_company, SLE_UINT8, SLV_179, SL_MAX_VERSION),
SLE_VAR(Engine, preview_wait, SLE_UINT8),
SLE_CONDVAR(Engine, company_avail, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_104),
SLE_CONDVAR(Engine, company_avail, SLE_UINT16, SLV_104, SL_MAX_VERSION),
SLE_CONDVAR(Engine, company_hidden, SLE_UINT16, SLV_193, SL_MAX_VERSION),
SLE_CONDSTR(Engine, name, SLE_STR, 0, SLV_84, SL_MAX_VERSION),
};
struct ENGNChunkHandler : ChunkHandler {
ENGNChunkHandler() : ChunkHandler('ENGN', CH_TABLE) {}
void Save() const override
{
SlTableHeader(_engine_desc);
for (Engine *e : Engine::Iterate()) {
SlSetArrayIndex(e->index);
SlObject(e, _engine_desc);
}
}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_engine_desc, _engine_sl_compat);
/* As engine data is loaded before engines are initialized we need to load
* this information into a temporary array. This is then copied into the
* engine pool after processing NewGRFs by CopyTempEngineData(). */
int index;
while ((index = SlIterateArray()) != -1) {
Engine *e = GetTempDataEngine(index);
SlObject(e, slt);
if (IsSavegameVersionBefore(SLV_179)) {
/* preview_company_rank was replaced with preview_company and preview_asked.
* Just cancel any previews. */
e->flags &= ~4; // ENGINE_OFFER_WINDOW_OPEN
e->preview_company = INVALID_COMPANY;
e->preview_asked = MAX_UVALUE(CompanyMask);
}
}
}
};
/** Save and load the mapping between the engine id in the pool, and the grf file it came from. */
static const SaveLoad _engine_id_mapping_desc[] = {
SLE_VAR(EngineIDMapping, grfid, SLE_UINT32),
SLE_VAR(EngineIDMapping, internal_id, SLE_UINT16),
SLE_VAR(EngineIDMapping, type, SLE_UINT8),
SLE_VAR(EngineIDMapping, substitute_id, SLE_UINT8),
};
struct EIDSChunkHandler : ChunkHandler {
EIDSChunkHandler() : ChunkHandler('EIDS', CH_TABLE) {}
void Save() const override
{
SlTableHeader(_engine_id_mapping_desc);
uint index = 0;
for (EngineIDMapping &eid : _engine_mngr) {
SlSetArrayIndex(index);
SlObject(&eid, _engine_id_mapping_desc);
index++;
}
}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_engine_id_mapping_desc, _engine_id_mapping_sl_compat);
_engine_mngr.clear();
while (SlIterateArray() != -1) {
EngineIDMapping *eid = &_engine_mngr.emplace_back();
SlObject(eid, slt);
}
}
};
static const EIDSChunkHandler EIDS;
static const ENGNChunkHandler ENGN;
static const ChunkHandlerRef engine_chunk_handlers[] = {
EIDS,
ENGN,
};
extern const ChunkHandlerTable _engine_chunk_handlers(engine_chunk_handlers);
}

@ -1,209 +0,0 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
/** @file game_sl.cpp Handles the saveload part of the GameScripts */
#include "../../stdafx.h"
#include "../../debug.h"
#include "saveload.h"
#include "compat/game_sl_compat.h"
#include "../../string_func.h"
#include "../../game/game.hpp"
#include "../../game/game_config.hpp"
#include "../../network/network.h"
#include "../../game/game_instance.hpp"
#include "../../game/game_text.hpp"
#include "../../safeguards.h"
extern GameStrings *_current_data;
namespace upstream_sl {
static std::string _game_saveload_name;
static int _game_saveload_version;
static std::string _game_saveload_settings;
static bool _game_saveload_is_random;
static const SaveLoad _game_script_desc[] = {
SLEG_SSTR("name", _game_saveload_name, SLE_STR),
SLEG_SSTR("settings", _game_saveload_settings, SLE_STR),
SLEG_VAR("version", _game_saveload_version, SLE_UINT32),
SLEG_VAR("is_random", _game_saveload_is_random, SLE_BOOL),
};
static void SaveReal_GSDT(int *index_ptr)
{
GameConfig *config = GameConfig::GetConfig();
if (config->HasScript()) {
_game_saveload_name = config->GetName();
_game_saveload_version = config->GetVersion();
} else {
/* No GameScript is configured for this so store an empty string as name. */
_game_saveload_name.clear();
_game_saveload_version = -1;
}
_game_saveload_is_random = config->IsRandom();
_game_saveload_settings = config->SettingsToString();
SlObject(nullptr, _game_script_desc);
Game::Save();
}
struct GSDTChunkHandler : ChunkHandler {
GSDTChunkHandler() : ChunkHandler('GSDT', CH_TABLE) {}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_game_script_desc, _game_script_sl_compat);
/* Free all current data */
GameConfig::GetConfig(GameConfig::SSS_FORCE_GAME)->Change(nullptr);
if (SlIterateArray() == -1) return;
_game_saveload_version = -1;
SlObject(nullptr, slt);
if (_game_mode == GM_MENU || (_networking && !_network_server)) {
GameInstance::LoadEmpty();
if (SlIterateArray() != -1) SlErrorCorrupt("Too many GameScript configs");
return;
}
GameConfig *config = GameConfig::GetConfig(GameConfig::SSS_FORCE_GAME);
if (!_game_saveload_name.empty()) {
config->Change(_game_saveload_name.c_str(), _game_saveload_version, false, _game_saveload_is_random);
if (!config->HasScript()) {
/* No version of the GameScript available that can load the data. Try to load the
* latest version of the GameScript instead. */
config->Change(_game_saveload_name.c_str(), -1, false, _game_saveload_is_random);
if (!config->HasScript()) {
if (_game_saveload_name.compare("%_dummy") != 0) {
DEBUG(script, 0, "The savegame has an GameScript by the name '%s', version %u which is no longer available.", _game_saveload_name.c_str(), _game_saveload_version);
DEBUG(script, 0, "This game will continue to run without GameScript.");
} else {
DEBUG(script, 0, "The savegame had no GameScript available at the time of saving.");
DEBUG(script, 0, "This game will continue to run without GameScript.");
}
} else {
DEBUG(script, 0, "The savegame has an GameScript by the name '%s', version %u which is no longer available.", _game_saveload_name.c_str(), _game_saveload_version);
DEBUG(script, 0, "The latest version of that GameScript has been loaded instead, but it'll not get the savegame data as it's incompatible.");
}
/* Make sure the GameScript doesn't get the saveload data, as it was not the
* writer of the saveload data in the first place */
_game_saveload_version = -1;
}
}
config->StringToSettings(_game_saveload_settings);
/* Load the GameScript saved data */
config->SetToLoadData(GameInstance::Load(_game_saveload_version));
if (SlIterateArray() != -1) SlErrorCorrupt("Too many GameScript configs");
}
void Save() const override
{
SlTableHeader(_game_script_desc);
SlSetArrayIndex(0);
SlAutolength((AutolengthProc *)SaveReal_GSDT, nullptr);
}
};
static std::string _game_saveload_string;
static uint32 _game_saveload_strings;
class SlGameLanguageString : public DefaultSaveLoadHandler<SlGameLanguageString, LanguageStrings> {
public:
inline static const SaveLoad description[] = {
SLEG_SSTR("string", _game_saveload_string, SLE_STR | SLF_ALLOW_CONTROL),
};
inline const static SaveLoadCompatTable compat_description = _game_language_string_sl_compat;
void Save(LanguageStrings *ls) const override
{
SlSetStructListLength(ls->lines.size());
for (const auto &string : ls->lines) {
_game_saveload_string = string;
SlObject(nullptr, this->GetDescription());
}
}
void Load(LanguageStrings *ls) const override
{
uint32 length = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? _game_saveload_strings : (uint32)SlGetStructListLength(UINT32_MAX);
for (uint32 i = 0; i < length; i++) {
SlObject(nullptr, this->GetLoadDescription());
ls->lines.emplace_back(_game_saveload_string);
}
}
};
static const SaveLoad _game_language_desc[] = {
SLE_SSTR(LanguageStrings, language, SLE_STR),
SLEG_CONDVAR("count", _game_saveload_strings, SLE_UINT32, SL_MIN_VERSION, SLV_SAVELOAD_LIST_LENGTH),
SLEG_STRUCTLIST("strings", SlGameLanguageString),
};
struct GSTRChunkHandler : ChunkHandler {
GSTRChunkHandler() : ChunkHandler('GSTR', CH_TABLE) {}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_game_language_desc, _game_language_sl_compat);
delete _current_data;
_current_data = new GameStrings();
while (SlIterateArray() != -1) {
LanguageStrings ls;
SlObject(&ls, slt);
_current_data->raw_strings.push_back(std::move(ls));
}
/* If there were no strings in the savegame, set GameStrings to nullptr */
if (_current_data->raw_strings.size() == 0) {
delete _current_data;
_current_data = nullptr;
return;
}
_current_data->Compile();
ReconsiderGameScriptLanguage();
}
void Save() const override
{
SlTableHeader(_game_language_desc);
if (_current_data == nullptr) return;
for (uint i = 0; i < _current_data->raw_strings.size(); i++) {
SlSetArrayIndex(i);
SlObject(&_current_data->raw_strings[i], _game_language_desc);
}
}
};
static const GSTRChunkHandler GSTR;
static const GSDTChunkHandler GSDT;
static const ChunkHandlerRef game_chunk_handlers[] = {
GSTR,
GSDT,
};
extern const ChunkHandlerTable _game_chunk_handlers(game_chunk_handlers);
}

@ -1,428 +0,0 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
/** @file gamelog_sl.cpp Code handling saving and loading of gamelog data */
#include "../../stdafx.h"
#include "saveload.h"
#include "compat/gamelog_sl_compat.h"
#include "../../gamelog_internal.h"
#include "../../fios.h"
#include "../../string_func.h"
#include "../../safeguards.h"
namespace upstream_sl {
class SlGamelogMode : public DefaultSaveLoadHandler<SlGamelogMode, LoggedChange> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(LoggedChange, mode.mode, SLE_UINT8),
SLE_VAR(LoggedChange, mode.landscape, SLE_UINT8),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_mode_sl_compat;
void Save(LoggedChange *lc) const override
{
if (lc->ct != GLCT_MODE) return;
SlObject(lc, this->GetDescription());
}
void Load(LoggedChange *lc) const override
{
if (lc->ct != GLCT_MODE) return;
SlObject(lc, this->GetLoadDescription());
}
void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
};
static char old_revision_text[GAMELOG_REVISION_LENGTH];
static std::string revision_test;
class SlGamelogRevision : public DefaultSaveLoadHandler<SlGamelogRevision, LoggedChange> {
public:
inline static const SaveLoad description[] = {
SLEG_CONDARR("revision.text", old_revision_text, SLE_UINT8, GAMELOG_REVISION_LENGTH, SL_MIN_VERSION, SLV_STRING_GAMELOG),
SLEG_CONDSSTR("revision.text", revision_test, SLE_STR, SLV_STRING_GAMELOG, SL_MAX_VERSION),
SLE_VAR(LoggedChange, revision.newgrf, SLE_UINT32),
SLE_VAR(LoggedChange, revision.slver, SLE_UINT16),
SLE_VAR(LoggedChange, revision.modified, SLE_UINT8),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_revision_sl_compat;
void Save(LoggedChange *lc) const override
{
if (lc->ct != GLCT_REVISION) return;
SlObject(lc, this->GetDescription());
}
void Load(LoggedChange *lc) const override
{
if (lc->ct != GLCT_REVISION) return;
SlObject(lc, this->GetLoadDescription());
if (IsSavegameVersionBefore(SLV_STRING_GAMELOG)) {
lc->revision.text = stredup(old_revision_text, lastof(old_revision_text));
} else {
lc->revision.text = stredup(revision_test.c_str());
}
}
void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
};
class SlGamelogOldver : public DefaultSaveLoadHandler<SlGamelogOldver, LoggedChange> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(LoggedChange, oldver.type, SLE_UINT32),
SLE_VAR(LoggedChange, oldver.version, SLE_UINT32),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_oldver_sl_compat;
void Save(LoggedChange *lc) const override
{
if (lc->ct != GLCT_OLDVER) return;
SlObject(lc, this->GetDescription());
}
void Load(LoggedChange *lc) const override
{
if (lc->ct != GLCT_OLDVER) return;
SlObject(lc, this->GetLoadDescription());
}
void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
};
class SlGamelogSetting : public DefaultSaveLoadHandler<SlGamelogSetting, LoggedChange> {
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),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_setting_sl_compat;
void Save(LoggedChange *lc) const override
{
if (lc->ct != GLCT_SETTING) return;
SlObject(lc, this->GetDescription());
}
void Load(LoggedChange *lc) const override
{
if (lc->ct != GLCT_SETTING) return;
SlObject(lc, this->GetLoadDescription());
}
void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
};
class SlGamelogGrfadd : public DefaultSaveLoadHandler<SlGamelogGrfadd, LoggedChange> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(LoggedChange, grfadd.grfid, SLE_UINT32 ),
SLE_ARR(LoggedChange, grfadd.md5sum, SLE_UINT8, 16),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_grfadd_sl_compat;
void Save(LoggedChange *lc) const override
{
if (lc->ct != GLCT_GRFADD) return;
SlObject(lc, this->GetDescription());
}
void Load(LoggedChange *lc) const override
{
if (lc->ct != GLCT_GRFADD) return;
SlObject(lc, this->GetLoadDescription());
}
void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
};
class SlGamelogGrfrem : public DefaultSaveLoadHandler<SlGamelogGrfrem, LoggedChange> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(LoggedChange, grfrem.grfid, SLE_UINT32),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_grfrem_sl_compat;
void Save(LoggedChange *lc) const override
{
if (lc->ct != GLCT_GRFREM) return;
SlObject(lc, this->GetDescription());
}
void Load(LoggedChange *lc) const override
{
if (lc->ct != GLCT_GRFREM) return;
SlObject(lc, this->GetLoadDescription());
}
void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
};
class SlGamelogGrfcompat : public DefaultSaveLoadHandler<SlGamelogGrfcompat, LoggedChange> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(LoggedChange, grfcompat.grfid, SLE_UINT32 ),
SLE_ARR(LoggedChange, grfcompat.md5sum, SLE_UINT8, 16),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_grfcompat_sl_compat;
void Save(LoggedChange *lc) const override
{
if (lc->ct != GLCT_GRFCOMPAT) return;
SlObject(lc, this->GetDescription());
}
void Load(LoggedChange *lc) const override
{
if (lc->ct != GLCT_GRFCOMPAT) return;
SlObject(lc, this->GetLoadDescription());
}
void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
};
class SlGamelogGrfparam : public DefaultSaveLoadHandler<SlGamelogGrfparam, LoggedChange> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(LoggedChange, grfparam.grfid, SLE_UINT32),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_grfparam_sl_compat;
void Save(LoggedChange *lc) const override
{
if (lc->ct != GLCT_GRFPARAM) return;
SlObject(lc, this->GetDescription());
}
void Load(LoggedChange *lc) const override
{
if (lc->ct != GLCT_GRFPARAM) return;
SlObject(lc, this->GetLoadDescription());
}
void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
};
class SlGamelogGrfmove : public DefaultSaveLoadHandler<SlGamelogGrfmove, LoggedChange> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(LoggedChange, grfmove.grfid, SLE_UINT32),
SLE_VAR(LoggedChange, grfmove.offset, SLE_INT32),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_grfmove_sl_compat;
void Save(LoggedChange *lc) const override
{
if (lc->ct != GLCT_GRFMOVE) return;
SlObject(lc, this->GetDescription());
}
void Load(LoggedChange *lc) const override
{
if (lc->ct != GLCT_GRFMOVE) return;
SlObject(lc, this->GetLoadDescription());
}
void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
};
class SlGamelogGrfbug : public DefaultSaveLoadHandler<SlGamelogGrfbug, LoggedChange> {
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),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_grfbug_sl_compat;
void Save(LoggedChange *lc) const override
{
if (lc->ct != GLCT_GRFBUG) return;
SlObject(lc, this->GetDescription());
}
void Load(LoggedChange *lc) const override
{
if (lc->ct != GLCT_GRFBUG) return;
SlObject(lc, this->GetLoadDescription());
}
void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
};
static bool _is_emergency_save = true;
class SlGamelogEmergency : public DefaultSaveLoadHandler<SlGamelogEmergency, LoggedChange> {
public:
/* We need to store something, so store a "true" value. */
inline static const SaveLoad description[] = {
SLEG_CONDVAR("is_emergency_save", _is_emergency_save, SLE_BOOL, SLV_RIFF_TO_ARRAY, SL_MAX_VERSION),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_emergency_sl_compat;
void Save(LoggedChange *lc) const override
{
if (lc->ct != GLCT_EMERGENCY) return;
_is_emergency_save = true;
SlObject(lc, this->GetDescription());
}
void Load(LoggedChange *lc) const override
{
if (lc->ct != GLCT_EMERGENCY) return;
SlObject(lc, this->GetLoadDescription());
}
void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
};
class SlGamelogAction : public DefaultSaveLoadHandler<SlGamelogAction, LoggedAction> {
public:
inline static const SaveLoad description[] = {
SLE_SAVEBYTE(LoggedChange, ct),
SLEG_STRUCT("mode", SlGamelogMode),
SLEG_STRUCT("revision", SlGamelogRevision),
SLEG_STRUCT("oldver", SlGamelogOldver),
SLEG_STRUCT("setting", SlGamelogSetting),
SLEG_STRUCT("grfadd", SlGamelogGrfadd),
SLEG_STRUCT("grfrem", SlGamelogGrfrem),
SLEG_STRUCT("grfcompat", SlGamelogGrfcompat),
SLEG_STRUCT("grfparam", SlGamelogGrfparam),
SLEG_STRUCT("grfmove", SlGamelogGrfmove),
SLEG_STRUCT("grfbug", SlGamelogGrfbug),
SLEG_STRUCT("emergency", SlGamelogEmergency),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_action_sl_compat;
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->GetLoadDescription());
}
return;
}
size_t length = SlGetStructListLength(UINT32_MAX);
la->change = ReallocT(la->change, length);
la->changes = (uint32)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->GetLoadDescription());
}
}
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_CONDVAR(LoggedAction, tick, SLE_FILE_U16 | SLE_VAR_U64, SL_MIN_VERSION, SLV_U64_TICK_COUNTER),
SLE_CONDVAR(LoggedAction, tick, SLE_UINT64, SLV_U64_TICK_COUNTER, SL_MAX_VERSION),
SLEG_STRUCTLIST("action", SlGamelogAction),
};
struct GLOGChunkHandler : ChunkHandler {
GLOGChunkHandler() : ChunkHandler('GLOG', CH_TABLE) {}
void LoadCommon(LoggedAction *&gamelog_action, uint &gamelog_actions) const
{
assert(gamelog_action == nullptr);
assert(gamelog_actions == 0);
const std::vector<SaveLoad> slt = SlCompatTableHeader(_gamelog_desc, _gamelog_sl_compat);
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, slt);
}
return;
}
while (SlIterateArray() != -1) {
gamelog_action = ReallocT(gamelog_action, gamelog_actions + 1);
LoggedAction *la = &gamelog_action[gamelog_actions++];
memset(la, 0, sizeof(*la));
SlObject(la, slt);
}
}
void Save() const override
{
SlTableHeader(_gamelog_desc);
const LoggedAction *laend = &_gamelog_action[_gamelog_actions];
uint i = 0;
for (LoggedAction *la = _gamelog_action; la != laend; la++, i++) {
SlSetArrayIndex(i);
SlObject(la, _gamelog_desc);
}
}
void Load() const override
{
this->LoadCommon(_gamelog_action, _gamelog_actions);
}
void LoadCheck(size_t) const override
{
this->LoadCommon(_load_check_data.gamelog_action, _load_check_data.gamelog_actions);
}
};
static const GLOGChunkHandler GLOG;
static const ChunkHandlerRef gamelog_chunk_handlers[] = {
GLOG,
};
extern const ChunkHandlerTable _gamelog_chunk_handlers(gamelog_chunk_handlers);
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save