[Recast NavMesh] Delegate FOnNavMeshUpdate does not seem to fire off ever for dynamic runtime updates

Dear Epic (and Miezsko),

I am really wanting to know when the nav mesh updates itself during runtime to respond to newly spawned level geometry.

My AI characters avoid newly created geometry beautifully (thank you!), since nav mesh generatoin is set to be fully dynamic in project settings.

However the delegate made available to find out when a Recast nav mesh updates does not seem to be firing off!

DECLARE_MULTICAST_DELEGATE(FOnNavMeshUpdate);

I am adding new UObject in Begin play, after waiting 0.3 seconds just to be sure.

UNavigationSystem* NavSys = GetWorld()->GetNavigationSystem();
if(!NavSys) return;

for (int32 Idx = 0; Idx < NavSys->NavDataSet.Num(); Idx++)
{
	ARecastNavMesh* EachRecast = Cast<ARecastNavMesh>(NavSys->NavDataSet[Idx]);
	if (EachRecast)
	{ 		
		EachRecast->OnNavMeshUpdate.AddUObject(this, &AJoyWorld::JoyNav_NavMeshUpdated);
		VSCREENMSG("Dynamic Added!");  
	} 
}

void AJoyWorld::JoyNav_NavMeshUpdated()
{
	VSCREENMSG("NAV MESH UPDATED WOOHOO!!!");
} 

#My test

My screen message fires off to tell me a delegate was added (only 1 for my test level, the Main Recast Nav Mesh)

During runtime I spawn new colliding geometry that I know is updating respective RecastNavmeshes because the AI avoids the new geometry and I also draw the polys of nav mesh and so I know they are reshaping just fine.

Yet that delegate is never firing off so I can’t easily know when to update my own internal structures after UE4 has finished.

#My Research For You

I have some good news!

I made my own UNavigationSystem subclass and can now capture updates!

But when I make a delegate in my custom subclass, the delegate does not fire even though it is bound, only the screen messages fires!

Conclusion: Somehow delegates not working properly in this particular class.

Enjoy!

/*
	By Rama
*/
#pragma once

#include "VictoryCore.h"

#include "JoyNavSys.generated.h"
 
/** Delegate to let interested parties know that Nav Data has been registered */
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FJoyNavSysUpdate);

UCLASS()
class UJoyNavSys : public UNavigationSystem
{
	GENERATED_BODY()
public:
	
	UPROPERTY(BlueprintAssignable, Transient)
	FJoyNavSysUpdate OnJoyNavSysUpdated;
	   
	virtual void Tick(float DeltaSeconds) override
	{
		//Check before all arrays emptied of pending updates
		bool PendingUpdate = PendingNavAreaRegistration.Num() > 0
											|| PendingNavBoundsUpdates.Num() > 0
											|| PendingOctreeUpdates.Num() > 0
											|| DirtyAreas.Num() > 0;
		//Super
		Super::Tick(DeltaSeconds);
		   
		//Broad Cast
		if(PendingUpdate && OnJoyNavSysUpdated.IsBound())  
		{ 
			VSCREENMSG("Joy Nav Sys Updated!"); //Works 
			OnJoyNavSysUpdated.Broadcast();	//doesnt fire even though bound!
		}
	}
};

#Thank You For UE4!

#:heart:

Rama

Hey Rama,

Thanks for pointing out. This is one piece of wrongly named and poorly commented variable, that’s what it is :confused:

I had to look at the code, since by the looks of it what you describe looks like a bug. But the thing is ARecastNavMesh::OnNavMeshUpdate gets triggered not on navmesh generation-related updates, but when ARecastNavMesh gets a new dtNavMesh instance. Terribly named delegate. I’ll file a ticket to get it renamed.

However, good news! Have you tried the UNavigationSystem::OnNavigationGenerationFinishedDelegate delegate? Should do exactly what you need :slight_smile:

Cheers,

–mieszko

Hi there! Thank you for the info!

Yes I actually tried OnNavigationGenerationFinishedDelegate first, and that did not work. But on that front, the good news I have for you is that I’ve tracked the issue to UNavigationSystem delegates not seeming to work properly, as I made a subclass of UNavigationSystem as explained above (code above) and that delegate simply would not fire no matter what I did.

I tried binding to OnNavigationGenerationFinishedDelegate in begin play after a 0.3 second delay and I just cannot get the delegate to fire :slight_smile:

#My Test Code

Here’s the test I am doing in a begin play that runs 0.3 seconds after regular begin play (just to be safe)

void AJoyWorld::BeginPlay_JoyNav()
{
	UNavigationSystem* NavSys = GetWorld()->GetNavigationSystem();
	if(NavSys)
	{
		NavSys->OnNavigationGenerationFinishedDelegate.AddDynamic(this,&AJoyWorld::JoyNav_UE4NavFinished);
	}
}  

void AJoyWorld::JoyNav_UE4NavFinished(ANavigationData* NavData)
{
	VSCREENMSG("OnNavigationGenerationFinishedDelegate Finished!");
}

I then try to add colliding geometry to the level as mentioned above, but this delegate does not ever seem to fire

Lovely to hear from you Miezsko!

#:heart:

Rama

Hey Rama,

I’m afraid I wasn’t able to repro this issue. OnNavigationGenerationFinishedDelegate fires just fine for me :confused: Can you try debugging it by placing a breakpoint in UNavigationSystem::OnNavigationGenerationFinished? And if that never gets triggered, can you look into ARecastNavMesh::OnNavMeshGenerationFinished to see what the execution never reached navigation system notification call?

Cheers,

–mieszko

Okay I will try that after upgrading to 4.9, thanks Mieszko!

#:heart:

Rama

#Problem Solved

I am happy to report I resolved this matter, sorry for the confusion Mieszko!

I did not make the delegate UFUNCTION() and did not see the ensuremsgf firing off.

Code sample for others

#.h
UFUNCTION() //<~~~~ I forgot this line
void JoyNav_UE4NavFinished(ANavigationData* NavData);

#.cpp

//... Begin Play
       UNavigationSystem* NavSys = GetWorld()->GetNavigationSystem();
	if(NavSys)
	{ 
		VSCREENMSG("delegate binded");
		NavSys->OnNavigationGenerationFinishedDelegate.AddDynamic(this,&AJoyWorld::JoyNav_UE4NavFinished);
	}
}  

//Because it was not UFUNCTION this was never getting bound and thus not firing
void AJoyWorld::JoyNav_UE4NavFinished(ANavigationData* NavData)
{
	VSCREENMSG("OnNavigationGenerationFinishedDelegate Finished!");
}

#Thank You For UE4 AI!

Thank you Mieszko for AI and nav meshes in UE4!

#:heart:

Rama

1 Like