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});
}
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
{
Settings mSettings = makeSettings();
@ -34,6 +51,7 @@ namespace
const osg::Vec3f mAgentHalfExtents {29, 29, 66};
const TilePosition mPlayerTile {0, 0};
const std::string mWorldspace = "sys::default";
const btBoxShape mBox {btVector3(100, 100, 20)};
Loading::Listener mListener;
};
@ -111,6 +129,7 @@ namespace
{
mRecastMeshManager.setWorldspace(mWorldspace);
addHeightFieldPlane(mRecastMeshManager);
addObject(mBox, mRecastMeshManager);
auto db = std::make_unique<NavMeshDb>(":memory:");
NavMeshDb* const dbPtr = db.get();
AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, std::move(db));
@ -130,10 +149,11 @@ namespace
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);
addHeightFieldPlane(mRecastMeshManager);
addObject(mBox, mRecastMeshManager);
auto db = std::make_unique<NavMeshDb>(":memory:");
NavMeshDb* const dbPtr = db.get();
mSettings.mWriteToNavMeshDb = false;
@ -152,6 +172,27 @@ namespace
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)
{
mRecastMeshManager.setWorldspace(mWorldspace);

@ -89,7 +89,8 @@ namespace DetourNavigator
{
if (db == 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)
@ -704,11 +705,12 @@ namespace DetourNavigator
}
DbWorker::DbWorker(AsyncNavMeshUpdater& updater, std::unique_ptr<NavMeshDb>&& db,
TileVersion version, const RecastSettings& recastSettings)
TileVersion version, const RecastSettings& recastSettings, bool writeToDb)
: mUpdater(updater)
, mRecastSettings(recastSettings)
, mDb(std::move(db))
, mVersion(version)
, mWriteToDb(writeToDb)
, mNextTileId(mDb->getMaxTileId() + 1)
, mNextShapeId(mDb->getMaxShapeId() + 1)
, mThread([this] { run(); })
@ -799,12 +801,23 @@ namespace DetourNavigator
if (job->mInput.empty())
{
Log(Debug::Debug) << "Serializing input for job " << job->mId;
const ShapeId shapeId = mNextShapeId;
const std::vector<DbRefGeometryObject> objects = makeDbRefGeometryObjects(job->mRecastMesh->getMeshSources(),
[&] (const MeshSource& v) { return resolveMeshSource(*mDb, v, mNextShapeId); });
if (shapeId != mNextShapeId)
++mWrites;
job->mInput = serialize(mRecastSettings, *job->mRecastMesh, objects);
if (mWriteToDb)
{
const ShapeId shapeId = mNextShapeId;
const auto objects = makeDbRefGeometryObjects(job->mRecastMesh->getMeshSources(),
[&] (const MeshSource& v) { return resolveMeshSource(*mDb, v, mNextShapeId); });
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);

@ -136,7 +136,7 @@ namespace DetourNavigator
};
DbWorker(AsyncNavMeshUpdater& updater, std::unique_ptr<NavMeshDb>&& db,
TileVersion version, const RecastSettings& recastSettings);
TileVersion version, const RecastSettings& recastSettings, bool writeToDb);
~DbWorker();
@ -153,6 +153,7 @@ namespace DetourNavigator
const RecastSettings& mRecastSettings;
const std::unique_ptr<NavMeshDb> mDb;
const TileVersion mVersion;
const bool mWriteToDb;
TileId mNextTileId;
ShapeId mNextShapeId;
DbJobQueue mQueue;

@ -4,10 +4,14 @@
#include "objecttransform.hpp"
#include "recastmesh.hpp"
#include <components/misc/typetraits.hpp>
#include <algorithm>
#include <cstdint>
#include <tuple>
#include <vector>
#include <optional>
#include <type_traits>
namespace DetourNavigator
{
@ -28,16 +32,27 @@ namespace DetourNavigator
};
template <class ResolveMeshSource>
inline std::vector<DbRefGeometryObject> makeDbRefGeometryObjects(const std::vector<MeshSource>& meshSources,
ResolveMeshSource&& resolveMeshSource)
inline auto makeDbRefGeometryObjects(const std::vector<MeshSource>& meshSources, 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;
result.reserve(meshSources.size());
std::transform(meshSources.begin(), meshSources.end(), std::back_inserter(result),
[&] (const MeshSource& meshSource)
for (const MeshSource& meshSource : meshSources)
{
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());
return result;
}

@ -5,12 +5,21 @@
#include <components/debug/debuglog.hpp>
#include <cassert>
#include <optional>
namespace DetourNavigator
{
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())};
if (const auto existingShapeId = db.findShapeId(name, type, hashData))
@ -37,4 +46,18 @@ namespace DetourNavigator
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 <optional>
namespace DetourNavigator
{
struct MeshSource;
ShapeId resolveMeshSource(NavMeshDb& db, const MeshSource& source, ShapeId& nextShapeId);
std::optional<ShapeId> resolveMeshSource(NavMeshDb& db, const MeshSource& source);
}
#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