mirror of
https://github.com/OpenMW/openmw.git
synced 2025-06-19 18:41:33 +00:00
Merge branch 'load-ESM4-Cell' into 'master'
Can load and coc into an interrior oblivion cell See merge request OpenMW/openmw!2647
This commit is contained in:
commit
4032c447e9
58 changed files with 1084 additions and 271 deletions
|
@ -78,7 +78,7 @@ add_openmw_dir (mwworld
|
|||
actionequip timestamp actionalchemy cellstore actionapply actioneat
|
||||
store esmstore fallback actionrepair actionsoulgem livecellref actiondoor
|
||||
contentloader esmloader actiontrap cellreflist cellref weather projectilemanager
|
||||
cellpreloader datetimemanager groundcoverstore magiceffects
|
||||
cellpreloader datetimemanager groundcoverstore magiceffects cell
|
||||
)
|
||||
|
||||
add_openmw_dir (mwphysics
|
||||
|
|
|
@ -92,6 +92,7 @@ namespace MWWorld
|
|||
class TimeStamp;
|
||||
class ESMStore;
|
||||
class RefData;
|
||||
class Cell;
|
||||
|
||||
typedef std::vector<std::pair<MWWorld::Ptr, MWMechanics::Movement>> PtrMovementList;
|
||||
}
|
||||
|
@ -179,6 +180,8 @@ namespace MWBase
|
|||
///
|
||||
/// \note If cell==0, the cell the player is currently in will be used instead to
|
||||
/// generate a name.
|
||||
virtual std::string_view getCellName(const MWWorld::Cell& cell) const = 0;
|
||||
|
||||
virtual std::string_view getCellName(const ESM::Cell* cell) const = 0;
|
||||
|
||||
virtual void removeRefScript(MWWorld::RefData* ref) = 0;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -705,7 +705,7 @@ namespace MWGui
|
|||
ESM::Position markedPosition;
|
||||
MWBase::Environment::get().getWorld()->getPlayer().getMarkedPosition(markedCell, markedPosition);
|
||||
if (markedCell && markedCell->isExterior() == !mInterior
|
||||
&& (!mInterior || Misc::StringUtils::ciEqual(markedCell->getCell()->mName, mPrefix)))
|
||||
&& (!mInterior || Misc::StringUtils::ciEqual(markedCell->getCell()->getNameId(), mPrefix)))
|
||||
{
|
||||
MarkerUserData markerPos(mLocalMapRender);
|
||||
MyGUI::ImageBox* markerWidget = mLocalMap->createWidget<MyGUI::ImageBox>("ImageBox",
|
||||
|
|
|
@ -200,7 +200,7 @@ namespace MWGui
|
|||
MWWorld::Ptr player = world->getPlayerPtr();
|
||||
if (mSleeping && player.getCell()->isExterior())
|
||||
{
|
||||
const ESM::RefId& regionstr = player.getCell()->getCell()->mRegion;
|
||||
const ESM::RefId& regionstr = player.getCell()->getCell()->getRegion();
|
||||
if (!regionstr.empty())
|
||||
{
|
||||
const ESM::Region* region = world->getStore().get<ESM::Region>().find(regionstr);
|
||||
|
|
|
@ -954,20 +954,21 @@ namespace MWGui
|
|||
|
||||
mMap->setCellName(name);
|
||||
mHud->setCellName(name);
|
||||
auto cellCommon = cell->getCell();
|
||||
|
||||
if (cell->getCell()->isExterior())
|
||||
if (cellCommon->isExterior())
|
||||
{
|
||||
if (!cell->getCell()->mName.empty())
|
||||
mMap->addVisitedLocation(name, cell->getCell()->getGridX(), cell->getCell()->getGridY());
|
||||
if (!cellCommon->getNameId().empty())
|
||||
mMap->addVisitedLocation(name, cellCommon->getGridX(), cellCommon->getGridY());
|
||||
|
||||
mMap->cellExplored(cell->getCell()->getGridX(), cell->getCell()->getGridY());
|
||||
mMap->cellExplored(cellCommon->getGridX(), cellCommon->getGridY());
|
||||
|
||||
setActiveMap(cell->getCell()->getGridX(), cell->getCell()->getGridY(), false);
|
||||
setActiveMap(cellCommon->getGridX(), cellCommon->getGridY(), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
mMap->setCellPrefix(cell->getCell()->mName);
|
||||
mHud->setCellPrefix(cell->getCell()->mName);
|
||||
mMap->setCellPrefix(std::string(cellCommon->getNameId()));
|
||||
mHud->setCellPrefix(std::string(cellCommon->getNameId()));
|
||||
|
||||
osg::Vec3f worldPos;
|
||||
if (!MWBase::Environment::get().getWorld()->findInteriorPositionInWorldSpace(cell, worldPos))
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "luabindings.hpp"
|
||||
|
||||
#include <components/esm/esmbridge.hpp>
|
||||
#include <components/esm/records.hpp>
|
||||
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
|
@ -29,35 +30,35 @@ namespace MWLua
|
|||
|
||||
cellT[sol::meta_function::equal_to] = [](const CellT& a, const CellT& b) { return a.mStore == b.mStore; };
|
||||
cellT[sol::meta_function::to_string] = [](const CellT& c) {
|
||||
const ESM::Cell* cell = c.mStore->getCell();
|
||||
auto cell = c.mStore->getCell();
|
||||
std::stringstream res;
|
||||
if (cell->isExterior())
|
||||
res << "exterior(" << cell->getGridX() << ", " << cell->getGridY() << ")";
|
||||
else
|
||||
res << "interior(" << cell->mName << ")";
|
||||
res << "interior(" << cell->getNameId() << ")";
|
||||
return res.str();
|
||||
};
|
||||
|
||||
cellT["name"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->mName; });
|
||||
cellT["name"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getNameId(); });
|
||||
cellT["region"]
|
||||
= sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->mRegion.getRefIdString(); });
|
||||
= sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getRegion().getRefIdString(); });
|
||||
cellT["gridX"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getGridX(); });
|
||||
cellT["gridY"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getGridY(); });
|
||||
cellT["hasWater"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->hasWater(); });
|
||||
cellT["hasSky"] = sol::readonly_property([](const CellT& c) {
|
||||
return c.mStore->getCell()->isExterior() || (c.mStore->getCell()->mData.mFlags & ESM::Cell::QuasiEx) != 0;
|
||||
return c.mStore->getCell()->isExterior() || (c.mStore->getCell()->isQuasiExterior()) != 0;
|
||||
});
|
||||
cellT["isExterior"] = sol::readonly_property([](const CellT& c) { return c.mStore->isExterior(); });
|
||||
|
||||
// deprecated, use cell:hasTag("QuasiExterior") instead
|
||||
cellT["isQuasiExterior"] = sol::readonly_property(
|
||||
[](const CellT& c) { return (c.mStore->getCell()->mData.mFlags & ESM::Cell::QuasiEx) != 0; });
|
||||
cellT["isQuasiExterior"]
|
||||
= sol::readonly_property([](const CellT& c) { return (c.mStore->getCell()->isQuasiExterior()) != 0; });
|
||||
|
||||
cellT["hasTag"] = [](const CellT& c, std::string_view tag) -> bool {
|
||||
if (tag == "NoSleep")
|
||||
return (c.mStore->getCell()->mData.mFlags & ESM::Cell::NoSleep) != 0;
|
||||
return (c.mStore->getCell()->noSleep()) != 0;
|
||||
else if (tag == "QuasiExterior")
|
||||
return (c.mStore->getCell()->mData.mFlags & ESM::Cell::QuasiEx) != 0;
|
||||
return (c.mStore->getCell()->isQuasiExterior()) != 0;
|
||||
return false;
|
||||
};
|
||||
|
||||
|
|
|
@ -176,12 +176,12 @@ namespace MWLua
|
|||
// TODO: change AiEscort implementation to accept ptr instead of a non-unique refId.
|
||||
const ESM::RefId& refId = target.ptr().getCellRef().getRefId();
|
||||
int gameHoursDuration = static_cast<int>(std::ceil(duration / 3600.0));
|
||||
const ESM::Cell* esmCell = cell.mStore->getCell();
|
||||
auto* esmCell = cell.mStore->getCell();
|
||||
if (esmCell->isExterior())
|
||||
ai.stack(MWMechanics::AiEscort(refId, gameHoursDuration, dest.x(), dest.y(), dest.z(), false), ptr);
|
||||
else
|
||||
ai.stack(MWMechanics::AiEscort(
|
||||
refId, esmCell->mName, gameHoursDuration, dest.x(), dest.y(), dest.z(), false),
|
||||
refId, esmCell->getNameId(), gameHoursDuration, dest.x(), dest.y(), dest.z(), false),
|
||||
ptr);
|
||||
};
|
||||
selfAPI["_startAiWander"] = [](SelfObject& self, int distance, float duration) {
|
||||
|
|
|
@ -274,8 +274,8 @@ namespace MWMechanics
|
|||
.find("fInteriorHeadTrackMult")
|
||||
->mValue.getFloat();
|
||||
float maxDistance = fMaxHeadTrackDistance;
|
||||
const ESM::Cell* currentCell = actor.getCell()->getCell();
|
||||
if (!currentCell->isExterior() && !(currentCell->mData.mFlags & ESM::Cell::QuasiEx))
|
||||
auto currentCell = actor.getCell()->getCell();
|
||||
if (!currentCell->isExterior() && !(currentCell->isQuasiExterior()))
|
||||
maxDistance *= fInteriorHeadTrackMult;
|
||||
|
||||
const osg::Vec3f actor1Pos(actorRefData.getPosition().asVec3());
|
||||
|
|
|
@ -357,12 +357,11 @@ namespace MWMechanics
|
|||
case AiCombatStorage::FleeState_Idle:
|
||||
{
|
||||
float triggerDist = getMaxAttackDistance(target);
|
||||
|
||||
const MWWorld::Cell* cellVariant = storage.mCell->getCell();
|
||||
if (storage.mLOS && (triggerDist >= 1000 || getDistanceMinusHalfExtents(actor, target) <= triggerDist))
|
||||
{
|
||||
const ESM::Pathgrid* pathgrid
|
||||
= MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(
|
||||
*storage.mCell->getCell());
|
||||
= MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*cellVariant);
|
||||
|
||||
bool runFallback = true;
|
||||
|
||||
|
@ -370,7 +369,7 @@ namespace MWMechanics
|
|||
&& !actor.getClass().isPureWaterCreature(actor))
|
||||
{
|
||||
ESM::Pathgrid::PointList points;
|
||||
Misc::CoordinateConverter coords(storage.mCell->getCell());
|
||||
Misc::CoordinateConverter coords(*storage.mCell->getCell());
|
||||
|
||||
osg::Vec3f localPos = actor.getRefData().getPosition().asVec3();
|
||||
coords.toLocal(localPos);
|
||||
|
|
|
@ -174,7 +174,8 @@ namespace MWMechanics
|
|||
return true;
|
||||
}
|
||||
}
|
||||
else if (Misc::StringUtils::ciEqual(mCellId, actor.getCell()->getCell()->mName)) // Cell to travel to
|
||||
else if (Misc::StringUtils::ciEqual(
|
||||
mCellId, actor.getCell()->getCell()->getNameId())) // Cell to travel to
|
||||
{
|
||||
mRemainingDuration = mDuration;
|
||||
return true;
|
||||
|
|
|
@ -411,11 +411,11 @@ bool MWMechanics::AiPackage::doesPathNeedRecalc(const osg::Vec3f& newDest, const
|
|||
|
||||
bool MWMechanics::AiPackage::isNearInactiveCell(osg::Vec3f position)
|
||||
{
|
||||
const ESM::Cell* playerCell(getPlayer().getCell()->getCell());
|
||||
const MWWorld::Cell* playerCell = getPlayer().getCell()->getCell();
|
||||
if (playerCell->isExterior())
|
||||
{
|
||||
// get actor's distance from origin of center cell
|
||||
Misc::CoordinateConverter(playerCell).toLocal(position);
|
||||
Misc::CoordinateConverter(*playerCell).toLocal(position);
|
||||
|
||||
// currently assumes 3 x 3 grid for exterior cells, with player at center cell.
|
||||
// AI shuts down actors before they reach edges of 3 x 3 grid.
|
||||
|
|
|
@ -730,7 +730,7 @@ namespace MWMechanics
|
|||
auto& prng = MWBase::Environment::get().getWorld()->getPrng();
|
||||
int index = Misc::Rng::rollDice(storage.mAllowedNodes.size(), prng);
|
||||
ESM::Pathgrid::Point worldDest = storage.mAllowedNodes[index];
|
||||
auto converter = Misc::CoordinateConverter(actor.getCell()->getCell());
|
||||
auto converter = Misc::CoordinateConverter(*actor.getCell()->getCell());
|
||||
ESM::Pathgrid::Point dest = converter.toLocalPoint(worldDest);
|
||||
|
||||
bool isPathGridOccupied = MWBase::Environment::get().getMechanicsManager()->isAnyActorInRange(
|
||||
|
@ -811,7 +811,7 @@ namespace MWMechanics
|
|||
getPathGridGraph(currentCell).getNeighbouringPoints(index, points);
|
||||
}
|
||||
|
||||
void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell, AiWanderStorage& storage)
|
||||
void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const MWWorld::Cell* cell, AiWanderStorage& storage)
|
||||
{
|
||||
// infrequently used, therefore no benefit in caching it as a member
|
||||
const ESM::Pathgrid* pathgrid
|
||||
|
@ -835,7 +835,7 @@ namespace MWMechanics
|
|||
if (mDistance && storage.mCanWanderAlongPathGrid && !actor.getClass().isPureWaterCreature(actor))
|
||||
{
|
||||
// get NPC's position in local (i.e. cell) coordinates
|
||||
auto converter = Misc::CoordinateConverter(cell);
|
||||
auto converter = Misc::CoordinateConverter(*cell);
|
||||
const osg::Vec3f npcPos = converter.toLocalVec3(mInitialActorPosition);
|
||||
|
||||
// Find closest pathgrid point
|
||||
|
|
|
@ -23,6 +23,10 @@ namespace Misc
|
|||
class CoordinateConverter;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
class Cell;
|
||||
}
|
||||
namespace MWMechanics
|
||||
{
|
||||
/// \brief This class holds the variables AiWander needs which are deleted if the package becomes inactive.
|
||||
|
@ -147,7 +151,7 @@ namespace MWMechanics
|
|||
void getNeighbouringNodes(
|
||||
ESM::Pathgrid::Point dest, const MWWorld::CellStore* currentCell, ESM::Pathgrid::PointList& points);
|
||||
|
||||
void getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell, AiWanderStorage& storage);
|
||||
void getAllowedNodes(const MWWorld::Ptr& actor, const MWWorld::Cell* cell, AiWanderStorage& storage);
|
||||
|
||||
void trimAllowedNodes(std::vector<ESM::Pathgrid::Point>& nodes, const PathFinder& pathfinder);
|
||||
|
||||
|
|
|
@ -196,7 +196,7 @@ namespace MWMechanics
|
|||
return;
|
||||
|
||||
// NOTE: getClosestPoint expects local coordinates
|
||||
Misc::CoordinateConverter converter(mCell->getCell());
|
||||
Misc::CoordinateConverter converter(*mCell->getCell());
|
||||
|
||||
// NOTE: It is possible that getClosestPoint returns a pathgrind point index
|
||||
// that is unreachable in some situations. e.g. actor is standing
|
||||
|
|
|
@ -105,7 +105,8 @@ namespace MWMechanics
|
|||
return true;
|
||||
|
||||
mCell = cell->getCell();
|
||||
mPathgrid = MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*cell->getCell());
|
||||
|
||||
mPathgrid = MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*mCell);
|
||||
if (!mPathgrid)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace ESM
|
|||
namespace MWWorld
|
||||
{
|
||||
class CellStore;
|
||||
class Cell;
|
||||
}
|
||||
|
||||
namespace MWMechanics
|
||||
|
@ -41,7 +42,7 @@ namespace MWMechanics
|
|||
std::deque<ESM::Pathgrid::Point> aStarSearch(const int start, const int end) const;
|
||||
|
||||
private:
|
||||
const ESM::Cell* mCell;
|
||||
const MWWorld::Cell* mCell;
|
||||
const ESM::Pathgrid* mPathgrid;
|
||||
|
||||
struct ConnectedPoint // edge
|
||||
|
|
|
@ -489,7 +489,7 @@ namespace MWMechanics
|
|||
{
|
||||
std::string_view dest;
|
||||
if (!markedCell->isExterior())
|
||||
dest = markedCell->getCell()->mName;
|
||||
dest = markedCell->getCell()->getNameId();
|
||||
MWWorld::ActionTeleport action(dest, markedPosition, false);
|
||||
action.execute(target);
|
||||
if (!caster.isEmpty())
|
||||
|
|
|
@ -2,11 +2,15 @@
|
|||
|
||||
#include <algorithm>
|
||||
|
||||
#include <components/esm/esmbridge.hpp>
|
||||
#include <components/esm3/loadcell.hpp>
|
||||
#include <components/esm4/loadcell.hpp>
|
||||
#include <components/fallback/fallback.hpp>
|
||||
#include <components/sceneutil/util.hpp>
|
||||
#include <components/settings/settings.hpp>
|
||||
|
||||
#include <apps/openmw/mwworld/cell.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
float DLLandFogStart;
|
||||
|
@ -38,13 +42,14 @@ namespace MWRender
|
|||
DLInteriorFogEnd = Settings::Manager::getFloat("distant interior fog end", "Fog");
|
||||
}
|
||||
|
||||
void FogManager::configure(float viewDistance, const ESM::Cell* cell)
|
||||
void FogManager::configure(float viewDistance, const MWWorld::Cell& cell)
|
||||
{
|
||||
osg::Vec4f color = SceneUtil::colourFromRGB(cell->mAmbi.mFog);
|
||||
osg::Vec4f color = SceneUtil::colourFromRGB(cell.getMood().mFogColor);
|
||||
|
||||
const float fogDensity = cell.getMood().mFogDensity;
|
||||
if (mDistantFog)
|
||||
{
|
||||
float density = std::max(0.2f, cell->mAmbi.mFogDensity);
|
||||
float density = std::max(0.2f, fogDensity);
|
||||
mLandFogStart = DLInteriorFogEnd * (1.0f - density) + DLInteriorFogStart * density;
|
||||
mLandFogEnd = DLInteriorFogEnd;
|
||||
mUnderwaterFogStart = DLUnderwaterFogStart;
|
||||
|
@ -52,7 +57,7 @@ namespace MWRender
|
|||
mFogColor = color;
|
||||
}
|
||||
else
|
||||
configure(viewDistance, cell->mAmbi.mFogDensity, mUnderwaterIndoorFog, 1.0f, 0.0f, color);
|
||||
configure(viewDistance, fogDensity, mUnderwaterIndoorFog, 1.0f, 0.0f, color);
|
||||
}
|
||||
|
||||
void FogManager::configure(float viewDistance, float fogDepth, float underwaterFog, float dlFactor, float dlOffset,
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
|
||||
#include <osg/Vec4f>
|
||||
|
||||
namespace ESM
|
||||
namespace MWWorld
|
||||
{
|
||||
struct Cell;
|
||||
class Cell;
|
||||
}
|
||||
|
||||
namespace MWRender
|
||||
|
@ -15,7 +15,7 @@ namespace MWRender
|
|||
public:
|
||||
FogManager();
|
||||
|
||||
void configure(float viewDistance, const ESM::Cell* cell);
|
||||
void configure(float viewDistance, const MWWorld::Cell& cell);
|
||||
void configure(float viewDistance, float fogDepth, float underwaterFog, float dlFactor, float dlOffset,
|
||||
const osg::Vec4f& color);
|
||||
|
||||
|
|
|
@ -102,12 +102,13 @@ namespace MWRender
|
|||
void Pathgrid::enableCellPathgrid(const MWWorld::CellStore* store)
|
||||
{
|
||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
|
||||
const ESM::Pathgrid* pathgrid = world->getStore().get<ESM::Pathgrid>().search(*store->getCell());
|
||||
if (!pathgrid)
|
||||
return;
|
||||
|
||||
osg::Vec3f cellPathGridPos(0, 0, 0);
|
||||
Misc::CoordinateConverter(store->getCell()).toWorld(cellPathGridPos);
|
||||
Misc::CoordinateConverter(*store->getCell()).toWorld(cellPathGridPos);
|
||||
|
||||
osg::ref_ptr<osg::PositionAttitudeTransform> cellPathGrid = new osg::PositionAttitudeTransform;
|
||||
cellPathGrid->setPosition(cellPathGridPos);
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include <components/terrain/terraingrid.hpp>
|
||||
|
||||
#include <components/esm3/loadcell.hpp>
|
||||
#include <components/esm4/loadcell.hpp>
|
||||
|
||||
#include <components/debug/debugdraw.hpp>
|
||||
#include <components/detournavigator/navigator.hpp>
|
||||
|
@ -720,14 +721,14 @@ namespace MWRender
|
|||
mSky->setMoonColour(red);
|
||||
}
|
||||
|
||||
void RenderingManager::configureAmbient(const ESM::Cell* cell)
|
||||
void RenderingManager::configureAmbient(const MWWorld::Cell& cell)
|
||||
{
|
||||
bool isInterior = !cell->isExterior() && !(cell->mData.mFlags & ESM::Cell::QuasiEx);
|
||||
bool isInterior = !cell.isExterior() && !cell.isQuasiExterior();
|
||||
bool needsAdjusting = false;
|
||||
if (mResourceSystem->getSceneManager()->getLightingMethod() != SceneUtil::LightingMethod::FFP)
|
||||
needsAdjusting = isInterior;
|
||||
|
||||
auto ambient = SceneUtil::colourFromRGB(cell->mAmbi.mAmbient);
|
||||
osg::Vec4f ambient = SceneUtil::colourFromRGB(cell.getMood().mAmbiantColor);
|
||||
|
||||
if (needsAdjusting)
|
||||
{
|
||||
|
@ -751,7 +752,8 @@ namespace MWRender
|
|||
|
||||
setAmbientColour(ambient);
|
||||
|
||||
osg::Vec4f diffuse = SceneUtil::colourFromRGB(cell->mAmbi.mSunlight);
|
||||
osg::Vec4f diffuse = SceneUtil::colourFromRGB(cell.getMood().mDirectionalColor);
|
||||
|
||||
setSunColour(diffuse, diffuse, 1.f);
|
||||
|
||||
const osg::Vec4f interiorSunPos = osg::Vec4f(-0.15f, 0.15f, 1.f, 0.f);
|
||||
|
@ -871,7 +873,7 @@ namespace MWRender
|
|||
return false;
|
||||
}
|
||||
|
||||
void RenderingManager::configureFog(const ESM::Cell* cell)
|
||||
void RenderingManager::configureFog(const MWWorld::Cell& cell)
|
||||
{
|
||||
mFog->configure(mViewDistance, cell);
|
||||
}
|
||||
|
@ -1405,7 +1407,7 @@ namespace MWRender
|
|||
mMinimumAmbientLuminance
|
||||
= std::clamp(Settings::Manager::getFloat("minimum interior brightness", "Shaders"), 0.f, 1.f);
|
||||
if (MWMechanics::getPlayer().isInCell())
|
||||
configureAmbient(MWMechanics::getPlayer().getCell()->getCell());
|
||||
configureAmbient(*MWMechanics::getPlayer().getCell()->getCell());
|
||||
}
|
||||
else if (it->first == "Shaders"
|
||||
&& (it->second == "light bounds multiplier" || it->second == "maximum light distance"
|
||||
|
|
|
@ -73,6 +73,7 @@ namespace DetourNavigator
|
|||
namespace MWWorld
|
||||
{
|
||||
class GroundcoverStore;
|
||||
class Cell;
|
||||
}
|
||||
|
||||
namespace Debug
|
||||
|
@ -140,8 +141,8 @@ namespace MWRender
|
|||
void setSunColour(const osg::Vec4f& diffuse, const osg::Vec4f& specular, float sunVis);
|
||||
void setNight(bool isNight) { mNight = isNight; }
|
||||
|
||||
void configureAmbient(const ESM::Cell* cell);
|
||||
void configureFog(const ESM::Cell* cell);
|
||||
void configureAmbient(const MWWorld::Cell& cell);
|
||||
void configureFog(const MWWorld::Cell& cell);
|
||||
void configureFog(
|
||||
float fogDepth, float underwaterFog, float dlFactor, float dlOffset, const osg::Vec4f& colour);
|
||||
|
||||
|
|
|
@ -744,7 +744,8 @@ namespace MWRender
|
|||
bool wasInterior = mInterior;
|
||||
if (!isInterior)
|
||||
{
|
||||
mWaterNode->setPosition(getSceneNodeCoordinates(store->getCell()->mData.mX, store->getCell()->mData.mY));
|
||||
mWaterNode->setPosition(
|
||||
getSceneNodeCoordinates(store->getCell()->getGridX(), store->getCell()->getGridY()));
|
||||
mInterior = false;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -766,14 +766,14 @@ namespace MWSound
|
|||
{
|
||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
const MWWorld::ConstPtr player = world->getPlayerPtr();
|
||||
const ESM::Cell* cell = player.getCell()->getCell();
|
||||
auto cell = player.getCell()->getCell();
|
||||
|
||||
if (!cell->isExterior())
|
||||
return;
|
||||
if (mCurrentRegionSound && mOutput->isSoundPlaying(mCurrentRegionSound))
|
||||
return;
|
||||
|
||||
if (const auto next = mRegionSoundSelector.getNextRandom(duration, cell->mRegion, *world))
|
||||
if (const auto next = mRegionSoundSelector.getNextRandom(duration, cell->getRegion(), *world))
|
||||
mCurrentRegionSound = playSound(*next, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
|
@ -781,7 +781,8 @@ namespace MWSound
|
|||
{
|
||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
const MWWorld::ConstPtr player = world->getPlayerPtr();
|
||||
const ESM::Cell* curcell = player.getCell()->getCell();
|
||||
|
||||
const MWWorld::Cell* curcell = player.getCell()->getCell();
|
||||
const auto update = mWaterSoundUpdater.update(player, *world);
|
||||
|
||||
WaterSoundAction action;
|
||||
|
@ -810,7 +811,7 @@ namespace MWSound
|
|||
}
|
||||
|
||||
std::pair<SoundManager::WaterSoundAction, Sound_Buffer*> SoundManager::getWaterSoundAction(
|
||||
const WaterSoundUpdate& update, const ESM::Cell* cell) const
|
||||
const WaterSoundUpdate& update, const MWWorld::Cell* cell) const
|
||||
{
|
||||
if (mNearWaterSound)
|
||||
{
|
||||
|
|
|
@ -30,6 +30,11 @@ namespace ESM
|
|||
struct Cell;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
class Cell;
|
||||
}
|
||||
|
||||
namespace MWSound
|
||||
{
|
||||
class Sound_Output;
|
||||
|
@ -107,7 +112,7 @@ namespace MWSound
|
|||
|
||||
float mTimePassed;
|
||||
|
||||
const ESM::Cell* mLastCell;
|
||||
const MWWorld::Cell* mLastCell;
|
||||
|
||||
Sound* mCurrentRegionSound;
|
||||
|
||||
|
@ -143,7 +148,7 @@ namespace MWSound
|
|||
};
|
||||
|
||||
std::pair<WaterSoundAction, Sound_Buffer*> getWaterSoundAction(
|
||||
const WaterSoundUpdate& update, const ESM::Cell* cell) const;
|
||||
const WaterSoundUpdate& update, const MWWorld::Cell* cell) const;
|
||||
|
||||
SoundManager(const SoundManager& rhs);
|
||||
SoundManager& operator=(const SoundManager& rhs);
|
||||
|
|
61
apps/openmw/mwworld/cell.cpp
Normal file
61
apps/openmw/mwworld/cell.cpp
Normal file
|
@ -0,0 +1,61 @@
|
|||
#include "cell.hpp"
|
||||
|
||||
#include <components/esm3/loadcell.hpp>
|
||||
#include <components/esm4/loadcell.hpp>
|
||||
#include <components/misc/algorithm.hpp>
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
Cell::Cell(const ESM4::Cell& cell)
|
||||
: ESM::CellVariant(cell)
|
||||
, mIsExterior(!(cell.mCellFlags & ESM4::CELL_Interior))
|
||||
, mIsQuasiExterior(cell.mCellFlags & ESM4::CELL_QuasiExt)
|
||||
, mHasWater(cell.mCellFlags & ESM4::CELL_HasWater)
|
||||
, mNoSleep(false) // No such notion in ESM4
|
||||
, mGridPos(cell.mX, cell.mY)
|
||||
, mDisplayname(cell.mFullName)
|
||||
, mNameID(cell.mEditorId)
|
||||
, mRegion(ESM::RefId::sEmpty) // Unimplemented for now
|
||||
, mCellId{
|
||||
.mWorldspace{ Misc::StringUtils::lowerCase(cell.mEditorId) },
|
||||
.mIndex{ cell.getGridX(), cell.getGridY() },
|
||||
.mPaged = isExterior(),}
|
||||
,mMood{
|
||||
.mAmbiantColor = cell.mLighting.ambient,
|
||||
.mDirectionalColor = cell.mLighting.directional,
|
||||
.mFogColor = cell.mLighting.fogColor,
|
||||
.mFogDensity = cell.mLighting.fogPower,}
|
||||
,mWaterHeight(cell.mWaterHeight)
|
||||
{
|
||||
}
|
||||
|
||||
Cell::Cell(const ESM::Cell& cell)
|
||||
: ESM::CellVariant(cell)
|
||||
, mIsExterior(!(cell.mData.mFlags & ESM::Cell::Interior))
|
||||
, mIsQuasiExterior(cell.mData.mFlags & ESM::Cell::QuasiEx)
|
||||
, mHasWater(cell.mData.mFlags & ESM::Cell::HasWater)
|
||||
, mNoSleep(cell.mData.mFlags & ESM::Cell::NoSleep)
|
||||
, mGridPos(cell.getGridX(), cell.getGridY())
|
||||
, mDisplayname(cell.mName)
|
||||
, mNameID(cell.mName)
|
||||
, mRegion(ESM::RefId::sEmpty) // Unimplemented for now
|
||||
, mCellId(cell.getCellId())
|
||||
, mMood{
|
||||
.mAmbiantColor = cell.mAmbi.mAmbient,
|
||||
.mDirectionalColor = cell.mAmbi.mSunlight,
|
||||
.mFogColor = cell.mAmbi.mFog,
|
||||
.mFogDensity = cell.mAmbi.mFogDensity,
|
||||
}
|
||||
,mWaterHeight(cell.mWater)
|
||||
{
|
||||
}
|
||||
|
||||
std::string Cell::getDescription() const
|
||||
{
|
||||
return ESM::visit(ESM::VisitOverload{
|
||||
[&](const ESM::Cell& cell) { return cell.getDescription(); },
|
||||
[&](const ESM4::Cell& cell) { return cell.mEditorId; },
|
||||
},
|
||||
*this);
|
||||
}
|
||||
}
|
70
apps/openmw/mwworld/cell.hpp
Normal file
70
apps/openmw/mwworld/cell.hpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
#ifndef OPENW_MWORLD_CELL
|
||||
#define OPENW_MWORLD_CELL
|
||||
|
||||
#include <osg/Vec2i>
|
||||
|
||||
#include <components/esm/esmbridge.hpp>
|
||||
#include <components/esm/refid.hpp>
|
||||
#include <components/esm3/cellid.hpp>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct Cell;
|
||||
struct CellId;
|
||||
}
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
struct Cell;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
class CellStore;
|
||||
|
||||
class Cell : public ESM::CellVariant
|
||||
{
|
||||
struct MoodData
|
||||
{
|
||||
uint32_t mAmbiantColor;
|
||||
uint32_t mDirectionalColor;
|
||||
uint32_t mFogColor;
|
||||
float mFogDensity;
|
||||
};
|
||||
|
||||
public:
|
||||
explicit Cell(const ESM4::Cell& cell);
|
||||
explicit Cell(const ESM::Cell& cell);
|
||||
|
||||
int getGridX() const { return mGridPos.x(); }
|
||||
int getGridY() const { return mGridPos.y(); }
|
||||
bool isExterior() const { return mIsExterior; }
|
||||
bool isQuasiExterior() const { return mIsQuasiExterior; }
|
||||
bool hasWater() const { return mHasWater; }
|
||||
bool noSleep() const { return mNoSleep; }
|
||||
const ESM::CellId& getCellId() const { return mCellId; }
|
||||
const ESM::RefId& getRegion() const { return mRegion; }
|
||||
std::string_view getNameId() const { return mNameID; }
|
||||
std::string_view getDisplayName() const { return mDisplayname; }
|
||||
std::string getDescription() const;
|
||||
const MoodData& getMood() const { return mMood; }
|
||||
float getWaterHeight() const { return mWaterHeight; }
|
||||
|
||||
private:
|
||||
bool mIsExterior;
|
||||
bool mIsQuasiExterior;
|
||||
bool mHasWater;
|
||||
bool mNoSleep;
|
||||
|
||||
osg::Vec2i mGridPos;
|
||||
std::string mDisplayname; // How the game displays it
|
||||
std::string mNameID; // The name that will be used by the script and console commands
|
||||
ESM::RefId mRegion;
|
||||
ESM::CellId mCellId;
|
||||
MoodData mMood;
|
||||
|
||||
float mWaterHeight;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -7,45 +7,97 @@
|
|||
|
||||
namespace MWWorld
|
||||
{
|
||||
CellRef::CellRef(const ESM::CellRef& ref)
|
||||
: mCellRef(ESM::ReferenceVariant(ref))
|
||||
{
|
||||
}
|
||||
|
||||
CellRef::CellRef(const ESM4::Reference& ref)
|
||||
: mCellRef(ESM::ReferenceVariant(ref))
|
||||
{
|
||||
}
|
||||
|
||||
static const ESM::RefNum emptyRefNum = {};
|
||||
|
||||
const ESM::RefNum& CellRef::getRefNum() const
|
||||
{
|
||||
return std::visit(ESM::VisitOverload{
|
||||
[&](const ESM4::Reference& /*ref*/) -> const ESM::RefNum& { return emptyRefNum; },
|
||||
[&](const ESM::CellRef& ref) -> const ESM::RefNum& { return ref.mRefNum; },
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
}
|
||||
|
||||
const ESM::RefNum& CellRef::getOrAssignRefNum(ESM::RefNum& lastAssignedRefNum)
|
||||
{
|
||||
if (!mCellRef.mRefNum.isSet())
|
||||
{
|
||||
// Generated RefNums have negative mContentFile
|
||||
assert(lastAssignedRefNum.mContentFile < 0);
|
||||
lastAssignedRefNum.mIndex++;
|
||||
if (lastAssignedRefNum.mIndex == 0) // mIndex overflow, so mContentFile should be changed
|
||||
auto esm3Visit = [&](ESM::CellRef& ref) -> const ESM::RefNum& {
|
||||
if (!ref.mRefNum.isSet())
|
||||
{
|
||||
if (lastAssignedRefNum.mContentFile > std::numeric_limits<int32_t>::min())
|
||||
lastAssignedRefNum.mContentFile--;
|
||||
else
|
||||
Log(Debug::Error) << "RefNum counter overflow in CellRef::getOrAssignRefNum";
|
||||
// Generated RefNums have negative mContentFile
|
||||
assert(lastAssignedRefNum.mContentFile < 0);
|
||||
lastAssignedRefNum.mIndex++;
|
||||
if (lastAssignedRefNum.mIndex == 0) // mIndex overflow, so mContentFile should be changed
|
||||
{
|
||||
if (lastAssignedRefNum.mContentFile > std::numeric_limits<int32_t>::min())
|
||||
lastAssignedRefNum.mContentFile--;
|
||||
else
|
||||
Log(Debug::Error) << "RefNum counter overflow in CellRef::getOrAssignRefNum";
|
||||
}
|
||||
ref.mRefNum = lastAssignedRefNum;
|
||||
mChanged = true;
|
||||
}
|
||||
mCellRef.mRefNum = lastAssignedRefNum;
|
||||
mChanged = true;
|
||||
}
|
||||
return mCellRef.mRefNum;
|
||||
return ref.mRefNum;
|
||||
};
|
||||
return std::visit(
|
||||
ESM::VisitOverload{
|
||||
[&](ESM4::Reference& /*ref*/) -> const ESM::RefNum& { return emptyRefNum; },
|
||||
esm3Visit,
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
}
|
||||
|
||||
void CellRef::unsetRefNum()
|
||||
{
|
||||
mCellRef.mRefNum = ESM::RefNum{};
|
||||
std::visit(ESM::VisitOverload{
|
||||
[&](ESM4::Reference& /*ref*/) {},
|
||||
[&](ESM::CellRef& ref) { ref.mRefNum = emptyRefNum; },
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
}
|
||||
|
||||
static const std::string emptyString = "";
|
||||
|
||||
const std::string& CellRef::getDestCell() const
|
||||
{
|
||||
return std::visit(ESM::VisitOverload{
|
||||
[&](const ESM4::Reference& /*ref*/) -> const std::string& { return emptyString; },
|
||||
[&](const ESM::CellRef& ref) -> const std::string& { return ref.mDestCell; },
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
}
|
||||
|
||||
void CellRef::setScale(float scale)
|
||||
{
|
||||
if (scale != mCellRef.mScale)
|
||||
if (scale != getScale())
|
||||
{
|
||||
mChanged = true;
|
||||
mCellRef.mScale = scale;
|
||||
std::visit([scale](auto&& ref) { ref.mScale = scale; }, mCellRef.mVariant);
|
||||
}
|
||||
}
|
||||
|
||||
void CellRef::setPosition(const ESM::Position& position)
|
||||
{
|
||||
mChanged = true;
|
||||
mCellRef.mPos = position;
|
||||
std::visit([&position](auto&& ref) { ref.mPos = position; }, mCellRef.mVariant);
|
||||
}
|
||||
|
||||
float CellRef::getEnchantmentCharge() const
|
||||
{
|
||||
return std::visit(ESM::VisitOverload{
|
||||
[&](const ESM4::Reference& /*ref*/) { return 0.f; },
|
||||
[&](const ESM::CellRef& ref) { return ref.mEnchantmentCharge; },
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
}
|
||||
|
||||
float CellRef::getNormalizedEnchantmentCharge(int maxCharge) const
|
||||
|
@ -54,112 +106,149 @@ namespace MWWorld
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
else if (mCellRef.mEnchantmentCharge == -1)
|
||||
else if (getEnchantmentCharge() == -1)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return mCellRef.mEnchantmentCharge / static_cast<float>(maxCharge);
|
||||
return getEnchantmentCharge() / static_cast<float>(maxCharge);
|
||||
}
|
||||
}
|
||||
|
||||
void CellRef::setEnchantmentCharge(float charge)
|
||||
{
|
||||
if (charge != mCellRef.mEnchantmentCharge)
|
||||
if (charge != getEnchantmentCharge())
|
||||
{
|
||||
mChanged = true;
|
||||
mCellRef.mEnchantmentCharge = charge;
|
||||
|
||||
std::visit(ESM::VisitOverload{
|
||||
[&](ESM4::Reference& /*ref*/) {},
|
||||
[&](ESM::CellRef& ref) { ref.mEnchantmentCharge = charge; },
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
}
|
||||
}
|
||||
|
||||
void CellRef::setCharge(int charge)
|
||||
{
|
||||
if (charge != mCellRef.mChargeInt)
|
||||
{
|
||||
mChanged = true;
|
||||
mCellRef.mChargeInt = charge;
|
||||
}
|
||||
std::visit(ESM::VisitOverload{
|
||||
[&](ESM4::Reference& /*ref*/) {},
|
||||
[&](ESM::CellRef& ref) { ref.mChargeInt = charge; },
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
}
|
||||
|
||||
void CellRef::applyChargeRemainderToBeSubtracted(float chargeRemainder)
|
||||
{
|
||||
mCellRef.mChargeIntRemainder += std::abs(chargeRemainder);
|
||||
if (mCellRef.mChargeIntRemainder > 1.0f)
|
||||
{
|
||||
float newChargeRemainder = (mCellRef.mChargeIntRemainder - std::floor(mCellRef.mChargeIntRemainder));
|
||||
if (mCellRef.mChargeInt <= static_cast<int>(mCellRef.mChargeIntRemainder))
|
||||
auto esm3Visit = [&](ESM::CellRef& cellRef3) {
|
||||
cellRef3.mChargeIntRemainder += std::abs(chargeRemainder);
|
||||
if (cellRef3.mChargeIntRemainder > 1.0f)
|
||||
{
|
||||
mCellRef.mChargeInt = 0;
|
||||
float newChargeRemainder = (cellRef3.mChargeIntRemainder - std::floor(cellRef3.mChargeIntRemainder));
|
||||
if (cellRef3.mChargeInt <= static_cast<int>(cellRef3.mChargeIntRemainder))
|
||||
{
|
||||
cellRef3.mChargeInt = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cellRef3.mChargeInt -= static_cast<int>(cellRef3.mChargeIntRemainder);
|
||||
}
|
||||
cellRef3.mChargeIntRemainder = newChargeRemainder;
|
||||
}
|
||||
else
|
||||
{
|
||||
mCellRef.mChargeInt -= static_cast<int>(mCellRef.mChargeIntRemainder);
|
||||
}
|
||||
mCellRef.mChargeIntRemainder = newChargeRemainder;
|
||||
}
|
||||
};
|
||||
std::visit(
|
||||
ESM::VisitOverload{
|
||||
[&](ESM4::Reference& /*ref*/) {},
|
||||
esm3Visit,
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
}
|
||||
|
||||
void CellRef::setChargeFloat(float charge)
|
||||
{
|
||||
if (charge != mCellRef.mChargeFloat)
|
||||
{
|
||||
mChanged = true;
|
||||
mCellRef.mChargeFloat = charge;
|
||||
}
|
||||
std::visit(ESM::VisitOverload{
|
||||
[&](ESM4::Reference& /*ref*/) {},
|
||||
[&](ESM::CellRef& ref) { ref.mChargeFloat = charge; },
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
}
|
||||
|
||||
const std::string& CellRef::getGlobalVariable() const
|
||||
{
|
||||
return std::visit(ESM::VisitOverload{
|
||||
[&](const ESM4::Reference& /*ref*/) -> const std::string& { return emptyString; },
|
||||
[&](const ESM::CellRef& ref) -> const std::string& { return ref.mGlobalVariable; },
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
}
|
||||
|
||||
void CellRef::resetGlobalVariable()
|
||||
{
|
||||
if (!mCellRef.mGlobalVariable.empty())
|
||||
if (!getGlobalVariable().empty())
|
||||
{
|
||||
mChanged = true;
|
||||
mCellRef.mGlobalVariable.erase();
|
||||
std::visit(ESM::VisitOverload{
|
||||
[&](ESM4::Reference& /*ref*/) {},
|
||||
[&](ESM::CellRef& ref) { ref.mGlobalVariable.erase(); },
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
}
|
||||
}
|
||||
|
||||
void CellRef::setFactionRank(int factionRank)
|
||||
{
|
||||
if (factionRank != mCellRef.mFactionRank)
|
||||
if (factionRank != getFactionRank())
|
||||
{
|
||||
mChanged = true;
|
||||
mCellRef.mFactionRank = factionRank;
|
||||
std::visit([&](auto&& ref) { ref.mFactionRank = factionRank; }, mCellRef.mVariant);
|
||||
}
|
||||
}
|
||||
|
||||
void CellRef::setOwner(const ESM::RefId& owner)
|
||||
{
|
||||
if (owner != mCellRef.mOwner)
|
||||
if (owner != getOwner())
|
||||
{
|
||||
mChanged = true;
|
||||
mCellRef.mOwner = owner;
|
||||
std::visit(ESM::VisitOverload{
|
||||
[&](ESM4::Reference& /*ref*/) {},
|
||||
[&](ESM::CellRef& ref) { ref.mOwner = owner; },
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
}
|
||||
}
|
||||
|
||||
void CellRef::setSoul(const ESM::RefId& soul)
|
||||
{
|
||||
if (soul != mCellRef.mSoul)
|
||||
if (soul != getSoul())
|
||||
{
|
||||
mChanged = true;
|
||||
mCellRef.mSoul = soul;
|
||||
std::visit(ESM::VisitOverload{
|
||||
[&](ESM4::Reference& /*ref*/) {},
|
||||
[&](ESM::CellRef& ref) { ref.mSoul = soul; },
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
}
|
||||
}
|
||||
|
||||
void CellRef::setFaction(const ESM::RefId& faction)
|
||||
{
|
||||
if (faction != mCellRef.mFaction)
|
||||
if (faction != getFaction())
|
||||
{
|
||||
mChanged = true;
|
||||
mCellRef.mFaction = faction;
|
||||
std::visit(ESM::VisitOverload{
|
||||
[&](ESM4::Reference& /*ref*/) {},
|
||||
[&](ESM::CellRef& ref) { ref.mFaction = faction; },
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
}
|
||||
}
|
||||
|
||||
void CellRef::setLockLevel(int lockLevel)
|
||||
{
|
||||
if (lockLevel != mCellRef.mLockLevel)
|
||||
if (lockLevel != getLockLevel())
|
||||
{
|
||||
mChanged = true;
|
||||
mCellRef.mLockLevel = lockLevel;
|
||||
std::visit([&](auto&& ref) { ref.mLockLevel = lockLevel; }, mCellRef.mVariant);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -173,30 +262,41 @@ namespace MWWorld
|
|||
|
||||
void CellRef::unlock()
|
||||
{
|
||||
setLockLevel(-abs(mCellRef.mLockLevel)); // Makes lockLevel negative
|
||||
setLockLevel(-abs(getLockLevel())); // Makes lockLevel negative
|
||||
}
|
||||
|
||||
void CellRef::setTrap(const ESM::RefId& trap)
|
||||
{
|
||||
if (trap != mCellRef.mTrap)
|
||||
if (trap != getTrap())
|
||||
{
|
||||
mChanged = true;
|
||||
mCellRef.mTrap = trap;
|
||||
std::visit(ESM::VisitOverload{
|
||||
[&](ESM4::Reference& /*ref*/) {},
|
||||
[&](ESM::CellRef& ref) { ref.mTrap = trap; },
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
}
|
||||
}
|
||||
|
||||
void CellRef::setGoldValue(int value)
|
||||
{
|
||||
if (value != mCellRef.mGoldValue)
|
||||
if (value != getGoldValue())
|
||||
{
|
||||
mChanged = true;
|
||||
mCellRef.mGoldValue = value;
|
||||
std::visit(ESM::VisitOverload{
|
||||
[&](ESM4::Reference& /*ref*/) {},
|
||||
[&](ESM::CellRef& ref) { ref.mGoldValue = value; },
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
}
|
||||
}
|
||||
|
||||
void CellRef::writeState(ESM::ObjectState& state) const
|
||||
{
|
||||
state.mRef = mCellRef;
|
||||
std::visit(ESM::VisitOverload{
|
||||
[&](const ESM4::Reference& /*ref*/) {},
|
||||
[&](const ESM::CellRef& ref) { state.mRef = ref; },
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
|
||||
#include <string_view>
|
||||
|
||||
#include <components/esm/esmbridge.hpp>
|
||||
#include <components/esm3/cellref.hpp>
|
||||
#include <components/esm4/loadrefr.hpp>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
|
@ -16,15 +18,14 @@ namespace MWWorld
|
|||
/// \brief Encapsulated variant of ESM::CellRef with change tracking
|
||||
class CellRef
|
||||
{
|
||||
protected:
|
||||
public:
|
||||
CellRef(const ESM::CellRef& ref)
|
||||
: mCellRef(ref)
|
||||
{
|
||||
mChanged = false;
|
||||
}
|
||||
explicit CellRef(const ESM::CellRef& ref);
|
||||
|
||||
explicit CellRef(const ESM4::Reference& ref);
|
||||
|
||||
// Note: Currently unused for items in containers
|
||||
const ESM::RefNum& getRefNum() const { return mCellRef.mRefNum; }
|
||||
const ESM::RefNum& getRefNum() const;
|
||||
|
||||
// Returns RefNum.
|
||||
// If RefNum is not set, assigns a generated one and changes the "lastAssignedRefNum" counter.
|
||||
|
@ -34,32 +35,62 @@ namespace MWWorld
|
|||
void unsetRefNum();
|
||||
|
||||
/// Does the RefNum have a content file?
|
||||
bool hasContentFile() const { return mCellRef.mRefNum.hasContentFile(); }
|
||||
bool hasContentFile() const { return getRefNum().hasContentFile(); }
|
||||
|
||||
// Id of object being referenced
|
||||
const ESM::RefId& getRefId() const { return mCellRef.mRefID; }
|
||||
const ESM::RefId& getRefId() const
|
||||
{
|
||||
struct Visitor
|
||||
{
|
||||
const ESM::RefId& operator()(const ESM::CellRef& ref) { return ref.mRefID; }
|
||||
const ESM::RefId& operator()(const ESM4::Reference& ref) { return ref.mBaseObj; }
|
||||
};
|
||||
return std::visit(Visitor(), mCellRef.mVariant);
|
||||
}
|
||||
|
||||
// For doors - true if this door teleports to somewhere else, false
|
||||
// if it should open through animation.
|
||||
bool getTeleport() const { return mCellRef.mTeleport; }
|
||||
bool getTeleport() const
|
||||
{
|
||||
struct Visitor
|
||||
{
|
||||
bool operator()(const ESM::CellRef& ref) { return ref.mTeleport; }
|
||||
bool operator()(const ESM4::Reference& ref) { return 0; }
|
||||
};
|
||||
return std::visit(Visitor(), mCellRef.mVariant);
|
||||
}
|
||||
|
||||
// Teleport location for the door, if this is a teleporting door.
|
||||
const ESM::Position& getDoorDest() const { return mCellRef.mDoorDest; }
|
||||
const ESM::Position& getDoorDest() const
|
||||
{
|
||||
struct Visitor
|
||||
{
|
||||
const ESM::Position& operator()(const ESM::CellRef& ref) { return ref.mDoorDest; }
|
||||
const ESM::Position& operator()(const ESM4::Reference& ref) { return ref.mDoor.destPos; }
|
||||
};
|
||||
return std::visit(Visitor(), mCellRef.mVariant);
|
||||
}
|
||||
|
||||
// Destination cell for doors (optional)
|
||||
const std::string& getDestCell() const { return mCellRef.mDestCell; }
|
||||
const std::string& getDestCell() const;
|
||||
|
||||
// Scale applied to mesh
|
||||
float getScale() const { return mCellRef.mScale; }
|
||||
float getScale() const
|
||||
{
|
||||
return std::visit([&](auto&& ref) { return ref.mScale; }, mCellRef.mVariant);
|
||||
}
|
||||
void setScale(float scale);
|
||||
|
||||
// The *original* position and rotation as it was given in the Construction Set.
|
||||
// Current position and rotation of the object is stored in RefData.
|
||||
const ESM::Position& getPosition() const { return mCellRef.mPos; }
|
||||
const ESM::Position& getPosition() const
|
||||
{
|
||||
return std::visit([](auto&& ref) -> const ESM::Position& { return ref.mPos; }, mCellRef.mVariant);
|
||||
}
|
||||
void setPosition(const ESM::Position& position);
|
||||
|
||||
// Remaining enchantment charge. This could be -1 if the charge was not touched yet (i.e. full).
|
||||
float getEnchantmentCharge() const { return mCellRef.mEnchantmentCharge; }
|
||||
float getEnchantmentCharge() const;
|
||||
|
||||
// Remaining enchantment charge rescaled to the supplied maximum charge (such as one of the enchantment).
|
||||
float getNormalizedEnchantmentCharge(int maxCharge) const;
|
||||
|
@ -69,50 +100,115 @@ namespace MWWorld
|
|||
// For weapon or armor, this is the remaining item health.
|
||||
// For tools (lockpicks, probes, repair hammer) it is the remaining uses.
|
||||
// If this returns int(-1) it means full health.
|
||||
int getCharge() const { return mCellRef.mChargeInt; }
|
||||
float getChargeFloat() const { return mCellRef.mChargeFloat; } // Implemented as union with int charge
|
||||
int getCharge() const
|
||||
{
|
||||
struct Visitor
|
||||
{
|
||||
int operator()(const ESM::CellRef& ref) { return ref.mChargeInt; }
|
||||
int operator()(const ESM4::Reference& /*ref*/) { return 0; }
|
||||
};
|
||||
return std::visit(Visitor(), mCellRef.mVariant);
|
||||
}
|
||||
float getChargeFloat() const
|
||||
{
|
||||
struct Visitor
|
||||
{
|
||||
float operator()(const ESM::CellRef& ref) { return ref.mChargeFloat; }
|
||||
float operator()(const ESM4::Reference& /*ref*/) { return 0; }
|
||||
};
|
||||
return std::visit(Visitor(), mCellRef.mVariant);
|
||||
} // Implemented as union with int charge
|
||||
void setCharge(int charge);
|
||||
void setChargeFloat(float charge);
|
||||
void applyChargeRemainderToBeSubtracted(float chargeRemainder); // Stores remainders and applies if > 1
|
||||
|
||||
// The NPC that owns this object (and will get angry if you steal it)
|
||||
const ESM::RefId& getOwner() const { return mCellRef.mOwner; }
|
||||
const ESM::RefId& getOwner() const
|
||||
{
|
||||
struct Visitor
|
||||
{
|
||||
const ESM::RefId& operator()(const ESM::CellRef& ref) { return ref.mOwner; }
|
||||
const ESM::RefId& operator()(const ESM4::Reference& /*ref*/) { return ESM::RefId::sEmpty; }
|
||||
};
|
||||
return std::visit(Visitor(), mCellRef.mVariant);
|
||||
}
|
||||
void setOwner(const ESM::RefId& owner);
|
||||
|
||||
// Name of a global variable. If the global variable is set to '1', using the object is temporarily allowed
|
||||
// even if it has an Owner field.
|
||||
// Used by bed rent scripts to allow the player to use the bed for the duration of the rent.
|
||||
const std::string& getGlobalVariable() const { return mCellRef.mGlobalVariable; }
|
||||
const std::string& getGlobalVariable() const;
|
||||
|
||||
void resetGlobalVariable();
|
||||
|
||||
// ID of creature trapped in this soul gem
|
||||
const ESM::RefId& getSoul() const { return mCellRef.mSoul; }
|
||||
const ESM::RefId& getSoul() const
|
||||
{
|
||||
struct Visitor
|
||||
{
|
||||
const ESM::RefId& operator()(const ESM::CellRef& ref) { return ref.mSoul; }
|
||||
const ESM::RefId& operator()(const ESM4::Reference& /*ref*/) { return ESM::RefId::sEmpty; }
|
||||
};
|
||||
return std::visit(Visitor(), mCellRef.mVariant);
|
||||
}
|
||||
void setSoul(const ESM::RefId& soul);
|
||||
|
||||
// The faction that owns this object (and will get angry if
|
||||
// you take it and are not a faction member)
|
||||
const ESM::RefId& getFaction() const { return mCellRef.mFaction; }
|
||||
const ESM::RefId& getFaction() const
|
||||
{
|
||||
struct Visitor
|
||||
{
|
||||
const ESM::RefId& operator()(const ESM::CellRef& ref) { return ref.mFaction; }
|
||||
const ESM::RefId& operator()(const ESM4::Reference& /*ref*/) { return ESM::RefId::sEmpty; }
|
||||
};
|
||||
return std::visit(Visitor(), mCellRef.mVariant);
|
||||
}
|
||||
void setFaction(const ESM::RefId& faction);
|
||||
|
||||
// PC faction rank required to use the item. Sometimes is -1, which means "any rank".
|
||||
void setFactionRank(int factionRank);
|
||||
int getFactionRank() const { return mCellRef.mFactionRank; }
|
||||
int getFactionRank() const
|
||||
{
|
||||
return std::visit([&](auto&& ref) { return ref.mFactionRank; }, mCellRef.mVariant);
|
||||
}
|
||||
|
||||
// Lock level for doors and containers
|
||||
// Positive for a locked door. 0 for a door that was never locked.
|
||||
// For an unlocked door, it is set to -(previous locklevel)
|
||||
int getLockLevel() const { return mCellRef.mLockLevel; }
|
||||
int getLockLevel() const
|
||||
{
|
||||
return std::visit([](auto&& ref) { return static_cast<int>(ref.mLockLevel); }, mCellRef.mVariant);
|
||||
}
|
||||
void setLockLevel(int lockLevel);
|
||||
void lock(int lockLevel);
|
||||
void unlock();
|
||||
// Key and trap ID names, if any
|
||||
const ESM::RefId& getKey() const { return mCellRef.mKey; }
|
||||
const ESM::RefId& getTrap() const { return mCellRef.mTrap; }
|
||||
const ESM::RefId& getKey() const
|
||||
{
|
||||
return std::visit([](auto&& ref) -> const ESM::RefId& { return ref.mKey; }, mCellRef.mVariant);
|
||||
}
|
||||
const ESM::RefId& getTrap() const
|
||||
{
|
||||
struct Visitor
|
||||
{
|
||||
const ESM::RefId& operator()(const ESM::CellRef& ref) { return ref.mTrap; }
|
||||
const ESM::RefId& operator()(const ESM4::Reference& /*ref*/) { return ESM::RefId::sEmpty; }
|
||||
};
|
||||
return std::visit(Visitor(), mCellRef.mVariant);
|
||||
}
|
||||
void setTrap(const ESM::RefId& trap);
|
||||
|
||||
// This is 5 for Gold_005 references, 100 for Gold_100 and so on.
|
||||
int getGoldValue() const { return mCellRef.mGoldValue; }
|
||||
int getGoldValue() const
|
||||
{
|
||||
struct Visitor
|
||||
{
|
||||
int operator()(const ESM::CellRef& ref) { return ref.mGoldValue; }
|
||||
int operator()(const ESM4::Reference& /*ref*/) { return 0; }
|
||||
};
|
||||
return std::visit(Visitor(), mCellRef.mVariant);
|
||||
}
|
||||
void setGoldValue(int value);
|
||||
|
||||
// Write the content of this CellRef into the given ObjectState
|
||||
|
@ -122,8 +218,8 @@ namespace MWWorld
|
|||
bool hasChanged() const { return mChanged; }
|
||||
|
||||
private:
|
||||
bool mChanged;
|
||||
ESM::CellRef mCellRef;
|
||||
bool mChanged = false;
|
||||
ESM::ReferenceVariant mCellRef;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@ namespace MWWorld
|
|||
/// all methods are known.
|
||||
void load(ESM::CellRef& ref, bool deleted, const MWWorld::ESMStore& esmStore);
|
||||
|
||||
void load(const ESM4::Reference& ref, bool deleted, const MWWorld::ESMStore& esmStore);
|
||||
|
||||
LiveRef& insert(const LiveRef& item)
|
||||
{
|
||||
mList.push_back(item);
|
||||
|
|
|
@ -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"
|
||||
|
@ -369,6 +371,29 @@ namespace MWWorld
|
|||
}
|
||||
}
|
||||
|
||||
template <typename X>
|
||||
void CellRefList<X>::load(const ESM4::Reference& ref, bool deleted, const MWWorld::ESMStore& esmStore)
|
||||
{
|
||||
|
||||
if constexpr (!ESM::isESM4Rec(X::sRecordId))
|
||||
return;
|
||||
|
||||
const MWWorld::Store<X>& store = esmStore.get<X>();
|
||||
|
||||
if (const X* ptr = store.search(ref.mBaseObj))
|
||||
{
|
||||
LiveRef liveCellRef(ref, ptr);
|
||||
if (deleted)
|
||||
liveCellRef.mData.setDeletedByContentFile(true);
|
||||
mList.push_back(liveCellRef);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log(Debug::Warning) << "Warning: could not resolve cell reference '" << ref.mId << "'"
|
||||
<< " (dropping reference)";
|
||||
}
|
||||
}
|
||||
|
||||
template <typename X>
|
||||
bool operator==(const LiveCellRef<X>& ref, int pRefnum)
|
||||
{
|
||||
|
@ -503,26 +528,27 @@ namespace MWWorld
|
|||
return false;
|
||||
}
|
||||
|
||||
CellStore::CellStore(const ESM::Cell* cell, const MWWorld::ESMStore& esmStore, ESM::ReadersCache& readers)
|
||||
CellStore::CellStore(MWWorld::Cell cell, const MWWorld::ESMStore& esmStore, ESM::ReadersCache& readers)
|
||||
: mStore(esmStore)
|
||||
, mReaders(readers)
|
||||
, mCell(cell)
|
||||
, mCellVariant(std::move(cell))
|
||||
, mState(State_Unloaded)
|
||||
, mHasState(false)
|
||||
, mLastRespawn(0, 0)
|
||||
, mCellStoreImp(std::make_unique<CellStoreImp>())
|
||||
, mRechargingItemsUpToDate(false)
|
||||
{
|
||||
|
||||
std::apply([this](auto&... x) { (CellStoreImp::assignStoreToIndex(*this, x), ...); }, mCellStoreImp->mRefLists);
|
||||
mWaterLevel = cell->mWater;
|
||||
mWaterLevel = mCellVariant.getWaterHeight();
|
||||
}
|
||||
|
||||
CellStore::~CellStore() = default;
|
||||
CellStore::CellStore(CellStore&&) = default;
|
||||
|
||||
const ESM::Cell* CellStore::getCell() const
|
||||
const MWWorld::Cell* CellStore::getCell() const
|
||||
{
|
||||
return mCell;
|
||||
return &mCellVariant;
|
||||
}
|
||||
|
||||
CellStore::State CellStore::getState() const
|
||||
|
@ -676,22 +702,20 @@ namespace MWWorld
|
|||
}
|
||||
}
|
||||
|
||||
void CellStore::listRefs()
|
||||
void CellStore::listRefs(const ESM::Cell& cell)
|
||||
{
|
||||
assert(mCell);
|
||||
|
||||
if (mCell->mContextList.empty())
|
||||
if (cell.mContextList.empty())
|
||||
return; // this is a dynamically generated cell -> skipping.
|
||||
|
||||
// Load references from all plugins that do something with this cell.
|
||||
for (size_t i = 0; i < mCell->mContextList.size(); i++)
|
||||
for (size_t i = 0; i < cell.mContextList.size(); i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Reopen the ESM reader and seek to the right position.
|
||||
const std::size_t index = static_cast<std::size_t>(mCell->mContextList[i].index);
|
||||
const std::size_t index = static_cast<std::size_t>(cell.mContextList[i].index);
|
||||
const ESM::ReadersCache::BusyItem reader = mReaders.get(index);
|
||||
mCell->restore(*reader, i);
|
||||
cell.restore(*reader, i);
|
||||
|
||||
ESM::CellRef ref;
|
||||
|
||||
|
@ -707,8 +731,8 @@ namespace MWWorld
|
|||
|
||||
// Don't list reference if it was moved to a different cell.
|
||||
ESM::MovedCellRefTracker::const_iterator iter
|
||||
= std::find(mCell->mMovedRefs.begin(), mCell->mMovedRefs.end(), ref.mRefNum);
|
||||
if (iter != mCell->mMovedRefs.end())
|
||||
= std::find(cell.mMovedRefs.begin(), cell.mMovedRefs.end(), ref.mRefNum);
|
||||
if (iter != cell.mMovedRefs.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -724,33 +748,46 @@ namespace MWWorld
|
|||
}
|
||||
|
||||
// List moved references, from separately tracked list.
|
||||
for (const auto& [ref, deleted] : mCell->mLeasedRefs)
|
||||
for (const auto& [ref, deleted] : cell.mLeasedRefs)
|
||||
{
|
||||
if (!deleted)
|
||||
mIds.push_back(ref.mRefID);
|
||||
}
|
||||
}
|
||||
|
||||
void CellStore::listRefs(const ESM4::Cell& cell)
|
||||
{
|
||||
auto& refs = MWBase::Environment::get().getWorld()->getStore().get<ESM4::Reference>();
|
||||
|
||||
for (const auto& ref : refs)
|
||||
{
|
||||
if (ref.mParent == cell.mId)
|
||||
{
|
||||
mIds.push_back(ref.mBaseObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CellStore::listRefs()
|
||||
{
|
||||
ESM::visit([&](auto&& cell) { listRefs(cell); }, mCellVariant);
|
||||
std::sort(mIds.begin(), mIds.end());
|
||||
}
|
||||
|
||||
void CellStore::loadRefs()
|
||||
void CellStore::loadRefs(const ESM::Cell& cell, std::map<ESM::RefNum, ESM::RefId>& refNumToID)
|
||||
{
|
||||
assert(mCell);
|
||||
|
||||
if (mCell->mContextList.empty())
|
||||
if (cell.mContextList.empty())
|
||||
return; // this is a dynamically generated cell -> skipping.
|
||||
|
||||
std::map<ESM::RefNum, ESM::RefId> refNumToID; // used to detect refID modifications
|
||||
|
||||
// Load references from all plugins that do something with this cell.
|
||||
for (size_t i = 0; i < mCell->mContextList.size(); i++)
|
||||
for (size_t i = 0; i < cell.mContextList.size(); i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Reopen the ESM reader and seek to the right position.
|
||||
const std::size_t index = static_cast<std::size_t>(mCell->mContextList[i].index);
|
||||
const std::size_t index = static_cast<std::size_t>(cell.mContextList[i].index);
|
||||
const ESM::ReadersCache::BusyItem reader = mReaders.get(index);
|
||||
mCell->restore(*reader, i);
|
||||
cell.restore(*reader, i);
|
||||
|
||||
ESM::CellRef ref;
|
||||
// Get each reference in turn
|
||||
|
@ -765,8 +802,8 @@ namespace MWWorld
|
|||
|
||||
// Don't load reference if it was moved to a different cell.
|
||||
ESM::MovedCellRefTracker::const_iterator iter
|
||||
= std::find(mCell->mMovedRefs.begin(), mCell->mMovedRefs.end(), ref.mRefNum);
|
||||
if (iter != mCell->mMovedRefs.end())
|
||||
= std::find(cell.mMovedRefs.begin(), cell.mMovedRefs.end(), ref.mRefNum);
|
||||
if (iter != cell.mMovedRefs.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -780,27 +817,46 @@ namespace MWWorld
|
|||
<< ": " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
// Load moved references, from separately tracked list.
|
||||
for (const auto& leasedRef : mCell->mLeasedRefs)
|
||||
for (const auto& leasedRef : cell.mLeasedRefs)
|
||||
{
|
||||
ESM::CellRef& ref = const_cast<ESM::CellRef&>(leasedRef.first);
|
||||
bool deleted = leasedRef.second;
|
||||
|
||||
loadRef(ref, deleted, refNumToID);
|
||||
}
|
||||
}
|
||||
|
||||
void CellStore::loadRefs(const ESM4::Cell& cell, std::map<ESM::RefNum, ESM::RefId>& refNumToID)
|
||||
{
|
||||
auto& refs = MWBase::Environment::get().getWorld()->getStore().get<ESM4::Reference>();
|
||||
|
||||
for (const auto& ref : refs)
|
||||
{
|
||||
if (ref.mParent == cell.mId)
|
||||
{
|
||||
loadRef(ref, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CellStore::loadRefs()
|
||||
{
|
||||
std::map<ESM::RefNum, ESM::RefId> refNumToID; // used to detect refID modifications
|
||||
|
||||
ESM::visit([&](auto&& cell) { loadRefs(cell, refNumToID); }, mCellVariant);
|
||||
|
||||
updateMergedRefs();
|
||||
}
|
||||
|
||||
bool CellStore::isExterior() const
|
||||
{
|
||||
return mCell->isExterior();
|
||||
return mCellVariant.isExterior();
|
||||
}
|
||||
|
||||
bool CellStore::isQuasiExterior() const
|
||||
{
|
||||
return (mCell->mData.mFlags & ESM::Cell::QuasiEx) != 0;
|
||||
return mCellVariant.isQuasiExterior();
|
||||
}
|
||||
|
||||
Ptr CellStore::searchInContainer(const ESM::RefId& id)
|
||||
|
@ -823,6 +879,18 @@ namespace MWWorld
|
|||
return Ptr();
|
||||
}
|
||||
|
||||
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) { storeIn.load(ref, deleted, store); });
|
||||
});
|
||||
}
|
||||
|
||||
void CellStore::loadRef(ESM::CellRef& ref, bool deleted, std::map<ESM::RefNum, ESM::RefId>& refNumToID)
|
||||
{
|
||||
const MWWorld::ESMStore& store = mStore;
|
||||
|
@ -874,7 +942,7 @@ namespace MWWorld
|
|||
{
|
||||
mHasState = true;
|
||||
|
||||
if (mCell->mData.mFlags & ESM::Cell::Interior && mCell->mData.mFlags & ESM::Cell::HasWater)
|
||||
if (!mCellVariant.isExterior() && mCellVariant.hasWater())
|
||||
mWaterLevel = state.mWaterLevel;
|
||||
|
||||
mLastRespawn = MWWorld::TimeStamp(state.mLastRespawn);
|
||||
|
@ -882,9 +950,9 @@ namespace MWWorld
|
|||
|
||||
void CellStore::saveState(ESM::CellState& state) const
|
||||
{
|
||||
state.mId = mCell->getCellId();
|
||||
state.mId = mCellVariant.getCellId();
|
||||
|
||||
if (mCell->mData.mFlags & ESM::Cell::Interior && mCell->mData.mFlags & ESM::Cell::HasWater)
|
||||
if (!mCellVariant.isExterior() && mCellVariant.hasWater())
|
||||
state.mWaterLevel = mWaterLevel;
|
||||
|
||||
state.mHasFogOfWar = (mFogState.get() ? 1 : 0);
|
||||
|
@ -895,7 +963,7 @@ namespace MWWorld
|
|||
{
|
||||
if (mFogState.get())
|
||||
{
|
||||
mFogState->save(writer, mCell->mData.mFlags & ESM::Cell::Interior);
|
||||
mFogState->save(writer, !mCellVariant.isExterior());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -999,8 +1067,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 +1084,21 @@ namespace MWWorld
|
|||
}
|
||||
}
|
||||
|
||||
bool operator==(const CellStore& left, const CellStore& right)
|
||||
struct IsEqualVisitor
|
||||
{
|
||||
return left.getCell()->getCellId() == right.getCell()->getCellId();
|
||||
}
|
||||
bool operator()(const ESM::Cell& a, const ESM::Cell& b) const { return a.getCellId() == b.getCellId(); }
|
||||
bool operator()(const ESM4::Cell& a, const ESM4::Cell& b) const { return a.mId == b.mId; }
|
||||
|
||||
bool operator!=(const CellStore& left, const CellStore& right)
|
||||
template <class L, class R>
|
||||
bool operator()(const L&, const R&) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
bool CellStore::operator==(const CellStore& right) const
|
||||
{
|
||||
return !(left == right);
|
||||
return ESM::visit(IsEqualVisitor(), this->mCellVariant, right.mCellVariant);
|
||||
}
|
||||
|
||||
void CellStore::setFog(std::unique_ptr<ESM::FogState>&& fog)
|
||||
|
@ -1230,4 +1305,5 @@ namespace MWWorld
|
|||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <typeinfo>
|
||||
#include <vector>
|
||||
|
||||
#include "cell.hpp"
|
||||
#include "cellreflist.hpp"
|
||||
#include "livecellref.hpp"
|
||||
|
||||
|
@ -49,6 +50,15 @@ namespace ESM
|
|||
struct Static;
|
||||
struct Weapon;
|
||||
struct BodyPart;
|
||||
struct CellCommon;
|
||||
}
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
struct Cell;
|
||||
struct Reference;
|
||||
struct Static;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
|
@ -61,7 +71,9 @@ namespace MWWorld
|
|||
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
|
||||
|
@ -85,7 +97,7 @@ namespace MWWorld
|
|||
// Note this is nullptr until the cell is explored to save some memory
|
||||
std::unique_ptr<ESM::FogState> mFogState;
|
||||
|
||||
const ESM::Cell* mCell;
|
||||
MWWorld::Cell mCellVariant;
|
||||
State mState;
|
||||
bool mHasState;
|
||||
std::vector<ESM::RefId> mIds;
|
||||
|
@ -180,11 +192,11 @@ 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(MWWorld::Cell cell, const MWWorld::ESMStore& store, ESM::ReadersCache& readers);
|
||||
CellStore(CellStore&&);
|
||||
~CellStore();
|
||||
|
||||
const ESM::Cell* getCell() const;
|
||||
const MWWorld::Cell* getCell() const;
|
||||
|
||||
State getState() const;
|
||||
|
||||
|
@ -331,6 +343,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;
|
||||
|
||||
|
@ -366,20 +379,27 @@ namespace MWWorld
|
|||
|
||||
Ptr getMovedActor(int actorId) const;
|
||||
|
||||
bool operator==(const CellStore& right) const;
|
||||
|
||||
private:
|
||||
/// Run through references and store IDs
|
||||
void listRefs(const ESM::Cell& cell);
|
||||
void listRefs(const ESM4::Cell& cell);
|
||||
void listRefs();
|
||||
|
||||
void loadRefs(const ESM::Cell& cell, std::map<ESM::RefNum, ESM::RefId>& refNumToID);
|
||||
void loadRefs(const ESM4::Cell& cell, std::map<ESM::RefNum, ESM::RefId>& refNumToID);
|
||||
|
||||
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
|
||||
|
|
|
@ -210,8 +210,8 @@ namespace MWWorld
|
|||
|
||||
static bool readRecord(ESM4::Reader& reader, ESMStore& store)
|
||||
{
|
||||
return std::apply([&reader](auto&... x) { return (ESMStoreImp::typedReadRecordESM4(reader, x) || ...); },
|
||||
store.mStoreImp->mStores);
|
||||
return std::apply(
|
||||
[&reader](auto&... x) { return (typedReadRecordESM4(reader, x) || ...); }, store.mStoreImp->mStores);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -278,6 +278,7 @@ namespace MWWorld
|
|||
case ESM::REC_STAT:
|
||||
case ESM::REC_WEAP:
|
||||
case ESM::REC_BODY:
|
||||
case ESM::REC_STAT4:
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
@ -595,8 +596,8 @@ namespace MWWorld
|
|||
removeMissingObjects(getWritable<ESM::ItemLevList>());
|
||||
}
|
||||
|
||||
// Leveled lists can be modified by scripts. This removes items that no longer exist (presumably because the plugin
|
||||
// was removed) from modified lists
|
||||
// Leveled lists can be modified by scripts. This removes items that no longer exist (presumably because the
|
||||
// plugin was removed) from modified lists
|
||||
template <class T>
|
||||
void ESMStore::removeMissingObjects(Store<T>& store)
|
||||
{
|
||||
|
|
|
@ -22,9 +22,16 @@ MWWorld::LiveCellRefBase::LiveCellRefBase(unsigned int type, const ESM::CellRef&
|
|||
{
|
||||
}
|
||||
|
||||
MWWorld::LiveCellRefBase::LiveCellRefBase(unsigned int type, const ESM4::Reference& cref)
|
||||
: mClass(&Class::get(type))
|
||||
, mRef(cref)
|
||||
, mData(cref)
|
||||
{
|
||||
}
|
||||
|
||||
void MWWorld::LiveCellRefBase::loadImp(const ESM::ObjectState& state)
|
||||
{
|
||||
mRef = state.mRef;
|
||||
mRef = MWWorld::CellRef(state.mRef);
|
||||
mData = RefData(state, mData.isDeletedByContentFile());
|
||||
|
||||
Ptr ptr(this);
|
||||
|
|
|
@ -35,6 +35,7 @@ namespace MWWorld
|
|||
RefData mData;
|
||||
|
||||
LiveCellRefBase(unsigned int type, const ESM::CellRef& cref = ESM::CellRef());
|
||||
LiveCellRefBase(unsigned int type, const ESM4::Reference& cref);
|
||||
/* Need this for the class to be recognized as polymorphic */
|
||||
virtual ~LiveCellRefBase() {}
|
||||
|
||||
|
@ -87,7 +88,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 +97,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.
|
||||
|
@ -113,6 +116,12 @@ namespace MWWorld
|
|||
{
|
||||
}
|
||||
|
||||
LiveCellRef(const ESM4::Reference& cref, const X* b = nullptr)
|
||||
: LiveCellRefBase(X::sRecordId, cref)
|
||||
, mBase(b)
|
||||
{
|
||||
}
|
||||
|
||||
LiveCellRef(const X* b = nullptr)
|
||||
: LiveCellRefBase(X::sRecordId)
|
||||
, mBase(b)
|
||||
|
@ -130,7 +139,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.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "manualref.hpp"
|
||||
#include <components/esm/records.hpp>
|
||||
#include <components/esm4/loadstat.hpp>
|
||||
|
||||
#include "esmstore.hpp"
|
||||
|
||||
|
@ -89,7 +90,9 @@ MWWorld::ManualRef::ManualRef(const MWWorld::ESMStore& store, const ESM::RefId&
|
|||
case ESM::REC_BODY:
|
||||
create(store.get<ESM::BodyPart>(), name, mRef, mPtr);
|
||||
break;
|
||||
|
||||
case ESM::REC_STAT4:
|
||||
create(store.get<ESM4::Static>(), name, mRef, mPtr);
|
||||
break;
|
||||
case 0:
|
||||
throw std::logic_error("failed to create manual cell ref for " + name.getRefIdString() + " (unknown ID)");
|
||||
|
||||
|
|
|
@ -85,6 +85,19 @@ namespace MWWorld
|
|||
{
|
||||
}
|
||||
|
||||
RefData::RefData(const ESM4::Reference& cellRef)
|
||||
: mBaseNode(nullptr)
|
||||
, mDeletedByContentFile(false)
|
||||
, mEnabled(true)
|
||||
, mPhysicsPostponed(false)
|
||||
, mCount(1)
|
||||
, mPosition(cellRef.mPos)
|
||||
, mCustomData(nullptr)
|
||||
, mChanged(false)
|
||||
, mFlags(0)
|
||||
{
|
||||
}
|
||||
|
||||
RefData::RefData(const ESM::ObjectState& objectState, bool deletedByContentFile)
|
||||
: mBaseNode(nullptr)
|
||||
, mDeletedByContentFile(deletedByContentFile)
|
||||
|
|
|
@ -25,6 +25,11 @@ namespace ESM
|
|||
struct ObjectState;
|
||||
}
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
struct Reference;
|
||||
}
|
||||
|
||||
namespace MWLua
|
||||
{
|
||||
class LocalScripts;
|
||||
|
@ -76,6 +81,7 @@ namespace MWWorld
|
|||
/// be altered without affecting the original data. This makes it possible
|
||||
/// to reset the position as the original data is still held in the CellRef
|
||||
RefData(const ESM::CellRef& cellRef);
|
||||
RefData(const ESM4::Reference& cellRef);
|
||||
|
||||
RefData(const ESM::ObjectState& objectState, bool deletedByContentFile);
|
||||
///< Ignores local variables and custom data (not enough context available here to
|
||||
|
|
|
@ -317,7 +317,6 @@ namespace MWWorld
|
|||
{
|
||||
if (mActiveCells.find(cell) == mActiveCells.end())
|
||||
return;
|
||||
|
||||
Log(Debug::Info) << "Unloading cell " << cell->getCell()->getDescription();
|
||||
|
||||
ListAndResetObjectsVisitor visitor;
|
||||
|
@ -355,8 +354,14 @@ namespace MWWorld
|
|||
if (cell->getCell()->hasWater())
|
||||
mNavigator.removeWater(osg::Vec2i(cellX, cellY), navigatorUpdateGuard);
|
||||
|
||||
if (const auto pathgrid = mWorld.getStore().get<ESM::Pathgrid>().search(*cell->getCell()))
|
||||
mNavigator.removePathgrid(*pathgrid);
|
||||
ESM::visit(ESM::VisitOverload{
|
||||
[&](const ESM::Cell& cell) {
|
||||
if (const auto pathgrid = mWorld.getStore().get<ESM::Pathgrid>().search(cell))
|
||||
mNavigator.removePathgrid(*pathgrid);
|
||||
},
|
||||
[&](const ESM4::Cell& cell) {},
|
||||
},
|
||||
*cell->getCell());
|
||||
|
||||
MWBase::Environment::get().getMechanicsManager()->drop(cell);
|
||||
|
||||
|
@ -384,8 +389,9 @@ namespace MWWorld
|
|||
|
||||
const int cellX = cell->getCell()->getGridX();
|
||||
const int cellY = cell->getCell()->getGridY();
|
||||
const MWWorld::Cell& cellVariant = *cell->getCell();
|
||||
|
||||
if (cell->getCell()->isExterior())
|
||||
if (cellVariant.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;
|
||||
|
@ -427,8 +433,14 @@ namespace MWWorld
|
|||
}
|
||||
}
|
||||
|
||||
if (const auto pathgrid = mWorld.getStore().get<ESM::Pathgrid>().search(*cell->getCell()))
|
||||
mNavigator.addPathgrid(*cell->getCell(), *pathgrid);
|
||||
ESM::visit(ESM::VisitOverload{
|
||||
[&](const ESM::Cell& cell) {
|
||||
if (const auto pathgrid = mWorld.getStore().get<ESM::Pathgrid>().search(cell))
|
||||
mNavigator.addPathgrid(cell, *pathgrid);
|
||||
},
|
||||
[&](const ESM4::Cell& cell) {},
|
||||
},
|
||||
*cell->getCell());
|
||||
|
||||
// register local scripts
|
||||
// do this before insertCell, to make sure we don't add scripts from levelled creature spawning twice
|
||||
|
@ -442,7 +454,7 @@ namespace MWWorld
|
|||
mRendering.addCell(cell);
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->addCell(cell);
|
||||
bool waterEnabled = cell->getCell()->hasWater() || cell->isExterior();
|
||||
bool waterEnabled = cellVariant.hasWater() || cell->isExterior();
|
||||
float waterLevel = cell->getWaterLevel();
|
||||
mRendering.setWaterEnabled(waterEnabled);
|
||||
if (waterEnabled)
|
||||
|
@ -450,7 +462,7 @@ namespace MWWorld
|
|||
mPhysics->enableWater(waterLevel);
|
||||
mRendering.setWaterHeight(waterLevel);
|
||||
|
||||
if (cell->getCell()->isExterior())
|
||||
if (cellVariant.isExterior())
|
||||
{
|
||||
if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
|
||||
mNavigator.addWater(
|
||||
|
@ -465,8 +477,8 @@ namespace MWWorld
|
|||
else
|
||||
mPhysics->disableWater();
|
||||
|
||||
if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx))
|
||||
mRendering.configureAmbient(cell->getCell());
|
||||
if (!cell->isExterior() && !cellVariant.isQuasiExterior())
|
||||
mRendering.configureAmbient(cellVariant);
|
||||
|
||||
mPreloader->notifyLoaded(cell);
|
||||
}
|
||||
|
@ -542,7 +554,7 @@ namespace MWWorld
|
|||
|
||||
mNavigator.setWorldspace(
|
||||
Misc::StringUtils::lowerCase(
|
||||
mWorld.getWorldModel().getExterior(playerCellX, playerCellY)->getCell()->mCellId.mWorldspace),
|
||||
mWorld.getWorldModel().getExterior(playerCellX, playerCellY)->getCell()->getCellId().mWorldspace),
|
||||
navigatorUpdateGuard.get());
|
||||
mNavigator.updateBounds(pos, navigatorUpdateGuard.get());
|
||||
|
||||
|
@ -665,7 +677,7 @@ namespace MWWorld
|
|||
|
||||
CellStore* cell = mWorld.getWorldModel().getExterior(it->mData.mX, it->mData.mY);
|
||||
mNavigator.setWorldspace(
|
||||
Misc::StringUtils::lowerCase(cell->getCell()->mCellId.mWorldspace), navigatorUpdateGuard.get());
|
||||
Misc::StringUtils::lowerCase(cell->getCell()->getCellId().mWorldspace), navigatorUpdateGuard.get());
|
||||
const osg::Vec3f position
|
||||
= osg::Vec3f(it->mData.mX + 0.5f, it->mData.mY + 0.5f, 0) * Constants::CellSizeInUnits;
|
||||
mNavigator.updateBounds(position, navigatorUpdateGuard.get());
|
||||
|
@ -723,7 +735,7 @@ namespace MWWorld
|
|||
|
||||
CellStore* cell = mWorld.getWorldModel().getInterior(it->mName);
|
||||
mNavigator.setWorldspace(
|
||||
Misc::StringUtils::lowerCase(cell->getCell()->mCellId.mWorldspace), navigatorUpdateGuard.get());
|
||||
Misc::StringUtils::lowerCase(cell->getCell()->getCellId().mWorldspace), navigatorUpdateGuard.get());
|
||||
ESM::Position position;
|
||||
mWorld.findInteriorPosition(it->mName, position);
|
||||
mNavigator.updateBounds(position.asVec3(), navigatorUpdateGuard.get());
|
||||
|
@ -739,7 +751,7 @@ namespace MWWorld
|
|||
{
|
||||
assert(!(*iter)->getCell()->isExterior());
|
||||
|
||||
if (it->mName == (*iter)->getCell()->mName)
|
||||
if (it->mName == (*iter)->getCell()->getNameId())
|
||||
{
|
||||
unloadCell(*iter, navigatorUpdateGuard.get());
|
||||
break;
|
||||
|
@ -880,7 +892,7 @@ namespace MWWorld
|
|||
loadingListener->setProgressRange(cell->count());
|
||||
|
||||
mNavigator.setWorldspace(
|
||||
Misc::StringUtils::lowerCase(cell->getCell()->mCellId.mWorldspace), navigatorUpdateGuard.get());
|
||||
Misc::StringUtils::lowerCase(cell->getCell()->getCellId().mWorldspace), navigatorUpdateGuard.get());
|
||||
mNavigator.updateBounds(position.asVec3(), navigatorUpdateGuard.get());
|
||||
|
||||
// Load cell.
|
||||
|
@ -892,7 +904,7 @@ namespace MWWorld
|
|||
changePlayerCell(cell, position, adjustPlayerPos);
|
||||
|
||||
// adjust fog
|
||||
mRendering.configureFog(mCurrentCell->getCell());
|
||||
mRendering.configureFog(*mCurrentCell->getCell());
|
||||
|
||||
// Sky system
|
||||
mWorld.adjustSky();
|
||||
|
@ -907,8 +919,7 @@ namespace MWWorld
|
|||
|
||||
MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell);
|
||||
|
||||
MWBase::Environment::get().getWorld()->getPostProcessor()->setExteriorFlag(
|
||||
cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx);
|
||||
MWBase::Environment::get().getWorld()->getPostProcessor()->setExteriorFlag(cell->getCell()->isQuasiExterior());
|
||||
}
|
||||
|
||||
void Scene::changeToExteriorCell(const ESM::Position& position, bool adjustPlayerPos, bool changeEvent)
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#include <components/loadinglistener/loadinglistener.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include <apps/openmw/mwworld/cell.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
// TODO: Switch to C++23 to get a working version of std::unordered_map::erase
|
||||
|
@ -961,6 +963,14 @@ namespace MWWorld
|
|||
else
|
||||
return search(ESM::RefId::stringRefId(cell.mName));
|
||||
}
|
||||
const ESM::Pathgrid* Store<ESM::Pathgrid>::search(const MWWorld::Cell& cellVariant) const
|
||||
{
|
||||
return ESM::visit(ESM::VisitOverload{
|
||||
[&](const ESM::Cell& cell) { return search(cell); },
|
||||
[&](const ESM4::Cell& cell) -> const ESM::Pathgrid* { return nullptr; },
|
||||
},
|
||||
cellVariant);
|
||||
}
|
||||
const ESM::Pathgrid* Store<ESM::Pathgrid>::find(const ESM::Cell& cell) const
|
||||
{
|
||||
if (!(cell.mData.mFlags & ESM::Cell::Interior))
|
||||
|
@ -1170,18 +1180,29 @@ namespace MWWorld
|
|||
return mKeywordSearch;
|
||||
}
|
||||
|
||||
ESM::FixedString<6> getRecNameString(ESM::RecNameInts recName)
|
||||
// ESM4 Cell
|
||||
//=========================================================================
|
||||
|
||||
const ESM4::Cell* Store<ESM4::Cell>::searchCellName(std::string_view cellName) const
|
||||
{
|
||||
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;
|
||||
const auto foundCell = mCellNameIndex.find(cellName);
|
||||
if (foundCell == mCellNameIndex.end())
|
||||
return nullptr;
|
||||
return foundCell->second;
|
||||
}
|
||||
|
||||
ESM4::Cell* Store<ESM4::Cell>::insert(const ESM4::Cell& item, bool overrideOnly)
|
||||
{
|
||||
auto cellPtr = TypedDynamicStore<ESM4::Cell>::insert(item, overrideOnly);
|
||||
mCellNameIndex[cellPtr->mEditorId] = cellPtr;
|
||||
return cellPtr;
|
||||
}
|
||||
|
||||
ESM4::Cell* Store<ESM4::Cell>::insertStatic(const ESM4::Cell& item)
|
||||
{
|
||||
auto cellPtr = TypedDynamicStore<ESM4::Cell>::insertStatic(item);
|
||||
mCellNameIndex[cellPtr->mEditorId] = cellPtr;
|
||||
return cellPtr;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <components/esm3/loadgmst.hpp>
|
||||
#include <components/esm3/loadland.hpp>
|
||||
#include <components/esm3/loadpgrd.hpp>
|
||||
#include <components/esm4/loadcell.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
#include <components/misc/strings/algorithm.hpp>
|
||||
|
||||
|
@ -38,6 +39,7 @@ namespace Loading
|
|||
|
||||
namespace MWWorld
|
||||
{
|
||||
class Cell;
|
||||
struct RecordId
|
||||
{
|
||||
ESM::RefId mId;
|
||||
|
@ -268,6 +270,19 @@ namespace MWWorld
|
|||
const ESM::GameSetting* find(const std::string_view id) const;
|
||||
const ESM::GameSetting* search(const std::string_view id) const;
|
||||
};
|
||||
|
||||
template <>
|
||||
class Store<ESM4::Cell> : public TypedDynamicStore<ESM4::Cell>
|
||||
{
|
||||
std::unordered_map<std::string, ESM4::Cell*, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual>
|
||||
mCellNameIndex;
|
||||
|
||||
public:
|
||||
const ESM4::Cell* searchCellName(std::string_view) const;
|
||||
ESM4::Cell* insert(const ESM4::Cell& item, bool overrideOnly = false);
|
||||
ESM4::Cell* insertStatic(const ESM4::Cell& item);
|
||||
};
|
||||
|
||||
template <>
|
||||
class Store<ESM::Land> : public DynamicStore
|
||||
{
|
||||
|
@ -416,6 +431,7 @@ namespace MWWorld
|
|||
const ESM::Pathgrid* find(int x, int y) const;
|
||||
const ESM::Pathgrid* find(const ESM::RefId& name) const;
|
||||
const ESM::Pathgrid* search(const ESM::Cell& cell) const;
|
||||
const ESM::Pathgrid* search(const MWWorld::Cell& cell) const;
|
||||
const ESM::Pathgrid* find(const ESM::Cell& cell) const;
|
||||
};
|
||||
|
||||
|
@ -519,8 +535,6 @@ namespace MWWorld
|
|||
const MWDialogue::KeywordSearch<std::string, int>& getDialogIdKeywordSearch() const;
|
||||
};
|
||||
|
||||
ESM::FixedString<6> getRecNameString(ESM::RecNameInts recName);
|
||||
|
||||
} // end namespace
|
||||
|
||||
#endif
|
||||
|
|
|
@ -704,7 +704,7 @@ namespace MWWorld
|
|||
if (!paused || mFastForward)
|
||||
{
|
||||
// Add new transitions when either the player's current external region changes.
|
||||
if (updateWeatherTime() || updateWeatherRegion(player.getCell()->getCell()->mRegion))
|
||||
if (updateWeatherTime() || updateWeatherRegion(player.getCell()->getCell()->getRegion()))
|
||||
{
|
||||
auto it = mRegions.find(mCurrentRegion);
|
||||
if (it != mRegions.end())
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#include <components/esm3/loadmgef.hpp>
|
||||
#include <components/esm3/loadregn.hpp>
|
||||
#include <components/esm3/loadstat.hpp>
|
||||
#include <components/esm4/loadcell.hpp>
|
||||
#include <components/esm4/loadstat.hpp>
|
||||
|
||||
#include <components/misc/constants.hpp>
|
||||
#include <components/misc/convert.hpp>
|
||||
|
@ -631,7 +633,21 @@ namespace MWWorld
|
|||
{
|
||||
if (!cell)
|
||||
cell = mWorldScene->getCurrentCell();
|
||||
return getCellName(cell->getCell());
|
||||
return getCellName(*cell->getCell());
|
||||
}
|
||||
|
||||
std::string_view World::getCellName(const MWWorld::Cell& cell) const
|
||||
{
|
||||
if (!cell.isExterior() || !cell.getNameId().empty())
|
||||
return cell.getNameId();
|
||||
|
||||
return ESM::visit(ESM::VisitOverload{
|
||||
[&](const ESM::Cell& cellIn) -> std::string_view { return getCellName(&cellIn); },
|
||||
[&](const ESM4::Cell& cellIn) -> std::string_view {
|
||||
return mStore.get<ESM::GameSetting>().find("sDefaultCellname")->mValue.getString();
|
||||
},
|
||||
},
|
||||
cell);
|
||||
}
|
||||
|
||||
std::string_view World::getCellName(const ESM::Cell* cell) const
|
||||
|
@ -644,7 +660,6 @@ namespace MWWorld
|
|||
if (const ESM::Region* region = mStore.get<ESM::Region>().search(cell->mRegion))
|
||||
return region->mName;
|
||||
}
|
||||
|
||||
return mStore.get<ESM::GameSetting>().find("sDefaultCellname")->mValue.getString();
|
||||
}
|
||||
|
||||
|
@ -1136,7 +1151,7 @@ namespace MWWorld
|
|||
{
|
||||
if (!newCell->isExterior())
|
||||
{
|
||||
changeToInteriorCell(newCell->getCell()->mName, pos, false);
|
||||
changeToInteriorCell(newCell->getCell()->getNameId(), pos, false);
|
||||
removeContainerScripts(getPlayerPtr());
|
||||
}
|
||||
else
|
||||
|
@ -1397,7 +1412,7 @@ namespace MWWorld
|
|||
esmPos.pos[2] = traced.z();
|
||||
std::string_view cell;
|
||||
if (!actor.getCell()->isExterior())
|
||||
cell = actor.getCell()->getCell()->mName;
|
||||
cell = actor.getCell()->getCell()->getNameId();
|
||||
MWWorld::ActionTeleport(cell, esmPos, false).execute(actor);
|
||||
}
|
||||
}
|
||||
|
@ -1985,10 +2000,7 @@ namespace MWWorld
|
|||
const CellStore* currentCell = mWorldScene->getCurrentCell();
|
||||
if (currentCell)
|
||||
{
|
||||
if (!(currentCell->getCell()->mData.mFlags & ESM::Cell::QuasiEx))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
return currentCell->getCell()->isQuasiExterior();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -2465,8 +2477,7 @@ namespace MWWorld
|
|||
|| isFlying(player))
|
||||
return Rest_PlayerIsInAir;
|
||||
|
||||
if ((currentCell->getCell()->mData.mFlags & ESM::Cell::NoSleep)
|
||||
|| player.getClass().getNpcStats(player).isWerewolf())
|
||||
if (currentCell->getCell()->noSleep() || player.getClass().getNpcStats(player).isWerewolf())
|
||||
return Rest_OnlyWaiting;
|
||||
|
||||
return Rest_Allowed;
|
||||
|
@ -2803,6 +2814,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())
|
||||
|
@ -2819,7 +2848,7 @@ namespace MWWorld
|
|||
{
|
||||
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
|
||||
|
||||
const ESM::Cell* ext = nullptr;
|
||||
const MWWorld::Cell* ext = nullptr;
|
||||
try
|
||||
{
|
||||
ext = mWorldModel.getCell(nameId)->getCell();
|
||||
|
@ -3226,9 +3255,10 @@ namespace MWWorld
|
|||
}
|
||||
else
|
||||
{
|
||||
uint32_t ambient = cell->getCell()->mAmbi.mAmbient;
|
||||
const MWWorld::Cell& cellVariant = *cell->getCell();
|
||||
uint32_t ambient = cellVariant.getMood().mAmbiantColor;
|
||||
int ambientTotal = (ambient & 0xff) + ((ambient >> 8) & 0xff) + ((ambient >> 16) & 0xff);
|
||||
return !(cell->getCell()->mData.mFlags & ESM::Cell::NoSleep) && ambientTotal <= 201;
|
||||
return !cell->getCell()->noSleep() && ambientTotal <= 201;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3252,7 +3282,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->getCell()->getNameId());
|
||||
|
||||
while (!nextCells.empty())
|
||||
{
|
||||
|
@ -3307,7 +3337,7 @@ namespace MWWorld
|
|||
std::set<std::string_view> nextCells;
|
||||
MWWorld::ConstPtr closestMarker;
|
||||
|
||||
nextCells.insert(ptr.getCell()->getCell()->mName);
|
||||
nextCells.insert(ptr.getCell()->getCell()->getNameId());
|
||||
while (!nextCells.empty())
|
||||
{
|
||||
currentCells = nextCells;
|
||||
|
@ -3402,7 +3432,7 @@ namespace MWWorld
|
|||
|
||||
std::string_view cellName = "";
|
||||
if (!closestMarker.mCell->isExterior())
|
||||
cellName = closestMarker.mCell->getCell()->mName;
|
||||
cellName = closestMarker.mCell->getCell()->getNameId();
|
||||
|
||||
MWWorld::ActionTeleport action(cellName, closestMarker.getRefData().getPosition(), false);
|
||||
action.execute(ptr);
|
||||
|
@ -3415,7 +3445,7 @@ namespace MWWorld
|
|||
{
|
||||
mPlayer->setTeleported(false);
|
||||
|
||||
const ESM::RefId& playerRegion = getPlayerPtr().getCell()->getCell()->mRegion;
|
||||
const ESM::RefId& playerRegion = getPlayerPtr().getCell()->getCell()->getRegion();
|
||||
mWeatherManager->playerTeleported(playerRegion, isExterior);
|
||||
}
|
||||
|
||||
|
|
|
@ -269,6 +269,7 @@ namespace MWWorld
|
|||
///
|
||||
/// \note If cell==0, the cell the player is currently in will be used instead to
|
||||
/// generate a name.
|
||||
std::string_view getCellName(const MWWorld::Cell& cell) const override;
|
||||
std::string_view getCellName(const ESM::Cell* cell) const override;
|
||||
|
||||
void removeRefScript(MWWorld::RefData* ref) override;
|
||||
|
|
|
@ -67,7 +67,7 @@ MWWorld::CellStore* MWWorld::WorldModel::getCellStore(const ESM::Cell* cell)
|
|||
auto result = mInteriors.find(cell->mName);
|
||||
|
||||
if (result == mInteriors.end())
|
||||
result = mInteriors.emplace(cell->mName, CellStore(cell, mStore, mReaders)).first;
|
||||
result = mInteriors.emplace(cell->mName, CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first;
|
||||
|
||||
return &result->second;
|
||||
}
|
||||
|
@ -78,7 +78,8 @@ MWWorld::CellStore* MWWorld::WorldModel::getCellStore(const ESM::Cell* cell)
|
|||
|
||||
if (result == mExteriors.end())
|
||||
result = mExteriors
|
||||
.emplace(std::make_pair(cell->getGridX(), cell->getGridY()), CellStore(cell, mStore, mReaders))
|
||||
.emplace(std::make_pair(cell->getGridX(), cell->getGridY()),
|
||||
CellStore(MWWorld::Cell(*cell), mStore, mReaders))
|
||||
.first;
|
||||
|
||||
return &result->second;
|
||||
|
@ -185,7 +186,7 @@ MWWorld::CellStore* MWWorld::WorldModel::getExterior(int x, int y)
|
|||
cell = MWBase::Environment::get().getWorld()->createRecord(record);
|
||||
}
|
||||
|
||||
result = mExteriors.emplace(std::make_pair(x, y), CellStore(cell, mStore, mReaders)).first;
|
||||
result = mExteriors.emplace(std::make_pair(x, y), CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first;
|
||||
}
|
||||
|
||||
if (result->second.getState() != CellStore::State_Loaded)
|
||||
|
@ -202,9 +203,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(MWWorld::Cell(*cell), mStore, mReaders)).first;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = mInteriors.emplace(name, CellStore(MWWorld::Cell(*cell4), mStore, mReaders)).first;
|
||||
}
|
||||
}
|
||||
|
||||
if (result->second.getState() != CellStore::State_Loaded)
|
||||
|
@ -253,6 +262,17 @@ const ESM::Cell* MWWorld::WorldModel::getESMCellByName(std::string_view name)
|
|||
return cell;
|
||||
}
|
||||
|
||||
ESM::CellVariant MWWorld::WorldModel::getCellByName(std::string_view name)
|
||||
{
|
||||
const ESM::Cell* cellEsm3 = getESMCellByName(name);
|
||||
if (!cellEsm3)
|
||||
{
|
||||
const ESM4::Cell* cellESM4 = mStore.get<ESM4::Cell>().searchCellName(name);
|
||||
return ESM::CellVariant(*cellESM4);
|
||||
}
|
||||
return ESM::CellVariant(*cellEsm3);
|
||||
}
|
||||
|
||||
MWWorld::CellStore* MWWorld::WorldModel::getCell(std::string_view name)
|
||||
{
|
||||
const ESM::Cell* cell = getESMCellByName(name);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <map>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <variant>
|
||||
|
||||
#include <components/misc/algorithm.hpp>
|
||||
|
||||
|
@ -21,6 +22,11 @@ namespace ESM
|
|||
struct RefNum;
|
||||
}
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
struct Cell;
|
||||
}
|
||||
|
||||
namespace Loading
|
||||
{
|
||||
class Listener;
|
||||
|
@ -45,8 +51,9 @@ namespace MWWorld
|
|||
WorldModel& operator=(const WorldModel&);
|
||||
|
||||
const ESM::Cell* getESMCellByName(std::string_view name);
|
||||
CellStore* getCellStore(const ESM::Cell* cell);
|
||||
ESM::CellVariant getCellByName(std::string_view name);
|
||||
|
||||
CellStore* getCellStore(const ESM::Cell* cell);
|
||||
Ptr getPtrAndCache(const ESM::RefId& name, CellStore& cellStore);
|
||||
|
||||
Ptr getPtr(CellStore& cellStore, const ESM::RefId& id, const ESM::RefNum& refNum);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <boost/program_options/options_description.hpp>
|
||||
#include <boost/program_options/variables_map.hpp>
|
||||
|
||||
#include <components/esm/defs.hpp>
|
||||
#include <components/esm/records.hpp>
|
||||
#include <components/esm3/esmreader.hpp>
|
||||
#include <components/esm3/esmwriter.hpp>
|
||||
|
@ -316,7 +317,7 @@ static void testRecNameIntCount(const MWWorld::Store<T>& store, const MWWorld::E
|
|||
const unsigned int recordIdCount
|
||||
= std::apply([](auto&&... x) { return (hasSameRecordId(x, T::sRecordId) + ...); }, stores);
|
||||
ASSERT_EQ(recordIdCount, static_cast<unsigned int>(1))
|
||||
<< "The same RecNameInt is used twice ESM::REC_" << MWWorld::getRecNameString(T::sRecordId).toStringView();
|
||||
<< "The same RecNameInt is used twice ESM::REC_" << ESM::getRecNameString(T::sRecordId).toStringView();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ add_component_dir (to_utf8
|
|||
to_utf8
|
||||
)
|
||||
|
||||
add_component_dir(esm attr common defs esmcommon records util luascripts format refid)
|
||||
add_component_dir(esm attr common defs esmcommon records util luascripts format refid esmbridge)
|
||||
|
||||
add_component_dir(fx pass technique lexer widgets stateupdater)
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
18
components/esm/esmbridge.cpp
Normal file
18
components/esm/esmbridge.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
#include <components/esm/esmbridge.hpp>
|
||||
#include <components/esm3/loadcell.hpp>
|
||||
#include <components/esm4/loadcell.hpp>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
const ESM4::Cell& CellVariant::getEsm4() const
|
||||
{
|
||||
auto cell4 = std::get<const ESM4::Cell*>(mVariant);
|
||||
return *cell4;
|
||||
}
|
||||
|
||||
const ESM::Cell& CellVariant::getEsm3() const
|
||||
{
|
||||
auto cell = std::get<const ESM::Cell*>(mVariant);
|
||||
return *cell;
|
||||
}
|
||||
}
|
83
components/esm/esmbridge.hpp
Normal file
83
components/esm/esmbridge.hpp
Normal file
|
@ -0,0 +1,83 @@
|
|||
#ifndef COMPONENTS_ESM_ESMBRIDGE
|
||||
#define COMPONENTS_ESM_ESMBRIDGE
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <variant>
|
||||
|
||||
#include <components/esm3/cellref.hpp>
|
||||
#include <components/esm4/loadrefr.hpp>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
struct Cell;
|
||||
}
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct Cell;
|
||||
struct CellId;
|
||||
struct RefId;
|
||||
|
||||
class CellVariant
|
||||
{
|
||||
protected:
|
||||
std::variant<const ESM4::Cell*, const ESM::Cell*> mVariant;
|
||||
|
||||
public:
|
||||
explicit CellVariant(const ESM4::Cell& cell)
|
||||
: mVariant(&cell)
|
||||
{
|
||||
}
|
||||
|
||||
explicit CellVariant(const ESM::Cell& cell)
|
||||
: mVariant(&cell)
|
||||
{
|
||||
}
|
||||
|
||||
bool isEsm4() const { return std::holds_alternative<const ESM4::Cell*>(mVariant); }
|
||||
const ESM4::Cell& getEsm4() const;
|
||||
const ESM::Cell& getEsm3() const;
|
||||
|
||||
template <class F, class... T>
|
||||
friend auto visit(F&& f, T&&... v);
|
||||
};
|
||||
|
||||
struct ReferenceVariant
|
||||
{
|
||||
std::variant<ESM::CellRef, ESM4::Reference> mVariant;
|
||||
|
||||
explicit ReferenceVariant(const ESM4::Reference& ref)
|
||||
: mVariant(ref)
|
||||
{
|
||||
}
|
||||
|
||||
explicit ReferenceVariant(const ESM::CellRef& ref)
|
||||
: mVariant(ref)
|
||||
{
|
||||
}
|
||||
|
||||
bool isESM4() const { return std::holds_alternative<ESM4::Reference>(mVariant); }
|
||||
|
||||
const ESM::CellRef& getEsm3() const { return std::get<ESM::CellRef>(mVariant); }
|
||||
const ESM4::Reference& getEsm4() const { return std::get<ESM4::Reference>(mVariant); }
|
||||
|
||||
ESM::CellRef& getEsm3() { return std::get<ESM::CellRef>(mVariant); }
|
||||
ESM4::Reference& getEsm4() { return std::get<ESM4::Reference>(mVariant); }
|
||||
};
|
||||
|
||||
template <class F, class... T>
|
||||
auto visit(F&& f, T&&... v)
|
||||
{
|
||||
return std::visit([&](auto*... ptr) { return std::forward<F>(f)(*ptr...); }, std::forward<T>(v).mVariant...);
|
||||
}
|
||||
|
||||
template <class... Ts>
|
||||
struct VisitOverload : Ts...
|
||||
{
|
||||
using Ts::operator()...;
|
||||
};
|
||||
|
||||
template <class... Ts>
|
||||
VisitOverload(Ts...) -> VisitOverload<Ts...>;
|
||||
}
|
||||
#endif
|
|
@ -36,6 +36,7 @@
|
|||
|
||||
#include <components/esm/defs.hpp>
|
||||
#include <components/esm/refid.hpp>
|
||||
#include <components/esm3/cellid.hpp>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
|
@ -101,6 +102,10 @@ namespace ESM4
|
|||
void blank();
|
||||
|
||||
static constexpr ESM::RecNameInts sRecordId = ESM::REC_CELL4;
|
||||
|
||||
int getGridX() const { return mX; }
|
||||
int getGridY() const { return mY; }
|
||||
bool isExterior() const { return !(mCellFlags & CELL_Interior); }
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ void ESM4::Reference::load(ESM4::Reader& reader)
|
|||
break;
|
||||
}
|
||||
case ESM4::SUB_DATA:
|
||||
reader.get(mPlacement);
|
||||
reader.get(mPos);
|
||||
break;
|
||||
case ESM4::SUB_XSCL:
|
||||
reader.get(mScale);
|
||||
|
@ -236,7 +236,9 @@ void ESM4::Reference::load(ESM4::Reader& reader)
|
|||
reader.get(dummy);
|
||||
reader.get(dummy);
|
||||
reader.get(dummy);
|
||||
reader.getFormId(mKey);
|
||||
FormId keyForm;
|
||||
reader.getFormId(keyForm);
|
||||
mKey = ESM::RefId::formIdRefId(keyForm);
|
||||
reader.get(dummy); // flag?
|
||||
reader.get(dummy);
|
||||
reader.get(dummy);
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace ESM4
|
|||
struct TeleportDest
|
||||
{
|
||||
FormId destDoor;
|
||||
Placement destPos;
|
||||
ESM::Position destPos;
|
||||
std::uint32_t flags; // 0x01 no alarm (only in TES5)
|
||||
};
|
||||
|
||||
|
@ -87,7 +87,7 @@ namespace ESM4
|
|||
std::string mFullName;
|
||||
ESM::RefId mBaseObj;
|
||||
|
||||
Placement mPlacement;
|
||||
ESM::Position mPos;
|
||||
float mScale = 1.0f;
|
||||
FormId mOwner;
|
||||
FormId mGlobal;
|
||||
|
@ -108,7 +108,7 @@ namespace ESM4
|
|||
TeleportDest mDoor;
|
||||
bool mIsLocked;
|
||||
std::int8_t mLockLevel;
|
||||
FormId mKey;
|
||||
ESM::RefId mKey;
|
||||
|
||||
FormId mTargetRef;
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
#ifndef OPENMW_COMPONENTS_MISC_COORDINATECONVERTER_H
|
||||
#define OPENMW_COMPONENTS_MISC_COORDINATECONVERTER_H
|
||||
|
||||
#include <components/esm/esmbridge.hpp>
|
||||
#include <components/esm3/loadcell.hpp>
|
||||
#include <components/esm3/loadland.hpp>
|
||||
#include <components/esm3/loadpgrd.hpp>
|
||||
#include <components/esm4/loadcell.hpp>
|
||||
|
||||
namespace Misc
|
||||
{
|
||||
|
@ -17,8 +19,15 @@ namespace Misc
|
|||
{
|
||||
}
|
||||
|
||||
explicit CoordinateConverter(const ESM::CellVariant& cell)
|
||||
: CoordinateConverter(cell.isEsm4() ? cell.getEsm4().isExterior() : cell.getEsm3().isExterior(),
|
||||
cell.isEsm4() ? cell.getEsm4().getGridX() : cell.getEsm3().getGridX(),
|
||||
cell.isEsm4() ? cell.getEsm4().getGridY() : cell.getEsm3().getGridY())
|
||||
{
|
||||
}
|
||||
|
||||
explicit CoordinateConverter(const ESM::Cell* cell)
|
||||
: CoordinateConverter(cell->isExterior(), cell->mData.mX, cell->mData.mY)
|
||||
: CoordinateConverter(cell->isExterior(), cell->getGridX(), cell->getGridY())
|
||||
{
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue