1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-07-10 03:11:35 +00:00

Merge branch 'esm4refs' into 'master'

ESM4 walking simulator improvements

See merge request OpenMW/openmw!3024
This commit is contained in:
psi29a 2023-05-18 16:30:59 +00:00
commit a939834a8b
11 changed files with 73 additions and 21 deletions

View file

@ -2,6 +2,7 @@
#define GAME_MWCLASS_ESM4BASE_H
#include <components/esm4/loadstat.hpp>
#include <components/misc/strings/algorithm.hpp>
#include "../mwgui/tooltips.hpp"
@ -44,9 +45,6 @@ namespace MWClass
void insertObjectRendering(const MWWorld::Ptr& ptr, const std::string& model,
MWRender::RenderingInterface& renderingInterface) const override
{
const MWWorld::LiveCellRef<Record>* ref = ptr.get<Record>();
if (ref->mBase->mFlags & ESM4::Rec_Marker)
return;
ESM4Impl::insertObjectRendering(ptr, model, renderingInterface);
}
@ -59,9 +57,6 @@ namespace MWClass
void insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation,
MWPhysics::PhysicsSystem& physics) const override
{
const MWWorld::LiveCellRef<Record>* ref = ptr.get<Record>();
if (ref->mBase->mFlags & ESM4::Rec_Marker)
return;
ESM4Impl::insertObjectPhysics(ptr, model, rotation, physics);
}
@ -69,7 +64,19 @@ namespace MWClass
std::string_view getName(const MWWorld::ConstPtr& ptr) const override { return ""; }
std::string getModel(const MWWorld::ConstPtr& ptr) const override { return getClassModel<Record>(ptr); }
std::string getModel(const MWWorld::ConstPtr& ptr) const override
{
std::string model = getClassModel<Record>(ptr);
// Hide meshes meshes/marker/* and *LOD.nif in ESM4 cells. It is a temporarty hack.
// Needed because otherwise LOD meshes are rendered on top of normal meshes.
// TODO: Figure out a better way find markers and LOD meshes; show LOD only outside of active grid.
if (model.empty() || Misc::StringUtils::ciStartsWith(model, "meshes\\marker")
|| Misc::StringUtils::ciEndsWith(model, "lod.nif"))
return "";
return model;
}
};
class ESM4Static final : public MWWorld::RegisteredClass<ESM4Static, ESM4Base<ESM4::Static>>

View file

@ -760,12 +760,10 @@ namespace MWWorld
template <typename ReferenceInvocable>
static void visitCell4References(const ESM4::Cell& cell, ESM::ReadersCache& readers, ReferenceInvocable&& invocable)
{
for (const ESM4::Reference& ref : MWBase::Environment::get().getESMStore()->get<ESM4::Reference>())
for (const ESM4::Reference* ref :
MWBase::Environment::get().getESMStore()->get<ESM4::Reference>().getByCell(cell.mId))
{
if (ref.mParent == cell.mId)
{
invocable(ref);
}
invocable(*ref);
}
}

View file

@ -447,6 +447,7 @@ namespace MWWorld
getWritable<ESM::Skill>().setUp();
getWritable<ESM::MagicEffect>().setUp();
getWritable<ESM::Attribute>().setUp();
getWritable<ESM4::Reference>().preprocessReferences(get<ESM4::Cell>());
}
void ESMStore::validateRecords(ESM::ReadersCache& readers)

View file

@ -779,6 +779,7 @@ namespace MWWorld
void Scene::changePlayerCell(CellStore& cell, const ESM::Position& pos, bool adjustPlayerPos)
{
mHalfGridSize = cell.getCell()->isEsm4() ? Constants::ESM4CellGridRadius : Constants::CellGridRadius;
mCurrentCell = &cell;
mRendering.enableTerrain(cell.isExterior());

View file

@ -102,7 +102,7 @@ namespace MWWorld
bool mPreloadFastTravel;
float mPredictionTime;
static const int mHalfGridSize = Constants::CellGridRadius;
int mHalfGridSize = Constants::CellGridRadius;
osg::Vec3f mLastPlayerPos;

View file

@ -1155,6 +1155,33 @@ namespace MWWorld
}
MWWorld::TypedDynamicStore<ESM4::Cell>::clearDynamic();
}
// ESM4 Reference
//=========================================================================
void Store<ESM4::Reference>::preprocessReferences(const Store<ESM4::Cell>& cells)
{
for (auto& [_, ref] : mStatic)
{
const ESM4::Cell* cell = cells.find(ref.mParent);
if (cell->isExterior() && (cell->mFlags & ESM4::Rec_Persistent))
{
const ESM4::Cell* actualCell
= cells.searchExterior(positionToCellIndex(ref.mPos.pos[0], ref.mPos.pos[1], cell->mParent));
if (actualCell)
ref.mParent = actualCell->mId;
}
mPerCellReferences[ref.mParent].push_back(&ref);
}
}
std::span<const ESM4::Reference* const> Store<ESM4::Reference>::getByCell(ESM::RefId cellId) const
{
auto it = mPerCellReferences.find(cellId);
if (it == mPerCellReferences.end())
return {};
return it->second;
}
}
template class MWWorld::TypedDynamicStore<ESM::Activator>;

View file

@ -4,6 +4,7 @@
#include <map>
#include <memory>
#include <set>
#include <span>
#include <string>
#include <unordered_map>
#include <vector>
@ -552,6 +553,13 @@ namespace MWWorld
template <>
class Store<ESM4::Reference> : public TypedDynamicStore<ESM4::Reference, ESM::FormId>
{
public:
void preprocessReferences(const Store<ESM4::Cell>& cells);
std::span<const ESM4::Reference* const> getByCell(ESM::RefId cellId) const;
private:
std::unordered_map<ESM::RefId, std::vector<ESM4::Reference*>> mPerCellReferences;
};
} // end namespace

View file

@ -1361,10 +1361,9 @@ namespace MWWorld
return;
}
const float terrainHeight
= ptr.getCell()->isExterior() ? getTerrainHeightAt(pos) : -std::numeric_limits<float>::max();
pos.z() = std::max(pos.z(), terrainHeight)
+ 20; // place slightly above terrain. will snap down to ground with code below
if (ptr.getCell()->isExterior() && !ptr.getCell()->getCell()->isEsm4())
pos.z() = std::max(pos.z(), getTerrainHeightAt(pos));
pos.z() += 20; // place slightly above terrain. will snap down to ground with code below
// We still should trace down dead persistent actors - they do not use the "swimdeath" animation.
bool swims = ptr.getClass().isActor() && isSwimming(ptr)

View file

@ -192,10 +192,18 @@ void ESM4::World::load(ESM4::Reader& reader)
throw std::runtime_error("ESM4::WRLD::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
}
if (isTES5 && usingDefaultLevels)
if (usingDefaultLevels)
{
mLandLevel = -2700.f;
mWaterLevel = -14000.f;
if (isTES5)
{
mLandLevel = -2700.f;
mWaterLevel = -14000.f;
}
else
{
mLandLevel = 0.f; // FIXME: not sure that this value is correct
mWaterLevel = 0.f;
}
}
}
}

View file

@ -28,6 +28,9 @@ namespace Constants
// Size of active cell grid in cells (it is a square with the (2 * CellGridRadius + 1) cells side)
constexpr int CellGridRadius = 1;
// ESM4 cells are twice smaller, so the active grid should have more cells.
constexpr int ESM4CellGridRadius = CellGridRadius * 2;
// A label to mark night/day visual switches
const std::string NightDayLabel = "NightDaySwitch";

View file

@ -119,7 +119,7 @@ namespace Nif
readRecordList(nif, effects);
// FIXME: stopgap solution until we figure out what Oblivion does if it does anything
if (nif->getVersion() > NIFFile::NIFVersion::VER_MW)
if (nif->getVersion() > NIFFile::NIFVersion::VER_MW && nif->getVersion() < NIFFile::NIFVersion::VER_BGS)
return;
// Discard transformations for the root node, otherwise some meshes