From dd674566a2aa85b4ed62dc4438777a97868e7ec8 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 31 Jan 2014 13:25:32 +0100 Subject: [PATCH] store content of containers in saved game files --- apps/openmw/mwclass/container.cpp | 23 ++++++ apps/openmw/mwclass/container.hpp | 8 ++ apps/openmw/mwworld/cellstore.cpp | 5 +- apps/openmw/mwworld/containerstore.cpp | 100 +++++++++++++++++++++++++ apps/openmw/mwworld/containerstore.hpp | 9 ++- apps/openmw/mwworld/livecellref.hpp | 12 ++- apps/openmw/mwworld/ptr.cpp | 8 ++ apps/openmw/mwworld/ptr.hpp | 2 + components/CMakeLists.txt | 2 +- components/esm/containerstate.cpp | 16 ++++ components/esm/containerstate.hpp | 20 +++++ components/esm/inventorystate.cpp | 60 +++++++++++++++ components/esm/inventorystate.hpp | 28 +++++++ components/esm/objectstate.cpp | 4 +- 14 files changed, 288 insertions(+), 9 deletions(-) create mode 100644 components/esm/containerstate.cpp create mode 100644 components/esm/containerstate.hpp create mode 100644 components/esm/inventorystate.cpp create mode 100644 components/esm/inventorystate.hpp diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index f89a6bce0f..546d6538c9 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -2,6 +2,7 @@ #include "container.hpp" #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -258,4 +259,26 @@ namespace MWClass return MWWorld::Ptr(&cell.mContainers.insert(*ref), &cell); } + + void Container::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) + const + { + const ESM::ContainerState& state2 = dynamic_cast (state); + + ensureCustomData (ptr); + + dynamic_cast (*ptr.getRefData().getCustomData()).mContainerStore. + readState (state2.mInventory); + } + + void Container::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) + const + { + ESM::ContainerState& state2 = dynamic_cast (state); + + ensureCustomData (ptr); + + dynamic_cast (*ptr.getRefData().getCustomData()).mContainerStore. + writeState (state2.mInventory); + } } diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 006e4bd223..c97867d35a 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -54,6 +54,14 @@ namespace MWClass virtual void unlock (const MWWorld::Ptr& ptr) const; ///< Unlock object + virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) + const; + ///< Read additional state from \a state into \a ptr. + + virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) + const; + ///< Write additional state from \a ptr into \a state. + static void registerSelf(); virtual std::string getModel(const MWWorld::Ptr &ptr) const; diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 77fdc971d8..154a2d1e7e 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -326,7 +327,7 @@ namespace MWWorld writeReferenceCollection (writer, mArmors); writeReferenceCollection (writer, mBooks); writeReferenceCollection (writer, mClothes); - writeReferenceCollection (writer, mContainers); + writeReferenceCollection (writer, mContainers); writeReferenceCollection (writer, mCreatures); writeReferenceCollection (writer, mDoors); writeReferenceCollection (writer, mIngreds); @@ -384,7 +385,7 @@ namespace MWWorld case ESM::REC_CONT: - readReferenceCollection (reader, mContainers, contentFileMap); + readReferenceCollection (reader, mContainers, contentFileMap); break; case ESM::REC_CREA: diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 0c4226f9bf..2d5a9bbd34 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -5,6 +5,8 @@ #include #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -55,6 +57,43 @@ namespace return MWWorld::Ptr(); } + + template + void getState (MWWorld::CellRefList& collection, const ESM::ObjectState& state) + { + if (!MWWorld::LiveCellRef::checkState (state)) + return; // not valid anymore with current content files -> skip + + const T *record = MWBase::Environment::get().getWorld()->getStore(). + get().search (state.mRef.mRefID); + + if (!record) + return; + + MWWorld::LiveCellRef ref (record); + ref.load (state); + ref.mRef.mRefNum.mContentFile = -1; + collection.mList.push_back (ref); + } + + template + void storeState (const MWWorld::LiveCellRef& ref, ESM::ObjectState& state) + { + ref.save (state); + } + + template + void storeStates (const MWWorld::CellRefList& collection, + std::vector > >& states) + { + for (typename MWWorld::CellRefList::List::const_iterator iter (collection.mList.begin()); + iter!=collection.mList.end(); ++iter) + { + ESM::ObjectState state; + storeState (*iter, state); + states.push_back (std::make_pair (state, std::make_pair (T::sRecordId, -1))); + } + } } const std::string MWWorld::ContainerStore::sGoldId = "gold_001"; @@ -495,6 +534,67 @@ MWWorld::Ptr MWWorld::ContainerStore::search (const std::string& id) return Ptr(); } +void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) const +{ + state.mItems.clear(); + + storeStates (potions, state.mItems); + storeStates (appas, state.mItems); + storeStates (armors, state.mItems); + storeStates (books, state.mItems); + storeStates (clothes, state.mItems); + storeStates (ingreds, state.mItems); + storeStates (lockpicks, state.mItems); + storeStates (miscItems, state.mItems); + storeStates (probes, state.mItems); + storeStates (repairs, state.mItems); + storeStates (weapons, state.mItems); + + state.mLights.clear(); + + for (MWWorld::CellRefList::List::const_iterator iter (lights.mList.begin()); + iter!=lights.mList.end(); ++iter) + { + ESM::LightState objectState; + storeState (*iter, objectState); + state.mLights.push_back (std::make_pair (objectState, -1)); + } +} + +void MWWorld::ContainerStore::readState (const ESM::InventoryState& state) +{ + clear(); + + for (std::vector > >::const_iterator + iter (state.mItems.begin()); iter!=state.mItems.end(); ++iter) + { + switch (iter->second.first) + { + case ESM::REC_ALCH: getState (potions, iter->first); break; + case ESM::REC_APPA: getState (appas, iter->first); break; + case ESM::REC_ARMO: getState (armors, iter->first); break; + case ESM::REC_BOOK: getState (books, iter->first); break; + case ESM::REC_CLOT: getState (clothes, iter->first); break; + case ESM::REC_INGR: getState (ingreds, iter->first); break; + case ESM::REC_LOCK: getState (lockpicks, iter->first); break; + case ESM::REC_MISC: getState (miscItems, iter->first); break; + case ESM::REC_PROB: getState (probes, iter->first); break; + case ESM::REC_REPA: getState (repairs, iter->first); break; + case ESM::REC_WEAP: getState (weapons, iter->first); break; + + default: + + std::cerr << "invalid item type in inventory state" << std::endl; + } + } + + for (std::vector >::const_iterator iter (state.mLights.begin()); + iter!=state.mLights.end(); ++iter) + { + getState (lights, iter->first); + } +} + MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container) : mType (-1), mMask (0), mContainer (container) diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 0a17287408..3bdefb1ec2 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -8,6 +8,7 @@ namespace ESM { struct InventoryList; + struct InventoryState; } namespace MWWorld @@ -123,6 +124,10 @@ namespace MWWorld Ptr search (const std::string& id); + void writeState (ESM::InventoryState& state) const; + + void readState (const ESM::InventoryState& state); + friend class ContainerStoreIterator; }; @@ -172,7 +177,7 @@ namespace MWWorld ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); - void copy (const ContainerStoreIterator& src); + void copy (const ContainerStoreIterator& src); void incType(); @@ -200,7 +205,7 @@ namespace MWWorld ContainerStoreIterator operator++ (int); - ContainerStoreIterator& operator= (const ContainerStoreIterator& rhs); + ContainerStoreIterator& operator= (const ContainerStoreIterator& rhs); bool isEqual (const ContainerStoreIterator& iter) const; diff --git a/apps/openmw/mwworld/livecellref.hpp b/apps/openmw/mwworld/livecellref.hpp index 46f49df78c..b2089fa7ae 100644 --- a/apps/openmw/mwworld/livecellref.hpp +++ b/apps/openmw/mwworld/livecellref.hpp @@ -35,6 +35,14 @@ namespace MWWorld /* Need this for the class to be recognized as polymorphic */ virtual ~LiveCellRefBase() { } + virtual void load (const ESM::ObjectState& state) = 0; + ///< Load state into a LiveCellRef, that has already been initialised with base and class. + /// + /// \attention Must not be called with an invalid \a state. + + virtual void save (ESM::ObjectState& state) const = 0; + ///< Save LiveCellRef state into \a state. + protected: void loadImp (const ESM::ObjectState& state); @@ -79,12 +87,12 @@ namespace MWWorld // The object that this instance is based on. const X* mBase; - void load (const ESM::ObjectState& state); + virtual void load (const ESM::ObjectState& state); ///< Load state into a LiveCellRef, that has already been initialised with base and class. /// /// \attention Must not be called with an invalid \a state. - void save (ESM::ObjectState& state) const; + virtual void save (ESM::ObjectState& state) const; ///< Save LiveCellRef state into \a state. static bool checkState (const ESM::ObjectState& state); diff --git a/apps/openmw/mwworld/ptr.cpp b/apps/openmw/mwworld/ptr.cpp index 384bd71b11..67bfe49007 100644 --- a/apps/openmw/mwworld/ptr.cpp +++ b/apps/openmw/mwworld/ptr.cpp @@ -21,6 +21,14 @@ const std::string& MWWorld::Ptr::getTypeName() const throw std::runtime_error("Can't get type name from an empty object."); } +MWWorld::LiveCellRefBase *MWWorld::Ptr::getBase() const +{ + if (!mRef) + throw std::runtime_error ("Can't access cell ref pointed to by null Ptr"); + + return mRef; +} + ESM::CellRef& MWWorld::Ptr::getCellRef() const { assert(mRef); diff --git a/apps/openmw/mwworld/ptr.hpp b/apps/openmw/mwworld/ptr.hpp index 8b70382d0a..1212619d03 100644 --- a/apps/openmw/mwworld/ptr.hpp +++ b/apps/openmw/mwworld/ptr.hpp @@ -52,6 +52,8 @@ namespace MWWorld throw std::runtime_error(str.str()); } + MWWorld::LiveCellRefBase *getBase() const; + ESM::CellRef& getCellRef() const; RefData& getRefData() const; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index f37a537c57..854d1f1aea 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -40,7 +40,7 @@ add_component_dir (esm loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter - savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate + savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate ) add_component_dir (misc diff --git a/components/esm/containerstate.cpp b/components/esm/containerstate.cpp new file mode 100644 index 0000000000..5dcf17733e --- /dev/null +++ b/components/esm/containerstate.cpp @@ -0,0 +1,16 @@ + +#include "containerstate.hpp" + +void ESM::ContainerState::load (ESMReader &esm) +{ + ObjectState::load (esm); + + mInventory.load (esm); +} + +void ESM::ContainerState::save (ESMWriter &esm, bool inInventory) const +{ + ObjectState::save (esm, inInventory); + + mInventory.save (esm); +} \ No newline at end of file diff --git a/components/esm/containerstate.hpp b/components/esm/containerstate.hpp new file mode 100644 index 0000000000..1ecf2b46ea --- /dev/null +++ b/components/esm/containerstate.hpp @@ -0,0 +1,20 @@ +#ifndef OPENMW_ESM_CONTAINERSTATE_H +#define OPENMW_ESM_CONTAINERSTATE_H + +#include "objectstate.hpp" +#include "inventorystate.hpp" + +namespace ESM +{ + // format 0, saved games only + + struct ContainerState : public ObjectState + { + InventoryState mInventory; + + virtual void load (ESMReader &esm); + virtual void save (ESMWriter &esm, bool inInventory = false) const; + }; +} + +#endif diff --git a/components/esm/inventorystate.cpp b/components/esm/inventorystate.cpp new file mode 100644 index 0000000000..4d8cbc6228 --- /dev/null +++ b/components/esm/inventorystate.cpp @@ -0,0 +1,60 @@ + +#include "inventorystate.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +namespace +{ + void read (ESM::ESMReader &esm, ESM::ObjectState& state, int& slot) + { + slot = -1; + esm.getHNOT (slot, "SLOT"); + + state.load (esm); + } + + void write (ESM::ESMWriter &esm, const ESM::ObjectState& state, unsigned int type, int slot) + { + esm.writeHNT ("IOBJ", type); + + if (slot!=-1) + esm.writeHNT ("SLOT", slot); + + state.save (esm, true); + } +} + +void ESM::InventoryState::load (ESMReader &esm) +{ + while (esm.isNextSub ("IOBJ")) + { + unsigned int id = 0; + esm.getHT (id); + + if (id==ESM::REC_LIGH) + { + LightState state; + int slot; + read (esm, state, slot); + mLights.push_back (std::make_pair (state, slot)); + } + else + { + ObjectState state; + int slot; + read (esm, state, slot); + mItems.push_back (std::make_pair (state, std::make_pair (id, slot))); + } + } +} + +void ESM::InventoryState::save (ESMWriter &esm) const +{ + for (std::vector > >::const_iterator iter (mItems.begin()); iter!=mItems.end(); ++iter) + write (esm, iter->first, iter->second.first, iter->second.second); + + for (std::vector >::const_iterator iter (mLights.begin()); + iter!=mLights.end(); ++iter) + write (esm, iter->first, ESM::REC_LIGH, iter->second); +} \ No newline at end of file diff --git a/components/esm/inventorystate.hpp b/components/esm/inventorystate.hpp new file mode 100644 index 0000000000..3cfffbccc9 --- /dev/null +++ b/components/esm/inventorystate.hpp @@ -0,0 +1,28 @@ +#ifndef OPENMW_ESM_INVENTORYSTATE_H +#define OPENMW_ESM_INVENTORYSTATE_H + +#include "objectstate.hpp" +#include "lightstate.hpp" + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + // format 0, saved games only + + /// \brief State for inventories and containers + struct InventoryState + { + // anything but lights (type, slot) + std::vector > > mItems; + + // lights (slot) + std::vector > mLights; + + virtual void load (ESMReader &esm); + virtual void save (ESMWriter &esm) const; + }; +} + +#endif diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index 6aa8205991..be00f3ef6e 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -20,9 +20,9 @@ void ESM::ObjectState::load (ESMReader &esm) mCount = 1; esm.getHNOT (mCount, "COUN"); - esm.getHNT (mPosition, "POS_", 24); + esm.getHNOT (mPosition, "POS_", 24); - esm.getHNT (mLocalRotation, "LROT", 12); + esm.getHNOT (mLocalRotation, "LROT", 12); } void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const