From 1c13a9037adc13a50e40c5f66650c5fe509b7a04 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 7 Dec 2013 13:17:28 +0100 Subject: [PATCH] save and load dynamic records --- apps/openmw/mwbase/mechanicsmanager.hpp | 36 ++++++------- apps/openmw/mwbase/world.hpp | 7 +++ .../mwmechanics/mechanicsmanagerimp.cpp | 8 +++ .../mwmechanics/mechanicsmanagerimp.hpp | 20 ++++---- apps/openmw/mwstate/statemanagerimp.cpp | 29 +++++++++-- apps/openmw/mwworld/esmstore.cpp | 50 +++++++++++++++++++ apps/openmw/mwworld/esmstore.hpp | 7 +++ apps/openmw/mwworld/store.hpp | 33 ++++++++++++ apps/openmw/mwworld/worldimp.cpp | 22 ++++++++ apps/openmw/mwworld/worldimp.hpp | 6 +++ 10 files changed, 189 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 3ab234de1..eeeab77e8 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -101,28 +101,30 @@ namespace MWBase float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange) = 0; ///< Perform a persuasion action on NPC - virtual void forceStateUpdate(const MWWorld::Ptr &ptr) = 0; - ///< Forces an object to refresh its animation state. + virtual void forceStateUpdate(const MWWorld::Ptr &ptr) = 0; + ///< Forces an object to refresh its animation state. - virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number=1) = 0; - ///< Run animation for a MW-reference. Calls to this function for references that are currently not - /// in the scene should be ignored. - /// - /// \param mode 0 normal, 1 immediate start, 2 immediate loop - /// \param count How many times the animation should be run + virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number=1) = 0; + ///< Run animation for a MW-reference. Calls to this function for references that are currently not + /// in the scene should be ignored. + /// + /// \param mode 0 normal, 1 immediate start, 2 immediate loop + /// \param count How many times the animation should be run - virtual void skipAnimation(const MWWorld::Ptr& ptr) = 0; - ///< Skip the animation for the given MW-reference for one frame. Calls to this function for - /// references that are currently not in the scene should be ignored. + virtual void skipAnimation(const MWWorld::Ptr& ptr) = 0; + ///< Skip the animation for the given MW-reference for one frame. Calls to this function for + /// references that are currently not in the scene should be ignored. - virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName) = 0; + virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName) = 0; - /// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently - /// paused we may want to do it manually (after equipping permanent enchantment) - virtual void updateMagicEffects (const MWWorld::Ptr& ptr) = 0; + /// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently + /// paused we may want to do it manually (after equipping permanent enchantment) + virtual void updateMagicEffects (const MWWorld::Ptr& ptr) = 0; - virtual void toggleAI() = 0; - virtual bool isAIActive() = 0; + virtual void toggleAI() = 0; + virtual bool isAIActive() = 0; + + virtual void playerLoaded() = 0; }; } diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 7d1678a11..717012f72 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -30,6 +30,7 @@ namespace OEngine namespace ESM { class ESMReader; + class ESMWriter; struct Position; struct Cell; struct Class; @@ -98,6 +99,12 @@ namespace MWBase virtual void clear() = 0; + virtual int countSavedGameRecords() const = 0; + + virtual void write (ESM::ESMWriter& writer) const = 0; + + virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; + virtual OEngine::Render::Fader* getFader() = 0; ///< \ŧodo remove this function. Rendering details should not be exposed. diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 1316baaeb..b6a7a7b75 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -701,4 +701,12 @@ namespace MWMechanics { return mAI; } + + void MechanicsManager::playerLoaded() + { + mUpdatePlayer = true; + mClassSelected = true; + mRaceSelected = true; + mAI = true; + } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index ec03b457b..ebc879d26 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -98,18 +98,20 @@ namespace MWMechanics void toLower(std::string npcFaction); ///< Perform a persuasion action on NPC - virtual void forceStateUpdate(const MWWorld::Ptr &ptr); + virtual void forceStateUpdate(const MWWorld::Ptr &ptr); - virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); - virtual void skipAnimation(const MWWorld::Ptr& ptr); - virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string &groupName); + virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); + virtual void skipAnimation(const MWWorld::Ptr& ptr); + virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string &groupName); - /// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently - /// paused we may want to do it manually (after equipping permanent enchantment) - virtual void updateMagicEffects (const MWWorld::Ptr& ptr); + /// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently + /// paused we may want to do it manually (after equipping permanent enchantment) + virtual void updateMagicEffects (const MWWorld::Ptr& ptr); - virtual void toggleAI(); - virtual bool isAIActive(); + virtual void toggleAI(); + virtual bool isAIActive(); + + virtual void playerLoaded(); }; } diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 293a9e232..94219b8fc 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -11,6 +11,7 @@ #include "../mwbase/journal.hpp" #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" @@ -103,8 +104,10 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot ESM::ESMWriter writer; writer.setFormat (ESM::Header::CurrentFormat); writer.setRecordCount ( - 1+ // saved game header - MWBase::Environment::get().getJournal()->countSavedGameRecords()); + 1 // saved game header + +MWBase::Environment::get().getJournal()->countSavedGameRecords() + +MWBase::Environment::get().getWorld()->countSavedGameRecords() + ); writer.save (stream); @@ -113,7 +116,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot writer.endRecord (ESM::REC_SAVE); MWBase::Environment::get().getJournal()->write (writer); - /// \todo write saved game data + MWBase::Environment::get().getWorld()->write (writer); writer.close(); @@ -149,6 +152,19 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl MWBase::Environment::get().getJournal()->readRecord (reader, n.val); break; + case ESM::REC_ALCH: + case ESM::REC_ARMO: + case ESM::REC_BOOK: + case ESM::REC_CLAS: + case ESM::REC_CLOT: + case ESM::REC_ENCH: + case ESM::REC_NPC_: + case ESM::REC_SPEL: + case ESM::REC_WEAP: + + MWBase::Environment::get().getWorld()->readRecord (reader, n.val); + break; + default: // ignore invalid records @@ -167,6 +183,13 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl MWBase::Environment::get().getWorld()->setupPlayer(); MWBase::Environment::get().getWorld()->renderPlayer(); MWBase::Environment::get().getWindowManager()->updatePlayer(); + MWBase::Environment::get().getMechanicsManager()->playerLoaded(); + + // for testing purpose only + ESM::Position pos; + pos.pos[0] = pos.pos[1] = pos.pos[2] = 0; + pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; + MWBase::Environment::get().getWorld()->changeToExteriorCell (pos); } MWState::Character *MWState::StateManager::getCurrentCharacter (bool create) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index f1bff11a2..cb4e441fc 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -139,4 +139,54 @@ void ESMStore::setUp() mAttributes.setUp(); } + int ESMStore::countSavedGameRecords() const + { + return + mPotions.getDynamicSize() + +mArmors.getDynamicSize() + +mBooks.getDynamicSize() + +mClasses.getDynamicSize() + +mClothes.getDynamicSize() + +mEnchants.getDynamicSize() + +mNpcs.getDynamicSize() + +mSpells.getDynamicSize() + +mWeapons.getDynamicSize(); + } + + void ESMStore::write (ESM::ESMWriter& writer) const + { + mPotions.write (writer); + mArmors.write (writer); + mBooks.write (writer); + mClasses.write (writer); + mClothes.write (writer); + mEnchants.write (writer); + mNpcs.write (writer); + mSpells.write (writer); + mWeapons.write (writer); + } + + bool ESMStore::readRecord (ESM::ESMReader& reader, int32_t type) + { + switch (type) + { + case ESM::REC_ALCH: + case ESM::REC_ARMO: + case ESM::REC_BOOK: + case ESM::REC_CLAS: + case ESM::REC_CLOT: + case ESM::REC_ENCH: + case ESM::REC_NPC_: + case ESM::REC_SPEL: + case ESM::REC_WEAP: + + mStores[type]->read (reader); + return true; + + default: + + return false; + } + } + } // end namespace diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index d5da5a866..e6730c307 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -209,6 +209,13 @@ namespace MWWorld // This method must be called once, after loading all master/plugin files. This can only be done // from the outside, so it must be public. void setUp(); + + int countSavedGameRecords() const; + + void write (ESM::ESMWriter& writer) const; + + bool readRecord (ESM::ESMReader& reader, int32_t type); + ///< \return Known type? }; template <> diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 233f2f702..df957408d 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -6,6 +6,8 @@ #include #include +#include + #include "recordcmp.hpp" namespace MWWorld @@ -18,10 +20,16 @@ namespace MWWorld virtual void listIdentifier(std::vector &list) const {} virtual size_t getSize() const = 0; + virtual int getDynamicSize() const { return 0; } virtual void load(ESM::ESMReader &esm, const std::string &id) = 0; virtual bool eraseStatic(const std::string &id) {return false;} virtual void clearDynamic() {} + + virtual void write (ESM::ESMWriter& writer) const {} + + virtual void read (ESM::ESMReader& reader) {} + ///< Read into dynamic storage }; template @@ -212,6 +220,11 @@ namespace MWWorld return mShared.size(); } + int getDynamicSize() const + { + return mDynamic.size(); + } + void listIdentifier(std::vector &list) const { list.reserve(list.size() + getSize()); typename std::vector::const_iterator it = mShared.begin(); @@ -290,6 +303,26 @@ namespace MWWorld bool erase(const T &item) { return erase(item.mId); } + + void write (ESM::ESMWriter& writer) const + { + for (typename Dynamic::const_iterator iter (mDynamic.begin()); iter!=mDynamic.end(); + ++iter) + { + writer.startRecord (T::sRecordId); + writer.writeHNString ("NAME", iter->second.mId); + iter->second.save (writer); + writer.endRecord (T::sRecordId); + } + } + + void read (ESM::ESMReader& reader) + { + T record; + record.mId = reader.getHNString ("NAME"); + record.load (reader); + insert (record); + } }; template <> diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 82b2301db..bfcd0ae1c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -282,7 +282,10 @@ namespace MWWorld mWorldScene->changeToVoid(); if (mPlayer) + { + mPlayer->setCell (0); mPlayer->getPlayer().getRefData() = RefData(); + } mStore.clearDynamic(); mStore.setUp(); @@ -299,6 +302,25 @@ namespace MWWorld mFacedDistance = FLT_MAX; } + int World::countSavedGameRecords() const + { + return mStore.countSavedGameRecords(); + } + + void World::write (ESM::ESMWriter& writer) const + { + mStore.write (writer); + } + + void World::readRecord (ESM::ESMReader& reader, int32_t type) + { + if (!mStore.readRecord (reader, type)) + { + /// \todo handle other world state records + + } + } + void World::ensureNeededRecords() { if (!mStore.get().search("sCompanionShare")) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index b09b42e94..40245b78d 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -171,6 +171,12 @@ namespace MWWorld virtual void clear(); + virtual int countSavedGameRecords() const; + + virtual void write (ESM::ESMWriter& writer) const; + + virtual void readRecord (ESM::ESMReader& reader, int32_t type); + virtual OEngine::Render::Fader* getFader(); ///< \ŧodo remove this function. Rendering details should not be exposed.