Move upstream saveload to src/saveload/, move jgrpp saveload to src/sl/
Leave afterload in src/saveload/
This commit is contained in:
@@ -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);
|
||||
}
|
||||
struct AIPLChunkHandler : ChunkHandler {
|
||||
AIPLChunkHandler() : ChunkHandler('AIPL', CH_TABLE) {}
|
||||
|
||||
CompanyID index;
|
||||
while ((index = (CompanyID)SlIterateArray()) != (CompanyID)-1) {
|
||||
if (index >= MAX_COMPANIES) SlErrorCorrupt("Too many AI configs");
|
||||
void Load() const override
|
||||
{
|
||||
const std::vector<SaveLoad> slt = SlCompatTableHeader(_ai_company_desc, _ai_company_sl_compat);
|
||||
|
||||
_ai_saveload_is_random = false;
|
||||
_ai_saveload_version = -1;
|
||||
SlObject(nullptr, _ai_company);
|
||||
|
||||
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);
|
||||
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.");
|
||||
} 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 %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;
|
||||
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));
|
||||
}
|
||||
|
||||
config->StringToSettings(_ai_saveload_settings);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
namespace upstream_sl {
|
||||
|
||||
static void Load_APID()
|
||||
{
|
||||
Load_NewGRFMapping(_airport_mngr);
|
||||
}
|
||||
struct APIDChunkHandler : NewGRFMappingChunkHandler {
|
||||
APIDChunkHandler() : NewGRFMappingChunkHandler('APID', _airport_mngr) {}
|
||||
};
|
||||
|
||||
static void Save_ATID()
|
||||
{
|
||||
Save_NewGRFMapping(_airporttile_mngr);
|
||||
}
|
||||
struct ATIDChunkHandler : NewGRFMappingChunkHandler {
|
||||
ATIDChunkHandler() : NewGRFMappingChunkHandler('ATID', _airporttile_mngr) {}
|
||||
};
|
||||
|
||||
static void Load_ATID()
|
||||
{
|
||||
Load_NewGRFMapping(_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 {
|
||||
|
||||
/**
|
||||
* 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);
|
||||
static std::vector <TileIndex> _tmp_animated_tiles;
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
if (anim_list[i] == 0) break;
|
||||
_animated_tiles[anim_list[i]] = {};
|
||||
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;
|
||||
}
|
||||
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()] = {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* "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 },
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
static void Load_ERNW()
|
||||
{
|
||||
int index;
|
||||
void Save() const override
|
||||
{
|
||||
SlTableHeader(_engine_renew_desc);
|
||||
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
EngineRenew *er = new (index) EngineRenew();
|
||||
SlObject(er, _engine_renew_desc);
|
||||
|
||||
/* 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;
|
||||
for (EngineRenew *er : EngineRenew::Iterate()) {
|
||||
SlSetArrayIndex(er->index);
|
||||
SlObject(er, _engine_renew_desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Ptrs_ERNW()
|
||||
{
|
||||
for (EngineRenew *er : EngineRenew::Iterate()) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const ChunkHandler autoreplace_chunk_handlers[] = {
|
||||
{ 'ERNW', Save_ERNW, Load_ERNW, Ptrs_ERNW, nullptr, CH_ARRAY },
|
||||
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,74 +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 bridge_signal_sl.cpp Code handling saving and loading of data for signal on bridges */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "../bridge_signal_map.h"
|
||||
#include "saveload.h"
|
||||
#include <vector>
|
||||
|
||||
/** stub save header struct */
|
||||
struct LongBridgeSignalStorageStub {
|
||||
uint32 length;
|
||||
};
|
||||
|
||||
static const SaveLoad _long_bridge_signal_storage_stub_desc[] = {
|
||||
SLE_VAR(LongBridgeSignalStorageStub, length, SLE_UINT32),
|
||||
};
|
||||
|
||||
static void Load_XBSS()
|
||||
{
|
||||
int index;
|
||||
LongBridgeSignalStorageStub stub;
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
LongBridgeSignalStorage &lbss = _long_bridge_signal_sim_map[index];
|
||||
SlObject(&stub, _long_bridge_signal_storage_stub_desc);
|
||||
lbss.signal_red_bits.resize(stub.length);
|
||||
SlArray(lbss.signal_red_bits.data(), stub.length, SLE_UINT64);
|
||||
}
|
||||
}
|
||||
|
||||
static void RealSave_XBSS(const LongBridgeSignalStorage *lbss)
|
||||
{
|
||||
LongBridgeSignalStorageStub stub;
|
||||
stub.length = (uint32)lbss->signal_red_bits.size();
|
||||
SlObject(&stub, _long_bridge_signal_storage_stub_desc);
|
||||
SlArray(const_cast<uint64*>(lbss->signal_red_bits.data()), stub.length, SLE_UINT64);
|
||||
}
|
||||
|
||||
static void Save_XBSS()
|
||||
{
|
||||
for (const auto &it : _long_bridge_signal_sim_map) {
|
||||
const LongBridgeSignalStorage &lbss = it.second;
|
||||
SlSetArrayIndex(it.first);
|
||||
SlAutolength((AutolengthProc*) RealSave_XBSS, const_cast<LongBridgeSignalStorage*>(&lbss));
|
||||
}
|
||||
}
|
||||
|
||||
static void Load_XBST()
|
||||
{
|
||||
size_t count = SlGetFieldLength() / sizeof(uint32);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
_bridge_signal_style_map.insert(SlReadUint32());
|
||||
}
|
||||
}
|
||||
|
||||
static void Save_XBST()
|
||||
{
|
||||
SlSetLength(_bridge_signal_style_map.size() * sizeof(uint32));
|
||||
for (uint32 val : _bridge_signal_style_map) {
|
||||
SlWriteUint32(val);
|
||||
}
|
||||
}
|
||||
|
||||
extern const ChunkHandler bridge_signal_chunk_handlers[] = {
|
||||
{ 'XBSS', Save_XBSS, Load_XBSS, nullptr, nullptr, CH_SPARSE_ARRAY },
|
||||
{ 'XBST', Save_XBST, Load_XBST, nullptr, nullptr, CH_RIFF },
|
||||
};
|
||||
|
||||
extern const ChunkHandlerTable _bridge_signal_chunk_handlers(bridge_signal_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) {}
|
||||
|
||||
int i = 0;
|
||||
CargoMonitorMap::const_iterator iter = _cargo_deliveries.begin();
|
||||
while (iter != _cargo_deliveries.end()) {
|
||||
storage.number = iter->first;
|
||||
storage.amount = iter->second;
|
||||
void Save() const override
|
||||
{
|
||||
SlTableHeader(_cargomonitor_pair_desc);
|
||||
|
||||
SlSetArrayIndex(i);
|
||||
SlObject(&storage, _cargomonitor_pair_desc);
|
||||
TempStorage storage;
|
||||
|
||||
i++;
|
||||
iter++;
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 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);
|
||||
|
||||
int i = 0;
|
||||
CargoMonitorMap::const_iterator iter = _cargo_pickups.begin();
|
||||
while (iter != _cargo_pickups.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_pickups.begin();
|
||||
while (iter != _cargo_pickups.end()) {
|
||||
storage.number = iter->first;
|
||||
storage.amount = iter->second;
|
||||
|
||||
i++;
|
||||
iter++;
|
||||
SlSetArrayIndex(i);
|
||||
SlObject(&storage, _cargomonitor_pair_desc);
|
||||
|
||||
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 "../vehicle_base.h"
|
||||
#include "../station_base.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();
|
||||
|
||||
for (Station *st : Station::Iterate()) {
|
||||
for (CargoID c = 0; c < NUM_CARGO; c++) st->goods[c].cargo.InvalidateCache();
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
/**
|
||||
* Save cargo packet deferred payments.
|
||||
*/
|
||||
void Save_CPDP()
|
||||
{
|
||||
SlSetLength(16 * _cargo_packet_deferred_payments.size());
|
||||
|
||||
for (auto &it : _cargo_packet_deferred_payments) {
|
||||
SlWriteUint64(it.first);
|
||||
SlWriteUint64(it.second);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
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;
|
||||
|
||||
/** 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 },
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
struct CHTSChunkHandler : ChunkHandler {
|
||||
CHTSChunkHandler() : ChunkHandler('CHTS', CH_TABLE) {}
|
||||
|
||||
/* 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);
|
||||
void Save() const override
|
||||
{
|
||||
SlTableHeader(_cheats_desc);
|
||||
|
||||
if (count == 0) break;
|
||||
SlSetArrayIndex(0);
|
||||
SlObject(&_cheats, _cheats_desc);
|
||||
}
|
||||
|
||||
SlObject(&_cheats, slt);
|
||||
}
|
||||
void Load() const override
|
||||
{
|
||||
std::vector<SaveLoad> slt = SlCompatTableHeader(_cheats_desc, _cheats_sl_compat);
|
||||
|
||||
/**
|
||||
* Load the extra cheat values.
|
||||
*/
|
||||
static void Load_CHTX()
|
||||
{
|
||||
struct CheatsExtLoad {
|
||||
char name[256];
|
||||
Cheat cht;
|
||||
};
|
||||
if (IsSavegameVersionBefore(SLV_TABLE_CHUNKS)) {
|
||||
size_t count = SlGetFieldLength();
|
||||
std::vector<SaveLoad> oslt;
|
||||
|
||||
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),
|
||||
};
|
||||
/* 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);
|
||||
|
||||
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(¤t_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 (count == 0) break;
|
||||
}
|
||||
slt = oslt;
|
||||
}
|
||||
if (!found) {
|
||||
DEBUG(sl, 1, "CHTX chunk: Could not find cheat: '%s'", current_cheat.name);
|
||||
_unknown_cheats[current_cheat.name] = current_cheat.cht;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal structure used in SaveSettingsPatx() and SaveSettingsPlyx()
|
||||
*/
|
||||
struct SettingsExtSave {
|
||||
uint32 flags;
|
||||
const char *name;
|
||||
uint32 setting_length;
|
||||
};
|
||||
|
||||
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),
|
||||
};
|
||||
|
||||
|
||||
/** 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 },
|
||||
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;
|
||||
void SetDefaultCompanySettings(CompanyID cid);
|
||||
|
||||
if (HasBit(face, 31)) SetBit(ge, GENDER_FEMALE);
|
||||
if (HasBit(face, 27) && (HasBit(face, 26) == HasBit(face, 19))) SetBit(ge, ETHNICITY_BLACK);
|
||||
namespace upstream_sl {
|
||||
|
||||
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));
|
||||
/* We do need to read this single value, as the bigger it gets, the more data is stored */
|
||||
struct CompanyOldAI {
|
||||
uint8 num_build_rec;
|
||||
};
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
SetCompanyManagerFaceBits(cmf, CMFV_NOSE, ge, nose);
|
||||
}
|
||||
SaveLoadTable GetDescription() const override { return {}; }
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
return cmf;
|
||||
}
|
||||
|
||||
/** Rebuilding of company statistics after loading a savegame. */
|
||||
void AfterLoadCompanyStats()
|
||||
{
|
||||
/* Reset infrastructure statistics to zero. */
|
||||
for (Company *c : Company::Iterate()) MemSetT(&c->infrastructure, 0);
|
||||
|
||||
/* 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 Load(CompanyOldAI *old_ai) const override
|
||||
{
|
||||
for (int i = 0; i != old_ai->num_build_rec; i++) {
|
||||
SlObject(nullptr, this->GetLoadDescription());
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
void LoadCheck(CompanyOldAI *old_ai) const override { this->Load(old_ai); }
|
||||
};
|
||||
|
||||
if (HasSignals(tile)) c->infrastructure.signal += CountBits(GetPresentSignals(tile));
|
||||
}
|
||||
break;
|
||||
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;
|
||||
|
||||
case MP_ROAD: {
|
||||
if (IsLevelCrossing(tile)) {
|
||||
c = Company::GetIfValid(GetTileOwner(tile));
|
||||
if (c != nullptr) c->infrastructure.rail[GetRailType(tile)] += LEVELCROSSING_TRACKBIT_FACTOR;
|
||||
}
|
||||
void Load(CompanyProperties *c) const override
|
||||
{
|
||||
if (!c->is_ai) return;
|
||||
|
||||
/* 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;
|
||||
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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
case MP_STATION:
|
||||
c = Company::GetIfValid(GetTileOwner(tile));
|
||||
if (c != nullptr && GetStationType(tile) != STATION_AIRPORT && !IsBuoy(tile)) c->infrastructure.station++;
|
||||
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];
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
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),
|
||||
struct PLYRChunkHandler : ChunkHandler {
|
||||
PLYRChunkHandler() : ChunkHandler('PLYR', CH_TABLE) {}
|
||||
|
||||
/* 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)),
|
||||
void Save() const override
|
||||
{
|
||||
SlTableHeader(_company_desc);
|
||||
|
||||
SLE_CONDNULL(63, SLV_2, SLV_144), // old reserved space
|
||||
};
|
||||
|
||||
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),
|
||||
};
|
||||
|
||||
/* 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(¬hing, _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(¬hing, _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);
|
||||
void Load() const override
|
||||
{
|
||||
const std::vector<SaveLoad> slt = SlCompatTableHeader(_company_desc, _company_sl_compat);
|
||||
|
||||
/* 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);
|
||||
int index;
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
Company *c = new (index) Company();
|
||||
SetDefaultCompanySettings(c->index);
|
||||
SlObject((CompanyProperties *)c, slt);
|
||||
_company_colours[index] = (Colours)c->colour;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 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 (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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
void FixPointers() const override
|
||||
{
|
||||
for (Company *c : Company::Iterate()) {
|
||||
SlObject((CompanyProperties *)c, _company_desc);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,94 +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 debug_sl.cpp Code handling saving and loading of debugging information */
|
||||
|
||||
#include "../stdafx.h"
|
||||
|
||||
#include "../debug.h"
|
||||
#include "saveload.h"
|
||||
#include "saveload_buffer.h"
|
||||
#include "../fios.h"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
static void Save_DBGL()
|
||||
{
|
||||
if (_savegame_DBGL_data != nullptr) {
|
||||
size_t length = strlen(_savegame_DBGL_data);
|
||||
SlSetLength(length);
|
||||
MemoryDumper::GetCurrent()->CopyBytes(reinterpret_cast<const byte *>(_savegame_DBGL_data), length);
|
||||
} else {
|
||||
SlSetLength(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void Load_DBGL()
|
||||
{
|
||||
size_t length = SlGetFieldLength();
|
||||
if (length) {
|
||||
_loadgame_DBGL_data.resize(length);
|
||||
ReadBuffer::GetCurrent()->CopyBytes(reinterpret_cast<byte *>(_loadgame_DBGL_data.data()), length);
|
||||
}
|
||||
}
|
||||
|
||||
static void Check_DBGL()
|
||||
{
|
||||
if (!_load_check_data.want_debug_data) {
|
||||
SlSkipBytes(SlGetFieldLength());
|
||||
return;
|
||||
}
|
||||
size_t length = SlGetFieldLength();
|
||||
if (length) {
|
||||
_load_check_data.debug_log_data.resize(length);
|
||||
ReadBuffer::GetCurrent()->CopyBytes(reinterpret_cast<byte *>(_load_check_data.debug_log_data.data()), length);
|
||||
}
|
||||
}
|
||||
|
||||
static void Save_DBGC()
|
||||
{
|
||||
extern std::string _config_file_text;
|
||||
const char header[] = "*** openttd.cfg start ***\n";
|
||||
const char footer[] = "*** openttd.cfg end ***\n";
|
||||
if (_save_DBGC_data) {
|
||||
SlSetLength(lengthof(header) + _config_file_text.size() + lengthof(footer) - 2);
|
||||
MemoryDumper::GetCurrent()->CopyBytes(reinterpret_cast<const byte *>(header), lengthof(header) - 1);
|
||||
MemoryDumper::GetCurrent()->CopyBytes(reinterpret_cast<const byte *>(_config_file_text.data()), _config_file_text.size());
|
||||
MemoryDumper::GetCurrent()->CopyBytes(reinterpret_cast<const byte *>(footer), lengthof(footer) - 1);
|
||||
} else {
|
||||
SlSetLength(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void Load_DBGC()
|
||||
{
|
||||
size_t length = SlGetFieldLength();
|
||||
if (length) {
|
||||
_loadgame_DBGC_data.resize(length);
|
||||
ReadBuffer::GetCurrent()->CopyBytes(reinterpret_cast<byte *>(_loadgame_DBGC_data.data()), length);
|
||||
}
|
||||
}
|
||||
|
||||
static void Check_DBGC()
|
||||
{
|
||||
if (!_load_check_data.want_debug_data) {
|
||||
SlSkipBytes(SlGetFieldLength());
|
||||
return;
|
||||
}
|
||||
size_t length = SlGetFieldLength();
|
||||
if (length) {
|
||||
_load_check_data.debug_config_data.resize(length);
|
||||
ReadBuffer::GetCurrent()->CopyBytes(reinterpret_cast<byte *>(_load_check_data.debug_config_data.data()), length);
|
||||
}
|
||||
}
|
||||
|
||||
extern const ChunkHandler debug_chunk_handlers[] = {
|
||||
{ 'DBGL', Save_DBGL, Load_DBGL, nullptr, Check_DBGL, CH_RIFF },
|
||||
{ 'DBGC', Save_DBGC, Load_DBGC, nullptr, Check_DBGC, CH_RIFF },
|
||||
};
|
||||
|
||||
extern const ChunkHandlerTable _debug_chunk_handlers(debug_chunk_handlers);
|
||||
@@ -8,57 +8,71 @@
|
||||
/** @file depot_sl.cpp Code handling saving and loading of depots */
|
||||
|
||||
#include "../stdafx.h"
|
||||
|
||||
#include "saveload.h"
|
||||
#include "compat/depot_sl_compat.h"
|
||||
|
||||
#include "../depot_base.h"
|
||||
#include "../town.h"
|
||||
|
||||
#include "saveload.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);
|
||||
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
Depot *depot = new (index) Depot();
|
||||
SlObject(depot, _depot_desc);
|
||||
int index;
|
||||
|
||||
/* Set the town 'pointer' so we can restore it later. */
|
||||
if (IsSavegameVersionBefore(SLV_141)) depot->town = (Town *)(size_t)_town_index;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 "saveload.h"
|
||||
#include "compat/economy_sl_compat.h"
|
||||
|
||||
#include "../economy_func.h"
|
||||
#include "../economy_base.h"
|
||||
|
||||
#include "saveload.h"
|
||||
|
||||
#include "../safeguards.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);
|
||||
}
|
||||
|
||||
/** 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) {}
|
||||
|
||||
void Save() const override
|
||||
{
|
||||
SlTableHeader(_cargopayment_desc);
|
||||
|
||||
for (CargoPayment *cp : CargoPayment::Iterate()) {
|
||||
SlSetArrayIndex(cp->index);
|
||||
SlObject(cp, _cargopayment_desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Load_CAPY()
|
||||
{
|
||||
int index;
|
||||
void Load() const override
|
||||
{
|
||||
const std::vector<SaveLoad> slt = SlCompatTableHeader(_cargopayment_desc, _cargopayment_sl_compat);
|
||||
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
CargoPayment *cp = new (index) CargoPayment();
|
||||
SlObject(cp, _cargopayment_desc);
|
||||
int index;
|
||||
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
CargoPayment *cp = new (index) CargoPayment();
|
||||
SlObject(cp, slt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Ptrs_CAPY()
|
||||
{
|
||||
for (CargoPayment *cp : CargoPayment::Iterate()) {
|
||||
SlObject(cp, _cargopayment_desc);
|
||||
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;
|
||||
struct ENGNChunkHandler : ChunkHandler {
|
||||
ENGNChunkHandler() : ChunkHandler('ENGN', CH_TABLE) {}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
void Save() const override
|
||||
{
|
||||
SlTableHeader(_engine_desc);
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
|
||||
static void Save_ENGN()
|
||||
{
|
||||
for (Engine *e : Engine::Iterate()) {
|
||||
SlSetArrayIndex(e->index);
|
||||
SlObject(e, _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;
|
||||
void Load() const override
|
||||
{
|
||||
const std::vector<SaveLoad> slt = SlCompatTableHeader(_engine_desc, _engine_sl_compat);
|
||||
|
||||
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;
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** 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) {}
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Load_EIDS()
|
||||
{
|
||||
_engine_mngr.clear();
|
||||
void Load() const override
|
||||
{
|
||||
const std::vector<SaveLoad> slt = SlCompatTableHeader(_engine_id_mapping_desc, _engine_id_mapping_sl_compat);
|
||||
|
||||
while (SlIterateArray() != -1) {
|
||||
EngineIDMapping *eid = &_engine_mngr.emplace_back();
|
||||
SlObject(eid, _engine_id_mapping_desc);
|
||||
_engine_mngr.clear();
|
||||
|
||||
while (SlIterateArray() != -1) {
|
||||
EngineIDMapping *eid = &_engine_mngr.emplace_back();
|
||||
SlObject(eid, slt);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void AfterLoadEngines()
|
||||
{
|
||||
AnalyseEngineCallbacks();
|
||||
}
|
||||
|
||||
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 },
|
||||
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,758 +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 extended_ver_sl.cpp Functions related to handling save/load extended version info.
|
||||
*
|
||||
* Known extended features are stored in _sl_xv_feature_versions, features which are currently enabled/in use and their versions are stored in the savegame.
|
||||
* On load, the list of features and their versions are loaded from the savegame. If the savegame contains a feature which is either unknown, or has too high a version,
|
||||
* loading can be either aborted, or the feature can be ignored if the the feature flags in the savegame indicate that it can be ignored. The savegame may also list any additional
|
||||
* chunk IDs which are associated with an extended feature, these can be discarded if the feature is discarded.
|
||||
* This information is stored in the SLXI chunk, the contents of which has the following format:
|
||||
*
|
||||
* uint32 chunk version
|
||||
* uint32 chunk flags
|
||||
* uint32 number of sub chunks/features
|
||||
* For each of N sub chunk/feature:
|
||||
* uint32 feature flags (SlxiSubChunkFlags)
|
||||
* uint16 feature version
|
||||
* SLE_STR feature name
|
||||
* uint32* extra data length [only present iff feature flags & XSCF_EXTRA_DATA_PRESENT]
|
||||
* N bytes extra data
|
||||
* uint32* chunk ID list count [only present iff feature flags & XSCF_CHUNK_ID_LIST_PRESENT]
|
||||
* N x uint32 chunk ID list
|
||||
*
|
||||
* Extended features as recorded in the SLXI chunk, above, MAY add, remove, change, or otherwise modify fields in chunks
|
||||
* not owned by the feature and therefore not listed in the sub chunk/feature information in the SLXI chunk.
|
||||
* In this case the XSCF_IGNORABLE_UNKNOWN flag SHOULD NOT be set, as it is not possible to correctly load the modified chunk without
|
||||
* knowledge of the feature.
|
||||
* In the case where the modifications to other chunks vary with respect to lower feature versions, the XSCF_IGNORABLE_VERSION flag
|
||||
* also SHOULD NOT be set.
|
||||
* Use of the XSCF_IGNORABLE_UNKNOWN and XSCF_IGNORABLE_VERSION flags MUST ONLY be used in the cases where the feature and any
|
||||
* associated chunks can be cleanly dropped, and the savegame can be correctly loaded by a client with no knowledge of the feature.
|
||||
*/
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "../debug.h"
|
||||
#include "saveload.h"
|
||||
#include "saveload_buffer.h"
|
||||
#include "extended_ver_sl.h"
|
||||
#include "../timetable.h"
|
||||
#include "../map_func.h"
|
||||
#include "../rev.h"
|
||||
#include "../strings_func.h"
|
||||
#include "../company_func.h"
|
||||
#include "table/strings.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
std::array<uint16, XSLFI_SIZE> _sl_xv_feature_versions; ///< array of all known feature types and their current versions
|
||||
std::array<uint16, XSLFI_SIZE> _sl_xv_feature_static_versions; ///< array of all known feature types and their static current version versions
|
||||
bool _sl_is_ext_version; ///< is this an extended savegame version, with more info in the SLXI chunk?
|
||||
bool _sl_is_faked_ext; ///< is this a faked extended savegame version, with no SLXI chunk? See: SlXvCheckSpecialSavegameVersions.
|
||||
bool _sl_maybe_springpp; ///< is this possibly a SpringPP savegame?
|
||||
bool _sl_maybe_chillpp; ///< is this possibly a ChillPP v8 savegame?
|
||||
bool _sl_upstream_mode; ///< load game using upstream loader
|
||||
std::vector<uint32> _sl_xv_discardable_chunk_ids; ///< list of chunks IDs which we can discard if no chunk loader exists
|
||||
std::string _sl_xv_version_label; ///< optional SLXI version label
|
||||
SaveLoadVersion _sl_xv_upstream_version; ///< optional SLXI upstream version
|
||||
|
||||
static const uint32 _sl_xv_slxi_chunk_version = 0; ///< current version of SLXI chunk
|
||||
|
||||
static void loadVL(const SlxiSubChunkInfo *info, uint32 length);
|
||||
static uint32 saveVL(const SlxiSubChunkInfo *info, bool dry_run);
|
||||
static void loadUV(const SlxiSubChunkInfo *info, uint32 length);
|
||||
static uint32 saveUV(const SlxiSubChunkInfo *info, bool dry_run);
|
||||
static void loadLC(const SlxiSubChunkInfo *info, uint32 length);
|
||||
static uint32 saveLC(const SlxiSubChunkInfo *info, bool dry_run);
|
||||
|
||||
const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
|
||||
{ XSLFI_VERSION_LABEL, XSCF_IGNORABLE_ALL, 1, 1, "version_label", saveVL, loadVL, nullptr },
|
||||
{ XSLFI_UPSTREAM_VERSION, XSCF_NULL, 1, 1, "upstream_version", saveUV, loadUV, nullptr },
|
||||
{ XSLFI_TRACE_RESTRICT, XSCF_NULL, 15, 15, "tracerestrict", nullptr, nullptr, "TRRM,TRRP,TRRS" },
|
||||
{ XSLFI_TRACE_RESTRICT_OWNER, XSCF_NULL, 1, 1, "tracerestrict_owner", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_TRACE_RESTRICT_ORDRCND, XSCF_NULL, 4, 4, "tracerestrict_order_cond", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_TRACE_RESTRICT_STATUSCND, XSCF_NULL, 2, 2, "tracerestrict_status_cond", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_TRACE_RESTRICT_REVERSE, XSCF_NULL, 1, 1, "tracerestrict_reverse", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_TRACE_RESTRICT_NEWSCTRL, XSCF_NULL, 1, 1, "tracerestrict_newsctrl", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_TRACE_RESTRICT_COUNTER, XSCF_NULL, 1, 1, "tracerestrict_counter", nullptr, nullptr, "TRRC" },
|
||||
{ XSLFI_TRACE_RESTRICT_TIMEDATE, XSCF_NULL, 2, 2, "tracerestrict_timedate", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_TRACE_RESTRICT_BRKCND, XSCF_NULL, 3, 3, "tracerestrict_braking_cond", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_TRACE_RESTRICT_CTGRYCND, XSCF_NULL, 1, 1, "tracerestrict_ctgry_cond", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_TRACE_RESTRICT_PENCTRL, XSCF_NULL, 1, 1, "tracerestrict_pfpenctrl", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_TRACE_RESTRICT_TUNBRIDGE, XSCF_NULL, 1, 1, "tracerestrict_sigtunbridge", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_TRACE_RESTRICT_SPDADAPTCTRL, XSCF_NULL, 1, 1, "tracerestrict_spdadaptctrl", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_PROG_SIGS, XSCF_NULL, 2, 2, "programmable_signals", nullptr, nullptr, "SPRG" },
|
||||
{ XSLFI_ADJACENT_CROSSINGS, XSCF_NULL, 1, 1, "adjacent_crossings", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_SAFER_CROSSINGS, XSCF_NULL, 1, 1, "safer_crossings", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_DEPARTURE_BOARDS, XSCF_IGNORABLE_UNKNOWN, 1, 1, "departure_boards", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_TIMETABLES_START_TICKS, XSCF_NULL, 2, 2, "timetable_start_ticks", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_TOWN_CARGO_ADJ, XSCF_IGNORABLE_UNKNOWN, 2, 2, "town_cargo_adj", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_SIG_TUNNEL_BRIDGE, XSCF_NULL, 10, 10, "signal_tunnel_bridge", nullptr, nullptr, "XBSS" },
|
||||
{ XSLFI_IMPROVED_BREAKDOWNS, XSCF_NULL, 8, 8, "improved_breakdowns", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_CONSIST_BREAKDOWN_FLAG, XSCF_NULL, 1, 1, "consist_breakdown_flag", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_TT_WAIT_IN_DEPOT, XSCF_NULL, 1, 1, "tt_wait_in_depot", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_AUTO_TIMETABLE, XSCF_NULL, 5, 5, "auto_timetables", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_VEHICLE_REPAIR_COST, XSCF_NULL, 2, 2, "vehicle_repair_cost", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_ENH_VIEWPORT_PLANS, XSCF_IGNORABLE_ALL, 4, 4, "enh_viewport_plans", nullptr, nullptr, "PLAN" },
|
||||
{ XSLFI_INFRA_SHARING, XSCF_NULL, 2, 2, "infra_sharing", nullptr, nullptr, "CPDP" },
|
||||
{ XSLFI_VARIABLE_DAY_LENGTH, XSCF_NULL, 3, 3, "variable_day_length", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_ORDER_OCCUPANCY, XSCF_NULL, 2, 2, "order_occupancy", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_MORE_COND_ORDERS, XSCF_NULL, 14, 14, "more_cond_orders", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_EXTRA_LARGE_MAP, XSCF_NULL, 0, 1, "extra_large_map", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_REVERSE_AT_WAYPOINT, XSCF_NULL, 1, 1, "reverse_at_waypoint", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_VEH_LIFETIME_PROFIT, XSCF_NULL, 1, 1, "veh_lifetime_profit", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_LINKGRAPH_DAY_SCALE, XSCF_NULL, 3, 3, "linkgraph_day_scale", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_TEMPLATE_REPLACEMENT, XSCF_NULL, 9, 9, "template_replacement", nullptr, nullptr, "TRPL,TMPL" },
|
||||
{ XSLFI_MORE_RAIL_TYPES, XSCF_NULL, 0, 1, "more_rail_types", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_CARGO_TYPE_ORDERS, XSCF_NULL, 3, 3, "cargo_type_orders", nullptr, nullptr, "ORDX,VEOX" },
|
||||
{ XSLFI_EXTENDED_GAMELOG, XSCF_NULL, 1, 1, "extended_gamelog", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_STATION_CATCHMENT_INC, XSCF_NULL, 1, 1, "station_catchment_inc", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_CUSTOM_BRIDGE_HEADS, XSCF_NULL, 4, 4, "custom_bridge_heads", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_CHUNNEL, XSCF_NULL, 2, 2, "chunnel", nullptr, nullptr, "TUNN" },
|
||||
{ XSLFI_SCHEDULED_DISPATCH, XSCF_NULL, 4, 4, "scheduled_dispatch", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_MORE_TOWN_GROWTH_RATES, XSCF_NULL, 1, 1, "more_town_growth_rates", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_MULTIPLE_DOCKS, XSCF_NULL, 2, 2, "multiple_docks", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_TIMETABLE_EXTRA, XSCF_NULL, 7, 7, "timetable_extra", nullptr, nullptr, "ORDX" },
|
||||
{ XSLFI_TRAIN_FLAGS_EXTRA, XSCF_NULL, 1, 1, "train_flags_extra", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_VEHICLE_FLAGS_EXTRA, XSCF_NULL, 1, 1, "veh_flags_extra", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_TRAIN_THROUGH_LOAD, XSCF_NULL, 2, 2, "train_through_load", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_ORDER_EXTRA_DATA, XSCF_NULL, 2, 2, "order_extra_data", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_WHOLE_MAP_CHUNK, XSCF_NULL, 2, 2, "whole_map_chunk", nullptr, nullptr, "WMAP" },
|
||||
{ XSLFI_ST_LAST_VEH_TYPE, XSCF_NULL, 1, 1, "station_last_veh_type", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_SELL_AT_DEPOT_ORDER, XSCF_NULL, 1, 1, "sell_at_depot_order", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_BUY_LAND_RATE_LIMIT, XSCF_NULL, 1, 1, "buy_land_rate_limit", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_DUAL_RAIL_TYPES, XSCF_NULL, 1, 1, "dual_rail_types", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_CONSIST_SPEED_RD_FLAG, XSCF_NULL, 1, 1, "consist_speed_rd_flag", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_SAVEGAME_UNIQUE_ID, XSCF_IGNORABLE_ALL, 1, 1, "savegame_unique_id", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_RV_OVERTAKING, XSCF_NULL, 2, 2, "roadveh_overtaking", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_LINKGRAPH_MODES, XSCF_NULL, 1, 1, "linkgraph_modes", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_GAME_EVENTS, XSCF_NULL, 1, 1, "game_events", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_ROAD_LAYOUT_CHANGE_CTR, XSCF_NULL, 1, 1, "road_layout_change_ctr", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_TOWN_CARGO_MATRIX, XSCF_NULL, 0, 1, "town_cargo_matrix", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_STATE_CHECKSUM, XSCF_NULL, 1, 1, "state_checksum", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_DEBUG, XSCF_IGNORABLE_ALL, 1, 1, "debug", nullptr, nullptr, "DBGL,DBGC" },
|
||||
{ XSLFI_FLOW_STAT_FLAGS, XSCF_NULL, 1, 1, "flow_stat_flags", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_SPEED_RESTRICTION, XSCF_NULL, 1, 1, "speed_restriction", nullptr, nullptr, "VESR" },
|
||||
{ XSLFI_STATION_GOODS_EXTRA, XSCF_NULL, 1, 1, "station_goods_extra", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_DOCKING_CACHE_VER, XSCF_IGNORABLE_ALL, 3, 3, "docking_cache_ver", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_EXTRA_CHEATS, XSCF_NULL, 1, 1, "extra_cheats", nullptr, nullptr, "CHTX" },
|
||||
{ XSLFI_TOWN_MULTI_BUILDING, XSCF_NULL, 1, 1, "town_multi_building", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_SHIP_LOST_COUNTER, XSCF_NULL, 1, 1, "ship_lost_counter", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_BUILD_OBJECT_RATE_LIMIT, XSCF_NULL, 1, 1, "build_object_rate_limit", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_LOCAL_COMPANY, XSCF_IGNORABLE_ALL, 1, 1, "local_company", saveLC, loadLC, nullptr },
|
||||
{ XSLFI_THROUGH_TRAIN_DEPOT, XSCF_NULL, 1, 1, "drive_through_train_depot", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_MORE_VEHICLE_ORDERS, XSCF_NULL, 1, 1, "more_veh_orders", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_ORDER_FLAGS_EXTRA, XSCF_NULL, 1, 1, "order_flags_extra", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_ONE_WAY_DT_ROAD_STOP, XSCF_NULL, 1, 1, "one_way_dt_road_stop", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_ONE_WAY_ROAD_STATE, XSCF_NULL, 1, 1, "one_way_road_state", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_VENC_CHUNK, XSCF_IGNORABLE_ALL, 0, 1, "venc_chunk", nullptr, nullptr, "VENC" },
|
||||
{ XSLFI_ANIMATED_TILE_EXTRA, XSCF_NULL, 1, 1, "animated_tile_extra", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_NEWGRF_INFO_EXTRA, XSCF_NULL, 1, 1, "newgrf_info_extra", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_INDUSTRY_CARGO_ADJ, XSCF_IGNORABLE_UNKNOWN, 1, 1, "industry_cargo_adj", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_REALISTIC_TRAIN_BRAKING, XSCF_NULL, 9, 9, "realistic_train_braking", nullptr, nullptr, "VLKA" },
|
||||
{ XSLFI_INFLATION_FIXED_DATES, XSCF_IGNORABLE_ALL, 1, 1, "inflation_fixed_dates", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_WATER_FLOODING, XSCF_NULL, 2, 2, "water_flooding", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_MORE_HOUSES, XSCF_NULL, 2, 2, "more_houses", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_CUSTOM_TOWN_ZONE, XSCF_IGNORABLE_UNKNOWN, 1, 1, "custom_town_zone", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_STATION_CARGO_HISTORY, XSCF_NULL, 2, 2, "station_cargo_history", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_TRAIN_SPEED_ADAPTATION, XSCF_NULL, 2, 2, "train_speed_adaptation", nullptr, nullptr, "TSAS" },
|
||||
{ XSLFI_EXTRA_STATION_NAMES, XSCF_NULL, 1, 1, "extra_station_names", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_DEPOT_ORDER_EXTRA_FLAGS, XSCF_IGNORABLE_UNKNOWN, 1, 1, "depot_order_extra_flags", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_EXTRA_SIGNAL_TYPES, XSCF_NULL, 1, 1, "extra_signal_types", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_BANKRUPTCY_EXTRA, XSCF_NULL, 2, 2, "bankruptcy_extra", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_OBJECT_GROUND_TYPES, XSCF_NULL, 3, 3, "object_ground_types", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_LINKGRAPH_AIRCRAFT, XSCF_NULL, 1, 1, "linkgraph_aircraft", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_COMPANY_PW, XSCF_IGNORABLE_ALL, 2, 2, "company_password", nullptr, nullptr, "PLYP" },
|
||||
{ XSLFI_ST_INDUSTRY_CARGO_MODE, XSCF_IGNORABLE_UNKNOWN, 1, 1, "st_industry_cargo_mode", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_TL_SPEED_LIMIT, XSCF_IGNORABLE_UNKNOWN, 1, 1, "tl_speed_limit", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_RAIL_DEPOT_SPEED_LIMIT, XSCF_IGNORABLE_UNKNOWN, 1, 1, "rail_depot_speed_limit", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_WAYPOINT_FLAGS, XSCF_NULL, 1, 1, "waypoint_flags", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_ROAD_WAYPOINTS, XSCF_NULL, 1, 1, "road_waypoints", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_MORE_STATION_TYPES, XSCF_NULL, 1, 1, "more_station_types", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_RV_ORDER_EXTRA_FLAGS, XSCF_IGNORABLE_UNKNOWN, 1, 1, "rv_order_extra_flags", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_GRF_ROADSTOPS, XSCF_NULL, 3, 3, "grf_road_stops", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_INDUSTRY_ANIM_MASK, XSCF_IGNORABLE_ALL, 1, 1, "industry_anim_mask", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_NEW_SIGNAL_STYLES, XSCF_NULL, 2, 2, "new_signal_styles", nullptr, nullptr, "XBST,NSID" },
|
||||
{ XSLFI_NO_TREE_COUNTER, XSCF_IGNORABLE_ALL, 1, 1, "no_tree_counter", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_TOWN_SETTING_OVERRIDE, XSCF_NULL, 1, 1, "town_setting_override", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_LINKGRAPH_SPARSE_EDGES, XSCF_NULL, 1, 1, "linkgraph_sparse_edges", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_AUX_TILE_LOOP, XSCF_NULL, 1, 1, "aux_tile_loop", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_NEWGRF_ENTITY_EXTRA, XSCF_NULL, 2, 2, "newgrf_entity_extra", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_TNNC_CHUNK, XSCF_IGNORABLE_ALL, 0, 1, "tnnc_chunk", nullptr, nullptr, "TNNC" },
|
||||
{ XSLFI_MULTI_CARGO_SHIPS, XSCF_NULL, 1, 1, "multi_cargo_ships", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_REMAIN_NEXT_ORDER_STATION, XSCF_IGNORABLE_UNKNOWN, 1, 1, "remain_next_order_station", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_LABEL_ORDERS, XSCF_NULL, 2, 2, "label_orders", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_VARIABLE_TICK_RATE, XSCF_IGNORABLE_ALL, 1, 1, "variable_tick_rate", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_SCRIPT_INT64, XSCF_NULL, 1, 1, "script_int64", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_U64_TICK_COUNTER, XSCF_NULL, 1, 1, "u64_tick_counter", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_LINKGRAPH_TRAVEL_TIME, XSCF_NULL, 1, 1, "linkgraph_travel_time", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_LAST_LOADING_TICK, XSCF_NULL, 2, 2, "last_loading_tick", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_SCRIPT_LEAGUE_TABLES, XSCF_NULL, 1, 1, "script_league_tables", nullptr, nullptr, "LEAE,LEAT" },
|
||||
{ XSLFI_VELOCITY_NAUTICAL, XSCF_IGNORABLE_ALL, 1, 1, "velocity_nautical", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_CONSISTENT_PARTIAL_Z, XSCF_NULL, 1, 1, "consistent_partial_z", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_MORE_CARGO_AGE, XSCF_NULL, 1, 1, "more_cargo_age", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_AI_START_DATE, XSCF_NULL, 1, 1, "slv_ai_start_date", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_EXTEND_VEHICLE_RANDOM, XSCF_NULL, 1, 1, "slv_extend_vehicle_random", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_DISASTER_VEH_STATE, XSCF_NULL, 1, 1, "slv_disaster_veh_state", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_NULL, XSCF_NULL, 0, 0, nullptr, nullptr, nullptr, nullptr },// This is the end marker
|
||||
};
|
||||
|
||||
/**
|
||||
* Extended save/load feature test
|
||||
*
|
||||
* First performs a tradional check on the provided @p savegame_version against @p savegame_version_from and @p savegame_version_to.
|
||||
* Then, if the feature set in the constructor is not XSLFI_NULL, also check than the feature version is inclusively bounded by @p min_version and @p max_version,
|
||||
* and return the combination of the two tests using the operator defined in the constructor.
|
||||
* Otherwise just returns the result of the savegame version test
|
||||
*/
|
||||
bool SlXvFeatureTest::IsFeaturePresent(const std::array<uint16, XSLFI_SIZE> &feature_versions, SaveLoadVersion savegame_version, SaveLoadVersion savegame_version_from, SaveLoadVersion savegame_version_to) const
|
||||
{
|
||||
bool savegame_version_ok = savegame_version >= savegame_version_from && savegame_version < savegame_version_to;
|
||||
|
||||
if (this->functor) return (*this->functor)(savegame_version, savegame_version_ok, feature_versions);
|
||||
|
||||
if (this->feature == XSLFI_NULL) return savegame_version_ok;
|
||||
|
||||
bool feature_ok = SlXvIsFeaturePresent(feature_versions, this->feature, this->min_version, this->max_version);
|
||||
|
||||
switch (op) {
|
||||
case XSLFTO_OR:
|
||||
return savegame_version_ok || feature_ok;
|
||||
|
||||
case XSLFTO_AND:
|
||||
return savegame_version_ok && feature_ok;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if @p feature is present and has a version inclusively bounded by @p min_version and @p max_version
|
||||
*/
|
||||
bool SlXvIsFeaturePresent(const std::array<uint16, XSLFI_SIZE> &feature_versions, SlXvFeatureIndex feature, uint16 min_version, uint16 max_version)
|
||||
{
|
||||
assert(feature < XSLFI_SIZE);
|
||||
return feature_versions[feature] >= min_version && feature_versions[feature] <= max_version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if @p feature is present and has a version inclusively bounded by @p min_version and @p max_version
|
||||
*/
|
||||
const char *SlXvGetFeatureName(SlXvFeatureIndex feature)
|
||||
{
|
||||
const SlxiSubChunkInfo *info = _sl_xv_sub_chunk_infos;
|
||||
for (; info->index != XSLFI_NULL; ++info) {
|
||||
if (info->index == feature) {
|
||||
return info->name;
|
||||
}
|
||||
}
|
||||
return "(unknown feature)";
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets all extended feature versions to 0
|
||||
*/
|
||||
void SlXvResetState()
|
||||
{
|
||||
_sl_is_ext_version = false;
|
||||
_sl_is_faked_ext = false;
|
||||
_sl_maybe_springpp = false;
|
||||
_sl_maybe_chillpp = false;
|
||||
_sl_upstream_mode = false;
|
||||
_sl_xv_discardable_chunk_ids.clear();
|
||||
std::fill(_sl_xv_feature_versions.begin(), _sl_xv_feature_versions.end(), 0);
|
||||
_sl_xv_version_label.clear();
|
||||
_sl_xv_upstream_version = SL_MIN_VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets all extended feature versions to their currently enabled versions, i.e. versions suitable for saving
|
||||
*/
|
||||
void SlXvSetCurrentState()
|
||||
{
|
||||
SlXvResetState();
|
||||
_sl_is_ext_version = true;
|
||||
|
||||
const SlxiSubChunkInfo *info = _sl_xv_sub_chunk_infos;
|
||||
for (; info->index != XSLFI_NULL; ++info) {
|
||||
_sl_xv_feature_versions[info->index] = info->save_version;
|
||||
}
|
||||
if (MapSizeX() > 8192 || MapSizeY() > 8192) {
|
||||
_sl_xv_feature_versions[XSLFI_EXTRA_LARGE_MAP] = 1;
|
||||
}
|
||||
if (IsScenarioSave()) {
|
||||
_sl_xv_feature_versions[XSLFI_WHOLE_MAP_CHUNK] = 0;
|
||||
}
|
||||
if (IsNetworkServerSave()) {
|
||||
_sl_xv_feature_versions[XSLFI_VENC_CHUNK] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_TNNC_CHUNK] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all extended feature versions in the current static version array to their currently enabled versions, i.e. versions suitable for saving
|
||||
*/
|
||||
void SlXvSetStaticCurrentVersions()
|
||||
{
|
||||
std::fill(_sl_xv_feature_static_versions.begin(), _sl_xv_feature_static_versions.end(), 0);
|
||||
|
||||
const SlxiSubChunkInfo *info = _sl_xv_sub_chunk_infos;
|
||||
for (; info->index != XSLFI_NULL; ++info) {
|
||||
_sl_xv_feature_static_versions[info->index] = info->save_version;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for "special" savegame versions (i.e. known patchpacks) and set correct savegame version, settings, etc.
|
||||
*/
|
||||
bool SlXvCheckSpecialSavegameVersions()
|
||||
{
|
||||
// Checks for special savegame versions go here
|
||||
extern SaveLoadVersion _sl_version;
|
||||
|
||||
if (_sl_version == SL_TRACE_RESTRICT_2000) {
|
||||
DEBUG(sl, 1, "Loading a trace restrict patch savegame version %d as version 194", _sl_version);
|
||||
_sl_version = SLV_194;
|
||||
_sl_is_faked_ext = true;
|
||||
_sl_xv_feature_versions[XSLFI_TRACE_RESTRICT] = 1;
|
||||
return true;
|
||||
}
|
||||
if (_sl_version == SL_TRACE_RESTRICT_2001) {
|
||||
DEBUG(sl, 1, "Loading a trace restrict patch savegame version %d as version 195", _sl_version);
|
||||
_sl_version = SLV_195;
|
||||
_sl_is_faked_ext = true;
|
||||
_sl_xv_feature_versions[XSLFI_TRACE_RESTRICT] = 6;
|
||||
return true;
|
||||
}
|
||||
if (_sl_version == SL_TRACE_RESTRICT_2002) {
|
||||
DEBUG(sl, 1, "Loading a trace restrict patch savegame version %d as version 196", _sl_version);
|
||||
_sl_version = SLV_196;
|
||||
_sl_is_faked_ext = true;
|
||||
_sl_xv_feature_versions[XSLFI_TRACE_RESTRICT] = 6;
|
||||
return true;
|
||||
}
|
||||
if (_sl_version >= SL_SPRING_2013_v2_0_102 && _sl_version <= SL_SPRING_2013_v2_4) { /* 220 - 227 */
|
||||
_sl_maybe_springpp = true;
|
||||
return true;
|
||||
}
|
||||
if (_sl_version >= SL_JOKER_1_19 && _sl_version <= SL_JOKER_1_27) { /* 278 - 286 */
|
||||
DEBUG(sl, 1, "Loading a JokerPP savegame version %d as version 197", _sl_version);
|
||||
_sl_xv_feature_versions[XSLFI_JOKERPP] = _sl_version;
|
||||
_sl_xv_feature_versions[XSLFI_TOWN_CARGO_ADJ] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_TEMPLATE_REPLACEMENT] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_VEH_LIFETIME_PROFIT] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_TRAIN_FLAGS_EXTRA] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_SIG_TUNNEL_BRIDGE] = 5;
|
||||
_sl_xv_feature_versions[XSLFI_REVERSE_AT_WAYPOINT] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_MULTIPLE_DOCKS] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_ST_LAST_VEH_TYPE] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_MORE_RAIL_TYPES] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_CHUNNEL] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_MORE_COND_ORDERS] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_TRACE_RESTRICT] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_CARGO_TYPE_ORDERS] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_RAIL_AGEING] = 1;
|
||||
if (_sl_version >= SL_JOKER_1_21) _sl_xv_feature_versions[XSLFI_LINKGRAPH_DAY_SCALE] = 1;
|
||||
if (_sl_version >= SL_JOKER_1_24) _sl_xv_feature_versions[XSLFI_TIMETABLE_EXTRA] = 1;
|
||||
if (_sl_version >= SL_JOKER_1_24) _sl_xv_feature_versions[XSLFI_ORDER_EXTRA_DATA] = 1;
|
||||
_sl_xv_discardable_chunk_ids.push_back('SPRG');
|
||||
_sl_xv_discardable_chunk_ids.push_back('SLNK');
|
||||
_sl_version = SLV_197;
|
||||
_sl_is_faked_ext = true;
|
||||
return true;
|
||||
}
|
||||
if (_sl_version == SL_CHILLPP_201) { /* 232 - 233 */
|
||||
_sl_maybe_chillpp = true;
|
||||
return true;
|
||||
}
|
||||
if (_sl_version >= SL_CHILLPP_232 && _sl_version <= SL_CHILLPP_233) { /* 232 - 233 */
|
||||
DEBUG(sl, 1, "Loading a ChillPP v14.7 savegame version %d as version 160", _sl_version);
|
||||
_sl_xv_feature_versions[XSLFI_CHILLPP] = _sl_version;
|
||||
_sl_xv_feature_versions[XSLFI_ZPOS_32_BIT] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_TOWN_CARGO_ADJ] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_TRAFFIC_LIGHTS] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_IMPROVED_BREAKDOWNS] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_INFRA_SHARING] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_AUTO_TIMETABLE] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_SIG_TUNNEL_BRIDGE] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_RAIL_AGEING] = 1;
|
||||
_sl_xv_discardable_chunk_ids.push_back('LGRP');
|
||||
_sl_xv_discardable_chunk_ids.push_back('SSIG');
|
||||
_sl_version = SLV_160;
|
||||
_sl_is_faked_ext = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SlXvSpringPPSpecialSavegameVersions()
|
||||
{
|
||||
extern SaveLoadVersion _sl_version;
|
||||
|
||||
if (_sl_version == SL_SPRING_2013_v2_0_102) { /* 220 */
|
||||
DEBUG(sl, 1, "Loading a SpringPP 2013 v2.0.102 savegame version %d as version 187", _sl_version);
|
||||
|
||||
_sl_version = SLV_187;
|
||||
_sl_is_faked_ext = true;
|
||||
_sl_xv_feature_versions[XSLFI_SPRINGPP] = 1;
|
||||
} else if (_sl_version == SL_SPRING_2013_v2_1_108) { /* 221 */
|
||||
DEBUG(sl, 1, "Loading a SpringPP 2013 v2.1.108 savegame version %d as version 188", _sl_version);
|
||||
|
||||
_sl_version = SLV_188;
|
||||
_sl_is_faked_ext = true;
|
||||
_sl_xv_feature_versions[XSLFI_SPRINGPP] = 2;
|
||||
} else if (_sl_version == SL_SPRING_2013_v2_1_147) { /* 222 */
|
||||
DEBUG(sl, 1, "Loading a SpringPP 2013 v2.1.147 savegame version %d as version 194", _sl_version);
|
||||
|
||||
_sl_version = SLV_194;
|
||||
_sl_is_faked_ext = true;
|
||||
_sl_xv_feature_versions[XSLFI_SPRINGPP] = 4; // Note that this break in numbering is deliberate
|
||||
} else if (_sl_version == SL_SPRING_2013_v2_3_XXX) { /* 223 */
|
||||
DEBUG(sl, 1, "Loading a SpringPP 2013 v2.3.xxx savegame version %d as version 194", _sl_version);
|
||||
|
||||
_sl_version = SLV_194;
|
||||
_sl_is_faked_ext = true;
|
||||
_sl_xv_feature_versions[XSLFI_SPRINGPP] = 3; // Note that this break in numbering is deliberate
|
||||
} else if (_sl_version == SL_SPRING_2013_v2_3_b3) { /* 224 */
|
||||
DEBUG(sl, 1, "Loading a SpringPP 2013 v2.3.b3 savegame version %d as version 194", _sl_version);
|
||||
|
||||
_sl_version = SLV_194;
|
||||
_sl_is_faked_ext = true;
|
||||
_sl_xv_feature_versions[XSLFI_SPRINGPP] = 5;
|
||||
} else if (_sl_version == SL_SPRING_2013_v2_3_b4) { /* 225 */
|
||||
DEBUG(sl, 1, "Loading a SpringPP 2013 v2.3.b4 savegame version %d as version 194", _sl_version);
|
||||
|
||||
_sl_version = SLV_194;
|
||||
_sl_is_faked_ext = true;
|
||||
_sl_xv_feature_versions[XSLFI_SPRINGPP] = 6;
|
||||
} else if (_sl_version == SL_SPRING_2013_v2_3_b5) { /* 226 */
|
||||
DEBUG(sl, 1, "Loading a SpringPP 2013 v2.3.b5 savegame version %d as version 195", _sl_version);
|
||||
|
||||
_sl_version = SLV_195;
|
||||
_sl_is_faked_ext = true;
|
||||
_sl_xv_feature_versions[XSLFI_SPRINGPP] = 7;
|
||||
} else if (_sl_version == SL_SPRING_2013_v2_4) { /* 227 */
|
||||
DEBUG(sl, 1, "Loading a SpringPP 2013 v2.4 savegame version %d as version 195", _sl_version);
|
||||
|
||||
_sl_version = SLV_195;
|
||||
_sl_is_faked_ext = true;
|
||||
_sl_xv_feature_versions[XSLFI_SPRINGPP] = 8;
|
||||
}
|
||||
|
||||
if (_sl_xv_feature_versions[XSLFI_SPRINGPP]) {
|
||||
_sl_xv_feature_versions[XSLFI_RIFF_HEADER_60_BIT] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_HEIGHT_8_BIT] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_MIGHT_USE_PAX_SIGNALS] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_TRAFFIC_LIGHTS] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_RAIL_AGEING] = 1;
|
||||
|
||||
_sl_xv_feature_versions[XSLFI_TIMETABLES_START_TICKS] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_VEHICLE_REPAIR_COST] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_IMPROVED_BREAKDOWNS] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_INFRA_SHARING] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_AUTO_TIMETABLE] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_MORE_COND_ORDERS] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_SIG_TUNNEL_BRIDGE] = 1;
|
||||
|
||||
_sl_xv_discardable_chunk_ids.push_back('SNOW');
|
||||
}
|
||||
}
|
||||
|
||||
void SlXvChillPPSpecialSavegameVersions()
|
||||
{
|
||||
extern SaveLoadVersion _sl_version;
|
||||
|
||||
if (_sl_version == SL_CHILLPP_201) { /* 201 */
|
||||
DEBUG(sl, 1, "Loading a ChillPP v8 savegame version %d as version 143", _sl_version);
|
||||
_sl_xv_feature_versions[XSLFI_CHILLPP] = _sl_version;
|
||||
_sl_xv_feature_versions[XSLFI_ZPOS_32_BIT] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_TOWN_CARGO_ADJ] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_AUTO_TIMETABLE] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_SIG_TUNNEL_BRIDGE] = 1;
|
||||
_sl_xv_feature_versions[XSLFI_RAIL_AGEING] = 1;
|
||||
_sl_xv_discardable_chunk_ids.push_back('LGRP');
|
||||
_sl_version = SLV_143;
|
||||
_sl_is_faked_ext = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this chunk has been marked as discardable
|
||||
*/
|
||||
bool SlXvIsChunkDiscardable(uint32 id)
|
||||
{
|
||||
for (size_t i = 0; i < _sl_xv_discardable_chunk_ids.size(); i++) {
|
||||
if (_sl_xv_discardable_chunk_ids[i] == id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a chunk ID list string to the savegame, returns the number of chunks written
|
||||
* In dry run mode, only returns the number of chunk which would have been written
|
||||
*/
|
||||
static uint32 WriteChunkIdList(const char *chunk_list, bool dry_run)
|
||||
{
|
||||
unsigned int chunk_count = 0; // number of chunks output
|
||||
unsigned int id_offset = 0; // how far are we into the ID
|
||||
for (; *chunk_list != 0; chunk_list++) {
|
||||
if (id_offset == 4) {
|
||||
assert(*chunk_list == ',');
|
||||
id_offset = 0;
|
||||
} else {
|
||||
if (!dry_run) {
|
||||
SlWriteByte(*chunk_list);
|
||||
}
|
||||
if (id_offset == 3) {
|
||||
chunk_count++;
|
||||
}
|
||||
id_offset++;
|
||||
}
|
||||
}
|
||||
assert(id_offset == 4);
|
||||
return chunk_count;
|
||||
}
|
||||
|
||||
static void Save_SLXI()
|
||||
{
|
||||
SlXvSetCurrentState();
|
||||
|
||||
static const SaveLoad _xlsi_sub_chunk_desc[] = {
|
||||
SLE_STR(SlxiSubChunkInfo, name, SLE_STR, 0),
|
||||
};
|
||||
|
||||
// calculate lengths
|
||||
uint32 item_count = 0;
|
||||
uint32 length = 12;
|
||||
std::vector<uint32> extra_data_lengths;
|
||||
std::vector<uint32> chunk_counts;
|
||||
extra_data_lengths.resize(XSLFI_SIZE);
|
||||
chunk_counts.resize(XSLFI_SIZE);
|
||||
const SlxiSubChunkInfo *info = _sl_xv_sub_chunk_infos;
|
||||
for (; info->index != XSLFI_NULL; ++info) {
|
||||
if (_sl_xv_feature_versions[info->index] > 0) {
|
||||
item_count++;
|
||||
length += 6;
|
||||
length += (uint32)SlCalcObjLength(info, _xlsi_sub_chunk_desc);
|
||||
if (info->save_proc) {
|
||||
uint32 extra_data_length = info->save_proc(info, true);
|
||||
if (extra_data_length) {
|
||||
extra_data_lengths[info->index] = extra_data_length;
|
||||
length += 4 + extra_data_length;
|
||||
}
|
||||
}
|
||||
if (info->chunk_list) {
|
||||
uint32 chunk_count = WriteChunkIdList(info->chunk_list, true);
|
||||
if (chunk_count) {
|
||||
chunk_counts[info->index] = chunk_count;
|
||||
length += 4 * (1 + chunk_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// write header
|
||||
SlSetLength(length);
|
||||
SlWriteUint32(_sl_xv_slxi_chunk_version); // chunk version
|
||||
SlWriteUint32(0); // flags
|
||||
SlWriteUint32(item_count); // item count
|
||||
|
||||
// write data
|
||||
info = _sl_xv_sub_chunk_infos;
|
||||
for (; info->index != XSLFI_NULL; ++info) {
|
||||
uint16 save_version = _sl_xv_feature_versions[info->index];
|
||||
if (save_version > 0) {
|
||||
SlxiSubChunkFlags flags = info->flags;
|
||||
assert(!(flags & (XSCF_EXTRA_DATA_PRESENT | XSCF_CHUNK_ID_LIST_PRESENT)));
|
||||
uint32 extra_data_length = extra_data_lengths[info->index];
|
||||
uint32 chunk_count = chunk_counts[info->index];
|
||||
if (extra_data_length > 0) flags |= XSCF_EXTRA_DATA_PRESENT;
|
||||
if (chunk_count > 0) flags |= XSCF_CHUNK_ID_LIST_PRESENT;
|
||||
SlWriteUint32(flags);
|
||||
SlWriteUint16(save_version);
|
||||
SlObject(const_cast<SlxiSubChunkInfo *>(info), _xlsi_sub_chunk_desc);
|
||||
|
||||
if (extra_data_length > 0) {
|
||||
SlWriteUint32(extra_data_length);
|
||||
size_t written = SlGetBytesWritten();
|
||||
info->save_proc(info, false);
|
||||
assert(SlGetBytesWritten() == written + extra_data_length);
|
||||
}
|
||||
if (chunk_count > 0) {
|
||||
SlWriteUint32(chunk_count);
|
||||
size_t written = SlGetBytesWritten();
|
||||
WriteChunkIdList(info->chunk_list, false);
|
||||
assert(SlGetBytesWritten() == written + (chunk_count * 4));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Load_SLXI()
|
||||
{
|
||||
if (_sl_is_faked_ext || !_sl_is_ext_version) {
|
||||
SlErrorCorrupt("SLXI chunk is unexpectedly present");
|
||||
}
|
||||
|
||||
SlXvResetState();
|
||||
_sl_is_ext_version = true;
|
||||
|
||||
uint32 version = SlReadUint32();
|
||||
if (version > _sl_xv_slxi_chunk_version) SlErrorCorruptFmt("SLXI chunk: version: %u is too new (expected max: %u)", version, _sl_xv_slxi_chunk_version);
|
||||
|
||||
uint32 chunk_flags = SlReadUint32();
|
||||
// flags are not in use yet, reserve for future expansion
|
||||
if (chunk_flags != 0) SlErrorCorruptFmt("SLXI chunk: unknown chunk header flags: 0x%X", chunk_flags);
|
||||
|
||||
char name_buffer[256];
|
||||
const SaveLoad xlsi_sub_chunk_name_desc[] = {
|
||||
SLEG_STR(name_buffer, SLE_STRB),
|
||||
};
|
||||
|
||||
auto version_error = [](StringID str, const char *feature, int64 p1, int64 p2) {
|
||||
char buf[256];
|
||||
int64 args_array[] = { _sl_xv_version_label.empty() ? STR_EMPTY : STR_GAME_SAVELOAD_FROM_VERSION, (int64)(size_t)_sl_xv_version_label.c_str(), (int64)(size_t)feature, p1, p2 };
|
||||
StringParameters tmp_params(args_array);
|
||||
GetStringWithArgs(buf, str, &tmp_params, lastof(buf));
|
||||
SlError(STR_JUST_RAW_STRING, buf);
|
||||
};
|
||||
|
||||
uint32 item_count = SlReadUint32();
|
||||
for (uint32 i = 0; i < item_count; i++) {
|
||||
SlxiSubChunkFlags flags = static_cast<SlxiSubChunkFlags>(SlReadUint32());
|
||||
uint16 version = SlReadUint16();
|
||||
SlGlobList(xlsi_sub_chunk_name_desc);
|
||||
|
||||
// linearly scan through feature list until found name match
|
||||
bool found = false;
|
||||
const SlxiSubChunkInfo *info = _sl_xv_sub_chunk_infos;
|
||||
for (; info->index != XSLFI_NULL; ++info) {
|
||||
if (strcmp(name_buffer, info->name) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool discard_chunks = false;
|
||||
if (found) {
|
||||
if (version > info->max_version) {
|
||||
if (flags & XSCF_IGNORABLE_VERSION) {
|
||||
// version too large but carry on regardless
|
||||
discard_chunks = true;
|
||||
if (flags & XSCF_EXTRA_DATA_PRESENT) {
|
||||
SlSkipBytes(SlReadUint32()); // skip extra data field
|
||||
}
|
||||
DEBUG(sl, 1, "SLXI chunk: too large version for feature: '%s', version: %d, max version: %d, ignoring", name_buffer, version, info->max_version);
|
||||
} else {
|
||||
version_error(STR_GAME_SAVELOAD_ERROR_TOO_NEW_FEATURE_VERSION, name_buffer, version, info->max_version);
|
||||
}
|
||||
} else {
|
||||
// success path :)
|
||||
|
||||
_sl_xv_feature_versions[info->index] = version;
|
||||
if (flags & XSCF_EXTRA_DATA_PRESENT) {
|
||||
uint32 extra_data_size = SlReadUint32();
|
||||
if (extra_data_size) {
|
||||
if (info->load_proc) {
|
||||
size_t read = SlGetBytesRead();
|
||||
info->load_proc(info, extra_data_size);
|
||||
if (SlGetBytesRead() != read + extra_data_size) {
|
||||
SlErrorCorruptFmt("SLXI chunk: feature: %s, version: %d, extra data length mismatch", name_buffer, version);
|
||||
}
|
||||
} else {
|
||||
SlErrorCorruptFmt("SLXI chunk: feature: %s, version: %d, unexpectedly includes extra data", name_buffer, version);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG(sl, 1, "SLXI chunk: found known feature: '%s', version: %d, max version: %d", name_buffer, version, info->max_version);
|
||||
}
|
||||
} else {
|
||||
if (flags & XSCF_IGNORABLE_UNKNOWN) {
|
||||
// not found but carry on regardless
|
||||
discard_chunks = true;
|
||||
if (flags & XSCF_EXTRA_DATA_PRESENT) {
|
||||
SlSkipBytes(SlReadUint32()); // skip extra data field
|
||||
}
|
||||
DEBUG(sl, 1, "SLXI chunk: unknown feature: '%s', version: %d, ignoring", name_buffer, version);
|
||||
} else {
|
||||
version_error(STR_GAME_SAVELOAD_ERROR_UNKNOWN_FEATURE, name_buffer, version, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// at this point the extra data field should have been consumed
|
||||
// handle chunk ID list field
|
||||
if (flags & XSCF_CHUNK_ID_LIST_PRESENT) {
|
||||
uint32 chunk_count = SlReadUint32();
|
||||
for (uint32 j = 0; j < chunk_count; j++) {
|
||||
uint32 chunk_id = SlReadUint32();
|
||||
if (discard_chunks) {
|
||||
_sl_xv_discardable_chunk_ids.push_back(chunk_id);
|
||||
DEBUG(sl, 2, "SLXI chunk: unknown feature: '%s', discarding chunk: %c%c%c%c", name_buffer, chunk_id >> 24, chunk_id >> 16, chunk_id >> 8, chunk_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void loadVL(const SlxiSubChunkInfo *info, uint32 length)
|
||||
{
|
||||
_sl_xv_version_label.resize(length);
|
||||
ReadBuffer::GetCurrent()->CopyBytes(reinterpret_cast<byte *>(_sl_xv_version_label.data()), length);
|
||||
DEBUG(sl, 2, "SLXI version label: %s", _sl_xv_version_label.c_str());
|
||||
}
|
||||
|
||||
static uint32 saveVL(const SlxiSubChunkInfo *info, bool dry_run)
|
||||
{
|
||||
const size_t length = strlen(_openttd_revision);
|
||||
if (!dry_run) MemoryDumper::GetCurrent()->CopyBytes(reinterpret_cast<const byte *>(_openttd_revision), length);
|
||||
return static_cast<uint32>(length);
|
||||
}
|
||||
|
||||
static void loadUV(const SlxiSubChunkInfo *info, uint32 length)
|
||||
{
|
||||
if (length == 2) {
|
||||
_sl_xv_upstream_version = (SaveLoadVersion)SlReadUint16();
|
||||
DEBUG(sl, 2, "SLXI upstream version: %u", _sl_xv_upstream_version);
|
||||
} else {
|
||||
DEBUG(sl, 1, "SLXI chunk: feature: '%s', version: %d, has data of wrong length: %u", info->name, _sl_xv_feature_versions[info->index], length);
|
||||
ReadBuffer::GetCurrent()->SkipBytes(length);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32 saveUV(const SlxiSubChunkInfo *info, bool dry_run)
|
||||
{
|
||||
if (!dry_run) SlWriteUint16(SL_MAX_VERSION - 1);
|
||||
return 2;
|
||||
}
|
||||
|
||||
static void loadLC(const SlxiSubChunkInfo *info, uint32 length)
|
||||
{
|
||||
if (length == 1) {
|
||||
_loaded_local_company = (CompanyID) ReadBuffer::GetCurrent()->ReadByte();
|
||||
} else {
|
||||
DEBUG(sl, 1, "SLXI chunk: feature: '%s', version: %d, has data of wrong length: %u", info->name, _sl_xv_feature_versions[info->index], length);
|
||||
ReadBuffer::GetCurrent()->SkipBytes(length);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32 saveLC(const SlxiSubChunkInfo *info, bool dry_run)
|
||||
{
|
||||
if (!dry_run) MemoryDumper::GetCurrent()->WriteByte(_local_company);
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern const ChunkHandler version_ext_chunk_handlers[] = {
|
||||
{ 'SLXI', Save_SLXI, Load_SLXI, nullptr, Load_SLXI, CH_RIFF },
|
||||
};
|
||||
extern const ChunkHandlerTable _version_ext_chunk_handlers(version_ext_chunk_handlers);
|
||||
@@ -1,277 +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 extended_ver_sl.h Functions/types related to handling save/load extended version info. */
|
||||
|
||||
#ifndef EXTENDED_VER_SL_H
|
||||
#define EXTENDED_VER_SL_H
|
||||
|
||||
#include "../core/bitmath_func.hpp"
|
||||
#include "../core/enum_type.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
enum SaveLoadVersion : uint16;
|
||||
|
||||
/**
|
||||
* List of extended features, each feature has its own (16 bit) version
|
||||
*/
|
||||
enum SlXvFeatureIndex {
|
||||
XSLFI_NULL = 0, ///< Unused value, to indicate that no extended feature test is in use
|
||||
XSLFI_VERSION_LABEL, ///< Version label
|
||||
XSLFI_UPSTREAM_VERSION, ///< Corresponding upstream savegame version
|
||||
XSLFI_TRACE_RESTRICT, ///< Trace restrict
|
||||
XSLFI_TRACE_RESTRICT_OWNER, ///< Trace restrict: train owner test
|
||||
XSLFI_TRACE_RESTRICT_ORDRCND, ///< Trace restrict: slot conditional order
|
||||
XSLFI_TRACE_RESTRICT_STATUSCND, ///< Trace restrict: train status condition
|
||||
XSLFI_TRACE_RESTRICT_REVERSE, ///< Trace restrict: reverse
|
||||
XSLFI_TRACE_RESTRICT_NEWSCTRL, ///< Trace restrict: news control
|
||||
XSLFI_TRACE_RESTRICT_COUNTER, ///< Trace restrict: counters
|
||||
XSLFI_TRACE_RESTRICT_TIMEDATE, ///< Trace restrict: time/date
|
||||
XSLFI_TRACE_RESTRICT_BRKCND, ///< Trace restrict: realistic braking related conditionals
|
||||
XSLFI_TRACE_RESTRICT_CTGRYCND, ///< Trace restrict: category conditionals
|
||||
XSLFI_TRACE_RESTRICT_PENCTRL, ///< Trace restrict: PF penalty control
|
||||
XSLFI_TRACE_RESTRICT_TUNBRIDGE, ///< Trace restrict: restricted signalled tunnel/bridge support
|
||||
XSLFI_TRACE_RESTRICT_SPDADAPTCTRL, ///< Trace restrict: speed adaptation control
|
||||
XSLFI_PROG_SIGS, ///< programmable pre-signals patch
|
||||
XSLFI_ADJACENT_CROSSINGS, ///< Adjacent level crossings closure patch
|
||||
XSLFI_SAFER_CROSSINGS, ///< Safer level crossings
|
||||
XSLFI_DEPARTURE_BOARDS, ///< Departure boards patch, in ticks mode
|
||||
XSLFI_TIMETABLES_START_TICKS, ///< Timetable start time is in ticks, instead of days (from departure boards patch)
|
||||
XSLFI_TOWN_CARGO_ADJ, ///< Town cargo adjustment patch
|
||||
XSLFI_SIG_TUNNEL_BRIDGE, ///< Signals on tunnels and bridges
|
||||
XSLFI_IMPROVED_BREAKDOWNS, ///< Improved breakdowns patch
|
||||
XSLFI_CONSIST_BREAKDOWN_FLAG, ///< Consist breakdown flag
|
||||
XSLFI_TT_WAIT_IN_DEPOT, ///< Timetabling waiting time in depot patch
|
||||
XSLFI_AUTO_TIMETABLE, ///< Auto timetables and separation patch
|
||||
XSLFI_VEHICLE_REPAIR_COST, ///< Vehicle repair costs patch
|
||||
XSLFI_ENH_VIEWPORT_PLANS, ///< Enhanced viewport patch: plans
|
||||
XSLFI_INFRA_SHARING, ///< Infrastructure sharing patch
|
||||
XSLFI_VARIABLE_DAY_LENGTH, ///< Variable day length patch
|
||||
XSLFI_ORDER_OCCUPANCY, ///< Running average of order occupancy
|
||||
XSLFI_MORE_COND_ORDERS, ///< More conditional orders patch
|
||||
XSLFI_EXTRA_LARGE_MAP, ///< Extra large map
|
||||
XSLFI_REVERSE_AT_WAYPOINT, ///< Reverse at waypoint orders
|
||||
XSLFI_VEH_LIFETIME_PROFIT, ///< Vehicle lifetime profit patch
|
||||
XSLFI_LINKGRAPH_DAY_SCALE, ///< Linkgraph job duration & interval may be in non-scaled days
|
||||
XSLFI_TEMPLATE_REPLACEMENT, ///< Template-based train replacement
|
||||
XSLFI_MORE_RAIL_TYPES, ///< Increased number of rail types
|
||||
XSLFI_CARGO_TYPE_ORDERS, ///< Cargo-specific load/unload order flags
|
||||
XSLFI_EXTENDED_GAMELOG, ///< Extended gamelog
|
||||
XSLFI_STATION_CATCHMENT_INC, ///< Station catchment radius increase
|
||||
XSLFI_CUSTOM_BRIDGE_HEADS, ///< Custom bridge heads
|
||||
XSLFI_CHUNNEL, ///< Tunnels under water (channel tunnel)
|
||||
XSLFI_SCHEDULED_DISPATCH, ///< Scheduled vehicle dispatching
|
||||
XSLFI_MORE_TOWN_GROWTH_RATES, ///< More town growth rates
|
||||
XSLFI_MULTIPLE_DOCKS, ///< Multiple docks
|
||||
XSLFI_TIMETABLE_EXTRA, ///< Vehicle timetable extra fields
|
||||
XSLFI_TRAIN_FLAGS_EXTRA, ///< Train flags field extra size
|
||||
XSLFI_VEHICLE_FLAGS_EXTRA, ///< Vehicle flags field extra size
|
||||
XSLFI_TRAIN_THROUGH_LOAD, ///< Train through load/unload
|
||||
XSLFI_ORDER_EXTRA_DATA, ///< Order extra data field(s)
|
||||
XSLFI_WHOLE_MAP_CHUNK, ///< Whole map chunk
|
||||
XSLFI_ST_LAST_VEH_TYPE, ///< Per-cargo station last vehicle type
|
||||
XSLFI_SELL_AT_DEPOT_ORDER, ///< Sell vehicle on arrival at depot orders
|
||||
XSLFI_BUY_LAND_RATE_LIMIT, ///< Buy land rate limit
|
||||
XSLFI_DUAL_RAIL_TYPES, ///< Two rail-types per tile
|
||||
XSLFI_CONSIST_SPEED_RD_FLAG, ///< Consist speed reduction flag
|
||||
XSLFI_SAVEGAME_UNIQUE_ID, ///< Savegame unique ID
|
||||
XSLFI_RV_OVERTAKING, ///< Roadvehicle overtaking
|
||||
XSLFI_LINKGRAPH_MODES, ///< Linkgraph additional distribution modes
|
||||
XSLFI_GAME_EVENTS, ///< Game event flags
|
||||
XSLFI_ROAD_LAYOUT_CHANGE_CTR, ///< Road layout change counter
|
||||
XSLFI_TOWN_CARGO_MATRIX, ///< Town cargo matrix savegame format changes (now obsolete)
|
||||
XSLFI_STATE_CHECKSUM, ///< State checksum
|
||||
XSLFI_DEBUG, ///< Debugging info
|
||||
XSLFI_FLOW_STAT_FLAGS, ///< FlowStat flags
|
||||
XSLFI_SPEED_RESTRICTION, ///< Train speed restrictions
|
||||
XSLFI_STATION_GOODS_EXTRA, ///< Extra station goods entry statuses
|
||||
XSLFI_DOCKING_CACHE_VER, ///< Multiple docks - docking tile cache version
|
||||
XSLFI_EXTRA_CHEATS, ///< Extra cheats
|
||||
XSLFI_TOWN_MULTI_BUILDING, ///< Allow multiple stadium/church buildings in a single town
|
||||
XSLFI_SHIP_LOST_COUNTER, ///< Ship lost counter
|
||||
XSLFI_BUILD_OBJECT_RATE_LIMIT, ///< Build object rate limit
|
||||
XSLFI_LOCAL_COMPANY, ///< Local company ID
|
||||
XSLFI_THROUGH_TRAIN_DEPOT, ///< Drive-through train depots
|
||||
XSLFI_MORE_VEHICLE_ORDERS, ///< More vehicle orders - VehicleOrderID is 16 bits instead of 8
|
||||
XSLFI_ORDER_FLAGS_EXTRA, ///< Order flags field extra size
|
||||
XSLFI_ONE_WAY_DT_ROAD_STOP, ///< One-way drive-through road stops
|
||||
XSLFI_ONE_WAY_ROAD_STATE, ///< One-way road state cache
|
||||
XSLFI_VENC_CHUNK, ///< VENC chunk
|
||||
XSLFI_ANIMATED_TILE_EXTRA, ///< Animated tile extra info
|
||||
XSLFI_NEWGRF_INFO_EXTRA, ///< Extra NewGRF info in savegame
|
||||
XSLFI_INDUSTRY_CARGO_ADJ, ///< Industry cargo adjustment patch
|
||||
XSLFI_REALISTIC_TRAIN_BRAKING, ///< Realistic train braking
|
||||
XSLFI_INFLATION_FIXED_DATES, ///< Inflation is applied between fixed dates
|
||||
XSLFI_WATER_FLOODING, ///< Water flooding map bit
|
||||
XSLFI_MORE_HOUSES, ///< More house types
|
||||
XSLFI_CUSTOM_TOWN_ZONE, ///< Custom town zones
|
||||
XSLFI_STATION_CARGO_HISTORY, ///< Station waiting cargo history
|
||||
XSLFI_TRAIN_SPEED_ADAPTATION, ///< Train speed adaptation
|
||||
XSLFI_EXTRA_STATION_NAMES, ///< Extra station names
|
||||
XSLFI_DEPOT_ORDER_EXTRA_FLAGS, ///< Depot order extra flags
|
||||
XSLFI_EXTRA_SIGNAL_TYPES, ///< Extra signal types
|
||||
XSLFI_BANKRUPTCY_EXTRA, ///< Extra company bankruptcy fields
|
||||
XSLFI_OBJECT_GROUND_TYPES, ///< Object ground types
|
||||
XSLFI_LINKGRAPH_AIRCRAFT, ///< Link graph last aircraft update field and aircraft link scaling setting
|
||||
XSLFI_COMPANY_PW, ///< Company passwords
|
||||
XSLFI_ST_INDUSTRY_CARGO_MODE, ///< Station industry cargo mode setting
|
||||
XSLFI_TL_SPEED_LIMIT, ///< Through load maximum speed setting
|
||||
XSLFI_RAIL_DEPOT_SPEED_LIMIT, ///< Rail depot maximum speed setting
|
||||
XSLFI_WAYPOINT_FLAGS, ///< Waypoint flags
|
||||
XSLFI_ROAD_WAYPOINTS, ///< Road waypoints
|
||||
XSLFI_MORE_STATION_TYPES, ///< More station types (field widening)
|
||||
XSLFI_RV_ORDER_EXTRA_FLAGS, ///< Road vehicle order extra flags
|
||||
XSLFI_GRF_ROADSTOPS, ///< NewGRF road stops
|
||||
XSLFI_INDUSTRY_ANIM_MASK, ///< Industry tile animation masking
|
||||
XSLFI_NEW_SIGNAL_STYLES, ///< New signal styles
|
||||
XSLFI_NO_TREE_COUNTER, ///< No tree counter
|
||||
XSLFI_TOWN_SETTING_OVERRIDE, ///< Town setting overrides
|
||||
XSLFI_LINKGRAPH_SPARSE_EDGES, ///< Link graph edge matrix is stored in sparse format, and saved in order
|
||||
XSLFI_AUX_TILE_LOOP, ///< Auxiliary tile loop
|
||||
XSLFI_NEWGRF_ENTITY_EXTRA, ///< NewGRF entity mappings are 16 bit
|
||||
XSLFI_TNNC_CHUNK, ///< TNNC chunk
|
||||
XSLFI_MULTI_CARGO_SHIPS, ///< Multi-cargo ships
|
||||
XSLFI_REMAIN_NEXT_ORDER_STATION, ///< Remain in station if next order is for same station
|
||||
XSLFI_LABEL_ORDERS, ///< Label orders
|
||||
XSLFI_VARIABLE_TICK_RATE, ///< Variable tick rate
|
||||
|
||||
XSLFI_SCRIPT_INT64, ///< See: SLV_SCRIPT_INT64
|
||||
XSLFI_U64_TICK_COUNTER, ///< See: SLV_U64_TICK_COUNTER
|
||||
XSLFI_LINKGRAPH_TRAVEL_TIME, ///< See: SLV_LINKGRAPH_TRAVEL_TIME
|
||||
XSLFI_LAST_LOADING_TICK, ///< See: SLV_LAST_LOADING_TICK
|
||||
XSLFI_SCRIPT_LEAGUE_TABLES, ///< See: Scriptable league tables (PR #10001)
|
||||
XSLFI_VELOCITY_NAUTICAL, ///< See: SLV_VELOCITY_NAUTICAL (PR #10594)
|
||||
XSLFI_CONSISTENT_PARTIAL_Z, ///< See: SLV_CONSISTENT_PARTIAL_Z (PR #10570)
|
||||
XSLFI_MORE_CARGO_AGE, ///< See: SLV_MORE_CARGO_AGE (PR #10596)
|
||||
XSLFI_AI_START_DATE, ///< See: SLV_AI_START_DATE (PR #10653)
|
||||
XSLFI_EXTEND_VEHICLE_RANDOM, ///< See: SLV_EXTEND_VEHICLE_RANDOM (PR #10701)
|
||||
XSLFI_DISASTER_VEH_STATE, ///< See: SLV_DISASTER_VEH_STATE (PR #10798)
|
||||
|
||||
XSLFI_RIFF_HEADER_60_BIT, ///< Size field in RIFF chunk header is 60 bit
|
||||
XSLFI_HEIGHT_8_BIT, ///< Map tile height is 8 bit instead of 4 bit, but savegame version may be before this became true in trunk
|
||||
XSLFI_ZPOS_32_BIT, ///< Vehicle/sign z_pos is 32 bit instead of 8 bit, but savegame version may be before this became true in trunk
|
||||
XSLFI_MIGHT_USE_PAX_SIGNALS, ///< This save game might use the pax-signals feature
|
||||
XSLFI_TRAFFIC_LIGHTS, ///< This save game uses road traffic lights
|
||||
XSLFI_RAIL_AGEING, ///< This save game uses the rail aging patch
|
||||
XSLFI_SPRINGPP, ///< This is a SpringPP game, use this for loading some settings
|
||||
XSLFI_JOKERPP, ///< This is a JokerPP game, use this for loading some settings
|
||||
XSLFI_CHILLPP, ///< This is a ChillPP game, use this for loading some settings
|
||||
|
||||
XSLFI_SIZE, ///< Total count of features, including null feature
|
||||
};
|
||||
|
||||
extern std::array<uint16, XSLFI_SIZE> _sl_xv_feature_versions;
|
||||
extern std::array<uint16, XSLFI_SIZE> _sl_xv_feature_static_versions;
|
||||
|
||||
/**
|
||||
* Operator to use when combining traditional savegame number test with an extended feature version test
|
||||
*/
|
||||
enum SlXvFeatureTestOperator {
|
||||
XSLFTO_OR = 0, ///< Test if traditional savegame version is in bounds OR extended feature is in version bounds
|
||||
XSLFTO_AND ///< Test if traditional savegame version is in bounds AND extended feature is in version bounds
|
||||
};
|
||||
|
||||
/**
|
||||
* Structure to describe an extended feature version test, and how it combines with a traditional savegame version test
|
||||
*/
|
||||
struct SlXvFeatureTest {
|
||||
using TestFunctorPtr = bool (*)(uint16, bool, const std::array<uint16, XSLFI_SIZE> &); ///< Return true if feature present, first parameter is standard savegame version, second is whether standard savegame version is within bounds
|
||||
|
||||
private:
|
||||
uint16 min_version;
|
||||
uint16 max_version;
|
||||
SlXvFeatureIndex feature;
|
||||
SlXvFeatureTestOperator op;
|
||||
TestFunctorPtr functor = nullptr;
|
||||
|
||||
public:
|
||||
SlXvFeatureTest()
|
||||
: min_version(0), max_version(0), feature(XSLFI_NULL), op(XSLFTO_OR) { }
|
||||
|
||||
SlXvFeatureTest(SlXvFeatureTestOperator op_, SlXvFeatureIndex feature_, uint16 min_version_ = 1, uint16 max_version_ = 0xFFFF)
|
||||
: min_version(min_version_), max_version(max_version_), feature(feature_), op(op_) { }
|
||||
|
||||
SlXvFeatureTest(TestFunctorPtr functor_)
|
||||
: min_version(0), max_version(0), feature(XSLFI_NULL), op(XSLFTO_OR), functor(functor_) { }
|
||||
|
||||
bool IsFeaturePresent(const std::array<uint16, XSLFI_SIZE> &feature_versions, SaveLoadVersion savegame_version, SaveLoadVersion savegame_version_from, SaveLoadVersion savegame_version_to) const;
|
||||
|
||||
inline bool IsFeaturePresent(SaveLoadVersion savegame_version, SaveLoadVersion savegame_version_from, SaveLoadVersion savegame_version_to) const
|
||||
{
|
||||
return this->IsFeaturePresent(_sl_xv_feature_versions, savegame_version, savegame_version_from, savegame_version_to);
|
||||
}
|
||||
};
|
||||
|
||||
bool SlXvIsFeaturePresent(const std::array<uint16, XSLFI_SIZE> &feature_versions, SlXvFeatureIndex feature, uint16 min_version = 1, uint16 max_version = 0xFFFF);
|
||||
|
||||
inline bool SlXvIsFeaturePresent(SlXvFeatureIndex feature, uint16 min_version = 1, uint16 max_version = 0xFFFF)
|
||||
{
|
||||
return SlXvIsFeaturePresent(_sl_xv_feature_versions, feature, min_version, max_version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if @p feature is missing (i.e. has a version of 0, or less than the specified minimum version)
|
||||
*/
|
||||
inline bool SlXvIsFeatureMissing(SlXvFeatureIndex feature, uint16 min_version = 1)
|
||||
{
|
||||
return !SlXvIsFeaturePresent(feature, min_version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if @p feature is missing (i.e. has a version of 0, or less than the specified minimum version)
|
||||
*/
|
||||
inline bool SlXvIsFeatureMissing(const std::array<uint16, XSLFI_SIZE> &feature_versions, SlXvFeatureIndex feature, uint16 min_version = 1)
|
||||
{
|
||||
return !SlXvIsFeaturePresent(feature_versions, feature, min_version);
|
||||
}
|
||||
|
||||
const char *SlXvGetFeatureName(SlXvFeatureIndex feature);
|
||||
|
||||
/**
|
||||
* sub chunk flags, this is saved as-is
|
||||
* (XSCF_EXTRA_DATA_PRESENT and XSCF_CHUNK_ID_LIST_PRESENT must only be set by the save code, and read by the load code)
|
||||
*/
|
||||
enum SlxiSubChunkFlags {
|
||||
XSCF_NULL = 0, ///< zero value
|
||||
XSCF_IGNORABLE_UNKNOWN = 1 << 0, ///< the loader is free to ignore this without aborting the load if it doesn't know what it is at all
|
||||
XSCF_IGNORABLE_VERSION = 1 << 1, ///< the loader is free to ignore this without aborting the load if the version is greater than the maximum that can be loaded
|
||||
XSCF_EXTRA_DATA_PRESENT = 1 << 2, ///< extra data field is present, extra data in some sub-chunk/feature specific format
|
||||
XSCF_CHUNK_ID_LIST_PRESENT = 1 << 3, ///< chunk ID list field is present, list of chunks which this sub-chunk/feature adds to the save game, this can be used to discard the chunks if the feature is unknown
|
||||
|
||||
XSCF_IGNORABLE_ALL = XSCF_IGNORABLE_UNKNOWN | XSCF_IGNORABLE_VERSION, ///< all "ignorable" flags
|
||||
};
|
||||
DECLARE_ENUM_AS_BIT_SET(SlxiSubChunkFlags)
|
||||
|
||||
struct SlxiSubChunkInfo;
|
||||
|
||||
typedef uint32 SlxiSubChunkSaveProc(const SlxiSubChunkInfo *info, bool dry_run); ///< sub chunk save procedure type, must return length and write no data when dry_run is true
|
||||
typedef void SlxiSubChunkLoadProc(const SlxiSubChunkInfo *info, uint32 length); ///< sub chunk load procedure, must consume length bytes
|
||||
|
||||
/** Handlers and description of chunk. */
|
||||
struct SlxiSubChunkInfo {
|
||||
SlXvFeatureIndex index; ///< feature index, this is saved
|
||||
SlxiSubChunkFlags flags; ///< flags, this is saved
|
||||
uint16 save_version; ///< version to save
|
||||
uint16 max_version; ///< maximum version to accept on load
|
||||
const char *name; ///< feature name, this *IS* saved, so must be globally unique
|
||||
SlxiSubChunkSaveProc *save_proc; ///< save procedure of the sub chunk, this may be nullptr in which case no extra chunk data is saved
|
||||
SlxiSubChunkLoadProc *load_proc; ///< load procedure of the sub chunk, this may be nullptr in which case the extra chunk data must be missing or of 0 length
|
||||
const char *chunk_list; ///< this is a list of chunks that this feature uses, which should be written to the savegame, this must be a comma-seperated list of 4-character IDs, with no spaces, or nullptr
|
||||
};
|
||||
|
||||
void SlXvResetState();
|
||||
|
||||
void SlXvSetCurrentState();
|
||||
void SlXvSetStaticCurrentVersions();
|
||||
|
||||
bool SlXvCheckSpecialSavegameVersions();
|
||||
|
||||
bool SlXvIsChunkDiscardable(uint32 id);
|
||||
|
||||
#endif /* EXTENDED_VER_SL_H */
|
||||
@@ -9,9 +9,11 @@
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "../debug.h"
|
||||
#include "saveload.h"
|
||||
#include "../string_func.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"
|
||||
@@ -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);
|
||||
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.");
|
||||
} 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 %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;
|
||||
_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");
|
||||
}
|
||||
|
||||
config->StringToSettings(_game_saveload_settings);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
static const SaveLoad _game_language_header[] = {
|
||||
SLEG_SSTR(_game_saveload_string, SLE_STR),
|
||||
SLEG_VAR(_game_saveload_strings, SLE_UINT32),
|
||||
};
|
||||
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;
|
||||
|
||||
static const SaveLoad _game_language_string[] = {
|
||||
SLEG_SSTR(_game_saveload_string, SLE_STR | SLF_ALLOW_CONTROL),
|
||||
};
|
||||
void Save(LanguageStrings *ls) const override
|
||||
{
|
||||
SlSetStructListLength(ls->lines.size());
|
||||
|
||||
static void SaveReal_GSTR(const LanguageStrings *ls)
|
||||
{
|
||||
_game_saveload_string = ls->language.c_str();
|
||||
_game_saveload_strings = (uint)ls->lines.size();
|
||||
|
||||
SlObject(nullptr, _game_language_header);
|
||||
for (const auto &i : ls->lines) {
|
||||
_game_saveload_string = i.c_str();
|
||||
SlObject(nullptr, _game_language_string);
|
||||
for (const auto &string : ls->lines) {
|
||||
_game_saveload_string = string;
|
||||
SlObject(nullptr, this->GetDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Load_GSTR()
|
||||
{
|
||||
delete _current_data;
|
||||
_current_data = new GameStrings();
|
||||
void Load(LanguageStrings *ls) const override
|
||||
{
|
||||
uint32 length = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? _game_saveload_strings : (uint32)SlGetStructListLength(UINT32_MAX);
|
||||
|
||||
while (SlIterateArray() != -1) {
|
||||
_game_saveload_string.clear();
|
||||
SlObject(nullptr, _game_language_header);
|
||||
for (uint32 i = 0; i < length; i++) {
|
||||
SlObject(nullptr, this->GetLoadDescription());
|
||||
ls->lines.emplace_back(_game_saveload_string);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
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));
|
||||
}
|
||||
|
||||
_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();
|
||||
}
|
||||
|
||||
/* 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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_current_data->Compile();
|
||||
ReconsiderGameScriptLanguage();
|
||||
}
|
||||
|
||||
static void Save_GSTR()
|
||||
{
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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),
|
||||
};
|
||||
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;
|
||||
|
||||
static const SaveLoad _glog_oldver_desc[] = {
|
||||
SLE_VAR(LoggedChange, oldver.type, SLE_UINT32),
|
||||
SLE_VAR(LoggedChange, oldver.version, SLE_UINT32),
|
||||
};
|
||||
void Save(LoggedChange *lc) const override
|
||||
{
|
||||
if (lc->ct != GLCT_REVISION) return;
|
||||
SlObject(lc, this->GetDescription());
|
||||
}
|
||||
|
||||
static const SaveLoad _glog_setting_desc[] = {
|
||||
SLE_STR(LoggedChange, setting.name, SLE_STR, 128),
|
||||
SLE_VAR(LoggedChange, setting.oldval, SLE_INT32),
|
||||
SLE_VAR(LoggedChange, setting.newval, SLE_INT32),
|
||||
};
|
||||
|
||||
static const SaveLoad _glog_grfadd_desc[] = {
|
||||
SLE_VAR(LoggedChange, grfadd.grfid, SLE_UINT32 ),
|
||||
SLE_ARR(LoggedChange, grfadd.md5sum, SLE_UINT8, 16),
|
||||
};
|
||||
|
||||
static const SaveLoad _glog_grfrem_desc[] = {
|
||||
SLE_VAR(LoggedChange, grfrem.grfid, SLE_UINT32),
|
||||
};
|
||||
|
||||
static const SaveLoad _glog_grfcompat_desc[] = {
|
||||
SLE_VAR(LoggedChange, grfcompat.grfid, SLE_UINT32 ),
|
||||
SLE_ARR(LoggedChange, grfcompat.md5sum, SLE_UINT8, 16),
|
||||
};
|
||||
|
||||
static const SaveLoad _glog_grfparam_desc[] = {
|
||||
SLE_VAR(LoggedChange, grfparam.grfid, SLE_UINT32),
|
||||
};
|
||||
|
||||
static const SaveLoad _glog_grfmove_desc[] = {
|
||||
SLE_VAR(LoggedChange, grfmove.grfid, SLE_UINT32),
|
||||
SLE_VAR(LoggedChange, grfmove.offset, SLE_INT32),
|
||||
};
|
||||
|
||||
static const SaveLoad _glog_grfbug_desc[] = {
|
||||
SLE_VAR(LoggedChange, grfbug.data, SLE_UINT64),
|
||||
SLE_VAR(LoggedChange, grfbug.grfid, SLE_UINT32),
|
||||
SLE_VAR(LoggedChange, grfbug.bug, SLE_UINT8),
|
||||
};
|
||||
|
||||
static const SaveLoad _glog_emergency_desc[] = {
|
||||
SLE_CONDNULL(0, SL_MIN_VERSION, SL_MIN_VERSION), // Just an empty list, to keep the rest of the code easier.
|
||||
};
|
||||
|
||||
static const SaveLoadTable _glog_desc[] = {
|
||||
_glog_mode_desc,
|
||||
_glog_revision_desc,
|
||||
_glog_oldver_desc,
|
||||
_glog_setting_desc,
|
||||
_glog_grfadd_desc,
|
||||
_glog_grfrem_desc,
|
||||
_glog_grfcompat_desc,
|
||||
_glog_grfparam_desc,
|
||||
_glog_grfmove_desc,
|
||||
_glog_grfbug_desc,
|
||||
_glog_emergency_desc,
|
||||
};
|
||||
|
||||
static_assert(lengthof(_glog_desc) == GLCT_END);
|
||||
|
||||
static void Load_GLOG_common(LoggedAction *&gamelog_action, uint &gamelog_actions)
|
||||
{
|
||||
assert(gamelog_action == nullptr);
|
||||
assert(gamelog_actions == 0);
|
||||
|
||||
byte type;
|
||||
while ((type = SlReadByte()) != GLAT_NONE) {
|
||||
if (type >= GLAT_END) SlErrorCorrupt("Invalid gamelog action type");
|
||||
GamelogActionType at = (GamelogActionType)type;
|
||||
|
||||
gamelog_action = ReallocT(gamelog_action, gamelog_actions + 1);
|
||||
LoggedAction *la = &gamelog_action[gamelog_actions++];
|
||||
|
||||
la->at = at;
|
||||
|
||||
SlObject(la, _glog_action_desc); // has to be saved after 'DATE'!
|
||||
la->change = nullptr;
|
||||
la->changes = 0;
|
||||
|
||||
while ((type = SlReadByte()) != GLCT_NONE) {
|
||||
if (type >= GLCT_END) SlErrorCorrupt("Invalid gamelog change type");
|
||||
GamelogChangeType ct = (GamelogChangeType)type;
|
||||
|
||||
la->change = ReallocT(la->change, la->changes + 1);
|
||||
|
||||
LoggedChange *lc = &la->change[la->changes++];
|
||||
/* for SLE_STR, pointer has to be valid! so make it nullptr */
|
||||
memset(lc, 0, sizeof(*lc));
|
||||
lc->ct = ct;
|
||||
|
||||
SlObject(lc, _glog_desc[ct]);
|
||||
if (ct == GLCT_REVISION && SlXvIsFeatureMissing(XSLFI_EXTENDED_GAMELOG)) {
|
||||
lc->revision.text = stredup(old_revision_text, lastof(old_revision_text));
|
||||
}
|
||||
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 void Save_GLOG()
|
||||
{
|
||||
const LoggedAction *laend = &_gamelog_action[_gamelog_actions];
|
||||
size_t length = 0;
|
||||
void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
|
||||
};
|
||||
|
||||
for (const LoggedAction *la = _gamelog_action; la != laend; la++) {
|
||||
const LoggedChange *lcend = &la->change[la->changes];
|
||||
for (LoggedChange *lc = la->change; lc != lcend; lc++) {
|
||||
assert((uint)lc->ct < lengthof(_glog_desc));
|
||||
length += SlCalcObjLength(lc, _glog_desc[lc->ct]) + 1;
|
||||
}
|
||||
length += 10;
|
||||
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());
|
||||
}
|
||||
length++;
|
||||
|
||||
SlSetLength(length);
|
||||
void Load(LoggedChange *lc) const override
|
||||
{
|
||||
if (lc->ct != GLCT_OLDVER) return;
|
||||
SlObject(lc, this->GetLoadDescription());
|
||||
}
|
||||
|
||||
for (LoggedAction *la = _gamelog_action; la != laend; la++) {
|
||||
SlWriteByte(la->at);
|
||||
SlObject(la, _glog_action_desc);
|
||||
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++) {
|
||||
SlWriteByte(lc->ct);
|
||||
assert((uint)lc->ct < GLCT_END);
|
||||
SlObject(lc, _glog_desc[lc->ct]);
|
||||
SlObject(lc, this->GetDescription());
|
||||
}
|
||||
SlWriteByte(GLCT_NONE);
|
||||
}
|
||||
SlWriteByte(GLAT_NONE);
|
||||
}
|
||||
|
||||
static void Load_GLOG()
|
||||
{
|
||||
Load_GLOG_common(_gamelog_action, _gamelog_actions);
|
||||
}
|
||||
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;
|
||||
|
||||
static void Check_GLOG()
|
||||
{
|
||||
Load_GLOG_common(_load_check_data.gamelog_action, _load_check_data.gamelog_actions);
|
||||
}
|
||||
la->change = ReallocT(la->change, la->changes + 1);
|
||||
|
||||
static const ChunkHandler gamelog_chunk_handlers[] = {
|
||||
{ 'GLOG', Save_GLOG, Load_GLOG, nullptr, Check_GLOG, CH_RIFF }
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
static void Load_GOAL()
|
||||
{
|
||||
int index;
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
Goal *s = new (index) Goal();
|
||||
SlObject(s, _goals_desc);
|
||||
}
|
||||
}
|
||||
void Save() const override
|
||||
{
|
||||
SlTableHeader(_goals_desc);
|
||||
|
||||
static const ChunkHandler goal_chunk_handlers[] = {
|
||||
{ 'GOAL', Save_GOAL, Load_GOAL, nullptr, nullptr, CH_ARRAY },
|
||||
for (Goal *s : Goal::Iterate()) {
|
||||
SlSetArrayIndex(s->index);
|
||||
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 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);
|
||||
|
||||
static void Load_GRPS()
|
||||
{
|
||||
int index;
|
||||
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
Group *g = new (index) Group();
|
||||
SlObject(g, _group_desc);
|
||||
|
||||
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;
|
||||
for (Group *g : Group::Iterate()) {
|
||||
SlSetArrayIndex(g->index);
|
||||
SlObject(g, _group_desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const ChunkHandler group_chunk_handlers[] = {
|
||||
{ 'GRPS', Save_GRPS, Load_GRPS, nullptr, nullptr, CH_ARRAY },
|
||||
|
||||
void Load() const override
|
||||
{
|
||||
const std::vector<SaveLoad> slt = SlCompatTableHeader(_group_desc, _group_sl_compat);
|
||||
|
||||
int index;
|
||||
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
Group *g = new (index) Group();
|
||||
SlObject(g, slt);
|
||||
|
||||
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 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);
|
||||
}
|
||||
|
||||
static void Load_INDY()
|
||||
{
|
||||
int index;
|
||||
|
||||
Industry::ResetIndustryCounts();
|
||||
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
Industry *i = new (index) Industry();
|
||||
SlObject(i, _industry_desc);
|
||||
|
||||
/* 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));
|
||||
/* Write the industries */
|
||||
for (Industry *ind : Industry::Iterate()) {
|
||||
SlSetArrayIndex(ind->index);
|
||||
SlObject(ind, _industry_desc);
|
||||
}
|
||||
Industry::IncIndustryTypeCount(i->type);
|
||||
}
|
||||
}
|
||||
|
||||
static void Load_IIDS()
|
||||
{
|
||||
Load_NewGRFMapping(_industry_mngr);
|
||||
}
|
||||
void Load() const override
|
||||
{
|
||||
const std::vector<SaveLoad> slt = SlCompatTableHeader(_industry_desc, _industry_sl_compat);
|
||||
|
||||
static void Load_TIDS()
|
||||
{
|
||||
Load_NewGRFMapping(_industile_mngr);
|
||||
}
|
||||
int index;
|
||||
|
||||
static void Ptrs_INDY()
|
||||
{
|
||||
for (Industry *i : Industry::Iterate()) {
|
||||
SlObject(i, _industry_desc);
|
||||
Industry::ResetIndustryCounts();
|
||||
|
||||
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));
|
||||
}
|
||||
Industry::IncIndustryTypeCount(i->type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FixPointers() const override
|
||||
{
|
||||
for (Industry *i : Industry::Iterate()) {
|
||||
SlObject(i, _industry_desc);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct IIDSChunkHandler : NewGRFMappingChunkHandler {
|
||||
IIDSChunkHandler() : NewGRFMappingChunkHandler('IIDS', _industry_mngr) {}
|
||||
};
|
||||
|
||||
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) {}
|
||||
|
||||
/** Load industry-type build data. */
|
||||
static void Load_ITBL()
|
||||
{
|
||||
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, _industrytype_builder_desc);
|
||||
}
|
||||
}
|
||||
void Save() const override
|
||||
{
|
||||
SlTableHeader(_industrytype_builder_desc);
|
||||
|
||||
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 },
|
||||
for (int i = 0; i < NUM_INDUSTRYTYPES; i++) {
|
||||
SlSetArrayIndex(i);
|
||||
SlObject(_industry_builder.builddata + i, _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 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 "saveload.h"
|
||||
#include "compat/labelmaps_sl_compat.h"
|
||||
|
||||
#include "../station_map.h"
|
||||
#include "../tunnelbridge_map.h"
|
||||
|
||||
#include "saveload.h"
|
||||
#include "saveload_internal.h"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
std::vector<RailTypeLabel> _railtype_list;
|
||||
void ResetLabelMaps();
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
extern std::vector<RailTypeLabel> _railtype_list;
|
||||
|
||||
/* 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;
|
||||
|
||||
railtype_conversion_map[i] = r;
|
||||
}
|
||||
for (uint i = (uint)_railtype_list.size(); i < RAILTYPE_END; i++) {
|
||||
railtype_conversion_map[i] = RAILTYPE_RAIL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ResetLabelMaps();
|
||||
}
|
||||
|
||||
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) {}
|
||||
|
||||
for (RailType r = RAILTYPE_BEGIN; r != RAILTYPE_END; r++) {
|
||||
lo.label = GetRailTypeInfo(r)->label;
|
||||
void Save() const override
|
||||
{
|
||||
SlTableHeader(_label_object_desc);
|
||||
|
||||
SlSetArrayIndex(r);
|
||||
SlObject(&lo, _label_object_desc);
|
||||
LabelObject lo;
|
||||
|
||||
for (RailType r = RAILTYPE_BEGIN; r != RAILTYPE_END; r++) {
|
||||
lo.label = GetRailTypeInfo(r)->label;
|
||||
|
||||
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"
|
||||
|
||||
struct GetLeagueChunkLoadInfo
|
||||
{
|
||||
static SaveLoadVersion GetLoadVersion()
|
||||
#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
|
||||
{
|
||||
return _sl_xv_upstream_version != SL_MIN_VERSION ? _sl_xv_upstream_version : SLV_MULTITRACK_LEVEL_CROSSINGS;
|
||||
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 ChunkHandler league_chunk_handlers[] = {
|
||||
MakeUpstreamChunkHandler<'LEAE', GetLeagueChunkLoadInfo>(),
|
||||
MakeUpstreamChunkHandler<'LEAT', GetLeagueChunkLoadInfo>(),
|
||||
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) {}
|
||||
|
||||
void Save() const override
|
||||
{
|
||||
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 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.";
|
||||
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),
|
||||
|
||||
/* 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);
|
||||
SLE_VAR2(LinkGraphJob, "join_date", join_date_ticks, SLE_INT32),
|
||||
SLE_VAR(LinkGraphJob, link_graph.index, SLE_UINT16),
|
||||
SLEG_STRUCT("linkgraph", SlLinkgraphJobProxy),
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
void Save() const override
|
||||
{
|
||||
SlTableHeader(_map_desc);
|
||||
|
||||
_map_dim_x = MapSizeX();
|
||||
_map_dim_y = MapSizeY();
|
||||
|
||||
SlSetArrayIndex(0);
|
||||
SlGlobList(_map_desc);
|
||||
}
|
||||
AllocateMap(_map_dim_x, _map_dim_y);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
void Load() const override
|
||||
{
|
||||
const std::vector<SaveLoad> slt = SlCompatTableHeader(_map_desc, _map_sl_compat);
|
||||
|
||||
if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() == -1) return;
|
||||
SlGlobList(slt);
|
||||
if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many MAPS entries");
|
||||
|
||||
AllocateMap(_map_dim_x, _map_dim_y);
|
||||
}
|
||||
|
||||
void LoadCheck(size_t) const override
|
||||
{
|
||||
const std::vector<SaveLoad> slt = SlCompatTableHeader(_map_desc, _map_sl_compat);
|
||||
|
||||
if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() == -1) return;
|
||||
SlGlobList(slt);
|
||||
if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many MAPS entries");
|
||||
|
||||
_load_check_data.map_size_x = _map_dim_x;
|
||||
_load_check_data.map_size_y = _map_dim_y;
|
||||
}
|
||||
};
|
||||
|
||||
static const uint MAP_SL_BUF_SIZE = 4096;
|
||||
|
||||
static void Load_MAPT()
|
||||
{
|
||||
std::array<byte, MAP_SL_BUF_SIZE> buf;
|
||||
TileIndex size = MapSize();
|
||||
struct MAPTChunkHandler : ChunkHandler {
|
||||
MAPTChunkHandler() : ChunkHandler('MAPT', CH_RIFF) {}
|
||||
|
||||
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];
|
||||
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++].type = buf[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static void Check_MAPH()
|
||||
{
|
||||
Check_MAPH_common();
|
||||
SlSkipBytes(SlGetFieldLength());
|
||||
}
|
||||
struct MAPHChunkHandler : ChunkHandler {
|
||||
MAPHChunkHandler() : ChunkHandler('MAPH', CH_RIFF) {}
|
||||
|
||||
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();
|
||||
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++].height = 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++].height;
|
||||
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct MAPOChunkHandler : ChunkHandler {
|
||||
MAPOChunkHandler() : ChunkHandler('MAPO', 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++].m1 = 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++].m1;
|
||||
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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;) {
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
void Save() const override
|
||||
{
|
||||
std::array<uint16, MAP_SL_BUF_SIZE> buf;
|
||||
TileIndex size = MapSize();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct M3LOChunkHandler : ChunkHandler {
|
||||
M3LOChunkHandler() : ChunkHandler('M3LO', 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++].m3 = 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++].m3;
|
||||
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
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++].m4;
|
||||
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct MAP5ChunkHandler : ChunkHandler {
|
||||
MAP5ChunkHandler() : ChunkHandler('MAP5', 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++].m5 = 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++].m5;
|
||||
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct MAPEChunkHandler : ChunkHandler {
|
||||
MAPEChunkHandler() : ChunkHandler('MAPE', CH_RIFF) {}
|
||||
|
||||
void Load() const override
|
||||
{
|
||||
std::array<byte, MAP_SL_BUF_SIZE> buf;
|
||||
TileIndex size = MapSize();
|
||||
|
||||
if (IsSavegameVersionBefore(SLV_42)) {
|
||||
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];
|
||||
/* 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];
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
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++].height = buf[j];
|
||||
}
|
||||
}
|
||||
|
||||
static void Load_MAP1()
|
||||
{
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
static void Load_MAP3()
|
||||
{
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
static void Load_MAP4()
|
||||
{
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
static void Load_MAP5()
|
||||
{
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
static void Load_MAP6()
|
||||
{
|
||||
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] = _me[i++].m6;
|
||||
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
};
|
||||
|
||||
struct MAP7ChunkHandler : ChunkHandler {
|
||||
MAP7ChunkHandler() : ChunkHandler('MAP7', CH_RIFF) {}
|
||||
|
||||
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++) _me[i++].m6 = buf[j];
|
||||
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
|
||||
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _me[i++].m7 = buf[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Load_MAP7()
|
||||
{
|
||||
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++) _me[i++].m7 = buf[j];
|
||||
}
|
||||
}
|
||||
|
||||
static void Load_MAP8()
|
||||
{
|
||||
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_UINT16);
|
||||
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _me[i++].m8 = buf[j];
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
#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();
|
||||
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);
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
};
|
||||
|
||||
struct MAP8ChunkHandler : ChunkHandler {
|
||||
MAP8ChunkHandler() : ChunkHandler('MAP8', CH_RIFF) {}
|
||||
|
||||
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];
|
||||
}
|
||||
#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);
|
||||
void Save() const override
|
||||
{
|
||||
std::array<uint16, MAP_SL_BUF_SIZE> buf;
|
||||
TileIndex size = MapSize();
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
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));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
struct MAPT {
|
||||
typedef uint8 FieldT;
|
||||
static const FieldT &GetField(TileIndex t) { return _m[t].type; }
|
||||
};
|
||||
|
||||
struct MAPH {
|
||||
typedef uint8 FieldT;
|
||||
static const FieldT &GetField(TileIndex t) { return _m[t].height; }
|
||||
};
|
||||
|
||||
struct MAP1 {
|
||||
typedef uint8 FieldT;
|
||||
static const FieldT &GetField(TileIndex t) { return _m[t].m1; }
|
||||
};
|
||||
|
||||
struct MAP2 {
|
||||
typedef uint16 FieldT;
|
||||
static const FieldT &GetField(TileIndex t) { return _m[t].m2; }
|
||||
};
|
||||
|
||||
struct MAP3 {
|
||||
typedef uint8 FieldT;
|
||||
static const FieldT &GetField(TileIndex t) { return _m[t].m3; }
|
||||
};
|
||||
|
||||
struct MAP4 {
|
||||
typedef uint8 FieldT;
|
||||
static const FieldT &GetField(TileIndex t) { return _m[t].m4; }
|
||||
};
|
||||
|
||||
struct MAP5 {
|
||||
typedef uint8 FieldT;
|
||||
static const FieldT &GetField(TileIndex t) { return _m[t].m5; }
|
||||
};
|
||||
|
||||
struct MAP6 {
|
||||
typedef uint8 FieldT;
|
||||
static const FieldT &GetField(TileIndex t) { return _me[t].m6; }
|
||||
};
|
||||
|
||||
struct MAP7 {
|
||||
typedef uint8 FieldT;
|
||||
static const FieldT &GetField(TileIndex t) { return _me[t].m7; }
|
||||
};
|
||||
|
||||
struct MAP8 {
|
||||
typedef uint16 FieldT;
|
||||
static const FieldT &GetField(TileIndex t) { return _me[t].m8; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct MAP_VarType {};
|
||||
|
||||
template <>
|
||||
struct MAP_VarType<uint8>
|
||||
{
|
||||
static const VarType var_type = SLE_UINT8;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct MAP_VarType<uint16>
|
||||
{
|
||||
static const VarType var_type = SLE_UINT16;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
static void Save_MAP()
|
||||
{
|
||||
assert(_sl_xv_feature_versions[XSLFI_WHOLE_MAP_CHUNK] == 0);
|
||||
|
||||
std::array<typename T::FieldT, 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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
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;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
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;
|
||||
extern int _saved_scrollpos_x;
|
||||
extern int _saved_scrollpos_y;
|
||||
extern 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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),
|
||||
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 void SaveLoad_VIEW()
|
||||
{
|
||||
SlGlobList(_view_desc);
|
||||
}
|
||||
static const SaveLoad _view_desc[] = {
|
||||
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 const ChunkHandler misc_chunk_handlers[] = {
|
||||
{ 'DATE', SaveLoad_DATE, SaveLoad_DATE, nullptr, Check_DATE, CH_RIFF },
|
||||
{ 'VIEW', SaveLoad_VIEW, SaveLoad_VIEW, nullptr, nullptr, CH_RIFF },
|
||||
struct VIEWChunkHandler : ChunkHandler {
|
||||
VIEWChunkHandler() : ChunkHandler('VIEW', CH_TABLE) {}
|
||||
|
||||
void Save() const override
|
||||
{
|
||||
SlTableHeader(_view_desc);
|
||||
|
||||
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();
|
||||
this->mapping.ResetMapping();
|
||||
|
||||
uint max_id = mapping.GetMaxMapping();
|
||||
|
||||
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;
|
||||
|
||||
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());
|
||||
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);
|
||||
}
|
||||
if (IsSavegameVersionBefore(SLV_101)) c->SetSuitablePalette();
|
||||
AppendToGRFConfigList(&grfconfig, c);
|
||||
}
|
||||
}
|
||||
|
||||
static void Load_NGRF()
|
||||
{
|
||||
Load_NGRF_common(_grfconfig);
|
||||
|
||||
if (_game_mode == GM_MENU) {
|
||||
/* Intro game must not have NewGRF. */
|
||||
if (_grfconfig != nullptr) SlErrorCorrupt("The intro game must not use NewGRF");
|
||||
void LoadCommon(GRFConfig *&grfconfig) const
|
||||
{
|
||||
const std::vector<SaveLoad> slt = SlCompatTableHeader(_grfconfig_desc, _grfconfig_sl_compat);
|
||||
|
||||
/* Activate intro NewGRFs (townnames) */
|
||||
ResetGRFConfig(false);
|
||||
} else {
|
||||
/* Append static NewGRF configuration */
|
||||
AppendStaticGRFConfigs(&_grfconfig);
|
||||
ClearGRFConfigList(&grfconfig);
|
||||
while (SlIterateArray() != -1) {
|
||||
GRFConfig *c = new GRFConfig();
|
||||
SlObject(c, slt);
|
||||
if (IsSavegameVersionBefore(SLV_101)) c->SetSuitablePalette();
|
||||
AppendToGRFConfigList(&grfconfig, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Check_NGRF()
|
||||
{
|
||||
Load_NGRF_common(_load_check_data.grfconfig);
|
||||
}
|
||||
void Load() const override
|
||||
{
|
||||
this->LoadCommon(_grfconfig);
|
||||
|
||||
static const ChunkHandler newgrf_chunk_handlers[] = {
|
||||
{ 'NGRF', Save_NGRF, Load_NGRF, nullptr, Check_NGRF, CH_ARRAY }
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void LoadCheck(size_t) const override
|
||||
{
|
||||
this->LoadCommon(_load_check_data.grfconfig);
|
||||
}
|
||||
};
|
||||
|
||||
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 */
|
||||
|
||||
@@ -1,42 +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 newsignals_sl.cpp Code handling saving and loading of new signals */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "../newgrf_newsignals.h"
|
||||
|
||||
#include "saveload.h"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
static void Save_NSID()
|
||||
{
|
||||
SlSetLength(4 + (lengthof(_new_signal_style_mapping) * 5));
|
||||
SlWriteUint32(lengthof(_new_signal_style_mapping));
|
||||
for (const NewSignalStyleMapping &mapping : _new_signal_style_mapping) {
|
||||
SlWriteUint32(mapping.grfid);
|
||||
SlWriteByte(mapping.grf_local_id);
|
||||
}
|
||||
}
|
||||
|
||||
static void Load_NSID()
|
||||
{
|
||||
uint count = SlReadUint32();
|
||||
for (uint i = 0; i < count; i++) {
|
||||
NewSignalStyleMapping mapping;
|
||||
mapping.grfid = SlReadUint32();
|
||||
mapping.grf_local_id = SlReadByte();
|
||||
if (i < lengthof(_new_signal_style_mapping)) _new_signal_style_mapping[i] = mapping;
|
||||
}
|
||||
}
|
||||
|
||||
static const ChunkHandler new_signal_chunk_handlers[] = {
|
||||
{ 'NSID', Save_NSID, Load_NSID, nullptr, nullptr, CH_RIFF },
|
||||
};
|
||||
|
||||
extern const ChunkHandlerTable _new_signal_chunk_handlers(new_signal_chunk_handlers);
|
||||
@@ -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) {}
|
||||
|
||||
static void Load_OBJS()
|
||||
{
|
||||
int index;
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
Object *o = new (index) Object();
|
||||
SlObject(o, _object_desc);
|
||||
}
|
||||
}
|
||||
void Save() const override
|
||||
{
|
||||
SlTableHeader(_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;
|
||||
/* Write the objects */
|
||||
for (Object *o : Object::Iterate()) {
|
||||
SlSetArrayIndex(o->index);
|
||||
SlObject(o, _object_desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Save_OBID()
|
||||
{
|
||||
Save_NewGRFMapping(_object_mngr);
|
||||
}
|
||||
void Load() const override
|
||||
{
|
||||
const std::vector<SaveLoad> slt = SlCompatTableHeader(_object_desc, _object_sl_compat);
|
||||
|
||||
static void Load_OBID()
|
||||
{
|
||||
Load_NewGRFMapping(_object_mngr);
|
||||
}
|
||||
int index;
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
Object *o = new (index) Object();
|
||||
SlObject(o, slt);
|
||||
}
|
||||
}
|
||||
|
||||
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 },
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct OBIDChunkHandler : NewGRFMappingChunkHandler {
|
||||
OBIDChunkHandler() : NewGRFMappingChunkHandler('OBID', _object_mngr) {}
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,333 +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 oldloader.cpp Functions for handling of TTO/TTD/TTDP savegames. */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "../debug.h"
|
||||
#include "../strings_type.h"
|
||||
#include "../string_func.h"
|
||||
#include "../settings_type.h"
|
||||
#include "../fileio_func.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
|
||||
#include "saveload_internal.h"
|
||||
#include "oldloader.h"
|
||||
|
||||
#include <exception>
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
static const int TTO_HEADER_SIZE = 41;
|
||||
static const int TTD_HEADER_SIZE = 49;
|
||||
|
||||
uint32 _bump_assert_value;
|
||||
|
||||
static inline OldChunkType GetOldChunkType(OldChunkType type) {return (OldChunkType)GB(type, 0, 4);}
|
||||
static inline OldChunkType GetOldChunkVarType(OldChunkType type) {return (OldChunkType)(GB(type, 8, 8) << 8);}
|
||||
static inline OldChunkType GetOldChunkFileType(OldChunkType type) {return (OldChunkType)(GB(type, 16, 8) << 16);}
|
||||
|
||||
static inline byte CalcOldVarLen(OldChunkType type)
|
||||
{
|
||||
static const byte type_mem_size[] = {0, 1, 1, 2, 2, 4, 4, 8};
|
||||
byte length = GB(type, 8, 8);
|
||||
assert(length != 0 && length < lengthof(type_mem_size));
|
||||
return type_mem_size[length];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Reads a byte from a file (do not call yourself, use ReadByte())
|
||||
*
|
||||
*/
|
||||
static byte ReadByteFromFile(LoadgameState *ls)
|
||||
{
|
||||
/* To avoid slow reads, we read BUFFER_SIZE of bytes per time
|
||||
and just return a byte per time */
|
||||
if (ls->buffer_cur >= ls->buffer_count) {
|
||||
|
||||
/* Read some new bytes from the file */
|
||||
int count = (int)fread(ls->buffer, 1, BUFFER_SIZE, ls->file);
|
||||
|
||||
/* We tried to read, but there is nothing in the file anymore.. */
|
||||
if (count == 0) {
|
||||
DEBUG(oldloader, 0, "Read past end of file, loading failed");
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
ls->buffer_count = count;
|
||||
ls->buffer_cur = 0;
|
||||
}
|
||||
|
||||
return ls->buffer[ls->buffer_cur++];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Reads a byte from the buffer and decompress if needed
|
||||
*
|
||||
*/
|
||||
byte ReadByte(LoadgameState *ls)
|
||||
{
|
||||
/* Old savegames have a nice compression algorithm (RLE)
|
||||
which means that we have a chunk, which starts with a length
|
||||
byte. If that byte is negative, we have to repeat the next byte
|
||||
that many times ( + 1). Else, we need to read that amount of bytes.
|
||||
Works pretty well if you have many zeros behind each other */
|
||||
|
||||
if (ls->chunk_size == 0) {
|
||||
/* Read new chunk */
|
||||
int8 new_byte = ReadByteFromFile(ls);
|
||||
|
||||
if (new_byte < 0) {
|
||||
/* Repeat next char for new_byte times */
|
||||
ls->decoding = true;
|
||||
ls->decode_char = ReadByteFromFile(ls);
|
||||
ls->chunk_size = -new_byte + 1;
|
||||
} else {
|
||||
ls->decoding = false;
|
||||
ls->chunk_size = new_byte + 1;
|
||||
}
|
||||
}
|
||||
|
||||
ls->total_read++;
|
||||
ls->chunk_size--;
|
||||
|
||||
return ls->decoding ? ls->decode_char : ReadByteFromFile(ls);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Loads a chunk from the old savegame
|
||||
*
|
||||
*/
|
||||
bool LoadChunk(LoadgameState *ls, void *base, const OldChunks *chunks)
|
||||
{
|
||||
byte *base_ptr = (byte*)base;
|
||||
|
||||
for (const OldChunks *chunk = chunks; chunk->type != OC_END; chunk++) {
|
||||
if (((chunk->type & OC_TTD) && _savegame_type == SGT_TTO) ||
|
||||
((chunk->type & OC_TTO) && _savegame_type != SGT_TTO)) {
|
||||
/* TTD(P)-only chunk, but TTO savegame || TTO-only chunk, but TTD/TTDP savegame */
|
||||
continue;
|
||||
}
|
||||
|
||||
byte *ptr = (byte*)chunk->ptr;
|
||||
if (chunk->type & OC_DEREFERENCE_POINTER) ptr = *(byte**)ptr;
|
||||
|
||||
for (uint i = 0; i < chunk->amount; i++) {
|
||||
/* Handle simple types */
|
||||
if (GetOldChunkType(chunk->type) != 0) {
|
||||
switch (GetOldChunkType(chunk->type)) {
|
||||
/* Just read the byte and forget about it */
|
||||
case OC_NULL: ReadByte(ls); break;
|
||||
|
||||
case OC_CHUNK:
|
||||
/* Call function, with 'i' as parameter to tell which item we
|
||||
* are going to read */
|
||||
if (!chunk->proc(ls, i)) return false;
|
||||
break;
|
||||
|
||||
case OC_ASSERT:
|
||||
DEBUG(oldloader, 4, "Assert point: 0x%X / 0x%X", ls->total_read, chunk->offset + _bump_assert_value);
|
||||
if (ls->total_read != chunk->offset + _bump_assert_value) throw std::exception();
|
||||
default: break;
|
||||
}
|
||||
} else {
|
||||
uint64 res = 0;
|
||||
|
||||
/* Reading from the file: bits 16 to 23 have the FILE type */
|
||||
switch (GetOldChunkFileType(chunk->type)) {
|
||||
case OC_FILE_I8: res = (int8)ReadByte(ls); break;
|
||||
case OC_FILE_U8: res = ReadByte(ls); break;
|
||||
case OC_FILE_I16: res = (int16)ReadUint16(ls); break;
|
||||
case OC_FILE_U16: res = ReadUint16(ls); break;
|
||||
case OC_FILE_I32: res = (int32)ReadUint32(ls); break;
|
||||
case OC_FILE_U32: res = ReadUint32(ls); break;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
|
||||
/* When both pointers are nullptr, we are just skipping data */
|
||||
if (base_ptr == nullptr && chunk->ptr == nullptr) continue;
|
||||
|
||||
/* Writing to the var: bits 8 to 15 have the VAR type */
|
||||
if (chunk->ptr == nullptr) ptr = base_ptr + chunk->offset;
|
||||
|
||||
/* Write the data */
|
||||
switch (GetOldChunkVarType(chunk->type)) {
|
||||
case OC_VAR_I8: *(int8 *)ptr = GB(res, 0, 8); break;
|
||||
case OC_VAR_U8: *(uint8 *)ptr = GB(res, 0, 8); break;
|
||||
case OC_VAR_I16:*(int16 *)ptr = GB(res, 0, 16); break;
|
||||
case OC_VAR_U16:*(uint16*)ptr = GB(res, 0, 16); break;
|
||||
case OC_VAR_I32:*(int32 *)ptr = res; break;
|
||||
case OC_VAR_U32:*(uint32*)ptr = res; break;
|
||||
case OC_VAR_I64:*(int64 *)ptr = res; break;
|
||||
case OC_VAR_U64:*(uint64*)ptr = res; break;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
|
||||
/* Increase pointer base for arrays when looping */
|
||||
if (chunk->amount > 1 && chunk->ptr != nullptr) ptr += CalcOldVarLen(chunk->type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Initialize some data before reading
|
||||
*
|
||||
*/
|
||||
static void InitLoading(LoadgameState *ls)
|
||||
{
|
||||
ls->chunk_size = 0;
|
||||
ls->total_read = 0;
|
||||
|
||||
ls->decoding = false;
|
||||
ls->decode_char = 0;
|
||||
|
||||
ls->buffer_cur = 0;
|
||||
ls->buffer_count = 0;
|
||||
memset(ls->buffer, 0, BUFFER_SIZE);
|
||||
|
||||
_bump_assert_value = 0;
|
||||
|
||||
_settings_game.construction.freeform_edges = false; // disable so we can convert map array (SetTileType is still used)
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the title has a valid checksum
|
||||
* @param title title and checksum
|
||||
* @param len the length of the title to read/checksum
|
||||
* @return true iff the title is valid
|
||||
* @note the title (incl. checksum) has to be at least 41/49 (HEADER_SIZE) bytes long!
|
||||
*/
|
||||
static bool VerifyOldNameChecksum(char *title, uint len)
|
||||
{
|
||||
uint16 sum = 0;
|
||||
for (uint i = 0; i < len - 2; i++) {
|
||||
sum += title[i];
|
||||
sum = ROL(sum, 1);
|
||||
}
|
||||
|
||||
sum ^= 0xAAAA; // computed checksum
|
||||
|
||||
uint16 sum2 = title[len - 2]; // checksum in file
|
||||
SB(sum2, 8, 8, title[len - 1]);
|
||||
|
||||
return sum == sum2;
|
||||
}
|
||||
|
||||
static inline bool CheckOldSavegameType(FILE *f, char *temp, const char *last, uint len)
|
||||
{
|
||||
assert(last - temp + 1 >= (int)len);
|
||||
|
||||
if (fread(temp, 1, len, f) != len) {
|
||||
temp[0] = '\0'; // if reading failed, make the name empty
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret = VerifyOldNameChecksum(temp, len);
|
||||
temp[len - 2] = '\0'; // name is null-terminated in savegame, but it's better to be sure
|
||||
StrMakeValidInPlace(temp, last);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static SavegameType DetermineOldSavegameType(FILE *f, char *title, const char *last)
|
||||
{
|
||||
static_assert(TTD_HEADER_SIZE >= TTO_HEADER_SIZE);
|
||||
char temp[TTD_HEADER_SIZE] = "Unknown";
|
||||
|
||||
SavegameType type = SGT_TTO;
|
||||
|
||||
/* Can't fseek to 0 as in tar files that is not correct */
|
||||
long pos = ftell(f);
|
||||
if (pos >= 0 && !CheckOldSavegameType(f, temp, lastof(temp), TTO_HEADER_SIZE)) {
|
||||
type = SGT_TTD;
|
||||
if (fseek(f, pos, SEEK_SET) < 0 || !CheckOldSavegameType(f, temp, lastof(temp), TTD_HEADER_SIZE)) {
|
||||
type = SGT_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
if (title != nullptr) {
|
||||
switch (type) {
|
||||
case SGT_TTO: title = strecpy(title, "(TTO) ", last); break;
|
||||
case SGT_TTD: title = strecpy(title, "(TTD) ", last); break;
|
||||
default: title = strecpy(title, "(broken) ", last); break;
|
||||
}
|
||||
strecpy(title, temp, last);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
typedef bool LoadOldMainProc(LoadgameState *ls);
|
||||
|
||||
bool LoadOldSaveGame(const std::string &file)
|
||||
{
|
||||
LoadgameState ls;
|
||||
|
||||
DEBUG(oldloader, 3, "Trying to load a TTD(Patch) savegame");
|
||||
|
||||
InitLoading(&ls);
|
||||
|
||||
/* Open file */
|
||||
ls.file = FioFOpenFile(file, "rb", NO_DIRECTORY);
|
||||
|
||||
if (ls.file == nullptr) {
|
||||
DEBUG(oldloader, 0, "Cannot open file '%s'", file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
SavegameType type = DetermineOldSavegameType(ls.file, nullptr, nullptr);
|
||||
|
||||
LoadOldMainProc *proc = nullptr;
|
||||
|
||||
switch (type) {
|
||||
case SGT_TTO: proc = &LoadTTOMain; break;
|
||||
case SGT_TTD: proc = &LoadTTDMain; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
_savegame_type = type;
|
||||
|
||||
bool game_loaded;
|
||||
try {
|
||||
game_loaded = proc != nullptr && proc(&ls);
|
||||
} catch (...) {
|
||||
game_loaded = false;
|
||||
}
|
||||
|
||||
fclose(ls.file);
|
||||
|
||||
if (!game_loaded) {
|
||||
SetSaveLoadError(STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED);
|
||||
return false;
|
||||
}
|
||||
|
||||
_pause_mode = PM_PAUSED_SAVELOAD;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GetOldSaveGameName(const std::string &file, char *title, const char *last)
|
||||
{
|
||||
FILE *f = FioFOpenFile(file, "rb", NO_DIRECTORY);
|
||||
|
||||
if (f == nullptr) {
|
||||
*title = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
DetermineOldSavegameType(f, title, last);
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
@@ -1,135 +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 oldloader.h Declarations of strctures and function used in loader of old savegames */
|
||||
|
||||
#ifndef OLDLOADER_H
|
||||
#define OLDLOADER_H
|
||||
|
||||
#include "saveload.h"
|
||||
#include "../tile_type.h"
|
||||
|
||||
static const uint BUFFER_SIZE = 4096;
|
||||
static const uint OLD_MAP_SIZE = 256 * 256;
|
||||
|
||||
struct LoadgameState {
|
||||
FILE *file;
|
||||
|
||||
uint chunk_size;
|
||||
|
||||
bool decoding;
|
||||
byte decode_char;
|
||||
|
||||
uint buffer_count;
|
||||
uint buffer_cur;
|
||||
byte buffer[BUFFER_SIZE];
|
||||
|
||||
uint total_read;
|
||||
};
|
||||
|
||||
/* OldChunk-Type */
|
||||
enum OldChunkType {
|
||||
OC_SIMPLE = 0,
|
||||
OC_NULL = 1,
|
||||
OC_CHUNK = 2,
|
||||
OC_ASSERT = 3,
|
||||
/* 4 bits allocated (16 max) */
|
||||
|
||||
OC_TTD = 1 << 4, ///< chunk is valid ONLY for TTD savegames
|
||||
OC_TTO = 1 << 5, ///< -//- TTO (default is neither of these)
|
||||
/* 4 bits allocated */
|
||||
|
||||
OC_VAR_I8 = 1 << 8,
|
||||
OC_VAR_U8 = 2 << 8,
|
||||
OC_VAR_I16 = 3 << 8,
|
||||
OC_VAR_U16 = 4 << 8,
|
||||
OC_VAR_I32 = 5 << 8,
|
||||
OC_VAR_U32 = 6 << 8,
|
||||
OC_VAR_I64 = 7 << 8,
|
||||
OC_VAR_U64 = 8 << 8,
|
||||
/* 8 bits allocated (256 max) */
|
||||
|
||||
OC_FILE_I8 = 1 << 16,
|
||||
OC_FILE_U8 = 2 << 16,
|
||||
OC_FILE_I16 = 3 << 16,
|
||||
OC_FILE_U16 = 4 << 16,
|
||||
OC_FILE_I32 = 5 << 16,
|
||||
OC_FILE_U32 = 6 << 16,
|
||||
/* 8 bits allocated (256 max) */
|
||||
|
||||
OC_INT8 = OC_VAR_I8 | OC_FILE_I8,
|
||||
OC_UINT8 = OC_VAR_U8 | OC_FILE_U8,
|
||||
OC_INT16 = OC_VAR_I16 | OC_FILE_I16,
|
||||
OC_UINT16 = OC_VAR_U16 | OC_FILE_U16,
|
||||
OC_INT32 = OC_VAR_I32 | OC_FILE_I32,
|
||||
OC_UINT32 = OC_VAR_U32 | OC_FILE_U32,
|
||||
|
||||
OC_TILE = OC_VAR_U32 | OC_FILE_U16,
|
||||
|
||||
/**
|
||||
* Dereference the pointer once before writing to it,
|
||||
* so we do not have to use big static arrays.
|
||||
*/
|
||||
OC_DEREFERENCE_POINTER = 1 << 31,
|
||||
|
||||
OC_END = 0, ///< End of the whole chunk, all 32 bits set to zero
|
||||
};
|
||||
|
||||
DECLARE_ENUM_AS_BIT_SET(OldChunkType)
|
||||
|
||||
typedef bool OldChunkProc(LoadgameState *ls, int num);
|
||||
|
||||
struct OldChunks {
|
||||
OldChunkType type; ///< Type of field
|
||||
uint32 amount; ///< Amount of fields
|
||||
|
||||
void *ptr; ///< Pointer where to save the data (may only be set if offset is 0)
|
||||
uint offset; ///< Offset from basepointer (may only be set if ptr is nullptr)
|
||||
OldChunkProc *proc; ///< Pointer to function that is called with OC_CHUNK
|
||||
};
|
||||
|
||||
/* If it fails, check lines above.. */
|
||||
static_assert(sizeof(TileIndex) == 4);
|
||||
|
||||
extern uint _bump_assert_value;
|
||||
byte ReadByte(LoadgameState *ls);
|
||||
bool LoadChunk(LoadgameState *ls, void *base, const OldChunks *chunks);
|
||||
|
||||
bool LoadTTDMain(LoadgameState *ls);
|
||||
bool LoadTTOMain(LoadgameState *ls);
|
||||
|
||||
static inline uint16 ReadUint16(LoadgameState *ls)
|
||||
{
|
||||
byte x = ReadByte(ls);
|
||||
return x | ReadByte(ls) << 8;
|
||||
}
|
||||
|
||||
static inline uint32 ReadUint32(LoadgameState *ls)
|
||||
{
|
||||
uint16 x = ReadUint16(ls);
|
||||
return x | ReadUint16(ls) << 16;
|
||||
}
|
||||
|
||||
/* Help:
|
||||
* - OCL_SVAR: load 'type' to offset 'offset' in a struct of type 'base', which must also
|
||||
* be given via base in LoadChunk() as real pointer
|
||||
* - OCL_VAR: load 'type' to a global var
|
||||
* - OCL_END: every struct must end with this
|
||||
* - OCL_NULL: read 'amount' of bytes and send them to /dev/null or something
|
||||
* - OCL_CHUNK: load another proc to load a part of the savegame, 'amount' times
|
||||
* - OCL_ASSERT: to check if we are really at the place we expect to be.. because old savegames are too binary to be sure ;)
|
||||
*/
|
||||
#define OCL_SVAR(type, base, offset) { type, 1, nullptr, (uint)cpp_offsetof(base, offset), nullptr }
|
||||
#define OCL_VAR(type, amount, pointer) { type, amount, pointer, 0, nullptr }
|
||||
#define OCL_END() { OC_END, 0, nullptr, 0, nullptr }
|
||||
#define OCL_CNULL(type, amount) { OC_NULL | type, amount, nullptr, 0, nullptr }
|
||||
#define OCL_CCHUNK(type, amount, proc) { OC_CHUNK | type, amount, nullptr, 0, proc }
|
||||
#define OCL_ASSERT(type, size) { OC_ASSERT | type, 1, nullptr, size, nullptr }
|
||||
#define OCL_NULL(amount) OCL_CNULL((OldChunkType)0, amount)
|
||||
#define OCL_CHUNK(amount, proc) OCL_CCHUNK((OldChunkType)0, amount, proc)
|
||||
|
||||
#endif /* OLDLOADER_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
|
||||
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]));
|
||||
}
|
||||
|
||||
free(orders);
|
||||
} else if (IsSavegameVersionBefore(SLV_5, 2)) {
|
||||
len /= sizeof(uint32);
|
||||
uint32 *orders = MallocT<uint32>(len + 1);
|
||||
|
||||
SlArray(orders, len, SLE_UINT32);
|
||||
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
Order *o = new (i) Order();
|
||||
o->AssignOrder(UnpackVersion5Order(orders[i]));
|
||||
}
|
||||
|
||||
free(orders);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
Order *order = new (index) Order();
|
||||
SlObjectLoadFiltered(order, _filtered_desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)),
|
||||
};
|
||||
|
||||
return _order_extra_info_desc;
|
||||
}
|
||||
|
||||
void Save_ORDX()
|
||||
{
|
||||
_filtered_desc = SlFilterObject(GetOrderExtraInfoDescription());
|
||||
for (Order *order : Order::Iterate()) {
|
||||
if (order->extra) {
|
||||
for (Order *order : Order::Iterate()) {
|
||||
SlSetArrayIndex(order->index);
|
||||
SlObjectSaveFiltered(order->extra.get(), _filtered_desc);
|
||||
SlObject(order, slt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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();
|
||||
|
||||
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);
|
||||
|
||||
SlCopy(orders, len, SLE_UINT16);
|
||||
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
Order *o = new (i) Order();
|
||||
o->AssignOrder(UnpackVersion4Order(orders[i]));
|
||||
}
|
||||
|
||||
free(orders);
|
||||
} else if (IsSavegameVersionBefore(SLV_5, 2)) {
|
||||
len /= sizeof(uint32);
|
||||
uint32 *orders = MallocT<uint32>(len + 1);
|
||||
|
||||
SlCopy(orders, len, SLE_UINT32);
|
||||
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
new (i) Order(orders[i]);
|
||||
}
|
||||
|
||||
free(orders);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
int index;
|
||||
|
||||
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);
|
||||
struct ORDLChunkHandler : ChunkHandler {
|
||||
ORDLChunkHandler() : ChunkHandler('ORDL', CH_TABLE) {}
|
||||
|
||||
void Save() const override
|
||||
{
|
||||
const SaveLoadTable slt = GetOrderListDescription();
|
||||
SlTableHeader(slt);
|
||||
|
||||
for (OrderList *list : OrderList::Iterate()) {
|
||||
SlSetArrayIndex(list->index);
|
||||
SlObject(list, slt);
|
||||
}
|
||||
}
|
||||
|
||||
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 FixPointers() const override
|
||||
{
|
||||
for (OrderList *list : OrderList::Iterate()) {
|
||||
SlObject(list, GetOrderListDescription());
|
||||
SlWriteUint32(list->GetScheduledDispatchScheduleCount());
|
||||
for (DispatchSchedule &ds : list->GetScheduledDispatchScheduleSet()) {
|
||||
SlObject(&ds, GetDispatchScheduleDescription());
|
||||
}
|
||||
}, list);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
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 Ptrs_ORDL()
|
||||
{
|
||||
for (OrderList *list : OrderList::Iterate()) {
|
||||
SlObject(list, GetOrderListDescription());
|
||||
list->ReindexOrderList();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
struct BKORChunkHandler : ChunkHandler {
|
||||
BKORChunkHandler() : ChunkHandler('BKOR', CH_TABLE) {}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
void Save() const override
|
||||
{
|
||||
const SaveLoadTable slt = GetOrderBackupDescription();
|
||||
SlTableHeader(slt);
|
||||
|
||||
void Load_BKOR()
|
||||
{
|
||||
int index;
|
||||
/* 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;
|
||||
|
||||
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());
|
||||
}
|
||||
for (OrderBackup *ob : OrderBackup::Iterate()) {
|
||||
SlSetArrayIndex(ob->index);
|
||||
SlObject(ob, slt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Ptrs_BKOR()
|
||||
{
|
||||
for (OrderBackup *ob : OrderBackup::Iterate()) {
|
||||
SlObject(ob, GetOrderBackupDescription());
|
||||
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 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 },
|
||||
void FixPointers() const override
|
||||
{
|
||||
for (OrderBackup *ob : OrderBackup::Iterate()) {
|
||||
SlObject(ob, GetOrderBackupDescription());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,97 +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 plans_sl.cpp Code handling saving and loading of plans data. */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "../plans_base.h"
|
||||
#include "../fios.h"
|
||||
|
||||
#include "saveload.h"
|
||||
|
||||
/** Description of a plan within the savegame. */
|
||||
static const SaveLoad _plan_desc[] = {
|
||||
SLE_VAR(Plan, owner, SLE_UINT8),
|
||||
SLE_VAR(Plan, visible, SLE_BOOL),
|
||||
SLE_VAR(Plan, visible_by_all, SLE_BOOL),
|
||||
SLE_VAR(Plan, creation_date, SLE_INT32),
|
||||
SLE_CONDSSTR_X(Plan, name, 0, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ENH_VIEWPORT_PLANS, 3)),
|
||||
SLE_CONDSSTR_X(Plan, name, 0, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP, SL_JOKER_1_20)),
|
||||
SLE_CONDVAR_X(Plan, colour, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ENH_VIEWPORT_PLANS, 4)),
|
||||
};
|
||||
|
||||
static void RealSave_PLAN(Plan *p)
|
||||
{
|
||||
SlObject(p, _plan_desc);
|
||||
SlWriteUint32((uint32)p->lines.size());
|
||||
for (size_t i = 0; i < p->lines.size(); i++) {
|
||||
PlanLine *pl = p->lines[i];
|
||||
SlWriteUint32((uint32)pl->tiles.size());
|
||||
SlArray(pl->tiles.data(), pl->tiles.size(), SLE_UINT32);
|
||||
}
|
||||
}
|
||||
|
||||
/** Save all plans. */
|
||||
static void Save_PLAN()
|
||||
{
|
||||
for (Plan *p : Plan::Iterate()) {
|
||||
SlSetArrayIndex(p->index);
|
||||
SlAutolength((AutolengthProc*) RealSave_PLAN, p);
|
||||
}
|
||||
}
|
||||
|
||||
/** Load all plans. */
|
||||
static void Load_PLAN()
|
||||
{
|
||||
int index;
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
Plan *p = new (index) Plan();
|
||||
SlObject(p, _plan_desc);
|
||||
if (SlXvIsFeaturePresent(XSLFI_ENH_VIEWPORT_PLANS, 2)) {
|
||||
const size_t line_count = SlReadUint32();
|
||||
p->lines.resize(line_count);
|
||||
for (size_t i = 0; i < line_count; i++) {
|
||||
PlanLine *pl = new PlanLine();
|
||||
p->lines[i] = pl;
|
||||
const size_t tile_count = SlReadUint32();
|
||||
pl->tiles.resize(tile_count);
|
||||
SlArray(pl->tiles.data(), tile_count, SLE_UINT32);
|
||||
pl->UpdateVisualExtents();
|
||||
}
|
||||
p->SetVisibility(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Load all plan lines. */
|
||||
static void Load_PLANLINE()
|
||||
{
|
||||
int index;
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
Plan *p = Plan::Get((uint) index >> 16);
|
||||
uint line_index = index & 0xFFFF;
|
||||
if (p->lines.size() <= line_index) p->lines.resize(line_index + 1);
|
||||
PlanLine *pl = new PlanLine();
|
||||
p->lines[line_index] = pl;
|
||||
size_t plsz = SlGetFieldLength() / sizeof(TileIndex);
|
||||
pl->tiles.resize(plsz);
|
||||
SlArray(pl->tiles.data(), plsz, SLE_UINT32);
|
||||
pl->UpdateVisualExtents();
|
||||
}
|
||||
|
||||
for (Plan *p : Plan::Iterate()) {
|
||||
p->SetVisibility(false);
|
||||
}
|
||||
}
|
||||
|
||||
/** Chunk handlers related to plans. */
|
||||
static const ChunkHandler plan_chunk_handlers[] = {
|
||||
{ 'PLAN', Save_PLAN, Load_PLAN, nullptr, nullptr, CH_ARRAY },
|
||||
{ 'PLLN', nullptr, Load_PLANLINE, nullptr, nullptr, CH_ARRAY },
|
||||
};
|
||||
|
||||
extern const ChunkHandlerTable _plan_chunk_handlers(plan_chunk_handlers);
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,264 +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 saveload_buffer.h Functions/types related to buffers used for saving and loading games. */
|
||||
|
||||
#ifndef SAVELOAD_BUFFER_H
|
||||
#define SAVELOAD_BUFFER_H
|
||||
|
||||
#include "../core/alloc_func.hpp"
|
||||
#include "../core/endian_type.hpp"
|
||||
#include "../core/endian_func.hpp"
|
||||
#include "../core/math_func.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
struct LoadFilter;
|
||||
struct SaveFilter;
|
||||
|
||||
/** Save in chunks of 128 KiB. */
|
||||
static const size_t MEMORY_CHUNK_SIZE = 128 * 1024;
|
||||
|
||||
/** A buffer for reading (and buffering) savegame data. */
|
||||
struct ReadBuffer {
|
||||
byte buf[MEMORY_CHUNK_SIZE]; ///< Buffer we're going to read from.
|
||||
byte *bufp; ///< Location we're at reading the buffer.
|
||||
byte *bufe; ///< End of the buffer we can read from.
|
||||
LoadFilter *reader; ///< The filter used to actually read.
|
||||
size_t read; ///< The amount of read bytes so far from the filter.
|
||||
|
||||
/**
|
||||
* Initialise our variables.
|
||||
* @param reader The filter to actually read data.
|
||||
*/
|
||||
ReadBuffer(LoadFilter *reader) : bufp(nullptr), bufe(nullptr), reader(reader), read(0)
|
||||
{
|
||||
}
|
||||
|
||||
static ReadBuffer *GetCurrent();
|
||||
|
||||
void SkipBytesSlowPath(size_t bytes);
|
||||
void AcquireBytes();
|
||||
|
||||
inline void SkipBytes(size_t bytes)
|
||||
{
|
||||
byte *b = this->bufp + bytes;
|
||||
if (likely(b <= this->bufe)) {
|
||||
this->bufp = b;
|
||||
} else {
|
||||
SkipBytesSlowPath(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
inline byte RawReadByte()
|
||||
{
|
||||
return *this->bufp++;
|
||||
}
|
||||
|
||||
inline byte ReadByte()
|
||||
{
|
||||
if (unlikely(this->bufp == this->bufe)) {
|
||||
this->AcquireBytes();
|
||||
}
|
||||
|
||||
return RawReadByte();
|
||||
}
|
||||
|
||||
inline void CheckBytes(size_t bytes)
|
||||
{
|
||||
while (unlikely(this->bufp + bytes > this->bufe)) this->AcquireBytes();
|
||||
}
|
||||
|
||||
inline int RawReadUint16()
|
||||
{
|
||||
#if OTTD_ALIGNMENT == 0
|
||||
int x = FROM_BE16(*((const unaligned_uint16*) this->bufp));
|
||||
this->bufp += 2;
|
||||
return x;
|
||||
#else
|
||||
int x = this->RawReadByte() << 8;
|
||||
return x | this->RawReadByte();
|
||||
#endif
|
||||
}
|
||||
|
||||
inline uint32 RawReadUint32()
|
||||
{
|
||||
#if OTTD_ALIGNMENT == 0
|
||||
uint32 x = FROM_BE32(*((const unaligned_uint32*) this->bufp));
|
||||
this->bufp += 4;
|
||||
return x;
|
||||
#else
|
||||
uint32 x = this->RawReadUint16() << 16;
|
||||
return x | this->RawReadUint16();
|
||||
#endif
|
||||
}
|
||||
|
||||
inline uint64 RawReadUint64()
|
||||
{
|
||||
#if OTTD_ALIGNMENT == 0
|
||||
uint64 x = FROM_BE64(*((const unaligned_uint64*) this->bufp));
|
||||
this->bufp += 8;
|
||||
return x;
|
||||
#else
|
||||
uint32 x = this->RawReadUint32();
|
||||
uint32 y = this->RawReadUint32();
|
||||
return (uint64)x << 32 | y;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void CopyBytes(byte *ptr, size_t length)
|
||||
{
|
||||
while (length) {
|
||||
if (unlikely(this->bufp == this->bufe)) {
|
||||
this->AcquireBytes();
|
||||
}
|
||||
size_t to_copy = std::min<size_t>(this->bufe - this->bufp, length);
|
||||
memcpy(ptr, this->bufp, to_copy);
|
||||
this->bufp += to_copy;
|
||||
ptr += to_copy;
|
||||
length -= to_copy;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of the memory dump made so far.
|
||||
* @return The size.
|
||||
*/
|
||||
inline size_t GetSize() const
|
||||
{
|
||||
return this->read - (this->bufe - this->bufp);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Container for dumping the savegame (quickly) to memory. */
|
||||
struct MemoryDumper {
|
||||
struct BufferInfo {
|
||||
byte *data;
|
||||
size_t size = 0;
|
||||
|
||||
BufferInfo(byte *d) : data(d) {}
|
||||
~BufferInfo() { free(this->data); }
|
||||
|
||||
BufferInfo(const BufferInfo &) = delete;
|
||||
BufferInfo(BufferInfo &&other) : data(other.data), size(other.size) { other.data = nullptr; };
|
||||
};
|
||||
|
||||
std::vector<BufferInfo> blocks; ///< Buffer with blocks of allocated memory.
|
||||
byte *buf = nullptr; ///< Buffer we're going to write to.
|
||||
byte *bufe = nullptr; ///< End of the buffer we write to.
|
||||
size_t completed_block_bytes = 0; ///< Total byte count of completed blocks.
|
||||
|
||||
byte *autolen_buf = nullptr;
|
||||
byte *autolen_buf_end = nullptr;
|
||||
byte *saved_buf = nullptr;
|
||||
byte *saved_bufe = nullptr;
|
||||
|
||||
MemoryDumper()
|
||||
{
|
||||
const size_t size = 8192;
|
||||
this->autolen_buf = CallocT<byte>(size);
|
||||
this->autolen_buf_end = this->autolen_buf + size;
|
||||
}
|
||||
|
||||
~MemoryDumper()
|
||||
{
|
||||
free(this->autolen_buf);
|
||||
}
|
||||
|
||||
static MemoryDumper *GetCurrent();
|
||||
|
||||
void FinaliseBlock();
|
||||
void AllocateBuffer();
|
||||
|
||||
inline void CheckBytes(size_t bytes)
|
||||
{
|
||||
if (unlikely(this->buf + bytes > this->bufe)) this->AllocateBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a single byte into the dumper.
|
||||
* @param b The byte to write.
|
||||
*/
|
||||
inline void WriteByte(byte b)
|
||||
{
|
||||
/* Are we at the end of this chunk? */
|
||||
if (unlikely(this->buf == this->bufe)) {
|
||||
this->AllocateBuffer();
|
||||
}
|
||||
|
||||
*this->buf++ = b;
|
||||
}
|
||||
|
||||
inline void CopyBytes(const byte *ptr, size_t length)
|
||||
{
|
||||
while (length) {
|
||||
if (unlikely(this->buf == this->bufe)) {
|
||||
this->AllocateBuffer();
|
||||
}
|
||||
size_t to_copy = std::min<size_t>(this->bufe - this->buf, length);
|
||||
memcpy(this->buf, ptr, to_copy);
|
||||
this->buf += to_copy;
|
||||
ptr += to_copy;
|
||||
length -= to_copy;
|
||||
}
|
||||
}
|
||||
|
||||
inline void RawWriteByte(byte b)
|
||||
{
|
||||
*this->buf++ = b;
|
||||
}
|
||||
|
||||
inline void RawWriteUint16(uint16 v)
|
||||
{
|
||||
#if OTTD_ALIGNMENT == 0
|
||||
*((unaligned_uint16 *) this->buf) = TO_BE16(v);
|
||||
#else
|
||||
this->buf[0] = GB(v, 8, 8);
|
||||
this->buf[1] = GB(v, 0, 8);
|
||||
#endif
|
||||
this->buf += 2;
|
||||
}
|
||||
|
||||
inline void RawWriteUint32(uint32 v)
|
||||
{
|
||||
#if OTTD_ALIGNMENT == 0
|
||||
*((unaligned_uint32 *) this->buf) = TO_BE32(v);
|
||||
#else
|
||||
this->buf[0] = GB(v, 24, 8);
|
||||
this->buf[1] = GB(v, 16, 8);
|
||||
this->buf[2] = GB(v, 8, 8);
|
||||
this->buf[3] = GB(v, 0, 8);
|
||||
#endif
|
||||
this->buf += 4;
|
||||
}
|
||||
|
||||
inline void RawWriteUint64(uint64 v)
|
||||
{
|
||||
#if OTTD_ALIGNMENT == 0
|
||||
*((unaligned_uint64 *) this->buf) = TO_BE64(v);
|
||||
#else
|
||||
this->buf[0] = GB(v, 56, 8);
|
||||
this->buf[1] = GB(v, 48, 8);
|
||||
this->buf[2] = GB(v, 40, 8);
|
||||
this->buf[3] = GB(v, 32, 8);
|
||||
this->buf[4] = GB(v, 24, 8);
|
||||
this->buf[5] = GB(v, 16, 8);
|
||||
this->buf[6] = GB(v, 8, 8);
|
||||
this->buf[7] = GB(v, 0, 8);
|
||||
#endif
|
||||
this->buf += 8;
|
||||
}
|
||||
|
||||
void Flush(SaveFilter *writer);
|
||||
size_t GetSize() const;
|
||||
void StartAutoLength();
|
||||
std::pair<byte *, size_t> StopAutoLength();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,422 +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 saveload_common.h Common functions/types for saving and loading games. */
|
||||
|
||||
#ifndef SAVELOAD_COMMON_H
|
||||
#define SAVELOAD_COMMON_H
|
||||
|
||||
#include "../strings_type.h"
|
||||
#include "../core/span_type.hpp"
|
||||
|
||||
struct SaveLoad;
|
||||
|
||||
/** A table of SaveLoad entries. */
|
||||
using SaveLoadTable = span<const SaveLoad>;
|
||||
|
||||
namespace upstream_sl {
|
||||
struct SaveLoad;
|
||||
|
||||
/** A table of SaveLoad entries. */
|
||||
using SaveLoadTable = span<const SaveLoad>;
|
||||
}
|
||||
|
||||
/** SaveLoad versions
|
||||
* Previous savegame versions, the trunk revision where they were
|
||||
* introduced and the released version that had that particular
|
||||
* savegame version.
|
||||
* Up to savegame version 18 there is a minor version as well.
|
||||
*
|
||||
* Older entries keep their original numbering.
|
||||
*
|
||||
* Newer entries should use a descriptive labels, numeric version
|
||||
* and PR can be added to comment.
|
||||
*
|
||||
* Note that this list must not be reordered.
|
||||
*/
|
||||
enum SaveLoadVersion : uint16 {
|
||||
SL_MIN_VERSION, ///< First savegame version
|
||||
|
||||
SLV_1, ///< 1.0 0.1.x, 0.2.x
|
||||
SLV_2, /**< 2.0 0.3.0
|
||||
* 2.1 0.3.1, 0.3.2 */
|
||||
SLV_3, ///< 3.x lost
|
||||
SLV_4, /**< 4.0 1
|
||||
* 4.1 122 0.3.3, 0.3.4
|
||||
* 4.2 1222 0.3.5
|
||||
* 4.3 1417
|
||||
* 4.4 1426 */
|
||||
|
||||
SLV_5, /**< 5.0 1429
|
||||
* 5.1 1440
|
||||
* 5.2 1525 0.3.6 */
|
||||
SLV_6, /**< 6.0 1721
|
||||
* 6.1 1768 */
|
||||
SLV_7, ///< 7.0 1770
|
||||
SLV_8, ///< 8.0 1786
|
||||
SLV_9, ///< 9.0 1909
|
||||
|
||||
SLV_10, ///< 10.0 2030
|
||||
SLV_11, /**< 11.0 2033
|
||||
* 11.1 2041 */
|
||||
SLV_12, ///< 12.1 2046
|
||||
SLV_13, ///< 13.1 2080 0.4.0, 0.4.0.1
|
||||
SLV_14, ///< 14.0 2441
|
||||
|
||||
SLV_15, ///< 15.0 2499
|
||||
SLV_16, /**< 16.0 2817
|
||||
* 16.1 3155 */
|
||||
SLV_17, /**< 17.0 3212
|
||||
* 17.1 3218 */
|
||||
SLV_18, ///< 18 3227
|
||||
SLV_19, ///< 19 3396
|
||||
|
||||
SLV_20, ///< 20 3403
|
||||
SLV_21, ///< 21 3472 0.4.x
|
||||
SLV_22, ///< 22 3726
|
||||
SLV_23, ///< 23 3915
|
||||
SLV_24, ///< 24 4150
|
||||
|
||||
SLV_25, ///< 25 4259
|
||||
SLV_26, ///< 26 4466
|
||||
SLV_27, ///< 27 4757
|
||||
SLV_28, ///< 28 4987
|
||||
SLV_29, ///< 29 5070
|
||||
|
||||
SLV_30, ///< 30 5946
|
||||
SLV_31, ///< 31 5999
|
||||
SLV_32, ///< 32 6001
|
||||
SLV_33, ///< 33 6440
|
||||
SLV_34, ///< 34 6455
|
||||
|
||||
SLV_35, ///< 35 6602
|
||||
SLV_36, ///< 36 6624
|
||||
SLV_37, ///< 37 7182
|
||||
SLV_38, ///< 38 7195
|
||||
SLV_39, ///< 39 7269
|
||||
|
||||
SLV_40, ///< 40 7326
|
||||
SLV_41, ///< 41 7348 0.5.x
|
||||
SLV_42, ///< 42 7573
|
||||
SLV_43, ///< 43 7642
|
||||
SLV_44, ///< 44 8144
|
||||
|
||||
SLV_45, ///< 45 8501
|
||||
SLV_46, ///< 46 8705
|
||||
SLV_47, ///< 47 8735
|
||||
SLV_48, ///< 48 8935
|
||||
SLV_49, ///< 49 8969
|
||||
|
||||
SLV_50, ///< 50 8973
|
||||
SLV_51, ///< 51 8978
|
||||
SLV_52, ///< 52 9066
|
||||
SLV_53, ///< 53 9316
|
||||
SLV_54, ///< 54 9613
|
||||
|
||||
SLV_55, ///< 55 9638
|
||||
SLV_56, ///< 56 9667
|
||||
SLV_57, ///< 57 9691
|
||||
SLV_58, ///< 58 9762
|
||||
SLV_59, ///< 59 9779
|
||||
|
||||
SLV_60, ///< 60 9874
|
||||
SLV_61, ///< 61 9892
|
||||
SLV_62, ///< 62 9905
|
||||
SLV_63, ///< 63 9956
|
||||
SLV_64, ///< 64 10006
|
||||
|
||||
SLV_65, ///< 65 10210
|
||||
SLV_66, ///< 66 10211
|
||||
SLV_67, ///< 67 10236
|
||||
SLV_68, ///< 68 10266
|
||||
SLV_69, ///< 69 10319
|
||||
|
||||
SLV_70, ///< 70 10541
|
||||
SLV_71, ///< 71 10567
|
||||
SLV_72, ///< 72 10601
|
||||
SLV_73, ///< 73 10903
|
||||
SLV_74, ///< 74 11030
|
||||
|
||||
SLV_75, ///< 75 11107
|
||||
SLV_76, ///< 76 11139
|
||||
SLV_77, ///< 77 11172
|
||||
SLV_78, ///< 78 11176
|
||||
SLV_79, ///< 79 11188
|
||||
|
||||
SLV_80, ///< 80 11228
|
||||
SLV_81, ///< 81 11244
|
||||
SLV_82, ///< 82 11410
|
||||
SLV_83, ///< 83 11589
|
||||
SLV_84, ///< 84 11822
|
||||
|
||||
SLV_85, ///< 85 11874
|
||||
SLV_86, ///< 86 12042
|
||||
SLV_87, ///< 87 12129
|
||||
SLV_88, ///< 88 12134
|
||||
SLV_89, ///< 89 12160
|
||||
|
||||
SLV_90, ///< 90 12293
|
||||
SLV_91, ///< 91 12347
|
||||
SLV_92, ///< 92 12381 0.6.x
|
||||
SLV_93, ///< 93 12648
|
||||
SLV_94, ///< 94 12816
|
||||
|
||||
SLV_95, ///< 95 12924
|
||||
SLV_96, ///< 96 13226
|
||||
SLV_97, ///< 97 13256
|
||||
SLV_98, ///< 98 13375
|
||||
SLV_99, ///< 99 13838
|
||||
|
||||
SLV_100, ///< 100 13952
|
||||
SLV_101, ///< 101 14233
|
||||
SLV_102, ///< 102 14332
|
||||
SLV_103, ///< 103 14598
|
||||
SLV_104, ///< 104 14735
|
||||
|
||||
SLV_105, ///< 105 14803
|
||||
SLV_106, ///< 106 14919
|
||||
SLV_107, ///< 107 15027
|
||||
SLV_108, ///< 108 15045
|
||||
SLV_109, ///< 109 15075
|
||||
|
||||
SLV_110, ///< 110 15148
|
||||
SLV_111, ///< 111 15190
|
||||
SLV_112, ///< 112 15290
|
||||
SLV_113, ///< 113 15340
|
||||
SLV_114, ///< 114 15601
|
||||
|
||||
SLV_115, ///< 115 15695
|
||||
SLV_116, ///< 116 15893 0.7.x
|
||||
SLV_117, ///< 117 16037
|
||||
SLV_118, ///< 118 16129
|
||||
SLV_119, ///< 119 16242
|
||||
|
||||
SLV_120, ///< 120 16439
|
||||
SLV_121, ///< 121 16694
|
||||
SLV_122, ///< 122 16855
|
||||
SLV_123, ///< 123 16909
|
||||
SLV_124, ///< 124 16993
|
||||
|
||||
SLV_125, ///< 125 17113
|
||||
SLV_126, ///< 126 17433
|
||||
SLV_127, ///< 127 17439
|
||||
SLV_128, ///< 128 18281
|
||||
SLV_129, ///< 129 18292
|
||||
|
||||
SLV_130, ///< 130 18404
|
||||
SLV_131, ///< 131 18481
|
||||
SLV_132, ///< 132 18522
|
||||
SLV_133, ///< 133 18674
|
||||
SLV_134, ///< 134 18703
|
||||
|
||||
SLV_135, ///< 135 18719
|
||||
SLV_136, ///< 136 18764
|
||||
SLV_137, ///< 137 18912
|
||||
SLV_138, ///< 138 18942 1.0.x
|
||||
SLV_139, ///< 139 19346
|
||||
|
||||
SLV_140, ///< 140 19382
|
||||
SLV_141, ///< 141 19799
|
||||
SLV_142, ///< 142 20003
|
||||
SLV_143, ///< 143 20048
|
||||
SLV_144, ///< 144 20334
|
||||
|
||||
SLV_145, ///< 145 20376
|
||||
SLV_146, ///< 146 20446
|
||||
SLV_147, ///< 147 20621
|
||||
SLV_148, ///< 148 20659
|
||||
SLV_149, ///< 149 20832
|
||||
|
||||
SLV_150, ///< 150 20857
|
||||
SLV_151, ///< 151 20918
|
||||
SLV_152, ///< 152 21171
|
||||
SLV_153, ///< 153 21263
|
||||
SLV_154, ///< 154 21426
|
||||
|
||||
SLV_155, ///< 155 21453
|
||||
SLV_156, ///< 156 21728
|
||||
SLV_157, ///< 157 21862
|
||||
SLV_158, ///< 158 21933
|
||||
SLV_159, ///< 159 21962
|
||||
|
||||
SLV_160, ///< 160 21974 1.1.x
|
||||
SLV_161, ///< 161 22567
|
||||
SLV_162, ///< 162 22713
|
||||
SLV_163, ///< 163 22767
|
||||
SLV_164, ///< 164 23290
|
||||
|
||||
SLV_165, ///< 165 23304
|
||||
SLV_166, ///< 166 23415
|
||||
SLV_167, ///< 167 23504
|
||||
SLV_168, ///< 168 23637
|
||||
SLV_169, ///< 169 23816
|
||||
|
||||
SLV_170, ///< 170 23826
|
||||
SLV_171, ///< 171 23835
|
||||
SLV_172, ///< 172 23947
|
||||
SLV_173, ///< 173 23967 1.2.0-RC1
|
||||
SLV_174, ///< 174 23973 1.2.x
|
||||
|
||||
SLV_175, ///< 175 24136
|
||||
SLV_176, ///< 176 24446
|
||||
SLV_177, ///< 177 24619
|
||||
SLV_178, ///< 178 24789
|
||||
SLV_179, ///< 179 24810
|
||||
|
||||
SLV_180, ///< 180 24998 1.3.x
|
||||
SLV_181, ///< 181 25012
|
||||
SLV_182, ///< 182 25115 FS#5492, r25259, r25296 Goal status
|
||||
SLV_183, ///< 183 25363 Cargodist
|
||||
SLV_184, ///< 184 25508 Unit localisation split
|
||||
|
||||
SLV_185, ///< 185 25620 Storybooks
|
||||
SLV_186, ///< 186 25833 Objects storage
|
||||
SLV_187, ///< 187 25899 Linkgraph - restricted flows
|
||||
SLV_188, ///< 188 26169 v1.4 FS#5831 Unify RV travel time
|
||||
SLV_189, ///< 189 26450 Hierarchical vehicle subgroups
|
||||
|
||||
SLV_190, ///< 190 26547 Separate order travel and wait times
|
||||
SLV_191, ///< 191 26636 FS#6026 Fix disaster vehicle storage (No bump)
|
||||
///< 191 26646 FS#6041 Linkgraph - store locations
|
||||
SLV_192, ///< 192 26700 FS#6066 Fix saving of order backups
|
||||
SLV_193, ///< 193 26802
|
||||
SLV_194, ///< 194 26881 v1.5
|
||||
|
||||
SLV_195, ///< 195 27572 v1.6.1
|
||||
SLV_196, ///< 196 27778 v1.7
|
||||
SLV_197, ///< 197 27978 v1.8
|
||||
SLV_198, ///< 198 PR#6763 Switch town growth rate and counter to actual game ticks
|
||||
SLV_EXTEND_CARGOTYPES, ///< 199 PR#6802 Extend cargotypes to 64
|
||||
|
||||
SLV_EXTEND_RAILTYPES, ///< 200 PR#6805 Extend railtypes to 64, adding uint16 to map array.
|
||||
SLV_EXTEND_PERSISTENT_STORAGE, ///< 201 PR#6885 Extend NewGRF persistent storages.
|
||||
SLV_EXTEND_INDUSTRY_CARGO_SLOTS, ///< 202 PR#6867 Increase industry cargo slots to 16 in, 16 out
|
||||
SLV_SHIP_PATH_CACHE, ///< 203 PR#7072 Add path cache for ships
|
||||
SLV_SHIP_ROTATION, ///< 204 PR#7065 Add extra rotation stages for ships.
|
||||
|
||||
SLV_GROUP_LIVERIES, ///< 205 PR#7108 Livery storage change and group liveries.
|
||||
SLV_SHIPS_STOP_IN_LOCKS, ///< 206 PR#7150 Ship/lock movement changes.
|
||||
SLV_FIX_CARGO_MONITOR, ///< 207 PR#7175 v1.9 Cargo monitor data packing fix to support 64 cargotypes.
|
||||
SLV_TOWN_CARGOGEN, ///< 208 PR#6965 New algorithms for town building cargo generation.
|
||||
SLV_SHIP_CURVE_PENALTY, ///< 209 PR#7289 Configurable ship curve penalties.
|
||||
|
||||
SLV_SERVE_NEUTRAL_INDUSTRIES, ///< 210 PR#7234 Company stations can serve industries with attached neutral stations.
|
||||
SLV_ROADVEH_PATH_CACHE, ///< 211 PR#7261 Add path cache for road vehicles.
|
||||
SLV_REMOVE_OPF, ///< 212 PR#7245 Remove OPF.
|
||||
SLV_TREES_WATER_CLASS, ///< 213 PR#7405 WaterClass update for tree tiles.
|
||||
SLV_ROAD_TYPES, ///< 214 PR#6811 NewGRF road types.
|
||||
|
||||
SLV_SCRIPT_MEMLIMIT, ///< 215 PR#7516 Limit on AI/GS memory consumption.
|
||||
SLV_MULTITILE_DOCKS, ///< 216 PR#7380 Multiple docks per station.
|
||||
SLV_TRADING_AGE, ///< 217 PR#7780 Configurable company trading age.
|
||||
SLV_ENDING_YEAR, ///< 218 PR#7747 v1.10 Configurable ending year.
|
||||
SLV_REMOVE_TOWN_CARGO_CACHE, ///< 219 PR#8258 Remove town cargo acceptance and production caches.
|
||||
|
||||
/* Patchpacks for a while considered it a good idea to jump a few versions
|
||||
* above our version for their savegames. But as time continued, this gap
|
||||
* has been closing, up to the point we would start to reuse versions from
|
||||
* their patchpacks. This is not a problem from our perspective: the
|
||||
* savegame will simply fail to load because they all contain chunks we
|
||||
* cannot digest. But, this gives for ugly errors. As we have plenty of
|
||||
* versions anyway, we simply skip the versions we know belong to
|
||||
* patchpacks. This way we can present the user with a clean error
|
||||
* indicate they are loading a savegame from a patchpack.
|
||||
* For future patchpack creators: please follow a system like JGRPP, where
|
||||
* the version is masked with 0x8000, and the true version is stored in
|
||||
* its own chunk with feature toggles.
|
||||
*/
|
||||
SLV_START_PATCHPACKS, ///< 220 First known patchpack to use a version just above ours.
|
||||
SLV_END_PATCHPACKS = 286, ///< 286 Last known patchpack to use a version just above ours.
|
||||
|
||||
SLV_GS_INDUSTRY_CONTROL, ///< 287 PR#7912 and PR#8115 GS industry control.
|
||||
SLV_VEH_MOTION_COUNTER, ///< 288 PR#8591 Desync safe motion counter
|
||||
SLV_INDUSTRY_TEXT, ///< 289 PR#8576 v1.11.0-RC1 Additional GS text for industries.
|
||||
SLV_MAPGEN_SETTINGS_REVAMP, ///< 290 PR#8891 v1.11 Revamp of some mapgen settings (snow coverage, desert coverage, heightmap height, custom terrain type).
|
||||
SLV_GROUP_REPLACE_WAGON_REMOVAL, ///< 291 PR#7441 Per-group wagon removal flag.
|
||||
SLV_CUSTOM_SUBSIDY_DURATION, ///< 292 PR#9081 Configurable subsidy duration.
|
||||
|
||||
/* upstream savegame versions follow */
|
||||
|
||||
SLV_SAVELOAD_LIST_LENGTH, ///< 293 PR#9374 Consistency in list length with SL_STRUCT / SL_STRUCTLIST / SL_DEQUE / SL_REFLIST.
|
||||
SLV_RIFF_TO_ARRAY, ///< 294 PR#9375 Changed many CH_RIFF chunks to CH_ARRAY chunks.
|
||||
|
||||
SLV_TABLE_CHUNKS, ///< 295 PR#9322 Introduction of CH_TABLE and CH_SPARSE_TABLE.
|
||||
SLV_SCRIPT_INT64, ///< 296 PR#9415 SQInteger is 64bit but was saved as 32bit.
|
||||
SLV_LINKGRAPH_TRAVEL_TIME, ///< 297 PR#9457 v12.0-RC1 Store travel time in the linkgraph.
|
||||
SLV_DOCK_DOCKINGTILES, ///< 298 PR#9578 All tiles around docks may be docking tiles.
|
||||
SLV_REPAIR_OBJECT_DOCKING_TILES, ///< 299 PR#9594 v12.0 Fixing issue with docking tiles overlapping objects.
|
||||
|
||||
SLV_U64_TICK_COUNTER, ///< 300 PR#10035 Make _tick_counter 64bit to avoid wrapping.
|
||||
SLV_LAST_LOADING_TICK, ///< 301 PR#9693 Store tick of last loading for vehicles.
|
||||
SLV_MULTITRACK_LEVEL_CROSSINGS, ///< 302 PR#9931 v13.0 Multi-track level crossings.
|
||||
SLV_NEWGRF_ROAD_STOPS, ///< 303 PR#10144 NewGRF road stops.
|
||||
SLV_LINKGRAPH_EDGES, ///< 304 PR#10314 Explicitly store link graph edges destination.
|
||||
|
||||
SLV_VELOCITY_NAUTICAL, ///< 305 PR#10594 Separation of land and nautical velocity (knots!)
|
||||
SLV_CONSISTENT_PARTIAL_Z, ///< 306 PR#10570 Conversion from an inconsistent partial Z calculation for slopes, to one that is (more) consistent.
|
||||
SLV_MORE_CARGO_AGE, ///< 307 PR#10596 Track cargo age for a longer period.
|
||||
SLV_LINKGRAPH_SECONDS, ///< 308 PR#10610 Store linkgraph update intervals in seconds instead of days.
|
||||
SLV_AI_START_DATE, ///< 309 PR#10653 Removal of individual AI start dates and added a generic one.
|
||||
|
||||
SLV_EXTEND_VEHICLE_RANDOM, ///< 310 PR#10701 Extend vehicle random bits.
|
||||
SLV_EXTEND_ENTITY_MAPPING, ///< 311 PR#10672 Extend entity mapping range.
|
||||
SLV_DISASTER_VEH_STATE, ///< 312 PR#10798 Explicit storage of disaster vehicle state.
|
||||
SLV_SAVEGAME_ID, ///< 313 PR#10719 Add an unique ID to every savegame (used to deduplicate surveys).
|
||||
SLV_STRING_GAMELOG, ///< 314 PR#10801 Use std::string in gamelog.
|
||||
|
||||
SLV_INDUSTRY_CARGO_REORGANISE, ///< 315 PR#10853 Industry accepts/produced data reorganised.
|
||||
|
||||
SL_MAX_VERSION, ///< Highest possible saveload version
|
||||
|
||||
SL_SPRING_2013_v2_0_102 = 220,
|
||||
SL_SPRING_2013_v2_1_108 = 221,
|
||||
SL_SPRING_2013_v2_1_147 = 222,
|
||||
SL_SPRING_2013_v2_3_XXX = 223,
|
||||
SL_SPRING_2013_v2_3_b3 = 224,
|
||||
SL_SPRING_2013_v2_3_b4 = 225,
|
||||
SL_SPRING_2013_v2_3_b5 = 226,
|
||||
SL_SPRING_2013_v2_4 = 227,
|
||||
SL_TRACE_RESTRICT_2000 = 2000,
|
||||
SL_TRACE_RESTRICT_2001 = 2001,
|
||||
SL_TRACE_RESTRICT_2002 = 2002,
|
||||
SL_JOKER_1_19 = 278,
|
||||
SL_JOKER_1_20 = 279,
|
||||
SL_JOKER_1_21 = 280,
|
||||
SL_JOKER_1_22 = 281,
|
||||
SL_JOKER_1_23 = 282,
|
||||
SL_JOKER_1_24 = 283,
|
||||
SL_JOKER_1_25 = 284,
|
||||
SL_JOKER_1_26 = 285,
|
||||
SL_JOKER_1_27 = 286,
|
||||
SL_CHILLPP_201 = 201,
|
||||
SL_CHILLPP_232 = 232,
|
||||
SL_CHILLPP_233 = 233,
|
||||
};
|
||||
|
||||
byte SlReadByte();
|
||||
void SlWriteByte(byte b);
|
||||
|
||||
int SlReadUint16();
|
||||
uint32 SlReadUint32();
|
||||
uint64 SlReadUint64();
|
||||
|
||||
void SlWriteUint16(uint16 v);
|
||||
void SlWriteUint32(uint32 v);
|
||||
void SlWriteUint64(uint64 v);
|
||||
|
||||
void SlSkipBytes(size_t length);
|
||||
|
||||
size_t SlGetBytesRead();
|
||||
size_t SlGetBytesWritten();
|
||||
|
||||
void NORETURN SlError(StringID string, std::string extra_msg = {});
|
||||
void NORETURN SlErrorCorrupt(std::string msg);
|
||||
void NORETURN CDECL SlErrorCorruptFmt(const char *format, ...) WARN_FORMAT(1, 2);
|
||||
|
||||
bool SaveLoadFileTypeIsScenario();
|
||||
|
||||
#endif
|
||||
@@ -1,105 +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 saveload_filter.h Declaration of filters used for saving and loading savegames. */
|
||||
|
||||
#ifndef SAVELOAD_FILTER_H
|
||||
#define SAVELOAD_FILTER_H
|
||||
|
||||
/** Interface for filtering a savegame till it is loaded. */
|
||||
struct LoadFilter {
|
||||
/** Chained to the (savegame) filters. */
|
||||
LoadFilter *chain;
|
||||
|
||||
/**
|
||||
* Initialise this filter.
|
||||
* @param chain The next filter in this chain.
|
||||
*/
|
||||
LoadFilter(LoadFilter *chain) : chain(chain)
|
||||
{
|
||||
}
|
||||
|
||||
/** Make sure the writers are properly closed. */
|
||||
virtual ~LoadFilter()
|
||||
{
|
||||
delete this->chain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a given number of bytes from the savegame.
|
||||
* @param buf The bytes to read.
|
||||
* @param len The number of bytes to read.
|
||||
* @return The number of actually read bytes.
|
||||
*/
|
||||
virtual size_t Read(byte *buf, size_t len) = 0;
|
||||
|
||||
/**
|
||||
* Reset this filter to read from the beginning of the file.
|
||||
*/
|
||||
virtual void Reset()
|
||||
{
|
||||
this->chain->Reset();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiator for a load filter.
|
||||
* @param chain The next filter in this chain.
|
||||
* @tparam T The type of load filter to create.
|
||||
*/
|
||||
template <typename T> LoadFilter *CreateLoadFilter(LoadFilter *chain)
|
||||
{
|
||||
return new T(chain);
|
||||
}
|
||||
|
||||
/** Interface for filtering a savegame till it is written. */
|
||||
struct SaveFilter {
|
||||
/** Chained to the (savegame) filters. */
|
||||
SaveFilter *chain;
|
||||
|
||||
/**
|
||||
* Initialise this filter.
|
||||
* @param chain The next filter in this chain.
|
||||
*/
|
||||
SaveFilter(SaveFilter *chain) : chain(chain)
|
||||
{
|
||||
}
|
||||
|
||||
/** Make sure the writers are properly closed. */
|
||||
virtual ~SaveFilter()
|
||||
{
|
||||
delete this->chain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a given number of bytes into the savegame.
|
||||
* @param buf The bytes to write.
|
||||
* @param len The number of bytes to write.
|
||||
*/
|
||||
virtual void Write(byte *buf, size_t len) = 0;
|
||||
|
||||
/**
|
||||
* Prepare everything to finish writing the savegame.
|
||||
*/
|
||||
virtual void Finish()
|
||||
{
|
||||
if (this->chain != nullptr) this->chain->Finish();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiator for a save filter.
|
||||
* @param chain The next filter in this chain.
|
||||
* @param compression_level The requested level of compression.
|
||||
* @tparam T The type of save filter to create.
|
||||
*/
|
||||
template <typename T> SaveFilter *CreateSaveFilter(SaveFilter *chain, byte compression_level)
|
||||
{
|
||||
return new T(chain, compression_level);
|
||||
}
|
||||
|
||||
#endif /* SAVELOAD_FILTER_H */
|
||||
@@ -1,70 +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 saveload_internal.h Declaration of functions used in more save/load files */
|
||||
|
||||
#ifndef SAVELOAD_INTERNAL_H
|
||||
#define SAVELOAD_INTERNAL_H
|
||||
|
||||
#include "../company_manager_face.h"
|
||||
#include "../order_base.h"
|
||||
#include "../engine_type.h"
|
||||
#include "saveload.h"
|
||||
|
||||
void InitializeOldNames();
|
||||
StringID RemapOldStringID(StringID s);
|
||||
std::string CopyFromOldName(StringID id);
|
||||
void ResetOldNames();
|
||||
|
||||
void ResetOldWaypoints();
|
||||
void MoveBuoysToWaypoints();
|
||||
void MoveWaypointsToBaseStations();
|
||||
SaveLoadTable GetBaseStationDescription();
|
||||
|
||||
void AfterLoadVehicles(bool part_of_load);
|
||||
void AfterLoadVehiclesRemoveAnyFoundInvalid();
|
||||
void AfterLoadEngines();
|
||||
void FixupTrainLengths();
|
||||
void AfterLoadTemplateVehicles();
|
||||
void AfterLoadStations();
|
||||
void AfterLoadRoadStops();
|
||||
void ResetLabelMaps();
|
||||
void AfterLoadLabelMaps();
|
||||
void AfterLoadStoryBook();
|
||||
void AfterLoadLinkGraphs();
|
||||
void AfterLoadCompanyStats();
|
||||
void AfterLoadTraceRestrict();
|
||||
void UpdateHousesAndTowns(bool cargo_update_required, bool old_map_position);
|
||||
|
||||
void UpdateOldAircraft();
|
||||
|
||||
void SaveViewportBeforeSaveGame();
|
||||
void ResetViewportAfterLoadGame();
|
||||
|
||||
void ConvertOldMultiheadToNew();
|
||||
void ConnectMultiheadedTrains();
|
||||
|
||||
void ResetTempEngineData();
|
||||
Engine *GetTempDataEngine(EngineID index);
|
||||
void CopyTempEngineData();
|
||||
|
||||
void AfterLoadTemplateVehiclesUpdate();
|
||||
void AfterLoadTemplateVehiclesUpdateImages();
|
||||
void AfterLoadTemplateVehiclesUpdateProperties();
|
||||
|
||||
extern int32 _saved_scrollpos_x;
|
||||
extern int32 _saved_scrollpos_y;
|
||||
extern ZoomLevel _saved_scrollpos_zoom;
|
||||
|
||||
extern SavegameType _savegame_type;
|
||||
extern uint32 _ttdp_version;
|
||||
|
||||
CompanyManagerFace ConvertFromOldCompanyManagerFace(uint32 face);
|
||||
|
||||
Order UnpackOldOrder(uint16 packed);
|
||||
|
||||
#endif /* SAVELOAD_INTERNAL_H */
|
||||
@@ -1,135 +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 saveload_common.h Common functions/types for saving and loading games. */
|
||||
|
||||
#ifndef SAVELOAD_TYPES_H
|
||||
#define SAVELOAD_TYPES_H
|
||||
|
||||
#include "saveload_common.h"
|
||||
#include "extended_ver_sl.h"
|
||||
|
||||
/**
|
||||
* VarTypes is the general bitmasked magic type that tells us
|
||||
* certain characteristics about the variable it refers to. For example
|
||||
* SLE_FILE_* gives the size(type) as it would be in the savegame and
|
||||
* SLE_VAR_* the size(type) as it is in memory during runtime. These are
|
||||
* the first 8 bits (0-3 SLE_FILE, 4-7 SLE_VAR).
|
||||
* Bits 8-15 are reserved for various flags as explained below
|
||||
*/
|
||||
enum VarTypes {
|
||||
/* 4 bits allocated a maximum of 16 types for NumberType */
|
||||
SLE_FILE_I8 = 0,
|
||||
SLE_FILE_U8 = 1,
|
||||
SLE_FILE_I16 = 2,
|
||||
SLE_FILE_U16 = 3,
|
||||
SLE_FILE_I32 = 4,
|
||||
SLE_FILE_U32 = 5,
|
||||
SLE_FILE_I64 = 6,
|
||||
SLE_FILE_U64 = 7,
|
||||
SLE_FILE_STRINGID = 8, ///< StringID offset into strings-array
|
||||
SLE_FILE_STRING = 9,
|
||||
SLE_FILE_VEHORDERID = 10,
|
||||
/* 5 more possible file-primitives */
|
||||
|
||||
/* 4 bits allocated a maximum of 16 types for NumberType */
|
||||
SLE_VAR_BL = 0 << 4,
|
||||
SLE_VAR_I8 = 1 << 4,
|
||||
SLE_VAR_U8 = 2 << 4,
|
||||
SLE_VAR_I16 = 3 << 4,
|
||||
SLE_VAR_U16 = 4 << 4,
|
||||
SLE_VAR_I32 = 5 << 4,
|
||||
SLE_VAR_U32 = 6 << 4,
|
||||
SLE_VAR_I64 = 7 << 4,
|
||||
SLE_VAR_U64 = 8 << 4,
|
||||
SLE_VAR_NULL = 9 << 4, ///< useful to write zeros in savegame.
|
||||
SLE_VAR_STRB = 10 << 4, ///< string (with pre-allocated buffer)
|
||||
SLE_VAR_STR = 12 << 4, ///< string pointer
|
||||
SLE_VAR_STRQ = 13 << 4, ///< string pointer enclosed in quotes
|
||||
SLE_VAR_NAME = 14 << 4, ///< old custom name to be converted to a std::string
|
||||
SLE_VAR_CNAME = 15 << 4, ///< old custom name to be converted to a char pointer
|
||||
/* 0 more possible memory-primitives */
|
||||
|
||||
/* Shortcut values */
|
||||
SLE_VAR_CHAR = SLE_VAR_I8,
|
||||
|
||||
/* Default combinations of variables. As savegames change, so can variables
|
||||
* and thus it is possible that the saved value and internal size do not
|
||||
* match and you need to specify custom combo. The defaults are listed here */
|
||||
SLE_BOOL = SLE_FILE_I8 | SLE_VAR_BL,
|
||||
SLE_INT8 = SLE_FILE_I8 | SLE_VAR_I8,
|
||||
SLE_UINT8 = SLE_FILE_U8 | SLE_VAR_U8,
|
||||
SLE_INT16 = SLE_FILE_I16 | SLE_VAR_I16,
|
||||
SLE_UINT16 = SLE_FILE_U16 | SLE_VAR_U16,
|
||||
SLE_INT32 = SLE_FILE_I32 | SLE_VAR_I32,
|
||||
SLE_UINT32 = SLE_FILE_U32 | SLE_VAR_U32,
|
||||
SLE_INT64 = SLE_FILE_I64 | SLE_VAR_I64,
|
||||
SLE_UINT64 = SLE_FILE_U64 | SLE_VAR_U64,
|
||||
SLE_CHAR = SLE_FILE_I8 | SLE_VAR_CHAR,
|
||||
SLE_STRINGID = SLE_FILE_STRINGID | SLE_VAR_U32,
|
||||
SLE_STRINGBUF = SLE_FILE_STRING | SLE_VAR_STRB,
|
||||
SLE_STRING = SLE_FILE_STRING | SLE_VAR_STR,
|
||||
SLE_STRINGQUOTE = SLE_FILE_STRING | SLE_VAR_STRQ,
|
||||
SLE_NAME = SLE_FILE_STRINGID | SLE_VAR_NAME,
|
||||
SLE_CNAME = SLE_FILE_STRINGID | SLE_VAR_CNAME,
|
||||
SLE_VEHORDERID = SLE_FILE_VEHORDERID | SLE_VAR_U16,
|
||||
|
||||
/* Shortcut values */
|
||||
SLE_UINT = SLE_UINT32,
|
||||
SLE_INT = SLE_INT32,
|
||||
SLE_STRB = SLE_STRINGBUF,
|
||||
SLE_STR = SLE_STRING,
|
||||
SLE_STRQ = SLE_STRINGQUOTE,
|
||||
|
||||
/* 8 bits allocated for a maximum of 8 flags
|
||||
* Flags directing saving/loading of a variable */
|
||||
SLF_ALLOW_CONTROL = 1 << 8, ///< Allow control codes in the strings.
|
||||
SLF_ALLOW_NEWLINE = 1 << 9, ///< Allow new lines in the strings.
|
||||
};
|
||||
|
||||
typedef uint32 VarType;
|
||||
|
||||
/** Type of data saved. */
|
||||
enum SaveLoadTypes {
|
||||
SL_VAR = 0, ///< Save/load a variable.
|
||||
SL_REF = 1, ///< Save/load a reference.
|
||||
SL_ARR = 2, ///< Save/load a fixed-size array of #SL_VAR elements.
|
||||
SL_STR = 3, ///< Save/load a string.
|
||||
SL_REFLIST = 4, ///< Save/load a list of #SL_REF elements.
|
||||
SL_DEQUE = 5, ///< Save/load a deque of #SL_VAR elements.
|
||||
SL_VEC = 6, ///< Save/load a vector of #SL_REF elements.
|
||||
SL_STDSTR = 7, ///< Save/load a std::string.
|
||||
|
||||
/* non-normal save-load types */
|
||||
SL_WRITEBYTE = 8,
|
||||
SL_VEH_INCLUDE = 9,
|
||||
SL_ST_INCLUDE = 10,
|
||||
|
||||
SL_PTRDEQ = 13, ///< Save/load a deque of #SL_REF elements.
|
||||
SL_VARVEC = 14, ///< Save/load a primitive type vector.
|
||||
};
|
||||
|
||||
typedef byte SaveLoadType; ///< Save/load type. @see SaveLoadTypes
|
||||
|
||||
/** SaveLoad type struct. Do NOT use this directly but use the SLE_ macros defined just below! */
|
||||
struct SaveLoad {
|
||||
bool global; ///< should we load a global variable or a non-global one
|
||||
SaveLoadType cmd; ///< the action to take with the saved/loaded type, All types need different action
|
||||
VarType conv; ///< type of the variable to be saved, int
|
||||
uint16 length; ///< (conditional) length of the variable (eg. arrays) (max array size is 65536 elements)
|
||||
SaveLoadVersion version_from; ///< save/load the variable starting from this savegame version
|
||||
SaveLoadVersion version_to; ///< save/load the variable until this savegame version
|
||||
/* NOTE: This element either denotes the address of the variable for a global
|
||||
* variable, or the offset within a struct which is then bound to a variable
|
||||
* during runtime. Decision on which one to use is controlled by the function
|
||||
* that is called to save it. address: global=true, offset: global=false */
|
||||
void *address; ///< address of variable OR offset of variable in the struct (max offset is 65536)
|
||||
size_t size; ///< the sizeof size.
|
||||
SlXvFeatureTest ext_feature_test; ///< extended feature test
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -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();
|
||||
|
||||
@@ -1,314 +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 signal_sl.cpp Code handling saving and loading of signals */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "../programmable_signals.h"
|
||||
#include "../core/alloc_type.hpp"
|
||||
#include "../core/bitmath_func.hpp"
|
||||
#include <vector>
|
||||
#include "saveload.h"
|
||||
#include "saveload_buffer.h"
|
||||
|
||||
typedef std::vector<byte> Buffer;
|
||||
|
||||
// Variable length integers are stored in Variable Length Quantity
|
||||
// format (http://en.wikipedia.org/wiki/Variable-length_quantity)
|
||||
|
||||
static void WriteVLI(Buffer &b, uint i)
|
||||
{
|
||||
uint lsmask = 0x7F;
|
||||
uint msmask = ~0x7F;
|
||||
while(i & msmask) {
|
||||
byte part = (i & lsmask) | 0x80;
|
||||
b.push_back(part);
|
||||
i >>= 7;
|
||||
}
|
||||
b.push_back((byte) i);
|
||||
}
|
||||
|
||||
static uint ReadVLI()
|
||||
{
|
||||
uint shift = 0;
|
||||
uint val = 0;
|
||||
byte b;
|
||||
|
||||
b = SlReadByte();
|
||||
while(b & 0x80) {
|
||||
val |= uint(b & 0x7F) << shift;
|
||||
shift += 7;
|
||||
b = SlReadByte();
|
||||
}
|
||||
val |= uint(b) << shift;
|
||||
return val;
|
||||
}
|
||||
|
||||
static void WriteCondition(Buffer &b, SignalCondition *c)
|
||||
{
|
||||
WriteVLI(b, c->ConditionCode());
|
||||
switch(c->ConditionCode()) {
|
||||
case PSC_NUM_GREEN:
|
||||
case PSC_NUM_RED: {
|
||||
SignalVariableCondition *vc = static_cast<SignalVariableCondition*>(c);
|
||||
WriteVLI(b, vc->comparator);
|
||||
WriteVLI(b, vc->value);
|
||||
} break;
|
||||
|
||||
case PSC_SIGNAL_STATE: {
|
||||
SignalStateCondition *sc = static_cast<SignalStateCondition*>(c);
|
||||
WriteVLI(b, sc->sig_tile);
|
||||
WriteVLI(b, sc->sig_track);
|
||||
} break;
|
||||
|
||||
case PSC_SLOT_OCC:
|
||||
case PSC_SLOT_OCC_REM: {
|
||||
SignalSlotCondition *cc = static_cast<SignalSlotCondition*>(c);
|
||||
WriteVLI(b, cc->slot_id);
|
||||
WriteVLI(b, cc->comparator);
|
||||
WriteVLI(b, cc->value);
|
||||
} break;
|
||||
|
||||
case PSC_COUNTER: {
|
||||
SignalCounterCondition *cc = static_cast<SignalCounterCondition*>(c);
|
||||
WriteVLI(b, cc->ctr_id);
|
||||
WriteVLI(b, cc->comparator);
|
||||
WriteVLI(b, cc->value);
|
||||
} break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static SignalCondition *ReadCondition(SignalReference this_sig)
|
||||
{
|
||||
SignalConditionCode code = (SignalConditionCode) ReadVLI();
|
||||
switch(code) {
|
||||
case PSC_NUM_GREEN:
|
||||
case PSC_NUM_RED: {
|
||||
SignalVariableCondition *c = new SignalVariableCondition(code);
|
||||
c->comparator = (SignalComparator) ReadVLI();
|
||||
if(c->comparator > SGC_LAST) NOT_REACHED();
|
||||
c->value = ReadVLI();
|
||||
return c;
|
||||
}
|
||||
|
||||
case PSC_SIGNAL_STATE: {
|
||||
TileIndex ti = (TileIndex) ReadVLI();
|
||||
Trackdir td = (Trackdir) ReadVLI();
|
||||
return new SignalStateCondition(this_sig, ti, td);
|
||||
}
|
||||
|
||||
case PSC_SLOT_OCC:
|
||||
case PSC_SLOT_OCC_REM: {
|
||||
TraceRestrictSlotID slot_id = (TraceRestrictSlotID) ReadVLI();
|
||||
SignalSlotCondition *c = new SignalSlotCondition(code, this_sig, slot_id);
|
||||
c->comparator = (SignalComparator) ReadVLI();
|
||||
if(c->comparator > SGC_LAST) NOT_REACHED();
|
||||
c->value = ReadVLI();
|
||||
return c;
|
||||
} break;
|
||||
|
||||
case PSC_COUNTER: {
|
||||
TraceRestrictCounterID ctr_id = (TraceRestrictCounterID) ReadVLI();
|
||||
SignalCounterCondition *c = new SignalCounterCondition(this_sig, ctr_id);
|
||||
c->comparator = (SignalComparator) ReadVLI();
|
||||
if(c->comparator > SGC_LAST) NOT_REACHED();
|
||||
c->value = ReadVLI();
|
||||
return c;
|
||||
}
|
||||
|
||||
default:
|
||||
return new SignalSimpleCondition(code);
|
||||
}
|
||||
}
|
||||
|
||||
static void Save_SPRG()
|
||||
{
|
||||
// Check for, and dispose of, any signal information on a tile which doesn't have signals.
|
||||
// This indicates that someone removed the signals from the tile but didn't clean them up.
|
||||
// (This code is to detect bugs and limit their consquences, not to cover them up!)
|
||||
for(ProgramList::iterator i = _signal_programs.begin(), e = _signal_programs.end();
|
||||
i != e; ++i) {
|
||||
SignalReference ref = i->first;
|
||||
if(!HasProgrammableSignals(ref)) {
|
||||
DEBUG(sl, 0, "Programmable pre-signal information for (%x, %d) has been leaked!",
|
||||
ref.tile, ref.track);
|
||||
++i;
|
||||
FreeSignalProgram(ref);
|
||||
if(i == e) break;
|
||||
}
|
||||
}
|
||||
|
||||
// OK, we can now write out our programs
|
||||
Buffer b;
|
||||
WriteVLI(b, (uint)_signal_programs.size());
|
||||
for(ProgramList::iterator i = _signal_programs.begin(), e = _signal_programs.end();
|
||||
i != e; ++i) {
|
||||
SignalProgram *prog = i->second;
|
||||
|
||||
WriteVLI(b, prog->tile);
|
||||
WriteVLI(b, prog->track);
|
||||
WriteVLI(b, (uint)prog->instructions.size());
|
||||
for (SignalInstruction *insn : prog->instructions) {
|
||||
WriteVLI(b, insn->Opcode());
|
||||
if(insn->Opcode() != PSO_FIRST)
|
||||
WriteVLI(b, insn->Previous()->Id());
|
||||
switch(insn->Opcode()) {
|
||||
case PSO_FIRST: {
|
||||
SignalSpecial *s = static_cast<SignalSpecial*>(insn);
|
||||
WriteVLI(b, s->next->Id());
|
||||
break;
|
||||
}
|
||||
|
||||
case PSO_LAST: break;
|
||||
|
||||
case PSO_IF: {
|
||||
SignalIf *i = static_cast<SignalIf*>(insn);
|
||||
WriteCondition(b, i->condition);
|
||||
WriteVLI(b, i->if_true->Id());
|
||||
WriteVLI(b, i->if_false->Id());
|
||||
WriteVLI(b, i->after->Id());
|
||||
break;
|
||||
}
|
||||
|
||||
case PSO_IF_ELSE:
|
||||
case PSO_IF_ENDIF: {
|
||||
SignalIf::PseudoInstruction *p = static_cast<SignalIf::PseudoInstruction*>(insn);
|
||||
WriteVLI(b, p->block->Id());
|
||||
break;
|
||||
}
|
||||
|
||||
case PSO_SET_SIGNAL: {
|
||||
SignalSet *s = static_cast<SignalSet*>(insn);
|
||||
WriteVLI(b, s->next->Id());
|
||||
WriteVLI(b, s->to_state ? 1 : 0);
|
||||
break;
|
||||
}
|
||||
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint size = (uint)b.size();
|
||||
SlSetLength(size);
|
||||
MemoryDumper::GetCurrent()->CopyBytes(b.data(), size);
|
||||
}
|
||||
|
||||
// We don't know the pointer values that need to be stored in various
|
||||
// instruction fields at load time, so we need to instead store the IDs and
|
||||
// then fix them up once all of the instructions have been loaded.
|
||||
//
|
||||
// Additionally, we store the opcode type we expect (if we expect a specific one)
|
||||
// to check for consistency (For example, an If Pseudo Instruction's block should
|
||||
// point at an If!)
|
||||
struct Fixup {
|
||||
Fixup(SignalInstruction **p, SignalOpcode type)
|
||||
: type(type), ptr(p)
|
||||
{}
|
||||
|
||||
SignalOpcode type;
|
||||
SignalInstruction **ptr;
|
||||
};
|
||||
|
||||
typedef std::vector<Fixup> FixupList;
|
||||
|
||||
template<typename T>
|
||||
static void MakeFixup(FixupList &l, T *&ir, uint id, SignalOpcode op = PSO_INVALID)
|
||||
{
|
||||
ir = reinterpret_cast<T*>((size_t)id);
|
||||
l.emplace_back(reinterpret_cast<SignalInstruction**>(&ir), op);
|
||||
}
|
||||
|
||||
static void DoFixups(FixupList &l, InstructionList &il)
|
||||
{
|
||||
for (Fixup &i : l) {
|
||||
uint id = (uint)reinterpret_cast<size_t>(*(i.ptr));
|
||||
if (id >= il.size())
|
||||
NOT_REACHED();
|
||||
|
||||
*(i.ptr) = il[id];
|
||||
|
||||
if (i.type != PSO_INVALID && (*(i.ptr))->Opcode() != i.type) {
|
||||
DEBUG(sl, 0, "Expected Id %d to be %d, but was in fact %d", id, i.type, (*(i.ptr))->Opcode());
|
||||
NOT_REACHED();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Load_SPRG()
|
||||
{
|
||||
uint count = ReadVLI();
|
||||
for(uint i = 0; i < count; i++) {
|
||||
FixupList l;
|
||||
TileIndex tile = ReadVLI();
|
||||
Track track = (Track) ReadVLI();
|
||||
uint instructions = ReadVLI();
|
||||
SignalReference ref(tile, track);
|
||||
|
||||
SignalProgram *sp = new SignalProgram(tile, track, true);
|
||||
_signal_programs[ref] = sp;
|
||||
|
||||
for(uint j = 0; j < instructions; j++) {
|
||||
SignalOpcode op = (SignalOpcode) ReadVLI();
|
||||
switch(op) {
|
||||
case PSO_FIRST: {
|
||||
sp->first_instruction = new SignalSpecial(sp, PSO_FIRST);
|
||||
sp->first_instruction->GetPrevHandle() = nullptr;
|
||||
MakeFixup(l, sp->first_instruction->next, ReadVLI());
|
||||
break;
|
||||
}
|
||||
|
||||
case PSO_LAST: {
|
||||
sp->last_instruction = new SignalSpecial(sp, PSO_LAST);
|
||||
sp->last_instruction->next = nullptr;
|
||||
MakeFixup(l, sp->last_instruction->GetPrevHandle(), ReadVLI());
|
||||
break;
|
||||
}
|
||||
|
||||
case PSO_IF: {
|
||||
SignalIf *i = new SignalIf(sp, true);
|
||||
MakeFixup(l, i->GetPrevHandle(), ReadVLI());
|
||||
i->condition = ReadCondition(ref);
|
||||
MakeFixup(l, i->if_true, ReadVLI());
|
||||
MakeFixup(l, i->if_false, ReadVLI());
|
||||
MakeFixup(l, i->after, ReadVLI());
|
||||
break;
|
||||
}
|
||||
|
||||
case PSO_IF_ELSE:
|
||||
case PSO_IF_ENDIF: {
|
||||
SignalIf::PseudoInstruction *p = new SignalIf::PseudoInstruction(sp, op);
|
||||
MakeFixup(l, p->GetPrevHandle(), ReadVLI());
|
||||
MakeFixup(l, p->block, ReadVLI(), PSO_IF);
|
||||
break;
|
||||
}
|
||||
|
||||
case PSO_SET_SIGNAL: {
|
||||
SignalSet *s = new SignalSet(sp);
|
||||
MakeFixup(l, s->GetPrevHandle(), ReadVLI());
|
||||
MakeFixup(l, s->next, ReadVLI());
|
||||
s->to_state = (SignalState) ReadVLI();
|
||||
if(s->to_state > SIGNAL_STATE_MAX) NOT_REACHED();
|
||||
break;
|
||||
}
|
||||
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
DoFixups(l, sp->instructions);
|
||||
}
|
||||
}
|
||||
|
||||
extern const ChunkHandler signal_chunk_handlers[] = {
|
||||
{ 'SPRG', Save_SPRG, Load_SPRG, nullptr, nullptr, CH_RIFF },
|
||||
};
|
||||
|
||||
extern const ChunkHandlerTable _signal_chunk_handlers(signal_chunk_handlers);
|
||||
@@ -8,13 +8,17 @@
|
||||
/** @file signs_sl.cpp Code handling saving and loading of economy data */
|
||||
|
||||
#include "../stdafx.h"
|
||||
|
||||
#include "saveload.h"
|
||||
#include "compat/signs_sl_compat.h"
|
||||
|
||||
#include "../signs_base.h"
|
||||
#include "../fios.h"
|
||||
|
||||
#include "saveload.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);
|
||||
|
||||
/* 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;
|
||||
for (Sign *si : Sign::Iterate()) {
|
||||
SlSetArrayIndex(si->index);
|
||||
SlObject(si, _sign_desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Chunk handlers related to signs. */
|
||||
static const ChunkHandler sign_chunk_handlers[] = {
|
||||
{ 'SIGN', Save_SIGN, Load_SIGN, nullptr, nullptr, CH_ARRAY },
|
||||
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 && SaveLoadFileTypeIsScenario()) {
|
||||
si->owner = OWNER_DEITY;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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) {}
|
||||
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
assert(PersistentStorage::CanAllocateItem());
|
||||
PersistentStorage *ps = new (index) PersistentStorage(0, 0, 0);
|
||||
SlObject(ps, _storage_desc);
|
||||
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, 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) {}
|
||||
|
||||
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 Save() const override
|
||||
{
|
||||
SlTableHeader(_story_page_elements_desc);
|
||||
|
||||
for (StoryPageElement *s : StoryPageElement::Iterate()) {
|
||||
SlSetArrayIndex(s->index);
|
||||
SlObject(s, _story_page_elements_desc);
|
||||
}
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
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) {}
|
||||
|
||||
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 Save() const override
|
||||
{
|
||||
SlTableHeader(_story_pages_desc);
|
||||
|
||||
for (StoryPage *s : StoryPage::Iterate()) {
|
||||
SlSetArrayIndex(s->index);
|
||||
SlObject(s, _story_pages_desc);
|
||||
}
|
||||
}
|
||||
/* 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 },
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,138 +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 strings_sl.cpp Code handling saving and loading of strings */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "../string_func.h"
|
||||
#include "../strings_func.h"
|
||||
#include "saveload_internal.h"
|
||||
#include <sstream>
|
||||
|
||||
#include "table/strings.h"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
static const int NUM_OLD_STRINGS = 512; ///< The number of custom strings stored in old savegames.
|
||||
static const int LEN_OLD_STRINGS = 32; ///< The number of characters per string.
|
||||
static const int LEN_OLD_STRINGS_TTO = 24; ///< The number of characters per string in TTO savegames.
|
||||
|
||||
/**
|
||||
* Remap a string ID from the old format to the new format
|
||||
* @param s StringID that requires remapping
|
||||
* @return translated ID
|
||||
*/
|
||||
StringID RemapOldStringID(StringID s)
|
||||
{
|
||||
switch (s) {
|
||||
case 0x0006: return STR_SV_EMPTY;
|
||||
case 0x7000: return STR_SV_UNNAMED;
|
||||
case 0x70E4: return SPECSTR_COMPANY_NAME_START;
|
||||
case 0x70E9: return SPECSTR_COMPANY_NAME_START;
|
||||
case 0x8864: return STR_SV_TRAIN_NAME;
|
||||
case 0x902B: return STR_SV_ROAD_VEHICLE_NAME;
|
||||
case 0x9830: return STR_SV_SHIP_NAME;
|
||||
case 0xA02F: return STR_SV_AIRCRAFT_NAME;
|
||||
|
||||
default:
|
||||
if (IsInsideMM(s, 0x300F, 0x3030)) {
|
||||
return s - 0x300F + STR_SV_STNAME;
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Location to load the old names to. */
|
||||
char *_old_name_array = nullptr;
|
||||
|
||||
/**
|
||||
* Copy and convert old custom names to UTF-8.
|
||||
* They were all stored in a 512 by 32 (200 by 24 for TTO) long string array
|
||||
* and are now stored with stations, waypoints and other places with names.
|
||||
* @param id the StringID of the custom name to clone.
|
||||
* @return the clones custom name.
|
||||
*/
|
||||
std::string CopyFromOldName(StringID id)
|
||||
{
|
||||
/* Is this name an (old) custom name? */
|
||||
if (GetStringTab(id) != TEXT_TAB_OLD_CUSTOM) return std::string();
|
||||
|
||||
if (IsSavegameVersionBefore(SLV_37)) {
|
||||
uint offs = _savegame_type == SGT_TTO ? LEN_OLD_STRINGS_TTO * GB(id, 0, 8) : LEN_OLD_STRINGS * GB(id, 0, 9);
|
||||
const char *strfrom = &_old_name_array[offs];
|
||||
|
||||
std::ostringstream tmp;
|
||||
std::ostreambuf_iterator<char> strto(tmp);
|
||||
for (; *strfrom != '\0'; strfrom++) {
|
||||
WChar c = (byte)*strfrom;
|
||||
|
||||
/* Map from non-ISO8859-15 characters to UTF-8. */
|
||||
switch (c) {
|
||||
case 0xA4: c = 0x20AC; break; // Euro
|
||||
case 0xA6: c = 0x0160; break; // S with caron
|
||||
case 0xA8: c = 0x0161; break; // s with caron
|
||||
case 0xB4: c = 0x017D; break; // Z with caron
|
||||
case 0xB8: c = 0x017E; break; // z with caron
|
||||
case 0xBC: c = 0x0152; break; // OE ligature
|
||||
case 0xBD: c = 0x0153; break; // oe ligature
|
||||
case 0xBE: c = 0x0178; break; // Y with diaeresis
|
||||
default: break;
|
||||
}
|
||||
|
||||
Utf8Encode(strto, c);
|
||||
}
|
||||
|
||||
return tmp.str();
|
||||
} else {
|
||||
/* Name will already be in UTF-8. */
|
||||
return std::string(&_old_name_array[LEN_OLD_STRINGS * GB(id, 0, 9)]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the memory of the old names array.
|
||||
* Should be called once the old names have all been converted.
|
||||
*/
|
||||
void ResetOldNames()
|
||||
{
|
||||
free(_old_name_array);
|
||||
_old_name_array = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the old names table memory.
|
||||
*/
|
||||
void InitializeOldNames()
|
||||
{
|
||||
free(_old_name_array);
|
||||
_old_name_array = CallocT<char>(NUM_OLD_STRINGS * LEN_OLD_STRINGS); // 200 * 24 would be enough for TTO savegames
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the NAME chunk.
|
||||
*/
|
||||
static void Load_NAME()
|
||||
{
|
||||
int index;
|
||||
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
if (index >= NUM_OLD_STRINGS) SlErrorCorrupt("Invalid old name index");
|
||||
if (SlGetFieldLength() > (uint)LEN_OLD_STRINGS) SlErrorCorrupt("Invalid old name length");
|
||||
|
||||
SlArray(&_old_name_array[LEN_OLD_STRINGS * index], SlGetFieldLength(), SLE_UINT8);
|
||||
/* Make sure the old name is null terminated */
|
||||
_old_name_array[LEN_OLD_STRINGS * index + LEN_OLD_STRINGS - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/** Chunk handlers related to strings. */
|
||||
static const ChunkHandler name_chunk_handlers[] = {
|
||||
{ 'NAME', nullptr, Load_NAME, nullptr, nullptr, CH_ARRAY },
|
||||
};
|
||||
|
||||
extern const ChunkHandlerTable _name_chunk_handlers(name_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) {}
|
||||
|
||||
static void Load_SUBS()
|
||||
{
|
||||
int index;
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
Subsidy *s = new (index) Subsidy();
|
||||
SlObject(s, _subsidies_desc);
|
||||
}
|
||||
}
|
||||
void Save() const override
|
||||
{
|
||||
SlTableHeader(_subsidies_desc);
|
||||
|
||||
static const ChunkHandler subsidy_chunk_handlers[] = {
|
||||
{ 'SUBS', Save_SUBS, Load_SUBS, nullptr, nullptr, CH_ARRAY },
|
||||
for (Subsidy *s : Subsidy::Iterate()) {
|
||||
SlSetArrayIndex(s->index);
|
||||
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 SUBSChunkHandler SUBS;
|
||||
static const ChunkHandlerRef subsidy_chunk_handlers[] = {
|
||||
SUBS,
|
||||
};
|
||||
|
||||
extern const ChunkHandlerTable _subsidy_chunk_handlers(subsidy_chunk_handlers);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
#include "../stdafx.h"
|
||||
|
||||
#include "../tbtr_template_vehicle.h"
|
||||
|
||||
#include "saveload.h"
|
||||
|
||||
static const SaveLoad _template_replacement_desc[] = {
|
||||
SLE_VAR(TemplateReplacement, sel_template, SLE_UINT16),
|
||||
SLE_VAR(TemplateReplacement, group, SLE_UINT16),
|
||||
};
|
||||
|
||||
static void Save_TMPL_RPLS()
|
||||
{
|
||||
for (TemplateReplacement *tr : TemplateReplacement::Iterate()) {
|
||||
SlSetArrayIndex(tr->index);
|
||||
SlObject(tr, _template_replacement_desc);
|
||||
}
|
||||
}
|
||||
|
||||
static void Load_TMPL_RPLS()
|
||||
{
|
||||
int index;
|
||||
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
TemplateReplacement *tr = new (index) TemplateReplacement();
|
||||
SlObject(tr, _template_replacement_desc);
|
||||
}
|
||||
ReindexTemplateReplacements();
|
||||
}
|
||||
|
||||
extern const ChunkHandler template_replacement_chunk_handlers[] = {
|
||||
{ 'TRPL', Save_TMPL_RPLS, Load_TMPL_RPLS, nullptr, nullptr, CH_ARRAY },
|
||||
};
|
||||
|
||||
extern const ChunkHandlerTable _template_replacement_chunk_handlers(template_replacement_chunk_handlers);
|
||||
@@ -1,159 +0,0 @@
|
||||
#include "../stdafx.h"
|
||||
|
||||
#include "../tbtr_template_vehicle.h"
|
||||
#include "../tbtr_template_vehicle_func.h"
|
||||
#include "../train.h"
|
||||
#include "../company_base.h"
|
||||
#include "../core/backup_type.hpp"
|
||||
#include "../core/random_func.hpp"
|
||||
|
||||
#include "saveload.h"
|
||||
|
||||
const SaveLoadTable GTD() {
|
||||
|
||||
static const SaveLoad _template_veh_desc[] = {
|
||||
SLE_REF(TemplateVehicle, next, REF_TEMPLATE_VEHICLE),
|
||||
|
||||
SLE_VAR(TemplateVehicle, reuse_depot_vehicles, SLE_UINT8),
|
||||
SLE_VAR(TemplateVehicle, keep_remaining_vehicles, SLE_UINT8),
|
||||
SLE_VAR(TemplateVehicle, refit_as_template, SLE_UINT8),
|
||||
SLE_CONDVAR_X(TemplateVehicle, replace_old_only, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 5)),
|
||||
|
||||
SLE_CONDVAR_X(TemplateVehicle, owner, SLE_VAR_U8 | SLE_FILE_U32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 0, 3)),
|
||||
SLE_CONDVAR_X(TemplateVehicle, owner, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 4)),
|
||||
SLE_CONDNULL_X(1, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 0, 3)),
|
||||
|
||||
SLE_VAR(TemplateVehicle, engine_type, SLE_UINT16),
|
||||
SLE_VAR(TemplateVehicle, cargo_type, SLE_UINT8),
|
||||
SLE_VAR(TemplateVehicle, cargo_cap, SLE_UINT16),
|
||||
SLE_VAR(TemplateVehicle, cargo_subtype, SLE_UINT8),
|
||||
|
||||
SLE_VAR(TemplateVehicle, subtype, SLE_UINT8),
|
||||
SLE_VAR(TemplateVehicle, railtype, SLE_UINT8),
|
||||
|
||||
SLE_VAR(TemplateVehicle, index, SLE_UINT32),
|
||||
|
||||
SLE_VAR(TemplateVehicle, real_consist_length, SLE_UINT16),
|
||||
|
||||
SLE_VAR(TemplateVehicle, max_speed, SLE_UINT16),
|
||||
SLE_VAR(TemplateVehicle, power, SLE_UINT32),
|
||||
SLE_VAR(TemplateVehicle, empty_weight, SLE_UINT32),
|
||||
SLE_CONDVAR_X(TemplateVehicle, full_weight, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 6)),
|
||||
SLE_VAR(TemplateVehicle, max_te, SLE_UINT32),
|
||||
SLE_CONDVAR_X(TemplateVehicle, air_drag, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 8)),
|
||||
|
||||
SLE_CONDVAR_X(TemplateVehicle, ctrl_flags, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 7)),
|
||||
SLE_CONDSSTR_X(TemplateVehicle, name, SLE_STR | SLF_ALLOW_CONTROL, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 9)),
|
||||
|
||||
SLE_CONDNULL_X(1, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 0, 3)),
|
||||
SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 0, 1)),
|
||||
SLE_CONDNULL_X(36, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 2, 3)),
|
||||
SLE_CONDNULL_X(36, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP)),
|
||||
SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 0, 3)),
|
||||
};
|
||||
|
||||
return _template_veh_desc;
|
||||
}
|
||||
|
||||
static void Save_TMPLS()
|
||||
{
|
||||
for (TemplateVehicle *tv : TemplateVehicle::Iterate()) {
|
||||
SlSetArrayIndex(tv->index);
|
||||
SlObject(tv, GTD());
|
||||
}
|
||||
}
|
||||
|
||||
static void Load_TMPLS()
|
||||
{
|
||||
int index;
|
||||
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
TemplateVehicle *tv = new (index) TemplateVehicle();
|
||||
SlObject(tv, GTD());
|
||||
}
|
||||
}
|
||||
|
||||
static void Ptrs_TMPLS()
|
||||
{
|
||||
for (TemplateVehicle *tv : TemplateVehicle::Iterate()) {
|
||||
SlObject(tv, GTD());
|
||||
}
|
||||
}
|
||||
|
||||
void AfterLoadTemplateVehicles()
|
||||
{
|
||||
for (TemplateVehicle *tv : TemplateVehicle::Iterate()) {
|
||||
/* Reinstate the previous pointer */
|
||||
if (tv->next != nullptr) tv->next->previous = tv;
|
||||
tv->first = nullptr;
|
||||
}
|
||||
for (TemplateVehicle *tv : TemplateVehicle::Iterate()) {
|
||||
/* Fill the first pointers */
|
||||
if (tv->previous == nullptr) {
|
||||
for (TemplateVehicle *u = tv; u != nullptr; u = u->Next()) {
|
||||
u->first = tv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AfterLoadTemplateVehiclesUpdate()
|
||||
{
|
||||
SavedRandomSeeds saved_seeds;
|
||||
SaveRandomSeeds(&saved_seeds);
|
||||
|
||||
if (!SlXvIsFeaturePresent(XSLFI_TEMPLATE_REPLACEMENT, 3)) {
|
||||
for (TemplateVehicle *tv : TemplateVehicle::Iterate()) {
|
||||
if (tv->Prev() == nullptr && !Company::IsValidID(tv->owner)) {
|
||||
// clean up leftover template vehicles which no longer have a valid owner
|
||||
delete tv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RestoreRandomSeeds(saved_seeds);
|
||||
|
||||
InvalidateTemplateReplacementImages();
|
||||
}
|
||||
|
||||
void AfterLoadTemplateVehiclesUpdateImages()
|
||||
{
|
||||
InvalidateTemplateReplacementImages();
|
||||
}
|
||||
|
||||
void AfterLoadTemplateVehiclesUpdateProperties()
|
||||
{
|
||||
SavedRandomSeeds saved_seeds;
|
||||
SaveRandomSeeds(&saved_seeds);
|
||||
|
||||
for (TemplateVehicle *tv : TemplateVehicle::Iterate()) {
|
||||
if (tv->Prev() == nullptr) {
|
||||
Backup<CompanyID> cur_company(_current_company, tv->owner, FILE_LINE);
|
||||
StringID err;
|
||||
Train* t = VirtualTrainFromTemplateVehicle(tv, err, 0);
|
||||
if (t != nullptr) {
|
||||
uint32 full_cargo_weight = 0;
|
||||
for (Train *u = t; u != nullptr; u = u->Next()) {
|
||||
full_cargo_weight += u->GetCargoWeight(u->cargo_cap);
|
||||
}
|
||||
const GroundVehicleCache *gcache = t->GetGroundVehicleCache();
|
||||
tv->max_speed = t->GetDisplayMaxSpeed();
|
||||
tv->power = gcache->cached_power;
|
||||
tv->empty_weight = gcache->cached_weight;
|
||||
tv->full_weight = gcache->cached_weight + full_cargo_weight;
|
||||
tv->max_te = gcache->cached_max_te;
|
||||
tv->air_drag = gcache->cached_air_drag;
|
||||
delete t;
|
||||
}
|
||||
cur_company.Restore();
|
||||
}
|
||||
}
|
||||
|
||||
RestoreRandomSeeds(saved_seeds);
|
||||
}
|
||||
|
||||
extern const ChunkHandler template_vehicle_chunk_handlers[] = {
|
||||
{ 'TMPL', Save_TMPLS, Load_TMPLS, Ptrs_TMPLS, nullptr, CH_ARRAY },
|
||||
};
|
||||
|
||||
extern const ChunkHandlerTable _template_vehicle_chunk_handlers(template_vehicle_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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
if (!_town_zone_radii_no_update) {
|
||||
/* Update the population and num_house dependent values */
|
||||
for (Town *town : Town::Iterate()) {
|
||||
UpdateTownRadius(town);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
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 Save(Town *t) const override
|
||||
{
|
||||
SlSetStructListLength(NUM_CARGO);
|
||||
for (CargoID i = 0; i < NUM_CARGO; i++) {
|
||||
SlObject(&t->supplied[i], this->GetDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
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());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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),
|
||||
};
|
||||
for (TileIndex t = 0; t < MapSize(); t++) {
|
||||
if (!IsTileType(t, MP_HOUSE)) continue;
|
||||
inline const static SaveLoadCompatTable compat_description = _town_received_sl_compat;
|
||||
|
||||
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;
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
RebuildTownCaches(cargo_update_required, 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),
|
||||
};
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** 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)),
|
||||
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_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),
|
||||
struct HIDSChunkHandler : NewGRFMappingChunkHandler {
|
||||
HIDSChunkHandler() : NewGRFMappingChunkHandler('HIDS', _house_mngr) {}
|
||||
};
|
||||
|
||||
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),
|
||||
};
|
||||
struct CITYChunkHandler : ChunkHandler {
|
||||
CITYChunkHandler() : ChunkHandler('CITY', CH_TABLE) {}
|
||||
|
||||
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),
|
||||
};
|
||||
void Save() const override
|
||||
{
|
||||
SlTableHeader(_town_desc);
|
||||
|
||||
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);
|
||||
}
|
||||
for (Town *t : Town::Iterate()) {
|
||||
SlSetArrayIndex(t->index);
|
||||
SlObject(t, _town_desc);
|
||||
}
|
||||
}
|
||||
|
||||
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() const override
|
||||
{
|
||||
const std::vector<SaveLoad> slt = SlCompatTableHeader(_town_desc, _town_sl_compat);
|
||||
|
||||
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)));
|
||||
int index;
|
||||
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
Town *t = new (index) Town();
|
||||
SlObject(t, slt);
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Fix pointers when loading town data. */
|
||||
static void Ptrs_TOWN()
|
||||
{
|
||||
/* Don't run when savegame version lower than 161. */
|
||||
if (IsSavegameVersionBefore(SLV_161)) return;
|
||||
void FixPointers() const override
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
SlSetLength(4 + (Town::GetNumItems() * (1 + lengthof(TownCache::squared_town_zone_radius)) * 4));
|
||||
|
||||
SlWriteUint32((uint32)Town::GetNumItems());
|
||||
|
||||
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]);
|
||||
for (Town *t : Town::Iterate()) {
|
||||
SlObject(t, _town_desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void Load_TNNC()
|
||||
{
|
||||
if (SlGetFieldLength() == 0) return;
|
||||
|
||||
if (!_networking || _network_server) {
|
||||
SlSkipBytes(SlGetFieldLength());
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,225 +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 tracerestrict_sl.cpp Code handling saving and loading of trace restrict programs */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "../tracerestrict.h"
|
||||
#include "../strings_func.h"
|
||||
#include "../string_func.h"
|
||||
#include "saveload.h"
|
||||
#include <vector>
|
||||
|
||||
static const SaveLoad _trace_restrict_mapping_desc[] = {
|
||||
SLE_VAR(TraceRestrictMappingItem, program_id, SLE_UINT32),
|
||||
};
|
||||
|
||||
/**
|
||||
* Load mappings
|
||||
*/
|
||||
static void Load_TRRM()
|
||||
{
|
||||
int index;
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
TraceRestrictMappingItem &item = _tracerestrictprogram_mapping[index];
|
||||
SlObject(&item, _trace_restrict_mapping_desc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save mappings
|
||||
*/
|
||||
static void Save_TRRM()
|
||||
{
|
||||
for (TraceRestrictMapping::iterator iter = _tracerestrictprogram_mapping.begin();
|
||||
iter != _tracerestrictprogram_mapping.end(); ++iter) {
|
||||
SlSetArrayIndex(iter->first);
|
||||
SlObject(&(iter->second), _trace_restrict_mapping_desc);
|
||||
}
|
||||
}
|
||||
|
||||
/** program length save header struct */
|
||||
struct TraceRestrictProgramStub {
|
||||
uint32 length;
|
||||
};
|
||||
|
||||
static const SaveLoad _trace_restrict_program_stub_desc[] = {
|
||||
SLE_VAR(TraceRestrictProgramStub, length, SLE_UINT32),
|
||||
};
|
||||
|
||||
/**
|
||||
* Load program pool
|
||||
*/
|
||||
static void Load_TRRP()
|
||||
{
|
||||
int index;
|
||||
TraceRestrictProgramStub stub;
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
TraceRestrictProgram *prog = new (index) TraceRestrictProgram();
|
||||
SlObject(&stub, _trace_restrict_program_stub_desc);
|
||||
prog->items.resize(stub.length);
|
||||
if (stub.length > 0) SlArray(prog->items.data(), stub.length, SLE_UINT32);
|
||||
if (SlXvIsFeaturePresent(XSLFI_JOKERPP)) {
|
||||
for (size_t i = 0; i < prog->items.size(); i++) {
|
||||
TraceRestrictItem &item = prog->items[i]; // note this is a reference,
|
||||
if (GetTraceRestrictType(item) == 19 || GetTraceRestrictType(item) == 20) {
|
||||
SetTraceRestrictType(item, (TraceRestrictItemType)(GetTraceRestrictType(item) + 2));
|
||||
}
|
||||
if (IsTraceRestrictDoubleItem(item)) i++;
|
||||
}
|
||||
}
|
||||
CommandCost validation_result = prog->Validate();
|
||||
if (validation_result.Failed()) {
|
||||
char str[4096];
|
||||
char *strend = str + seprintf(str, lastof(str), "Trace restrict program %d: %s\nProgram dump:",
|
||||
index, GetStringPtr(validation_result.GetErrorMessage()));
|
||||
uint fail_offset = validation_result.HasResultData() ? validation_result.GetResultData() : UINT32_MAX;
|
||||
for (uint i = 0; i < (uint)prog->items.size(); i++) {
|
||||
if ((i % 3) == 0) {
|
||||
strend += seprintf(strend, lastof(str), "\n%4u:", i);
|
||||
}
|
||||
strend += seprintf(strend, lastof(str), (i == fail_offset) ? " [%08X]" : " %08X", prog->items[i]);
|
||||
}
|
||||
SlErrorCorrupt(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a program, used by SlAutolength
|
||||
*/
|
||||
static void RealSave_TRRP(TraceRestrictProgram *prog)
|
||||
{
|
||||
TraceRestrictProgramStub stub;
|
||||
stub.length = (uint32)prog->items.size();
|
||||
SlObject(&stub, _trace_restrict_program_stub_desc);
|
||||
SlArray(prog->items.data(), stub.length, SLE_UINT32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save program pool
|
||||
*/
|
||||
static void Save_TRRP()
|
||||
{
|
||||
for (TraceRestrictProgram *prog : TraceRestrictProgram::Iterate()) {
|
||||
SlSetArrayIndex(prog->index);
|
||||
SlAutolength((AutolengthProc*) RealSave_TRRP, prog);
|
||||
}
|
||||
}
|
||||
|
||||
/** program length save header struct */
|
||||
struct TraceRestrictSlotStub {
|
||||
uint32 length;
|
||||
};
|
||||
|
||||
static const SaveLoad _trace_restrict_slot_stub_desc[] = {
|
||||
SLE_VAR(TraceRestrictSlotStub, length, SLE_UINT32),
|
||||
};
|
||||
|
||||
static const SaveLoad _trace_restrict_slot_desc[] = {
|
||||
SLE_VAR(TraceRestrictSlot, max_occupancy, SLE_UINT32),
|
||||
SLE_SSTR(TraceRestrictSlot, name, SLF_ALLOW_CONTROL),
|
||||
SLE_VAR(TraceRestrictSlot, owner, SLE_UINT8),
|
||||
SLE_CONDVAR_X(TraceRestrictSlot, vehicle_type, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TRACE_RESTRICT, 13)),
|
||||
};
|
||||
|
||||
/**
|
||||
* Load slot pool
|
||||
*/
|
||||
static void Load_TRRS()
|
||||
{
|
||||
int index;
|
||||
TraceRestrictSlotStub stub;
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
TraceRestrictSlot *slot = new (index) TraceRestrictSlot();
|
||||
SlObject(slot, _trace_restrict_slot_desc);
|
||||
SlObject(&stub, _trace_restrict_slot_stub_desc);
|
||||
slot->occupants.resize(stub.length);
|
||||
if (stub.length) SlArray(slot->occupants.data(), stub.length, SLE_UINT32);
|
||||
}
|
||||
TraceRestrictSlot::RebuildVehicleIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a slot, used by SlAutolength
|
||||
*/
|
||||
static void RealSave_TRRS(TraceRestrictSlot *slot)
|
||||
{
|
||||
SlObject(slot, _trace_restrict_slot_desc);
|
||||
TraceRestrictSlotStub stub;
|
||||
stub.length = (uint32)slot->occupants.size();
|
||||
SlObject(&stub, _trace_restrict_slot_stub_desc);
|
||||
if (stub.length) SlArray(slot->occupants.data(), stub.length, SLE_UINT32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save slot pool
|
||||
*/
|
||||
static void Save_TRRS()
|
||||
{
|
||||
for (TraceRestrictSlot *slot : TraceRestrictSlot::Iterate()) {
|
||||
SlSetArrayIndex(slot->index);
|
||||
SlAutolength((AutolengthProc*) RealSave_TRRS, slot);
|
||||
}
|
||||
}
|
||||
|
||||
static const SaveLoad _trace_restrict_counter_desc[] = {
|
||||
SLE_VAR(TraceRestrictCounter, value, SLE_INT32),
|
||||
SLE_SSTR(TraceRestrictCounter, name, SLF_ALLOW_CONTROL),
|
||||
SLE_VAR(TraceRestrictCounter, owner, SLE_UINT8),
|
||||
};
|
||||
|
||||
/**
|
||||
* Load counter pool
|
||||
*/
|
||||
static void Load_TRRC()
|
||||
{
|
||||
int index;
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
TraceRestrictCounter *ctr = new (index) TraceRestrictCounter();
|
||||
SlObject(ctr, _trace_restrict_counter_desc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a counter, used by SlAutolength
|
||||
*/
|
||||
static void RealSave_TRRC(TraceRestrictCounter *ctr)
|
||||
{
|
||||
SlObject(ctr, _trace_restrict_counter_desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save counter pool
|
||||
*/
|
||||
static void Save_TRRC()
|
||||
{
|
||||
for (TraceRestrictCounter *ctr : TraceRestrictCounter::Iterate()) {
|
||||
SlSetArrayIndex(ctr->index);
|
||||
SlAutolength((AutolengthProc*) RealSave_TRRC, ctr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update program reference counts from just-loaded mapping
|
||||
*/
|
||||
void AfterLoadTraceRestrict()
|
||||
{
|
||||
for (TraceRestrictMapping::iterator iter = _tracerestrictprogram_mapping.begin();
|
||||
iter != _tracerestrictprogram_mapping.end(); ++iter) {
|
||||
_tracerestrictprogram_pool.Get(iter->second.program_id)->IncrementRefCount(iter->first);
|
||||
}
|
||||
}
|
||||
|
||||
extern const ChunkHandler trace_restrict_chunk_handlers[] = {
|
||||
{ 'TRRM', Save_TRRM, Load_TRRM, nullptr, nullptr, CH_SPARSE_ARRAY }, // Trace Restrict Mapping chunk
|
||||
{ 'TRRP', Save_TRRP, Load_TRRP, nullptr, nullptr, CH_ARRAY }, // Trace Restrict Mapping Program Pool chunk
|
||||
{ 'TRRS', Save_TRRS, Load_TRRS, nullptr, nullptr, CH_ARRAY }, // Trace Restrict Slot Pool chunk
|
||||
{ 'TRRC', Save_TRRC, Load_TRRC, nullptr, nullptr, CH_ARRAY }, // Trace Restrict Counter Pool chunk
|
||||
};
|
||||
|
||||
extern const ChunkHandlerTable _trace_restrict_chunk_handlers(trace_restrict_chunk_handlers);
|
||||
@@ -1,59 +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 train_speed_adaptation.cpp Code handling saving and loading of data for train speed adaptation */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "../train_speed_adaptation.h"
|
||||
#include "saveload.h"
|
||||
|
||||
using SignalSpeedType = std::pair<const SignalSpeedKey, SignalSpeedValue>;
|
||||
|
||||
static const SaveLoad _train_speed_adaptation_map_desc[] = {
|
||||
SLE_CONDVAR_X(SignalSpeedType, first.signal_track, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TRAIN_SPEED_ADAPTATION, 1, 1)),
|
||||
SLE_CONDVAR_X(SignalSpeedType, first.signal_track, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TRAIN_SPEED_ADAPTATION, 2)),
|
||||
SLE_VAR(SignalSpeedType, first.last_passing_train_dir, SLE_UINT8),
|
||||
SLE_VAR(SignalSpeedType, second.train_speed, SLE_UINT16),
|
||||
SLE_VAR(SignalSpeedType, second.time_stamp, SLE_UINT64),
|
||||
};
|
||||
|
||||
static std::vector<SaveLoad> _filtered_train_speed_adaptation_map_desc = SlFilterObject(_train_speed_adaptation_map_desc);
|
||||
|
||||
static void Load_TSAS()
|
||||
{
|
||||
_filtered_train_speed_adaptation_map_desc = SlFilterObject(_train_speed_adaptation_map_desc);
|
||||
int index;
|
||||
SignalSpeedType data;
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
const_cast<SignalSpeedKey &>(data.first).signal_tile = index;
|
||||
SlObjectLoadFiltered(&data, _filtered_train_speed_adaptation_map_desc);
|
||||
_signal_speeds.insert(data);
|
||||
}
|
||||
_filtered_train_speed_adaptation_map_desc.clear();
|
||||
}
|
||||
|
||||
static void RealSave_TSAS(SignalSpeedType *data)
|
||||
{
|
||||
SlObjectSaveFiltered(data, _filtered_train_speed_adaptation_map_desc);
|
||||
}
|
||||
|
||||
static void Save_TSAS()
|
||||
{
|
||||
_filtered_train_speed_adaptation_map_desc = SlFilterObject(_train_speed_adaptation_map_desc);
|
||||
for (auto &it : _signal_speeds) {
|
||||
SlSetArrayIndex(it.first.signal_tile);
|
||||
SignalSpeedType *data = ⁢
|
||||
SlAutolength((AutolengthProc*) RealSave_TSAS, data);
|
||||
}
|
||||
_filtered_train_speed_adaptation_map_desc.clear();
|
||||
}
|
||||
|
||||
extern const ChunkHandler train_speed_adaptation_chunk_handlers[] = {
|
||||
{ 'TSAS', Save_TSAS, Load_TSAS, nullptr, nullptr, CH_SPARSE_ARRAY },
|
||||
};
|
||||
|
||||
extern const ChunkHandlerTable _train_speed_adaptation_chunk_handlers(train_speed_adaptation_chunk_handlers);
|
||||
@@ -1,50 +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 tunnel_sl.cpp Code handling saving and loading of tunnels */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "../tunnel_base.h"
|
||||
|
||||
#include "saveload.h"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
|
||||
static const SaveLoad _tunnel_desc[] = {
|
||||
SLE_CONDVAR(Tunnel, tile_n, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Tunnel, tile_s, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Tunnel, height, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Tunnel, is_chunnel, SLE_BOOL, SL_MIN_VERSION, SL_MAX_VERSION),
|
||||
SLE_CONDVAR_X(Tunnel, style, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_NEW_SIGNAL_STYLES)),
|
||||
};
|
||||
|
||||
static void Save_TUNN()
|
||||
{
|
||||
for (Tunnel *tunnel : Tunnel::Iterate()) {
|
||||
SlSetArrayIndex(tunnel->index);
|
||||
SlObject(tunnel, _tunnel_desc);
|
||||
}
|
||||
}
|
||||
|
||||
static void Load_TUNN()
|
||||
{
|
||||
int index;
|
||||
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
Tunnel *tunnel = new (index) Tunnel();
|
||||
SlObject(tunnel, _tunnel_desc);
|
||||
tunnel->UpdateIndexes();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extern const ChunkHandler tunnel_chunk_handlers[] = {
|
||||
{ 'TUNN', Save_TUNN, Load_TUNN, nullptr, nullptr, CH_ARRAY },
|
||||
};
|
||||
|
||||
extern const ChunkHandlerTable _tunnel_chunk_handlers(tunnel_chunk_handlers);
|
||||
@@ -1,39 +0,0 @@
|
||||
add_subdirectory(compat)
|
||||
|
||||
add_files(
|
||||
ai_sl.cpp
|
||||
airport_sl.cpp
|
||||
animated_tile_sl.cpp
|
||||
autoreplace_sl.cpp
|
||||
cargomonitor_sl.cpp
|
||||
cargopacket_sl.cpp
|
||||
cheat_sl.cpp
|
||||
company_sl.cpp
|
||||
depot_sl.cpp
|
||||
economy_sl.cpp
|
||||
engine_sl.cpp
|
||||
game_sl.cpp
|
||||
gamelog_sl.cpp
|
||||
goal_sl.cpp
|
||||
group_sl.cpp
|
||||
industry_sl.cpp
|
||||
labelmaps_sl.cpp
|
||||
league_sl.cpp
|
||||
linkgraph_sl.cpp
|
||||
map_sl.cpp
|
||||
misc_sl.cpp
|
||||
newgrf_sl.cpp
|
||||
newgrf_sl.h
|
||||
object_sl.cpp
|
||||
order_sl.cpp
|
||||
saveload.cpp
|
||||
saveload.h
|
||||
settings_sl.cpp
|
||||
signs_sl.cpp
|
||||
station_sl.cpp
|
||||
storage_sl.cpp
|
||||
story_sl.cpp
|
||||
subsidy_sl.cpp
|
||||
town_sl.cpp
|
||||
vehicle_sl.cpp
|
||||
)
|
||||
@@ -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,36 +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 airport_sl.cpp Code handling saving and loading airport ids */
|
||||
|
||||
#include "../../stdafx.h"
|
||||
|
||||
#include "saveload.h"
|
||||
#include "newgrf_sl.h"
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
namespace upstream_sl {
|
||||
|
||||
struct APIDChunkHandler : NewGRFMappingChunkHandler {
|
||||
APIDChunkHandler() : NewGRFMappingChunkHandler('APID', _airport_mngr) {}
|
||||
};
|
||||
|
||||
struct ATIDChunkHandler : NewGRFMappingChunkHandler {
|
||||
ATIDChunkHandler() : NewGRFMappingChunkHandler('ATID', _airporttile_mngr) {}
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
@@ -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,78 +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 depot_sl.cpp Code handling saving and loading of depots */
|
||||
|
||||
#include "../../stdafx.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", _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),
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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, slt);
|
||||
|
||||
/* Set the town 'pointer' so we can restore it later. */
|
||||
if (IsSavegameVersionBefore(SLV_141)) depot->town = (Town *)(size_t)_town_index;
|
||||
}
|
||||
}
|
||||
|
||||
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 DEPTChunkHandler DEPT;
|
||||
static const ChunkHandlerRef depot_chunk_handlers[] = {
|
||||
DEPT,
|
||||
};
|
||||
|
||||
extern const ChunkHandlerTable _depot_chunk_handlers(depot_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);
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user