mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-20 15:40:32 +00:00
Add navmeshtool flag to remove unused tiles from navmesh disk cache
* Remove tiles outside processing range. Useful when new content profile map has different bounds. * Remove ignored tiles. For a case when content profile maps have intersection but there is no more data for navmesh. * Remove older tiles at the same worldspace position. If navmesh tile data has changed with new content, the old ones unlikely to be used. * Vacuum the database when there are modifications. SQLite leaves empty pages in the file on database modification. Vacuum cleans up unused pages reducing the file size.
This commit is contained in:
parent
67741402b5
commit
ab1a6e034e
@ -83,6 +83,9 @@ namespace NavMeshTool
|
||||
|
||||
("process-interior-cells", bpo::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "build navmesh for interior cells")
|
||||
|
||||
("remove-unused-tiles", bpo::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "remove tiles from cache that will not be used with current content profile")
|
||||
;
|
||||
Files::ConfigurationManager::addCommonOptions(result);
|
||||
|
||||
@ -141,6 +144,7 @@ namespace NavMeshTool
|
||||
}
|
||||
|
||||
const bool processInteriorCells = variables["process-interior-cells"].as<bool>();
|
||||
const bool removeUnusedTiles = variables["remove-unused-tiles"].as<bool>();
|
||||
|
||||
Fallback::Map::init(variables["fallback"].as<Fallback::FallbackMap>().mMap);
|
||||
|
||||
@ -177,7 +181,8 @@ namespace NavMeshTool
|
||||
WorldspaceData cellsData = gatherWorldspaceData(navigatorSettings, readers, vfs, bulletShapeManager,
|
||||
esmData, processInteriorCells);
|
||||
|
||||
generateAllNavMeshTiles(agentHalfExtents, navigatorSettings, threadsNumber, cellsData, std::move(db));
|
||||
generateAllNavMeshTiles(agentHalfExtents, navigatorSettings, threadsNumber, removeUnusedTiles,
|
||||
cellsData, std::move(db));
|
||||
|
||||
Log(Debug::Info) << "Done";
|
||||
|
||||
|
@ -41,6 +41,7 @@ namespace NavMeshTool
|
||||
using DetourNavigator::TileId;
|
||||
using DetourNavigator::TilePosition;
|
||||
using DetourNavigator::TileVersion;
|
||||
using DetourNavigator::TilesPositionsRange;
|
||||
using Sqlite3::Transaction;
|
||||
|
||||
void logGeneratedTiles(std::size_t provided, std::size_t expected)
|
||||
@ -63,8 +64,9 @@ namespace NavMeshTool
|
||||
public:
|
||||
std::atomic_size_t mExpected {0};
|
||||
|
||||
explicit NavMeshTileConsumer(NavMeshDb&& db)
|
||||
explicit NavMeshTileConsumer(NavMeshDb&& db, bool removeUnusedTiles)
|
||||
: mDb(std::move(db))
|
||||
, mRemoveUnusedTiles(removeUnusedTiles)
|
||||
, mTransaction(mDb.startTransaction())
|
||||
, mNextTileId(mDb.getMaxTileId() + 1)
|
||||
, mNextShapeId(mDb.getMaxShapeId() + 1)
|
||||
@ -76,6 +78,12 @@ namespace NavMeshTool
|
||||
|
||||
std::size_t getUpdated() const { return mUpdated.load(); }
|
||||
|
||||
std::size_t getDeleted() const
|
||||
{
|
||||
const std::lock_guard lock(mMutex);
|
||||
return mDeleted;
|
||||
}
|
||||
|
||||
std::int64_t resolveMeshSource(const MeshSource& source) override
|
||||
{
|
||||
const std::lock_guard lock(mMutex);
|
||||
@ -97,11 +105,34 @@ namespace NavMeshTool
|
||||
return result;
|
||||
}
|
||||
|
||||
void ignore() override { report(); }
|
||||
|
||||
void insert(std::string_view worldspace, const TilePosition& tilePosition, std::int64_t version,
|
||||
const std::vector<std::byte>& input, PreparedNavMeshData& data) override
|
||||
void ignore(std::string_view worldspace, const TilePosition& tilePosition) override
|
||||
{
|
||||
if (mRemoveUnusedTiles)
|
||||
{
|
||||
std::lock_guard lock(mMutex);
|
||||
mDeleted += static_cast<std::size_t>(mDb.deleteTilesAt(worldspace, tilePosition));
|
||||
}
|
||||
report();
|
||||
}
|
||||
|
||||
void identity(std::string_view worldspace, const TilePosition& tilePosition, std::int64_t tileId) override
|
||||
{
|
||||
if (mRemoveUnusedTiles)
|
||||
{
|
||||
std::lock_guard lock(mMutex);
|
||||
mDeleted += static_cast<std::size_t>(mDb.deleteTilesAtExcept(worldspace, tilePosition, TileId {tileId}));
|
||||
}
|
||||
report();
|
||||
}
|
||||
|
||||
void insert(std::string_view worldspace, const TilePosition& tilePosition,
|
||||
std::int64_t version, const std::vector<std::byte>& input, PreparedNavMeshData& data) override
|
||||
{
|
||||
if (mRemoveUnusedTiles)
|
||||
{
|
||||
std::lock_guard lock(mMutex);
|
||||
mDeleted += static_cast<std::size_t>(mDb.deleteTilesAt(worldspace, tilePosition));
|
||||
}
|
||||
data.mUserId = static_cast<unsigned>(mNextTileId);
|
||||
{
|
||||
std::lock_guard lock(mMutex);
|
||||
@ -112,11 +143,14 @@ namespace NavMeshTool
|
||||
report();
|
||||
}
|
||||
|
||||
void update(std::int64_t tileId, std::int64_t version, PreparedNavMeshData& data) override
|
||||
void update(std::string_view worldspace, const TilePosition& tilePosition,
|
||||
std::int64_t tileId, std::int64_t version, PreparedNavMeshData& data) override
|
||||
{
|
||||
data.mUserId = static_cast<unsigned>(tileId);
|
||||
{
|
||||
std::lock_guard lock(mMutex);
|
||||
if (mRemoveUnusedTiles)
|
||||
mDeleted += static_cast<std::size_t>(mDb.deleteTilesAtExcept(worldspace, tilePosition, TileId {tileId}));
|
||||
mDb.updateTile(TileId {tileId}, TileVersion {version}, serialize(data));
|
||||
}
|
||||
++mUpdated;
|
||||
@ -141,49 +175,66 @@ namespace NavMeshTool
|
||||
|
||||
void commit() { mTransaction.commit(); }
|
||||
|
||||
void vacuum() { mDb.vacuum(); }
|
||||
|
||||
void removeTilesOutsideRange(std::string_view worldspace, const TilesPositionsRange& range)
|
||||
{
|
||||
const std::lock_guard lock(mMutex);
|
||||
mTransaction.commit();
|
||||
Log(Debug::Info) << "Removing tiles outside processed range for worldspace \"" << worldspace << "\"...";
|
||||
mDeleted += static_cast<std::size_t>(mDb.deleteTilesOutsideRange(worldspace, range));
|
||||
mTransaction = mDb.startTransaction();
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic_size_t mProvided {0};
|
||||
std::atomic_size_t mInserted {0};
|
||||
std::atomic_size_t mUpdated {0};
|
||||
std::mutex mMutex;
|
||||
std::size_t mDeleted = 0;
|
||||
mutable std::mutex mMutex;
|
||||
NavMeshDb mDb;
|
||||
const bool mRemoveUnusedTiles;
|
||||
Transaction mTransaction;
|
||||
TileId mNextTileId;
|
||||
std::condition_variable mHasTile;
|
||||
Misc::ProgressReporter<LogGeneratedTiles> mReporter;
|
||||
ShapeId mNextShapeId;
|
||||
std::mutex mReportMutex;
|
||||
|
||||
void report()
|
||||
{
|
||||
mReporter(mProvided + 1, mExpected);
|
||||
++mProvided;
|
||||
const std::size_t provided = mProvided.fetch_add(1, std::memory_order_relaxed) + 1;
|
||||
mReporter(provided, mExpected);
|
||||
mHasTile.notify_one();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void generateAllNavMeshTiles(const osg::Vec3f& agentHalfExtents, const Settings& settings,
|
||||
const std::size_t threadsNumber, WorldspaceData& data, NavMeshDb&& db)
|
||||
std::size_t threadsNumber, bool removeUnusedTiles, WorldspaceData& data, NavMeshDb&& db)
|
||||
{
|
||||
Log(Debug::Info) << "Generating navmesh tiles by " << threadsNumber << " parallel workers...";
|
||||
|
||||
SceneUtil::WorkQueue workQueue(threadsNumber);
|
||||
auto navMeshTileConsumer = std::make_shared<NavMeshTileConsumer>(std::move(db));
|
||||
auto navMeshTileConsumer = std::make_shared<NavMeshTileConsumer>(std::move(db), removeUnusedTiles);
|
||||
std::size_t tiles = 0;
|
||||
std::mt19937_64 random;
|
||||
|
||||
for (const std::unique_ptr<WorldspaceNavMeshInput>& input : data.mNavMeshInputs)
|
||||
{
|
||||
const auto range = DetourNavigator::makeTilesPositionsRange(
|
||||
Misc::Convert::toOsgXY(input->mAabb.m_min),
|
||||
Misc::Convert::toOsgXY(input->mAabb.m_max),
|
||||
settings.mRecast
|
||||
);
|
||||
|
||||
if (removeUnusedTiles)
|
||||
navMeshTileConsumer->removeTilesOutsideRange(input->mWorldspace, range);
|
||||
|
||||
std::vector<TilePosition> worldspaceTiles;
|
||||
|
||||
DetourNavigator::getTilesPositions(
|
||||
DetourNavigator::makeTilesPositionsRange(
|
||||
Misc::Convert::toOsgXY(input->mAabb.m_min),
|
||||
Misc::Convert::toOsgXY(input->mAabb.m_max),
|
||||
settings.mRecast
|
||||
),
|
||||
[&] (const TilePosition& tilePosition) { worldspaceTiles.push_back(tilePosition); }
|
||||
);
|
||||
DetourNavigator::getTilesPositions(range,
|
||||
[&] (const TilePosition& tilePosition) { worldspaceTiles.push_back(tilePosition); });
|
||||
|
||||
tiles += worldspaceTiles.size();
|
||||
|
||||
@ -205,8 +256,19 @@ namespace NavMeshTool
|
||||
navMeshTileConsumer->wait();
|
||||
navMeshTileConsumer->commit();
|
||||
|
||||
const auto inserted = navMeshTileConsumer->getInserted();
|
||||
const auto updated = navMeshTileConsumer->getUpdated();
|
||||
const auto deleted = navMeshTileConsumer->getDeleted();
|
||||
|
||||
Log(Debug::Info) << "Generated navmesh for " << navMeshTileConsumer->getProvided() << " tiles, "
|
||||
<< navMeshTileConsumer->getInserted() << " are inserted and "
|
||||
<< navMeshTileConsumer->getUpdated() << " updated";
|
||||
<< inserted << " are inserted, "
|
||||
<< updated << " updated and "
|
||||
<< deleted << " deleted";
|
||||
|
||||
if (inserted + updated + deleted > 0)
|
||||
{
|
||||
Log(Debug::Info) << "Vacuuming the database...";
|
||||
navMeshTileConsumer->vacuum();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,8 @@ namespace NavMeshTool
|
||||
struct WorldspaceData;
|
||||
|
||||
void generateAllNavMeshTiles(const osg::Vec3f& agentHalfExtents, const DetourNavigator::Settings& settings,
|
||||
const std::size_t threadsNumber, WorldspaceData& cellsData, DetourNavigator::NavMeshDb&& db);
|
||||
std::size_t threadsNumber, bool removeUnusedTiles, WorldspaceData& cellsData,
|
||||
DetourNavigator::NavMeshDb&& db);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -109,4 +109,61 @@ namespace
|
||||
EXPECT_THROW(mDb.insertTile(tileId, worldspace, tilePosition, version, input, data), std::runtime_error);
|
||||
EXPECT_NO_THROW(insertTile(TileId {54}, version));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshDbTest, delete_tiles_at_should_remove_all_tiles_with_given_worldspace_and_position)
|
||||
{
|
||||
const TileVersion version {1};
|
||||
const std::string worldspace = "sys::default";
|
||||
const TilePosition tilePosition {3, 4};
|
||||
const std::vector<std::byte> input1 = generateData();
|
||||
const std::vector<std::byte> input2 = generateData();
|
||||
const std::vector<std::byte> data = generateData();
|
||||
ASSERT_EQ(mDb.insertTile(TileId {53}, worldspace, tilePosition, version, input1, data), 1);
|
||||
ASSERT_EQ(mDb.insertTile(TileId {54}, worldspace, tilePosition, version, input2, data), 1);
|
||||
ASSERT_EQ(mDb.deleteTilesAt(worldspace, tilePosition), 2);
|
||||
EXPECT_FALSE(mDb.findTile(worldspace, tilePosition, input1).has_value());
|
||||
EXPECT_FALSE(mDb.findTile(worldspace, tilePosition, input2).has_value());
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshDbTest, delete_tiles_at_except_should_leave_tile_with_given_id)
|
||||
{
|
||||
const TileId leftTileId {53};
|
||||
const TileId removedTileId {54};
|
||||
const TileVersion version {1};
|
||||
const std::string worldspace = "sys::default";
|
||||
const TilePosition tilePosition {3, 4};
|
||||
const std::vector<std::byte> leftInput = generateData();
|
||||
const std::vector<std::byte> removedInput = generateData();
|
||||
const std::vector<std::byte> data = generateData();
|
||||
ASSERT_EQ(mDb.insertTile(leftTileId, worldspace, tilePosition, version, leftInput, data), 1);
|
||||
ASSERT_EQ(mDb.insertTile(removedTileId, worldspace, tilePosition, version, removedInput, data), 1);
|
||||
ASSERT_EQ(mDb.deleteTilesAtExcept(worldspace, tilePosition, leftTileId), 1);
|
||||
const auto left = mDb.findTile(worldspace, tilePosition, leftInput);
|
||||
ASSERT_TRUE(left.has_value());
|
||||
EXPECT_EQ(left->mTileId, leftTileId);
|
||||
EXPECT_FALSE(mDb.findTile(worldspace, tilePosition, removedInput).has_value());
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshDbTest, delete_tiles_outside_range_should_leave_tiles_inside_given_rectangle)
|
||||
{
|
||||
TileId tileId {1};
|
||||
const TileVersion version {1};
|
||||
const std::string worldspace = "sys::default";
|
||||
const std::vector<std::byte> input = generateData();
|
||||
const std::vector<std::byte> data = generateData();
|
||||
for (int x = -2; x <= 2; ++x)
|
||||
{
|
||||
for (int y = -2; y <= 2; ++y)
|
||||
{
|
||||
ASSERT_EQ(mDb.insertTile(tileId, worldspace, TilePosition {x, y}, version, input, data), 1);
|
||||
++tileId.t;
|
||||
}
|
||||
}
|
||||
const TilesPositionsRange range {TilePosition {-1, -1}, TilePosition {2, 2}};
|
||||
ASSERT_EQ(mDb.deleteTilesOutsideRange(worldspace, range), 16);
|
||||
for (int x = -2; x <= 2; ++x)
|
||||
for (int y = -2; y <= 2; ++y)
|
||||
ASSERT_EQ(mDb.findTile(worldspace, TilePosition {x, y}, input).has_value(),
|
||||
-1 <= x && x <= 1 && -1 <= y && y <= 1) << "x=" << x << " y=" << y;
|
||||
}
|
||||
}
|
||||
|
@ -25,12 +25,14 @@ namespace DetourNavigator
|
||||
{
|
||||
struct Ignore
|
||||
{
|
||||
std::string_view mWorldspace;
|
||||
const TilePosition& mTilePosition;
|
||||
std::shared_ptr<NavMeshTileConsumer> mConsumer;
|
||||
|
||||
~Ignore() noexcept
|
||||
{
|
||||
if (mConsumer != nullptr)
|
||||
mConsumer->ignore();
|
||||
mConsumer->ignore(mWorldspace, mTilePosition);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -59,7 +61,7 @@ namespace DetourNavigator
|
||||
|
||||
try
|
||||
{
|
||||
Ignore ignore {consumer};
|
||||
Ignore ignore {mWorldspace, mTilePosition, consumer};
|
||||
|
||||
const std::shared_ptr<RecastMesh> recastMesh = mRecastMeshProvider.getMesh(mWorldspace, mTilePosition);
|
||||
|
||||
@ -72,7 +74,11 @@ namespace DetourNavigator
|
||||
const std::optional<NavMeshTileInfo> info = consumer->find(mWorldspace, mTilePosition, input);
|
||||
|
||||
if (info.has_value() && info->mVersion == mSettings.mNavMeshVersion)
|
||||
{
|
||||
consumer->identity(mWorldspace, mTilePosition, info->mTileId);
|
||||
ignore.mConsumer = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto data = prepareNavMeshTileData(*recastMesh, mTilePosition, mAgentHalfExtents, mSettings.mRecast);
|
||||
|
||||
@ -80,7 +86,7 @@ namespace DetourNavigator
|
||||
return;
|
||||
|
||||
if (info.has_value())
|
||||
consumer->update(info->mTileId, mSettings.mNavMeshVersion, *data);
|
||||
consumer->update(mWorldspace, mTilePosition, info->mTileId, mSettings.mNavMeshVersion, *data);
|
||||
else
|
||||
consumer->insert(mWorldspace, mTilePosition, mSettings.mNavMeshVersion, input, *data);
|
||||
|
||||
|
@ -39,12 +39,16 @@ namespace DetourNavigator
|
||||
virtual std::optional<NavMeshTileInfo> find(std::string_view worldspace, const TilePosition& tilePosition,
|
||||
const std::vector<std::byte>& input) = 0;
|
||||
|
||||
virtual void ignore() = 0;
|
||||
virtual void ignore(std::string_view worldspace, const TilePosition& tilePosition) = 0;
|
||||
|
||||
virtual void identity(std::string_view worldspace, const TilePosition& tilePosition,
|
||||
std::int64_t tileId) = 0;
|
||||
|
||||
virtual void insert(std::string_view worldspace, const TilePosition& tilePosition,
|
||||
std::int64_t version, const std::vector<std::byte>& input, PreparedNavMeshData& data) = 0;
|
||||
|
||||
virtual void update(std::int64_t tileId, std::int64_t version, PreparedNavMeshData& data) = 0;
|
||||
virtual void update(std::string_view worldspace, const TilePosition& tilePosition,
|
||||
std::int64_t tileId, std::int64_t version, PreparedNavMeshData& data) = 0;
|
||||
};
|
||||
|
||||
class GenerateNavMeshTile final : public SceneUtil::WorkItem
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "tilebounds.hpp"
|
||||
#include "tileposition.hpp"
|
||||
#include "tilespositionsrange.hpp"
|
||||
|
||||
class btVector3;
|
||||
class btTransform;
|
||||
@ -17,12 +18,6 @@ namespace DetourNavigator
|
||||
{
|
||||
struct RecastSettings;
|
||||
|
||||
struct TilesPositionsRange
|
||||
{
|
||||
TilePosition mBegin;
|
||||
TilePosition mEnd;
|
||||
};
|
||||
|
||||
TilesPositionsRange makeTilesPositionsRange(const osg::Vec2f& aabbMin,
|
||||
const osg::Vec2f& aabbMax, const RecastSettings& settings);
|
||||
|
||||
|
@ -34,6 +34,9 @@ namespace DetourNavigator
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS index_unique_tiles_by_worldspace_and_tile_position_and_input
|
||||
ON tiles (worldspace, tile_position_x, tile_position_y, input);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS index_tiles_by_worldspace_and_tile_position
|
||||
ON tiles (worldspace, tile_position_x, tile_position_y);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS shapes (
|
||||
shape_id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
@ -82,6 +85,31 @@ namespace DetourNavigator
|
||||
WHERE tile_id = :tile_id
|
||||
)";
|
||||
|
||||
constexpr std::string_view deleteTilesAtQuery = R"(
|
||||
DELETE FROM tiles
|
||||
WHERE worldspace = :worldspace
|
||||
AND tile_position_x = :tile_position_x
|
||||
AND tile_position_y = :tile_position_y
|
||||
)";
|
||||
|
||||
constexpr std::string_view deleteTilesAtExceptQuery = R"(
|
||||
DELETE FROM tiles
|
||||
WHERE worldspace = :worldspace
|
||||
AND tile_position_x = :tile_position_x
|
||||
AND tile_position_y = :tile_position_y
|
||||
AND tile_id != :exclude_tile_id
|
||||
)";
|
||||
|
||||
constexpr std::string_view deleteTilesOutsideRangeQuery = R"(
|
||||
DELETE FROM tiles
|
||||
WHERE worldspace = :worldspace
|
||||
AND ( tile_position_x < :begin_tile_position_x
|
||||
OR tile_position_y < :begin_tile_position_y
|
||||
OR tile_position_x >= :end_tile_position_x
|
||||
OR tile_position_y >= :end_tile_position_y
|
||||
)
|
||||
)";
|
||||
|
||||
constexpr std::string_view getMaxShapeIdQuery = R"(
|
||||
SELECT max(shape_id) FROM shapes
|
||||
)";
|
||||
@ -98,6 +126,10 @@ namespace DetourNavigator
|
||||
INSERT INTO shapes ( shape_id, name, type, hash)
|
||||
VALUES (:shape_id, :name, :type, :hash)
|
||||
)";
|
||||
|
||||
constexpr std::string_view vacuumQuery = R"(
|
||||
VACUUM;
|
||||
)";
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, ShapeType value)
|
||||
@ -117,9 +149,13 @@ namespace DetourNavigator
|
||||
, mGetTileData(*mDb, DbQueries::GetTileData {})
|
||||
, mInsertTile(*mDb, DbQueries::InsertTile {})
|
||||
, mUpdateTile(*mDb, DbQueries::UpdateTile {})
|
||||
, mDeleteTilesAt(*mDb, DbQueries::DeleteTilesAt {})
|
||||
, mDeleteTilesAtExcept(*mDb, DbQueries::DeleteTilesAtExcept {})
|
||||
, mDeleteTilesOutsideRange(*mDb, DbQueries::DeleteTilesOutsideRange {})
|
||||
, mGetMaxShapeId(*mDb, DbQueries::GetMaxShapeId {})
|
||||
, mFindShapeId(*mDb, DbQueries::FindShapeId {})
|
||||
, mInsertShape(*mDb, DbQueries::InsertShape {})
|
||||
, mVacuum(*mDb, DbQueries::Vacuum {})
|
||||
{
|
||||
}
|
||||
|
||||
@ -172,6 +208,21 @@ namespace DetourNavigator
|
||||
return execute(*mDb, mUpdateTile, tileId, version, compressedData);
|
||||
}
|
||||
|
||||
int NavMeshDb::deleteTilesAt(std::string_view worldspace, const TilePosition& tilePosition)
|
||||
{
|
||||
return execute(*mDb, mDeleteTilesAt, worldspace, tilePosition);
|
||||
}
|
||||
|
||||
int NavMeshDb::deleteTilesAtExcept(std::string_view worldspace, const TilePosition& tilePosition, TileId excludeTileId)
|
||||
{
|
||||
return execute(*mDb, mDeleteTilesAtExcept, worldspace, tilePosition, excludeTileId);
|
||||
}
|
||||
|
||||
int NavMeshDb::deleteTilesOutsideRange(std::string_view worldspace, const TilesPositionsRange& range)
|
||||
{
|
||||
return execute(*mDb, mDeleteTilesOutsideRange, worldspace, range);
|
||||
}
|
||||
|
||||
ShapeId NavMeshDb::getMaxShapeId()
|
||||
{
|
||||
ShapeId shapeId {0};
|
||||
@ -194,6 +245,11 @@ namespace DetourNavigator
|
||||
return execute(*mDb, mInsertShape, shapeId, name, type, hash);
|
||||
}
|
||||
|
||||
void NavMeshDb::vacuum()
|
||||
{
|
||||
execute(*mDb, mVacuum);
|
||||
}
|
||||
|
||||
namespace DbQueries
|
||||
{
|
||||
std::string_view GetMaxTileId::text() noexcept
|
||||
@ -260,6 +316,48 @@ namespace DetourNavigator
|
||||
Sqlite3::bindParameter(db, statement, ":data", data);
|
||||
}
|
||||
|
||||
std::string_view DeleteTilesAt::text() noexcept
|
||||
{
|
||||
return deleteTilesAtQuery;
|
||||
}
|
||||
|
||||
void DeleteTilesAt::bind(sqlite3& db, sqlite3_stmt& statement, std::string_view worldspace,
|
||||
const TilePosition& tilePosition)
|
||||
{
|
||||
Sqlite3::bindParameter(db, statement, ":worldspace", worldspace);
|
||||
Sqlite3::bindParameter(db, statement, ":tile_position_x", tilePosition.x());
|
||||
Sqlite3::bindParameter(db, statement, ":tile_position_y", tilePosition.y());
|
||||
}
|
||||
|
||||
std::string_view DeleteTilesAtExcept::text() noexcept
|
||||
{
|
||||
return deleteTilesAtExceptQuery;
|
||||
}
|
||||
|
||||
void DeleteTilesAtExcept::bind(sqlite3& db, sqlite3_stmt& statement, std::string_view worldspace,
|
||||
const TilePosition& tilePosition, TileId excludeTileId)
|
||||
{
|
||||
Sqlite3::bindParameter(db, statement, ":worldspace", worldspace);
|
||||
Sqlite3::bindParameter(db, statement, ":tile_position_x", tilePosition.x());
|
||||
Sqlite3::bindParameter(db, statement, ":tile_position_y", tilePosition.y());
|
||||
Sqlite3::bindParameter(db, statement, ":exclude_tile_id", excludeTileId);
|
||||
}
|
||||
|
||||
std::string_view DeleteTilesOutsideRange::text() noexcept
|
||||
{
|
||||
return deleteTilesOutsideRangeQuery;
|
||||
}
|
||||
|
||||
void DeleteTilesOutsideRange::bind(sqlite3& db, sqlite3_stmt& statement, std::string_view worldspace,
|
||||
const TilesPositionsRange& range)
|
||||
{
|
||||
Sqlite3::bindParameter(db, statement, ":worldspace", worldspace);
|
||||
Sqlite3::bindParameter(db, statement, ":begin_tile_position_x", range.mBegin.x());
|
||||
Sqlite3::bindParameter(db, statement, ":begin_tile_position_y", range.mBegin.y());
|
||||
Sqlite3::bindParameter(db, statement, ":end_tile_position_x", range.mEnd.x());
|
||||
Sqlite3::bindParameter(db, statement, ":end_tile_position_y", range.mEnd.y());
|
||||
}
|
||||
|
||||
std::string_view GetMaxShapeId::text() noexcept
|
||||
{
|
||||
return getMaxShapeIdQuery;
|
||||
@ -291,5 +389,10 @@ namespace DetourNavigator
|
||||
Sqlite3::bindParameter(db, statement, ":type", static_cast<int>(type));
|
||||
Sqlite3::bindParameter(db, statement, ":hash", hash);
|
||||
}
|
||||
|
||||
std::string_view Vacuum::text() noexcept
|
||||
{
|
||||
return vacuumQuery;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
#include "tileposition.hpp"
|
||||
|
||||
#include <components/detournavigator/tilespositionsrange.hpp>
|
||||
|
||||
#include <components/sqlite3/db.hpp>
|
||||
#include <components/sqlite3/statement.hpp>
|
||||
#include <components/sqlite3/transaction.hpp>
|
||||
@ -89,6 +91,27 @@ namespace DetourNavigator
|
||||
const std::vector<std::byte>& data);
|
||||
};
|
||||
|
||||
struct DeleteTilesAt
|
||||
{
|
||||
static std::string_view text() noexcept;
|
||||
static void bind(sqlite3& db, sqlite3_stmt& statement, std::string_view worldspace,
|
||||
const TilePosition& tilePosition);
|
||||
};
|
||||
|
||||
struct DeleteTilesAtExcept
|
||||
{
|
||||
static std::string_view text() noexcept;
|
||||
static void bind(sqlite3& db, sqlite3_stmt& statement, std::string_view worldspace,
|
||||
const TilePosition& tilePosition, TileId excludeTileId);
|
||||
};
|
||||
|
||||
struct DeleteTilesOutsideRange
|
||||
{
|
||||
static std::string_view text() noexcept;
|
||||
static void bind(sqlite3& db, sqlite3_stmt& statement, std::string_view worldspace,
|
||||
const TilesPositionsRange& range);
|
||||
};
|
||||
|
||||
struct GetMaxShapeId
|
||||
{
|
||||
static std::string_view text() noexcept;
|
||||
@ -108,6 +131,12 @@ namespace DetourNavigator
|
||||
static void bind(sqlite3& db, sqlite3_stmt& statement, ShapeId shapeId, std::string_view name,
|
||||
ShapeType type, const Sqlite3::ConstBlob& hash);
|
||||
};
|
||||
|
||||
struct Vacuum
|
||||
{
|
||||
static std::string_view text() noexcept;
|
||||
static void bind(sqlite3&, sqlite3_stmt&) {}
|
||||
};
|
||||
}
|
||||
|
||||
class NavMeshDb
|
||||
@ -130,12 +159,20 @@ namespace DetourNavigator
|
||||
|
||||
int updateTile(TileId tileId, TileVersion version, const std::vector<std::byte>& data);
|
||||
|
||||
int deleteTilesAt(std::string_view worldspace, const TilePosition& tilePosition);
|
||||
|
||||
int deleteTilesAtExcept(std::string_view worldspace, const TilePosition& tilePosition, TileId excludeTileId);
|
||||
|
||||
int deleteTilesOutsideRange(std::string_view worldspace, const TilesPositionsRange& range);
|
||||
|
||||
ShapeId getMaxShapeId();
|
||||
|
||||
std::optional<ShapeId> findShapeId(std::string_view name, ShapeType type, const Sqlite3::ConstBlob& hash);
|
||||
|
||||
int insertShape(ShapeId shapeId, std::string_view name, ShapeType type, const Sqlite3::ConstBlob& hash);
|
||||
|
||||
void vacuum();
|
||||
|
||||
private:
|
||||
Sqlite3::Db mDb;
|
||||
Sqlite3::Statement<DbQueries::GetMaxTileId> mGetMaxTileId;
|
||||
@ -143,9 +180,13 @@ namespace DetourNavigator
|
||||
Sqlite3::Statement<DbQueries::GetTileData> mGetTileData;
|
||||
Sqlite3::Statement<DbQueries::InsertTile> mInsertTile;
|
||||
Sqlite3::Statement<DbQueries::UpdateTile> mUpdateTile;
|
||||
Sqlite3::Statement<DbQueries::DeleteTilesAt> mDeleteTilesAt;
|
||||
Sqlite3::Statement<DbQueries::DeleteTilesAtExcept> mDeleteTilesAtExcept;
|
||||
Sqlite3::Statement<DbQueries::DeleteTilesOutsideRange> mDeleteTilesOutsideRange;
|
||||
Sqlite3::Statement<DbQueries::GetMaxShapeId> mGetMaxShapeId;
|
||||
Sqlite3::Statement<DbQueries::FindShapeId> mFindShapeId;
|
||||
Sqlite3::Statement<DbQueries::InsertShape> mInsertShape;
|
||||
Sqlite3::Statement<DbQueries::Vacuum> mVacuum;
|
||||
};
|
||||
}
|
||||
|
||||
|
15
components/detournavigator/tilespositionsrange.hpp
Normal file
15
components/detournavigator/tilespositionsrange.hpp
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_TILESPOSITIONSRANGE_H
|
||||
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_TILESPOSITIONSRANGE_H
|
||||
|
||||
#include "tileposition.hpp"
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
struct TilesPositionsRange
|
||||
{
|
||||
TilePosition mBegin;
|
||||
TilePosition mEnd;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user