You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw/components/detournavigator/generatenavmeshtile.cpp

102 lines
3.2 KiB
C++

#include "generatenavmeshtile.hpp"
#include "dbrefgeometryobject.hpp"
#include "makenavmesh.hpp"
#include "preparednavmeshdata.hpp"
#include "serialization.hpp"
#include "settings.hpp"
#include <components/debug/debuglog.hpp>
#include <osg/io_utils>
#include <functional>
#include <memory>
#include <optional>
#include <stdexcept>
#include <vector>
namespace DetourNavigator
{
namespace
{
struct Ignore
{
std::string_view mWorldspace;
const TilePosition& mTilePosition;
std::shared_ptr<NavMeshTileConsumer> mConsumer;
~Ignore() noexcept
{
if (mConsumer != nullptr)
mConsumer->ignore(mWorldspace, mTilePosition);
}
};
}
GenerateNavMeshTile::GenerateNavMeshTile(std::string worldspace, const TilePosition& tilePosition,
RecastMeshProvider recastMeshProvider, const AgentBounds& agentBounds,
const DetourNavigator::Settings& settings, std::weak_ptr<NavMeshTileConsumer> consumer)
: mWorldspace(std::move(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> recastMesh = mRecastMeshProvider.getMesh(mWorldspace, mTilePosition);
if (recastMesh == nullptr || isEmpty(*recastMesh))
return;
const std::vector<DbRefGeometryObject> objects = makeDbRefGeometryObjects(
recastMesh->getMeshSources(), [&](const MeshSource& v) { return consumer->resolveMeshSource(v); });
std::vector<std::byte> input = serialize(mSettings.mRecast, mAgentBounds, *recastMesh, objects);
const std::optional<NavMeshTileInfo> 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, 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());
}
}
}