From 29c3a288e3525ca29cef275e66536dded60a3683 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 27 Jan 2014 13:27:42 +0100 Subject: [PATCH] load and save of reference in cells (without CustomData state) --- apps/openmw/engine.cpp | 9 +- apps/openmw/mwbase/world.hpp | 4 +- apps/openmw/mwstate/statemanagerimp.cpp | 40 +++++- apps/openmw/mwstate/statemanagerimp.hpp | 4 + apps/openmw/mwworld/cells.cpp | 9 +- apps/openmw/mwworld/cells.hpp | 3 +- apps/openmw/mwworld/cellstore.cpp | 163 +++++++++++++++++++++++- apps/openmw/mwworld/cellstore.hpp | 2 + apps/openmw/mwworld/worldimp.cpp | 5 +- apps/openmw/mwworld/worldimp.hpp | 3 +- components/esm/defs.hpp | 1 - 11 files changed, 222 insertions(+), 21 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 66dea4f1d..08f9cdb5c 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -127,7 +127,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) if(!paused && player.getClass().getCreatureStats(player).isDead()) MWBase::Environment::get().getStateManager()->endGame(); } - + // update world MWBase::Environment::get().getWorld()->update(frametime, paused); @@ -282,12 +282,7 @@ void OMW::Engine::setCell (const std::string& cellName) void OMW::Engine::addContentFile(const std::string& file) { - if (file.find_last_of(".") == std::string::npos) - { - throw std::runtime_error("Missing extension in content file!"); - } - - mContentFiles.push_back(file); + mContentFiles.push_back(file); } void OMW::Engine::setScriptsVerbosity(bool scriptsVerbosity) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 64104f2ba..cbf363581 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -2,6 +2,7 @@ #define GAME_MWBASE_WORLD_H #include +#include #include @@ -102,7 +103,8 @@ namespace MWBase virtual void write (ESM::ESMWriter& writer) const = 0; - virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; + virtual void readRecord (ESM::ESMReader& reader, int32_t type, + const std::map& contentFileMap) = 0; virtual OEngine::Render::Fader* getFader() = 0; ///< \todo remove this function. Rendering details should not be exposed. diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index a396d78c5..fb2d10bbf 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -6,6 +6,8 @@ #include #include +#include + #include #include @@ -43,6 +45,31 @@ void MWState::StateManager::cleanup (bool force) } } +std::map MWState::StateManager::buildContentFileIndexMap (const ESM::ESMReader& reader) + const +{ + const std::vector& current = + MWBase::Environment::get().getWorld()->getContentFiles(); + + const std::vector& prev = reader.getGameFiles(); + + std::map map; + + for (int iPrev = 0; iPrev (prev.size()); ++iPrev) + { + std::string id = Misc::StringUtils::lowerCase (prev[iPrev].name); + + for (int iCurrent = 0; iCurrent (current.size()); ++iCurrent) + if (id==Misc::StringUtils::lowerCase (current[iCurrent])) + { + map.insert (std::make_pair (iPrev, iCurrent)); + break; + } + } + + return map; +} + MWState::StateManager::StateManager (const boost::filesystem::path& saves, const std::string& game) : mQuitRequest (false), mAskLoadRecent(false), mState (State_NoGame), mCharacterManager (saves, game), mTimePlayed (0) { @@ -167,7 +194,16 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot slot = mCharacterManager.getCurrentCharacter()->updateSlot (slot, profile); std::ofstream stream (slot->mPath.string().c_str()); + ESM::ESMWriter writer; + + const std::vector& current = + MWBase::Environment::get().getWorld()->getContentFiles(); + + for (std::vector::const_iterator iter (current.begin()); iter!=current.end(); + ++iter) + writer.addMaster (*iter, 0); // not using the size information anyway -> use value of 0 + writer.setFormat (ESM::Header::CurrentFormat); writer.setRecordCount ( 1 // saved game header @@ -205,6 +241,8 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl ESM::ESMReader reader; reader.open (slot->mPath.string()); + std::map contentFileMap = buildContentFileIndexMap (reader); + while (reader.hasMoreRecs()) { ESM::NAME n = reader.getRecName(); @@ -237,7 +275,7 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl case ESM::REC_PLAY: case ESM::REC_CSTA: - MWBase::Environment::get().getWorld()->readRecord (reader, n.val); + MWBase::Environment::get().getWorld()->readRecord (reader, n.val, contentFileMap); break; case ESM::REC_GSCR: diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index d6bb7575d..46ade236b 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -1,6 +1,8 @@ #ifndef GAME_STATE_STATEMANAGER_H #define GAME_STATE_STATEMANAGER_H +#include + #include "../mwbase/statemanager.hpp" #include @@ -21,6 +23,8 @@ namespace MWState void cleanup (bool force = false); + std::map buildContentFileIndexMap (const ESM::ESMReader& reader) const; + public: StateManager (const boost::filesystem::path& saves, const std::string& game); diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 26ec14a6d..965c9fc5d 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -352,7 +352,8 @@ void MWWorld::Cells::write (ESM::ESMWriter& writer) const writeCell (writer, iter->second); } -bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, int32_t type) +bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, int32_t type, + const std::map& contentFileMap) { if (type==ESM::REC_CSTA) { @@ -373,7 +374,11 @@ bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, int32_t type) state.load (reader); cellStore->loadState (state); - reader.skipRecord(); + + if (cellStore->mState!=CellStore::State_Loaded) + cellStore->load (mStore, mReader); + + cellStore->readReferences (reader, contentFileMap); return true; } diff --git a/apps/openmw/mwworld/cells.hpp b/apps/openmw/mwworld/cells.hpp index 1b0fe6724..7ee8a3f6c 100644 --- a/apps/openmw/mwworld/cells.hpp +++ b/apps/openmw/mwworld/cells.hpp @@ -73,7 +73,8 @@ namespace MWWorld void write (ESM::ESMWriter& writer) const; - bool readRecord (ESM::ESMReader& reader, int32_t type); + bool readRecord (ESM::ESMReader& reader, int32_t type, + const std::map& contentFileMap); }; } diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index aea4e5b6a..88c241e1a 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -41,9 +41,6 @@ namespace { if (!collection.mList.empty()) { - // section header - writer.writeHNT ("CSEC", collection.mList.front().mBase->sRecordId); - // references for (typename MWWorld::CellRefList::List::const_iterator iter (collection.mList.begin()); @@ -55,12 +52,51 @@ namespace RecordType state; iter->save (state); - writer.startRecord (ESM::REC_OBJE); + writer.writeHNT ("OBJE", collection.mList.front().mBase->sRecordId); state.save (writer); - writer.endRecord (ESM::REC_OBJE); } } } + + template + void readReferenceCollection (ESM::ESMReader& reader, + MWWorld::CellRefList& collection, const std::map& contentFileMap) + { + const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); + + RecordType state; + state.load (reader); + + std::map::const_iterator iter = + contentFileMap.find (state.mRef.mRefNum.mContentFile); + + if (iter==contentFileMap.end()) + return; // content file has been removed -> skip + + state.mRef.mRefNum.mContentFile = iter->second; + + if (!MWWorld::LiveCellRef::checkState (state)) + return; // not valid anymore with current content files -> skip + + const T *record = esmStore.get().search (state.mRef.mRefID); + + if (!record) + return; + + for (typename MWWorld::CellRefList::List::iterator iter (collection.mList.begin()); + iter!=collection.mList.end(); ++iter) + if (iter->mRef.mRefNum==state.mRef.mRefNum) + { + // overwrite existing reference + iter->load (state); + return; + } + + // new reference + MWWorld::LiveCellRef ref (record); + ref.load (state); + collection.mList.push_back (ref); + } } namespace MWWorld @@ -304,4 +340,121 @@ namespace MWWorld writeReferenceCollection (writer, mStatics); writeReferenceCollection (writer, mWeapons); } + + void CellStore::readReferences (ESM::ESMReader& reader, + const std::map& contentFileMap) + { + while (reader.isNextSub ("OBJE")) + { + unsigned int id = 0; + reader.getHT (id); + + switch (id) + { + case ESM::REC_ACTI: + + readReferenceCollection (reader, mActivators, contentFileMap); + break; + + case ESM::REC_ALCH: + + readReferenceCollection (reader, mPotions, contentFileMap); + break; + + case ESM::REC_APPA: + + readReferenceCollection (reader, mAppas, contentFileMap); + break; + + case ESM::REC_ARMO: + + readReferenceCollection (reader, mArmors, contentFileMap); + break; + + case ESM::REC_BOOK: + + readReferenceCollection (reader, mBooks, contentFileMap); + break; + + case ESM::REC_CLOT: + + readReferenceCollection (reader, mClothes, contentFileMap); + break; + + case ESM::REC_CONT: + + readReferenceCollection (reader, mContainers, contentFileMap); + break; + + case ESM::REC_CREA: + + readReferenceCollection (reader, mCreatures, contentFileMap); + break; + + case ESM::REC_DOOR: + + readReferenceCollection (reader, mDoors, contentFileMap); + break; + + case ESM::REC_INGR: + + readReferenceCollection (reader, mIngreds, contentFileMap); + break; + + case ESM::REC_LEVC: + + readReferenceCollection (reader, mCreatureLists, contentFileMap); + break; + + case ESM::REC_LEVI: + + readReferenceCollection (reader, mItemLists, contentFileMap); + break; + + case ESM::REC_LIGH: + + readReferenceCollection (reader, mLights, contentFileMap); + break; + + case ESM::REC_LOCK: + + readReferenceCollection (reader, mLockpicks, contentFileMap); + break; + + case ESM::REC_MISC: + + readReferenceCollection (reader, mMiscItems, contentFileMap); + break; + + case ESM::REC_NPC_: + + readReferenceCollection (reader, mNpcs, contentFileMap); + break; + + case ESM::REC_PROB: + + readReferenceCollection (reader, mProbes, contentFileMap); + break; + + case ESM::REC_REPA: + + readReferenceCollection (reader, mRepairs, contentFileMap); + break; + + case ESM::REC_STAT: + + readReferenceCollection (reader, mStatics, contentFileMap); + break; + + case ESM::REC_WEAP: + + readReferenceCollection (reader, mWeapons, contentFileMap); + break; + + default: + + throw std::runtime_error ("unknown type in cell reference section"); + } + } + } } diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index feebfe90a..a4f219013 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -144,6 +144,8 @@ namespace MWWorld void writeReferences (ESM::ESMWriter& writer) const; + void readReferences (ESM::ESMReader& reader, const std::map& contentFileMap); + private: template diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 076fcfdb6..26cb34977 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -324,12 +324,13 @@ namespace MWWorld mPlayer->write (writer); } - void World::readRecord (ESM::ESMReader& reader, int32_t type) + void World::readRecord (ESM::ESMReader& reader, int32_t type, + const std::map& contentFileMap) { if (!mStore.readRecord (reader, type) && !mGlobalVariables.readRecord (reader, type) && !mPlayer->readRecord (reader, type) && - !mCells.readRecord (reader, type)) + !mCells.readRecord (reader, type, contentFileMap)) { throw std::runtime_error ("unknown record in saved game"); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 0fb4ed1ea..b99509322 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -179,7 +179,8 @@ namespace MWWorld virtual void write (ESM::ESMWriter& writer) const; - virtual void readRecord (ESM::ESMReader& reader, int32_t type); + virtual void readRecord (ESM::ESMReader& reader, int32_t type, + const std::map& contentFileMap); virtual OEngine::Render::Fader* getFader(); ///< \todo remove this function. Rendering details should not be exposed. diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 40ef7ecb6..1b0125e78 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -90,7 +90,6 @@ enum RecNameInts REC_GSCR = 0x52435347, REC_PLAY = 0x59414c50, REC_CSTA = 0x41545343, - REC_OBJE = 0x454a424f, REC_GMAP = 0x50414d47, // format 1