1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-16 00:19:56 +00:00
openmw-tes3mp/apps/openmw/mwworld/cellstore.hpp

565 lines
20 KiB
C++
Raw Normal View History

#ifndef GAME_MWWORLD_CELLSTORE_H
#define GAME_MWWORLD_CELLSTORE_H
#include <algorithm>
2014-02-23 20:21:27 +00:00
#include <stdexcept>
2015-02-22 18:12:54 +00:00
#include <string>
#include <typeinfo>
2015-07-25 02:14:22 +00:00
#include <map>
#include <memory>
2013-04-04 09:23:17 +00:00
#include "livecellref.hpp"
2014-02-23 19:11:05 +00:00
#include "cellreflist.hpp"
2015-07-25 02:14:22 +00:00
#include <components/esm/loadacti.hpp>
#include <components/esm/loadalch.hpp>
#include <components/esm/loadappa.hpp>
#include <components/esm/loadarmo.hpp>
#include <components/esm/loadbook.hpp>
#include <components/esm/loadclot.hpp>
#include <components/esm/loadcont.hpp>
#include <components/esm/loadcrea.hpp>
#include <components/esm/loaddoor.hpp>
#include <components/esm/loadingr.hpp>
#include <components/esm/loadlevlist.hpp>
#include <components/esm/loadligh.hpp>
#include <components/esm/loadlock.hpp>
#include <components/esm/loadprob.hpp>
#include <components/esm/loadrepa.hpp>
#include <components/esm/loadstat.hpp>
#include <components/esm/loadweap.hpp>
#include <components/esm/loadnpc.hpp>
#include <components/esm/loadmisc.hpp>
#include <components/esm/loadbody.hpp>
#include "timestamp.hpp"
#include "ptr.hpp"
namespace ESM
{
struct Cell;
struct CellState;
struct FogState;
struct CellId;
struct RefNum;
}
namespace MWWorld
{
class ESMStore;
2014-02-23 20:39:18 +00:00
/// \brief Mutable state of a cell
class CellStore
{
2014-02-23 20:39:18 +00:00
public:
enum State
{
State_Unloaded, State_Preloaded, State_Loaded
};
private:
const MWWorld::ESMStore& mStore;
std::vector<ESM::ESMReader>& mReader;
// Even though fog actually belongs to the player and not cells,
// it makes sense to store it here since we need it once for each cell.
2018-10-09 06:21:12 +00:00
// Note this is nullptr until the cell is explored to save some memory
std::shared_ptr<ESM::FogState> mFogState;
2014-02-23 20:39:18 +00:00
const ESM::Cell *mCell;
State mState;
bool mHasState;
2014-02-23 20:39:18 +00:00
std::vector<std::string> mIds;
float mWaterLevel;
MWWorld::TimeStamp mLastRespawn;
// List of refs owned by this cell
2014-02-23 20:39:18 +00:00
CellRefList<ESM::Activator> mActivators;
CellRefList<ESM::Potion> mPotions;
CellRefList<ESM::Apparatus> mAppas;
CellRefList<ESM::Armor> mArmors;
CellRefList<ESM::Book> mBooks;
CellRefList<ESM::Clothing> mClothes;
CellRefList<ESM::Container> mContainers;
CellRefList<ESM::Creature> mCreatures;
CellRefList<ESM::Door> mDoors;
CellRefList<ESM::Ingredient> mIngreds;
CellRefList<ESM::CreatureLevList> mCreatureLists;
CellRefList<ESM::ItemLevList> mItemLists;
CellRefList<ESM::Light> mLights;
CellRefList<ESM::Lockpick> mLockpicks;
CellRefList<ESM::Miscellaneous> mMiscItems;
CellRefList<ESM::NPC> mNpcs;
CellRefList<ESM::Probe> mProbes;
CellRefList<ESM::Repair> mRepairs;
CellRefList<ESM::Static> mStatics;
CellRefList<ESM::Weapon> mWeapons;
CellRefList<ESM::BodyPart> mBodyParts;
2014-02-23 20:39:18 +00:00
2015-11-14 16:44:16 +00:00
typedef std::map<LiveCellRefBase*, MWWorld::CellStore*> MovedRefTracker;
// References owned by a different cell that have been moved here.
// <reference, cell the reference originally came from>
MovedRefTracker mMovedHere;
// References owned by this cell that have been moved to another cell.
// <reference, cell the reference was moved to>
MovedRefTracker mMovedToAnotherCell;
// Merged list of ref's currently in this cell - i.e. with added refs from mMovedHere, removed refs from mMovedToAnotherCell
std::vector<LiveCellRefBase*> mMergedRefs;
// Get the Ptr for the given ref which originated from this cell (possibly moved to another cell at this point).
Ptr getCurrentPtr(MWWorld::LiveCellRefBase* ref);
2015-11-14 16:44:16 +00:00
/// Moves object from the given cell to this cell.
void moveFrom(const MWWorld::Ptr& object, MWWorld::CellStore* from);
/// Repopulate mMergedRefs.
void updateMergedRefs();
// (item, max charge)
typedef std::vector<std::pair<LiveCellRefBase*, float> > TRechargingItems;
TRechargingItems mRechargingItems;
bool mRechargingItemsUpToDate;
void updateRechargingItems();
void rechargeItems(float duration);
void checkItem(Ptr ptr);
// helper function for forEachInternal
2015-12-06 17:13:04 +00:00
template<class Visitor, class List>
bool forEachImp (Visitor& visitor, List& list)
{
for (typename List::List::iterator iter (list.mList.begin()); iter!=list.mList.end();
++iter)
{
if (!isAccessible(iter->mData, iter->mRef))
continue;
2015-12-06 17:13:04 +00:00
if (!visitor (MWWorld::Ptr(&*iter, this)))
return false;
}
return true;
}
// listing only objects owned by this cell. Internal use only, you probably want to use forEach() so that moved objects are accounted for.
2015-12-06 17:13:04 +00:00
template<class Visitor>
bool forEachInternal (Visitor& visitor)
{
return
2015-12-06 17:13:04 +00:00
forEachImp (visitor, mActivators) &&
forEachImp (visitor, mPotions) &&
forEachImp (visitor, mAppas) &&
forEachImp (visitor, mArmors) &&
forEachImp (visitor, mBooks) &&
forEachImp (visitor, mClothes) &&
forEachImp (visitor, mContainers) &&
forEachImp (visitor, mDoors) &&
forEachImp (visitor, mIngreds) &&
forEachImp (visitor, mItemLists) &&
forEachImp (visitor, mLights) &&
forEachImp (visitor, mLockpicks) &&
forEachImp (visitor, mMiscItems) &&
forEachImp (visitor, mProbes) &&
forEachImp (visitor, mRepairs) &&
forEachImp (visitor, mStatics) &&
forEachImp (visitor, mWeapons) &&
forEachImp (visitor, mBodyParts) &&
2015-12-06 17:13:04 +00:00
forEachImp (visitor, mCreatures) &&
forEachImp (visitor, mNpcs) &&
forEachImp (visitor, mCreatureLists);
}
/// @note If you get a linker error here, this means the given type can not be stored in a cell. The supported types are
/// defined at the bottom of this file.
template <class T>
CellRefList<T>& get();
2014-02-23 20:39:18 +00:00
public:
/// Should this reference be accessible to the outside world (i.e. to scripts / game logic)?
/// Determined based on the deletion flags. By default, objects deleted by content files are never accessible;
/// objects deleted by setCount(0) are still accessible *if* they came from a content file (needed for vanilla
/// scripting compatibility, and the fact that objects may be "un-deleted" in the original game).
static bool isAccessible(const MWWorld::RefData& refdata, const MWWorld::CellRef& cref)
{
return !refdata.isDeletedByContentFile() && (cref.hasContentFile() || refdata.getCount() > 0);
}
2015-11-14 16:44:16 +00:00
/// Moves object from this cell to the given cell.
/// @note automatically updates given cell by calling cellToMoveTo->moveFrom(...)
/// @note throws exception if cellToMoveTo == this
/// @return updated MWWorld::Ptr with the new CellStore pointer set.
MWWorld::Ptr moveTo(const MWWorld::Ptr& object, MWWorld::CellStore* cellToMoveTo);
2015-11-14 16:44:16 +00:00
void rest(double hours);
void recharge(float duration);
2015-11-14 16:25:00 +00:00
/// Make a copy of the given object and insert it into this cell.
/// @note If you get a linker error here, this means the given type can not be inserted into a cell.
/// The supported types are defined at the bottom of this file.
template <typename T>
LiveCellRefBase* insert(const LiveCellRef<T>* ref)
{
mHasState = true;
CellRefList<T>& list = get<T>();
LiveCellRefBase* ret = &list.insert(*ref);
updateMergedRefs();
return ret;
}
/// @param readerList The readers to use for loading of the cell on-demand.
CellStore (const ESM::Cell *cell_,
const MWWorld::ESMStore& store,
std::vector<ESM::ESMReader>& readerList);
2014-02-23 20:39:18 +00:00
const ESM::Cell *getCell() const;
State getState() const;
const std::vector<std::string>& getPreloadedIds() const;
///< Get Ids of objects in this cell, only valid in State_Preloaded
bool hasState() const;
///< Does this cell have state that needs to be stored in a saved game file?
2014-02-23 20:39:18 +00:00
bool hasId (const std::string& id) const;
///< May return true for deleted IDs when in preload state. Will return false, if cell is
/// unloaded.
/// @note Will not account for moved references which may exist in Loaded state. Use search() instead if the cell is loaded.
2014-02-23 20:39:18 +00:00
Ptr search (const std::string& id);
///< Will return an empty Ptr if cell is not loaded. Does not check references in
/// containers.
/// @note Triggers CellStore hasState flag.
2015-12-17 22:59:18 +00:00
ConstPtr searchConst (const std::string& id) const;
///< Will return an empty Ptr if cell is not loaded. Does not check references in
/// containers.
2015-12-18 13:33:15 +00:00
/// @note Does not trigger CellStore hasState flag.
2014-02-23 20:39:18 +00:00
2014-04-29 13:27:49 +00:00
Ptr searchViaActorId (int id);
///< Will return an empty Ptr if cell is not loaded.
Ptr searchViaRefNum (const ESM::RefNum& refNum);
///< Will return an empty Ptr if cell is not loaded. Does not check references in
/// containers.
/// @note Triggers CellStore hasState flag.
2014-02-23 20:39:18 +00:00
float getWaterLevel() const;
bool movedHere(const MWWorld::Ptr& ptr) const;
2014-02-23 20:39:18 +00:00
void setWaterLevel (float level);
void setFog (ESM::FogState* fog);
///< \note Takes ownership of the pointer
ESM::FogState* getFog () const;
std::size_t count() const;
2014-02-23 20:39:18 +00:00
///< Return total number of references, including deleted ones.
void load ();
2014-02-23 20:39:18 +00:00
///< Load references from content file.
void preload ();
2014-02-23 20:39:18 +00:00
///< Build ID list from content file.
2015-12-17 22:59:18 +00:00
/// Call visitor (MWWorld::Ptr) for each reference. visitor must return a bool. Returning
2014-02-23 20:39:18 +00:00
/// false will abort the iteration.
2015-12-17 22:59:18 +00:00
/// \note Prefer using forEachConst when possible.
/// \note Do not modify this cell (i.e. remove/add objects) during the forEach, doing this may result in unintended behaviour.
2015-05-07 14:46:59 +00:00
/// \attention This function also lists deleted (count 0) objects!
2014-02-23 20:39:18 +00:00
/// \return Iteration completed?
2015-12-06 17:13:04 +00:00
template<class Visitor>
bool forEach (Visitor&& visitor)
2014-02-23 20:39:18 +00:00
{
if (mState != State_Loaded)
return false;
2014-02-23 20:39:18 +00:00
if (mMergedRefs.empty())
return true;
mHasState = true;
for (unsigned int i=0; i<mMergedRefs.size(); ++i)
{
if (!isAccessible(mMergedRefs[i]->mData, mMergedRefs[i]->mRef))
continue;
2015-12-06 17:13:04 +00:00
if (!visitor(MWWorld::Ptr(mMergedRefs[i], this)))
return false;
}
return true;
}
2015-12-17 22:59:18 +00:00
/// Call visitor (MWWorld::ConstPtr) for each reference. visitor must return a bool. Returning
/// false will abort the iteration.
/// \note Do not modify this cell (i.e. remove/add objects) during the forEach, doing this may result in unintended behaviour.
2015-12-17 22:59:18 +00:00
/// \attention This function also lists deleted (count 0) objects!
/// \return Iteration completed?
template<class Visitor>
2018-03-13 22:49:08 +00:00
bool forEachConst (Visitor&& visitor) const
2015-12-17 22:59:18 +00:00
{
if (mState != State_Loaded)
return false;
for (unsigned int i=0; i<mMergedRefs.size(); ++i)
{
if (!isAccessible(mMergedRefs[i]->mData, mMergedRefs[i]->mRef))
continue;
if (!visitor(MWWorld::ConstPtr(mMergedRefs[i], this)))
return false;
}
return true;
}
/// Call visitor (ref) for each reference of given type. visitor must return a bool. Returning
/// false will abort the iteration.
/// \note Do not modify this cell (i.e. remove/add objects) during the forEach, doing this may result in unintended behaviour.
/// \attention This function also lists deleted (count 0) objects!
/// \return Iteration completed?
template <class T, class Visitor>
bool forEachType(Visitor& visitor)
{
if (mState != State_Loaded)
return false;
if (mMergedRefs.empty())
return true;
mHasState = true;
CellRefList<T>& list = get<T>();
for (typename CellRefList<T>::List::iterator it (list.mList.begin()); it!=list.mList.end(); ++it)
{
LiveCellRefBase* base = &*it;
if (mMovedToAnotherCell.find(base) != mMovedToAnotherCell.end())
continue;
if (!isAccessible(base->mData, base->mRef))
continue;
if (!visitor(MWWorld::Ptr(base, this)))
return false;
}
for (MovedRefTracker::const_iterator it = mMovedHere.begin(); it != mMovedHere.end(); ++it)
{
LiveCellRefBase* base = it->first;
if (dynamic_cast<LiveCellRef<T>*>(base))
if (!visitor(MWWorld::Ptr(base, this)))
return false;
}
return true;
}
2015-12-06 20:58:25 +00:00
// NOTE: does not account for moved references
// Should be phased out when we have const version of forEach
inline const CellRefList<ESM::Door>& getReadOnlyDoors() const
{
return mDoors;
}
inline const CellRefList<ESM::Static>& getReadOnlyStatics() const
{
return mStatics;
}
2014-02-23 20:39:18 +00:00
bool isExterior() const;
Ptr searchInContainer (const std::string& id);
void loadState (const ESM::CellState& state);
void saveState (ESM::CellState& state) const;
void writeFog (ESM::ESMWriter& writer) const;
void readFog (ESM::ESMReader& reader);
2014-02-23 20:39:18 +00:00
void writeReferences (ESM::ESMWriter& writer) const;
struct GetCellStoreCallback
{
public:
2018-10-09 06:21:12 +00:00
///@note must return nullptr if the cell is not found
virtual CellStore* getCellStore(const ESM::CellId& cellId) = 0;
virtual ~GetCellStoreCallback() = default;
};
/// @param callback to use for retrieving of additional CellStore objects by ID (required for resolving moved references)
void readReferences (ESM::ESMReader& reader, const std::map<int, int>& contentFileMap, GetCellStoreCallback* callback);
2014-02-23 20:39:18 +00:00
void respawn ();
///< Check mLastRespawn and respawn references if necessary. This is a no-op if the cell is not loaded.
2014-02-23 20:39:18 +00:00
private:
/// Run through references and store IDs
void listRefs();
2014-02-23 20:39:18 +00:00
void loadRefs();
2014-02-23 20:39:18 +00:00
void loadRef (ESM::CellRef& ref, bool deleted, std::map<ESM::RefNum, std::string>& refNumToID);
2014-02-23 20:39:18 +00:00
///< Make case-adjustments to \a ref and insert it into the respective container.
///
/// Invalid \a ref objects are silently dropped.
};
2014-02-23 20:21:27 +00:00
template<>
inline CellRefList<ESM::Activator>& CellStore::get<ESM::Activator>()
{
mHasState = true;
return mActivators;
}
template<>
inline CellRefList<ESM::Potion>& CellStore::get<ESM::Potion>()
{
mHasState = true;
return mPotions;
}
template<>
inline CellRefList<ESM::Apparatus>& CellStore::get<ESM::Apparatus>()
{
mHasState = true;
return mAppas;
}
template<>
inline CellRefList<ESM::Armor>& CellStore::get<ESM::Armor>()
{
mHasState = true;
return mArmors;
}
template<>
inline CellRefList<ESM::Book>& CellStore::get<ESM::Book>()
{
mHasState = true;
return mBooks;
}
template<>
inline CellRefList<ESM::Clothing>& CellStore::get<ESM::Clothing>()
{
mHasState = true;
return mClothes;
}
template<>
inline CellRefList<ESM::Container>& CellStore::get<ESM::Container>()
{
mHasState = true;
return mContainers;
}
template<>
inline CellRefList<ESM::Creature>& CellStore::get<ESM::Creature>()
{
mHasState = true;
return mCreatures;
}
template<>
inline CellRefList<ESM::Door>& CellStore::get<ESM::Door>()
{
mHasState = true;
return mDoors;
}
template<>
inline CellRefList<ESM::Ingredient>& CellStore::get<ESM::Ingredient>()
{
mHasState = true;
return mIngreds;
}
template<>
inline CellRefList<ESM::CreatureLevList>& CellStore::get<ESM::CreatureLevList>()
{
mHasState = true;
return mCreatureLists;
}
template<>
inline CellRefList<ESM::ItemLevList>& CellStore::get<ESM::ItemLevList>()
{
mHasState = true;
return mItemLists;
}
template<>
inline CellRefList<ESM::Light>& CellStore::get<ESM::Light>()
{
mHasState = true;
return mLights;
}
template<>
inline CellRefList<ESM::Lockpick>& CellStore::get<ESM::Lockpick>()
{
mHasState = true;
return mLockpicks;
}
template<>
inline CellRefList<ESM::Miscellaneous>& CellStore::get<ESM::Miscellaneous>()
{
mHasState = true;
return mMiscItems;
}
template<>
inline CellRefList<ESM::NPC>& CellStore::get<ESM::NPC>()
{
mHasState = true;
return mNpcs;
}
template<>
inline CellRefList<ESM::Probe>& CellStore::get<ESM::Probe>()
{
mHasState = true;
return mProbes;
}
template<>
inline CellRefList<ESM::Repair>& CellStore::get<ESM::Repair>()
{
mHasState = true;
return mRepairs;
}
template<>
inline CellRefList<ESM::Static>& CellStore::get<ESM::Static>()
{
mHasState = true;
return mStatics;
}
template<>
inline CellRefList<ESM::Weapon>& CellStore::get<ESM::Weapon>()
{
mHasState = true;
return mWeapons;
}
template<>
inline CellRefList<ESM::BodyPart>& CellStore::get<ESM::BodyPart>()
{
mHasState = true;
return mBodyParts;
}
2014-02-23 20:39:18 +00:00
bool operator== (const CellStore& left, const CellStore& right);
bool operator!= (const CellStore& left, const CellStore& right);
}
#endif