Do not write shapes to navmeshdb when writing is disabled

pull/3225/head
elsid 3 years ago
parent cc97c4450a
commit aaf6c82e33
No known key found for this signature in database
GPG Key ID: B845CB9FEE18AB40

@ -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,13 +801,24 @@ 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;
if (mWriteToDb)
{
const ShapeId shapeId = mNextShapeId; const ShapeId shapeId = mNextShapeId;
const std::vector<DbRefGeometryObject> objects = makeDbRefGeometryObjects(job->mRecastMesh->getMeshSources(), const auto objects = makeDbRefGeometryObjects(job->mRecastMesh->getMeshSources(),
[&] (const MeshSource& v) { return resolveMeshSource(*mDb, v, mNextShapeId); }); [&] (const MeshSource& v) { return resolveMeshSource(*mDb, v, mNextShapeId); });
if (shapeId != mNextShapeId) if (shapeId != mNextShapeId)
++mWrites; ++mWrites;
job->mInput = serialize(mRecastSettings, *job->mRecastMesh, objects); 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);
++mGetTileCount; ++mGetTileCount;

@ -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

@ -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…
Cancel
Save