diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 27980f0705..5e844ffae7 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -443,6 +443,8 @@ namespace MWBase virtual void applyDeferredPreviewRotationToPlayer(float dt) = 0; virtual void disableDeferredPreviewRotation() = 0; + virtual void saveLoaded() = 0; + virtual void setupPlayer() = 0; virtual void renderPlayer() = 0; diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index f605344bf7..93f75c6f10 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -505,6 +505,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str character->getPath().filename().string()); MWBase::Environment::get().getWindowManager()->setNewGame(false); + MWBase::Environment::get().getWorld()->saveLoaded(); MWBase::Environment::get().getWorld()->setupPlayer(); MWBase::Environment::get().getWorld()->renderPlayer(); MWBase::Environment::get().getWindowManager()->updatePlayer(); diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 5fa4684283..986c4f8580 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -48,6 +48,57 @@ namespace } } } + + std::vector getNPCsToReplace(const MWWorld::Store& factions, const MWWorld::Store& classes, const std::map& npcs) + { + // Cache first class from store - we will use it if current class is not found + std::string defaultCls; + auto it = classes.begin(); + if (it != classes.end()) + defaultCls = it->mId; + else + throw std::runtime_error("List of NPC classes is empty!"); + + // Validate NPCs for non-existing class and faction. + // We will replace invalid entries by fixed ones + std::vector npcsToReplace; + + for (auto it : npcs) + { + ESM::NPC npc = it.second; + bool changed = false; + + const std::string npcFaction = npc.mFaction; + if (!npcFaction.empty()) + { + const ESM::Faction *fact = factions.search(npcFaction); + if (!fact) + { + Log(Debug::Verbose) << "NPC '" << npc.mId << "' (" << npc.mName << ") has nonexistent faction '" << npc.mFaction << "', ignoring it."; + npc.mFaction.clear(); + npc.mNpdt.mRank = 0; + changed = true; + } + } + + std::string npcClass = npc.mClass; + if (!npcClass.empty()) + { + const ESM::Class *cls = classes.search(npcClass); + if (!cls) + { + Log(Debug::Verbose) << "NPC '" << npc.mId << "' (" << npc.mName << ") has nonexistent class '" << npc.mClass << "', using '" << defaultCls << "' class as replacement."; + npc.mClass = defaultCls; + changed = true; + } + } + + if (changed) + npcsToReplace.push_back(npc); + } + + return npcsToReplace; + } } namespace MWWorld @@ -218,49 +269,7 @@ int ESMStore::getRefCount(const std::string& id) const void ESMStore::validate() { - // Cache first class from store - we will use it if current class is not found - std::string defaultCls = ""; - Store::iterator it = mClasses.begin(); - if (it != mClasses.end()) - defaultCls = it->mId; - else - throw std::runtime_error("List of NPC classes is empty!"); - - // Validate NPCs for non-existing class and faction. - // We will replace invalid entries by fixed ones - std::vector npcsToReplace; - for (ESM::NPC npc : mNpcs) - { - bool changed = false; - - const std::string npcFaction = npc.mFaction; - if (!npcFaction.empty()) - { - const ESM::Faction *fact = mFactions.search(npcFaction); - if (!fact) - { - Log(Debug::Verbose) << "NPC '" << npc.mId << "' (" << npc.mName << ") has nonexistent faction '" << npc.mFaction << "', ignoring it."; - npc.mFaction.clear(); - npc.mNpdt.mRank = 0; - changed = true; - } - } - - std::string npcClass = npc.mClass; - if (!npcClass.empty()) - { - const ESM::Class *cls = mClasses.search(npcClass); - if (!cls) - { - Log(Debug::Verbose) << "NPC '" << npc.mId << "' (" << npc.mName << ") has nonexistent class '" << npc.mClass << "', using '" << defaultCls << "' class as replacement."; - npc.mClass = defaultCls; - changed = true; - } - } - - if (changed) - npcsToReplace.push_back(npc); - } + std::vector npcsToReplace = getNPCsToReplace(mFactions, mClasses, mNpcs.mStatic); for (const ESM::NPC &npc : npcsToReplace) { @@ -331,6 +340,14 @@ void ESMStore::validate() } } +void ESMStore::validateDynamic() +{ + std::vector npcsToReplace = getNPCsToReplace(mFactions, mClasses, mNpcs.mDynamic); + + for (const ESM::NPC &npc : npcsToReplace) + mNpcs.insert(npc); +} + int ESMStore::countSavedGameRecords() const { return 1 // DYNA (dynamic name counter) diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index 4d962b28c3..26f497a527 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -179,6 +179,9 @@ namespace MWWorld mNpcs.insert(*player); } + /// Validate entries in store after loading a save + void validateDynamic(); + void load(ESM::ESMReader &esm, Loading::Listener* listener); template diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 01b90e9078..ce09cf1122 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2473,6 +2473,11 @@ namespace MWWorld mRendering->getCamera()->adjustCameraDistance(dist); } + void World::saveLoaded() + { + mStore.validateDynamic(); + } + void World::setupPlayer() { const ESM::NPC *player = mStore.get().find("player"); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 23153a31c4..e2d3449304 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -549,6 +549,8 @@ namespace MWWorld void applyDeferredPreviewRotationToPlayer(float dt) override; void disableDeferredPreviewRotation() override; + void saveLoaded() override; + void setupPlayer() override; void renderPlayer() override;