FRecastNavMeshGenerator::Init() dirties all tiles in World Partition projects without Navigation Invokers (NavMesh Dynamic)

We want to use WPNavmesh in Dynamic Navmesh. Bake Navmesh and allow generation at some point when we want. But when i launch my package i see all the NavMesh I baked before gets rebuilt. I tried several things and when i put some breakpoints i found this :

In FRecastNavMeshGenerator::Init() (RecastNavMeshGenerator.cpp, around line 5519 (in ue5-main branch on github)

The code checks NavSys->IsActiveTilesGenerationEnabled() to decide whether to skip dirtying all navigation bounds. However, this function only checks bGenerateNavigationOnlyAroundNavigationInvokers and does not account for World Partition (bIsWorldPartitioned).

After searching i found this function :

IsUsingActiveTilesGeneration() which covers both cases (invokers OR World Partition).

As a result, in a World Partition project that does not enable Navigation Invokers, IsActiveTilesGenerationEnabled() returns false and the system marks all tiles as dirty at initialization, when i changed this from :

if (NavSys && NavSys->IsActiveTilesGenerationEnabled() == false)
{
	MarkNavBoundsDirty();
}

To :

if (NavSys && !DestNavMesh->IsUsingActiveTilesGeneration(*NavSys))
{
	MarkNavBoundsDirty();
}

With this change, the pre-built NavMesh data is preserved at initialization and dynamic NavMesh generation only occurs around active tiles.

Tested on UE 5.6.1, bug also visible in ue5-main branch.

[Attachment Removed]

Steps to Reproduce

Reproduction steps (based on our project setup, should be reproducible on any World Partition NavMesh project):

  1. Create a new project with World Partition enabled
  2. In Project Settings → Navigation Mesh, set Runtime Generation to Dynamic
  3. Make sure bGenerateNavigationOnlyAroundNavigationInvokers is disabled (default)
  4. Place a NavMeshBoundsVolume covering the playable area
  5. Use the command ai.nav.bNavmeshAllowPartitionedBuildingFromEditor 1
  6. Build Navigation (Build → Build Paths)
  7. Verify in editor that NavMesh is correctly baked with NavDataChunkActors
  8. Move NavDataChunkActors to a Runtime Partition Grid (so they stream with World Partition cells)
  9. Package the project in Development
  10. Launch the packaged build
  11. Observe that all previously baked NavMesh is rebuilt at initialization : MarkNavBoundsDirty() is called on all tiles because IsActiveTilesGenerationEnabled() returns false.
    [Attachment Removed]

Do you see the rebuild if the nav data chunk actors are left in the main grid after building WP navmesh? I think the issue arises from moving them out of that grid. If you debug inside of the Init function where it checks for DestNavMesh->HasValidNavmesh, are the data chunk actors spawned yet? Do you see anything printed in the logs for LogNavigation or LogNavigationDirtyArea?

-James

[Attachment Removed]

Sorry the tests took a while, but here is what I have

I did the test you wanted, and with the debugger I don’t go inside this :

if (Config.MaxPolysPerTile <= 0 && DestNavMesh->HasValidNavmesh())
{
	const dtNavMeshParams* SavedNavParams = DestNavMesh->GetRecastNavMeshImpl()->DetourNavMesh->getParams();
	if (SavedNavParams)
	{
		Config.MaxPolysPerTile = SavedNavParams->maxPolys;
	}
}

Config.MaxPolysPerTile = -1

For LogNavigation and LogNavigationDirtyArea i see no logs.

I tested it with my fix :

if (NavSys && !DestNavMesh->IsUsingActiveTilesGeneration(*NavSys))
{
	MarkNavBoundsDirty();
}

So the result is the same, i don’t have rebuild at init

[Attachment Removed]

I believe we have fixed this issue of the rebuild when PIE for dynamic WP navmesh. I am not seeing it using the latest on Main, but I am using the default setup which does not move the nav data chunks to a different grid. I believe there are a couple CLs you may need that fixed a race for registering nav data in the level. The two CLs are:

  • CL 51013969
    • Fix reentrance in RegisterNavData
  • CL 51174146
    • Don’t spawn missing navigation data that is already pending for registration

-James

[Attachment Removed]