From d6f3d34f2f75078d8b897a89484dc5fcbc1ea546 Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 6 Apr 2024 15:40:42 +0200 Subject: [PATCH] Remove tiles present on navmesh but outside desired area --- .../detournavigator/navigator.cpp | 90 +++++++++++++++++++ .../detournavigator/navmeshcacheitem.hpp | 9 ++ components/detournavigator/navmeshmanager.cpp | 8 +- 3 files changed, 104 insertions(+), 3 deletions(-) diff --git a/apps/openmw_test_suite/detournavigator/navigator.cpp b/apps/openmw_test_suite/detournavigator/navigator.cpp index b61a88662b..6dcade083a 100644 --- a/apps/openmw_test_suite/detournavigator/navigator.cpp +++ b/apps/openmw_test_suite/detournavigator/navigator.cpp @@ -1055,6 +1055,96 @@ namespace } } + TEST_P(DetourNavigatorUpdateTest, update_should_change_covered_area_when_player_moves_without_waiting_for_all) + { + Loading::Listener listener; + Settings settings = makeSettings(); + settings.mMaxTilesNumber = 1; + settings.mWaitUntilMinDistanceToPlayer = 1; + NavigatorImpl navigator(settings, nullptr); + const AgentBounds agentBounds{ CollisionShapeType::Aabb, { 29, 29, 66 } }; + ASSERT_TRUE(navigator.addAgent(agentBounds)); + + GetParam()(navigator); + + { + auto updateGuard = navigator.makeUpdateGuard(); + navigator.update(osg::Vec3f(3000, 3000, 0), updateGuard.get()); + } + + navigator.wait(WaitConditionType::requiredTilesPresent, &listener); + + { + const auto navMesh = navigator.getNavMesh(agentBounds); + ASSERT_NE(navMesh, nullptr); + + const TilePosition expectedTile(4, 4); + const auto usedTiles = getUsedTiles(*navMesh->lockConst()); + EXPECT_THAT(usedTiles, Contains(expectedTile)) << usedTiles; + } + + { + auto updateGuard = navigator.makeUpdateGuard(); + navigator.update(osg::Vec3f(6000, 3000, 0), updateGuard.get()); + } + + navigator.wait(WaitConditionType::requiredTilesPresent, &listener); + + { + const auto navMesh = navigator.getNavMesh(agentBounds); + ASSERT_NE(navMesh, nullptr); + + const TilePosition expectedTile(8, 4); + const auto usedTiles = getUsedTiles(*navMesh->lockConst()); + EXPECT_THAT(usedTiles, Contains(expectedTile)) << usedTiles; + } + } + + TEST_P(DetourNavigatorUpdateTest, update_should_change_covered_area_when_player_moves_with_db) + { + Loading::Listener listener; + Settings settings = makeSettings(); + settings.mMaxTilesNumber = 1; + settings.mWaitUntilMinDistanceToPlayer = 1; + NavigatorImpl navigator(settings, std::make_unique(":memory:", settings.mMaxDbFileSize)); + const AgentBounds agentBounds{ CollisionShapeType::Aabb, { 29, 29, 66 } }; + ASSERT_TRUE(navigator.addAgent(agentBounds)); + + GetParam()(navigator); + + { + auto updateGuard = navigator.makeUpdateGuard(); + navigator.update(osg::Vec3f(3000, 3000, 0), updateGuard.get()); + } + + navigator.wait(WaitConditionType::requiredTilesPresent, &listener); + + { + const auto navMesh = navigator.getNavMesh(agentBounds); + ASSERT_NE(navMesh, nullptr); + + const TilePosition expectedTile(4, 4); + const auto usedTiles = getUsedTiles(*navMesh->lockConst()); + EXPECT_THAT(usedTiles, Contains(expectedTile)) << usedTiles; + } + + { + auto updateGuard = navigator.makeUpdateGuard(); + navigator.update(osg::Vec3f(6000, 3000, 0), updateGuard.get()); + } + + navigator.wait(WaitConditionType::requiredTilesPresent, &listener); + + { + const auto navMesh = navigator.getNavMesh(agentBounds); + ASSERT_NE(navMesh, nullptr); + + const TilePosition expectedTile(8, 4); + const auto usedTiles = getUsedTiles(*navMesh->lockConst()); + EXPECT_THAT(usedTiles, Contains(expectedTile)) << usedTiles; + } + } + struct AddHeightfieldSurface { static constexpr std::size_t sSize = 65; diff --git a/components/detournavigator/navmeshcacheitem.hpp b/components/detournavigator/navmeshcacheitem.hpp index ec76b56a46..120a374195 100644 --- a/components/detournavigator/navmeshcacheitem.hpp +++ b/components/detournavigator/navmeshcacheitem.hpp @@ -131,6 +131,15 @@ namespace DetourNavigator function(position, tile.mVersion, *meshTile); } + template + void forEachTilePosition(Function&& function) const + { + for (const auto& [position, tile] : mUsedTiles) + function(position); + for (const TilePosition& position : mEmptyTiles) + function(position); + } + private: struct Tile { diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index e6f831bb6e..ea20f8bc34 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -13,8 +13,6 @@ #include -#include - namespace { /// Safely reset shared_ptr with definite underlying object destrutor call. @@ -179,9 +177,9 @@ namespace DetourNavigator { std::map tilesToPost = changedTiles; { + const int maxTiles = mSettings.mMaxTilesNumber; const auto locked = cached->lockConst(); const auto& navMesh = locked->getImpl(); - const int maxTiles = mSettings.mMaxTilesNumber; getTilesPositions(range, [&](const TilePosition& tile) { if (changedTiles.find(tile) != changedTiles.end()) return; @@ -192,6 +190,10 @@ namespace DetourNavigator else if (!shouldAdd && presentInNavMesh) tilesToPost.emplace(tile, ChangeType::mixed); }); + locked->forEachTilePosition([&](const TilePosition& tile) { + if (!shouldAddTile(tile, playerTile, maxTiles)) + tilesToPost.emplace(tile, ChangeType::remove); + }); } mAsyncNavMeshUpdater.post(agentBounds, cached, playerTile, mWorldspace, tilesToPost); Log(Debug::Debug) << "Cache update posted for agent=" << agentBounds << " playerTile=" << playerTile