1
0
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:
elsid 2022-02-18 21:35:09 +01:00
parent 67741402b5
commit ab1a6e034e
No known key found for this signature in database
GPG Key ID: B845CB9FEE18AB40
10 changed files with 323 additions and 34 deletions

View File

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

View File

@ -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();
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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