mirror of
https://github.com/OpenMW/openmw.git
synced 2025-04-02 22:06:40 +00:00
Merge branch 'restrict_navmesh_cache_writes' into 'master'
Do not write shapes to navmeshdb when writing is disabled (#6498) Closes #6498 See merge request OpenMW/openmw!1486
This commit is contained in:
commit
844266b58e
7 changed files with 133 additions and 17 deletions
|
@ -26,6 +26,23 @@ namespace
|
||||||
recastMeshManager.addHeightfield(cellPosition, cellSize, HeightfieldPlane {0});
|
recastMeshManager.addHeightfield(cellPosition, cellSize, HeightfieldPlane {0});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addObject(const btBoxShape& shape, TileCachedRecastMeshManager& recastMeshManager)
|
||||||
|
{
|
||||||
|
const ObjectId id(&shape);
|
||||||
|
osg::ref_ptr<Resource::BulletShape> bulletShape(new Resource::BulletShape);
|
||||||
|
bulletShape->mFileName = "test.nif";
|
||||||
|
bulletShape->mFileHash = "test_hash";
|
||||||
|
ObjectTransform objectTransform;
|
||||||
|
std::fill(std::begin(objectTransform.mPosition.pos), std::end(objectTransform.mPosition.pos), 0.1f);
|
||||||
|
std::fill(std::begin(objectTransform.mPosition.rot), std::end(objectTransform.mPosition.rot), 0.2f);
|
||||||
|
objectTransform.mScale = 3.14f;
|
||||||
|
const CollisionShape collisionShape(
|
||||||
|
osg::ref_ptr<Resource::BulletShapeInstance>(new Resource::BulletShapeInstance(bulletShape)),
|
||||||
|
shape, objectTransform
|
||||||
|
);
|
||||||
|
recastMeshManager.addObject(id, collisionShape, btTransform::getIdentity(), AreaType_ground);
|
||||||
|
}
|
||||||
|
|
||||||
struct DetourNavigatorAsyncNavMeshUpdaterTest : Test
|
struct DetourNavigatorAsyncNavMeshUpdaterTest : Test
|
||||||
{
|
{
|
||||||
Settings mSettings = makeSettings();
|
Settings mSettings = makeSettings();
|
||||||
|
@ -34,6 +51,7 @@ namespace
|
||||||
const osg::Vec3f mAgentHalfExtents {29, 29, 66};
|
const osg::Vec3f mAgentHalfExtents {29, 29, 66};
|
||||||
const TilePosition mPlayerTile {0, 0};
|
const TilePosition mPlayerTile {0, 0};
|
||||||
const std::string mWorldspace = "sys::default";
|
const std::string mWorldspace = "sys::default";
|
||||||
|
const btBoxShape mBox {btVector3(100, 100, 20)};
|
||||||
Loading::Listener mListener;
|
Loading::Listener mListener;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -111,6 +129,7 @@ namespace
|
||||||
{
|
{
|
||||||
mRecastMeshManager.setWorldspace(mWorldspace);
|
mRecastMeshManager.setWorldspace(mWorldspace);
|
||||||
addHeightFieldPlane(mRecastMeshManager);
|
addHeightFieldPlane(mRecastMeshManager);
|
||||||
|
addObject(mBox, mRecastMeshManager);
|
||||||
auto db = std::make_unique<NavMeshDb>(":memory:");
|
auto db = std::make_unique<NavMeshDb>(":memory:");
|
||||||
NavMeshDb* const dbPtr = db.get();
|
NavMeshDb* const dbPtr = db.get();
|
||||||
AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, std::move(db));
|
AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, std::move(db));
|
||||||
|
@ -130,10 +149,11 @@ namespace
|
||||||
EXPECT_EQ(tile->mVersion, mSettings.mNavMeshVersion);
|
EXPECT_EQ(tile->mVersion, mSettings.mNavMeshVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DetourNavigatorAsyncNavMeshUpdaterTest, post_when_writing_to_db_disabled_should_not_write)
|
TEST_F(DetourNavigatorAsyncNavMeshUpdaterTest, post_when_writing_to_db_disabled_should_not_write_tiles)
|
||||||
{
|
{
|
||||||
mRecastMeshManager.setWorldspace(mWorldspace);
|
mRecastMeshManager.setWorldspace(mWorldspace);
|
||||||
addHeightFieldPlane(mRecastMeshManager);
|
addHeightFieldPlane(mRecastMeshManager);
|
||||||
|
addObject(mBox, mRecastMeshManager);
|
||||||
auto db = std::make_unique<NavMeshDb>(":memory:");
|
auto db = std::make_unique<NavMeshDb>(":memory:");
|
||||||
NavMeshDb* const dbPtr = db.get();
|
NavMeshDb* const dbPtr = db.get();
|
||||||
mSettings.mWriteToNavMeshDb = false;
|
mSettings.mWriteToNavMeshDb = false;
|
||||||
|
@ -152,6 +172,27 @@ namespace
|
||||||
ASSERT_FALSE(tile.has_value());
|
ASSERT_FALSE(tile.has_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(DetourNavigatorAsyncNavMeshUpdaterTest, post_when_writing_to_db_disabled_should_not_write_shapes)
|
||||||
|
{
|
||||||
|
mRecastMeshManager.setWorldspace(mWorldspace);
|
||||||
|
addHeightFieldPlane(mRecastMeshManager);
|
||||||
|
addObject(mBox, mRecastMeshManager);
|
||||||
|
auto db = std::make_unique<NavMeshDb>(":memory:");
|
||||||
|
NavMeshDb* const dbPtr = db.get();
|
||||||
|
mSettings.mWriteToNavMeshDb = false;
|
||||||
|
AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, std::move(db));
|
||||||
|
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), 1);
|
||||||
|
const TilePosition tilePosition {0, 0};
|
||||||
|
const std::map<TilePosition, ChangeType> changedTiles {{tilePosition, ChangeType::add}};
|
||||||
|
updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
||||||
|
updater.wait(mListener, WaitConditionType::allJobsDone);
|
||||||
|
const auto recastMesh = mRecastMeshManager.getMesh(mWorldspace, tilePosition);
|
||||||
|
ASSERT_NE(recastMesh, nullptr);
|
||||||
|
const auto objects = makeDbRefGeometryObjects(recastMesh->getMeshSources(),
|
||||||
|
[&] (const MeshSource& v) { return resolveMeshSource(*dbPtr, v); });
|
||||||
|
EXPECT_FALSE(objects.has_value());
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(DetourNavigatorAsyncNavMeshUpdaterTest, post_should_read_from_db_on_cache_miss)
|
TEST_F(DetourNavigatorAsyncNavMeshUpdaterTest, post_should_read_from_db_on_cache_miss)
|
||||||
{
|
{
|
||||||
mRecastMeshManager.setWorldspace(mWorldspace);
|
mRecastMeshManager.setWorldspace(mWorldspace);
|
||||||
|
|
|
@ -89,7 +89,8 @@ namespace DetourNavigator
|
||||||
{
|
{
|
||||||
if (db == nullptr)
|
if (db == nullptr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return std::make_unique<DbWorker>(updater, std::move(db), TileVersion(settings.mNavMeshVersion), settings.mRecast);
|
return std::make_unique<DbWorker>(updater, std::move(db), TileVersion(settings.mNavMeshVersion),
|
||||||
|
settings.mRecast, settings.mWriteToNavMeshDb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateJobs(std::deque<JobIt>& jobs, TilePosition playerTile, int maxTiles)
|
void updateJobs(std::deque<JobIt>& jobs, TilePosition playerTile, int maxTiles)
|
||||||
|
@ -704,11 +705,12 @@ namespace DetourNavigator
|
||||||
}
|
}
|
||||||
|
|
||||||
DbWorker::DbWorker(AsyncNavMeshUpdater& updater, std::unique_ptr<NavMeshDb>&& db,
|
DbWorker::DbWorker(AsyncNavMeshUpdater& updater, std::unique_ptr<NavMeshDb>&& db,
|
||||||
TileVersion version, const RecastSettings& recastSettings)
|
TileVersion version, const RecastSettings& recastSettings, bool writeToDb)
|
||||||
: mUpdater(updater)
|
: mUpdater(updater)
|
||||||
, mRecastSettings(recastSettings)
|
, mRecastSettings(recastSettings)
|
||||||
, mDb(std::move(db))
|
, mDb(std::move(db))
|
||||||
, mVersion(version)
|
, mVersion(version)
|
||||||
|
, mWriteToDb(writeToDb)
|
||||||
, mNextTileId(mDb->getMaxTileId() + 1)
|
, mNextTileId(mDb->getMaxTileId() + 1)
|
||||||
, mNextShapeId(mDb->getMaxShapeId() + 1)
|
, mNextShapeId(mDb->getMaxShapeId() + 1)
|
||||||
, mThread([this] { run(); })
|
, mThread([this] { run(); })
|
||||||
|
@ -799,12 +801,23 @@ namespace DetourNavigator
|
||||||
if (job->mInput.empty())
|
if (job->mInput.empty())
|
||||||
{
|
{
|
||||||
Log(Debug::Debug) << "Serializing input for job " << job->mId;
|
Log(Debug::Debug) << "Serializing input for job " << job->mId;
|
||||||
const ShapeId shapeId = mNextShapeId;
|
if (mWriteToDb)
|
||||||
const std::vector<DbRefGeometryObject> objects = makeDbRefGeometryObjects(job->mRecastMesh->getMeshSources(),
|
{
|
||||||
[&] (const MeshSource& v) { return resolveMeshSource(*mDb, v, mNextShapeId); });
|
const ShapeId shapeId = mNextShapeId;
|
||||||
if (shapeId != mNextShapeId)
|
const auto objects = makeDbRefGeometryObjects(job->mRecastMesh->getMeshSources(),
|
||||||
++mWrites;
|
[&] (const MeshSource& v) { return resolveMeshSource(*mDb, v, mNextShapeId); });
|
||||||
job->mInput = serialize(mRecastSettings, *job->mRecastMesh, objects);
|
if (shapeId != mNextShapeId)
|
||||||
|
++mWrites;
|
||||||
|
job->mInput = serialize(mRecastSettings, *job->mRecastMesh, objects);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto objects = makeDbRefGeometryObjects(job->mRecastMesh->getMeshSources(),
|
||||||
|
[&] (const MeshSource& v) { return resolveMeshSource(*mDb, v); });
|
||||||
|
if (!objects.has_value())
|
||||||
|
return;
|
||||||
|
job->mInput = serialize(mRecastSettings, *job->mRecastMesh, *objects);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
job->mCachedTileData = mDb->getTileData(job->mWorldspace, job->mChangedTile, job->mInput);
|
job->mCachedTileData = mDb->getTileData(job->mWorldspace, job->mChangedTile, job->mInput);
|
||||||
|
|
|
@ -136,7 +136,7 @@ namespace DetourNavigator
|
||||||
};
|
};
|
||||||
|
|
||||||
DbWorker(AsyncNavMeshUpdater& updater, std::unique_ptr<NavMeshDb>&& db,
|
DbWorker(AsyncNavMeshUpdater& updater, std::unique_ptr<NavMeshDb>&& db,
|
||||||
TileVersion version, const RecastSettings& recastSettings);
|
TileVersion version, const RecastSettings& recastSettings, bool writeToDb);
|
||||||
|
|
||||||
~DbWorker();
|
~DbWorker();
|
||||||
|
|
||||||
|
@ -153,6 +153,7 @@ namespace DetourNavigator
|
||||||
const RecastSettings& mRecastSettings;
|
const RecastSettings& mRecastSettings;
|
||||||
const std::unique_ptr<NavMeshDb> mDb;
|
const std::unique_ptr<NavMeshDb> mDb;
|
||||||
const TileVersion mVersion;
|
const TileVersion mVersion;
|
||||||
|
const bool mWriteToDb;
|
||||||
TileId mNextTileId;
|
TileId mNextTileId;
|
||||||
ShapeId mNextShapeId;
|
ShapeId mNextShapeId;
|
||||||
DbJobQueue mQueue;
|
DbJobQueue mQueue;
|
||||||
|
|
|
@ -4,10 +4,14 @@
|
||||||
#include "objecttransform.hpp"
|
#include "objecttransform.hpp"
|
||||||
#include "recastmesh.hpp"
|
#include "recastmesh.hpp"
|
||||||
|
|
||||||
|
#include <components/misc/typetraits.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <optional>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
namespace DetourNavigator
|
namespace DetourNavigator
|
||||||
{
|
{
|
||||||
|
@ -28,16 +32,27 @@ namespace DetourNavigator
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class ResolveMeshSource>
|
template <class ResolveMeshSource>
|
||||||
inline std::vector<DbRefGeometryObject> makeDbRefGeometryObjects(const std::vector<MeshSource>& meshSources,
|
inline auto makeDbRefGeometryObjects(const std::vector<MeshSource>& meshSources, ResolveMeshSource&& resolveMeshSource)
|
||||||
ResolveMeshSource&& resolveMeshSource)
|
-> std::conditional_t<
|
||||||
|
Misc::isOptional<std::decay_t<decltype(resolveMeshSource(meshSources.front()))>>,
|
||||||
|
std::optional<std::vector<DbRefGeometryObject>>,
|
||||||
|
std::vector<DbRefGeometryObject>
|
||||||
|
>
|
||||||
{
|
{
|
||||||
std::vector<DbRefGeometryObject> result;
|
std::vector<DbRefGeometryObject> result;
|
||||||
result.reserve(meshSources.size());
|
result.reserve(meshSources.size());
|
||||||
std::transform(meshSources.begin(), meshSources.end(), std::back_inserter(result),
|
for (const MeshSource& meshSource : meshSources)
|
||||||
[&] (const MeshSource& meshSource)
|
{
|
||||||
|
const auto shapeId = resolveMeshSource(meshSource);
|
||||||
|
if constexpr (Misc::isOptional<std::decay_t<decltype(shapeId)>>)
|
||||||
{
|
{
|
||||||
return DbRefGeometryObject {resolveMeshSource(meshSource), meshSource.mObjectTransform};
|
if (!shapeId.has_value())
|
||||||
});
|
return std::nullopt;
|
||||||
|
result.push_back(DbRefGeometryObject {*shapeId, meshSource.mObjectTransform});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
result.push_back(DbRefGeometryObject {shapeId, meshSource.mObjectTransform});
|
||||||
|
}
|
||||||
std::sort(result.begin(), result.end());
|
std::sort(result.begin(), result.end());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,21 @@
|
||||||
#include <components/debug/debuglog.hpp>
|
#include <components/debug/debuglog.hpp>
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
namespace DetourNavigator
|
namespace DetourNavigator
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
ShapeId getShapeId(NavMeshDb& db, const std::string& name, ShapeType type, const std::string& hash, ShapeId& nextShapeId)
|
std::optional<ShapeId> findShapeId(NavMeshDb& db, const std::string& name, ShapeType type,
|
||||||
|
const std::string& hash)
|
||||||
|
{
|
||||||
|
const Sqlite3::ConstBlob hashData {hash.data(), static_cast<int>(hash.size())};
|
||||||
|
return db.findShapeId(name, type, hashData);
|
||||||
|
}
|
||||||
|
|
||||||
|
ShapeId getShapeId(NavMeshDb& db, const std::string& name, ShapeType type,
|
||||||
|
const std::string& hash, ShapeId& nextShapeId)
|
||||||
{
|
{
|
||||||
const Sqlite3::ConstBlob hashData {hash.data(), static_cast<int>(hash.size())};
|
const Sqlite3::ConstBlob hashData {hash.data(), static_cast<int>(hash.size())};
|
||||||
if (const auto existingShapeId = db.findShapeId(name, type, hashData))
|
if (const auto existingShapeId = db.findShapeId(name, type, hashData))
|
||||||
|
@ -37,4 +46,18 @@ namespace DetourNavigator
|
||||||
return ShapeId(0);
|
return ShapeId(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<ShapeId> resolveMeshSource(NavMeshDb& db, const MeshSource& source)
|
||||||
|
{
|
||||||
|
switch (source.mAreaType)
|
||||||
|
{
|
||||||
|
case AreaType_null:
|
||||||
|
return findShapeId(db, source.mShape->mFileName, ShapeType::Avoid, source.mShape->mFileHash);
|
||||||
|
case AreaType_ground:
|
||||||
|
return findShapeId(db, source.mShape->mFileName, ShapeType::Collision, source.mShape->mFileHash);
|
||||||
|
default:
|
||||||
|
Log(Debug::Warning) << "Trying to resolve recast mesh source with unsupported area type: " << source.mAreaType;
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,15 @@
|
||||||
|
|
||||||
#include "navmeshdb.hpp"
|
#include "navmeshdb.hpp"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
namespace DetourNavigator
|
namespace DetourNavigator
|
||||||
{
|
{
|
||||||
struct MeshSource;
|
struct MeshSource;
|
||||||
|
|
||||||
ShapeId resolveMeshSource(NavMeshDb& db, const MeshSource& source, ShapeId& nextShapeId);
|
ShapeId resolveMeshSource(NavMeshDb& db, const MeshSource& source, ShapeId& nextShapeId);
|
||||||
|
|
||||||
|
std::optional<ShapeId> resolveMeshSource(NavMeshDb& db, const MeshSource& source);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
19
components/misc/typetraits.hpp
Normal file
19
components/misc/typetraits.hpp
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef OPENMW_COMPONENTS_MISC_TYPETRAITS_H
|
||||||
|
#define OPENMW_COMPONENTS_MISC_TYPETRAITS_H
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace Misc
|
||||||
|
{
|
||||||
|
template <class T>
|
||||||
|
struct IsOptional : std::false_type {};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct IsOptional<std::optional<T>> : std::true_type {};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline constexpr bool isOptional = IsOptional<T>::value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue