diff --git a/apps/navmeshtool/main.cpp b/apps/navmeshtool/main.cpp index e024a35530..58b7ca4847 100644 --- a/apps/navmeshtool/main.cpp +++ b/apps/navmeshtool/main.cpp @@ -171,8 +171,9 @@ namespace NavMeshTool const osg::Vec3f agentHalfExtents = Settings::Manager::getVector3("default actor pathfind half extents", "Game"); const std::uint64_t maxDbFileSize = static_cast(Settings::Manager::getInt64("max navmeshdb file size", "Navigator")); + const std::string dbPath = (config.getUserDataPath() / "navmesh.db").string(); - DetourNavigator::NavMeshDb db((config.getUserDataPath() / "navmesh.db").string(), maxDbFileSize); + DetourNavigator::NavMeshDb db(dbPath, maxDbFileSize); std::vector readers(contentFiles.size()); EsmLoader::Query query; @@ -196,10 +197,24 @@ namespace NavMeshTool WorldspaceData cellsData = gatherWorldspaceData(navigatorSettings, readers, vfs, bulletShapeManager, esmData, processInteriorCells, writeBinaryLog); - generateAllNavMeshTiles(agentHalfExtents, navigatorSettings, threadsNumber, removeUnusedTiles, - writeBinaryLog, cellsData, std::move(db)); + const Status status = generateAllNavMeshTiles(agentHalfExtents, navigatorSettings, threadsNumber, + removeUnusedTiles, writeBinaryLog, cellsData, std::move(db)); - Log(Debug::Info) << "Done"; + switch (status) + { + case Status::Ok: + Log(Debug::Info) << "Done"; + break; + case Status::Cancelled: + Log(Debug::Warning) << "Cancelled"; + break; + case Status::NotEnoughSpace: + Log(Debug::Warning) << "Navmesh genration is cancelled due to running out of disk space or limits " + << "for navmesh db. Check disk space at the db location \"" << dbPath + << "\". If there is enough space, adjust \"max navmeshdb file size\" setting (see " + << "https://openmw.readthedocs.io/en/latest/reference/modding/settings/navigator.html?highlight=navmesh#max-navmeshdb-file-size)."; + break; + } return 0; } diff --git a/apps/navmeshtool/navmesh.cpp b/apps/navmeshtool/navmesh.cpp index 975f697a20..a51d0bbc81 100644 --- a/apps/navmeshtool/navmesh.cpp +++ b/apps/navmeshtool/navmesh.cpp @@ -169,19 +169,22 @@ namespace NavMeshTool report(); } - void cancel() override + void cancel(std::string_view reason) override { std::unique_lock lock(mMutex); - mCancelled = true; + if (reason.find("database or disk is full") != std::string_view::npos) + mStatus = Status::NotEnoughSpace; + else + mStatus = Status::Cancelled; mHasTile.notify_one(); } - bool wait() + Status wait() { constexpr std::chrono::seconds transactionInterval(1); std::unique_lock lock(mMutex); auto start = std::chrono::steady_clock::now(); - while (mProvided < mExpected && !mCancelled) + while (mProvided < mExpected && mStatus == Status::Ok) { mHasTile.wait(lock); const auto now = std::chrono::steady_clock::now(); @@ -195,7 +198,7 @@ namespace NavMeshTool logGeneratedTiles(mProvided, mExpected); if (mWriteBinaryLog) logGeneratedTilesMessage(mProvided); - return !mCancelled; + return mStatus; } void commit() @@ -224,7 +227,7 @@ namespace NavMeshTool std::atomic_size_t mInserted {0}; std::atomic_size_t mUpdated {0}; std::size_t mDeleted = 0; - bool mCancelled = false; + Status mStatus = Status::Ok; mutable std::mutex mMutex; NavMeshDb mDb; const bool mRemoveUnusedTiles; @@ -247,7 +250,7 @@ namespace NavMeshTool }; } - void generateAllNavMeshTiles(const osg::Vec3f& agentHalfExtents, const Settings& settings, + Status generateAllNavMeshTiles(const osg::Vec3f& agentHalfExtents, const Settings& settings, std::size_t threadsNumber, bool removeUnusedTiles, bool writeBinaryLog, WorldspaceData& data, NavMeshDb&& db) { @@ -294,7 +297,8 @@ namespace NavMeshTool )); } - if (navMeshTileConsumer->wait()) + const Status status = navMeshTileConsumer->wait(); + if (status == Status::Ok) navMeshTileConsumer->commit(); const auto inserted = navMeshTileConsumer->getInserted(); @@ -311,5 +315,7 @@ namespace NavMeshTool Log(Debug::Info) << "Vacuuming the database..."; navMeshTileConsumer->vacuum(); } + + return status; } } diff --git a/apps/navmeshtool/navmesh.hpp b/apps/navmeshtool/navmesh.hpp index e25f1dd845..fa340b5de7 100644 --- a/apps/navmeshtool/navmesh.hpp +++ b/apps/navmeshtool/navmesh.hpp @@ -15,7 +15,14 @@ namespace NavMeshTool { struct WorldspaceData; - void generateAllNavMeshTiles(const osg::Vec3f& agentHalfExtents, const DetourNavigator::Settings& settings, + enum class Status + { + Ok, + Cancelled, + NotEnoughSpace, + }; + + Status generateAllNavMeshTiles(const osg::Vec3f& agentHalfExtents, const DetourNavigator::Settings& settings, std::size_t threadsNumber, bool removeUnusedTiles, bool writeBinaryLog, WorldspaceData& cellsData, DetourNavigator::NavMeshDb&& db); } diff --git a/components/detournavigator/generatenavmeshtile.cpp b/components/detournavigator/generatenavmeshtile.cpp index a725c5bc23..3475b4ee8a 100644 --- a/components/detournavigator/generatenavmeshtile.cpp +++ b/components/detournavigator/generatenavmeshtile.cpp @@ -96,7 +96,7 @@ namespace DetourNavigator { Log(Debug::Warning) << "Failed to generate navmesh for worldspace \"" << mWorldspace << "\" tile " << mTilePosition << ": " << e.what(); - consumer->cancel(); + consumer->cancel(e.what()); } } } diff --git a/components/detournavigator/generatenavmeshtile.hpp b/components/detournavigator/generatenavmeshtile.hpp index 2cd669c8ec..ecdf1c8bc0 100644 --- a/components/detournavigator/generatenavmeshtile.hpp +++ b/components/detournavigator/generatenavmeshtile.hpp @@ -50,7 +50,7 @@ namespace DetourNavigator virtual void update(std::string_view worldspace, const TilePosition& tilePosition, std::int64_t tileId, std::int64_t version, PreparedNavMeshData& data) = 0; - virtual void cancel() = 0; + virtual void cancel(std::string_view reason) = 0; }; class GenerateNavMeshTile final : public SceneUtil::WorkItem