#include "generatenavmeshtile.hpp" #include "dbrefgeometryobject.hpp" #include "makenavmesh.hpp" #include "preparednavmeshdata.hpp" #include "serialization.hpp" #include "settings.hpp" #include #include #include #include #include #include #include namespace DetourNavigator { namespace { struct Ignore { ESM::RefId mWorldspace; const TilePosition& mTilePosition; std::shared_ptr mConsumer; ~Ignore() noexcept { if (mConsumer != nullptr) mConsumer->ignore(mWorldspace, mTilePosition); } }; } GenerateNavMeshTile::GenerateNavMeshTile(ESM::RefId worldspace, const TilePosition& tilePosition, RecastMeshProvider recastMeshProvider, const AgentBounds& agentBounds, const DetourNavigator::Settings& settings, std::weak_ptr consumer) : mWorldspace(worldspace) , mTilePosition(tilePosition) , mRecastMeshProvider(recastMeshProvider) , mAgentBounds(agentBounds) , mSettings(settings) , mConsumer(std::move(consumer)) { } void GenerateNavMeshTile::doWork() { impl(); } void GenerateNavMeshTile::impl() noexcept { const auto consumer = mConsumer.lock(); if (consumer == nullptr) return; try { Ignore ignore{ mWorldspace, mTilePosition, consumer }; const std::shared_ptr recastMesh = mRecastMeshProvider.getMesh(mWorldspace, mTilePosition); if (recastMesh == nullptr || isEmpty(*recastMesh)) return; const std::vector objects = makeDbRefGeometryObjects( recastMesh->getMeshSources(), [&](const MeshSource& v) { return consumer->resolveMeshSource(v); }); std::vector input = serialize(mSettings.mRecast, mAgentBounds, *recastMesh, objects); const std::optional info = consumer->find(mWorldspace, mTilePosition, input); if (info.has_value() && info->mVersion == navMeshFormatVersion) { consumer->identity(mWorldspace, mTilePosition, info->mTileId); ignore.mConsumer = nullptr; return; } const auto data = prepareNavMeshTileData(*recastMesh, mWorldspace, mTilePosition, mAgentBounds, mSettings.mRecast); if (data == nullptr) return; if (info.has_value()) consumer->update(mWorldspace, mTilePosition, info->mTileId, navMeshFormatVersion, *data); else consumer->insert(mWorldspace, mTilePosition, navMeshFormatVersion, input, *data); ignore.mConsumer = nullptr; } catch (const std::exception& e) { Log(Debug::Warning) << "Failed to generate navmesh for worldspace \"" << mWorldspace << "\" tile " << mTilePosition << ": " << e.what(); consumer->cancel(e.what()); } } }