1 #ifndef GAME_MWWORLD_CELLSTORE_H
2 #define GAME_MWWORLD_CELLSTORE_H
3 
4 #include <algorithm>
5 #include <stdexcept>
6 #include <string>
7 #include <typeinfo>
8 #include <map>
9 #include <memory>
10 
11 #include "livecellref.hpp"
12 #include "cellreflist.hpp"
13 
14 #include <components/esm/loadacti.hpp>
15 #include <components/esm/loadalch.hpp>
16 #include <components/esm/loadappa.hpp>
17 #include <components/esm/loadarmo.hpp>
18 #include <components/esm/loadbook.hpp>
19 #include <components/esm/loadclot.hpp>
20 #include <components/esm/loadcont.hpp>
21 #include <components/esm/loadcrea.hpp>
22 #include <components/esm/loaddoor.hpp>
23 #include <components/esm/loadingr.hpp>
24 #include <components/esm/loadlevlist.hpp>
25 #include <components/esm/loadligh.hpp>
26 #include <components/esm/loadlock.hpp>
27 #include <components/esm/loadprob.hpp>
28 #include <components/esm/loadrepa.hpp>
29 #include <components/esm/loadstat.hpp>
30 #include <components/esm/loadweap.hpp>
31 #include <components/esm/loadnpc.hpp>
32 #include <components/esm/loadmisc.hpp>
33 #include <components/esm/loadbody.hpp>
34 
35 #include "timestamp.hpp"
36 #include "ptr.hpp"
37 
38 namespace ESM
39 {
40     struct Cell;
41     struct CellState;
42     struct FogState;
43     struct CellId;
44     struct RefNum;
45 }
46 
47 namespace MWWorld
48 {
49     class ESMStore;
50 
51     /// \brief Mutable state of a cell
52     class CellStore
53     {
54         public:
55 
56             enum State
57             {
58                 State_Unloaded, State_Preloaded, State_Loaded
59             };
60 
61         private:
62 
63             const MWWorld::ESMStore& mStore;
64             std::vector<ESM::ESMReader>& mReader;
65 
66             // Even though fog actually belongs to the player and not cells,
67             // it makes sense to store it here since we need it once for each cell.
68             // Note this is nullptr until the cell is explored to save some memory
69             std::shared_ptr<ESM::FogState> mFogState;
70 
71             const ESM::Cell *mCell;
72             State mState;
73             bool mHasState;
74             std::vector<std::string> mIds;
75             float mWaterLevel;
76 
77             MWWorld::TimeStamp mLastRespawn;
78 
79             // List of refs owned by this cell
80             CellRefList<ESM::Activator>         mActivators;
81             CellRefList<ESM::Potion>            mPotions;
82             CellRefList<ESM::Apparatus>         mAppas;
83             CellRefList<ESM::Armor>             mArmors;
84             CellRefList<ESM::Book>              mBooks;
85             CellRefList<ESM::Clothing>          mClothes;
86             CellRefList<ESM::Container>         mContainers;
87             CellRefList<ESM::Creature>          mCreatures;
88             CellRefList<ESM::Door>              mDoors;
89             CellRefList<ESM::Ingredient>        mIngreds;
90             CellRefList<ESM::CreatureLevList>   mCreatureLists;
91             CellRefList<ESM::ItemLevList>       mItemLists;
92             CellRefList<ESM::Light>             mLights;
93             CellRefList<ESM::Lockpick>          mLockpicks;
94             CellRefList<ESM::Miscellaneous>     mMiscItems;
95             CellRefList<ESM::NPC>               mNpcs;
96             CellRefList<ESM::Probe>             mProbes;
97             CellRefList<ESM::Repair>            mRepairs;
98             CellRefList<ESM::Static>            mStatics;
99             CellRefList<ESM::Weapon>            mWeapons;
100             CellRefList<ESM::BodyPart>          mBodyParts;
101 
102             typedef std::map<LiveCellRefBase*, MWWorld::CellStore*> MovedRefTracker;
103             // References owned by a different cell that have been moved here.
104             // <reference, cell the reference originally came from>
105             MovedRefTracker mMovedHere;
106             // References owned by this cell that have been moved to another cell.
107             // <reference, cell the reference was moved to>
108             MovedRefTracker mMovedToAnotherCell;
109 
110             // Merged list of ref's currently in this cell - i.e. with added refs from mMovedHere, removed refs from mMovedToAnotherCell
111             std::vector<LiveCellRefBase*> mMergedRefs;
112 
113             // Get the Ptr for the given ref which originated from this cell (possibly moved to another cell at this point).
114             Ptr getCurrentPtr(MWWorld::LiveCellRefBase* ref);
115 
116             /// Moves object from the given cell to this cell.
117             void moveFrom(const MWWorld::Ptr& object, MWWorld::CellStore* from);
118 
119             /// Repopulate mMergedRefs.
120             void updateMergedRefs();
121 
122             // (item, max charge)
123             typedef std::vector<std::pair<LiveCellRefBase*, float> > TRechargingItems;
124             TRechargingItems mRechargingItems;
125 
126             bool mRechargingItemsUpToDate;
127 
128             void updateRechargingItems();
129             void rechargeItems(float duration);
130             void checkItem(Ptr ptr);
131 
132             // helper function for forEachInternal
133             template<class Visitor, class List>
forEachImp(Visitor & visitor,List & list)134             bool forEachImp (Visitor& visitor, List& list)
135             {
136                 for (typename List::List::iterator iter (list.mList.begin()); iter!=list.mList.end();
137                     ++iter)
138                 {
139                     if (!isAccessible(iter->mData, iter->mRef))
140                         continue;
141                     if (!visitor (MWWorld::Ptr(&*iter, this)))
142                         return false;
143                 }
144                 return true;
145             }
146 
147             // listing only objects owned by this cell. Internal use only, you probably want to use forEach() so that moved objects are accounted for.
148             template<class Visitor>
forEachInternal(Visitor & visitor)149             bool forEachInternal (Visitor& visitor)
150             {
151                 return
152                     forEachImp (visitor, mActivators) &&
153                     forEachImp (visitor, mPotions) &&
154                     forEachImp (visitor, mAppas) &&
155                     forEachImp (visitor, mArmors) &&
156                     forEachImp (visitor, mBooks) &&
157                     forEachImp (visitor, mClothes) &&
158                     forEachImp (visitor, mContainers) &&
159                     forEachImp (visitor, mDoors) &&
160                     forEachImp (visitor, mIngreds) &&
161                     forEachImp (visitor, mItemLists) &&
162                     forEachImp (visitor, mLights) &&
163                     forEachImp (visitor, mLockpicks) &&
164                     forEachImp (visitor, mMiscItems) &&
165                     forEachImp (visitor, mProbes) &&
166                     forEachImp (visitor, mRepairs) &&
167                     forEachImp (visitor, mStatics) &&
168                     forEachImp (visitor, mWeapons) &&
169                     forEachImp (visitor, mBodyParts) &&
170                     forEachImp (visitor, mCreatures) &&
171                     forEachImp (visitor, mNpcs) &&
172                     forEachImp (visitor, mCreatureLists);
173             }
174 
175             /// @note If you get a linker error here, this means the given type can not be stored in a cell. The supported types are
176             /// defined at the bottom of this file.
177             template <class T>
178             CellRefList<T>& get();
179 
180         public:
181 
182             /// Should this reference be accessible to the outside world (i.e. to scripts / game logic)?
183             /// Determined based on the deletion flags. By default, objects deleted by content files are never accessible;
184             /// objects deleted by setCount(0) are still accessible *if* they came from a content file (needed for vanilla
185             /// scripting compatibility, and the fact that objects may be "un-deleted" in the original game).
isAccessible(const MWWorld::RefData & refdata,const MWWorld::CellRef & cref)186             static bool isAccessible(const MWWorld::RefData& refdata, const MWWorld::CellRef& cref)
187             {
188                 return !refdata.isDeletedByContentFile() && (cref.hasContentFile() || refdata.getCount() > 0);
189             }
190 
191             /// Moves object from this cell to the given cell.
192             /// @note automatically updates given cell by calling cellToMoveTo->moveFrom(...)
193             /// @note throws exception if cellToMoveTo == this
194             /// @return updated MWWorld::Ptr with the new CellStore pointer set.
195             MWWorld::Ptr moveTo(const MWWorld::Ptr& object, MWWorld::CellStore* cellToMoveTo);
196 
197             void rest(double hours);
198             void recharge(float duration);
199 
200             /// Make a copy of the given object and insert it into this cell.
201             /// @note If you get a linker error here, this means the given type can not be inserted into a cell.
202             /// The supported types are defined at the bottom of this file.
203             template <typename T>
insert(const LiveCellRef<T> * ref)204             LiveCellRefBase* insert(const LiveCellRef<T>* ref)
205             {
206                 mHasState = true;
207                 CellRefList<T>& list = get<T>();
208                 LiveCellRefBase* ret = &list.insert(*ref);
209                 updateMergedRefs();
210                 return ret;
211             }
212 
213             /// @param readerList The readers to use for loading of the cell on-demand.
214             CellStore (const ESM::Cell *cell_,
215                        const MWWorld::ESMStore& store,
216                        std::vector<ESM::ESMReader>& readerList);
217 
218             const ESM::Cell *getCell() const;
219 
220             State getState() const;
221 
222             const std::vector<std::string>& getPreloadedIds() const;
223             ///< Get Ids of objects in this cell, only valid in State_Preloaded
224 
225             bool hasState() const;
226             ///< Does this cell have state that needs to be stored in a saved game file?
227 
228             bool hasId (const std::string& id) const;
229             ///< May return true for deleted IDs when in preload state. Will return false, if cell is
230             /// unloaded.
231             /// @note Will not account for moved references which may exist in Loaded state. Use search() instead if the cell is loaded.
232 
233             Ptr search (const std::string& id);
234             ///< Will return an empty Ptr if cell is not loaded. Does not check references in
235             /// containers.
236             /// @note Triggers CellStore hasState flag.
237 
238             ConstPtr searchConst (const std::string& id) const;
239             ///< Will return an empty Ptr if cell is not loaded. Does not check references in
240             /// containers.
241             /// @note Does not trigger CellStore hasState flag.
242 
243             Ptr searchViaActorId (int id);
244             ///< Will return an empty Ptr if cell is not loaded.
245 
246             Ptr searchViaRefNum (const ESM::RefNum& refNum);
247             ///< Will return an empty Ptr if cell is not loaded. Does not check references in
248             /// containers.
249             /// @note Triggers CellStore hasState flag.
250 
251             float getWaterLevel() const;
252 
253             bool movedHere(const MWWorld::Ptr& ptr) const;
254 
255             void setWaterLevel (float level);
256 
257             void setFog (ESM::FogState* fog);
258             ///< \note Takes ownership of the pointer
259 
260             ESM::FogState* getFog () const;
261 
262             std::size_t count() const;
263             ///< Return total number of references, including deleted ones.
264 
265             void load ();
266             ///< Load references from content file.
267 
268             void preload ();
269             ///< Build ID list from content file.
270 
271             /// Call visitor (MWWorld::Ptr) for each reference. visitor must return a bool. Returning
272             /// false will abort the iteration.
273             /// \note Prefer using forEachConst when possible.
274             /// \note Do not modify this cell (i.e. remove/add objects) during the forEach, doing this may result in unintended behaviour.
275             /// \attention This function also lists deleted (count 0) objects!
276             /// \return Iteration completed?
277             template<class Visitor>
forEach(Visitor && visitor)278             bool forEach (Visitor&& visitor)
279             {
280                 if (mState != State_Loaded)
281                     return false;
282 
283                 if (mMergedRefs.empty())
284                     return true;
285 
286                 mHasState = true;
287 
288                 for (unsigned int i=0; i<mMergedRefs.size(); ++i)
289                 {
290                     if (!isAccessible(mMergedRefs[i]->mData, mMergedRefs[i]->mRef))
291                         continue;
292 
293                     if (!visitor(MWWorld::Ptr(mMergedRefs[i], this)))
294                         return false;
295                 }
296                 return true;
297             }
298 
299             /// Call visitor (MWWorld::ConstPtr) for each reference. visitor must return a bool. Returning
300             /// false will abort the iteration.
301             /// \note Do not modify this cell (i.e. remove/add objects) during the forEach, doing this may result in unintended behaviour.
302             /// \attention This function also lists deleted (count 0) objects!
303             /// \return Iteration completed?
304             template<class Visitor>
forEachConst(Visitor && visitor) const305             bool forEachConst (Visitor&& visitor) const
306             {
307                 if (mState != State_Loaded)
308                     return false;
309 
310                 for (unsigned int i=0; i<mMergedRefs.size(); ++i)
311                 {
312                     if (!isAccessible(mMergedRefs[i]->mData, mMergedRefs[i]->mRef))
313                         continue;
314 
315                     if (!visitor(MWWorld::ConstPtr(mMergedRefs[i], this)))
316                         return false;
317                 }
318                 return true;
319             }
320 
321 
322             /// Call visitor (ref) for each reference of given type. visitor must return a bool. Returning
323             /// false will abort the iteration.
324             /// \note Do not modify this cell (i.e. remove/add objects) during the forEach, doing this may result in unintended behaviour.
325             /// \attention This function also lists deleted (count 0) objects!
326             /// \return Iteration completed?
327             template <class T, class Visitor>
forEachType(Visitor & visitor)328             bool forEachType(Visitor& visitor)
329             {
330                 if (mState != State_Loaded)
331                     return false;
332 
333                 if (mMergedRefs.empty())
334                     return true;
335 
336                 mHasState = true;
337 
338                 CellRefList<T>& list = get<T>();
339 
340                 for (typename CellRefList<T>::List::iterator it (list.mList.begin()); it!=list.mList.end(); ++it)
341                 {
342                     LiveCellRefBase* base = &*it;
343                     if (mMovedToAnotherCell.find(base) != mMovedToAnotherCell.end())
344                         continue;
345                     if (!isAccessible(base->mData, base->mRef))
346                         continue;
347                     if (!visitor(MWWorld::Ptr(base, this)))
348                         return false;
349                 }
350 
351                 for (MovedRefTracker::const_iterator it = mMovedHere.begin(); it != mMovedHere.end(); ++it)
352                 {
353                     LiveCellRefBase* base = it->first;
354                     if (dynamic_cast<LiveCellRef<T>*>(base))
355                         if (!visitor(MWWorld::Ptr(base, this)))
356                             return false;
357                 }
358                 return true;
359             }
360 
361             // NOTE: does not account for moved references
362             // Should be phased out when we have const version of forEach
getReadOnlyDoors() const363             inline const CellRefList<ESM::Door>& getReadOnlyDoors() const
364             {
365                 return mDoors;
366             }
getReadOnlyStatics() const367             inline const CellRefList<ESM::Static>& getReadOnlyStatics() const
368             {
369                 return mStatics;
370             }
371 
372             bool isExterior() const;
373 
374             Ptr searchInContainer (const std::string& id);
375 
376             void loadState (const ESM::CellState& state);
377 
378             void saveState (ESM::CellState& state) const;
379 
380             void writeFog (ESM::ESMWriter& writer) const;
381 
382             void readFog (ESM::ESMReader& reader);
383 
384             void writeReferences (ESM::ESMWriter& writer) const;
385 
386             struct GetCellStoreCallback
387             {
388             public:
389                 ///@note must return nullptr if the cell is not found
390                 virtual CellStore* getCellStore(const ESM::CellId& cellId) = 0;
391                 virtual ~GetCellStoreCallback() = default;
392             };
393 
394             /// @param callback to use for retrieving of additional CellStore objects by ID (required for resolving moved references)
395             void readReferences (ESM::ESMReader& reader, const std::map<int, int>& contentFileMap, GetCellStoreCallback* callback);
396 
397             void respawn ();
398             ///< Check mLastRespawn and respawn references if necessary. This is a no-op if the cell is not loaded.
399 
400         private:
401 
402             /// Run through references and store IDs
403             void listRefs();
404 
405             void loadRefs();
406 
407             void loadRef (ESM::CellRef& ref, bool deleted, std::map<ESM::RefNum, std::string>& refNumToID);
408             ///< Make case-adjustments to \a ref and insert it into the respective container.
409             ///
410             /// Invalid \a ref objects are silently dropped.
411     };
412 
413     template<>
get()414     inline CellRefList<ESM::Activator>& CellStore::get<ESM::Activator>()
415     {
416         mHasState = true;
417         return mActivators;
418     }
419 
420     template<>
get()421     inline CellRefList<ESM::Potion>& CellStore::get<ESM::Potion>()
422     {
423         mHasState = true;
424         return mPotions;
425     }
426 
427     template<>
get()428     inline CellRefList<ESM::Apparatus>& CellStore::get<ESM::Apparatus>()
429     {
430         mHasState = true;
431         return mAppas;
432     }
433 
434     template<>
get()435     inline CellRefList<ESM::Armor>& CellStore::get<ESM::Armor>()
436     {
437         mHasState = true;
438         return mArmors;
439     }
440 
441     template<>
get()442     inline CellRefList<ESM::Book>& CellStore::get<ESM::Book>()
443     {
444         mHasState = true;
445         return mBooks;
446     }
447 
448     template<>
get()449     inline CellRefList<ESM::Clothing>& CellStore::get<ESM::Clothing>()
450     {
451         mHasState = true;
452         return mClothes;
453     }
454 
455     template<>
get()456     inline CellRefList<ESM::Container>& CellStore::get<ESM::Container>()
457     {
458         mHasState = true;
459         return mContainers;
460     }
461 
462     template<>
get()463     inline CellRefList<ESM::Creature>& CellStore::get<ESM::Creature>()
464     {
465         mHasState = true;
466         return mCreatures;
467     }
468 
469     template<>
get()470     inline CellRefList<ESM::Door>& CellStore::get<ESM::Door>()
471     {
472         mHasState = true;
473         return mDoors;
474     }
475 
476     template<>
get()477     inline CellRefList<ESM::Ingredient>& CellStore::get<ESM::Ingredient>()
478     {
479         mHasState = true;
480         return mIngreds;
481     }
482 
483     template<>
get()484     inline CellRefList<ESM::CreatureLevList>& CellStore::get<ESM::CreatureLevList>()
485     {
486         mHasState = true;
487         return mCreatureLists;
488     }
489 
490     template<>
get()491     inline CellRefList<ESM::ItemLevList>& CellStore::get<ESM::ItemLevList>()
492     {
493         mHasState = true;
494         return mItemLists;
495     }
496 
497     template<>
get()498     inline CellRefList<ESM::Light>& CellStore::get<ESM::Light>()
499     {
500         mHasState = true;
501         return mLights;
502     }
503 
504     template<>
get()505     inline CellRefList<ESM::Lockpick>& CellStore::get<ESM::Lockpick>()
506     {
507         mHasState = true;
508         return mLockpicks;
509     }
510 
511     template<>
get()512     inline CellRefList<ESM::Miscellaneous>& CellStore::get<ESM::Miscellaneous>()
513     {
514         mHasState = true;
515         return mMiscItems;
516     }
517 
518     template<>
get()519     inline CellRefList<ESM::NPC>& CellStore::get<ESM::NPC>()
520     {
521         mHasState = true;
522         return mNpcs;
523     }
524 
525     template<>
get()526     inline CellRefList<ESM::Probe>& CellStore::get<ESM::Probe>()
527     {
528         mHasState = true;
529         return mProbes;
530     }
531 
532     template<>
get()533     inline CellRefList<ESM::Repair>& CellStore::get<ESM::Repair>()
534     {
535         mHasState = true;
536         return mRepairs;
537     }
538 
539     template<>
get()540     inline CellRefList<ESM::Static>& CellStore::get<ESM::Static>()
541     {
542         mHasState = true;
543         return mStatics;
544     }
545 
546     template<>
get()547     inline CellRefList<ESM::Weapon>& CellStore::get<ESM::Weapon>()
548     {
549         mHasState = true;
550         return mWeapons;
551     }
552 
553     template<>
get()554     inline CellRefList<ESM::BodyPart>& CellStore::get<ESM::BodyPart>()
555     {
556         mHasState = true;
557         return mBodyParts;
558     }
559 
560     bool operator== (const CellStore& left, const CellStore& right);
561     bool operator!= (const CellStore& left, const CellStore& right);
562 }
563 
564 #endif
565