25#include "../station_base.h"
28#include "../network/network.h"
29#include "../window_func.h"
30#include "../strings_func.h"
31#include "../core/endian_func.hpp"
32#include "../core/string_builder.hpp"
33#include "../vehicle_base.h"
34#include "../company_func.h"
35#include "../timer/timer_game_economy.h"
36#include "../autoreplace_base.h"
37#include "../roadstop_base.h"
38#include "../linkgraph/linkgraph.h"
39#include "../linkgraph/linkgraphjob.h"
40#include "../statusbar_gui.h"
41#include "../fileio_func.h"
42#include "../gamelog.h"
43#include "../string_func.h"
46#include "../strings_type.h"
47#include "../newgrf_railtype.h"
48#include "../newgrf_roadtype.h"
49#include "../settings_internal.h"
55# include <emscripten.h>
58#include "table/strings.h"
60#include "../safeguards.h"
96 std::shared_ptr<LoadFilter>
reader{};
107 inline uint8_t ReadByte()
109 if (this->bufp == this->bufe) {
114 this->bufp = this->
buf;
115 this->bufe = this->buf + len;
118 return *this->bufp++;
127 return this->read - (this->bufe - this->
bufp);
134 std::vector<std::unique_ptr<uint8_t[]>>
blocks{};
145 if (this->buf == this->bufe) {
157 void Flush(std::shared_ptr<SaveFilter> writer)
165 writer->Write(this->
blocks[i++].get(), to_write);
178 return this->
blocks.size() * MEMORY_CHUNK_SIZE - (this->bufe - this->
buf);
194 std::shared_ptr<SaveFilter>
sf;
197 std::shared_ptr<LoadFilter>
lf;
249 _gamelog_chunk_handlers,
251 _misc_chunk_handlers,
252 _name_chunk_handlers,
253 _cheat_chunk_handlers,
254 _setting_chunk_handlers,
256 _waypoint_chunk_handlers,
257 _depot_chunk_handlers,
258 _order_chunk_handlers,
259 _industry_chunk_handlers,
260 _economy_chunk_handlers,
261 _subsidy_chunk_handlers,
262 _cargomonitor_chunk_handlers,
263 _goal_chunk_handlers,
264 _story_page_chunk_handlers,
265 _league_chunk_handlers,
266 _engine_chunk_handlers,
267 _town_chunk_handlers,
268 _sign_chunk_handlers,
269 _station_chunk_handlers,
270 _company_chunk_handlers,
272 _game_chunk_handlers,
273 _animated_tile_chunk_handlers,
274 _newgrf_chunk_handlers,
275 _group_chunk_handlers,
276 _cargopacket_chunk_handlers,
277 _autoreplace_chunk_handlers,
278 _labelmaps_chunk_handlers,
279 _linkgraph_chunk_handlers,
280 _airport_chunk_handlers,
281 _object_chunk_handlers,
282 _persistent_storage_chunk_handlers,
283 _water_region_chunk_handlers,
284 _randomizer_chunk_handlers,
287 static std::vector<ChunkHandlerRef> _chunk_handlers;
289 if (_chunk_handlers.empty()) {
290 for (
auto &chunk_handler_table : _chunk_handler_tables) {
291 for (
auto &chunk_handler : chunk_handler_table) {
292 _chunk_handlers.push_back(chunk_handler);
297 return _chunk_handlers;
311 Debug(sl, 3,
"Nulling pointers for {}", ch.GetName());
346 throw std::exception();
358 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, msg);
372 if (_exit_game)
return;
384 if (proc ==
nullptr)
return;
411static inline int SlReadUint16()
417static inline uint32_t SlReadUint32()
419 uint32_t x = SlReadUint16() << 16;
420 return x | SlReadUint16();
423static inline uint64_t SlReadUint64()
425 uint32_t x = SlReadUint32();
426 uint32_t y = SlReadUint32();
427 return (uint64_t)x << 32 | y;
430static inline void SlWriteUint16(uint16_t v)
436static inline void SlWriteUint32(uint32_t v)
438 SlWriteUint16(
GB(v, 16, 16));
439 SlWriteUint16(
GB(v, 0, 16));
442static inline void SlWriteUint64(uint64_t x)
444 SlWriteUint32((uint32_t)(x >> 32));
445 SlWriteUint32((uint32_t)x);
502 if (i >= (1 << 14)) {
503 if (i >= (1 << 21)) {
504 if (i >= (1 << 28)) {
505 assert(i <= UINT32_MAX);
526 return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21)) + (i >= (1 << 28));
529static inline uint SlReadSparseIndex()
534static inline void SlWriteSparseIndex(uint index)
539static inline uint SlReadArrayLength()
544static inline void SlWriteArrayLength(
size_t length)
549static inline uint SlGetArrayLength(
size_t length)
583 default: NOT_REACHED();
596 case SLE_VAR_BL:
return sizeof(bool);
597 case SLE_VAR_I8:
return sizeof(int8_t);
598 case SLE_VAR_U8:
return sizeof(uint8_t);
599 case SLE_VAR_I16:
return sizeof(int16_t);
600 case SLE_VAR_U16:
return sizeof(uint16_t);
601 case SLE_VAR_I32:
return sizeof(int32_t);
602 case SLE_VAR_U32:
return sizeof(uint32_t);
603 case SLE_VAR_I64:
return sizeof(int64_t);
604 case SLE_VAR_U64:
return sizeof(uint64_t);
609 return SlReadArrayLength();
627 case SLE_FILE_I8:
return sizeof(int8_t);
628 case SLE_FILE_U8:
return sizeof(uint8_t);
629 case SLE_FILE_I16:
return sizeof(int16_t);
630 case SLE_FILE_U16:
return sizeof(uint16_t);
631 case SLE_FILE_I32:
return sizeof(int32_t);
632 case SLE_FILE_U32:
return sizeof(uint32_t);
633 case SLE_FILE_I64:
return sizeof(int64_t);
634 case SLE_FILE_U64:
return sizeof(uint64_t);
637 case SLE_FILE_STRING:
638 return SlReadArrayLength();
640 case SLE_FILE_STRUCT:
652void SlSetArrayIndex(uint index)
655 _sl.array_index = index;
658static size_t _next_offs;
668 if (_next_offs != 0 &&
_sl.
reader->GetSize() != _next_offs) {
669 SlErrorCorruptFmt(
"Invalid chunk size iterating array - expected to be at position {}, actually at {}", _next_offs,
_sl.
reader->GetSize());
673 uint length = SlReadArrayLength();
681 _next_offs =
_sl.
reader->GetSize() + length;
690 case CH_SPARSE_TABLE:
691 case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex();
break;
693 case CH_ARRAY: index =
_sl.array_index++;
break;
695 Debug(sl, 0,
"SlIterateArray error");
699 if (length != 0)
return index;
727 SlWriteArrayLength(length + 1);
736 assert(length < (1 << 28));
737 SlWriteUint32((uint32_t)((length & 0xFFFFFF) | ((length >> 24) << 28)));
743 SlWriteArrayLength(1);
745 SlWriteArrayLength(length + 1);
747 case CH_SPARSE_TABLE:
748 case CH_SPARSE_ARRAY:
749 SlWriteArrayLength(length + 1 + SlGetArrayLength(
_sl.array_index));
750 SlWriteSparseIndex(
_sl.array_index);
752 default: NOT_REACHED();
760 default: NOT_REACHED();
772 uint8_t *p = (uint8_t *)ptr;
777 for (; length != 0; length--) *p++ =
SlReadByte();
782 default: NOT_REACHED();
802 case SLE_VAR_BL:
return (*(
const bool *)ptr != 0);
803 case SLE_VAR_I8:
return *(
const int8_t *)ptr;
804 case SLE_VAR_U8:
return *(
const uint8_t *)ptr;
805 case SLE_VAR_I16:
return *(
const int16_t *)ptr;
806 case SLE_VAR_U16:
return *(
const uint16_t*)ptr;
807 case SLE_VAR_I32:
return *(
const int32_t *)ptr;
808 case SLE_VAR_U32:
return *(
const uint32_t*)ptr;
809 case SLE_VAR_I64:
return *(
const int64_t *)ptr;
810 case SLE_VAR_U64:
return *(
const uint64_t*)ptr;
812 default: NOT_REACHED();
826 case SLE_VAR_BL: *(
bool *)ptr = (val != 0);
break;
827 case SLE_VAR_I8: *(int8_t *)ptr = val;
break;
828 case SLE_VAR_U8: *(uint8_t *)ptr = val;
break;
829 case SLE_VAR_I16: *(int16_t *)ptr = val;
break;
830 case SLE_VAR_U16: *(uint16_t*)ptr = val;
break;
831 case SLE_VAR_I32: *(int32_t *)ptr = val;
break;
832 case SLE_VAR_U32: *(uint32_t*)ptr = val;
break;
833 case SLE_VAR_I64: *(int64_t *)ptr = val;
break;
834 case SLE_VAR_U64: *(uint64_t*)ptr = val;
break;
837 default: NOT_REACHED();
857 case SLE_FILE_I8: assert(x >= -128 && x <= 127);
SlWriteByte(x);
break;
858 case SLE_FILE_U8: assert(x >= 0 && x <= 255);
SlWriteByte(x);
break;
859 case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);
break;
861 case SLE_FILE_U16:assert(x >= 0 && x <= 65535); SlWriteUint16(x);
break;
863 case SLE_FILE_U32: SlWriteUint32((uint32_t)x);
break;
865 case SLE_FILE_U64: SlWriteUint64(x);
break;
866 default: NOT_REACHED();
875 case SLE_FILE_I8: x = (int8_t )
SlReadByte();
break;
876 case SLE_FILE_U8: x = (uint8_t )
SlReadByte();
break;
877 case SLE_FILE_I16: x = (int16_t )SlReadUint16();
break;
878 case SLE_FILE_U16: x = (uint16_t)SlReadUint16();
break;
879 case SLE_FILE_I32: x = (int32_t )SlReadUint32();
break;
880 case SLE_FILE_U32: x = (uint32_t)SlReadUint32();
break;
881 case SLE_FILE_I64: x = (int64_t )SlReadUint64();
break;
882 case SLE_FILE_U64: x = (uint64_t)SlReadUint64();
break;
884 default: NOT_REACHED();
893 default: NOT_REACHED();
906 const std::string *str =
reinterpret_cast<const std::string *
>(ptr);
908 size_t len = str->length();
909 return len + SlGetArrayLength(len);
922 if (str.empty())
return;
934 bool is_encoded =
false;
935 bool in_string =
false;
936 bool need_type =
true;
938 for (
auto it = std::begin(str); it != std::end(str); ) {
940 if (len == 0 || it + len > std::end(str))
break;
945 if (c ==
SCC_ENCODED || (fix_code && (c == 0xE028 || c == 0xE02A))) {
953 if (!is_encoded)
return;
956 in_string = !in_string;
957 if (in_string && need_type) {
965 if (!in_string && c ==
':') {
966 builder.
PutUtf8(SCC_RECORD_SEPARATOR);
979 str = std::move(result);
1001 std::string *str =
reinterpret_cast<std::string *
>(ptr);
1005 size_t len = str->length();
1006 SlWriteArrayLength(len);
1007 SlCopyBytes(
const_cast<void *
>(
static_cast<const void *
>(str->c_str())), len);
1013 size_t len = SlReadArrayLength();
1034 default: NOT_REACHED();
1058 if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
1059 conv == SLE_INT32 || conv == SLE_UINT32) {
1064 if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
1065 for (uint i = 0; i < length; i++) {
1066 ((int64_t*)
object)[i] = (int32_t)std::byteswap(SlReadUint32());
1074 if (conv == SLE_INT8 || conv == SLE_UINT8) {
1077 uint8_t *a = (uint8_t*)
object;
1080 for (; length != 0; length --) {
1095void SlCopy(
void *
object,
size_t length, VarType conv)
1125static void SlArray(
void *array,
size_t length, VarType conv)
1129 SlWriteArrayLength(length);
1136 size_t sv_length = SlReadArrayLength();
1140 }
else if (sv_length != length) {
1175 if (obj ==
nullptr)
return 0;
1190 default: NOT_REACHED();
1206 static_assert(
sizeof(size_t) <=
sizeof(
void *));
1271 default: NOT_REACHED();
1294 *(
void **)ptr =
nullptr;
1296 default: NOT_REACHED();
1303template <
template <
typename,
typename>
typename Tstorage,
typename Tvar,
typename Tallocator = std::allocator<Tvar>>
1305 typedef Tstorage<Tvar, Tallocator> SlStorageT;
1317 const SlStorageT *list =
static_cast<const SlStorageT *
>(storage);
1319 int type_size = SlGetArrayLength(list->size());
1321 return list->size() * item_size + type_size;
1324 static void SlSaveLoadMember(
SaveLoadType cmd, Tvar *item, VarType conv)
1345 SlStorageT *list =
static_cast<SlStorageT *
>(storage);
1349 SlWriteArrayLength(list->size());
1351 for (
auto &item : *list) {
1352 SlSaveLoadMember(cmd, &item, conv);
1362 case SL_STDSTR: length = SlReadArrayLength();
break;
1363 default: NOT_REACHED();
1367 if constexpr (std::is_same_v<SlStorageT, std::vector<Tvar, Tallocator>>) {
1368 list->reserve(length);
1372 for (
size_t i = 0; i < length; i++) {
1373 Tvar &data = list->emplace_back();
1374 SlSaveLoadMember(cmd, &data, conv);
1380 for (
auto &item : *list) {
1381 SlSaveLoadMember(cmd, &item, conv);
1389 default: NOT_REACHED();
1471 default: NOT_REACHED();
1502 default: NOT_REACHED();
1514 case SLE_VAR_BL: NOT_REACHED();
1529 default: NOT_REACHED();
1541 case SLE_VAR_BL: NOT_REACHED();
1560 default: NOT_REACHED();
1579 for (
auto &sld : slt) {
1588 for (
auto &sld : slt) {
1609 for (
auto &sld : slt) {
1610 length += SlCalcObjMemberLength(
object, sld);
1615size_t SlCalcObjMemberLength(
const void *
object,
const SaveLoad &sld)
1644 sld.
handler->Save(
const_cast<void *
>(
object));
1651 length += SlGetArrayLength(1);
1657 default: NOT_REACHED();
1662static bool SlObjectMember(
void *
object,
const SaveLoad &sld)
1666 VarType conv =
GB(sld.
conv, 0, 8);
1687 default: NOT_REACHED();
1704 default: NOT_REACHED();
1718 default: NOT_REACHED();
1739 sld.
handler->LoadCheck(
object);
1752 sld.
handler->FixPointers(
object);
1756 default: NOT_REACHED();
1760 default: NOT_REACHED();
1777 SlWriteArrayLength(length);
1787 size_t length = SlReadArrayLength();
1806 for (
auto &sld : slt) {
1807 SlObjectMember(
object, sld);
1821 void Load(
void *
object)
const override
1824 for (; length > 0; length--) {
1859 std::vector<SaveLoad> saveloads;
1862 std::map<std::string, const SaveLoad *> key_lookup;
1863 for (
auto &sld : slt) {
1867 assert(key_lookup.find(sld.
name) == key_lookup.end());
1868 key_lookup[sld.
name] = &sld;
1879 auto sld_it = key_lookup.find(key);
1880 if (sld_it == key_lookup.end()) {
1884 std::shared_ptr<SaveLoadHandler> handler =
nullptr;
1887 case SLE_FILE_STRING:
1892 case SLE_FILE_STRUCT:
1895 handler = std::make_shared<SlSkipHandler>();
1914 if (correct_type != type) {
1915 Debug(sl, 1,
"Field type for '{}' was expected to be 0x{:02x} but 0x{:02x} was found", key, correct_type, type);
1918 saveloads.emplace_back(*sld_it->second);
1921 for (
auto &sld : saveloads) {
1937 for (
auto &sld : slt) {
1940 assert(!sld.
name.empty());
1954 for (
auto &sld : slt) {
1970 default: NOT_REACHED();
1973 return std::vector<SaveLoad>();
1995 std::vector<SaveLoad> saveloads;
1998 std::map<std::string, std::vector<const SaveLoad *>> key_lookup;
1999 for (
auto &sld : slt) {
2001 assert(!sld.
name.empty());
2003 key_lookup[sld.
name].push_back(&sld);
2006 for (
auto &slc : slct) {
2007 if (slc.name.empty()) {
2013 auto sld_it = key_lookup.find(slc.name);
2017 if (sld_it == key_lookup.end()) {
2020 Debug(sl, 0,
"internal error: saveload compatibility field '{}' not found", slc.name);
2023 for (
auto &sld : sld_it->second) {
2024 saveloads.push_back(*sld);
2029 for (
auto &sld : saveloads) {
2066 size_t start_pos =
_sl.
dumper->GetSize();
2067 size_t expected_offs = start_pos +
_sl.
obj_len;
2072 if (expected_offs !=
_sl.
dumper->GetSize()) {
2073 SlErrorCorruptFmt(
"Invalid chunk size when writing autolength block, expected {}, got {}",
_sl.
obj_len,
_sl.
dumper->GetSize() - start_pos);
2081 case CH_SPARSE_TABLE:
2085 case CH_SPARSE_ARRAY:
2117 _sl.array_index = 0;
2121 case CH_SPARSE_TABLE:
2122 case CH_SPARSE_ARRAY:
2128 size_t len = (
SlReadByte() << 16) | ((m >> 4) << 24);
2129 len += SlReadUint16();
2131 size_t start_pos =
_sl.
reader->GetSize();
2132 size_t endoffs = start_pos + len;
2136 SlErrorCorruptFmt(
"Invalid chunk size in RIFF in {} - expected {}, got {}", ch.GetName(), len,
_sl.
reader->GetSize() - start_pos);
2170 _sl.array_index = 0;
2173 case CH_SPARSE_TABLE:
2174 case CH_SPARSE_ARRAY:
2179 size_t len = (
SlReadByte() << 16) | ((m >> 4) << 24);
2180 len += SlReadUint16();
2182 size_t start_pos =
_sl.
reader->GetSize();
2183 size_t endoffs = start_pos + len;
2187 SlErrorCorruptFmt(
"Invalid chunk size in RIFF in {} - expected {}, got {}", ch.GetName(), len,
_sl.
reader->GetSize() - start_pos);
2208 SlWriteUint32(ch.
id);
2209 Debug(sl, 2,
"Saving chunk {}", ch.GetName());
2225 SlWriteArrayLength(0);
2227 case CH_SPARSE_TABLE:
2228 case CH_SPARSE_ARRAY:
2231 SlWriteArrayLength(0);
2233 default: NOT_REACHED();
2268 for (
id = SlReadUint32();
id != 0;
id = SlReadUint32()) {
2269 Debug(sl, 2,
"Loading chunk {:c}{:c}{:c}{:c}",
id >> 24,
id >> 16,
id >> 8,
id);
2283 for (
id = SlReadUint32();
id != 0;
id = SlReadUint32()) {
2284 Debug(sl, 2,
"Loading chunk {:c}{:c}{:c}{:c}",
id >> 24,
id >> 16,
id >> 8,
id);
2298 Debug(sl, 3,
"Fixing pointers for {}", ch.GetName());
2322 if (this->file.has_value()) {
2327 size_t Read(uint8_t *buf,
size_t size)
override
2330 if (!this->file.has_value())
return 0;
2332 return fread(buf, 1, size, *this->file);
2337 clearerr(*this->file);
2338 if (fseek(*this->file, this->begin, SEEK_SET)) {
2339 Debug(sl, 1,
"Could not reset the file reading");
2362 void Write(uint8_t *buf,
size_t size)
override
2365 if (!this->file.has_value())
return;
2367 if (fwrite(buf, 1, size, *this->file) != size)
SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
2372 if (this->file.has_value()) {
2384#include <lzo/lzo1x.h>
2397 if (lzo_init() != LZO_E_OK)
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR,
"cannot initialize decompressor");
2400 size_t Read(uint8_t *buf,
size_t ssize)
override
2408 lzo_uint len = ssize;
2411 if (this->
chain->Read((uint8_t*)tmp,
sizeof(tmp)) !=
sizeof(tmp))
SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE,
"File read failed");
2414 ((uint32_t*)out)[0] = size = tmp[1];
2417 tmp[0] = TO_BE32(tmp[0]);
2418 size = TO_BE32(size);
2424 if (this->
chain->Read(out +
sizeof(uint32_t), size) != size)
SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
2427 if (tmp[0] != lzo_adler32(0, out, size +
sizeof(uint32_t)))
SlErrorCorrupt(
"Bad checksum");
2430 int ret = lzo1x_decompress_safe(out +
sizeof(uint32_t) * 1, size, buf, &len,
nullptr);
2431 if (ret != LZO_E_OK)
SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
2444 if (lzo_init() != LZO_E_OK)
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR,
"cannot initialize compressor");
2447 void Write(uint8_t *buf,
size_t size)
override
2449 const lzo_bytep in = buf;
2452 uint8_t wrkmem[LZO1X_1_MEM_COMPRESS];
2458 lzo1x_1_compress(in, len, out +
sizeof(uint32_t) * 2, &outlen, wrkmem);
2459 ((uint32_t*)out)[1] = TO_BE32((uint32_t)outlen);
2460 ((uint32_t*)out)[0] = TO_BE32(lzo_adler32(0, out +
sizeof(uint32_t), outlen +
sizeof(uint32_t)));
2461 this->
chain->Write(out, outlen +
sizeof(uint32_t) * 2);
2486 size_t Read(uint8_t *buf,
size_t size)
override
2488 return this->
chain->Read(buf, size);
2502 void Write(uint8_t *buf,
size_t size)
override
2504 this->
chain->Write(buf, size);
2512#if defined(WITH_ZLIB)
2526 memset(&this->z, 0,
sizeof(this->z));
2527 if (inflateInit(&this->z) != Z_OK)
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR,
"cannot initialize decompressor");
2533 inflateEnd(&this->z);
2536 size_t Read(uint8_t *buf,
size_t size)
override
2538 this->z.next_out = buf;
2539 this->z.avail_out = (uint)size;
2543 if (this->z.avail_in == 0) {
2545 this->z.avail_in = (uint)this->
chain->Read(this->fread_buf,
sizeof(this->fread_buf));
2549 int r = inflate(&this->z, 0);
2550 if (r == Z_STREAM_END)
break;
2552 if (r != Z_OK)
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR,
"inflate() failed");
2553 }
while (this->z.avail_out != 0);
2555 return size - this->z.avail_out;
2571 memset(&this->z, 0,
sizeof(this->z));
2572 if (deflateInit(&this->z, compression_level) != Z_OK)
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR,
"cannot initialize compressor");
2578 deflateEnd(&this->z);
2590 this->z.next_in = p;
2591 this->z.avail_in = (uInt)len;
2594 this->z.avail_out =
sizeof(this->
fwrite_buf);
2603 int r = deflate(&this->z, mode);
2606 if ((n =
sizeof(this->fwrite_buf) - this->z.avail_out) != 0) {
2607 this->
chain->Write(this->fwrite_buf, n);
2609 if (r == Z_STREAM_END)
break;
2611 if (r != Z_OK)
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR,
"zlib returned error code");
2612 }
while (this->z.avail_in || !this->z.avail_out);
2615 void Write(uint8_t *buf,
size_t size)
override
2623 this->
chain->Finish();
2633#if defined(WITH_LIBLZMA)
2656 if (lzma_auto_decoder(&this->lzma, 1 << 28, 0) != LZMA_OK)
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR,
"cannot initialize decompressor");
2662 lzma_end(&this->lzma);
2665 size_t Read(uint8_t *buf,
size_t size)
override
2667 this->lzma.next_out = buf;
2668 this->lzma.avail_out = size;
2672 if (this->lzma.avail_in == 0) {
2674 this->lzma.avail_in = this->
chain->Read(this->fread_buf,
sizeof(this->fread_buf));
2678 lzma_ret r = lzma_code(&this->lzma, LZMA_RUN);
2679 if (r == LZMA_STREAM_END)
break;
2680 if (r != LZMA_OK)
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR,
"liblzma returned error code");
2681 }
while (this->lzma.avail_out != 0);
2683 return size - this->lzma.avail_out;
2699 if (lzma_easy_encoder(&this->lzma, compression_level, LZMA_CHECK_CRC32) != LZMA_OK)
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR,
"cannot initialize compressor");
2705 lzma_end(&this->lzma);
2717 this->lzma.next_in = p;
2718 this->lzma.avail_in = len;
2721 this->lzma.avail_out =
sizeof(this->
fwrite_buf);
2723 lzma_ret r = lzma_code(&this->lzma, action);
2726 if ((n =
sizeof(this->fwrite_buf) - this->lzma.avail_out) != 0) {
2727 this->
chain->Write(this->fwrite_buf, n);
2729 if (r == LZMA_STREAM_END)
break;
2730 if (r != LZMA_OK)
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR,
"liblzma returned error code");
2731 }
while (this->lzma.avail_in || !this->lzma.avail_out);
2734 void Write(uint8_t *buf,
size_t size)
override
2741 this->
WriteLoop(
nullptr, 0, LZMA_FINISH);
2742 this->
chain->Finish();
2757 std::shared_ptr<LoadFilter> (*
init_load)(std::shared_ptr<LoadFilter> chain);
2758 std::shared_ptr<SaveFilter> (*
init_write)(std::shared_ptr<SaveFilter> chain, uint8_t compression);
2765static const uint32_t SAVEGAME_TAG_LZO = TO_BE32(
'OTTD');
2766static const uint32_t SAVEGAME_TAG_NONE = TO_BE32(
'OTTN');
2767static const uint32_t SAVEGAME_TAG_ZLIB = TO_BE32(
'OTTZ');
2768static const uint32_t SAVEGAME_TAG_LZMA = TO_BE32(
'OTTX');
2772#if defined(WITH_LZO)
2774 {
"lzo", SAVEGAME_TAG_LZO, CreateLoadFilter<LZOLoadFilter>, CreateSaveFilter<LZOSaveFilter>, 0, 0, 0},
2776 {
"lzo", SAVEGAME_TAG_LZO,
nullptr,
nullptr, 0, 0, 0},
2779 {
"none", SAVEGAME_TAG_NONE, CreateLoadFilter<NoCompLoadFilter>, CreateSaveFilter<NoCompSaveFilter>, 0, 0, 0},
2780#if defined(WITH_ZLIB)
2784 {
"zlib", SAVEGAME_TAG_ZLIB, CreateLoadFilter<ZlibLoadFilter>, CreateSaveFilter<ZlibSaveFilter>, 0, 6, 9},
2786 {
"zlib", SAVEGAME_TAG_ZLIB,
nullptr,
nullptr, 0, 0, 0},
2788#if defined(WITH_LIBLZMA)
2794 {
"lzma", SAVEGAME_TAG_LZMA, CreateLoadFilter<LZMALoadFilter>, CreateSaveFilter<LZMASaveFilter>, 0, 2, 9},
2796 {
"lzma", SAVEGAME_TAG_LZMA,
nullptr,
nullptr, 0, 0, 0},
2810 if (it == std::rend(
_saveload_formats))
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR,
"no writeable savegame formats");
2814 if (!full_name.empty()) {
2816 size_t separator = full_name.find(
':');
2817 bool has_comp_level = separator != std::string::npos;
2818 const std::string name(full_name, 0, has_comp_level ? separator : full_name.size());
2821 if (slf.init_write !=
nullptr && name.compare(slf.name) == 0) {
2822 if (has_comp_level) {
2823 const std::string complevel(full_name, separator + 1);
2827 long level = std::stol(complevel, &processed, 10);
2828 if (processed == 0 || level !=
Clamp(level, slf.min_compression, slf.max_compression)) {
2831 GetEncodedString(STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL, complevel),
2834 return {slf, ClampTo<uint8_t>(level)};
2837 return {slf, slf.default_compression};
2850void InitializeGame(uint size_x, uint size_y,
bool reset_date,
bool reset_settings);
2852extern bool LoadOldSaveGame(
const std::string &file);
2875 ResetTempEngineData();
2876 ClearRailTypeLabelList();
2877 ClearRoadTypeLabelList();
2878 ResetOldWaypoints();
2910#ifdef __EMSCRIPTEN__
2911 EM_ASM(
if (window[
"openttd_syncfs"]) openttd_syncfs());
2951 _sl.
sf->Write((uint8_t*)hdr,
sizeof(hdr));
2953 _sl.
sf = fmt.init_write(
_sl.
sf, compression);
2968 if (
_sl.
error_str != STR_NETWORK_ERROR_LOSTCONNECTION) {
3005 _sl.
dumper = std::make_unique<MemoryDumper>();
3006 _sl.
sf = std::move(writer);
3010 SaveViewportBeforeSaveGame();
3016 if (threaded)
Debug(sl, 1,
"Cannot create savegame thread, reverting to single-threaded mode...");
3037 return DoSave(std::move(writer), threaded);
3071 Debug(sl, 0,
"Unknown savegame type, trying to load it as the buggy format");
3095 _sl.
lf = std::move(reader);
3105 if (
_sl.
lf->Read((uint8_t*)hdr,
sizeof(hdr)) !=
sizeof(hdr))
SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
3112 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, fmt::format(
"Loader for '{}' is not available.", fmt->
name));
3125 InitializeGame(256, 256,
true,
true);
3197 return DoLoad(std::move(reader),
false);
3228 InitializeGame(256, 256,
true,
true);
3236 if (!LoadOldSaveGame(filename))
return SL_REINIT;
3262 default: NOT_REACHED();
3272 if (!fh.has_value()) {
3273 SlError(fop ==
SLO_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
3280 return DoSave(std::make_shared<FileWriter>(std::move(*fh)), threaded);
3285 Debug(desync, 1,
"load: {}", filename);
3286 return DoLoad(std::make_shared<FileReader>(std::move(*fh)), fop ==
SLO_CHECK);
3306 std::string filename;
3314 Debug(sl, 2,
"Autosaving to '{}'", filename);
3343 std::array<StringParameter, 4> params{};
3344 auto it = params.begin();
3351 *it++ = STR_SAVEGAME_DURATION_REALTIME;
3352 *it++ = play_time / 60 / 60;
3353 *it++ = (play_time / 60) % 60;
3357 case 0: *it++ = STR_JUST_DATE_LONG;
break;
3358 case 1: *it++ = STR_JUST_DATE_TINY;
break;
3359 case 2: *it++ = STR_JUST_DATE_ISO;
break;
3360 default: NOT_REACHED();
3407 this->
name = item.name;
3408 this->
title = item.title;
3413 assert(this->load_description.has_value());
3414 return *this->load_description;
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
debug_inline static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Timpl & Set()
Set all bits.
void PutUtf8(char32_t c)
Append UTF.8 char.
Container for an encoded string, created by GetEncodedString.
void StartAction(GamelogActionType at)
Stores information about new action, but doesn't allocate it Action is allocated only when there is a...
void Reset()
Resets and frees all memory allocated - used before loading or starting a new game.
void StopAction()
Stops logging of any changes.
Class for calculation jobs to be run on link graphs.
A connected component of a link graph.
Handler for saving/loading an object to/from disk.
SaveLoadTable GetLoadDescription() const
Get the description for how to load the chunk.
Handler that is assigned when there is a struct read in the savegame which is not known to the code.
virtual SaveLoadTable GetDescription() const override
Get the description of the fields in the savegame.
virtual SaveLoadCompatTable GetCompatDescription() const override
Get the pre-header description of the fields in the savegame.
void LoadCheck(void *object) const override
Similar to load, but used only to validate savegames.
void Load(void *object) const override
Load the object from disk.
void Save(void *) const override
Save the object to disk.
Template class to help with list-like types.
static void SlSaveLoad(void *storage, VarType conv, SaveLoadType cmd=SL_VAR)
Internal templated helper to save/load a list-like type.
static size_t SlCalcLen(const void *storage, VarType conv, SaveLoadType cmd=SL_VAR)
Internal templated helper to return the size in bytes of a list-like type.
Compose data into a growing std::string.
static constexpr TimerGameTick::Ticks TICKS_PER_SECOND
Estimation of how many ticks fit in a single second.
static Date date
Current date in days (day counter).
static bool UsingWallclockUnits(bool newgame=false)
Check if we are using wallclock units.
static DateFract date_fract
Fractional part of the day.
static TickCounter counter
Monotonic counter, in ticks, since start of game.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
@ SCC_ENCODED
Encoded string marker and sub-string parameter.
@ SCC_ENCODED_NUMERIC
Encoded numeric parameter.
@ SCC_ENCODED_STRING
Encoded string parameter.
#define Debug(category, level, format_string,...)
Output a line of debugging information.
@ WL_ERROR
Errors (eg. saving/loading failed)
@ WL_CRITICAL
Critical errors, the MessageBox is shown in all cases.
void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, CommandCost &cc)
Display an error message in a window.
void SanitizeFilename(std::string &filename)
Sanitizes a filename, i.e.
std::optional< FileHandle > FioFOpenFile(const std::string &filename, const char *mode, Subdirectory subdir, size_t *filesize)
Opens a OpenTTD file somewhere in a personal or global directory.
SaveLoadOperation
Operation performed on the file.
@ SLO_CHECK
Load file for checking and/or preview.
@ SLO_SAVE
File is being saved.
@ SLO_LOAD
File is being loaded.
@ SLO_INVALID
Unknown file operation.
DetailedFileType GetDetailedFileType(FiosType fios_type)
Extract the detailed file type from a FiosType.
AbstractFileType GetAbstractFileType(FiosType fios_type)
Extract the abstract file type from a FiosType.
FiosType
Elements of a file system that are recognized.
DetailedFileType
Kinds of files in each AbstractFileType.
@ DFT_GAME_FILE
Save game or scenario file.
@ DFT_INVALID
Unknown or invalid file.
@ DFT_OLD_GAME_FILE
Old save game or scenario file.
Subdirectory
The different kinds of subdirectories OpenTTD uses.
@ SCENARIO_DIR
Base directory for all scenarios.
@ BASE_DIR
Base directory for all subdirectories.
@ SAVE_DIR
Base directory for all savegames.
@ AUTOSAVE_DIR
Subdirectory of save for autosaves.
AbstractFileType
The different abstract types of files that the system knows about.
@ FT_INVALID
Invalid or unknown file type.
LoadCheckData _load_check_data
Data loaded from save during SL_LOAD_CHECK.
fluid_settings_t * settings
FluidSynth settings handle.
Gamelog _gamelog
Gamelog instance.
void SetMouseCursorBusy(bool busy)
Set or unset the ZZZ cursor.
GameSessionStats _game_session_stats
Statistics about the current session.
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
bool _networking
are we in networking mode?
bool _network_server
network-server is active
GRFConfigList _grfconfig
First item in list of current GRF set up.
GRFListCompatibility IsGoodGRFConfigList(GRFConfigList &grfconfig)
Check if all GRFs in the GRF config from a savegame can be loaded.
void ClearGRFConfigList(GRFConfigList &config)
Clear a GRF Config list, freeing all nodes.
static void SlRefVector(void *vector, VarType conv)
Save/Load a vector.
static const uint LZO_BUFFER_SIZE
Buffer size for the LZO compressor.
void SlError(StringID string, const std::string &extra_msg)
Error handler.
static const ChunkHandler * SlFindChunkHandler(uint32_t id)
Find the ChunkHandler that will be used for processing the found chunk in the savegame or in memory.
static uint8_t GetSavegameFileType(const SaveLoad &sld)
Return the type as saved/loaded inside the savegame.
static SaveOrLoadResult DoSave(std::shared_ptr< SaveFilter > writer, bool threaded)
Actually perform the saving of the savegame.
void ProcessAsyncSaveFinish()
Handle async save finishes.
static const lzma_stream _lzma_init
Have a copy of an initialised LZMA stream.
static void * IntToReference(size_t index, SLRefType rt)
Pointers cannot be loaded from a savegame, so this function gets the index from the savegame and retu...
uint32_t _ttdp_version
version of TTDP savegame (if applicable)
static const SaveLoadFormat _saveload_formats[]
The different saveload formats known/understood by OpenTTD.
std::string _savegame_format
how to compress savegames
static void SaveFileDone()
Update the gui accordingly when saving is done and release locks on saveload.
SaveLoadVersion _sl_version
the major savegame version identifier
static const std::vector< ChunkHandlerRef > & ChunkHandlers()
uint8_t _sl_minor_version
the minor savegame version, DO NOT USE!
static size_t SlCalcRefVectorLen(const void *vector, VarType conv)
Return the size in bytes of a vector.
SaveOrLoadResult LoadWithFilter(std::shared_ptr< LoadFilter > reader)
Load the game using a (reader) filter.
static SaveOrLoadResult SaveFileToDisk(bool threaded)
We have written the whole game into memory, _memory_savegame, now find and appropriate compressor and...
static void ResetSaveloadData()
Clear temporary data that is passed between various saveload phases.
static size_t ReferenceToInt(const void *obj, SLRefType rt)
Pointers cannot be saved to a savegame, so this functions gets the index of the item,...
SaveOrLoadResult SaveWithFilter(std::shared_ptr< SaveFilter > writer, bool threaded)
Save the game using a (writer) filter.
static void SlWriteSimpleGamma(size_t i)
Write the header descriptor of an object or an array.
static size_t SlCalcTableHeader(const SaveLoadTable &slt)
Calculate the size of the table header.
static void ClearSaveLoadState()
Clear/free saveload state.
bool _do_autosave
are we doing an autosave at the moment?
static std::atomic< AsyncSaveFinishProc > _async_save_finish
Callback to call when the savegame loading is finished.
static std::thread _save_thread
The thread we're using to compress and write a savegame.
static uint SlCalcConvMemLen(VarType conv)
Return the size in bytes of a certain type of normal/atomic variable as it appears in memory.
std::vector< SaveLoad > SlCompatTableHeader(const SaveLoadTable &slt, const SaveLoadCompatTable &slct)
Load a table header in a savegame compatible way.
static void ResetSettings()
Reset all settings to their default, so any settings missing in the savegame are their default,...
void SlWriteByte(uint8_t b)
Wrapper for writing a byte to the dumper.
size_t SlGetStructListLength(size_t limit)
Get the length of this list; if it exceeds the limit, error out.
static size_t SlCalcArrayLen(size_t length, VarType conv)
Return the size in bytes of a certain type of atomic array.
void WriteValue(void *ptr, VarType conv, int64_t val)
Write the value of a setting.
void(* AsyncSaveFinishProc)()
Callback for when the savegame loading is finished.
int SlIterateArray()
Iterate through the elements of an array and read the whole thing.
SaveOrLoadResult SaveOrLoad(const std::string &filename, SaveLoadOperation fop, DetailedFileType dft, Subdirectory sb, bool threaded)
Main Save or Load function where the high-level saveload functions are handled.
static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
Called by save thread to tell we finished saving.
void SetSaveLoadError(StringID str)
Set the error message from outside of the actual loading/saving of the game (AfterLoadGame and friend...
void SlCopy(void *object, size_t length, VarType conv)
Copy a list of SL_VARs to/from a savegame.
static std::pair< const SaveLoadFormat &, uint8_t > GetSavegameFormat(const std::string &full_name)
Return the savegameformat of the game.
size_t SlGetFieldLength()
Get the length of the current object.
void DoAutoOrNetsave(FiosNumberedSaveName &counter)
Create an autosave or netsave.
static size_t SlCalcRefLen()
Return the size in bytes of a reference (pointer)
@ NL_WANTLENGTH
writing length and data
@ NL_NONE
not working in NeedLength mode
@ NL_CALCLENGTH
need to calculate the length
static void SaveFileStart()
Update the gui accordingly when starting saving and set locks on saveload.
static void SlNullPointers()
Null all pointers (convert index -> nullptr)
static void SlStdString(void *ptr, VarType conv)
Save/Load a std::string.
static SaveOrLoadResult DoLoad(std::shared_ptr< LoadFilter > reader, bool load_check)
Actually perform the loading of a "non-old" savegame.
static size_t SlCalcRefListLen(const void *list, VarType conv)
Return the size in bytes of a list.
static bool SlIsObjectValidInSavegame(const SaveLoad &sld)
Are we going to save this object or not?
EncodedString GetSaveLoadErrorType()
Return the appropriate initial string for an error depending on whether we are saving or loading.
void SlSaveLoadRef(void *ptr, VarType conv)
Handle conversion for references.
static void SlFixPointers()
Fix all pointers (convert index -> pointer)
void SlErrorCorrupt(const std::string &msg)
Error handler for corrupt savegames.
void SlSkipArray()
Skip an array or sparse array.
static void SlLoadChunk(const ChunkHandler &ch)
Load a chunk of data (eg vehicles, stations, etc.)
static void SlLoadCheckChunks()
Load all chunks for savegame checking.
static size_t SlCalcStdStringLen(const void *ptr)
Calculate the gross length of the string that it will occupy in the savegame.
static uint SlReadSimpleGamma()
Read in the header descriptor of an object or an array.
SaveLoadAction
What are we currently doing?
@ SLA_NULL
null all pointers (on loading error)
@ SLA_LOAD_CHECK
partial loading into _load_check_data
@ SLA_PTRS
fixing pointers
static void SlCopyBytes(void *ptr, size_t length)
Save/Load bytes.
static void SlCopyInternal(void *object, size_t length, VarType conv)
Internal function to save/Load a list of SL_VARs.
static void SlArray(void *array, size_t length, VarType conv)
Save/Load the length of the array followed by the array of SL_VAR elements.
SavegameType _savegame_type
type of savegame we are loading
static void SlSaveLoadConv(void *ptr, VarType conv)
Handle all conversion and typechecking of variables here.
FileToSaveLoad _file_to_saveload
File to save or load in the openttd loop.
static void SlLoadCheckChunk(const ChunkHandler &ch)
Load a chunk of data for checking savegames.
void SlSetLength(size_t length)
Sets the length of either a RIFF object or the number of items in an array.
uint8_t SlReadByte()
Wrapper for reading a byte from the buffer.
static SaveLoadParams _sl
Parameters used for/at saveload.
void DoExitSave()
Do a save when exiting the game (_settings_client.gui.autosave_on_exit)
static void SlLoadChunks()
Load all chunks.
static void SlDeque(void *deque, VarType conv)
Save/load a std::deque.
static uint8_t SlCalcConvFileLen(VarType conv)
Return the size in bytes of a certain type of normal/atomic variable as it appears in a saved game.
static void SlSaveChunk(const ChunkHandler &ch)
Save a chunk of data (eg.
const SaveLoadVersion SAVEGAME_VERSION
Current savegame version of OpenTTD.
size_t SlCalcObjLength(const void *object, const SaveLoadTable &slt)
Calculate the size of an object.
void SlObject(void *object, const SaveLoadTable &slt)
Main SaveLoad function.
EncodedString GetSaveLoadErrorMessage()
Return the description of the error.
std::vector< SaveLoad > SlTableHeader(const SaveLoadTable &slt)
Save or Load a table header.
bool AfterLoadGame()
Perform a (large) amount of savegame conversion magic in order to load older savegames and to fill th...
int64_t ReadValue(const void *ptr, VarType conv)
Return a signed-long version of the value of a setting.
static void SlVector(void *vector, VarType conv)
Save/load a std::vector.
static void SaveFileError()
Show a gui message when saving has failed.
void SlGlobList(const SaveLoadTable &slt)
Save or Load (a list of) global variables.
void FixSCCEncoded(std::string &str, bool fix_code)
Scan the string for old values of SCC_ENCODED and fix it to it's new, value.
static void SlSaveChunks()
Save all chunks.
std::string GenerateDefaultSaveName()
Get the default name for a savegame or screenshot.
static const size_t MEMORY_CHUNK_SIZE
Save in chunks of 128 KiB.
static const SaveLoadFormat * DetermineSaveLoadFormat(uint32_t tag, uint32_t raw_version)
Determines the SaveLoadFormat that is connected to the given tag.
void SlAutolength(AutolengthProc *proc, int arg)
Do something of which I have no idea what it is :P.
void SlReadString(std::string &str, size_t length)
Read the given amount of bytes from the buffer into the string.
void SlSetStructListLength(size_t length)
Set the length of this list.
static uint SlGetGammaLength(size_t i)
Return how many bytes used to encode a gamma value.
static size_t SlCalcVectorLen(const void *vector, VarType conv)
Return the size in bytes of a std::vector.
static void SlRefList(void *list, VarType conv)
Save/Load a list.
static size_t SlCalcDequeLen(const void *deque, VarType conv)
Return the size in bytes of a std::deque.
SavegameType
Types of save games.
SaveOrLoadResult
Save or load result codes.
@ SL_OK
completed successfully
@ SL_REINIT
error that was caught in the middle of updating game state, need to clear it. (can only happen during...
@ SLE_VAR_NULL
useful to write zeros in savegame.
@ SLE_FILE_END
Used to mark end-of-header in tables.
@ SLE_FILE_TYPE_MASK
Mask to get the file-type (and not any flags).
@ SLE_FILE_HAS_LENGTH_FIELD
Bit stored in savegame to indicate field has a length field for each entry.
@ SLF_ALLOW_NEWLINE
Allow new lines in the strings.
@ SLF_ALLOW_CONTROL
Allow control codes in the strings.
@ SLE_VAR_STR
string pointer
@ SLE_VAR_NAME
old custom name to be converted to a char pointer
@ SLE_VAR_STRQ
string pointer enclosed in quotes
@ SLE_FILE_STRINGID
StringID offset into strings-array.
void SlSkipBytes(size_t length)
Read in bytes from the file/data structure but don't do anything with them, discarding them in effect...
constexpr VarType GetVarFileType(VarType type)
Get the FileType of a setting.
SLRefType
Type of reference (SLE_REF, SLE_CONDREF).
@ REF_VEHICLE_OLD
Load/save an old-style reference to a vehicle (for pre-4.4 savegames).
@ REF_LINK_GRAPH_JOB
Load/save a reference to a link graph job.
@ REF_TOWN
Load/save a reference to a town.
@ REF_LINK_GRAPH
Load/save a reference to a link graph.
@ REF_CARGO_PACKET
Load/save a reference to a cargo packet.
@ REF_ENGINE_RENEWS
Load/save a reference to an engine renewal (autoreplace).
@ REF_STATION
Load/save a reference to a station.
@ REF_ORDER
Load/save a reference to an order.
@ REF_ORDERLIST
Load/save a reference to an orderlist.
@ REF_STORAGE
Load/save a reference to a persistent storage.
@ REF_VEHICLE
Load/save a reference to a vehicle.
@ REF_ROADSTOPS
Load/save a reference to a bus/truck stop.
void * GetVariableAddress(const void *object, const SaveLoad &sld)
Get the address of the variable.
std::span< const ChunkHandlerRef > ChunkHandlerTable
A table of ChunkHandler entries.
SaveLoadType
Type of data saved.
@ SL_NULL
Save null-bytes and load to nowhere.
@ SL_STRUCTLIST
Save/load a list of structs.
@ SL_STDSTR
Save/load a std::string.
@ SL_REF
Save/load a reference.
@ SL_SAVEBYTE
Save (but not load) a byte.
@ SL_DEQUE
Save/load a deque of SL_VAR elements.
@ SL_STRUCT
Save/load a struct.
@ SL_VECTOR
Save/load a vector of SL_VAR elements.
@ SL_REFVECTOR
Save/load a vector of SL_REF elements.
@ SL_REFLIST
Save/load a list of SL_REF elements.
@ SL_ARR
Save/load a fixed-size array of SL_VAR elements.
@ SL_VAR
Save/load a variable.
std::span< const struct SaveLoadCompat > SaveLoadCompatTable
A table of SaveLoadCompat entries.
bool IsSavegameVersionBefore(SaveLoadVersion major, uint8_t minor=0)
Checks whether the savegame is below major.
constexpr VarType GetVarMemType(VarType type)
Get the NumberType of a setting.
SaveLoadVersion
SaveLoad versions Previous savegame versions, the trunk revision where they were introduced and the r...
@ 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_SAVELOAD_LIST_LENGTH
293 PR#9374 Consistency in list length with SL_STRUCT / SL_STRUCTLIST / SL_DEQUE / SL_REFLIST.
@ SLV_START_PATCHPACKS
220 First known patchpack to use a version just above ours.
@ SL_MAX_VERSION
Highest possible saveload version.
@ SL_MIN_VERSION
First savegame version.
@ SLV_END_PATCHPACKS
286 Last known patchpack to use a version just above ours.
@ SLV_ENCODED_STRING_FORMAT
350 PR#13499 Encoded String format changed.
@ SLV_5
5.0 1429 5.1 1440 5.2 1525 0.3.6
std::vector< SaveLoad > SlTableHeader(const SaveLoadTable &slt)
Save or Load a table header.
std::span< const struct SaveLoad > SaveLoadTable
A table of SaveLoad entries.
@ CH_TYPE_MASK
All ChunkType values have to be within this mask.
@ CH_READONLY
Chunk is never saved.
Declaration of filters used for saving and loading savegames.
Declaration of functions used in more save/load files.
StringID RemapOldStringID(StringID s)
Remap a string ID from the old format to the new format.
std::string CopyFromOldName(StringID id)
Copy and convert old custom names to UTF-8.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
SettingTable GetSaveLoadSettingTable()
Create a single table with all settings that should be stored/loaded in the savegame.
ClientSettings _settings_client
The current settings for this game.
@ NotInSave
Do not save with savegame, basically client-based.
@ NoNetworkSync
Do not synchronize over network (but it is saved if SettingFlag::NotInSave is not set).
static constexpr const SettingDesc * GetSettingDesc(const SettingVariant &desc)
Helper to convert the type of the iterated settings description to a pointer to it.
@ SBI_SAVELOAD_FINISH
finished saving
@ SBI_SAVELOAD_START
started saving
#define lengthof(array)
Return the length of an fixed size array.
void StrMakeValidInPlace(char *str, StringValidationSettings settings)
Scans the string for invalid characters and replaces them with a question mark '?' (if not ignored).
size_t Utf8Decode(char32_t *c, const char *s)
Decode and consume the next UTF-8 encoded character.
int8_t Utf8EncodedCharLen(char c)
Return the length of an UTF-8 encoded value based on a single char.
@ ReplaceWithQuestionMark
Replace the unknown/bad bits with question marks.
@ AllowControlCode
Allow the special control codes.
@ AllowNewline
Allow newlines; replaces '\r ' with ' ' during processing.
void GetStringWithArgs(StringBuilder &builder, StringID string, StringParameters &args, uint case_index, bool game_script)
Get a parsed string with most special stringcodes replaced by the string parameters.
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Container for cargo from the same location and time.
Handlers and description of chunk.
ChunkType type
Type of the chunk.
virtual void LoadCheck(size_t len=0) const
Load the chunk for game preview.
virtual void Load() const =0
Load the chunk.
uint32_t id
Unique ID (4 letters).
virtual void Save() const
Save the chunk.
GUISettings gui
settings related to the GUI
Struct to store engine replacements.
Yes, simply reading from a file.
~FileReader()
Make sure everything is cleaned up.
size_t Read(uint8_t *buf, size_t size) override
Read a given number of bytes from the savegame.
void Reset() override
Reset this filter to read from the beginning of the file.
FileReader(FileHandle &&file)
Create the file reader, so it reads from a specific file.
long begin
The begin of the file.
std::optional< FileHandle > file
The file to read from.
Deals with the type of the savegame, independent of extension.
AbstractFileType abstract_ftype
Abstract type of file (scenario, heightmap, etc).
void SetMode(FiosType ft)
Set the mode and file type of the file to save or load based on the type of file entry at the file sy...
DetailedFileType detail_ftype
Concrete file type (PNG, BMP, old save, etc).
std::string title
Internal name of the game.
SaveLoadOperation file_op
File operation to perform.
std::string name
Name of the file.
void Set(const FiosItem &item)
Set the title of the file.
Yes, simply writing to a file.
std::optional< FileHandle > file
The file to write to.
FileWriter(FileHandle &&file)
Create the file writer, so it writes to a specific file.
void Finish() override
Prepare everything to finish writing the savegame.
~FileWriter()
Make sure everything is cleaned up.
void Write(uint8_t *buf, size_t size) override
Write a given number of bytes into the savegame.
Deals with finding savegames.
A savegame name automatically numbered.
std::string Filename()
Generate a savegame name and number according to _settings_client.gui.max_num_autosaves.
std::string Extension()
Generate an extension for a savegame name.
bool keep_all_autosave
name the autosave in a different way
uint8_t date_format_in_default_names
should the default savegame/screenshot name use long dates (31th Dec 2008), short dates (31-12-2008) ...
bool threaded_saves
should we do threaded saves?
std::optional< size_t > savegame_size
Size of the last saved savegame in bytes, or std::nullopt if not saved yet.
Filter without any compression.
~LZMALoadFilter()
Clean everything up.
lzma_stream lzma
Stream state that we are reading from.
size_t Read(uint8_t *buf, size_t size) override
Read a given number of bytes from the savegame.
uint8_t fread_buf[MEMORY_CHUNK_SIZE]
Buffer for reading from the file.
LZMALoadFilter(std::shared_ptr< LoadFilter > chain)
Initialise this filter.
Filter using LZMA compression.
void Write(uint8_t *buf, size_t size) override
Write a given number of bytes into the savegame.
void Finish() override
Prepare everything to finish writing the savegame.
void WriteLoop(uint8_t *p, size_t len, lzma_action action)
Helper loop for writing the data.
LZMASaveFilter(std::shared_ptr< SaveFilter > chain, uint8_t compression_level)
Initialise this filter.
lzma_stream lzma
Stream state that we are writing to.
uint8_t fwrite_buf[MEMORY_CHUNK_SIZE]
Buffer for writing to the file.
~LZMASaveFilter()
Clean up what we allocated.
Filter using LZO compression.
LZOLoadFilter(std::shared_ptr< LoadFilter > chain)
Initialise this filter.
size_t Read(uint8_t *buf, size_t ssize) override
Read a given number of bytes from the savegame.
Filter using LZO compression.
void Write(uint8_t *buf, size_t size) override
Write a given number of bytes into the savegame.
LZOSaveFilter(std::shared_ptr< SaveFilter > chain, uint8_t)
Initialise this filter.
bool checkable
True if the savegame could be checked by SL_LOAD_CHECK. (Old savegames are not checkable....
std::string error_msg
Data to pass to string parameters when displaying error.
StringID error
Error message from loading. INVALID_STRING_ID if no error.
void Clear()
Reset read data.
GRFListCompatibility grf_compatibility
Summary state of NewGrfs, whether missing files or only compatible found.
GRFConfigList grfconfig
NewGrf configuration from save.
Interface for filtering a savegame till it is loaded.
std::shared_ptr< LoadFilter > chain
Chained to the (savegame) filters.
Container for dumping the savegame (quickly) to memory.
uint8_t * buf
Buffer we're going to write to.
void WriteByte(uint8_t b)
Write a single byte into the dumper.
std::vector< std::unique_ptr< uint8_t[]> > blocks
Buffer with blocks of allocated memory.
uint8_t * bufe
End of the buffer we write to.
size_t GetSize() const
Get the size of the memory dump made so far.
void Flush(std::shared_ptr< SaveFilter > writer)
Flush this dumper into a writer.
Filter without any compression.
NoCompLoadFilter(std::shared_ptr< LoadFilter > chain)
Initialise this filter.
size_t Read(uint8_t *buf, size_t size) override
Read a given number of bytes from the savegame.
Filter without any compression.
NoCompSaveFilter(std::shared_ptr< SaveFilter > chain, uint8_t)
Initialise this filter.
void Write(uint8_t *buf, size_t size) override
Write a given number of bytes into the savegame.
Shared order list linking together the linked list of orders and the list of vehicles sharing this or...
Class for pooled persistent storage of data.
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static Titem * Get(auto index)
Returns Titem with given index.
static bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
A buffer for reading (and buffering) savegame data.
uint8_t * bufp
Location we're at reading the buffer.
ReadBuffer(std::shared_ptr< LoadFilter > reader)
Initialise our variables.
size_t read
The amount of read bytes so far from the filter.
size_t GetSize() const
Get the size of the memory dump made so far.
std::shared_ptr< LoadFilter > reader
The filter used to actually read.
uint8_t buf[MEMORY_CHUNK_SIZE]
Buffer we're going to read from.
uint8_t * bufe
End of the buffer we can read from.
A Stop for a Road Vehicle.
Interface for filtering a savegame till it is written.
std::shared_ptr< SaveFilter > chain
Chained to the (savegame) filters.
The saveload struct, containing reader-writer functions, buffer, version, etc.
std::unique_ptr< ReadBuffer > reader
Savegame reading buffer.
std::shared_ptr< SaveFilter > sf
Filter to write the savegame to.
std::unique_ptr< MemoryDumper > dumper
Memory dumper to write the savegame to.
StringID error_str
the translatable error message to show
SaveLoadAction action
are we doing a save or a load atm.
std::string extra_msg
the error message
NeedLength need_length
working in NeedLength (Autolength) mode?
bool saveinprogress
Whether there is currently a save in progress.
std::shared_ptr< LoadFilter > lf
Filter to read the savegame from.
bool expect_table_header
In the case of a table, if the header is saved/loaded.
size_t obj_len
the length of the current object we are busy with
bool error
did an error occur or not
int last_array_index
in the case of an array, the current and last positions
uint16_t length
(Conditional) length of the variable (eg. arrays) (max array size is 65536 elements).
std::shared_ptr< SaveLoadHandler > handler
Custom handler for Save/Load procs.
SaveLoadVersion version_to
Save/load the variable before this savegame version.
SaveLoadType cmd
The action to take with the saved/loaded type, All types need different action.
std::string name
Name of this field (optional, used for tables).
VarType conv
Type of the variable to be saved; this field combines both FileVarType and MemVarType.
SaveLoadVersion version_from
Save/load the variable starting from this savegame version.
Properties of config file settings.
SettingFlags flags
Handles how a setting would show up in the GUI (text/currency, etc.).
virtual void ResetToDefault(void *object) const =0
Reset the setting to its default value.
static bool IsValidID(auto index)
Tests whether given index is a valid index for station of this type.
static Station * Get(auto index)
Gets station with given index.
Filter using Zlib compression.
size_t Read(uint8_t *buf, size_t size) override
Read a given number of bytes from the savegame.
ZlibLoadFilter(std::shared_ptr< LoadFilter > chain)
Initialise this filter.
uint8_t fread_buf[MEMORY_CHUNK_SIZE]
Buffer for reading from the file.
~ZlibLoadFilter()
Clean everything up.
z_stream z
Stream state we are reading from.
Filter using Zlib compression.
void WriteLoop(uint8_t *p, size_t len, int mode)
Helper loop for writing the data.
z_stream z
Stream state we are writing to.
uint8_t fwrite_buf[MEMORY_CHUNK_SIZE]
Buffer for writing to the file.
void Finish() override
Prepare everything to finish writing the savegame.
~ZlibSaveFilter()
Clean up what we allocated.
ZlibSaveFilter(std::shared_ptr< SaveFilter > chain, uint8_t compression_level)
Initialise this filter.
void Write(uint8_t *buf, size_t size) override
Write a given number of bytes into the savegame.
void CSleep(int milliseconds)
Sleep on the current thread for a defined time.
bool StartNewThread(std::thread *thr, const char *name, TFn &&_Fx, TArgs &&... _Ax)
Start a new thread.
void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope)
Mark window data of the window of a given class and specific window number as invalid (in need of re-...
@ WC_STATUS_BAR
Statusbar (at the bottom of your screen); Window numbers: