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:
commit
a939834a8b
11 changed files with 73 additions and 21 deletions
|
@ -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>>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -102,7 +102,7 @@ namespace MWWorld
|
|||
bool mPreloadFastTravel;
|
||||
float mPredictionTime;
|
||||
|
||||
static const int mHalfGridSize = Constants::CellGridRadius;
|
||||
int mHalfGridSize = Constants::CellGridRadius;
|
||||
|
||||
osg::Vec3f mLastPlayerPos;
|
||||
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue