Cannot load a cell yet, but getting more necessary parts in

7220-lua-add-a-general-purpose-lexical-parser
florent.teppe 2 years ago
parent cddf6f29d6
commit 08b68fcd48

@ -47,5 +47,7 @@ namespace MWClass
Repair::registerSelf();
Static::registerSelf();
BodyPart::registerSelf();
ESM4Static::registerSelf();
}
}

@ -1,6 +1,7 @@
#include "static.hpp"
#include <components/esm3/loadstat.hpp>
#include <components/esm4/loadstat.hpp>
#include <components/sceneutil/positionattitudetransform.hpp>
#include "../mwphysics/physicssystem.hpp"
@ -63,4 +64,53 @@ namespace MWClass
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;
};
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

@ -39,6 +39,8 @@
#include <components/esm3/npcstate.hpp>
#include <components/esm3/objectstate.hpp>
#include <components/esm3/readerscache.hpp>
#include <components/esm4/loadrefr.hpp>
#include <components/esm4/loadstat.hpp>
#include <components/misc/tuplehelpers.hpp>
#include "../mwbase/environment.hpp"
@ -503,18 +505,22 @@ namespace MWWorld
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)
, mReaders(readers)
, mCell(cell)
, mCellVariant(cell)
, mState(State_Unloaded)
, mHasState(false)
, mLastRespawn(0, 0)
, mCellStoreImp(std::make_unique<CellStoreImp>())
, mRechargingItemsUpToDate(false)
{
mCell = mCellVariant.getEsm3();
std::apply([this](auto&... x) { (CellStoreImp::assignStoreToIndex(*this, x), ...); }, mCellStoreImp->mRefLists);
mWaterLevel = cell->mWater;
if (mCell)
mWaterLevel = mCell->mWater;
}
CellStore::~CellStore() = default;
@ -525,6 +531,24 @@ namespace MWWorld
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
{
return mState;
@ -735,7 +759,24 @@ namespace MWWorld
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())
return; // this is a dynamically generated cell -> skipping.
@ -795,12 +836,15 @@ namespace MWWorld
bool CellStore::isExterior() const
{
return mCell->isExterior();
auto cell3 = mCellVariant.getEsm3();
return cell3 ? cell3->isExterior() : false;
}
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)
@ -823,6 +867,28 @@ namespace MWWorld
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)
{
const MWWorld::ESMStore& store = mStore;
@ -999,8 +1065,8 @@ namespace MWWorld
Log(Debug::Warning) << "Warning: Dropping moved ref tag for " << movedRef.getCellRef().getRefId()
<< " (target cell " << movedTo.mWorldspace
<< " 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
// at inapproriate coordinates. Restore original coordinates:
// Note by dropping tag the object will automatically re-appear in its original cell, though
// potentially at inapproriate coordinates. Restore original coordinates:
movedRef.getRefData().setPosition(movedRef.getCellRef().getPosition());
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)
{
return !(left == right);
if (!cell4Left && !cell4Right)
return getCell()->getCellId() == right.getCell()->getCellId();
else if (cell4Left && cell4Right)
return cell4Left->mId == cell4Right->mId;
else
return false;
}
void CellStore::setFog(std::unique_ptr<ESM::FogState>&& fog)

@ -55,20 +55,56 @@ namespace ESM4
{
class Reader;
struct Cell;
struct Reference;
struct Static;
}
namespace MWWorld
{
class ESMStore;
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>,
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>>;
CellRefList<ESM::Repair>, CellRefList<ESM::Static>, CellRefList<ESM::Weapon>, CellRefList<ESM::BodyPart>,
CellRefList<ESM4::Static>>;
/// \brief Mutable state of a cell
class CellStore
@ -188,11 +224,14 @@ namespace MWWorld
}
/// @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();
const ESM::Cell* getCell() const;
CellVariant getCellVariant() const;
std::string_view getEditorName() const;
State getState() const;
@ -339,6 +378,7 @@ namespace MWWorld
// 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>(); }
inline const CellRefList<ESM4::Static>& getReadOnlyEsm4Statics() const { return get<ESM4::Static>(); }
bool isExterior() const;
@ -374,20 +414,22 @@ namespace MWWorld
Ptr getMovedActor(int actorId) const;
bool operator==(const CellStore& right) const;
private:
/// Run through references and store IDs
void listRefs();
void loadRefs();
void loadRef(const ESM4::Reference& ref, bool deleted);
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.
///
/// Invalid \a ref objects are silently dropped.
///
};
bool operator==(const CellStore& left, const CellStore& right);
bool operator!=(const CellStore& left, const CellStore& right);
}
#endif

@ -87,7 +87,8 @@ namespace MWWorld
{
if (const LiveCellRef<T>* ref = dynamic_cast<const LiveCellRef<T>*>(value))
return ref;
throw std::runtime_error(makeDynamicCastErrorMessage(value, T::getRecordType()));
throw std::runtime_error(
makeDynamicCastErrorMessage(value, ESM::getRecNameString(T::sRecordId).toStringView()));
}
template <class T>
@ -95,7 +96,8 @@ namespace MWWorld
{
if (LiveCellRef<T>* ref = dynamic_cast<LiveCellRef<T>*>(value))
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.
@ -130,7 +132,13 @@ namespace MWWorld
void save(ESM::ObjectState& state) const override;
///< 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);
///< Check if state is valid and report errors.

@ -380,55 +380,62 @@ namespace MWWorld
assert(mActiveCells.find(cell) == mActiveCells.end());
mActiveCells.insert(cell);
Log(Debug::Info) << "Loading cell " << cell->getCell()->getDescription();
Log(Debug::Info) << "Loading cell " << cell->getEditorName();
const int cellX = cell->getCell()->getGridX();
const int cellY = cell->getCell()->getGridY();
if (cell->getCell()->isExterior())
auto cell3 = cell->getCellVariant().getEsm3();
int cellX = 0;
int cellY = 0;
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))
int cellX = cell3->getGridX();
int cellY = cell3->getGridY();
if (cell3->isExterior())
{
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);
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()))
mNavigator.addPathgrid(*cell->getCell(), *pathgrid);
if (const auto pathgrid = mWorld.getStore().get<ESM::Pathgrid>().search(*cell3))
mNavigator.addPathgrid(*cell3, *pathgrid);
}
// register local scripts
// 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);
MWBase::Environment::get().getWindowManager()->addCell(cell);
bool waterEnabled = cell->getCell()->hasWater() || cell->isExterior();
bool waterEnabled = cell3 && (cell3->hasWater() || cell->isExterior());
float waterLevel = cell->getWaterLevel();
mRendering.setWaterEnabled(waterEnabled);
if (waterEnabled)
@ -450,7 +457,7 @@ namespace MWWorld
mPhysics->enableWater(waterLevel);
mRendering.setWaterHeight(waterLevel);
if (cell->getCell()->isExterior())
if (cell3->isExterior())
{
if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
mNavigator.addWater(
@ -465,8 +472,8 @@ namespace MWWorld
else
mPhysics->disableWater();
if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx))
mRendering.configureAmbient(cell->getCell());
if (cell3 && !cell->isExterior() && !(cell3->mData.mFlags & ESM::Cell::QuasiEx))
mRendering.configureAmbient(cell3);
mPreloader->notifyLoaded(cell);
}
@ -879,8 +886,7 @@ namespace MWWorld
loadingListener->setProgressRange(cell->count());
mNavigator.setWorldspace(
Misc::StringUtils::lowerCase(cell->getCell()->mCellId.mWorldspace), navigatorUpdateGuard.get());
mNavigator.setWorldspace(Misc::StringUtils::lowerCase(cell->getEditorName()), navigatorUpdateGuard.get());
mNavigator.updateBounds(position.asVec3(), navigatorUpdateGuard.get());
// Load cell.

@ -1170,20 +1170,6 @@ namespace MWWorld
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
//=========================================================================

@ -533,8 +533,6 @@ namespace MWWorld
const MWDialogue::KeywordSearch<std::string, int>& getDialogIdKeywordSearch() const;
};
ESM::FixedString<6> getRecNameString(ESM::RecNameInts recName);
} // end namespace
#endif

@ -24,6 +24,8 @@
#include <components/esm3/loadregn.hpp>
#include <components/esm3/loadstat.hpp>
#include <components/esm4/loadstat.hpp>
#include <components/misc/constants.hpp>
#include <components/misc/convert.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.
const MWWorld::CellRefList<ESM::Static>::List& statics = cellStore->getReadOnlyStatics().mList;
if (!statics.empty())
@ -3253,7 +3273,7 @@ namespace MWWorld
std::set<std::string_view> checkedCells;
std::set<std::string_view> currentCells;
std::set<std::string_view> nextCells;
nextCells.insert(cell->getCell()->mName);
nextCells.insert(cell->getEditorName());
while (!nextCells.empty())
{

@ -202,9 +202,17 @@ MWWorld::CellStore* MWWorld::WorldModel::getInterior(std::string_view name)
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)

@ -9,6 +9,7 @@
#include <osg/Vec3f>
#include "components/esm/fourcc.hpp"
#include <components/esm/esmcommon.hpp>
#include <components/esm4/common.hpp>
namespace ESM
@ -338,6 +339,20 @@ namespace ESM
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
enum SubRecNameInts
{

Loading…
Cancel
Save