Download

How to create and enable/disable offmeshlink (navlink) from code

I’m trying to build a actor representing door generating at runtime.
Door has two states, open & close - just visual models are different, collision model for navmesh is the same (there is no navmesh under the door)
I want to create offmesh link to allow my agent to pathfind (and traverse) through this gap.

Here is the code:



m_OffMeshLink = GetWorld()->SpawnActor<ANavLinkProxy>();
m_OffMeshLink->AttachRootComponentToActor(this);
m_OffMeshLink->SetActorRotation(GetActorRotation());
m_OffMeshLink->SetActorLocation(GetActorLocation());

UNavigationSystem* NavSys = UNavigationSystem::GetCurrent(GetWorld()); //not nullptr
NavSys->RegisterCustomLink(*m_OffMeshLink->GetSmartLinkComp());

m_OffMeshLink->SetSmartLinkEnabled(false);


by default, navigation link should be disabled, bud pathfinding still use it.

I think this should be handled in



dtNavMeshQuery::passLinkFilter


but within this function
a) isLinkAllowed return always true
b) userId is always 0
so filter allows traversal of the link

(user id is 0 from NavLinkProxy constructor through all building process and there is no way to provide custom userId other than changing the engine code)

I think I’m doing something wrong.
What is the correct way to create off mesh link from c++ and be able to disable/enable it?

Version: 4.12.5

Can someone please take a look at that? Thank you

This stuff is pretty confusingly set up I think. Essentially an ANavLinkProxy has both regular links and a smart link, and it’s not entirely obvious when one or the other is active. I’m far from sure but here’s some suggestions:

Set the following, it is distinct from SetSmartLinkEnabled:


m_OffMeshLink->bSmartLinkIsRelevant = true;

May also be worth doing this, as a default (non-smart) point link is created by ANavLinkProxy:


m_OffMeshLink->PointLinks.Empty();

You shouldn’t really need to call RegisterCustomLink yourself, since the component inside the ANavLinkProxy calls it in its OnRegister method. Problem is this stuff is super sensitive to the order in which things are called in my experience. Ideally you want to make the above adjustments before the component gets registered. I think the cleanest way would be to use SpawnActorDeferred, make the above changes, then call UGameplayStatics::FinishSpawningActor.