|
|
|
@ -214,86 +214,92 @@ struct SaveLoadParams {
|
|
|
|
|
|
|
|
|
|
static SaveLoadParams _sl; ///< Parameters used for/at saveload.
|
|
|
|
|
|
|
|
|
|
/* these define the chunks */
|
|
|
|
|
extern const ChunkHandler _gamelog_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _map_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _misc_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _name_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _cheat_chunk_handlers[] ;
|
|
|
|
|
extern const ChunkHandler _setting_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _company_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _engine_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _veh_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _waypoint_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _depot_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _order_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _town_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _sign_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _station_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _industry_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _economy_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _subsidy_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _cargomonitor_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _goal_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _story_page_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _ai_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _game_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _animated_tile_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _newgrf_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _group_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _cargopacket_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _autoreplace_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _labelmaps_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _linkgraph_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _airport_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _object_chunk_handlers[];
|
|
|
|
|
extern const ChunkHandler _persistent_storage_chunk_handlers[];
|
|
|
|
|
|
|
|
|
|
/** Array of all chunks in a savegame, \c nullptr terminated. */
|
|
|
|
|
static const ChunkHandler * const _chunk_handlers[] = {
|
|
|
|
|
_gamelog_chunk_handlers,
|
|
|
|
|
_map_chunk_handlers,
|
|
|
|
|
_misc_chunk_handlers,
|
|
|
|
|
_name_chunk_handlers,
|
|
|
|
|
_cheat_chunk_handlers,
|
|
|
|
|
_setting_chunk_handlers,
|
|
|
|
|
_veh_chunk_handlers,
|
|
|
|
|
_waypoint_chunk_handlers,
|
|
|
|
|
_depot_chunk_handlers,
|
|
|
|
|
_order_chunk_handlers,
|
|
|
|
|
_industry_chunk_handlers,
|
|
|
|
|
_economy_chunk_handlers,
|
|
|
|
|
_subsidy_chunk_handlers,
|
|
|
|
|
_cargomonitor_chunk_handlers,
|
|
|
|
|
_goal_chunk_handlers,
|
|
|
|
|
_story_page_chunk_handlers,
|
|
|
|
|
_engine_chunk_handlers,
|
|
|
|
|
_town_chunk_handlers,
|
|
|
|
|
_sign_chunk_handlers,
|
|
|
|
|
_station_chunk_handlers,
|
|
|
|
|
_company_chunk_handlers,
|
|
|
|
|
_ai_chunk_handlers,
|
|
|
|
|
_game_chunk_handlers,
|
|
|
|
|
_animated_tile_chunk_handlers,
|
|
|
|
|
_newgrf_chunk_handlers,
|
|
|
|
|
_group_chunk_handlers,
|
|
|
|
|
_cargopacket_chunk_handlers,
|
|
|
|
|
_autoreplace_chunk_handlers,
|
|
|
|
|
_labelmaps_chunk_handlers,
|
|
|
|
|
_linkgraph_chunk_handlers,
|
|
|
|
|
_airport_chunk_handlers,
|
|
|
|
|
_object_chunk_handlers,
|
|
|
|
|
_persistent_storage_chunk_handlers,
|
|
|
|
|
nullptr,
|
|
|
|
|
};
|
|
|
|
|
static const std::vector<ChunkHandler> &ChunkHandlers()
|
|
|
|
|
{
|
|
|
|
|
/* These define the chunks */
|
|
|
|
|
extern const ChunkHandlerTable _gamelog_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _map_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _misc_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _name_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _cheat_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _setting_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _company_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _engine_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _veh_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _waypoint_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _depot_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _order_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _town_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _sign_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _station_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _industry_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _economy_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _subsidy_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _cargomonitor_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _goal_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _story_page_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _ai_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _game_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _animated_tile_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _newgrf_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _group_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _cargopacket_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _autoreplace_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _labelmaps_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _linkgraph_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _airport_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _object_chunk_handlers;
|
|
|
|
|
extern const ChunkHandlerTable _persistent_storage_chunk_handlers;
|
|
|
|
|
|
|
|
|
|
/** List of all chunks in a savegame. */
|
|
|
|
|
static const ChunkHandlerTable _chunk_handler_tables[] = {
|
|
|
|
|
_gamelog_chunk_handlers,
|
|
|
|
|
_map_chunk_handlers,
|
|
|
|
|
_misc_chunk_handlers,
|
|
|
|
|
_name_chunk_handlers,
|
|
|
|
|
_cheat_chunk_handlers,
|
|
|
|
|
_setting_chunk_handlers,
|
|
|
|
|
_veh_chunk_handlers,
|
|
|
|
|
_waypoint_chunk_handlers,
|
|
|
|
|
_depot_chunk_handlers,
|
|
|
|
|
_order_chunk_handlers,
|
|
|
|
|
_industry_chunk_handlers,
|
|
|
|
|
_economy_chunk_handlers,
|
|
|
|
|
_subsidy_chunk_handlers,
|
|
|
|
|
_cargomonitor_chunk_handlers,
|
|
|
|
|
_goal_chunk_handlers,
|
|
|
|
|
_story_page_chunk_handlers,
|
|
|
|
|
_engine_chunk_handlers,
|
|
|
|
|
_town_chunk_handlers,
|
|
|
|
|
_sign_chunk_handlers,
|
|
|
|
|
_station_chunk_handlers,
|
|
|
|
|
_company_chunk_handlers,
|
|
|
|
|
_ai_chunk_handlers,
|
|
|
|
|
_game_chunk_handlers,
|
|
|
|
|
_animated_tile_chunk_handlers,
|
|
|
|
|
_newgrf_chunk_handlers,
|
|
|
|
|
_group_chunk_handlers,
|
|
|
|
|
_cargopacket_chunk_handlers,
|
|
|
|
|
_autoreplace_chunk_handlers,
|
|
|
|
|
_labelmaps_chunk_handlers,
|
|
|
|
|
_linkgraph_chunk_handlers,
|
|
|
|
|
_airport_chunk_handlers,
|
|
|
|
|
_object_chunk_handlers,
|
|
|
|
|
_persistent_storage_chunk_handlers,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static std::vector<ChunkHandler> _chunk_handlers;
|
|
|
|
|
|
|
|
|
|
if (_chunk_handlers.empty()) {
|
|
|
|
|
for (auto &chunk_handler_table : _chunk_handler_tables) {
|
|
|
|
|
for (auto &chunk_handler : chunk_handler_table) {
|
|
|
|
|
_chunk_handlers.push_back(chunk_handler);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Iterate over all chunk handlers.
|
|
|
|
|
* @param ch the chunk handler iterator
|
|
|
|
|
*/
|
|
|
|
|
#define FOR_ALL_CHUNK_HANDLERS(ch) \
|
|
|
|
|
for (const ChunkHandler * const *chsc = _chunk_handlers; *chsc != nullptr; chsc++) \
|
|
|
|
|
for (const ChunkHandler *ch = *chsc; ch != nullptr; ch = (ch->flags & CH_LAST) ? nullptr : ch + 1)
|
|
|
|
|
return _chunk_handlers;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Null all pointers (convert index -> nullptr) */
|
|
|
|
|
static void SlNullPointers()
|
|
|
|
@ -305,10 +311,10 @@ static void SlNullPointers()
|
|
|
|
|
* pointers from other pools. */
|
|
|
|
|
_sl_version = SAVEGAME_VERSION;
|
|
|
|
|
|
|
|
|
|
FOR_ALL_CHUNK_HANDLERS(ch) {
|
|
|
|
|
if (ch->ptrs_proc != nullptr) {
|
|
|
|
|
DEBUG(sl, 3, "Nulling pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
|
|
|
|
|
ch->ptrs_proc();
|
|
|
|
|
for (auto &ch : ChunkHandlers()) {
|
|
|
|
|
if (ch.ptrs_proc != nullptr) {
|
|
|
|
|
DEBUG(sl, 3, "Nulling pointers for %c%c%c%c", ch.id >> 24, ch.id >> 16, ch.id >> 8, ch.id);
|
|
|
|
|
ch.ptrs_proc();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1654,7 +1660,7 @@ void SlAutolength(AutolengthProc *proc, void *arg)
|
|
|
|
|
* Load a chunk of data (eg vehicles, stations, etc.)
|
|
|
|
|
* @param ch The chunkhandler that will be used for the operation
|
|
|
|
|
*/
|
|
|
|
|
static void SlLoadChunk(const ChunkHandler *ch)
|
|
|
|
|
static void SlLoadChunk(const ChunkHandler &ch)
|
|
|
|
|
{
|
|
|
|
|
byte m = SlReadByte();
|
|
|
|
|
size_t len;
|
|
|
|
@ -1666,11 +1672,11 @@ static void SlLoadChunk(const ChunkHandler *ch)
|
|
|
|
|
switch (m) {
|
|
|
|
|
case CH_ARRAY:
|
|
|
|
|
_sl.array_index = 0;
|
|
|
|
|
ch->load_proc();
|
|
|
|
|
ch.load_proc();
|
|
|
|
|
if (_next_offs != 0) SlErrorCorrupt("Invalid array length");
|
|
|
|
|
break;
|
|
|
|
|
case CH_SPARSE_ARRAY:
|
|
|
|
|
ch->load_proc();
|
|
|
|
|
ch.load_proc();
|
|
|
|
|
if (_next_offs != 0) SlErrorCorrupt("Invalid array length");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
@ -1680,7 +1686,7 @@ static void SlLoadChunk(const ChunkHandler *ch)
|
|
|
|
|
len += SlReadUint16();
|
|
|
|
|
_sl.obj_len = len;
|
|
|
|
|
endoffs = _sl.reader->GetSize() + len;
|
|
|
|
|
ch->load_proc();
|
|
|
|
|
ch.load_proc();
|
|
|
|
|
if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
|
|
|
|
|
} else {
|
|
|
|
|
SlErrorCorrupt("Invalid chunk type");
|
|
|
|
@ -1694,7 +1700,7 @@ static void SlLoadChunk(const ChunkHandler *ch)
|
|
|
|
|
* If the chunkhandler is nullptr, the chunk is skipped.
|
|
|
|
|
* @param ch The chunkhandler that will be used for the operation
|
|
|
|
|
*/
|
|
|
|
|
static void SlLoadCheckChunk(const ChunkHandler *ch)
|
|
|
|
|
static void SlLoadCheckChunk(const ChunkHandler &ch)
|
|
|
|
|
{
|
|
|
|
|
byte m = SlReadByte();
|
|
|
|
|
size_t len;
|
|
|
|
@ -1706,15 +1712,15 @@ static void SlLoadCheckChunk(const ChunkHandler *ch)
|
|
|
|
|
switch (m) {
|
|
|
|
|
case CH_ARRAY:
|
|
|
|
|
_sl.array_index = 0;
|
|
|
|
|
if (ch->load_check_proc) {
|
|
|
|
|
ch->load_check_proc();
|
|
|
|
|
if (ch.load_check_proc) {
|
|
|
|
|
ch.load_check_proc();
|
|
|
|
|
} else {
|
|
|
|
|
SlSkipArray();
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case CH_SPARSE_ARRAY:
|
|
|
|
|
if (ch->load_check_proc) {
|
|
|
|
|
ch->load_check_proc();
|
|
|
|
|
if (ch.load_check_proc) {
|
|
|
|
|
ch.load_check_proc();
|
|
|
|
|
} else {
|
|
|
|
|
SlSkipArray();
|
|
|
|
|
}
|
|
|
|
@ -1726,8 +1732,8 @@ static void SlLoadCheckChunk(const ChunkHandler *ch)
|
|
|
|
|
len += SlReadUint16();
|
|
|
|
|
_sl.obj_len = len;
|
|
|
|
|
endoffs = _sl.reader->GetSize() + len;
|
|
|
|
|
if (ch->load_check_proc) {
|
|
|
|
|
ch->load_check_proc();
|
|
|
|
|
if (ch.load_check_proc) {
|
|
|
|
|
ch.load_check_proc();
|
|
|
|
|
} else {
|
|
|
|
|
SlSkipBytes(len);
|
|
|
|
|
}
|
|
|
|
@ -1744,18 +1750,18 @@ static void SlLoadCheckChunk(const ChunkHandler *ch)
|
|
|
|
|
* prefixed by an ID identifying it, followed by data, and terminator where appropriate
|
|
|
|
|
* @param ch The chunkhandler that will be used for the operation
|
|
|
|
|
*/
|
|
|
|
|
static void SlSaveChunk(const ChunkHandler *ch)
|
|
|
|
|
static void SlSaveChunk(const ChunkHandler &ch)
|
|
|
|
|
{
|
|
|
|
|
ChunkSaveLoadProc *proc = ch->save_proc;
|
|
|
|
|
ChunkSaveLoadProc *proc = ch.save_proc;
|
|
|
|
|
|
|
|
|
|
/* Don't save any chunk information if there is no save handler. */
|
|
|
|
|
if (proc == nullptr) return;
|
|
|
|
|
|
|
|
|
|
SlWriteUint32(ch->id);
|
|
|
|
|
DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
|
|
|
|
|
SlWriteUint32(ch.id);
|
|
|
|
|
DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch.id >> 24, ch.id >> 16, ch.id >> 8, ch.id);
|
|
|
|
|
|
|
|
|
|
_sl.block_mode = ch->flags & CH_TYPE_MASK;
|
|
|
|
|
switch (ch->flags & CH_TYPE_MASK) {
|
|
|
|
|
_sl.block_mode = ch.type;
|
|
|
|
|
switch (ch.type) {
|
|
|
|
|
case CH_RIFF:
|
|
|
|
|
_sl.need_length = NL_WANTLENGTH;
|
|
|
|
|
proc();
|
|
|
|
@ -1778,7 +1784,7 @@ static void SlSaveChunk(const ChunkHandler *ch)
|
|
|
|
|
/** Save all chunks */
|
|
|
|
|
static void SlSaveChunks()
|
|
|
|
|
{
|
|
|
|
|
FOR_ALL_CHUNK_HANDLERS(ch) {
|
|
|
|
|
for (auto &ch : ChunkHandlers()) {
|
|
|
|
|
SlSaveChunk(ch);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1794,7 +1800,7 @@ static void SlSaveChunks()
|
|
|
|
|
*/
|
|
|
|
|
static const ChunkHandler *SlFindChunkHandler(uint32 id)
|
|
|
|
|
{
|
|
|
|
|
FOR_ALL_CHUNK_HANDLERS(ch) if (ch->id == id) return ch;
|
|
|
|
|
for (auto &ch : ChunkHandlers()) if (ch.id == id) return &ch;
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1809,7 +1815,7 @@ static void SlLoadChunks()
|
|
|
|
|
|
|
|
|
|
ch = SlFindChunkHandler(id);
|
|
|
|
|
if (ch == nullptr) SlErrorCorrupt("Unknown chunk type");
|
|
|
|
|
SlLoadChunk(ch);
|
|
|
|
|
SlLoadChunk(*ch);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1824,7 +1830,7 @@ static void SlLoadCheckChunks()
|
|
|
|
|
|
|
|
|
|
ch = SlFindChunkHandler(id);
|
|
|
|
|
if (ch == nullptr) SlErrorCorrupt("Unknown chunk type");
|
|
|
|
|
SlLoadCheckChunk(ch);
|
|
|
|
|
SlLoadCheckChunk(*ch);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1833,10 +1839,10 @@ static void SlFixPointers()
|
|
|
|
|
{
|
|
|
|
|
_sl.action = SLA_PTRS;
|
|
|
|
|
|
|
|
|
|
FOR_ALL_CHUNK_HANDLERS(ch) {
|
|
|
|
|
if (ch->ptrs_proc != nullptr) {
|
|
|
|
|
DEBUG(sl, 3, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
|
|
|
|
|
ch->ptrs_proc();
|
|
|
|
|
for (auto &ch : ChunkHandlers()) {
|
|
|
|
|
if (ch.ptrs_proc != nullptr) {
|
|
|
|
|
DEBUG(sl, 3, "Fixing pointers for %c%c%c%c", ch.id >> 24, ch.id >> 16, ch.id >> 8, ch.id);
|
|
|
|
|
ch.ptrs_proc();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|