Issues with Static NavMesh Generation on Overlapping Level Streaming Sublevels

Hi everyone,

We’re facing a challenge with NavMesh generation in a LevelStreaming setup, and I’d appreciate any input or guidance.

Context

Our project uses Level Streaming to split the world into modular sublevels. We also use a static RecastNavMesh. However, some sublevels are intentionally overlapping in world space — for example, different dungeon variants occupying the same coordinates and being loaded/unloaded at runtime depending on gameplay logic.

This leads to issues with NavMesh generation. Since Recast considers all geometry present in the world when generating the NavMesh, overlapping geometry results in invalid or broken navigation data in the overlapping zones.

Our Current Solution

We’ve built a workflow where each streaming sublevel is opened individually in the editor and we manually run BuildPaths. This generates a RecastNavMesh specific to that sublevel, as well as a corresponding RecastNavMeshChunk.

At runtime, the tiles from these NavMesh chunks are dynamically attached to or detached from the main RecastNavMesh on the PersistentLevel, depending on whether the corresponding sublevel is streamed in or out. This allows us to keep only the navigation data relevant to the currently loaded geometry active.

To support this, we had to:

  • Enable generation of a NavMesh chunk for the PersistentLevel when running BuildPaths from an opened streaming sublevel. By default, chunk generation didn’t work in that context.
  • Patch the engine to correctly handle AttachTiles and DetachTiles, so that tiles from the sublevel’s chunk can be dynamically added to or removed from the main RecastNavMesh at runtime.
  • Increase the internal REGISTRATION_QUEUE_SIZE to avoid runtime warnings and registration failures when multiple navmeshes are being loaded simultaneously.

Problems with This Approach

  • It required non-trivial engine modifications.
  • At runtime we get several warnings:
    • NavData RegistrationFailed_AgentAlreadySupported specified agent type already has its navmesh implemented
    • Navigation System: registration queue full!
  • Overall, it feels like we are fighting the system — like we’re doing something fundamentally wrong.

Question

Is there a better or more canonical way to handle streaming levels with overlapping geometry and modular static NavMesh generation?

Specifically:

  • Is our idea of pre-generating NavMesh chunks per sublevel and managing them manually at runtime a good direction, or are there recommended alternatives?
  • Can we safely support overlapping geometry in streaming levels with the navigation system?
  • Are the warnings above indicative of a misconfiguration, or are they harmless?

Any insights on whether this setup is sustainable long-term — or if there are more robust, supported ways to handle static NavMesh generation for overlapping streamed sublevels — would be very helpful.

Thanks!

There is no way in the engine to do this currently. When using sublevels like in UE4 streaming, our advice was to avoid overlapping geometry and navmesh bounds (if present) in the sublevels. The typical solution is to use dynamic navmesh either by itself or with invokers.

There have been other threads of licensees using Level Instances and managing navmesh tiles for the instance to add to the main level. The main thing to keep in mind if you attempt something similar is that the navmesh tile grid for the level instance needs to match up with the main/persistent level’s navmesh grid. You would need to add logic for keeping the tiles from the level instance when loading it as the default behavior is to discard them.

The warnings are indicative of potential problems. When you see the registration queue is full, any navdata attempting to be registered during this time is discarded. This can lead to some agent’s navmesh not being added to the world. Similarly, the RegistrationFailed_AgentAlreadySupported will fire if the SupportedAgent of a navmesh is already supported by a registered navmesh. This discards the navmesh that is attempting to be added along with its tiles.

-James