From f87c45c92a6cfba68d431398a1ceab57976b74ff Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sat, 30 Jan 2021 16:03:02 +0200 Subject: [PATCH 01/15] Get collision box extents and center from btBvhTriangleMeshShape --- components/resource/bulletshapemanager.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index bcadf51c4..d1da9090d 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -86,7 +86,17 @@ public: return osg::ref_ptr(); osg::ref_ptr shape (new BulletShape); - shape->mCollisionShape = new TriangleMeshShape(mTriangleMesh.release(), true); + btBvhTriangleMeshShape* triangleMeshShape = new TriangleMeshShape(mTriangleMesh.release(), true); + btVector3 aabbMin = triangleMeshShape->getLocalAabbMin(); + btVector3 aabbMax = triangleMeshShape->getLocalAabbMax(); + shape->mCollisionBox.extents[0] = (aabbMax[0] - aabbMin[0]) / 2.0f; + shape->mCollisionBox.extents[1] = (aabbMax[1] - aabbMin[1]) / 2.0f; + shape->mCollisionBox.extents[2] = (aabbMax[2] - aabbMin[2]) / 2.0f; + shape->mCollisionBox.center = osg::Vec3f( (aabbMax[0] + aabbMin[0]) / 2.0f, + (aabbMax[1] + aabbMin[1]) / 2.0f, + (aabbMax[2] + aabbMin[2]) / 2.0f ); + shape->mCollisionShape = triangleMeshShape; + return shape; } From 7edaa50195baad8ac126ca116b12049d0fe29e5d Mon Sep 17 00:00:00 2001 From: madsbuvi Date: Sun, 31 Jan 2021 18:02:05 +0100 Subject: [PATCH 02/15] another approach --- components/sceneutil/mwshadowtechnique.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 294780cfd..7476bc219 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -997,9 +997,9 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) } // 1. Traverse main scene graph - cv.pushStateSet( _shadowRecievingPlaceholderStateSet.get() ); - - osg::ref_ptr decoratorStateGraph = cv.getCurrentStateGraph(); + auto* shadowReceiverStateSet = vdd->getStateSet(cv.getTraversalNumber()); + shadowReceiverStateSet->clear(); + cv.pushStateSet(shadowReceiverStateSet); cullShadowReceivingScene(&cv); @@ -1426,7 +1426,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) if (numValidShadows>0) { - decoratorStateGraph->setStateSet(selectStateSetForRenderingShadow(*vdd, cv.getTraversalNumber())); + selectStateSetForRenderingShadow(*vdd, cv.getTraversalNumber()); } // OSG_NOTICE<<"End of shadow setup Projection matrix "<<*cv.getProjectionMatrix()< Date: Mon, 1 Feb 2021 18:34:10 +0000 Subject: [PATCH 03/15] Fix the regression involving Cure --- apps/openmw/mwmechanics/actors.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index c9fcf8280..cb3570d21 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -958,22 +958,22 @@ namespace MWMechanics if (actor.getClass().hasInventoryStore(actor)) actor.getClass().getInventoryStore(actor).purgeEffect(ESM::MagicEffect::Paralyze); } - else if (effects.get(ESM::MagicEffect::CureCommonDisease).getModifier() > 0) + if (effects.get(ESM::MagicEffect::CureCommonDisease).getModifier() > 0) { creatureStats.getSpells().purgeCommonDisease(); } - else if (effects.get(ESM::MagicEffect::CureBlightDisease).getModifier() > 0) + if (effects.get(ESM::MagicEffect::CureBlightDisease).getModifier() > 0) { creatureStats.getSpells().purgeBlightDisease(); } - else if (effects.get(ESM::MagicEffect::CureCorprusDisease).getModifier() > 0) + if (effects.get(ESM::MagicEffect::CureCorprusDisease).getModifier() > 0) { creatureStats.getActiveSpells().purgeCorprusDisease(); creatureStats.getSpells().purgeCorprusDisease(); if (actor.getClass().hasInventoryStore(actor)) actor.getClass().getInventoryStore(actor).purgeEffect(ESM::MagicEffect::Corprus, true); } - else if (effects.get(ESM::MagicEffect::RemoveCurse).getModifier() > 0) + if (effects.get(ESM::MagicEffect::RemoveCurse).getModifier() > 0) { creatureStats.getSpells().purgeCurses(); } From 0639f8b7c6d5536f8a0ab03a058ab16bfb54c8bb Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 3 Feb 2021 18:45:22 +0000 Subject: [PATCH 04/15] Make the dummy texture for the character preview shadow-friendly --- apps/openmw/mwrender/characterpreview.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 14735050c..262b03229 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -184,6 +184,9 @@ namespace MWRender osg::ref_ptr dummyTexture = new osg::Texture2D(); dummyTexture->setInternalFormat(GL_RED); dummyTexture->setTextureSize(1, 1); + // This might clash with a shadow map, so make sure it doesn't cast shadows + dummyTexture->setShadowComparison(true); + dummyTexture->setShadowCompareFunc(osg::Texture::ShadowCompareFunc::ALWAYS); stateset->setTextureAttributeAndModes(7, dummyTexture, osg::StateAttribute::ON); stateset->setTextureAttribute(7, noBlendAlphaEnv, osg::StateAttribute::ON); stateset->addUniform(new osg::Uniform("noAlpha", true)); From 88ca4a1db6e10eeeecd0d9f97fbe61dd5b8a9411 Mon Sep 17 00:00:00 2001 From: elsid Date: Thu, 4 Feb 2021 00:18:25 +0100 Subject: [PATCH 05/15] Count navmesh cache hit rate --- components/detournavigator/navmeshtilescache.cpp | 12 +++++++++++- components/detournavigator/navmeshtilescache.hpp | 2 ++ components/resource/stats.cpp | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/components/detournavigator/navmeshtilescache.cpp b/components/detournavigator/navmeshtilescache.cpp index cff93ac0e..1b90ea89e 100644 --- a/components/detournavigator/navmeshtilescache.cpp +++ b/components/detournavigator/navmeshtilescache.cpp @@ -53,13 +53,16 @@ namespace DetourNavigator } NavMeshTilesCache::NavMeshTilesCache(const std::size_t maxNavMeshDataSize) - : mMaxNavMeshDataSize(maxNavMeshDataSize), mUsedNavMeshDataSize(0), mFreeNavMeshDataSize(0) {} + : mMaxNavMeshDataSize(maxNavMeshDataSize), mUsedNavMeshDataSize(0), mFreeNavMeshDataSize(0), + mHitCount(0), mGetCount(0){} NavMeshTilesCache::Value NavMeshTilesCache::get(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile, const RecastMesh& recastMesh, const std::vector& offMeshConnections) { const std::lock_guard lock(mMutex); + ++mGetCount; + const auto agentValues = mValues.find(agentHalfExtents); if (agentValues == mValues.end()) return Value(); @@ -74,6 +77,8 @@ namespace DetourNavigator acquireItemUnsafe(tile->second); + ++mHitCount; + return Value(*this, tile->second); } @@ -123,17 +128,22 @@ namespace DetourNavigator std::size_t navMeshCacheSize = 0; std::size_t usedNavMeshTiles = 0; std::size_t cachedNavMeshTiles = 0; + std::size_t hitCount = 0; + std::size_t getCount = 0; { const std::lock_guard lock(mMutex); navMeshCacheSize = mUsedNavMeshDataSize; usedNavMeshTiles = mBusyItems.size(); cachedNavMeshTiles = mFreeItems.size(); + hitCount = mHitCount; + getCount = mGetCount; } stats.setAttribute(frameNumber, "NavMesh CacheSize", navMeshCacheSize); stats.setAttribute(frameNumber, "NavMesh UsedTiles", usedNavMeshTiles); stats.setAttribute(frameNumber, "NavMesh CachedTiles", cachedNavMeshTiles); + stats.setAttribute(frameNumber, "NavMesh CacheHitRate", static_cast(hitCount) / getCount * 100.0); } void NavMeshTilesCache::removeLeastRecentlyUsed() diff --git a/components/detournavigator/navmeshtilescache.hpp b/components/detournavigator/navmeshtilescache.hpp index 064d9e185..a6dd1ed9a 100644 --- a/components/detournavigator/navmeshtilescache.hpp +++ b/components/detournavigator/navmeshtilescache.hpp @@ -194,6 +194,8 @@ namespace DetourNavigator std::size_t mMaxNavMeshDataSize; std::size_t mUsedNavMeshDataSize; std::size_t mFreeNavMeshDataSize; + std::size_t mHitCount; + std::size_t mGetCount; std::list mBusyItems; std::list mFreeItems; std::map> mValues; diff --git a/components/resource/stats.cpp b/components/resource/stats.cpp index 3649af089..690814f91 100644 --- a/components/resource/stats.cpp +++ b/components/resource/stats.cpp @@ -394,6 +394,7 @@ void StatsHandler::setUpScene(osgViewer::ViewerBase *viewer) "NavMesh CacheSize", "NavMesh UsedTiles", "NavMesh CachedTiles", + "NavMesh CacheHitRate", "", "Mechanics Actors", "Mechanics Objects", From 489107c5eed4de2ce0cef3a88d1cedf0cb811311 Mon Sep 17 00:00:00 2001 From: elsid Date: Thu, 4 Feb 2021 00:44:15 +0100 Subject: [PATCH 06/15] Count navmesh cache key once in item size Key is stored only in NavMeshTilesCache::Item, TileMap uses KeyView with a pointer to a vector. --- .../detournavigator/navmeshtilescache.cpp | 22 +++++++++---------- .../detournavigator/navmeshtilescache.cpp | 2 +- .../detournavigator/navmeshtilescache.hpp | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp b/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp index e8e7820d9..5bc7af646 100644 --- a/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp +++ b/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp @@ -68,7 +68,7 @@ namespace { const std::size_t navMeshDataSize = 1; const std::size_t navMeshKeySize = cRecastMeshKeySize; - const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; + const std::size_t maxSize = navMeshDataSize + navMeshKeySize; NavMeshTilesCache cache(maxSize); const auto result = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections, @@ -81,7 +81,7 @@ namespace { const std::size_t navMeshDataSize = 1; const std::size_t navMeshKeySize = cRecastMeshKeySize; - const std::size_t maxSize = 2 * (navMeshDataSize + 2 * navMeshKeySize); + const std::size_t maxSize = 2 * (navMeshDataSize + navMeshKeySize); NavMeshTilesCache cache(maxSize); const auto anotherData = reinterpret_cast(dtAlloc(1, DT_ALLOC_PERM)); NavMeshData anotherNavMeshData {anotherData, 1}; @@ -97,7 +97,7 @@ namespace { const std::size_t navMeshDataSize = 1; const std::size_t navMeshKeySize = cRecastMeshKeySize; - const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; + const std::size_t maxSize = navMeshDataSize + navMeshKeySize; NavMeshTilesCache cache(maxSize); cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections, std::move(mNavMeshData)); @@ -142,7 +142,7 @@ namespace { const std::size_t navMeshDataSize = 1; const std::size_t navMeshKeySize = cRecastMeshWithWaterKeySize; - const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; + const std::size_t maxSize = navMeshDataSize + navMeshKeySize; NavMeshTilesCache cache(maxSize); const std::vector water {1, RecastMesh::Water {1, btTransform::getIdentity()}}; @@ -163,7 +163,7 @@ namespace { const std::size_t navMeshDataSize = 1; const std::size_t navMeshKeySize = cRecastMeshKeySize; - const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; + const std::size_t maxSize = navMeshDataSize + navMeshKeySize; NavMeshTilesCache cache(maxSize); const std::vector water {1, RecastMesh::Water {1, btTransform::getIdentity()}}; @@ -182,7 +182,7 @@ namespace { const std::size_t navMeshDataSize = 1; const std::size_t navMeshKeySize = cRecastMeshWithWaterKeySize; - const std::size_t maxSize = 2 * (navMeshDataSize + 2 * navMeshKeySize); + const std::size_t maxSize = 2 * (navMeshDataSize + navMeshKeySize); NavMeshTilesCache cache(maxSize); const std::vector leastRecentlySetWater {1, RecastMesh::Water {1, btTransform::getIdentity()}}; @@ -214,7 +214,7 @@ namespace { const std::size_t navMeshDataSize = 1; const std::size_t navMeshKeySize = cRecastMeshWithWaterKeySize; - const std::size_t maxSize = 2 * (navMeshDataSize + 2 * navMeshKeySize); + const std::size_t maxSize = 2 * (navMeshDataSize + navMeshKeySize); NavMeshTilesCache cache(maxSize); const std::vector leastRecentlyUsedWater {1, RecastMesh::Water {1, btTransform::getIdentity()}}; @@ -258,7 +258,7 @@ namespace { const std::size_t navMeshDataSize = 1; const std::size_t navMeshKeySize = cRecastMeshKeySize; - const std::size_t maxSize = 2 * (navMeshDataSize + 2 * navMeshKeySize); + const std::size_t maxSize = 2 * (navMeshDataSize + navMeshKeySize); NavMeshTilesCache cache(maxSize); const std::vector water {1, RecastMesh::Water {1, btTransform::getIdentity()}}; @@ -277,7 +277,7 @@ namespace const std::size_t navMeshDataSize = 1; const std::size_t navMeshKeySize1 = cRecastMeshKeySize; const std::size_t navMeshKeySize2 = cRecastMeshWithWaterKeySize; - const std::size_t maxSize = 2 * navMeshDataSize + 2 * navMeshKeySize1 + 2 * navMeshKeySize2; + const std::size_t maxSize = 2 * navMeshDataSize + navMeshKeySize1 + navMeshKeySize2; NavMeshTilesCache cache(maxSize); const std::vector anotherWater {1, RecastMesh::Water {1, btTransform::getIdentity()}}; @@ -306,7 +306,7 @@ namespace { const std::size_t navMeshDataSize = 1; const std::size_t navMeshKeySize = cRecastMeshKeySize; - const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; + const std::size_t maxSize = navMeshDataSize + navMeshKeySize; NavMeshTilesCache cache(maxSize); const std::vector water {1, RecastMesh::Water {1, btTransform::getIdentity()}}; @@ -330,7 +330,7 @@ namespace { const std::size_t navMeshDataSize = 1; const std::size_t navMeshKeySize = cRecastMeshKeySize; - const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; + const std::size_t maxSize = navMeshDataSize + navMeshKeySize; NavMeshTilesCache cache(maxSize); const std::vector water {1, RecastMesh::Water {1, btTransform::getIdentity()}}; diff --git a/components/detournavigator/navmeshtilescache.cpp b/components/detournavigator/navmeshtilescache.cpp index 1b90ea89e..d9879fcbb 100644 --- a/components/detournavigator/navmeshtilescache.cpp +++ b/components/detournavigator/navmeshtilescache.cpp @@ -97,7 +97,7 @@ namespace DetourNavigator return Value(); auto navMeshKey = makeNavMeshKey(recastMesh, offMeshConnections); - const auto itemSize = navMeshSize + 2 * navMeshKey.size(); + const auto itemSize = navMeshSize + navMeshKey.size(); if (itemSize > mFreeNavMeshDataSize + (mMaxNavMeshDataSize - mUsedNavMeshDataSize)) return Value(); diff --git a/components/detournavigator/navmeshtilescache.hpp b/components/detournavigator/navmeshtilescache.hpp index a6dd1ed9a..338ead3aa 100644 --- a/components/detournavigator/navmeshtilescache.hpp +++ b/components/detournavigator/navmeshtilescache.hpp @@ -208,7 +208,7 @@ namespace DetourNavigator static std::size_t getSize(const Item& item) { - return static_cast(item.mNavMeshData.mSize) + 2 * item.mNavMeshKey.size(); + return static_cast(item.mNavMeshData.mSize) + item.mNavMeshKey.size(); } }; } From ad1f8c1e8445acdb2f40f7fcee767b587e5df11c Mon Sep 17 00:00:00 2001 From: elsid Date: Thu, 4 Feb 2021 00:14:29 +0100 Subject: [PATCH 07/15] Sort water and off mesh connections for recast mesh Inconsisten order of these objects in navmesh cache key leads to cache misses due to key inequality. --- components/bullethelpers/operators.hpp | 15 +++++++++++++++ components/detournavigator/offmeshconnection.hpp | 7 +++++++ .../detournavigator/offmeshconnectionsmanager.hpp | 2 ++ components/detournavigator/recastmesh.hpp | 8 ++++++++ components/detournavigator/recastmeshbuilder.cpp | 1 + 5 files changed, 33 insertions(+) diff --git a/components/bullethelpers/operators.hpp b/components/bullethelpers/operators.hpp index ea88deddf..dd2ec8017 100644 --- a/components/bullethelpers/operators.hpp +++ b/components/bullethelpers/operators.hpp @@ -68,4 +68,19 @@ inline std::ostream& operator <<(std::ostream& stream, BroadphaseNativeTypes val } } +inline bool operator <(const btVector3& lhs, const btVector3& rhs) +{ + return std::tie(lhs.x(), lhs.y(), lhs.z()) < std::tie(rhs.x(), rhs.y(), rhs.z()); +} + +inline bool operator <(const btMatrix3x3& lhs, const btMatrix3x3& rhs) +{ + return std::tie(lhs[0], lhs[1], lhs[2]) < std::tie(rhs[0], rhs[1], rhs[2]); +} + +inline bool operator <(const btTransform& lhs, const btTransform& rhs) +{ + return std::tie(lhs.getBasis(), lhs.getOrigin()) < std::tie(rhs.getBasis(), rhs.getOrigin()); +} + #endif diff --git a/components/detournavigator/offmeshconnection.hpp b/components/detournavigator/offmeshconnection.hpp index ca999dbdb..01bae0273 100644 --- a/components/detournavigator/offmeshconnection.hpp +++ b/components/detournavigator/offmeshconnection.hpp @@ -5,6 +5,8 @@ #include +#include + namespace DetourNavigator { struct OffMeshConnection @@ -13,6 +15,11 @@ namespace DetourNavigator osg::Vec3f mEnd; AreaType mAreaType; }; + + inline bool operator<(const OffMeshConnection& lhs, const OffMeshConnection& rhs) + { + return std::tie(lhs.mStart, lhs.mEnd, lhs.mAreaType) < std::tie(rhs.mStart, rhs.mEnd, rhs.mAreaType); + } } #endif diff --git a/components/detournavigator/offmeshconnectionsmanager.hpp b/components/detournavigator/offmeshconnectionsmanager.hpp index de707f3a8..1ad96e3b9 100644 --- a/components/detournavigator/offmeshconnectionsmanager.hpp +++ b/components/detournavigator/offmeshconnectionsmanager.hpp @@ -85,6 +85,8 @@ namespace DetourNavigator std::for_each(byId.first, byId.second, [&] (const auto& v) { result.push_back(v.second); }); }); + std::sort(result.begin(), result.end()); + return result; } diff --git a/components/detournavigator/recastmesh.hpp b/components/detournavigator/recastmesh.hpp index f3259903f..29f37822e 100644 --- a/components/detournavigator/recastmesh.hpp +++ b/components/detournavigator/recastmesh.hpp @@ -5,9 +5,12 @@ #include "chunkytrimesh.hpp" #include "bounds.hpp" +#include + #include #include #include +#include #include @@ -87,6 +90,11 @@ namespace DetourNavigator ChunkyTriMesh mChunkyTriMesh; Bounds mBounds; }; + + inline bool operator<(const RecastMesh::Water& lhs, const RecastMesh::Water& rhs) + { + return std::tie(lhs.mCellSize, lhs.mTransform) < std::tie(rhs.mCellSize, rhs.mTransform); + } } #endif diff --git a/components/detournavigator/recastmeshbuilder.cpp b/components/detournavigator/recastmeshbuilder.cpp index ee014b932..f8456acf0 100644 --- a/components/detournavigator/recastmeshbuilder.cpp +++ b/components/detournavigator/recastmeshbuilder.cpp @@ -155,6 +155,7 @@ namespace DetourNavigator std::shared_ptr RecastMeshBuilder::create(std::size_t generation, std::size_t revision) { optimizeRecastMesh(mIndices, mVertices); + std::sort(mWater.begin(), mWater.end()); return std::make_shared(generation, revision, mIndices, mVertices, mAreaTypes, mWater, mSettings.get().mTrianglesPerChunk); } From 3a2cea52714b26c69dfd89672dd1ad6a9886acac Mon Sep 17 00:00:00 2001 From: elsid Date: Thu, 4 Feb 2021 00:15:54 +0100 Subject: [PATCH 08/15] Use raw recast mesh data and off mesh connections for navmesh key Serialization into a vector of chars produces inconsistent results that leads to reduced cache hit rate. Using a structured object is a more clear solution and allows to remove serialization and nontrivial key compare logic with more straigt forward structured object comparison. --- .../detournavigator/navmeshtilescache.cpp | 123 ++----------- .../detournavigator/navmeshtilescache.hpp | 168 ++++++++++-------- components/detournavigator/recastmesh.hpp | 6 + 3 files changed, 110 insertions(+), 187 deletions(-) diff --git a/components/detournavigator/navmeshtilescache.cpp b/components/detournavigator/navmeshtilescache.cpp index d9879fcbb..84c658653 100644 --- a/components/detournavigator/navmeshtilescache.cpp +++ b/components/detournavigator/navmeshtilescache.cpp @@ -9,52 +9,21 @@ namespace DetourNavigator { namespace { - inline std::vector makeNavMeshKey(const RecastMesh& recastMesh, - const std::vector& offMeshConnections) + inline std::size_t getSize(const RecastMesh& recastMesh, + const std::vector& offMeshConnections) { const std::size_t indicesSize = recastMesh.getIndices().size() * sizeof(int); const std::size_t verticesSize = recastMesh.getVertices().size() * sizeof(float); const std::size_t areaTypesSize = recastMesh.getAreaTypes().size() * sizeof(AreaType); const std::size_t waterSize = recastMesh.getWater().size() * sizeof(RecastMesh::Water); const std::size_t offMeshConnectionsSize = offMeshConnections.size() * sizeof(OffMeshConnection); - - std::vector result(indicesSize + verticesSize + areaTypesSize + waterSize + offMeshConnectionsSize); - unsigned char* dst = result.data(); - - if (indicesSize > 0) - { - std::memcpy(dst, recastMesh.getIndices().data(), indicesSize); - dst += indicesSize; - } - - if (verticesSize > 0) - { - std::memcpy(dst, recastMesh.getVertices().data(), verticesSize); - dst += verticesSize; - } - - if (areaTypesSize > 0) - { - std::memcpy(dst, recastMesh.getAreaTypes().data(), areaTypesSize); - dst += areaTypesSize; - } - - if (waterSize > 0) - { - std::memcpy(dst, recastMesh.getWater().data(), waterSize); - dst += waterSize; - } - - if (offMeshConnectionsSize > 0) - std::memcpy(dst, offMeshConnections.data(), offMeshConnectionsSize); - - return result; + return indicesSize + verticesSize + areaTypesSize + waterSize + offMeshConnectionsSize; } } NavMeshTilesCache::NavMeshTilesCache(const std::size_t maxNavMeshDataSize) : mMaxNavMeshDataSize(maxNavMeshDataSize), mUsedNavMeshDataSize(0), mFreeNavMeshDataSize(0), - mHitCount(0), mGetCount(0){} + mHitCount(0), mGetCount(0) {} NavMeshTilesCache::Value NavMeshTilesCache::get(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile, const RecastMesh& recastMesh, const std::vector& offMeshConnections) @@ -71,7 +40,7 @@ namespace DetourNavigator if (tileValues == agentValues->second.end()) return Value(); - const auto tile = tileValues->second.mMap.find(RecastMeshKeyView(recastMesh, offMeshConnections)); + const auto tile = tileValues->second.mMap.find(NavMeshKeyView(recastMesh, offMeshConnections)); if (tile == tileValues->second.mMap.end()) return Value(); @@ -96,8 +65,11 @@ namespace DetourNavigator if (navMeshSize > mFreeNavMeshDataSize + (mMaxNavMeshDataSize - mUsedNavMeshDataSize)) return Value(); - auto navMeshKey = makeNavMeshKey(recastMesh, offMeshConnections); - const auto itemSize = navMeshSize + navMeshKey.size(); + NavMeshKey navMeshKey { + RecastMeshData {recastMesh.getIndices(), recastMesh.getVertices(), recastMesh.getAreaTypes(), recastMesh.getWater()}, + offMeshConnections + }; + const auto itemSize = navMeshSize + getSize(recastMesh, offMeshConnections); if (itemSize > mFreeNavMeshDataSize + (mMaxNavMeshDataSize - mUsedNavMeshDataSize)) return Value(); @@ -105,7 +77,7 @@ namespace DetourNavigator while (!mFreeItems.empty() && mUsedNavMeshDataSize + itemSize > mMaxNavMeshDataSize) removeLeastRecentlyUsed(); - const auto iterator = mFreeItems.emplace(mFreeItems.end(), agentHalfExtents, changedTile, std::move(navMeshKey)); + const auto iterator = mFreeItems.emplace(mFreeItems.end(), agentHalfExtents, changedTile, std::move(navMeshKey), itemSize); const auto emplaced = mValues[agentHalfExtents][changedTile].mMap.emplace(iterator->mNavMeshKey, iterator); if (!emplaced.second) @@ -162,8 +134,8 @@ namespace DetourNavigator if (value == tileValues->second.mMap.end()) return; - mUsedNavMeshDataSize -= getSize(item); - mFreeNavMeshDataSize -= getSize(item); + mUsedNavMeshDataSize -= item.mSize; + mFreeNavMeshDataSize -= item.mSize; tileValues->second.mMap.erase(value); mFreeItems.pop_back(); @@ -184,7 +156,7 @@ namespace DetourNavigator return; mBusyItems.splice(mBusyItems.end(), mFreeItems, iterator); - mFreeNavMeshDataSize -= getSize(*iterator); + mFreeNavMeshDataSize -= iterator->mSize; } void NavMeshTilesCache::releaseItem(ItemIterator iterator) @@ -195,71 +167,6 @@ namespace DetourNavigator const std::lock_guard lock(mMutex); mFreeItems.splice(mFreeItems.begin(), mBusyItems, iterator); - mFreeNavMeshDataSize += getSize(*iterator); - } - - namespace - { - struct CompareBytes - { - const unsigned char* mRhsIt; - const unsigned char* const mRhsEnd; - - template - int operator ()(const std::vector& lhs) - { - const auto lhsBegin = reinterpret_cast(lhs.data()); - const auto lhsEnd = reinterpret_cast(lhs.data() + lhs.size()); - const auto lhsSize = static_cast(lhsEnd - lhsBegin); - const auto rhsSize = static_cast(mRhsEnd - mRhsIt); - - if (lhsBegin == nullptr || mRhsIt == nullptr) - { - if (lhsSize < rhsSize) - return -1; - else if (lhsSize > rhsSize) - return 1; - else - return 0; - } - - const auto size = std::min(lhsSize, rhsSize); - - if (const auto result = std::memcmp(lhsBegin, mRhsIt, size)) - return result; - - if (lhsSize > rhsSize) - return 1; - - mRhsIt += size; - - return 0; - } - }; - } - - int NavMeshTilesCache::RecastMeshKeyView::compare(const std::vector& other) const - { - CompareBytes compareBytes {other.data(), other.data() + other.size()}; - - if (const auto result = compareBytes(mRecastMesh.get().getIndices())) - return result; - - if (const auto result = compareBytes(mRecastMesh.get().getVertices())) - return result; - - if (const auto result = compareBytes(mRecastMesh.get().getAreaTypes())) - return result; - - if (const auto result = compareBytes(mRecastMesh.get().getWater())) - return result; - - if (const auto result = compareBytes(mOffMeshConnections.get())) - return result; - - if (compareBytes.mRhsIt < compareBytes.mRhsEnd) - return -1; - - return 0; + mFreeNavMeshDataSize += iterator->mSize; } } diff --git a/components/detournavigator/navmeshtilescache.hpp b/components/detournavigator/navmeshtilescache.hpp index 338ead3aa..25f4dc187 100644 --- a/components/detournavigator/navmeshtilescache.hpp +++ b/components/detournavigator/navmeshtilescache.hpp @@ -27,6 +27,89 @@ namespace DetourNavigator int mSize; }; + struct RecastMeshData + { + std::vector mIndices; + std::vector mVertices; + std::vector mAreaTypes; + std::vector mWater; + }; + + inline bool operator <(const RecastMeshData& lhs, const RecastMeshData& rhs) + { + return std::tie(lhs.mIndices, lhs.mVertices, lhs.mAreaTypes, lhs.mWater) + < std::tie(rhs.mIndices, rhs.mVertices, rhs.mAreaTypes, rhs.mWater); + } + + inline bool operator <(const RecastMeshData& lhs, const RecastMesh& rhs) + { + return std::tie(lhs.mIndices, lhs.mVertices, lhs.mAreaTypes, lhs.mWater) + < std::tie(rhs.getIndices(), rhs.getVertices(), rhs.getAreaTypes(), rhs.getWater()); + } + + inline bool operator <(const RecastMesh& lhs, const RecastMeshData& rhs) + { + return std::tie(lhs.getIndices(), lhs.getVertices(), lhs.getAreaTypes(), lhs.getWater()) + < std::tie(rhs.mIndices, rhs.mVertices, rhs.mAreaTypes, rhs.mWater); + } + + struct NavMeshKey + { + RecastMeshData mRecastMesh; + std::vector mOffMeshConnections; + }; + + inline bool operator <(const NavMeshKey& lhs, const NavMeshKey& rhs) + { + return std::tie(lhs.mRecastMesh, lhs.mOffMeshConnections) + < std::tie(rhs.mRecastMesh, rhs.mOffMeshConnections); + } + + struct NavMeshKeyRef + { + std::reference_wrapper mRef; + + explicit NavMeshKeyRef(const NavMeshKey& ref) : mRef(ref) {} + }; + + inline bool operator <(const NavMeshKeyRef& lhs, const NavMeshKeyRef& rhs) + { + return lhs.mRef.get() < rhs.mRef.get(); + } + + struct NavMeshKeyView + { + std::reference_wrapper mRecastMesh; + std::reference_wrapper> mOffMeshConnections; + + NavMeshKeyView(const RecastMesh& recastMesh, const std::vector& offMeshConnections) + : mRecastMesh(recastMesh), mOffMeshConnections(offMeshConnections) {} + }; + + inline bool operator <(const NavMeshKeyView& lhs, const NavMeshKey& rhs) + { + return std::tie(lhs.mRecastMesh.get(), lhs.mOffMeshConnections.get()) + < std::tie(rhs.mRecastMesh, rhs.mOffMeshConnections); + } + + inline bool operator <(const NavMeshKey& lhs, const NavMeshKeyView& rhs) + { + return std::tie(lhs.mRecastMesh, lhs.mOffMeshConnections) + < std::tie(rhs.mRecastMesh.get(), rhs.mOffMeshConnections.get()); + } + + template + inline bool operator <(const NavMeshKeyRef& lhs, const R& rhs) + { + return lhs.mRef.get() < rhs; + } + + template + inline bool operator <(const L& lhs, const NavMeshKeyRef& rhs) + { + return lhs < rhs.mRef.get(); + } + class NavMeshTilesCache { public: @@ -35,14 +118,16 @@ namespace DetourNavigator std::atomic mUseCount; osg::Vec3f mAgentHalfExtents; TilePosition mChangedTile; - std::vector mNavMeshKey; + NavMeshKey mNavMeshKey; NavMeshData mNavMeshData; + std::size_t mSize; - Item(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile, std::vector&& navMeshKey) + Item(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile, NavMeshKey&& navMeshKey, std::size_t size) : mUseCount(0) , mAgentHalfExtents(agentHalfExtents) , mChangedTile(changedTile) - , mNavMeshKey(std::move(navMeshKey)) + , mNavMeshKey(navMeshKey) + , mSize(size) {} }; @@ -115,79 +200,9 @@ namespace DetourNavigator void reportStats(unsigned int frameNumber, osg::Stats& stats) const; private: - class KeyView - { - public: - KeyView() = default; - - virtual ~KeyView() = default; - - KeyView(const std::vector& value) - : mValue(&value) {} - - const std::vector& getValue() const - { - assert(mValue); - return *mValue; - } - - virtual int compare(const std::vector& other) const - { - assert(mValue); - - const auto valueSize = mValue->size(); - const auto otherSize = other.size(); - - if (const auto result = std::memcmp(mValue->data(), other.data(), std::min(valueSize, otherSize))) - return result; - - if (valueSize < otherSize) - return -1; - - if (valueSize > otherSize) - return 1; - - return 0; - } - - virtual bool isLess(const KeyView& other) const - { - assert(mValue); - return other.compare(*mValue) > 0; - } - - friend bool operator <(const KeyView& lhs, const KeyView& rhs) - { - return lhs.isLess(rhs); - } - - private: - const std::vector* mValue = nullptr; - }; - - class RecastMeshKeyView : public KeyView - { - public: - RecastMeshKeyView(const RecastMesh& recastMesh, const std::vector& offMeshConnections) - : mRecastMesh(recastMesh), mOffMeshConnections(offMeshConnections) {} - - int compare(const std::vector& other) const override; - - bool isLess(const KeyView& other) const override - { - return compare(other.getValue()) < 0; - } - - virtual ~RecastMeshKeyView() = default; - - private: - std::reference_wrapper mRecastMesh; - std::reference_wrapper> mOffMeshConnections; - }; - struct TileMap { - std::map mMap; + std::map> mMap; }; mutable std::mutex mMutex; @@ -205,11 +220,6 @@ namespace DetourNavigator void acquireItemUnsafe(ItemIterator iterator); void releaseItem(ItemIterator iterator); - - static std::size_t getSize(const Item& item) - { - return static_cast(item.mNavMeshData.mSize) + item.mNavMeshKey.size(); - } }; } diff --git a/components/detournavigator/recastmesh.hpp b/components/detournavigator/recastmesh.hpp index 29f37822e..746422ac8 100644 --- a/components/detournavigator/recastmesh.hpp +++ b/components/detournavigator/recastmesh.hpp @@ -95,6 +95,12 @@ namespace DetourNavigator { return std::tie(lhs.mCellSize, lhs.mTransform) < std::tie(rhs.mCellSize, rhs.mTransform); } + + inline bool operator <(const RecastMesh& lhs, const RecastMesh& rhs) + { + return std::tie(lhs.getIndices(), lhs.getVertices(), lhs.getAreaTypes(), lhs.getWater()) + < std::tie(rhs.getIndices(), rhs.getVertices(), rhs.getAreaTypes(), rhs.getWater()); + } } #endif From 68fe6b91145350c12487332cc26483f032f2ec64 Mon Sep 17 00:00:00 2001 From: elsid Date: Thu, 4 Feb 2021 01:12:52 +0100 Subject: [PATCH 09/15] Use only item size to check whether item fits cache Item size has to be counted anyway and there is no reason to check only navmesh data first. --- .../detournavigator/navmeshtilescache.cpp | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/components/detournavigator/navmeshtilescache.cpp b/components/detournavigator/navmeshtilescache.cpp index 84c658653..b6048da58 100644 --- a/components/detournavigator/navmeshtilescache.cpp +++ b/components/detournavigator/navmeshtilescache.cpp @@ -55,28 +55,21 @@ namespace DetourNavigator const RecastMesh& recastMesh, const std::vector& offMeshConnections, NavMeshData&& value) { - const auto navMeshSize = static_cast(value.mSize); + const auto itemSize = static_cast(value.mSize) + getSize(recastMesh, offMeshConnections); const std::lock_guard lock(mMutex); - if (navMeshSize > mMaxNavMeshDataSize) - return Value(); - - if (navMeshSize > mFreeNavMeshDataSize + (mMaxNavMeshDataSize - mUsedNavMeshDataSize)) - return Value(); - - NavMeshKey navMeshKey { - RecastMeshData {recastMesh.getIndices(), recastMesh.getVertices(), recastMesh.getAreaTypes(), recastMesh.getWater()}, - offMeshConnections - }; - const auto itemSize = navMeshSize + getSize(recastMesh, offMeshConnections); - if (itemSize > mFreeNavMeshDataSize + (mMaxNavMeshDataSize - mUsedNavMeshDataSize)) return Value(); while (!mFreeItems.empty() && mUsedNavMeshDataSize + itemSize > mMaxNavMeshDataSize) removeLeastRecentlyUsed(); + NavMeshKey navMeshKey { + RecastMeshData {recastMesh.getIndices(), recastMesh.getVertices(), recastMesh.getAreaTypes(), recastMesh.getWater()}, + offMeshConnections + }; + const auto iterator = mFreeItems.emplace(mFreeItems.end(), agentHalfExtents, changedTile, std::move(navMeshKey), itemSize); const auto emplaced = mValues[agentHalfExtents][changedTile].mMap.emplace(iterator->mNavMeshKey, iterator); From 61e014a7657092bf8ea1e426665ea3934169c560 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Thu, 4 Feb 2021 21:25:38 +0100 Subject: [PATCH 10/15] Allow negative values for ai stats --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/stat.cpp | 4 +++- apps/openmw/mwmechanics/stat.hpp | 2 +- apps/openmw/mwscript/aiextensions.cpp | 6 ++---- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa74164d9..b5b66ee01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -98,6 +98,7 @@ Bug #5758: Paralyzed actors behavior is inconsistent with vanilla Bug #5762: Movement solver is insufficiently robust Bug #5821: NPCs from mods getting removed if mod order was changed + Bug #5835: OpenMW doesn't accept negative values for NPC's hello, alarm, fight, and flee Feature #390: 3rd person look "over the shoulder" Feature #1536: Show more information about level on menu Feature #2386: Distant Statics in the form of Object Paging diff --git a/apps/openmw/mwmechanics/stat.cpp b/apps/openmw/mwmechanics/stat.cpp index 7f71cf9b1..c87de2ccb 100644 --- a/apps/openmw/mwmechanics/stat.cpp +++ b/apps/openmw/mwmechanics/stat.cpp @@ -18,8 +18,10 @@ namespace MWMechanics } template - T Stat::getModified() const + T Stat::getModified(bool capped) const { + if(!capped) + return mModified; return std::max(static_cast(0), mModified); } diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index 5f49da48e..fb9dca922 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -28,7 +28,7 @@ namespace MWMechanics const T& getBase() const; - T getModified() const; + T getModified(bool capped = true) const; T getCurrentModified() const; T getModifier() const; T getCurrentModifier() const; diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 499c2f672..223ae3a15 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -241,7 +241,7 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - runtime.push(ptr.getClass().getCreatureStats (ptr).getAiSetting (mIndex).getModified()); + runtime.push(ptr.getClass().getCreatureStats (ptr).getAiSetting (mIndex).getModified(false)); } }; template @@ -276,9 +276,7 @@ namespace MWScript Interpreter::Type_Integer value = runtime[0].mInteger; runtime.pop(); - MWMechanics::Stat stat = ptr.getClass().getCreatureStats(ptr).getAiSetting(mIndex); - stat.setModified(value, 0); - ptr.getClass().getCreatureStats(ptr).setAiSetting(mIndex, stat); + ptr.getClass().getCreatureStats(ptr).setAiSetting(mIndex, value); ptr.getClass().setBaseAISetting(ptr.getCellRef().getRefId(), mIndex, value); } }; From e42b67ee50b8d5950e183db51d750198d87db7f2 Mon Sep 17 00:00:00 2001 From: Noah Gooder Date: Fri, 5 Feb 2021 17:59:36 +0000 Subject: [PATCH 11/15] Modified actors.cpp and Authors.md --- AUTHORS.md | 1 + apps/openmw/mwmechanics/actors.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/AUTHORS.md b/AUTHORS.md index e6ff67293..53efdd286 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -215,6 +215,7 @@ Programmers Yohaulticetl Yuri Krupenin zelurker + Noah Gooder Documentation ------------- diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index cb3570d21..c0a137158 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -951,7 +951,7 @@ namespace MWMechanics if (actor.getClass().hasInventoryStore(actor)) actor.getClass().getInventoryStore(actor).purgeEffect(ESM::MagicEffect::Poison); } - else if (effects.get(ESM::MagicEffect::CureParalyzation).getModifier() > 0) + if (effects.get(ESM::MagicEffect::CureParalyzation).getModifier() > 0) { creatureStats.getActiveSpells().purgeEffect(ESM::MagicEffect::Paralyze); creatureStats.getSpells().purgeEffect(ESM::MagicEffect::Paralyze); From 3007cb14a9fa10ef2d17f53a2519030135d737db Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Fri, 5 Feb 2021 19:00:35 +0100 Subject: [PATCH 12/15] Also allow negative AI values in dialogue --- CHANGELOG.md | 1 + apps/openmw/mwdialogue/filter.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5b66ee01..d25984a83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -99,6 +99,7 @@ Bug #5762: Movement solver is insufficiently robust Bug #5821: NPCs from mods getting removed if mod order was changed Bug #5835: OpenMW doesn't accept negative values for NPC's hello, alarm, fight, and flee + Bug #5836: OpenMW dialogue/greeting/voice filter doesn't accept negative Ai values for NPC's hello, alarm, fight, and flee Feature #390: 3rd person look "over the shoulder" Feature #1536: Show more information about level on menu Feature #2386: Distant Statics in the form of Object Paging diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index a3c326ab8..334a9db39 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -316,7 +316,7 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con case SelectWrapper::Function_AiSetting: return mActor.getClass().getCreatureStats (mActor).getAiSetting ( - (MWMechanics::CreatureStats::AiSetting)select.getArgument()).getModified(); + (MWMechanics::CreatureStats::AiSetting)select.getArgument()).getModified(false); case SelectWrapper::Function_PcAttribute: From 3e273a759acc8e238de5ce2ceb03d877405a6f0f Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 6 Feb 2021 16:41:46 +0000 Subject: [PATCH 13/15] Clarify method name now we're using it differently --- components/sceneutil/mwshadowtechnique.cpp | 6 +++--- components/sceneutil/mwshadowtechnique.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 7476bc219..ba903f6db 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -1426,7 +1426,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) if (numValidShadows>0) { - selectStateSetForRenderingShadow(*vdd, cv.getTraversalNumber()); + prepareStateSetForRenderingShadow(*vdd, cv.getTraversalNumber()); } // OSG_NOTICE<<"End of shadow setup Projection matrix "<<*cv.getProjectionMatrix()< stateset = vdd.getStateSet(traversalNumber); diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 5125247dd..7b934b798 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -231,7 +231,7 @@ namespace SceneUtil { virtual void cullShadowCastingScene(osgUtil::CullVisitor* cv, osg::Camera* camera) const; - virtual osg::StateSet* selectStateSetForRenderingShadow(ViewDependentData& vdd, unsigned int traversalNumber) const; + virtual osg::StateSet* prepareStateSetForRenderingShadow(ViewDependentData& vdd, unsigned int traversalNumber) const; protected: virtual ~MWShadowTechnique(); From 31b5150e0db3f2094d4ac4a67990a82529c69a83 Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Sun, 7 Feb 2021 09:12:38 +0100 Subject: [PATCH 14/15] Fix implementation of Misc::swapEndiannessInplace --- components/misc/endianness.hpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/components/misc/endianness.hpp b/components/misc/endianness.hpp index 1b43e584e..8019d33ed 100644 --- a/components/misc/endianness.hpp +++ b/components/misc/endianness.hpp @@ -2,6 +2,8 @@ #define COMPONENTS_MISC_ENDIANNESS_H #include +#include +#include namespace Misc { @@ -15,20 +17,26 @@ namespace Misc if constexpr (sizeof(T) == 2) { - uint16_t& v16 = *reinterpret_cast(&v); + uint16_t v16; + std::memcpy(&v16, &v, sizeof(T)); v16 = (v16 >> 8) | (v16 << 8); + std::memcpy(&v, &v16, sizeof(T)); } if constexpr (sizeof(T) == 4) { - uint32_t& v32 = *reinterpret_cast(&v); - v32 = (v32 >> 24) | ((v32 >> 8) & 0xff00) | ((v32 & 0xff00) << 8) || v32 << 24; + uint32_t v32; + std::memcpy(&v32, &v, sizeof(T)); + v32 = (v32 >> 24) | ((v32 >> 8) & 0xff00) | ((v32 & 0xff00) << 8) | v32 << 24; + std::memcpy(&v, &v32, sizeof(T)); } if constexpr (sizeof(T) == 8) { - uint64_t& v64 = *reinterpret_cast(&v); + uint64_t v64; + std::memcpy(&v64, &v, sizeof(T)); v64 = (v64 >> 56) | ((v64 & 0x00ff'0000'0000'0000) >> 40) | ((v64 & 0x0000'ff00'0000'0000) >> 24) | ((v64 & 0x0000'00ff'0000'0000) >> 8) | ((v64 & 0x0000'0000'ff00'0000) << 8) | ((v64 & 0x0000'0000'00ff'0000) << 24) | ((v64 & 0x0000'0000'0000'ff00) << 40) | (v64 << 56); + std::memcpy(&v, &v64, sizeof(T)); } } From 39c2c19daee5d4cff5379a077bdee4d75ab07d7a Mon Sep 17 00:00:00 2001 From: Jonas Tobias Hopusch Date: Sun, 7 Feb 2021 12:53:06 +0100 Subject: [PATCH 15/15] Update 'toggle sneak' documentation The docs now correctly say that this setting can be changed in the launcher, instead of insisting it's a config-file-only setting. Closes #5844 Signed-off-by: Jonas Tobias Hopusch --- CHANGELOG.md | 1 + docs/source/reference/modding/settings/input.rst | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d25984a83..20932c89f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -132,6 +132,7 @@ Feature #5813: Instanced groundcover support Task #5480: Drop Qt4 support Task #5520: Improve cell name autocompleter implementation + Task #5844: Update 'toggle sneak' documentation 0.46.0 ------ diff --git a/docs/source/reference/modding/settings/input.rst b/docs/source/reference/modding/settings/input.rst index 8a95686cf..d04c267a7 100644 --- a/docs/source/reference/modding/settings/input.rst +++ b/docs/source/reference/modding/settings/input.rst @@ -38,7 +38,7 @@ This setting causes the behavior of the sneak key (bound to Ctrl by default) to toggle sneaking on and off rather than requiring the key to be held down while sneaking. Players that spend significant time sneaking may find the character easier to control with this option enabled. -This setting can only be configured by editing the settings configuration file. +This setting can be toggled in the launcher under "Advanced" -> "Game Mechanics" -> "Toggle sneak". always run ----------