diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index 503acfd39d..8b77c8c064 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -184,7 +184,7 @@ void SlNullPointers() /* We don't want any savegame conversion code to run * during NULLing; especially those that try to get * pointers from other pools. */ - _sl_version = SAVEGAME_VERSION; + _sl_version = MAX_LOAD_SAVEGAME_VERSION; for (const ChunkHandler &ch : ChunkHandlers()) { DEBUG(sl, 3, "Nulling pointers for %c%c%c%c", ch.id >> 24, ch.id >> 16, ch.id >> 8, ch.id); @@ -2038,12 +2038,24 @@ void SlFixPointers() void SlFixPointerChunkByID(uint32_t id) { + _sl.action = SLA_PTRS; + 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(); } +void SlNullPointerChunkByID(uint32_t id) +{ + _sl.action = SLA_NULL; + + const ChunkHandler *ch = SlFindChunkHandler(id); + if (ch == nullptr) SlErrorCorrupt("Unknown chunk type"); + DEBUG(sl, 3, "Nulling 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 diff --git a/src/sl/saveload.cpp b/src/sl/saveload.cpp index 065cfc17bb..db4c7c0a9d 100644 --- a/src/sl/saveload.cpp +++ b/src/sl/saveload.cpp @@ -91,6 +91,7 @@ extern bool _sl_upstream_mode; namespace upstream_sl { void SlNullPointers(); + void SlNullPointerChunkByID(uint32_t); void SlLoadChunks(); void SlLoadChunkByID(uint32_t id); void SlLoadCheckChunks(); @@ -380,6 +381,14 @@ static void SlNullPointers() _sl.action = SLA_NULL; + /* Do upstream chunk tests before clearing version data */ + ring_buffer upstream_null_chunks; + for (auto &ch : ChunkHandlers()) { + if (ch.special_proc != nullptr && ch.special_proc(ch.id, CSLSO_PRE_NULL_PTRS) == CSLSOR_UPSTREAM_NULL_PTRS) { + upstream_null_chunks.push_back(ch.id); + } + } + /* We don't want any savegame conversion code to run * during NULLing; especially those that try to get * pointers from other pools. */ @@ -387,9 +396,14 @@ static void SlNullPointers() SlXvSetCurrentState(); for (auto &ch : ChunkHandlers()) { - if (ch.special_proc != nullptr) { - if (ch.special_proc(ch.id, CSLSO_PRE_PTRS) == CSLSOR_LOAD_CHUNK_CONSUMED) continue; + if (!upstream_null_chunks.empty() && upstream_null_chunks.front() == ch.id) { + upstream_null_chunks.pop_front(); + SlExecWithSlVersion(MAX_LOAD_SAVEGAME_VERSION, [&]() { + upstream_sl::SlNullPointerChunkByID(ch.id); + }); + continue; } + 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(); diff --git a/src/sl/saveload.h b/src/sl/saveload.h index 7f7a1b0878..00d7f93589 100644 --- a/src/sl/saveload.h +++ b/src/sl/saveload.h @@ -90,6 +90,7 @@ enum ChunkSaveLoadSpecialOp { CSLSO_PRE_LOAD, CSLSO_PRE_LOADCHECK, CSLSO_PRE_PTRS, + CSLSO_PRE_NULL_PTRS, CSLSO_SHOULD_SAVE_CHUNK, }; enum ChunkSaveLoadSpecialOpResult { @@ -97,6 +98,7 @@ enum ChunkSaveLoadSpecialOpResult { CSLSOR_LOAD_CHUNK_CONSUMED, CSLSOR_DONT_SAVE_CHUNK, CSLSOR_UPSTREAM_SAVE_CHUNK, + CSLSOR_UPSTREAM_NULL_PTRS, }; typedef ChunkSaveLoadSpecialOpResult ChunkSaveLoadSpecialProc(uint32_t, ChunkSaveLoadSpecialOp); @@ -189,6 +191,8 @@ namespace upstream_sl { SlFixPointerChunkByID(id); }); return CSLSOR_LOAD_CHUNK_CONSUMED; + case CSLSO_PRE_NULL_PTRS: + return CSLSOR_UPSTREAM_NULL_PTRS; case CSLSO_SHOULD_SAVE_CHUNK: return CSLSOR_UPSTREAM_SAVE_CHUNK; default: @@ -234,6 +238,9 @@ namespace upstream_sl { SlFixPointerChunkByID(id); }); return CSLSOR_LOAD_CHUNK_CONSUMED; + case CSLSO_PRE_NULL_PTRS: + if (!F::LoadUpstream()) return CSLSOR_NONE; + return CSLSOR_UPSTREAM_NULL_PTRS; case CSLSO_SHOULD_SAVE_CHUNK: return F::SaveUpstream() ? CSLSOR_UPSTREAM_SAVE_CHUNK : CSLSOR_NONE; default: