mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-30 09:15:38 +00:00
Merge branch 'fix_navigator_update' into 'master'
Fix navmesh update on player changing tile See merge request OpenMW/openmw!3756
This commit is contained in:
commit
c84386aa4b
7 changed files with 299 additions and 31 deletions
|
@ -1,3 +1,4 @@
|
|||
#include <components/detournavigator/debug.hpp>
|
||||
#include <components/detournavigator/gettilespositions.hpp>
|
||||
#include <components/detournavigator/settings.hpp>
|
||||
|
||||
|
@ -86,4 +87,79 @@ namespace
|
|||
|
||||
EXPECT_THAT(mTilesPositions, ElementsAre(TilePosition(0, 0)));
|
||||
}
|
||||
|
||||
struct TilesPositionsRangeParams
|
||||
{
|
||||
TilesPositionsRange mA;
|
||||
TilesPositionsRange mB;
|
||||
TilesPositionsRange mResult;
|
||||
};
|
||||
|
||||
struct DetourNavigatorGetIntersectionTest : TestWithParam<TilesPositionsRangeParams>
|
||||
{
|
||||
};
|
||||
|
||||
TEST_P(DetourNavigatorGetIntersectionTest, should_return_expected_result)
|
||||
{
|
||||
EXPECT_EQ(getIntersection(GetParam().mA, GetParam().mB), GetParam().mResult);
|
||||
EXPECT_EQ(getIntersection(GetParam().mB, GetParam().mA), GetParam().mResult);
|
||||
}
|
||||
|
||||
const TilesPositionsRangeParams getIntersectionParams[] = {
|
||||
{ .mA = TilesPositionsRange{}, .mB = TilesPositionsRange{}, .mResult = TilesPositionsRange{} },
|
||||
{
|
||||
.mA = TilesPositionsRange{ .mBegin = TilePosition{ 0, 0 }, .mEnd = TilePosition{ 2, 2 } },
|
||||
.mB = TilesPositionsRange{ .mBegin = TilePosition{ 1, 1 }, .mEnd = TilePosition{ 3, 3 } },
|
||||
.mResult = TilesPositionsRange{ .mBegin = TilePosition{ 1, 1 }, .mEnd = TilePosition{ 2, 2 } },
|
||||
},
|
||||
{
|
||||
.mA = TilesPositionsRange{ .mBegin = TilePosition{ 0, 0 }, .mEnd = TilePosition{ 1, 1 } },
|
||||
.mB = TilesPositionsRange{ .mBegin = TilePosition{ 2, 2 }, .mEnd = TilePosition{ 3, 3 } },
|
||||
.mResult = TilesPositionsRange{},
|
||||
},
|
||||
{
|
||||
.mA = TilesPositionsRange{ .mBegin = TilePosition{ 0, 0 }, .mEnd = TilePosition{ 1, 1 } },
|
||||
.mB = TilesPositionsRange{ .mBegin = TilePosition{ 1, 1 }, .mEnd = TilePosition{ 2, 2 } },
|
||||
.mResult = TilesPositionsRange{ .mBegin = TilePosition{ 1, 1 }, .mEnd = TilePosition{ 1, 1 } },
|
||||
},
|
||||
{
|
||||
.mA = TilesPositionsRange{ .mBegin = TilePosition{ 0, 0 }, .mEnd = TilePosition{ 1, 1 } },
|
||||
.mB = TilesPositionsRange{ .mBegin = TilePosition{ 0, 2 }, .mEnd = TilePosition{ 3, 3 } },
|
||||
.mResult = TilesPositionsRange{},
|
||||
},
|
||||
{
|
||||
.mA = TilesPositionsRange{ .mBegin = TilePosition{ 0, 0 }, .mEnd = TilePosition{ 1, 1 } },
|
||||
.mB = TilesPositionsRange{ .mBegin = TilePosition{ 2, 0 }, .mEnd = TilePosition{ 3, 3 } },
|
||||
.mResult = TilesPositionsRange{},
|
||||
},
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
GetIntersectionParams, DetourNavigatorGetIntersectionTest, ValuesIn(getIntersectionParams));
|
||||
|
||||
struct DetourNavigatorGetUnionTest : TestWithParam<TilesPositionsRangeParams>
|
||||
{
|
||||
};
|
||||
|
||||
TEST_P(DetourNavigatorGetUnionTest, should_return_expected_result)
|
||||
{
|
||||
EXPECT_EQ(getUnion(GetParam().mA, GetParam().mB), GetParam().mResult);
|
||||
EXPECT_EQ(getUnion(GetParam().mB, GetParam().mA), GetParam().mResult);
|
||||
}
|
||||
|
||||
const TilesPositionsRangeParams getUnionParams[] = {
|
||||
{ .mA = TilesPositionsRange{}, .mB = TilesPositionsRange{}, .mResult = TilesPositionsRange{} },
|
||||
{
|
||||
.mA = TilesPositionsRange{ .mBegin = TilePosition{ 0, 0 }, .mEnd = TilePosition{ 2, 2 } },
|
||||
.mB = TilesPositionsRange{ .mBegin = TilePosition{ 1, 1 }, .mEnd = TilePosition{ 3, 3 } },
|
||||
.mResult = TilesPositionsRange{ .mBegin = TilePosition{ 0, 0 }, .mEnd = TilePosition{ 3, 3 } },
|
||||
},
|
||||
{
|
||||
.mA = TilesPositionsRange{ .mBegin = TilePosition{ 0, 0 }, .mEnd = TilePosition{ 1, 1 } },
|
||||
.mB = TilesPositionsRange{ .mBegin = TilePosition{ 1, 1 }, .mEnd = TilePosition{ 2, 2 } },
|
||||
.mResult = TilesPositionsRange{ .mBegin = TilePosition{ 0, 0 }, .mEnd = TilePosition{ 2, 2 } },
|
||||
},
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(GetUnionParams, DetourNavigatorGetUnionTest, ValuesIn(getUnionParams));
|
||||
}
|
||||
|
|
|
@ -39,6 +39,8 @@ namespace
|
|||
using namespace DetourNavigator;
|
||||
using namespace DetourNavigator::Tests;
|
||||
|
||||
constexpr int heightfieldTileSize = ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1);
|
||||
|
||||
struct DetourNavigatorNavigatorTest : Test
|
||||
{
|
||||
Settings mSettings = makeSettings();
|
||||
|
@ -53,7 +55,6 @@ namespace
|
|||
AreaCosts mAreaCosts;
|
||||
Loading::Listener mListener;
|
||||
const osg::Vec2i mCellPosition{ 0, 0 };
|
||||
const int mHeightfieldTileSize = ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1);
|
||||
const float mEndTolerance = 0;
|
||||
const btTransform mTransform{ btMatrix3x3::getIdentity(), btVector3(256, 256, 0) };
|
||||
const ObjectTransform mObjectTransform{ ESM::Position{ { 256, 256, 0 }, { 0, 0, 0 } }, 0.0f };
|
||||
|
@ -129,7 +130,7 @@ namespace
|
|||
{
|
||||
}
|
||||
|
||||
T& shape() { return static_cast<T&>(*mInstance->mCollisionShape); }
|
||||
T& shape() const { return static_cast<T&>(*mInstance->mCollisionShape); }
|
||||
const osg::ref_ptr<const Resource::BulletShapeInstance>& instance() const { return mInstance; }
|
||||
|
||||
private:
|
||||
|
@ -167,7 +168,7 @@ namespace
|
|||
TEST_F(DetourNavigatorNavigatorTest, update_then_find_path_should_return_path)
|
||||
{
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(defaultHeightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const int cellSize = heightfieldTileSize * static_cast<int>(surface.mSize - 1);
|
||||
|
||||
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||
auto updateGuard = mNavigator->makeUpdateGuard();
|
||||
|
@ -189,7 +190,7 @@ namespace
|
|||
TEST_F(DetourNavigatorNavigatorTest, find_path_to_the_start_position_should_contain_single_point)
|
||||
{
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(defaultHeightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const int cellSize = heightfieldTileSize * static_cast<int>(surface.mSize - 1);
|
||||
|
||||
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||
auto updateGuard = mNavigator->makeUpdateGuard();
|
||||
|
@ -211,7 +212,7 @@ namespace
|
|||
mSettings, std::make_unique<NavMeshDb>(":memory:", std::numeric_limits<std::uint64_t>::max())));
|
||||
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(defaultHeightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const int cellSize = heightfieldTileSize * static_cast<int>(surface.mSize - 1);
|
||||
|
||||
CollisionShapeInstance compound(std::make_unique<btCompoundShape>());
|
||||
compound.shape().addChildShape(
|
||||
|
@ -256,7 +257,7 @@ namespace
|
|||
TEST_F(DetourNavigatorNavigatorTest, update_changed_object_should_change_navmesh)
|
||||
{
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(defaultHeightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const int cellSize = heightfieldTileSize * static_cast<int>(surface.mSize - 1);
|
||||
|
||||
CollisionShapeInstance compound(std::make_unique<btCompoundShape>());
|
||||
compound.shape().addChildShape(
|
||||
|
@ -335,7 +336,7 @@ namespace
|
|||
TEST_F(DetourNavigatorNavigatorTest, only_one_heightfield_per_cell_is_allowed)
|
||||
{
|
||||
const HeightfieldSurface surface1 = makeSquareHeightfieldSurface(defaultHeightfieldData);
|
||||
const int cellSize1 = mHeightfieldTileSize * (surface1.mSize - 1);
|
||||
const int cellSize1 = heightfieldTileSize * (surface1.mSize - 1);
|
||||
|
||||
const std::array<float, 5 * 5> heightfieldData2{ {
|
||||
-25, -25, -25, -25, -25, // row 0
|
||||
|
@ -345,7 +346,7 @@ namespace
|
|||
-25, -25, -25, -25, -25, // row 4
|
||||
} };
|
||||
const HeightfieldSurface surface2 = makeSquareHeightfieldSurface(heightfieldData2);
|
||||
const int cellSize2 = mHeightfieldTileSize * (surface2.mSize - 1);
|
||||
const int cellSize2 = heightfieldTileSize * (surface2.mSize - 1);
|
||||
|
||||
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize1, surface1, nullptr);
|
||||
|
@ -412,7 +413,7 @@ namespace
|
|||
0, -50, -100, -100, -100, // row 4
|
||||
} };
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const int cellSize = heightfieldTileSize * static_cast<int>(surface.mSize - 1);
|
||||
|
||||
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||
mNavigator->addWater(mCellPosition, cellSize, 300, nullptr);
|
||||
|
@ -446,7 +447,7 @@ namespace
|
|||
0, 0, 0, 0, 0, 0, 0, // row 6
|
||||
} };
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const int cellSize = heightfieldTileSize * static_cast<int>(surface.mSize - 1);
|
||||
|
||||
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||
mNavigator->addWater(mCellPosition, cellSize, -25, nullptr);
|
||||
|
@ -480,7 +481,7 @@ namespace
|
|||
0, 0, 0, 0, 0, 0, 0, // row 6
|
||||
} };
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const int cellSize = heightfieldTileSize * static_cast<int>(surface.mSize - 1);
|
||||
|
||||
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
||||
|
@ -513,7 +514,7 @@ namespace
|
|||
0, 0, 0, 0, 0, 0, 0, // row 6
|
||||
} };
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const int cellSize = heightfieldTileSize * static_cast<int>(surface.mSize - 1);
|
||||
|
||||
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||
mNavigator->addWater(mCellPosition, cellSize, -25, nullptr);
|
||||
|
@ -566,7 +567,7 @@ namespace
|
|||
TEST_F(DetourNavigatorNavigatorTest, update_heightfield_remove_and_update_then_find_path_should_return_path)
|
||||
{
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(defaultHeightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const int cellSize = heightfieldTileSize * static_cast<int>(surface.mSize - 1);
|
||||
|
||||
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
||||
|
@ -602,7 +603,7 @@ namespace
|
|||
0, -25, -100, -100, -100, -100, // row 5
|
||||
} };
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const int cellSize = heightfieldTileSize * static_cast<int>(surface.mSize - 1);
|
||||
|
||||
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
||||
|
@ -629,7 +630,7 @@ namespace
|
|||
mSettings, std::make_unique<NavMeshDb>(":memory:", std::numeric_limits<std::uint64_t>::max())));
|
||||
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(defaultHeightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const int cellSize = heightfieldTileSize * static_cast<int>(surface.mSize - 1);
|
||||
const btVector3 shift = getHeightfieldShift(mCellPosition, cellSize, surface.mMinHeight, surface.mMaxHeight);
|
||||
|
||||
std::vector<CollisionShapeInstance<btBoxShape>> boxes;
|
||||
|
@ -718,7 +719,7 @@ namespace
|
|||
TEST_F(DetourNavigatorNavigatorTest, update_then_raycast_should_return_position)
|
||||
{
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(defaultHeightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const int cellSize = heightfieldTileSize * static_cast<int>(surface.mSize - 1);
|
||||
|
||||
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
||||
|
@ -737,7 +738,7 @@ namespace
|
|||
update_for_oscillating_object_that_does_not_change_navmesh_should_not_trigger_navmesh_update)
|
||||
{
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(defaultHeightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const int cellSize = heightfieldTileSize * static_cast<int>(surface.mSize - 1);
|
||||
|
||||
CollisionShapeInstance oscillatingBox(std::make_unique<btBoxShape>(btVector3(20, 20, 20)));
|
||||
const btVector3 oscillatingBoxShapePosition(288, 288, 400);
|
||||
|
@ -777,7 +778,7 @@ namespace
|
|||
TEST_F(DetourNavigatorNavigatorTest, should_provide_path_over_flat_heightfield)
|
||||
{
|
||||
const HeightfieldPlane plane{ 100 };
|
||||
const int cellSize = mHeightfieldTileSize * 4;
|
||||
const int cellSize = heightfieldTileSize * 4;
|
||||
|
||||
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, plane, nullptr);
|
||||
|
@ -796,7 +797,7 @@ namespace
|
|||
TEST_F(DetourNavigatorNavigatorTest, for_not_reachable_destination_find_path_should_provide_partial_path)
|
||||
{
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(defaultHeightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const int cellSize = heightfieldTileSize * static_cast<int>(surface.mSize - 1);
|
||||
|
||||
CollisionShapeInstance compound(std::make_unique<btCompoundShape>());
|
||||
compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(204, -204, 0)),
|
||||
|
@ -822,7 +823,7 @@ namespace
|
|||
TEST_F(DetourNavigatorNavigatorTest, end_tolerance_should_extent_available_destinations)
|
||||
{
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(defaultHeightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const int cellSize = heightfieldTileSize * static_cast<int>(surface.mSize - 1);
|
||||
|
||||
CollisionShapeInstance compound(std::make_unique<btCompoundShape>());
|
||||
compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(204, -204, 0)),
|
||||
|
@ -948,7 +949,7 @@ namespace
|
|||
TEST_F(DetourNavigatorNavigatorTest, find_nearest_nav_mesh_position_should_return_nav_mesh_position)
|
||||
{
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(defaultHeightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const int cellSize = heightfieldTileSize * static_cast<int>(surface.mSize - 1);
|
||||
|
||||
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||
auto updateGuard = mNavigator->makeUpdateGuard();
|
||||
|
@ -966,7 +967,7 @@ namespace
|
|||
TEST_F(DetourNavigatorNavigatorTest, find_nearest_nav_mesh_position_should_return_nullopt_when_too_far)
|
||||
{
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(defaultHeightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const int cellSize = heightfieldTileSize * static_cast<int>(surface.mSize - 1);
|
||||
|
||||
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||
auto updateGuard = mNavigator->makeUpdateGuard();
|
||||
|
@ -984,7 +985,7 @@ namespace
|
|||
TEST_F(DetourNavigatorNavigatorTest, find_nearest_nav_mesh_position_should_return_nullopt_when_flags_do_not_match)
|
||||
{
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(defaultHeightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const int cellSize = heightfieldTileSize * static_cast<int>(surface.mSize - 1);
|
||||
|
||||
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||
auto updateGuard = mNavigator->makeUpdateGuard();
|
||||
|
@ -998,4 +999,142 @@ namespace
|
|||
EXPECT_EQ(findNearestNavMeshPosition(*mNavigator, mAgentBounds, position, searchAreaHalfExtents, Flag_swim),
|
||||
std::nullopt);
|
||||
}
|
||||
|
||||
struct DetourNavigatorUpdateTest : TestWithParam<std::function<void(Navigator&)>>
|
||||
{
|
||||
};
|
||||
|
||||
std::vector<TilePosition> getUsedTiles(const NavMeshCacheItem& navMesh)
|
||||
{
|
||||
std::vector<TilePosition> result;
|
||||
navMesh.forEachUsedTile([&](const TilePosition& position, const auto&...) { result.push_back(position); });
|
||||
return result;
|
||||
}
|
||||
|
||||
TEST_P(DetourNavigatorUpdateTest, update_should_change_covered_area_when_player_moves)
|
||||
{
|
||||
Loading::Listener listener;
|
||||
Settings settings = makeSettings();
|
||||
settings.mMaxTilesNumber = 5;
|
||||
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::allJobsDone, &listener);
|
||||
|
||||
{
|
||||
const auto navMesh = navigator.getNavMesh(agentBounds);
|
||||
ASSERT_NE(navMesh, nullptr);
|
||||
|
||||
const TilePosition expectedTiles[] = { { 3, 4 }, { 4, 3 }, { 4, 4 }, { 4, 5 }, { 5, 4 } };
|
||||
const auto usedTiles = getUsedTiles(*navMesh->lockConst());
|
||||
EXPECT_THAT(usedTiles, UnorderedElementsAreArray(expectedTiles)) << usedTiles;
|
||||
}
|
||||
|
||||
{
|
||||
auto updateGuard = navigator.makeUpdateGuard();
|
||||
navigator.update(osg::Vec3f(4000, 3000, 0), updateGuard.get());
|
||||
}
|
||||
|
||||
navigator.wait(WaitConditionType::allJobsDone, &listener);
|
||||
|
||||
{
|
||||
const auto navMesh = navigator.getNavMesh(agentBounds);
|
||||
ASSERT_NE(navMesh, nullptr);
|
||||
|
||||
const TilePosition expectedTiles[] = { { 4, 4 }, { 5, 3 }, { 5, 4 }, { 5, 5 }, { 6, 4 } };
|
||||
const auto usedTiles = getUsedTiles(*navMesh->lockConst());
|
||||
EXPECT_THAT(usedTiles, UnorderedElementsAreArray(expectedTiles)) << usedTiles;
|
||||
}
|
||||
}
|
||||
|
||||
struct AddHeightfieldSurface
|
||||
{
|
||||
static constexpr std::size_t sSize = 65;
|
||||
static constexpr float sHeights[sSize * sSize]{};
|
||||
|
||||
void operator()(Navigator& navigator) const
|
||||
{
|
||||
const osg::Vec2i cellPosition(0, 0);
|
||||
const HeightfieldSurface surface{
|
||||
.mHeights = sHeights,
|
||||
.mSize = sSize,
|
||||
.mMinHeight = -1,
|
||||
.mMaxHeight = 1,
|
||||
};
|
||||
const int cellSize = heightfieldTileSize * static_cast<int>(surface.mSize - 1);
|
||||
navigator.addHeightfield(cellPosition, cellSize, surface, nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
struct AddHeightfieldPlane
|
||||
{
|
||||
void operator()(Navigator& navigator) const
|
||||
{
|
||||
const osg::Vec2i cellPosition(0, 0);
|
||||
const HeightfieldPlane plane{ .mHeight = 0 };
|
||||
const int cellSize = 8192;
|
||||
navigator.addHeightfield(cellPosition, cellSize, plane, nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
struct AddWater
|
||||
{
|
||||
void operator()(Navigator& navigator) const
|
||||
{
|
||||
const osg::Vec2i cellPosition(0, 0);
|
||||
const float level = 0;
|
||||
const int cellSize = 8192;
|
||||
navigator.addWater(cellPosition, cellSize, level, nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
struct AddObject
|
||||
{
|
||||
const float mSize = 8192;
|
||||
CollisionShapeInstance<btBoxShape> mBox{ std::make_unique<btBoxShape>(btVector3(mSize, mSize, 1)) };
|
||||
const ObjectTransform mTransform{
|
||||
.mPosition = ESM::Position{ .pos = { 0, 0, 0 }, .rot{ 0, 0, 0 } },
|
||||
.mScale = 1.0f,
|
||||
};
|
||||
|
||||
void operator()(Navigator& navigator) const
|
||||
{
|
||||
navigator.addObject(ObjectId(&mBox.shape()), ObjectShapes(mBox.instance(), mTransform),
|
||||
btTransform::getIdentity(), nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
struct AddAll
|
||||
{
|
||||
AddHeightfieldSurface mAddHeightfieldSurface;
|
||||
AddHeightfieldPlane mAddHeightfieldPlane;
|
||||
AddWater mAddWater;
|
||||
AddObject mAddObject;
|
||||
|
||||
void operator()(Navigator& navigator) const
|
||||
{
|
||||
mAddHeightfieldSurface(navigator);
|
||||
mAddHeightfieldPlane(navigator);
|
||||
mAddWater(navigator);
|
||||
mAddObject(navigator);
|
||||
}
|
||||
};
|
||||
|
||||
const std::function<void(Navigator&)> addNavMeshData[] = {
|
||||
AddHeightfieldSurface{},
|
||||
AddHeightfieldPlane{},
|
||||
AddWater{},
|
||||
AddObject{},
|
||||
AddAll{},
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DifferentNavMeshData, DetourNavigatorUpdateTest, ValuesIn(addNavMeshData));
|
||||
}
|
||||
|
|
|
@ -42,12 +42,24 @@ namespace testing
|
|||
<< ", " << value.y() << ", " << value.z() << ')';
|
||||
}
|
||||
|
||||
template <>
|
||||
inline testing::Message& Message::operator<<(const osg::Vec2i& value)
|
||||
{
|
||||
return (*this) << "{" << value.x() << ", " << value.y() << '}';
|
||||
}
|
||||
|
||||
template <>
|
||||
inline testing::Message& Message::operator<<(const Wrapper<osg::Vec3f>& value)
|
||||
{
|
||||
return (*this) << value.mValue;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline testing::Message& Message::operator<<(const Wrapper<osg::Vec2i>& value)
|
||||
{
|
||||
return (*this) << value.mValue;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline testing::Message& Message::operator<<(const Wrapper<float>& value)
|
||||
{
|
||||
|
@ -72,6 +84,12 @@ namespace testing
|
|||
return writeRange(*this, value, 1);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline testing::Message& Message::operator<<(const std::vector<osg::Vec2i>& value)
|
||||
{
|
||||
return writeRange(*this, value, 1);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline testing::Message& Message::operator<<(const std::vector<float>& value)
|
||||
{
|
||||
|
|
|
@ -76,4 +76,13 @@ namespace DetourNavigator
|
|||
return {};
|
||||
return TilesPositionsRange{ TilePosition(beginX, beginY), TilePosition(endX, endY) };
|
||||
}
|
||||
|
||||
TilesPositionsRange getUnion(const TilesPositionsRange& a, const TilesPositionsRange& b) noexcept
|
||||
{
|
||||
const int beginX = std::min(a.mBegin.x(), b.mBegin.x());
|
||||
const int endX = std::max(a.mEnd.x(), b.mEnd.x());
|
||||
const int beginY = std::min(a.mBegin.y(), b.mBegin.y());
|
||||
const int endY = std::max(a.mEnd.y(), b.mEnd.y());
|
||||
return TilesPositionsRange{ .mBegin = TilePosition(beginX, beginY), .mEnd = TilePosition(endX, endY) };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,8 @@ namespace DetourNavigator
|
|||
}
|
||||
|
||||
TilesPositionsRange getIntersection(const TilesPositionsRange& a, const TilesPositionsRange& b) noexcept;
|
||||
|
||||
TilesPositionsRange getUnion(const TilesPositionsRange& a, const TilesPositionsRange& b) noexcept;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -166,6 +166,7 @@ namespace DetourNavigator
|
|||
return;
|
||||
mLastRecastMeshManagerRevision = mRecastMeshManager.getRevision();
|
||||
mPlayerTile = playerTile;
|
||||
mRecastMeshManager.setRange(makeRange(playerTile, mSettings.mMaxTilesNumber), guard);
|
||||
const auto changedTiles = mRecastMeshManager.takeChangedTiles(guard);
|
||||
const TilesPositionsRange range = mRecastMeshManager.getLimitedObjectsRange();
|
||||
for (const auto& [agentBounds, cached] : mCache)
|
||||
|
|
|
@ -54,6 +54,15 @@ namespace DetourNavigator
|
|||
private:
|
||||
const std::optional<std::unique_lock<Mutex>> mImpl;
|
||||
};
|
||||
|
||||
TilesPositionsRange getIndexRange(const auto& index)
|
||||
{
|
||||
const auto bounds = index.bounds();
|
||||
return TilesPositionsRange{
|
||||
.mBegin = makeTilePosition(bounds.min_corner()),
|
||||
.mEnd = makeTilePosition(bounds.max_corner()) + TilePosition(1, 1),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
TileCachedRecastMeshManager::TileCachedRecastMeshManager(const RecastSettings& settings)
|
||||
|
@ -104,14 +113,28 @@ namespace DetourNavigator
|
|||
|
||||
TilesPositionsRange TileCachedRecastMeshManager::getLimitedObjectsRange() const
|
||||
{
|
||||
if (mObjects.empty())
|
||||
return {};
|
||||
const auto bounds = mObjectIndex.bounds();
|
||||
const TilesPositionsRange objectsRange{
|
||||
.mBegin = makeTilePosition(bounds.min_corner()),
|
||||
.mEnd = makeTilePosition(bounds.max_corner()) + TilePosition(1, 1),
|
||||
};
|
||||
return getIntersection(mRange, objectsRange);
|
||||
std::optional<TilesPositionsRange> result;
|
||||
if (!mWater.empty())
|
||||
result = getIndexRange(mWaterIndex);
|
||||
if (!mHeightfields.empty())
|
||||
{
|
||||
const TilesPositionsRange range = getIndexRange(mHeightfieldIndex);
|
||||
if (result.has_value())
|
||||
result = getUnion(*result, range);
|
||||
else
|
||||
result = range;
|
||||
}
|
||||
if (!mObjects.empty())
|
||||
{
|
||||
const TilesPositionsRange range = getIndexRange(mObjectIndex);
|
||||
if (result.has_value())
|
||||
result = getUnion(*result, range);
|
||||
else
|
||||
result = range;
|
||||
}
|
||||
if (result.has_value())
|
||||
return getIntersection(mRange, *result);
|
||||
return {};
|
||||
}
|
||||
|
||||
void TileCachedRecastMeshManager::setWorldspace(std::string_view worldspace, const UpdateGuard* guard)
|
||||
|
|
Loading…
Reference in a new issue