Yes, this is was a temp class. I rebuilt it to be bit more usable since then:
//NavigationQuery.h
#pragma once
class ARecastNavMesh;
class FNavigationQuery
{
public:
static bool GetClosestLocationOnNavMesh(const UObject* Context, const FVector& Point, FVector& ClosestLocation, const FVector& Extents = FVector(2000, 2000, 2000));
static ARecastNavMesh* GetRecastNavMesh(UWorld* World);
};
//NavigationQuery.cpp
#include "NavigationQuery.h"
#include "NavigationSystem.h"
#include "NavMesh/RecastNavMesh.h"
/**
*
* @param Context - UObject of world where recast mesh is
* @param Point
* @param ClosestLocation
* @param Extents
* @return
*/
bool FNavigationQuery::GetClosestLocationOnNavMesh(const UObject* Context, const FVector& Point, FVector& ClosestLocation, const FVector& Extents)
{
UWorld* World = GEngine->GetWorldFromContextObject(Context, EGetWorldErrorMode::ReturnNull);
#if UE_EDITOR
if (World == nullptr)
{
//Debug::Print("World Context is null while getting closest location on nav mesh!");
ClosestLocation = Point;
return false;
}
#endif
const ARecastNavMesh* NavMesh = GetRecastNavMesh(World);
#if UE_EDITOR
if (NavMesh == nullptr)
{
//Debug::Print("NavMesh is null!");
ClosestLocation = Point;
return false;
}
#endif
const FBox Box = FBox::BuildAABB(Point, Extents);
TArray<FNavPoly> Polies;
NavMesh->GetPolysInBox(Box, Polies);
double ClosestLength = std::numeric_limits<double>::max();
NavNodeRef ClosestPolyRef = INVALID_NAVNODEREF;
for (int i = 0; i < Polies.Num(); i++)
{
const double LengthToPoly = (Polies[i].Center - Point).SquaredLength();
if (LengthToPoly < ClosestLength)
{
// find edges
TArray<FNavigationPortalEdge> Edges;
NavMesh->GetPolyNeighbors(Polies[i].Ref, Edges);
bool HasConnectingNeighbour = false;
for (int c = 0; c < Edges.Num(); c++)
{
if (Edges[c].ToRef != INVALID_NAVNODEREF)
{
HasConnectingNeighbour = true;
break;
}
}
if (HasConnectingNeighbour)
{
ClosestPolyRef = Polies[i].Ref;
ClosestLength = LengthToPoly;
}
}
}
/*NavNodeRef NodeRef = INVALID_NAVNODEREF;
for (int i = 0; i < 10; i++)
{
// TODO: use this for priority, so that actor doesn't get stuck on top of buildings or areas that aren't connect to anything.
//ANavigation::Instance()->RecastMesh->GetPolyNeighbors()
NodeRef = ANavigation::Instance()->RecastMesh->FindNearestPoly(Point, FVector(500 + i * 500, 500 + i * 500, 500 + i * 500));
if (NodeRef != INVALID_NAVNODEREF)
break;
TArray<FNavigationPortalEdge> Edges;
ANavigation::Instance()->RecastMesh->GetPolyNeighbors(NodeRef, Edges);
}
*/
if (ClosestPolyRef == INVALID_NAVNODEREF)
{
//Debug::Print("Unable to find location on navmesh for point: ", Point, Context);
ClosestLocation = Point;
return false;
}
NavMesh->GetClosestPointOnPoly(ClosestPolyRef, Point, ClosestLocation);
return true;
}
/**
*
* @param World
* @return
*/
ARecastNavMesh* FNavigationQuery::GetRecastNavMesh(UWorld* World)
{
UNavigationSystemV1* NavSystem = UNavigationSystemV1::GetNavigationSystem(World);
ARecastNavMesh* RecastMesh = Cast<ARecastNavMesh>(NavSystem->GetDefaultNavDataInstance(FNavigationSystem::ECreateIfEmpty::DontCreate));
return RecastMesh;
}