Saveload: Add support for using upstream save/load for specific chunks
This commit is contained in:
@@ -95,8 +95,12 @@ extern bool _sl_upstream_mode;
|
|||||||
namespace upstream_sl {
|
namespace upstream_sl {
|
||||||
void SlNullPointers();
|
void SlNullPointers();
|
||||||
void SlLoadChunks();
|
void SlLoadChunks();
|
||||||
|
void SlLoadChunkByID(uint32 id);
|
||||||
void SlLoadCheckChunks();
|
void SlLoadCheckChunks();
|
||||||
|
void SlLoadCheckChunkByID(uint32 id);
|
||||||
void SlFixPointers();
|
void SlFixPointers();
|
||||||
|
void SlFixPointerChunkByID(uint32 id);
|
||||||
|
void SlSaveChunkChunkByID(uint32 id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** What are we currently doing? */
|
/** What are we currently doing? */
|
||||||
@@ -2132,6 +2136,10 @@ inline void SlRIFFSpringPPCheck(size_t len)
|
|||||||
*/
|
*/
|
||||||
static void SlLoadChunk(const ChunkHandler &ch)
|
static void SlLoadChunk(const ChunkHandler &ch)
|
||||||
{
|
{
|
||||||
|
if (ch.special_proc != nullptr) {
|
||||||
|
if (ch.special_proc(ch.id, CSLSO_PRE_LOADCHECK)) return;
|
||||||
|
}
|
||||||
|
|
||||||
byte m = SlReadByte();
|
byte m = SlReadByte();
|
||||||
size_t len;
|
size_t len;
|
||||||
size_t endoffs;
|
size_t endoffs;
|
||||||
@@ -2195,6 +2203,10 @@ static void SlLoadChunk(const ChunkHandler &ch)
|
|||||||
*/
|
*/
|
||||||
static void SlLoadCheckChunk(const ChunkHandler *ch)
|
static void SlLoadCheckChunk(const ChunkHandler *ch)
|
||||||
{
|
{
|
||||||
|
if (ch && ch->special_proc != nullptr) {
|
||||||
|
if (ch->special_proc(ch->id, CSLSO_PRE_LOAD)) return;
|
||||||
|
}
|
||||||
|
|
||||||
byte m = SlReadByte();
|
byte m = SlReadByte();
|
||||||
size_t len;
|
size_t len;
|
||||||
size_t endoffs;
|
size_t endoffs;
|
||||||
@@ -2281,6 +2293,14 @@ static void SlLoadCheckChunk(const ChunkHandler *ch)
|
|||||||
*/
|
*/
|
||||||
static void SlSaveChunk(const ChunkHandler &ch)
|
static void SlSaveChunk(const ChunkHandler &ch)
|
||||||
{
|
{
|
||||||
|
if (ch.type == CH_UPSTREAM_SAVE) {
|
||||||
|
SaveLoadVersion old_ver = _sl_version;
|
||||||
|
_sl_version = MAX_LOAD_SAVEGAME_VERSION;
|
||||||
|
upstream_sl::SlSaveChunkChunkByID(ch.id);
|
||||||
|
_sl_version = old_ver;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ChunkSaveLoadProc *proc = ch.save_proc;
|
ChunkSaveLoadProc *proc = ch.save_proc;
|
||||||
|
|
||||||
/* Don't save any chunk information if there is no save handler. */
|
/* Don't save any chunk information if there is no save handler. */
|
||||||
@@ -3804,3 +3824,8 @@ bool SaveLoadFileTypeIsScenario()
|
|||||||
{
|
{
|
||||||
return _file_to_saveload.abstract_ftype == FT_SCENARIO;
|
return _file_to_saveload.abstract_ftype == FT_SCENARIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SlUnreachablePlaceholder()
|
||||||
|
{
|
||||||
|
NOT_REACHED();
|
||||||
|
}
|
||||||
|
@@ -77,12 +77,22 @@ bool IsNetworkServerSave();
|
|||||||
typedef void ChunkSaveLoadProc();
|
typedef void ChunkSaveLoadProc();
|
||||||
typedef void AutolengthProc(void *arg);
|
typedef void AutolengthProc(void *arg);
|
||||||
|
|
||||||
|
void SlUnreachablePlaceholder();
|
||||||
|
|
||||||
|
enum ChunkSaveLoadSpecialOp {
|
||||||
|
CSLSO_PRE_LOAD,
|
||||||
|
CSLSO_PRE_LOADCHECK,
|
||||||
|
};
|
||||||
|
typedef bool ChunkSaveLoadSpecialProc(uint32, ChunkSaveLoadSpecialOp);
|
||||||
|
|
||||||
/** Type of a chunk. */
|
/** Type of a chunk. */
|
||||||
enum ChunkType {
|
enum ChunkType {
|
||||||
CH_RIFF = 0,
|
CH_RIFF = 0,
|
||||||
CH_ARRAY = 1,
|
CH_ARRAY = 1,
|
||||||
CH_SPARSE_ARRAY = 2,
|
CH_SPARSE_ARRAY = 2,
|
||||||
CH_EXT_HDR = 15, ///< Extended chunk header
|
CH_EXT_HDR = 15, ///< Extended chunk header
|
||||||
|
|
||||||
|
CH_UPSTREAM_SAVE = 0x80,
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Handlers and description of chunk. */
|
/** Handlers and description of chunk. */
|
||||||
@@ -93,8 +103,62 @@ struct ChunkHandler {
|
|||||||
ChunkSaveLoadProc *ptrs_proc; ///< Manipulate pointers in the chunk.
|
ChunkSaveLoadProc *ptrs_proc; ///< Manipulate pointers in the chunk.
|
||||||
ChunkSaveLoadProc *load_check_proc; ///< Load procedure for game preview.
|
ChunkSaveLoadProc *load_check_proc; ///< Load procedure for game preview.
|
||||||
ChunkType type; ///< Type of the chunk. @see ChunkType
|
ChunkType type; ///< Type of the chunk. @see ChunkType
|
||||||
|
ChunkSaveLoadSpecialProc *special_proc = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
void SlExecWithSlVersion(SaveLoadVersion use_version, F proc)
|
||||||
|
{
|
||||||
|
extern SaveLoadVersion _sl_version;
|
||||||
|
SaveLoadVersion old_ver = _sl_version;
|
||||||
|
_sl_version = use_version;
|
||||||
|
proc();
|
||||||
|
_sl_version = old_ver;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace upstream_sl {
|
||||||
|
template <uint32 id, typename F>
|
||||||
|
ChunkHandler MakeUpstreamChunkHandler()
|
||||||
|
{
|
||||||
|
extern void SlLoadChunkByID(uint32);
|
||||||
|
extern void SlLoadCheckChunkByID(uint32);
|
||||||
|
extern void SlFixPointerChunkByID(uint32);
|
||||||
|
|
||||||
|
ChunkHandler ch = {
|
||||||
|
id,
|
||||||
|
nullptr,
|
||||||
|
SlUnreachablePlaceholder,
|
||||||
|
[]() {
|
||||||
|
SlExecWithSlVersion(F::GetVersion(), []() {
|
||||||
|
SlFixPointerChunkByID(id);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
SlUnreachablePlaceholder,
|
||||||
|
CH_UPSTREAM_SAVE
|
||||||
|
};
|
||||||
|
ch.special_proc = [](uint32 chunk_id, ChunkSaveLoadSpecialOp op) -> bool {
|
||||||
|
assert(id == chunk_id);
|
||||||
|
switch (op) {
|
||||||
|
case CSLSO_PRE_LOAD:
|
||||||
|
SlExecWithSlVersion(F::GetVersion(), []() {
|
||||||
|
SlLoadChunkByID(id);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case CSLSO_PRE_LOADCHECK:
|
||||||
|
SlExecWithSlVersion(F::GetVersion(), []() {
|
||||||
|
SlLoadCheckChunkByID(id);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true; // chunk has been consumed
|
||||||
|
};
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
using upstream_sl::MakeUpstreamChunkHandler;
|
||||||
|
|
||||||
struct NullStruct {
|
struct NullStruct {
|
||||||
byte null;
|
byte null;
|
||||||
};
|
};
|
||||||
|
@@ -2014,6 +2014,18 @@ void SlLoadChunks()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Load a chunk */
|
||||||
|
void SlLoadChunkByID(uint32 id)
|
||||||
|
{
|
||||||
|
_sl.action = SLA_LOAD;
|
||||||
|
|
||||||
|
DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
|
||||||
|
|
||||||
|
const ChunkHandler *ch = SlFindChunkHandler(id);
|
||||||
|
if (ch == nullptr) SlErrorCorrupt("Unknown chunk type");
|
||||||
|
SlLoadChunk(*ch);
|
||||||
|
}
|
||||||
|
|
||||||
/** Load all chunks for savegame checking */
|
/** Load all chunks for savegame checking */
|
||||||
void SlLoadCheckChunks()
|
void SlLoadCheckChunks()
|
||||||
{
|
{
|
||||||
@@ -2031,6 +2043,18 @@ void SlLoadCheckChunks()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Load a chunk for savegame checking */
|
||||||
|
void SlLoadCheckChunkByID(uint32 id)
|
||||||
|
{
|
||||||
|
_sl.action = SLA_LOAD_CHECK;
|
||||||
|
|
||||||
|
DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
|
||||||
|
|
||||||
|
const ChunkHandler *ch = SlFindChunkHandler(id);
|
||||||
|
if (ch == nullptr) SlErrorCorrupt("Unknown chunk type");
|
||||||
|
SlLoadCheckChunk(*ch);
|
||||||
|
}
|
||||||
|
|
||||||
/** Fix all pointers (convert index -> pointer) */
|
/** Fix all pointers (convert index -> pointer) */
|
||||||
void SlFixPointers()
|
void SlFixPointers()
|
||||||
{
|
{
|
||||||
@@ -2044,6 +2068,64 @@ void SlFixPointers()
|
|||||||
assert(_sl.action == SLA_PTRS);
|
assert(_sl.action == SLA_PTRS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SlFixPointerChunkByID(uint32 id)
|
||||||
|
{
|
||||||
|
const ChunkHandler *ch = SlFindChunkHandler(id);
|
||||||
|
if (ch == nullptr) SlErrorCorrupt("Unknown chunk type");
|
||||||
|
DEBUG(sl, 3, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
|
||||||
|
ch->FixPointers();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save a chunk of data (eg. vehicles, stations, etc.). Each chunk is
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
if (ch.type == CH_READONLY) return;
|
||||||
|
|
||||||
|
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.type;
|
||||||
|
_sl.expect_table_header = (_sl.block_mode == CH_TABLE || _sl.block_mode == CH_SPARSE_TABLE);
|
||||||
|
|
||||||
|
_sl.need_length = (_sl.expect_table_header || _sl.block_mode == CH_RIFF) ? NL_WANTLENGTH : NL_NONE;
|
||||||
|
|
||||||
|
switch (_sl.block_mode) {
|
||||||
|
case CH_RIFF:
|
||||||
|
ch.Save();
|
||||||
|
break;
|
||||||
|
case CH_TABLE:
|
||||||
|
case CH_ARRAY:
|
||||||
|
_sl.last_array_index = 0;
|
||||||
|
SlWriteByte(_sl.block_mode);
|
||||||
|
ch.Save();
|
||||||
|
SlWriteArrayLength(0); // Terminate arrays
|
||||||
|
break;
|
||||||
|
case CH_SPARSE_TABLE:
|
||||||
|
case CH_SPARSE_ARRAY:
|
||||||
|
SlWriteByte(_sl.block_mode);
|
||||||
|
ch.Save();
|
||||||
|
SlWriteArrayLength(0); // Terminate arrays
|
||||||
|
break;
|
||||||
|
default: NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_sl.expect_table_header) SlErrorCorrupt("Table chunk without header");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Save a chunk of data */
|
||||||
|
void SlSaveChunkChunkByID(uint32 id)
|
||||||
|
{
|
||||||
|
const ChunkHandler *ch = SlFindChunkHandler(id);
|
||||||
|
if (ch == nullptr) SlErrorCorrupt("Unknown chunk type");
|
||||||
|
|
||||||
|
_sl.action = SLA_SAVE;
|
||||||
|
SlSaveChunk(*ch);
|
||||||
|
}
|
||||||
|
|
||||||
SaveLoadTable SaveLoadHandler::GetLoadDescription() const
|
SaveLoadTable SaveLoadHandler::GetLoadDescription() const
|
||||||
{
|
{
|
||||||
assert(this->load_description.has_value());
|
assert(this->load_description.has_value());
|
||||||
|
Reference in New Issue
Block a user