1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-05 06:40:09 +00:00
OpenMW/apps/openmw/mwworld/cellstore.hpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

385 lines
14 KiB
C++
Raw Normal View History

#ifndef GAME_MWWORLD_CELLSTORE_H
#define GAME_MWWORLD_CELLSTORE_H
#include <algorithm>
#include <map>
#include <memory>
2014-02-23 21:21:27 +01:00
#include <stdexcept>
2015-02-22 12:12:54 -06:00
#include <string>
2022-08-27 13:07:59 +02:00
#include <string_view>
#include <tuple>
2015-02-22 12:12:54 -06:00
#include <typeinfo>
#include <vector>
2014-02-23 20:11:05 +01:00
#include "cellreflist.hpp"
2013-04-04 11:23:17 +02:00
#include "livecellref.hpp"
2022-04-08 22:04:32 +02:00
#include <components/esm3/fogstate.hpp>
#include <components/misc/tuplemeta.hpp>
#include "ptr.hpp"
#include "timestamp.hpp"
namespace ESM
{
class ReadersCache;
struct Cell;
struct CellState;
struct CellId;
struct RefNum;
struct Activator;
struct Potion;
struct Apparatus;
struct Armor;
struct Book;
struct Clothing;
struct Container;
struct Creature;
struct Door;
struct Ingredient;
struct CreatureLevList;
struct ItemLevList;
struct Light;
struct Lockpick;
struct Miscellaneous;
struct NPC;
struct Probe;
struct Repair;
struct Static;
struct Weapon;
struct BodyPart;
}
namespace MWWorld
{
class ESMStore;
struct CellStoreImp;
using CellStoreTuple = std::tuple<CellRefList<ESM::Activator>, CellRefList<ESM::Potion>,
CellRefList<ESM::Apparatus>, CellRefList<ESM::Armor>, CellRefList<ESM::Book>, CellRefList<ESM::Clothing>,
CellRefList<ESM::Container>, CellRefList<ESM::Creature>, CellRefList<ESM::Door>, CellRefList<ESM::Ingredient>,
CellRefList<ESM::CreatureLevList>, CellRefList<ESM::ItemLevList>, CellRefList<ESM::Light>,
CellRefList<ESM::Lockpick>, CellRefList<ESM::Miscellaneous>, CellRefList<ESM::NPC>, CellRefList<ESM::Probe>,
CellRefList<ESM::Repair>, CellRefList<ESM::Static>, CellRefList<ESM::Weapon>, CellRefList<ESM::BodyPart>>;
2014-02-23 21:39:18 +01:00
/// \brief Mutable state of a cell
class CellStore
{
friend struct CellStoreImp;
2022-09-22 21:26:05 +03:00
public:
2014-02-23 21:39:18 +01:00
enum State
2022-09-22 21:26:05 +03:00
{
2014-02-23 21:39:18 +01:00
State_Unloaded,
State_Preloaded,
State_Loaded
2022-09-22 21:26:05 +03:00
};
private:
const MWWorld::ESMStore& mStore;
ESM::ReadersCache& mReaders;
2022-09-22 21:26:05 +03:00
// 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 10:21:12 +04:00
// Note this is nullptr until the cell is explored to save some memory
2022-04-08 22:04:32 +02:00
std::unique_ptr<ESM::FogState> mFogState;
2022-09-22 21:26:05 +03:00
const ESM::Cell* mCell;
2014-02-23 21:39:18 +01:00
State mState;
bool mHasState;
2014-02-23 21:39:18 +01:00
std::vector<std::string> mIds;
float mWaterLevel;
2022-09-22 21:26:05 +03:00
MWWorld::TimeStamp mLastRespawn;
2022-09-22 21:26:05 +03:00
template <typename T>
static constexpr std::size_t getTypeIndex()
2022-09-22 21:26:05 +03:00
{
static_assert(Misc::TupleHasType<CellRefList<T>, CellStoreTuple>::value);
return Misc::TupleTypeIndex<CellRefList<T>, CellStoreTuple>::value;
2022-09-22 21:26:05 +03:00
}
std::unique_ptr<CellStoreImp> mCellStoreImp;
std::vector<CellRefListBase*> mCellRefLists;
2022-09-22 21:26:05 +03:00
template <class T>
CellRefList<T>& get()
2022-09-22 21:26:05 +03:00
{
mHasState = true;
return static_cast<CellRefList<T>&>(*mCellRefLists[getTypeIndex<T>()]);
2022-09-22 21:26:05 +03:00
}
template <class T>
const CellRefList<T>& get() const
2022-09-22 21:26:05 +03:00
{
return static_cast<const CellRefList<T>&>(*mCellRefLists[getTypeIndex<T>()]);
2022-09-22 21:26:05 +03:00
}
2015-11-14 17:44:16 +01: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;
2022-09-22 21:26:05 +03:00
2015-11-14 17:44:16 +01:00
// Merged list of ref's currently in this cell - i.e. with added refs from mMovedHere, removed refs from
// mMovedToAnotherCell
std::vector<LiveCellRefBase*> mMergedRefs;
2022-09-22 21:26:05 +03:00
// 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);
2022-09-22 21:26:05 +03:00
2015-11-14 17:44:16 +01:00
/// Moves object from the given cell to this cell.
void moveFrom(const MWWorld::Ptr& object, MWWorld::CellStore* from);
2022-09-22 21:26:05 +03:00
2015-11-14 17:44:16 +01:00
/// Repopulate mMergedRefs.
void updateMergedRefs();
2022-09-22 21:26:05 +03:00
// (item, max charge)
typedef std::vector<std::pair<LiveCellRefBase*, float>> TRechargingItems;
TRechargingItems mRechargingItems;
2022-09-22 21:26:05 +03:00
bool mRechargingItemsUpToDate;
2022-09-22 21:26:05 +03:00
void updateRechargingItems();
void rechargeItems(float duration);
2021-06-23 23:13:59 +02:00
void checkItem(const Ptr& ptr);
2022-09-22 21:26:05 +03: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)
2022-09-22 21:26:05 +03:00
{
return !refdata.isDeletedByContentFile() && (cref.hasContentFile() || refdata.getCount() > 0);
2022-09-22 21:26:05 +03:00
}
2015-11-14 17:44:16 +01: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);
2022-09-22 21:26:05 +03:00
void rest(double hours);
void recharge(float duration);
2022-09-22 21:26:05 +03:00
2015-11-14 17:25:00 +01: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)
2022-09-22 21:26:05 +03:00
{
mHasState = true;
CellRefList<T>& list = get<T>();
LiveCellRefBase* ret = &list.insert(*ref);
updateMergedRefs();
return ret;
2022-09-22 21:26:05 +03:00
}
/// @param readerList The readers to use for loading of the cell on-demand.
CellStore(const ESM::Cell* cell, const MWWorld::ESMStore& store, ESM::ReadersCache& readers);
CellStore(CellStore&&);
~CellStore();
2022-09-22 21:26:05 +03:00
2014-02-23 21:39:18 +01:00
const ESM::Cell* getCell() const;
2022-09-22 21:26:05 +03:00
2014-02-23 21:39:18 +01:00
State getState() const;
2022-09-22 21:26:05 +03:00
const std::vector<std::string>& getPreloadedIds() const;
///< Get Ids of objects in this cell, only valid in State_Preloaded
2022-09-22 21:26:05 +03:00
bool hasState() const;
///< Does this cell have state that needs to be stored in a saved game file?
2022-09-22 21:26:05 +03:00
2022-08-27 13:07:59 +02:00
bool hasId(std::string_view id) const;
2014-02-23 21:39:18 +01:00
///< 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.
2022-09-22 21:26:05 +03:00
2022-08-27 13:07:59 +02:00
Ptr search(std::string_view id);
2014-02-23 21:39:18 +01:00
///< Will return an empty Ptr if cell is not loaded. Does not check references in
/// containers.
/// @note Triggers CellStore hasState flag.
2022-09-22 21:26:05 +03:00
2022-08-27 13:07:59 +02:00
ConstPtr searchConst(std::string_view id) const;
2014-02-23 21:39:18 +01:00
///< Will return an empty Ptr if cell is not loaded. Does not check references in
/// containers.
2015-12-18 14:33:15 +01:00
/// @note Does not trigger CellStore hasState flag.
2022-09-22 21:26:05 +03:00
2014-04-29 15:27:49 +02:00
Ptr searchViaActorId(int id);
2014-02-23 21:39:18 +01:00
///< Will return an empty Ptr if cell is not loaded.
2022-09-22 21:26:05 +03:00
Ptr searchViaRefNum(const ESM::RefNum& refNum);
2014-02-23 21:39:18 +01:00
///< Will return an empty Ptr if cell is not loaded. Does not check references in
/// containers.
/// @note Triggers CellStore hasState flag.
2022-09-22 21:26:05 +03:00
2014-02-23 21:39:18 +01:00
float getWaterLevel() const;
2022-09-22 21:26:05 +03:00
bool movedHere(const MWWorld::Ptr& ptr) const;
2022-09-22 21:26:05 +03:00
2014-02-23 21:39:18 +01:00
void setWaterLevel(float level);
2022-09-22 21:26:05 +03:00
2022-04-08 22:04:32 +02:00
void setFog(std::unique_ptr<ESM::FogState>&& fog);
///< \note Takes ownership of the pointer
2022-09-22 21:26:05 +03:00
ESM::FogState* getFog() const;
2022-09-22 21:26:05 +03:00
std::size_t count() const;
2014-02-23 21:39:18 +01:00
///< Return total number of references, including deleted ones.
2022-09-22 21:26:05 +03:00
void load();
2014-02-23 21:39:18 +01:00
///< Load references from content file.
2022-09-22 21:26:05 +03:00
void preload();
2014-02-23 21:39:18 +01:00
///< Build ID list from content file.
2022-09-22 21:26:05 +03:00
2015-12-17 23:59:18 +01:00
/// Call visitor (MWWorld::Ptr) for each reference. visitor must return a bool. Returning
2014-02-23 21:39:18 +01:00
/// false will abort the iteration.
2015-12-17 23:59:18 +01: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
2015-05-07 16:46:59 +02:00
/// unintended behaviour. \attention This function also lists deleted (count 0) objects! \return Iteration
2014-02-23 21:39:18 +01:00
/// completed?
template <class Visitor>
bool forEach(Visitor&& visitor)
2022-09-22 21:26:05 +03:00
{
if (mState != State_Loaded)
return false;
2022-09-22 21:26:05 +03:00
if (mMergedRefs.empty())
return true;
mHasState = true;
for (unsigned int i = 0; i < mMergedRefs.size(); ++i)
{
2015-11-14 17:44:16 +01:00
if (!isAccessible(mMergedRefs[i]->mData, mMergedRefs[i]->mRef))
continue;
if (!visitor(MWWorld::Ptr(mMergedRefs[i], this)))
return false;
}
return true;
2022-09-22 21:26:05 +03:00
}
/// Call visitor (MWWorld::ConstPtr) for each reference. visitor must return a bool. Returning
2015-11-14 17:25:00 +01:00
/// 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 Visitor>
bool forEachConst(Visitor&& visitor) const
2022-09-22 21:26:05 +03:00
{
if (mState != State_Loaded)
return false;
2022-09-22 21:26:05 +03:00
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;
2022-09-22 21:26:05 +03:00
}
return true;
2022-09-22 21:26:05 +03:00
}
/// Call visitor (ref) for each reference of given type. visitor must return a bool. Returning
2015-12-17 23:59:18 +01:00
/// false will abort the iteration.
/// \note Do not modify this cell (i.e. remove/add objects) during the forEach, doing this may result in
2015-12-17 23:59:18 +01:00
/// unintended behaviour. \attention This function also lists deleted (count 0) objects! \return Iteration
/// completed?
template <class T, class Visitor>
bool forEachType(Visitor& visitor)
2022-09-22 21:26:05 +03:00
{
2015-12-17 23:59:18 +01:00
if (mState != State_Loaded)
return false;
2022-09-22 21:26:05 +03:00
if (mMergedRefs.empty())
2015-12-17 23:59:18 +01:00
return true;
2014-02-23 21:39:18 +01:00
mHasState = true;
2015-12-06 18:13:04 +01:00
CellRefList<T>& list = get<T>();
2015-12-17 23:59:18 +01:00
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)))
2015-12-17 23:59:18 +01:00
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;
2022-09-22 21:26:05 +03:00
}
2015-12-06 21:58:25 +01: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 get<ESM::Door>(); }
inline const CellRefList<ESM::Static>& getReadOnlyStatics() const { return get<ESM::Static>(); }
2014-02-23 21:39:18 +01:00
bool isExterior() const;
2022-08-19 14:51:52 +00:00
bool isQuasiExterior() const;
2022-08-27 13:07:59 +02:00
Ptr searchInContainer(std::string_view id);
2014-02-23 21:39:18 +01:00
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 21:39:18 +01:00
void writeReferences(ESM::ESMWriter& writer) const;
struct GetCellStoreCallback
{
public:
2018-10-09 10:21:12 +04:00
///@note must return nullptr if the cell is not found
virtual CellStore* getCellStore(const ESM::CellId& cellId) = 0;
virtual ~GetCellStoreCallback() = default;
};
2014-02-23 21:39:18 +01:00
/// @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);
void respawn();
///< Check mLastRespawn and respawn references if necessary. This is a no-op if the cell is not loaded.
2014-02-23 21:39:18 +01:00
Ptr getMovedActor(int actorId) const;
2022-09-22 21:26:05 +03:00
private:
2014-02-23 21:39:18 +01:00
/// Run through references and store IDs
void listRefs();
2014-02-23 21:39:18 +01:00
void loadRefs();
2014-02-23 21:39:18 +01:00
void loadRef(ESM::CellRef& ref, bool deleted, std::map<ESM::RefNum, std::string>& refNumToID);
2014-02-23 21:39:18 +01:00
///< Make case-adjustments to \a ref and insert it into the respective container.
///
/// Invalid \a ref objects are silently dropped.
};
2014-02-23 21:21:27 +01:00
2014-02-23 21:39:18 +01:00
bool operator==(const CellStore& left, const CellStore& right);
bool operator!=(const CellStore& left, const CellStore& right);
}
#endif