Non-deterministic navigation build on World Partition map with DynamicModifiersOnly

We’re encountering non-deterministic behavior during NavMesh generation on a World Partition map with the following setup:

  • Engine ~5.5.4
  • Map type: world partition, Runtime generation: dynamic modifiers only
  • Navigation built via commandlet or editor with ai.nav.bNavmeshAllowPartitionedBuildingFromEditor 1

Our map contains several types of static objects that act as obstacles. These are duplicated many times across the level, and we expect them to cut off navigation underneath. The two main object types currently under test are:

  • Static Mesh Actor
  • Blueprint-based actors with multiple components, including a Static Mesh Component

We’ve observed several inconsistent behaviors:

  • When building navigation in the editor using the old method for testing only, all objects in the loaded world partition area correctly cut off navigation.
  • When building via commandlet or with partitioned editor build (ai.nav.bNavmeshAllowPartitionedBuildingFromEditor=1), only some object instances cut off navigation - others do not.
  • InPIE, all tested instances currently cut off navigation correctly, but this wasn’t always the case - and the failing instances didn’t match those in the editor.
  • In cooked builds, only a few object copies cut off navigation, the rest do not.
  • When experimenting with various settings, navigation sometimes appeared current - but reverted to incorrect behavior after 1-3 builds
  • When navigation fails to cut properly, it doesn’t appear to be caused by missing collision data - I was able to log and debug-draw valid geometry for both working and non-working instances.
  • I’ve tested multiple settings across Static Mesh assets, blueprints, actor instances and project settings - but haven’t found a way to make the behavior deterministic.
  • In a quick test on a clean World Partition map, placing several copies of these objects resulted in correct navigation behavior across editor, PIE and cooked builds.

Questions:

1) What is the recommended way to set up a static obstacle that reliably cuts off navigation underneath (and ideally above, to prevent NPCs walking on it), in a World Partition map with partitioned nav build and Runtime Generation set to Dynamic Modifiers Only ? Ideally with minimal memory and performance impact.

2) Is it correct to disable “Gather Convex” in Static Mesh assets and use simple shapes (eg. box collisions) for navigation purposes ? (screen_00_A)

3) What may cause this non-deterministic behavior and how can it be prevented?

4) Are there any recommended cleanup steps before running the build commandlet - such as P4 revert, reconcile, clearing DDC, clearing saved or other ?

I was able to reproduce only part of the problem on clean 5.5.4 engine (project included).

There are multiple object copies with various setups. In general, Static Mesh Actor instances seem to consistently cut off navigation (but in our project this is not so obvious), while blueprint-based actors only do it sometimes. In our project, converting blueprint actors to static meshes didn’t fully resolve the issue.

Any insights or recommendations would be greatly appreciated.

Our build command:

%ENGINE_BIN_DIR%UnrealEditor.exe %UPROJECT% -run=WorldPartitionBuilderCommandlet "%MAP%" -AllowCommandletRendering -BaseDir="%ENGINE_BIN_DIR%" -Builder=WorldPartitionNavigationDataBuilder -log=WPNavigationBuilderLog.txt -SCCProvider=%SCCPRIVIDER% -ddc=noshared %OPTIONS%

Some values from nav setup:

Filed Tile Pool Size = 1
Tile Pool Size = 32769
Tile Size UU = 2584
Mav Mesh Resolution: Cell Size = 19, Cell Height = 32, Agent Max Step Height = 5
Agent Radius = 35
Agent Height = 144
Agent Max Slope = 55
Min Region Area = 0
Merge Region Size = 400
Max Simplification Error = 1,3
Simplification Elevation Ratio = 0
Force Rebuild on Load = false;
Runtime Generation = Dynamic Modifiers Only
Data Gathering Mode = Lazy
Supported Agents: 1 - Radius = 35, Height = 144, Step Height = -1

Steps to Reproduce

  • Open attached project
  • Load L_Test01 map
  • Build paths, observe correct navigation
  • Set ai.nav.bNavmeshAllowPartitionedBuildingFromEditor = 1
  • Build paths again, observe incorrect navigation
  • Repeat a few times: move any modifier and build paths until navigation changes to correct/incorrect

Screens:

  • screen_01_test_map - Build from editor (non partitioned)
  • screen_02_non_partitioned_build - Build with ai.nav.bNavmeshAllowPartitionedBuildingFromEditor 0
  • screen_03_partitioned_build - Build with ai.nav.bNavmeshAllowPartitionedBuildingFromEditor 1
  • screen_04_moved - Interestingly, moving a modifier and rebuilding navigation (twice) seems to restore correct behavior. Similarly, simply adding a Nav Modifier Component to any of these objects can also fix the issue — across editor, PIE, and cooked builds.
  • screen_05_moved_again - Moving and building additional 2..3 times. Editor, PIE, cook

In the attached project, it seems there is an issue where the BP created for the tables is causing an warning in the builder for an “Unknown actor base class”. So I believe something is not loading correctly for the BP in the commandlet. In your larger project, do you see any warnings in the WP navigation builder log for unknown actor base class? It seems that some times it fails to load the BP class.

I am working with some of my colleagues in the world building team about what is happening. Can you confirm if this warning happens in your other project? I want to make sure we tackle the correct issue and this is not a red herring in the repro project from conversions to get it running.

-James

Yes, it seems that in attached repro project there are warnings in log related to BP:

LogWorldPartition: Can't find class descriptor
LogWorldPartition: Warning: Unknown actor base class

I found they occur only when navigation is not cut properly under the objects. So in my case it seems quite random. Also when disabled partitioned building by ai.nav.bNavmeshAllowPartitionedBuildingFromEditor 0 they never occurred and navigation builds properly.

So I was experimenting a bit with waiting for loading stuff and it seems that it helped in partitioned build path and finally I found this: CL 39084383:

WorldPartitionBuilder.cpp (line: ~92)

// Wait for the asset registry to finish scanning
IAssetRegistry& AssetRegistry = FModuleManager::GetModuleChecked<FAssetRegistryModule>("AssetRegistry").Get();
AssetRegistry.WaitForCompletion();

This seems to permanently fix the problem in the partitioned build path in the attached project.

Unfortunately it turned out that this is not exactly the same case that occurs in our game.

(we have a few similar warnings, but on navigation irrelevant actors, not connected with the issue).

As a workaround for this and other problems we started experimenting with a custom navigation building commandlet. We load the whole world (as the world is extending this may not be an option later), build nav and save it into chunks.

From this time it seems that the reported problem does not occur (at least yet after a few builds).

Problem persists when using WorldPartitionNavigationDataBuilder - unfortunately I cannot reproduce it on a small test map or pure 5.5.4.

Beside that

Backing to questions from 1st post - 1, 2, 4 are actual.

Also extending the 1st question: which of the all possible options (to cut nav mesh under object - or ideally also above and in interior) will bake navigation hole into static navmesh and which will make something will be processed at runtime in our setup (dynamic modifiers only).

1) What is the recommended way to set up a static obstacle that reliably cuts off navigation underneath (and ideally above, to prevent NPCs walking on it), in a World Partition map with partitioned nav build and Runtime Generation set to Dynamic Modifiers Only ? Ideally with minimal memory and performance impact.

If you want to prevent navigation inside AND on top of a mesh, mark it as a dynamic obstacle. Even if it does not move in the world, mark it as an obstacle. Obstacles build faster than traditional geometry as they markup existing tiles. Our recommendation is to make as many meshes obstacles as possible for faster nav generation. How far does your mesh need to cut off navigation underneath of it?

2) Is it correct to disable “Gather Convex” in Static Mesh assets and use simple shapes (eg. box collisions) for navigation purposes ? (screen_00_A)

Yes. Simpler collision for navigation makes it generate faster. Use it everywhere possible. You can find more of our recommendations for navmesh generation speed here in our official docs.

3) What may cause this non-deterministic behavior and how can it be prevented?

I believe this is failing to load the class which then does not load the actor. This needs addressing, and your waiting for it to finish is likely the correct way to ensure that everything is loaded in the commandlet world. I have been speaking with some of our World Building team around this issue.

4) Are there any recommended cleanup steps before running the build commandlet - such as P4 revert, reconcile, clearing DDC, clearing saved or other ?

I do not believe we have any recommendations here. Are you running into issues with your workspace being out of sync with other parts? We are not using WP navmesh internally, and thus have little info to share on this.

-James

Thanks for the answers.

Ad.1) Ok, since according to the doc, dynamic obstacle prevents full rebuild of the entire tile, it seems to be a great option for stuff like object #1 from screen (and many others). We have some modifiers added/removed in runtime which currently triggers full tile rebuild. But also we have some meshes (like small to medium size rocks - npc should generally not walk on them) which are massively used in various rotations, height over terrain, etc., in some cases are mostly hidden underground like example shape on screen 2-4. In this case - not setting any flags results with navigation inside and on the top (#2), setting dynamic obstacle results in way too much cutting (#3), what we would need is something which work like hybrid of these two (#4). Is there any option to achieve it globally (eg. per asset?) and locally per actor on map (probably something like modifier volume but in shape of our object?)

[Image Removed] Just wondering - in context of question 3.

We do not have something in the engine that readily does what you would prefer. Nav Modifiers create rotated bounding boxes for the mesh which affect all of it above and below a surface. Which would cause cutouts marked with red similar to the 3. You can use the Rasterize as Filled Convex Volume which will prevent generating navmesh “inside” of the mesh, but it will still generate on top of any walkable area. The usual methods we use would be hand placing nav modifiers or blocking volumes for the affected areas.

I would try using Rasterize as Filled Convex Volume in conjunction with testing settings for Min Region Area to cut out small navmesh islands similar to what is on top of 2.

-James