56# include <emscripten.h>
67#if defined(WITH_LIBLZMA)
71#include "table/strings.h"
122 if (this->bufp == this->bufe) {
123 size_t len = this->reader->Read(this->buf,
lengthof(this->buf));
127 this->bufp = this->buf;
128 this->bufe = this->buf + len;
131 return *this->
bufp++;
140 return this->read - (this->bufe - this->bufp);
147 std::vector<std::unique_ptr<uint8_t[]>>
blocks{};
158 if (this->buf == this->bufe) {
159 this->buf = this->blocks.emplace_back(std::make_unique<uint8_t[]>(
MEMORY_CHUNK_SIZE)).get();
170 void Flush(std::shared_ptr<SaveFilter> writer)
178 writer->Write(this->blocks[i++].get(), to_write);
207 std::shared_ptr<SaveFilter>
sf;
210 std::shared_ptr<LoadFilter>
lf;
262 _gamelog_chunk_handlers,
264 _misc_chunk_handlers,
265 _name_chunk_handlers,
266 _cheat_chunk_handlers,
267 _setting_chunk_handlers,
269 _waypoint_chunk_handlers,
270 _depot_chunk_handlers,
271 _order_chunk_handlers,
272 _industry_chunk_handlers,
273 _economy_chunk_handlers,
274 _subsidy_chunk_handlers,
275 _cargomonitor_chunk_handlers,
276 _goal_chunk_handlers,
277 _story_page_chunk_handlers,
278 _league_chunk_handlers,
279 _engine_chunk_handlers,
280 _town_chunk_handlers,
281 _sign_chunk_handlers,
282 _station_chunk_handlers,
283 _company_chunk_handlers,
285 _game_chunk_handlers,
286 _animated_tile_chunk_handlers,
287 _newgrf_chunk_handlers,
288 _group_chunk_handlers,
289 _cargopacket_chunk_handlers,
290 _autoreplace_chunk_handlers,
291 _labelmaps_chunk_handlers,
292 _linkgraph_chunk_handlers,
293 _airport_chunk_handlers,
294 _object_chunk_handlers,
295 _persistent_storage_chunk_handlers,
296 _water_region_chunk_handlers,
297 _randomizer_chunk_handlers,
300 static std::vector<ChunkHandlerRef> _chunk_handlers;
302 if (_chunk_handlers.empty()) {
303 for (
auto &chunk_handler_table : _chunk_handler_tables) {
304 for (
auto &chunk_handler : chunk_handler_table) {
305 _chunk_handlers.push_back(chunk_handler);
310 return _chunk_handlers;
324 Debug(sl, 3,
"Nulling pointers for {}", ch.GetName());
346 _sl.error_str = string;
347 _sl.extra_msg = extra_msg;
359 throw std::exception();
371 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, msg);
385 if (_exit_game)
return;
397 if (proc ==
nullptr)
return;
412 return _sl.reader->ReadByte();
421 _sl.dumper->WriteByte(b);
424static inline int SlReadUint16()
430static inline uint32_t SlReadUint32()
432 uint32_t x = SlReadUint16() << 16;
433 return x | SlReadUint16();
436static inline uint64_t SlReadUint64()
438 uint32_t x = SlReadUint32();
439 uint32_t y = SlReadUint32();
440 return (uint64_t)x << 32 | y;
443static inline void SlWriteUint16(uint16_t v)
449static inline void SlWriteUint32(uint32_t v)
451 SlWriteUint16(
GB(v, 16, 16));
452 SlWriteUint16(
GB(v, 0, 16));
455static inline void SlWriteUint64(uint64_t x)
457 SlWriteUint32((uint32_t)(x >> 32));
458 SlWriteUint32((uint32_t)x);
515 if (i >= (1 << 14)) {
516 if (i >= (1 << 21)) {
517 if (i >= (1 << 28)) {
518 assert(i <= UINT32_MAX);
543 return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21)) + (i >= (1 << 28));
546static inline uint SlReadSparseIndex()
551static inline void SlWriteSparseIndex(uint index)
556static inline uint SlReadArrayLength()
561static inline void SlWriteArrayLength(
size_t length)
566static inline uint SlGetArrayLength(
size_t length)
602 default: NOT_REACHED();
615 case SLE_VAR_BL:
return sizeof(bool);
616 case SLE_VAR_I8:
return sizeof(int8_t);
617 case SLE_VAR_U8:
return sizeof(uint8_t);
618 case SLE_VAR_I16:
return sizeof(int16_t);
619 case SLE_VAR_U16:
return sizeof(uint16_t);
620 case SLE_VAR_I32:
return sizeof(int32_t);
621 case SLE_VAR_U32:
return sizeof(uint32_t);
622 case SLE_VAR_I64:
return sizeof(int64_t);
623 case SLE_VAR_U64:
return sizeof(uint64_t);
628 return SlReadArrayLength();
646 case SLE_FILE_I8:
return sizeof(int8_t);
647 case SLE_FILE_U8:
return sizeof(uint8_t);
648 case SLE_FILE_I16:
return sizeof(int16_t);
649 case SLE_FILE_U16:
return sizeof(uint16_t);
650 case SLE_FILE_I32:
return sizeof(int32_t);
651 case SLE_FILE_U32:
return sizeof(uint32_t);
652 case SLE_FILE_I64:
return sizeof(int64_t);
653 case SLE_FILE_U64:
return sizeof(uint64_t);
656 case SLE_FILE_STRING:
657 return SlReadArrayLength();
659 case SLE_FILE_STRUCT:
674void SlSetArrayIndex(uint index)
677 _sl.array_index = index;
680static size_t _next_offs;
690 if (_next_offs != 0 &&
_sl.reader->GetSize() != _next_offs) {
691 SlErrorCorruptFmt(
"Invalid chunk size iterating array - expected to be at position {}, actually at {}", _next_offs,
_sl.reader->GetSize());
695 uint length = SlReadArrayLength();
697 assert(!
_sl.expect_table_header);
702 _sl.obj_len = --length;
703 _next_offs =
_sl.reader->GetSize() + length;
705 if (
_sl.expect_table_header) {
706 _sl.expect_table_header =
false;
711 switch (
_sl.block_mode) {
712 case CH_SPARSE_TABLE:
713 case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex();
break;
715 case CH_ARRAY: index =
_sl.array_index++;
break;
717 Debug(sl, 0,
"SlIterateArray error");
721 if (length != 0)
return index;
744 switch (
_sl.need_length) {
747 if ((
_sl.block_mode == CH_TABLE ||
_sl.block_mode == CH_SPARSE_TABLE) &&
_sl.expect_table_header) {
748 _sl.expect_table_header =
false;
749 SlWriteArrayLength(length + 1);
753 switch (
_sl.block_mode) {
758 assert(length < (1 << 28));
759 SlWriteUint32((uint32_t)((length & 0xFFFFFF) | ((length >> 24) << 28)));
763 assert(
_sl.last_array_index <=
_sl.array_index);
764 while (++
_sl.last_array_index <=
_sl.array_index) {
765 SlWriteArrayLength(1);
767 SlWriteArrayLength(length + 1);
769 case CH_SPARSE_TABLE:
770 case CH_SPARSE_ARRAY:
771 SlWriteArrayLength(length + 1 + SlGetArrayLength(
_sl.array_index));
772 SlWriteSparseIndex(
_sl.array_index);
774 default: NOT_REACHED();
779 _sl.obj_len += (int)length;
782 default: NOT_REACHED();
794 uint8_t *p = (uint8_t *)ptr;
796 switch (
_sl.action) {
799 for (; length != 0; length--) *p++ =
SlReadByte();
804 default: NOT_REACHED();
827 case SLE_VAR_BL:
return (*(
const bool *)ptr != 0);
828 case SLE_VAR_I8:
return *(
const int8_t *)ptr;
829 case SLE_VAR_U8:
return *(
const uint8_t *)ptr;
830 case SLE_VAR_I16:
return *(
const int16_t *)ptr;
831 case SLE_VAR_U16:
return *(
const uint16_t*)ptr;
832 case SLE_VAR_I32:
return *(
const int32_t *)ptr;
833 case SLE_VAR_U32:
return *(
const uint32_t*)ptr;
834 case SLE_VAR_I64:
return *(
const int64_t *)ptr;
835 case SLE_VAR_U64:
return *(
const uint64_t*)ptr;
837 default: NOT_REACHED();
851 case SLE_VAR_BL: *(
bool *)ptr = (val != 0);
break;
852 case SLE_VAR_I8: *(int8_t *)ptr = val;
break;
853 case SLE_VAR_U8: *(uint8_t *)ptr = val;
break;
854 case SLE_VAR_I16: *(int16_t *)ptr = val;
break;
855 case SLE_VAR_U16: *(uint16_t*)ptr = val;
break;
856 case SLE_VAR_I32: *(int32_t *)ptr = val;
break;
857 case SLE_VAR_U32: *(uint32_t*)ptr = val;
break;
858 case SLE_VAR_I64: *(int64_t *)ptr = val;
break;
859 case SLE_VAR_U64: *(uint64_t*)ptr = val;
break;
862 default: NOT_REACHED();
876 switch (
_sl.action) {
882 case SLE_FILE_I8: assert(x >= -128 && x <= 127);
SlWriteByte(x);
break;
883 case SLE_FILE_U8: assert(x >= 0 && x <= 255);
SlWriteByte(x);
break;
884 case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);
break;
886 case SLE_FILE_U16:assert(x >= 0 && x <= 65535); SlWriteUint16(x);
break;
888 case SLE_FILE_U32: SlWriteUint32((uint32_t)x);
break;
890 case SLE_FILE_U64: SlWriteUint64(x);
break;
891 default: NOT_REACHED();
900 case SLE_FILE_I8: x = (int8_t )
SlReadByte();
break;
901 case SLE_FILE_U8: x = (uint8_t )
SlReadByte();
break;
902 case SLE_FILE_I16: x = (int16_t )SlReadUint16();
break;
903 case SLE_FILE_U16: x = (uint16_t)SlReadUint16();
break;
904 case SLE_FILE_I32: x = (int32_t )SlReadUint32();
break;
905 case SLE_FILE_U32: x = (uint32_t)SlReadUint32();
break;
906 case SLE_FILE_I64: x = (int64_t )SlReadUint64();
break;
907 case SLE_FILE_U64: x = (uint64_t)SlReadUint64();
break;
909 default: NOT_REACHED();
918 default: NOT_REACHED();
931 const std::string *str =
reinterpret_cast<const std::string *
>(ptr);
933 size_t len = str->length();
934 return len + SlGetArrayLength(len);
948 if (str.empty())
return;
960 bool is_encoded =
false;
961 bool in_string =
false;
962 bool need_type =
true;
967 if (
auto r = consumer.
TryReadUtf8(); r.has_value()) {
972 if (c ==
SCC_ENCODED || (fix_code && (c == 0xE028 || c == 0xE02A))) {
980 if (!is_encoded)
return;
983 in_string = !in_string;
984 if (in_string && need_type) {
992 if (!in_string && c ==
':') {
993 builder.
PutUtf8(SCC_RECORD_SEPARATOR);
1006 str = std::move(result);
1015 if (str.empty())
return;
1043 str = std::move(result);
1065 std::string *str =
reinterpret_cast<std::string *
>(ptr);
1067 switch (
_sl.action) {
1069 size_t len = str->length();
1070 SlWriteArrayLength(len);
1071 SlCopyBytes(
const_cast<void *
>(
static_cast<const void *
>(str->data())), len);
1077 size_t len = SlReadArrayLength();
1102 default: NOT_REACHED();
1126 if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
1127 conv == SLE_INT32 || conv == SLE_UINT32) {
1132 if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
1133 for (uint i = 0; i < length; i++) {
1134 ((int64_t*)
object)[i] = (int32_t)
std::byteswap(SlReadUint32());
1142 if (conv == SLE_INT8 || conv == SLE_UINT8) {
1145 uint8_t *a = (uint8_t*)
object;
1148 for (; length != 0; length --) {
1163void SlCopy(
void *
object,
size_t length, VarType conv)
1194static void SlArray(
void *array,
size_t length, VarType conv)
1196 switch (
_sl.action) {
1198 SlWriteArrayLength(length);
1205 size_t sv_length = SlReadArrayLength();
1209 }
else if (sv_length != length) {
1244 if (obj ==
nullptr)
return 0;
1258 default: NOT_REACHED();
1274 static_assert(
sizeof(size_t) <=
sizeof(
void *));
1333 default: NOT_REACHED();
1344 switch (
_sl.action) {
1356 *(
void **)ptr =
nullptr;
1358 default: NOT_REACHED();
1365template <
template <
typename,
typename>
typename Tstorage,
typename Tvar,
typename Tallocator = std::allocator<Tvar>>
1367 typedef Tstorage<Tvar, Tallocator> SlStorageT;
1380 const SlStorageT *list =
static_cast<const SlStorageT *
>(storage);
1382 int type_size = SlGetArrayLength(list->size());
1384 return list->size() * item_size + type_size;
1387 static void SlSaveLoadMember(
SaveLoadType cmd, Tvar *item, VarType conv)
1408 SlStorageT *list =
static_cast<SlStorageT *
>(storage);
1410 switch (
_sl.action) {
1412 SlWriteArrayLength(list->size());
1414 for (
auto &item : *list) {
1415 SlSaveLoadMember(cmd, &item, conv);
1425 case SL_STDSTR: length = SlReadArrayLength();
break;
1426 default: NOT_REACHED();
1430 if constexpr (std::is_same_v<SlStorageT, std::vector<Tvar, Tallocator>>) {
1431 list->reserve(length);
1435 for (
size_t i = 0; i < length; i++) {
1436 Tvar &data = list->emplace_back();
1437 SlSaveLoadMember(cmd, &data, conv);
1443 for (
auto &item : *list) {
1444 SlSaveLoadMember(cmd, &item, conv);
1452 default: NOT_REACHED();
1537 default: NOT_REACHED();
1568 default: NOT_REACHED();
1581 case SLE_VAR_BL: NOT_REACHED();
1596 default: NOT_REACHED();
1608 case SLE_VAR_BL: NOT_REACHED();
1627 default: NOT_REACHED();
1650 for (
auto &sld : slt) {
1659 for (
auto &sld : slt) {
1680 for (
auto &sld : slt) {
1681 length += SlCalcObjMemberLength(
object, sld);
1686size_t SlCalcObjMemberLength(
const void *
object,
const SaveLoad &sld)
1707 size_t old_obj_len =
_sl.obj_len;
1715 sld.
handler->Save(
const_cast<void *
>(
object));
1716 size_t length =
_sl.obj_len;
1718 _sl.obj_len = old_obj_len;
1719 _sl.need_length = old_need_length;
1722 length += SlGetArrayLength(1);
1728 default: NOT_REACHED();
1733static bool SlObjectMember(
void *
object,
const SaveLoad &sld)
1737 VarType conv =
GB(sld.
conv, 0, 8);
1758 default: NOT_REACHED();
1769 switch (
_sl.action) {
1775 default: NOT_REACHED();
1783 switch (
_sl.action) {
1789 default: NOT_REACHED();
1796 switch (
_sl.action) {
1810 sld.
handler->LoadCheck(
object);
1823 sld.
handler->FixPointers(
object);
1827 default: NOT_REACHED();
1831 default: NOT_REACHED();
1848 SlWriteArrayLength(length);
1858 size_t length = SlReadArrayLength();
1877 for (
auto &sld : slt) {
1878 SlObjectMember(
object, sld);
1892 void Load(
void *
object)
const override
1895 for (; length > 0; length--) {
1925 assert(
_sl.block_mode == CH_TABLE ||
_sl.block_mode == CH_SPARSE_TABLE);
1927 switch (
_sl.action) {
1930 std::vector<SaveLoad> saveloads;
1933 std::map<std::string, const SaveLoad *> key_lookup;
1934 for (
auto &sld : slt) {
1938 assert(key_lookup.find(sld.
name) == key_lookup.end());
1939 key_lookup[sld.
name] = &sld;
1950 auto sld_it = key_lookup.find(key);
1951 if (sld_it == key_lookup.end()) {
1953 Debug(sl,
_sl.action ==
SLA_LOAD ? 2 : 6,
"Field '{}' of type 0x{:02x} not found, skipping", key, type);
1955 std::shared_ptr<SaveLoadHandler> handler =
nullptr;
1958 case SLE_FILE_STRING:
1963 case SLE_FILE_STRUCT:
1966 handler = std::make_shared<SlSkipHandler>();
1985 if (correct_type != type) {
1986 Debug(sl, 1,
"Field type for '{}' was expected to be 0x{:02x} but 0x{:02x} was found", key, correct_type, type);
1989 saveloads.emplace_back(*sld_it->second);
1992 for (
auto &sld : saveloads) {
2008 for (
auto &sld : slt) {
2011 assert(!sld.
name.empty());
2025 for (
auto &sld : slt) {
2034 _sl.need_length = old_need_length;
2041 default: NOT_REACHED();
2044 return std::vector<SaveLoad>();
2064 if (
_sl.block_mode == CH_TABLE ||
_sl.block_mode == CH_SPARSE_TABLE)
return SlTableHeader(slt);
2066 std::vector<SaveLoad> saveloads;
2069 std::map<std::string, std::vector<const SaveLoad *>> key_lookup;
2070 for (
auto &sld : slt) {
2072 assert(!sld.
name.empty());
2074 key_lookup[sld.
name].push_back(&sld);
2077 for (
auto &slc : slct) {
2078 if (slc.name.empty()) {
2084 auto sld_it = key_lookup.find(slc.name);
2088 if (sld_it == key_lookup.end()) {
2091 Debug(sl, 0,
"internal error: saveload compatibility field '{}' not found", slc.name);
2094 for (
auto &sld : sld_it->second) {
2095 saveloads.push_back(*sld);
2100 for (
auto &sld : saveloads) {
2137 size_t start_pos =
_sl.dumper->GetSize();
2138 size_t expected_offs = start_pos +
_sl.obj_len;
2143 if (expected_offs !=
_sl.dumper->GetSize()) {
2144 SlErrorCorruptFmt(
"Invalid chunk size when writing autolength block, expected {}, got {}",
_sl.obj_len,
_sl.dumper->GetSize() - start_pos);
2150 switch (
_sl.block_mode) {
2152 case CH_SPARSE_TABLE:
2156 case CH_SPARSE_ARRAY:
2177 _sl.expect_table_header = (
_sl.block_mode == CH_TABLE ||
_sl.block_mode == CH_SPARSE_TABLE);
2181 if (
_sl.expect_table_header) {
2185 switch (
_sl.block_mode) {
2188 _sl.array_index = 0;
2192 case CH_SPARSE_TABLE:
2193 case CH_SPARSE_ARRAY:
2199 size_t len = (
SlReadByte() << 16) | ((m >> 4) << 24);
2200 len += SlReadUint16();
2202 size_t start_pos =
_sl.reader->GetSize();
2203 size_t endoffs = start_pos + len;
2206 if (
_sl.reader->GetSize() != endoffs) {
2207 SlErrorCorruptFmt(
"Invalid chunk size in RIFF in {} - expected {}, got {}", ch.GetName(), len,
_sl.reader->GetSize() - start_pos);
2230 _sl.expect_table_header = (
_sl.block_mode == CH_TABLE ||
_sl.block_mode == CH_SPARSE_TABLE);
2234 if (
_sl.expect_table_header) {
2238 switch (
_sl.block_mode) {
2241 _sl.array_index = 0;
2244 case CH_SPARSE_TABLE:
2245 case CH_SPARSE_ARRAY:
2250 size_t len = (
SlReadByte() << 16) | ((m >> 4) << 24);
2251 len += SlReadUint16();
2253 size_t start_pos =
_sl.reader->GetSize();
2254 size_t endoffs = start_pos + len;
2257 if (
_sl.reader->GetSize() != endoffs) {
2258 SlErrorCorruptFmt(
"Invalid chunk size in RIFF in {} - expected {}, got {}", ch.GetName(), len,
_sl.reader->GetSize() - start_pos);
2279 SlWriteUint32(ch.
id);
2280 Debug(sl, 2,
"Saving chunk {}", ch.GetName());
2283 _sl.expect_table_header = (
_sl.block_mode == CH_TABLE ||
_sl.block_mode == CH_SPARSE_TABLE);
2287 switch (
_sl.block_mode) {
2293 _sl.last_array_index = 0;
2296 SlWriteArrayLength(0);
2298 case CH_SPARSE_TABLE:
2299 case CH_SPARSE_ARRAY:
2302 SlWriteArrayLength(0);
2304 default: NOT_REACHED();
2339 for (
id = SlReadUint32();
id != 0;
id = SlReadUint32()) {
2340 Debug(sl, 2,
"Loading chunk {:c}{:c}{:c}{:c}",
id >> 24,
id >> 16,
id >> 8,
id);
2354 for (
id = SlReadUint32();
id != 0;
id = SlReadUint32()) {
2355 Debug(sl, 2,
"Loading chunk {:c}{:c}{:c}{:c}",
id >> 24,
id >> 16,
id >> 8,
id);
2369 Debug(sl, 3,
"Fixing pointers for {}", ch.GetName());
2393 if (this->file.has_value()) {
2398 size_t Read(uint8_t *buf,
size_t size)
override
2401 if (!this->file.has_value())
return 0;
2403 return fread(buf, 1, size, *this->file);
2408 clearerr(*this->file);
2409 if (fseek(*this->file, this->begin, SEEK_SET)) {
2410 Debug(sl, 1,
"Could not reset the file reading");
2433 void Write(uint8_t *buf,
size_t size)
override
2436 if (!this->file.has_value())
return;
2438 if (fwrite(buf, 1, size, *this->file) != size)
SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
2443 if (this->file.has_value()) {
2467 if (lzo_init() != LZO_E_OK)
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR,
"cannot initialize decompressor");
2470 size_t Read(uint8_t *buf,
size_t ssize)
override
2478 lzo_uint len = ssize;
2481 if (this->
chain->Read((uint8_t*)tmp,
sizeof(tmp)) !=
sizeof(tmp))
SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE,
"File read failed");
2484 ((uint32_t*)out)[0] = size = tmp[1];
2487 tmp[0] = TO_BE32(tmp[0]);
2488 size = TO_BE32(size);
2494 if (this->
chain->Read(out +
sizeof(uint32_t), size) != size)
SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
2497 if (tmp[0] != lzo_adler32(0, out, size +
sizeof(uint32_t)))
SlErrorCorrupt(
"Bad checksum");
2500 int ret = lzo1x_decompress_safe(out +
sizeof(uint32_t) * 1, size, buf, &len,
nullptr);
2501 if (ret != LZO_E_OK)
SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
2514 if (lzo_init() != LZO_E_OK)
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR,
"cannot initialize compressor");
2517 void Write(uint8_t *buf,
size_t size)
override
2519 const lzo_bytep in = buf;
2522 uint8_t wrkmem[LZO1X_1_MEM_COMPRESS];
2528 lzo1x_1_compress(in, len, out +
sizeof(uint32_t) * 2, &outlen, wrkmem);
2529 ((uint32_t*)out)[1] = TO_BE32((uint32_t)outlen);
2530 ((uint32_t*)out)[0] = TO_BE32(lzo_adler32(0, out +
sizeof(uint32_t), outlen +
sizeof(uint32_t)));
2531 this->
chain->Write(out, outlen +
sizeof(uint32_t) * 2);
2556 size_t Read(uint8_t *buf,
size_t size)
override
2558 return this->
chain->Read(buf, size);
2572 void Write(uint8_t *buf,
size_t size)
override
2574 this->
chain->Write(buf, size);
2582#if defined(WITH_ZLIB)
2595 if (inflateInit(&this->z) != Z_OK)
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR,
"cannot initialize decompressor");
2601 inflateEnd(&this->z);
2604 size_t Read(uint8_t *buf,
size_t size)
override
2606 this->z.next_out = buf;
2607 this->z.avail_out = (uint)size;
2611 if (this->z.avail_in == 0) {
2612 this->z.next_in = this->fread_buf;
2613 this->z.avail_in = (uint)this->
chain->Read(this->fread_buf,
sizeof(this->fread_buf));
2617 int r = inflate(&this->z, 0);
2618 if (r == Z_STREAM_END)
break;
2620 if (r != Z_OK)
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR,
"inflate() failed");
2621 }
while (this->z.avail_out != 0);
2623 return size - this->z.avail_out;
2639 if (deflateInit(&this->z, compression_level) != Z_OK)
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR,
"cannot initialize compressor");
2645 deflateEnd(&this->z);
2657 this->z.next_in = p;
2658 this->z.avail_in = (uInt)len;
2660 this->z.next_out = this->fwrite_buf;
2661 this->z.avail_out =
sizeof(this->fwrite_buf);
2670 int r = deflate(&this->z, mode);
2673 if ((n =
sizeof(this->fwrite_buf) - this->z.avail_out) != 0) {
2674 this->
chain->Write(this->fwrite_buf, n);
2676 if (r == Z_STREAM_END)
break;
2678 if (r != Z_OK)
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR,
"zlib returned error code");
2679 }
while (this->z.avail_in || !this->z.avail_out);
2682 void Write(uint8_t *buf,
size_t size)
override
2690 this->
chain->Finish();
2700#if defined(WITH_LIBLZMA)
2722 if (lzma_auto_decoder(&this->lzma, 1 << 28, 0) != LZMA_OK)
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR,
"cannot initialize decompressor");
2728 lzma_end(&this->lzma);
2731 size_t Read(uint8_t *buf,
size_t size)
override
2733 this->lzma.next_out = buf;
2734 this->lzma.avail_out = size;
2738 if (this->lzma.avail_in == 0) {
2739 this->lzma.next_in = this->fread_buf;
2740 this->lzma.avail_in = this->
chain->Read(this->fread_buf,
sizeof(this->fread_buf));
2744 lzma_ret r = lzma_code(&this->lzma, LZMA_RUN);
2745 if (r == LZMA_STREAM_END)
break;
2746 if (r != LZMA_OK)
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR,
"liblzma returned error code");
2747 }
while (this->lzma.avail_out != 0);
2749 return size - this->lzma.avail_out;
2765 if (lzma_easy_encoder(&this->lzma, compression_level, LZMA_CHECK_CRC32) != LZMA_OK)
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR,
"cannot initialize compressor");
2771 lzma_end(&this->lzma);
2783 this->lzma.next_in = p;
2784 this->lzma.avail_in = len;
2786 this->lzma.next_out = this->fwrite_buf;
2787 this->lzma.avail_out =
sizeof(this->fwrite_buf);
2789 lzma_ret r = lzma_code(&this->lzma, action);
2792 if ((n =
sizeof(this->fwrite_buf) - this->lzma.avail_out) != 0) {
2793 this->
chain->Write(this->fwrite_buf, n);
2795 if (r == LZMA_STREAM_END)
break;
2796 if (r != LZMA_OK)
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR,
"liblzma returned error code");
2797 }
while (this->lzma.avail_in || !this->lzma.avail_out);
2800 void Write(uint8_t *buf,
size_t size)
override
2807 this->
WriteLoop(
nullptr, 0, LZMA_FINISH);
2808 this->
chain->Finish();
2820 std::shared_ptr<LoadFilter> (*
init_load)(std::shared_ptr<LoadFilter> chain);
2821 std::shared_ptr<SaveFilter> (*
init_write)(std::shared_ptr<SaveFilter> chain, uint8_t compression);
2831static const uint32_t SAVEGAME_TAG_LZO = TO_BE32(
'OTTD');
2832static const uint32_t SAVEGAME_TAG_NONE = TO_BE32(
'OTTN');
2833static const uint32_t SAVEGAME_TAG_ZLIB = TO_BE32(
'OTTZ');
2834static const uint32_t SAVEGAME_TAG_LZMA = TO_BE32(
'OTTX');
2838#if defined(WITH_LZO)
2842 {
nullptr,
nullptr,
"lzo", SAVEGAME_TAG_LZO, 0, 0, 0},
2846#if defined(WITH_ZLIB)
2852 {
nullptr,
nullptr,
"zlib", SAVEGAME_TAG_ZLIB, 0, 0, 0},
2854#if defined(WITH_LIBLZMA)
2862 {
nullptr,
nullptr,
"lzma", SAVEGAME_TAG_LZMA, 0, 0, 0},
2876 if (it == std::rend(
_saveload_formats))
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR,
"no writeable savegame formats");
2880 if (!full_name.empty()) {
2882 size_t separator = full_name.find(
':');
2883 bool has_comp_level = separator != std::string::npos;
2884 std::string_view name = has_comp_level ? full_name.substr(0, separator) : full_name;
2887 if (slf.init_write !=
nullptr && name == slf.name) {
2888 if (has_comp_level) {
2889 auto complevel = full_name.substr(separator + 1);
2893 if (!level.has_value() || *level !=
Clamp(*level, slf.min_compression, slf.max_compression)) {
2896 GetEncodedString(STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL, complevel),
2899 return {slf, *level};
2902 return {slf, slf.default_compression};
2915void InitializeGame(uint size_x, uint size_y,
bool reset_date,
bool reset_settings);
2917extern bool LoadOldSaveGame(std::string_view file);
2943 ResetTempEngineData();
2944 ClearRailTypeLabelList();
2945 ClearRoadTypeLabelList();
2946 ResetOldWaypoints();
2955 _sl.dumper =
nullptr;
2957 _sl.reader =
nullptr;
2967 _sl.saveinprogress =
true;
2976 _sl.saveinprogress =
false;
2978#ifdef __EMSCRIPTEN__
2979 EM_ASM(
if (window[
"openttd_syncfs"]) openttd_syncfs());
2989 _sl.error_str = str;
3030 _sl.sf->Write((uint8_t*)hdr,
sizeof(hdr));
3032 _sl.sf = fmt.init_write(
_sl.sf, compression);
3033 _sl.dumper->Flush(
_sl.sf);
3047 if (
_sl.error_str != STR_NETWORK_ERROR_LOSTCONNECTION) {
3082 assert(!
_sl.saveinprogress);
3084 _sl.dumper = std::make_unique<MemoryDumper>();
3085 _sl.sf = std::move(writer);
3089 SaveViewportBeforeSaveGame();
3095 if (threaded)
Debug(sl, 1,
"Cannot create savegame thread, reverting to single-threaded mode...");
3116 return DoSave(std::move(writer), threaded);
3150 Debug(sl, 0,
"Unknown savegame type, trying to load it as the buggy format");
3174 _sl.lf = std::move(reader);
3184 if (
_sl.lf->Read((uint8_t*)hdr,
sizeof(hdr)) !=
sizeof(hdr))
SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
3190 if (fmt->init_load ==
nullptr) {
3191 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, fmt::format(
"Loader for '{}' is not available.", fmt->name));
3194 _sl.lf = fmt->init_load(
_sl.lf);
3195 _sl.reader = std::make_unique<ReadBuffer>(
_sl.lf);
3204 InitializeGame(256, 256,
true,
true);
3276 return DoLoad(std::move(reader),
false);
3308 InitializeGame(256, 256,
true,
true);
3316 if (!LoadOldSaveGame(filename))
return SL_REINIT;
3342 default: NOT_REACHED();
3352 if (!fh.has_value()) {
3353 SlError(fop ==
SLO_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
3360 return DoSave(std::make_shared<FileWriter>(std::move(*fh)), threaded);
3365 Debug(desync, 1,
"load: {}", filename);
3366 return DoLoad(std::make_shared<FileReader>(std::move(*fh)), fop ==
SLO_CHECK);
3385 std::string filename;
3393 Debug(sl, 2,
"Autosaving to '{}'", filename);
3423 std::array<StringParameter, 4> params{};
3424 auto it = params.begin();
3431 *it++ = STR_SAVEGAME_DURATION_REALTIME;
3432 *it++ = play_time / 60 / 60;
3433 *it++ = (play_time / 60) % 60;
3437 case 0: *it++ = STR_JUST_DATE_LONG;
break;
3438 case 1: *it++ = STR_JUST_DATE_TINY;
break;
3439 case 2: *it++ = STR_JUST_DATE_ISO;
break;
3440 default: NOT_REACHED();
3460 this->
ftype = FIOS_TYPE_INVALID;
3475 this->
name = item.name;
3476 this->
title = item.title;
Base class for autoreplaces/autorenews.
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 HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr enable_if_t< is_integral_v< T >, T > byteswap(T x) noexcept
Custom implementation of std::byteswap; remove once we build with C++23.
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
void PutUtf8(char32_t c)
Append UTF-8 char.
void Put(std::string_view str)
Append string.
void PutIntegerBase(T value, int base)
Append integer 'value' in given number 'base'.
Container for an encoded string, created by GetEncodedString.
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.
std::optional< std::vector< SaveLoad > > load_description
Description derived from savegame being loaded.
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.
SaveLoadCompatTable GetCompatDescription() const override
Get the pre-header description of the fields in the savegame.
SaveLoadTable GetDescription() const override
Get the 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.
Parse data from a string / buffer.
std::optional< T > TryReadIntegerBase(int base, bool clamp=false)
Try to read and parse an integer in number 'base', and then advance the reader.
@ READ_ONE_SEPARATOR
Read one separator, and include it in the result.
bool AnyBytesLeft() const noexcept
Check whether any bytes left to read.
std::optional< char32_t > TryReadUtf8()
Try to read a UTF-8 character, and then advance reader.
T ReadIntegerBase(int base, T def=0, bool clamp=false)
Read and parse an integer in number 'base', and advance the reader.
bool ReadUtf8If(char32_t c)
Check whether the next UTF-8 char matches 'c', and skip it.
std::string_view ReadUntilUtf8(char32_t c, SeparatorUsage sep)
Read data until the first occurrence of UTF-8 char 'c', and advance reader.
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.
Functions related to companies.
@ SCC_ENCODED
Encoded string marker and sub-string parameter.
@ SCC_ENCODED_NUMERIC
Encoded numeric parameter.
@ SCC_ENCODED_STRING
Encoded string parameter.
Functions related to debugging.
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Function to handling different endian machines.
Functions related to errors.
@ 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(std::string_view filename, std::string_view mode, Subdirectory subdir, size_t *filesize)
Opens a OpenTTD file somewhere in a personal or global directory.
Functions for standard in/out file operations.
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
Kinds of files in each AbstractFileType.
@ DFT_GAME_FILE
Save game or scenario 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.
@ FT_INVALID
Invalid or unknown file type.
Declarations for savegames operations.
LoadCheckData _load_check_data
Data loaded from save during SL_LOAD_CHECK.
fluid_settings_t * settings
FluidSynth settings handle.
uint32_t _ttdp_version
version of TTDP savegame (if applicable)
SaveLoadVersion _sl_version
the major savegame version identifier
uint8_t _sl_minor_version
the minor savegame version, DO NOT USE!
Gamelog _gamelog
Gamelog instance.
SavegameType _savegame_type
type of savegame we are loading
const SaveLoadVersion SAVEGAME_VERSION
current savegame version
Functions to be called to log fundamental changes to the game.
void SetMouseCursorBusy(bool busy)
Set or unset the ZZZ cursor.
GameSessionStats _game_session_stats
Statistics about the current session.
Declaration of link graph classes used for cargo distribution.
Declaration of link graph job classes used for cargo distribution.
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
Basic functions/variables used all over the place.
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.
NewGRF handling of rail types.
NewGRF handling of road types.
uint8_t ReadByte(LoadgameState &ls)
Reads a byte from the buffer and decompress if needed.
Base class for roadstops.
A number of safeguards to prevent using unsafe methods.
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.
void FixSCCEncodedNegative(std::string &str)
Scan the string for SCC_ENCODED_NUMERIC with negative values, and reencode them as uint64_t.
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...
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()
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.
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.
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.
SaveOrLoadResult SaveOrLoad(std::string_view filename, SaveLoadOperation fop, DetailedFileType dft, Subdirectory sb, bool threaded)
Main Save or Load function where the high-level saveload functions are handled.
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.
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.
void ClearOldOrders()
Clear all old orders.
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.
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.
static std::pair< const SaveLoadFormat &, uint8_t > GetSavegameFormat(std::string_view full_name)
Return the savegameformat of the game.
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_REPLACE_TABCRLF
Replace tabs, cr and lf in the string with spaces.
@ 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 string 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_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_FIX_SCC_ENCODED_NEGATIVE
353 PR#14049 Fix encoding of negative parameters.
@ 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.
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.
void SlErrorCorruptFmt(const fmt::format_string< Args... > format, Args &&... fmt_args)
Issue an SlErrorCorrupt with a format string.
Declaration of filters used for saving and loading savegames.
std::shared_ptr< SaveFilter > CreateSaveFilter(std::shared_ptr< SaveFilter > chain, uint8_t compression_level)
Instantiator for a save filter.
std::shared_ptr< LoadFilter > CreateLoadFilter(std::shared_ptr< LoadFilter > chain)
Instantiator for a load filter.
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.
Functions and types used internally for the settings configurations.
@ 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.
Base classes/functions for stations.
Functions, definitions and such used only by the GUI.
@ SBI_SAVELOAD_FINISH
finished saving
@ SBI_SAVELOAD_START
started saving
Definition of base types and functions in a cross-platform compatible way.
#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 '?
Compose strings from textual and binary data.
static std::optional< T > ParseInteger(std::string_view arg, int base=10, bool clamp=false)
Change a string into its number representation.
Functions related to low-level strings.
@ ReplaceWithQuestionMark
Replace the unknown/bad bits with question marks.
@ AllowControlCode
Allow the special control codes.
@ AllowNewline
Allow newlines; replaces '\r ' with ' ' during processing.
@ ReplaceTabCrNlWithSpace
Replace tabs ('\t'), carriage returns ('\r') and newlines (' ') with spaces.
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.
Functions related to OTTD's strings.
Types related to strings.
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.
Struct to store engine replacements.
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() override
Make sure everything is cleaned up.
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.
void SetMode(const FiosType &ft, SaveLoadOperation fop=SLO_LOAD)
Set the mode and file type of the file to save or load.
SaveLoadOperation file_op
File operation to perform.
std::string name
Name of the file.
EncodedString title
Internal name of the game.
void Set(const FiosItem &item)
Set the mode, title and name of the file.
std::optional< FileHandle > file
The file to write to.
~FileWriter() override
Make sure everything is cleaned up.
FileWriter(FileHandle &&file)
Create the file writer, so it writes to a specific file.
void Finish() override
Prepare everything to finish writing the savegame.
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.
Elements of a file system that are recognized.
AbstractFileType abstract
Abstract file type.
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.
~LZMALoadFilter() override
Clean everything up.
uint8_t fread_buf[MEMORY_CHUNK_SIZE]
Buffer for reading from the file.
LZMALoadFilter(std::shared_ptr< LoadFilter > chain)
Initialise this filter.
~LZMASaveFilter() override
Clean up what we allocated.
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.
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.
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.
std::shared_ptr< LoadFilter > chain
Chained to the (savegame) filters.
LoadFilter(std::shared_ptr< LoadFilter > chain)
Initialise this filter.
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.
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.
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< Company > Iterate(size_t from=0)
static OrderList * Get(auto index)
static bool IsValidID(auto index)
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.
SaveFilter(std::shared_ptr< SaveFilter > chain)
Initialise this filter.
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)
static Station * Get(auto index)
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() override
Clean everything up.
z_stream z
Stream state we are reading from.
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.
~ZlibSaveFilter() override
Clean up what we allocated.
void Finish() override
Prepare everything to finish writing the savegame.
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, std::string_view name, TFn &&_Fx, TArgs &&... _Ax)
Start a new thread.
Definition of the game-economy-timer.
Base class for all vehicles.
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-...
Window functions not directly related to making/drawing windows.
@ WC_STATUS_BAR
Statusbar (at the bottom of your screen); Window numbers: