Ok so after a few hours of poking around and thinking, I came up with a slightly different solution. Note that this is pretty advanced but if you’re at the point where you’re even considering sending pathfinding to background threads, I assume you can handle it. This solution begins from the assumption that RVO is of secondary importance to path finding, and blocks RVO if any async pathfinding is in progress.
Firstly, we create a child class of CrowdManager, override tick, create a boolean gate and an int that keeps track of async operations:
// MyCrowdManager.h
public:
static void SetAsyncInFlight(UWorld* World, bool bInFlight);
protected:
virtual void Tick(float DeltaTime) override;
bool bAsyncPathfindingInFlight;
int32 OperationsInProgress;
then we keep track of how many ongoing pathfinding requests are ongoing and only allow tick to fire if there are none:
// MyCrowdManager.cpp
void UMyCrowdManager::Tick(float DeltaTime)
{
if (!bAsyncPathfindingInFlight)
{
Super::Tick(DeltaTime);
}
}
void UMyCrowdManager::SetAsyncInFlight(UWorld* World, bool bInFlight)
{
if (auto* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(World))
{
if (auto* CM = Cast<UShoniCrowdManager>(NavSys->GetCrowdManager()))
{
CM->OperationsInProgress += (bInFlight ? 1 : -1);
CM->OperationsInProgress = FMath::Max(0, CM->OperationsInProgress);
CM->bAsyncPathfindingInFlight = (CM->OperationsInProgress > 0);
}
}
}
Then, once you’ve built your async MoveTo, just make sure you fire off SetAsyncInFlight (true) before calling the asyn pathfind and then again (false) when your bound delegate is fired.