mirror of
https://github.com/OpenMW/openmw.git
synced 2025-05-16 16:41:28 +00:00
Cannot load a cell yet, but getting more necessary parts in
This commit is contained in:
parent
cddf6f29d6
commit
08b68fcd48
12 changed files with 324 additions and 93 deletions
|
@ -47,5 +47,7 @@ namespace MWClass
|
||||||
Repair::registerSelf();
|
Repair::registerSelf();
|
||||||
Static::registerSelf();
|
Static::registerSelf();
|
||||||
BodyPart::registerSelf();
|
BodyPart::registerSelf();
|
||||||
|
|
||||||
|
ESM4Static::registerSelf();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "static.hpp"
|
#include "static.hpp"
|
||||||
|
|
||||||
#include <components/esm3/loadstat.hpp>
|
#include <components/esm3/loadstat.hpp>
|
||||||
|
#include <components/esm4/loadstat.hpp>
|
||||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||||
|
|
||||||
#include "../mwphysics/physicssystem.hpp"
|
#include "../mwphysics/physicssystem.hpp"
|
||||||
|
@ -63,4 +64,53 @@ namespace MWClass
|
||||||
|
|
||||||
return MWWorld::Ptr(cell.insert(ref), &cell);
|
return MWWorld::Ptr(cell.insert(ref), &cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ESM4Static::ESM4Static()
|
||||||
|
: MWWorld::RegisteredClass<ESM4Static>(ESM4::Static::sRecordId)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESM4Static ::insertObjectRendering(
|
||||||
|
const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const
|
||||||
|
{
|
||||||
|
if (!model.empty())
|
||||||
|
{
|
||||||
|
renderingInterface.getObjects().insertModel(ptr, model);
|
||||||
|
ptr.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Static);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESM4Static::insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation,
|
||||||
|
MWPhysics::PhysicsSystem& physics) const
|
||||||
|
{
|
||||||
|
insertObjectPhysics(ptr, model, rotation, physics);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESM4Static::insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation,
|
||||||
|
MWPhysics::PhysicsSystem& physics) const
|
||||||
|
{
|
||||||
|
physics.addObject(ptr, model, rotation, MWPhysics::CollisionType_World);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ESM4Static::getModel(const MWWorld::ConstPtr& ptr) const
|
||||||
|
{
|
||||||
|
return getClassModel<ESM4::Static>(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view ESM4Static ::getName(const MWWorld::ConstPtr& ptr) const
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ESM4Static::hasToolTip(const MWWorld::ConstPtr& ptr) const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MWWorld::Ptr ESM4Static::copyToCellImpl(const MWWorld::ConstPtr& ptr, MWWorld::CellStore& cell) const
|
||||||
|
{
|
||||||
|
const MWWorld::LiveCellRef<ESM4::Static>* ref = ptr.get<ESM4::Static>();
|
||||||
|
|
||||||
|
return MWWorld::Ptr(cell.insert(ref), &cell);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,33 @@ namespace MWClass
|
||||||
|
|
||||||
std::string getModel(const MWWorld::ConstPtr& ptr) const override;
|
std::string getModel(const MWWorld::ConstPtr& ptr) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ESM4Static : public MWWorld::RegisteredClass<ESM4Static>
|
||||||
|
{
|
||||||
|
friend MWWorld::RegisteredClass<ESM4Static>;
|
||||||
|
|
||||||
|
ESM4Static();
|
||||||
|
|
||||||
|
MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr& ptr, MWWorld::CellStore& cell) const override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void insertObjectRendering(const MWWorld::Ptr& ptr, const std::string& model,
|
||||||
|
MWRender::RenderingInterface& renderingInterface) const override;
|
||||||
|
///< Add reference into a cell for rendering
|
||||||
|
|
||||||
|
void insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation,
|
||||||
|
MWPhysics::PhysicsSystem& physics) const override;
|
||||||
|
void insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation,
|
||||||
|
MWPhysics::PhysicsSystem& physics) const override;
|
||||||
|
|
||||||
|
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
|
||||||
|
///< \return name or ID; can return an empty string.
|
||||||
|
|
||||||
|
bool hasToolTip(const MWWorld::ConstPtr& ptr) const override;
|
||||||
|
///< @return true if this object has a tooltip when focused (default implementation: true)
|
||||||
|
|
||||||
|
std::string getModel(const MWWorld::ConstPtr& ptr) const override;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -39,6 +39,8 @@
|
||||||
#include <components/esm3/npcstate.hpp>
|
#include <components/esm3/npcstate.hpp>
|
||||||
#include <components/esm3/objectstate.hpp>
|
#include <components/esm3/objectstate.hpp>
|
||||||
#include <components/esm3/readerscache.hpp>
|
#include <components/esm3/readerscache.hpp>
|
||||||
|
#include <components/esm4/loadrefr.hpp>
|
||||||
|
#include <components/esm4/loadstat.hpp>
|
||||||
#include <components/misc/tuplehelpers.hpp>
|
#include <components/misc/tuplehelpers.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
@ -503,18 +505,22 @@ namespace MWWorld
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CellStore::CellStore(const ESM::Cell* cell, const MWWorld::ESMStore& esmStore, ESM::ReadersCache& readers)
|
CellStore::CellStore(CellVariant cell, const MWWorld::ESMStore& esmStore, ESM::ReadersCache& readers)
|
||||||
: mStore(esmStore)
|
: mStore(esmStore)
|
||||||
, mReaders(readers)
|
, mReaders(readers)
|
||||||
, mCell(cell)
|
, mCellVariant(cell)
|
||||||
, mState(State_Unloaded)
|
, mState(State_Unloaded)
|
||||||
, mHasState(false)
|
, mHasState(false)
|
||||||
, mLastRespawn(0, 0)
|
, mLastRespawn(0, 0)
|
||||||
, mCellStoreImp(std::make_unique<CellStoreImp>())
|
, mCellStoreImp(std::make_unique<CellStoreImp>())
|
||||||
, mRechargingItemsUpToDate(false)
|
, mRechargingItemsUpToDate(false)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
mCell = mCellVariant.getEsm3();
|
||||||
|
|
||||||
std::apply([this](auto&... x) { (CellStoreImp::assignStoreToIndex(*this, x), ...); }, mCellStoreImp->mRefLists);
|
std::apply([this](auto&... x) { (CellStoreImp::assignStoreToIndex(*this, x), ...); }, mCellStoreImp->mRefLists);
|
||||||
mWaterLevel = cell->mWater;
|
if (mCell)
|
||||||
|
mWaterLevel = mCell->mWater;
|
||||||
}
|
}
|
||||||
|
|
||||||
CellStore::~CellStore() = default;
|
CellStore::~CellStore() = default;
|
||||||
|
@ -525,6 +531,24 @@ namespace MWWorld
|
||||||
return mCell;
|
return mCell;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CellVariant CellStore::getCellVariant() const
|
||||||
|
{
|
||||||
|
return mCellVariant;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view CellStore::getEditorName() const
|
||||||
|
{
|
||||||
|
const ESM4::Cell* cell4 = mCellVariant.getEsm4();
|
||||||
|
if (cell4)
|
||||||
|
{
|
||||||
|
return cell4->mEditorId;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return mCellVariant.getEsm3()->mName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CellStore::State CellStore::getState() const
|
CellStore::State CellStore::getState() const
|
||||||
{
|
{
|
||||||
return mState;
|
return mState;
|
||||||
|
@ -735,7 +759,24 @@ namespace MWWorld
|
||||||
|
|
||||||
void CellStore::loadRefs()
|
void CellStore::loadRefs()
|
||||||
{
|
{
|
||||||
assert(mCell);
|
assert(mCellVariant.getEsm4() || mCellVariant.getEsm3());
|
||||||
|
const ESM4::Cell* cell4 = mCellVariant.getEsm4();
|
||||||
|
if (cell4)
|
||||||
|
{
|
||||||
|
|
||||||
|
auto& refs = MWBase::Environment::get().getWorld()->getStore().get<ESM4::Reference>();
|
||||||
|
auto it = refs.begin();
|
||||||
|
|
||||||
|
while (it != refs.end())
|
||||||
|
{
|
||||||
|
if (it->mParent == cell4->mId)
|
||||||
|
{
|
||||||
|
loadRef(*it, false);
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (mCell->mContextList.empty())
|
if (mCell->mContextList.empty())
|
||||||
return; // this is a dynamically generated cell -> skipping.
|
return; // this is a dynamically generated cell -> skipping.
|
||||||
|
@ -795,12 +836,15 @@ namespace MWWorld
|
||||||
|
|
||||||
bool CellStore::isExterior() const
|
bool CellStore::isExterior() const
|
||||||
{
|
{
|
||||||
return mCell->isExterior();
|
auto cell3 = mCellVariant.getEsm3();
|
||||||
|
return cell3 ? cell3->isExterior() : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CellStore::isQuasiExterior() const
|
bool CellStore::isQuasiExterior() const
|
||||||
{
|
{
|
||||||
return (mCell->mData.mFlags & ESM::Cell::QuasiEx) != 0;
|
auto cell3 = mCellVariant.getEsm3();
|
||||||
|
|
||||||
|
return cell3 ? (mCell->mData.mFlags & ESM::Cell::QuasiEx) != 0 : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ptr CellStore::searchInContainer(const ESM::RefId& id)
|
Ptr CellStore::searchInContainer(const ESM::RefId& id)
|
||||||
|
@ -823,6 +867,28 @@ namespace MWWorld
|
||||||
return Ptr();
|
return Ptr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static void loadRefESM4(
|
||||||
|
const MWWorld::ESMStore& store, const ESM4::Reference& ref, MWWorld::CellRefList<T>& storeIn, bool deleted)
|
||||||
|
{
|
||||||
|
if constexpr (ESM::isESM4Rec(T::sRecordId))
|
||||||
|
{
|
||||||
|
// storeIn.load(ref, deleted, store);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CellStore::loadRef(const ESM4::Reference& ref, bool deleted)
|
||||||
|
{
|
||||||
|
const MWWorld::ESMStore& store = mStore;
|
||||||
|
|
||||||
|
ESM::RecNameInts foundType = static_cast<ESM::RecNameInts>(store.find(ref.mBaseObj));
|
||||||
|
|
||||||
|
Misc::tupleForEach(this->mCellStoreImp->mRefLists, [&ref, &deleted, &store, foundType](auto& x) {
|
||||||
|
recNameSwitcher(
|
||||||
|
x, foundType, [&ref, &deleted, &store](auto& storeIn) { loadRefESM4(store, ref, storeIn, deleted); });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void CellStore::loadRef(ESM::CellRef& ref, bool deleted, std::map<ESM::RefNum, ESM::RefId>& refNumToID)
|
void CellStore::loadRef(ESM::CellRef& ref, bool deleted, std::map<ESM::RefNum, ESM::RefId>& refNumToID)
|
||||||
{
|
{
|
||||||
const MWWorld::ESMStore& store = mStore;
|
const MWWorld::ESMStore& store = mStore;
|
||||||
|
@ -999,8 +1065,8 @@ namespace MWWorld
|
||||||
Log(Debug::Warning) << "Warning: Dropping moved ref tag for " << movedRef.getCellRef().getRefId()
|
Log(Debug::Warning) << "Warning: Dropping moved ref tag for " << movedRef.getCellRef().getRefId()
|
||||||
<< " (target cell " << movedTo.mWorldspace
|
<< " (target cell " << movedTo.mWorldspace
|
||||||
<< " no longer exists). Reference moved back to its original location.";
|
<< " no longer exists). Reference moved back to its original location.";
|
||||||
// Note by dropping tag the object will automatically re-appear in its original cell, though potentially
|
// Note by dropping tag the object will automatically re-appear in its original cell, though
|
||||||
// at inapproriate coordinates. Restore original coordinates:
|
// potentially at inapproriate coordinates. Restore original coordinates:
|
||||||
movedRef.getRefData().setPosition(movedRef.getCellRef().getPosition());
|
movedRef.getRefData().setPosition(movedRef.getCellRef().getPosition());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1016,14 +1082,17 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const CellStore& left, const CellStore& right)
|
bool CellStore::operator==(const CellStore& right) const
|
||||||
{
|
{
|
||||||
return left.getCell()->getCellId() == right.getCell()->getCellId();
|
auto cell4Left = mCellVariant.getEsm4();
|
||||||
}
|
auto cell4Right = right.mCellVariant.getEsm4();
|
||||||
|
|
||||||
bool operator!=(const CellStore& left, const CellStore& right)
|
if (!cell4Left && !cell4Right)
|
||||||
{
|
return getCell()->getCellId() == right.getCell()->getCellId();
|
||||||
return !(left == right);
|
else if (cell4Left && cell4Right)
|
||||||
|
return cell4Left->mId == cell4Right->mId;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CellStore::setFog(std::unique_ptr<ESM::FogState>&& fog)
|
void CellStore::setFog(std::unique_ptr<ESM::FogState>&& fog)
|
||||||
|
|
|
@ -55,20 +55,56 @@ namespace ESM4
|
||||||
{
|
{
|
||||||
class Reader;
|
class Reader;
|
||||||
struct Cell;
|
struct Cell;
|
||||||
|
struct Reference;
|
||||||
|
struct Static;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
class ESMStore;
|
class ESMStore;
|
||||||
struct CellStoreImp;
|
struct CellStoreImp;
|
||||||
typedef std::variant<const ESM4::Cell*, const ESM::Cell*> CellVariant;
|
|
||||||
|
struct CellVariant
|
||||||
|
{
|
||||||
|
std::variant<const ESM4::Cell*, const ESM::Cell*> mVariant;
|
||||||
|
|
||||||
|
CellVariant(const ESM4::Cell* cell)
|
||||||
|
: mVariant(cell)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CellVariant(const ESM::Cell* cell)
|
||||||
|
: mVariant(cell)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEsm4() const { return getEsm4(); }
|
||||||
|
|
||||||
|
const ESM4::Cell* getEsm4() const
|
||||||
|
{
|
||||||
|
auto cell4 = std::get_if<const ESM4::Cell*>(&mVariant);
|
||||||
|
if (cell4)
|
||||||
|
return *cell4;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ESM::Cell* getEsm3() const
|
||||||
|
{
|
||||||
|
auto cell3 = std::get_if<const ESM::Cell*>(&mVariant);
|
||||||
|
if (cell3)
|
||||||
|
return *cell3;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
using CellStoreTuple = std::tuple<CellRefList<ESM::Activator>, CellRefList<ESM::Potion>,
|
using CellStoreTuple = std::tuple<CellRefList<ESM::Activator>, CellRefList<ESM::Potion>,
|
||||||
CellRefList<ESM::Apparatus>, CellRefList<ESM::Armor>, CellRefList<ESM::Book>, CellRefList<ESM::Clothing>,
|
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::Container>, CellRefList<ESM::Creature>, CellRefList<ESM::Door>, CellRefList<ESM::Ingredient>,
|
||||||
CellRefList<ESM::CreatureLevList>, CellRefList<ESM::ItemLevList>, CellRefList<ESM::Light>,
|
CellRefList<ESM::CreatureLevList>, CellRefList<ESM::ItemLevList>, CellRefList<ESM::Light>,
|
||||||
CellRefList<ESM::Lockpick>, CellRefList<ESM::Miscellaneous>, CellRefList<ESM::NPC>, CellRefList<ESM::Probe>,
|
CellRefList<ESM::Lockpick>, CellRefList<ESM::Miscellaneous>, CellRefList<ESM::NPC>, CellRefList<ESM::Probe>,
|
||||||
CellRefList<ESM::Repair>, CellRefList<ESM::Static>, CellRefList<ESM::Weapon>, CellRefList<ESM::BodyPart>>;
|
CellRefList<ESM::Repair>, CellRefList<ESM::Static>, CellRefList<ESM::Weapon>, CellRefList<ESM::BodyPart>,
|
||||||
|
|
||||||
|
CellRefList<ESM4::Static>>;
|
||||||
|
|
||||||
/// \brief Mutable state of a cell
|
/// \brief Mutable state of a cell
|
||||||
class CellStore
|
class CellStore
|
||||||
|
@ -188,11 +224,14 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @param readerList The readers to use for loading of the cell on-demand.
|
/// @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(CellVariant cell, const MWWorld::ESMStore& store, ESM::ReadersCache& readers);
|
||||||
CellStore(CellStore&&);
|
CellStore(CellStore&&);
|
||||||
~CellStore();
|
~CellStore();
|
||||||
|
|
||||||
const ESM::Cell* getCell() const;
|
const ESM::Cell* getCell() const;
|
||||||
|
CellVariant getCellVariant() const;
|
||||||
|
|
||||||
|
std::string_view getEditorName() const;
|
||||||
|
|
||||||
State getState() const;
|
State getState() const;
|
||||||
|
|
||||||
|
@ -339,6 +378,7 @@ namespace MWWorld
|
||||||
// Should be phased out when we have const version of forEach
|
// 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::Door>& getReadOnlyDoors() const { return get<ESM::Door>(); }
|
||||||
inline const CellRefList<ESM::Static>& getReadOnlyStatics() const { return get<ESM::Static>(); }
|
inline const CellRefList<ESM::Static>& getReadOnlyStatics() const { return get<ESM::Static>(); }
|
||||||
|
inline const CellRefList<ESM4::Static>& getReadOnlyEsm4Statics() const { return get<ESM4::Static>(); }
|
||||||
|
|
||||||
bool isExterior() const;
|
bool isExterior() const;
|
||||||
|
|
||||||
|
@ -374,20 +414,22 @@ namespace MWWorld
|
||||||
|
|
||||||
Ptr getMovedActor(int actorId) const;
|
Ptr getMovedActor(int actorId) const;
|
||||||
|
|
||||||
|
bool operator==(const CellStore& right) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Run through references and store IDs
|
/// Run through references and store IDs
|
||||||
void listRefs();
|
void listRefs();
|
||||||
|
|
||||||
void loadRefs();
|
void loadRefs();
|
||||||
|
|
||||||
|
void loadRef(const ESM4::Reference& ref, bool deleted);
|
||||||
void loadRef(ESM::CellRef& ref, bool deleted, std::map<ESM::RefNum, ESM::RefId>& refNumToID);
|
void loadRef(ESM::CellRef& ref, bool deleted, std::map<ESM::RefNum, ESM::RefId>& refNumToID);
|
||||||
///< Make case-adjustments to \a ref and insert it into the respective container.
|
///< Make case-adjustments to \a ref and insert it into the respective container.
|
||||||
///
|
///
|
||||||
/// Invalid \a ref objects are silently dropped.
|
/// Invalid \a ref objects are silently dropped.
|
||||||
|
///
|
||||||
};
|
};
|
||||||
|
|
||||||
bool operator==(const CellStore& left, const CellStore& right);
|
|
||||||
bool operator!=(const CellStore& left, const CellStore& right);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -87,7 +87,8 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
if (const LiveCellRef<T>* ref = dynamic_cast<const LiveCellRef<T>*>(value))
|
if (const LiveCellRef<T>* ref = dynamic_cast<const LiveCellRef<T>*>(value))
|
||||||
return ref;
|
return ref;
|
||||||
throw std::runtime_error(makeDynamicCastErrorMessage(value, T::getRecordType()));
|
throw std::runtime_error(
|
||||||
|
makeDynamicCastErrorMessage(value, ESM::getRecNameString(T::sRecordId).toStringView()));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
|
@ -95,7 +96,8 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
if (LiveCellRef<T>* ref = dynamic_cast<LiveCellRef<T>*>(value))
|
if (LiveCellRef<T>* ref = dynamic_cast<LiveCellRef<T>*>(value))
|
||||||
return ref;
|
return ref;
|
||||||
throw std::runtime_error(makeDynamicCastErrorMessage(value, T::getRecordType()));
|
throw std::runtime_error(
|
||||||
|
makeDynamicCastErrorMessage(value, ESM::getRecNameString(T::sRecordId).toStringView()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A reference to one object (of any type) in a cell.
|
/// A reference to one object (of any type) in a cell.
|
||||||
|
@ -130,7 +132,13 @@ namespace MWWorld
|
||||||
void save(ESM::ObjectState& state) const override;
|
void save(ESM::ObjectState& state) const override;
|
||||||
///< Save LiveCellRef state into \a state.
|
///< Save LiveCellRef state into \a state.
|
||||||
|
|
||||||
std::string_view getTypeDescription() const override { return X::getRecordType(); }
|
std::string_view getTypeDescription() const override
|
||||||
|
{
|
||||||
|
if constexpr (ESM::isESM4Rec(X::sRecordId))
|
||||||
|
return ESM::getRecNameString(X::sRecordId).toStringView();
|
||||||
|
else
|
||||||
|
return X::getRecordType();
|
||||||
|
}
|
||||||
|
|
||||||
static bool checkState(const ESM::ObjectState& state);
|
static bool checkState(const ESM::ObjectState& state);
|
||||||
///< Check if state is valid and report errors.
|
///< Check if state is valid and report errors.
|
||||||
|
|
|
@ -380,55 +380,62 @@ namespace MWWorld
|
||||||
assert(mActiveCells.find(cell) == mActiveCells.end());
|
assert(mActiveCells.find(cell) == mActiveCells.end());
|
||||||
mActiveCells.insert(cell);
|
mActiveCells.insert(cell);
|
||||||
|
|
||||||
Log(Debug::Info) << "Loading cell " << cell->getCell()->getDescription();
|
Log(Debug::Info) << "Loading cell " << cell->getEditorName();
|
||||||
|
|
||||||
const int cellX = cell->getCell()->getGridX();
|
auto cell3 = cell->getCellVariant().getEsm3();
|
||||||
const int cellY = cell->getCell()->getGridY();
|
int cellX = 0;
|
||||||
|
int cellY = 0;
|
||||||
if (cell->getCell()->isExterior())
|
if (cell3 != nullptr)
|
||||||
{
|
{
|
||||||
osg::ref_ptr<const ESMTerrain::LandObject> land = mRendering.getLandManager()->getLand(cellX, cellY);
|
|
||||||
const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr;
|
|
||||||
const int verts = ESM::Land::LAND_SIZE;
|
|
||||||
const int worldsize = ESM::Land::REAL_SIZE;
|
|
||||||
if (data)
|
|
||||||
{
|
|
||||||
mPhysics->addHeightField(
|
|
||||||
data->mHeights, cellX, cellY, worldsize, verts, data->mMinHeight, data->mMaxHeight, land.get());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
static std::vector<float> defaultHeight;
|
|
||||||
defaultHeight.resize(verts * verts, ESM::Land::DEFAULT_HEIGHT);
|
|
||||||
mPhysics->addHeightField(defaultHeight.data(), cellX, cellY, worldsize, verts,
|
|
||||||
ESM::Land::DEFAULT_HEIGHT, ESM::Land::DEFAULT_HEIGHT, land.get());
|
|
||||||
}
|
|
||||||
if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
|
|
||||||
{
|
|
||||||
const osg::Vec2i cellPosition(cellX, cellY);
|
|
||||||
const btVector3& origin = heightField->getCollisionObject()->getWorldTransform().getOrigin();
|
|
||||||
const osg::Vec3f shift(origin.x(), origin.y(), origin.z());
|
|
||||||
const HeightfieldShape shape = [&]() -> HeightfieldShape {
|
|
||||||
if (data == nullptr)
|
|
||||||
{
|
|
||||||
return DetourNavigator::HeightfieldPlane{ static_cast<float>(ESM::Land::DEFAULT_HEIGHT) };
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DetourNavigator::HeightfieldSurface heights;
|
|
||||||
heights.mHeights = data->mHeights;
|
|
||||||
heights.mSize = static_cast<std::size_t>(ESM::Land::LAND_SIZE);
|
|
||||||
heights.mMinHeight = data->mMinHeight;
|
|
||||||
heights.mMaxHeight = data->mMaxHeight;
|
|
||||||
return heights;
|
|
||||||
}
|
|
||||||
}();
|
|
||||||
mNavigator.addHeightfield(cellPosition, ESM::Land::REAL_SIZE, shape, navigatorUpdateGuard);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const auto pathgrid = mWorld.getStore().get<ESM::Pathgrid>().search(*cell->getCell()))
|
int cellX = cell3->getGridX();
|
||||||
mNavigator.addPathgrid(*cell->getCell(), *pathgrid);
|
int cellY = cell3->getGridY();
|
||||||
|
|
||||||
|
if (cell3->isExterior())
|
||||||
|
{
|
||||||
|
osg::ref_ptr<const ESMTerrain::LandObject> land = mRendering.getLandManager()->getLand(cellX, cellY);
|
||||||
|
const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr;
|
||||||
|
const int verts = ESM::Land::LAND_SIZE;
|
||||||
|
const int worldsize = ESM::Land::REAL_SIZE;
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
mPhysics->addHeightField(
|
||||||
|
data->mHeights, cellX, cellY, worldsize, verts, data->mMinHeight, data->mMaxHeight, land.get());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static std::vector<float> defaultHeight;
|
||||||
|
defaultHeight.resize(verts * verts, ESM::Land::DEFAULT_HEIGHT);
|
||||||
|
mPhysics->addHeightField(defaultHeight.data(), cellX, cellY, worldsize, verts,
|
||||||
|
ESM::Land::DEFAULT_HEIGHT, ESM::Land::DEFAULT_HEIGHT, land.get());
|
||||||
|
}
|
||||||
|
if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
|
||||||
|
{
|
||||||
|
const osg::Vec2i cellPosition(cellX, cellY);
|
||||||
|
const btVector3& origin = heightField->getCollisionObject()->getWorldTransform().getOrigin();
|
||||||
|
const osg::Vec3f shift(origin.x(), origin.y(), origin.z());
|
||||||
|
const HeightfieldShape shape = [&]() -> HeightfieldShape {
|
||||||
|
if (data == nullptr)
|
||||||
|
{
|
||||||
|
return DetourNavigator::HeightfieldPlane{ static_cast<float>(ESM::Land::DEFAULT_HEIGHT) };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DetourNavigator::HeightfieldSurface heights;
|
||||||
|
heights.mHeights = data->mHeights;
|
||||||
|
heights.mSize = static_cast<std::size_t>(ESM::Land::LAND_SIZE);
|
||||||
|
heights.mMinHeight = data->mMinHeight;
|
||||||
|
heights.mMaxHeight = data->mMaxHeight;
|
||||||
|
return heights;
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
mNavigator.addHeightfield(cellPosition, ESM::Land::REAL_SIZE, shape, navigatorUpdateGuard);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const auto pathgrid = mWorld.getStore().get<ESM::Pathgrid>().search(*cell3))
|
||||||
|
mNavigator.addPathgrid(*cell3, *pathgrid);
|
||||||
|
}
|
||||||
|
|
||||||
// register local scripts
|
// register local scripts
|
||||||
// do this before insertCell, to make sure we don't add scripts from levelled creature spawning twice
|
// do this before insertCell, to make sure we don't add scripts from levelled creature spawning twice
|
||||||
|
@ -442,7 +449,7 @@ namespace MWWorld
|
||||||
mRendering.addCell(cell);
|
mRendering.addCell(cell);
|
||||||
|
|
||||||
MWBase::Environment::get().getWindowManager()->addCell(cell);
|
MWBase::Environment::get().getWindowManager()->addCell(cell);
|
||||||
bool waterEnabled = cell->getCell()->hasWater() || cell->isExterior();
|
bool waterEnabled = cell3 && (cell3->hasWater() || cell->isExterior());
|
||||||
float waterLevel = cell->getWaterLevel();
|
float waterLevel = cell->getWaterLevel();
|
||||||
mRendering.setWaterEnabled(waterEnabled);
|
mRendering.setWaterEnabled(waterEnabled);
|
||||||
if (waterEnabled)
|
if (waterEnabled)
|
||||||
|
@ -450,7 +457,7 @@ namespace MWWorld
|
||||||
mPhysics->enableWater(waterLevel);
|
mPhysics->enableWater(waterLevel);
|
||||||
mRendering.setWaterHeight(waterLevel);
|
mRendering.setWaterHeight(waterLevel);
|
||||||
|
|
||||||
if (cell->getCell()->isExterior())
|
if (cell3->isExterior())
|
||||||
{
|
{
|
||||||
if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
|
if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
|
||||||
mNavigator.addWater(
|
mNavigator.addWater(
|
||||||
|
@ -465,8 +472,8 @@ namespace MWWorld
|
||||||
else
|
else
|
||||||
mPhysics->disableWater();
|
mPhysics->disableWater();
|
||||||
|
|
||||||
if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx))
|
if (cell3 && !cell->isExterior() && !(cell3->mData.mFlags & ESM::Cell::QuasiEx))
|
||||||
mRendering.configureAmbient(cell->getCell());
|
mRendering.configureAmbient(cell3);
|
||||||
|
|
||||||
mPreloader->notifyLoaded(cell);
|
mPreloader->notifyLoaded(cell);
|
||||||
}
|
}
|
||||||
|
@ -879,8 +886,7 @@ namespace MWWorld
|
||||||
|
|
||||||
loadingListener->setProgressRange(cell->count());
|
loadingListener->setProgressRange(cell->count());
|
||||||
|
|
||||||
mNavigator.setWorldspace(
|
mNavigator.setWorldspace(Misc::StringUtils::lowerCase(cell->getEditorName()), navigatorUpdateGuard.get());
|
||||||
Misc::StringUtils::lowerCase(cell->getCell()->mCellId.mWorldspace), navigatorUpdateGuard.get());
|
|
||||||
mNavigator.updateBounds(position.asVec3(), navigatorUpdateGuard.get());
|
mNavigator.updateBounds(position.asVec3(), navigatorUpdateGuard.get());
|
||||||
|
|
||||||
// Load cell.
|
// Load cell.
|
||||||
|
|
|
@ -1170,20 +1170,6 @@ namespace MWWorld
|
||||||
return mKeywordSearch;
|
return mKeywordSearch;
|
||||||
}
|
}
|
||||||
|
|
||||||
ESM::FixedString<6> getRecNameString(ESM::RecNameInts recName)
|
|
||||||
{
|
|
||||||
ESM::FixedString<6> name;
|
|
||||||
name.assign("");
|
|
||||||
ESM::NAME fourCCName(recName & ~ESM::sEsm4RecnameFlag);
|
|
||||||
for (int i = 0; i < 4; i++)
|
|
||||||
name.mData[i] = fourCCName.mData[i];
|
|
||||||
if (ESM::isESM4Rec(recName))
|
|
||||||
{
|
|
||||||
name.mData[4] = '4';
|
|
||||||
}
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ESM4 Cell
|
// ESM4 Cell
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
|
|
||||||
|
|
|
@ -533,8 +533,6 @@ namespace MWWorld
|
||||||
const MWDialogue::KeywordSearch<std::string, int>& getDialogIdKeywordSearch() const;
|
const MWDialogue::KeywordSearch<std::string, int>& getDialogIdKeywordSearch() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
ESM::FixedString<6> getRecNameString(ESM::RecNameInts recName);
|
|
||||||
|
|
||||||
} // end namespace
|
} // end namespace
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
#include <components/esm3/loadregn.hpp>
|
#include <components/esm3/loadregn.hpp>
|
||||||
#include <components/esm3/loadstat.hpp>
|
#include <components/esm3/loadstat.hpp>
|
||||||
|
|
||||||
|
#include <components/esm4/loadstat.hpp>
|
||||||
|
|
||||||
#include <components/misc/constants.hpp>
|
#include <components/misc/constants.hpp>
|
||||||
#include <components/misc/convert.hpp>
|
#include <components/misc/convert.hpp>
|
||||||
#include <components/misc/mathutil.hpp>
|
#include <components/misc/mathutil.hpp>
|
||||||
|
@ -2804,6 +2806,24 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (const MWWorld::LiveCellRef<ESM4::Static>& stat4 : cellStore->getReadOnlyEsm4Statics().mList)
|
||||||
|
{
|
||||||
|
if (Misc::StringUtils::lowerCase(stat4.mBase->mEditorId) == "cocmarkerheading")
|
||||||
|
{
|
||||||
|
// found the COC position?
|
||||||
|
pos = stat4.mRef.getPosition();
|
||||||
|
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Fall back to the first static location.
|
||||||
|
const MWWorld::CellRefList<ESM4::Static>::List& statics4 = cellStore->getReadOnlyEsm4Statics().mList;
|
||||||
|
if (!statics4.empty())
|
||||||
|
{
|
||||||
|
pos = statics4.begin()->mRef.getPosition();
|
||||||
|
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
// Fall back to the first static location.
|
// Fall back to the first static location.
|
||||||
const MWWorld::CellRefList<ESM::Static>::List& statics = cellStore->getReadOnlyStatics().mList;
|
const MWWorld::CellRefList<ESM::Static>::List& statics = cellStore->getReadOnlyStatics().mList;
|
||||||
if (!statics.empty())
|
if (!statics.empty())
|
||||||
|
@ -3253,7 +3273,7 @@ namespace MWWorld
|
||||||
std::set<std::string_view> checkedCells;
|
std::set<std::string_view> checkedCells;
|
||||||
std::set<std::string_view> currentCells;
|
std::set<std::string_view> currentCells;
|
||||||
std::set<std::string_view> nextCells;
|
std::set<std::string_view> nextCells;
|
||||||
nextCells.insert(cell->getCell()->mName);
|
nextCells.insert(cell->getEditorName());
|
||||||
|
|
||||||
while (!nextCells.empty())
|
while (!nextCells.empty())
|
||||||
{
|
{
|
||||||
|
|
|
@ -202,9 +202,17 @@ MWWorld::CellStore* MWWorld::WorldModel::getInterior(std::string_view name)
|
||||||
|
|
||||||
if (result == mInteriors.end())
|
if (result == mInteriors.end())
|
||||||
{
|
{
|
||||||
const ESM::Cell* cell = mStore.get<ESM::Cell>().find(name);
|
const ESM4::Cell* cell4 = mStore.get<ESM4::Cell>().searchCellName(name);
|
||||||
|
|
||||||
result = mInteriors.emplace(name, CellStore(cell, mStore, mReaders)).first;
|
if (!cell4)
|
||||||
|
{
|
||||||
|
const ESM::Cell* cell = mStore.get<ESM::Cell>().find(name);
|
||||||
|
result = mInteriors.emplace(name, CellStore(cell, mStore, mReaders)).first;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = mInteriors.emplace(name, CellStore(cell4, mStore, mReaders)).first;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result->second.getState() != CellStore::State_Loaded)
|
if (result->second.getState() != CellStore::State_Loaded)
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <osg/Vec3f>
|
#include <osg/Vec3f>
|
||||||
|
|
||||||
#include "components/esm/fourcc.hpp"
|
#include "components/esm/fourcc.hpp"
|
||||||
|
#include <components/esm/esmcommon.hpp>
|
||||||
#include <components/esm4/common.hpp>
|
#include <components/esm4/common.hpp>
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
|
@ -338,6 +339,20 @@ namespace ESM
|
||||||
return RecName & sEsm4RecnameFlag;
|
return RecName & sEsm4RecnameFlag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline FixedString<6> getRecNameString(ESM::RecNameInts recName)
|
||||||
|
{
|
||||||
|
ESM::FixedString<6> name;
|
||||||
|
name.assign("");
|
||||||
|
ESM::NAME fourCCName(recName & ~ESM::sEsm4RecnameFlag);
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
name.mData[i] = fourCCName.mData[i];
|
||||||
|
if (ESM::isESM4Rec(recName))
|
||||||
|
{
|
||||||
|
name.mData[4] = '4';
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
/// Common subrecords
|
/// Common subrecords
|
||||||
enum SubRecNameInts
|
enum SubRecNameInts
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue