From 68be9a95446f04e5db335e37debd5c0204ac9526 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Thu, 25 Jul 2024 22:22:23 +0200 Subject: [PATCH 1/2] Rebuild ESMStore indices before loading any cell or player state --- apps/openmw/mwworld/worldimp.cpp | 26 +++++++++++++++++++------- apps/openmw/mwworld/worldimp.hpp | 1 + 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0bd686ce7f..57fe28ed58 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -436,6 +436,7 @@ namespace MWWorld mLevitationEnabled = true; mPlayerTraveling = false; mPlayerInJail = false; + mIdsRebuilt = false; fillGlobalVariables(); } @@ -507,11 +508,13 @@ namespace MWWorld } break; case ESM::REC_PLAY: - // World::write always puts `ESM::REC_PLAY` between ESMStore (that contains dynamic records) - // and WorldModel (that can contain instances of dynamic records). Here we need to rebuild - // ESMStore index in order to be able to lookup dynamic records while loading the player and - // WorldModel. - mStore.rebuildIdsIndex(); + if (!mIdsRebuilt) + { + // FIME this can be removed when MinSupportedSaveGameFormatVersion > 32 + // Older saves have the player before the WorldModel. + mStore.rebuildIdsIndex(); + mIdsRebuilt = true; + } mStore.checkPlayer(); mPlayer->readRecord(reader, type); @@ -523,10 +526,19 @@ namespace MWWorld mWorldScene->preloadCellWithSurroundings(*getPlayerPtr().getCell()); } break; + case ESM::REC_CSTA: + // We need to rebuild the ESMStore index in order to be able to lookup dynamic records while loading the + // WorldModel and, afterwards, the player. + if (!mIdsRebuilt) + { + mStore.rebuildIdsIndex(); + mIdsRebuilt = true; + } + mWorldModel.readRecord(reader, type); + break; default: if (!mStore.readRecord(reader, type) && !mGlobalVariables.readRecord(reader, type) - && !mWeatherManager->readRecord(reader, type) && !mWorldModel.readRecord(reader, type) - && !mProjectileManager->readRecord(reader, type)) + && !mWeatherManager->readRecord(reader, type) && !mProjectileManager->readRecord(reader, type)) { throw std::runtime_error("unknown record in saved game"); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 20e33ad66c..f4c22e94d3 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -134,6 +134,7 @@ namespace MWWorld ///< only holds doors that are currently moving. 1 = opening, 2 = closing uint32_t mRandomSeed{}; + bool mIdsRebuilt{}; // not implemented World(const World&) = delete; From 5c4deb3f889a88f4e77f7ce441609ba2d6a59f6e Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Thu, 25 Jul 2024 22:37:44 +0200 Subject: [PATCH 2/2] Prevent older binaries from incorrectly loading newer saves --- apps/openmw/mwworld/worldimp.cpp | 4 +--- components/esm3/formatversion.hpp | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 57fe28ed58..bbf15312d3 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -508,10 +508,8 @@ namespace MWWorld } break; case ESM::REC_PLAY: - if (!mIdsRebuilt) + if (reader.getFormatVersion() <= ESM::MaxPlayerBeforeCellDataFormatVersion && !mIdsRebuilt) { - // FIME this can be removed when MinSupportedSaveGameFormatVersion > 32 - // Older saves have the player before the WorldModel. mStore.rebuildIdsIndex(); mIdsRebuilt = true; } diff --git a/components/esm3/formatversion.hpp b/components/esm3/formatversion.hpp index 36e43728e2..b09a42cae5 100644 --- a/components/esm3/formatversion.hpp +++ b/components/esm3/formatversion.hpp @@ -27,7 +27,8 @@ namespace ESM inline constexpr FormatVersion MaxActiveSpellSlotIndexFormatVersion = 27; inline constexpr FormatVersion MaxOldCountFormatVersion = 30; inline constexpr FormatVersion MaxActiveSpellTypeVersion = 31; - inline constexpr FormatVersion CurrentSaveGameFormatVersion = 32; + inline constexpr FormatVersion MaxPlayerBeforeCellDataFormatVersion = 32; + inline constexpr FormatVersion CurrentSaveGameFormatVersion = 33; inline constexpr FormatVersion MinSupportedSaveGameFormatVersion = 5; inline constexpr FormatVersion OpenMW0_48SaveGameFormatVersion = 21;