World Partition, External Data Layers and navmesh

Hi,

I am trying to build a map with potential changes to the world that are in game feature plugin and added through external data layer. We have reasonable amount of combinations of those game feature plugins that we deemed possible and we really want to avoid dynamic navmesh generation.

So the thinking was as described in the repro step to basically create navmesh for each potential combination and activate just the correct one in runtime.

Unfortunately it seems that moving game feature plugin to registered seemingly removes the navmesh from the world, but some reference is probably still stuck.

So say if I enable plugin 01, generate navmesh, move navmesh to external data layer. Restart the eidotr and do the same for plugin 02 I’ll get working state. But I have to be very careful to never activate both plugin within the same session (not at the same time, in same session is enough)

I am thinking that there might be something simple to do (force unload navmesh) but as of right now I struggle the find it.

Help with this would be greatly appreciated

Cheers

Steps to Reproduce

  1. Create new ThirdPersonMap
  2. Enable World Partition External Data Layers in Editor Preferences
  3. Ensure “Update navigation automatically” is set to false
  4. Enable Game Features plugin
  5. Create two Game Features Plugins and do following for each
    1. Add External Data Layer into its content
    2. Add Action “Add World Partition Content” and add the data layer there
    3. Add the create layer as data layer into ThirdPersonMap
    4. Select some static meshes in the outliner, right click on them and move them to the external Data Layer you just added.
    5. Move the plugin current state to registered
  6. Checkin: you see the map in editor, it is missing the objects you added, you don’t see any Data Layer in data layers because they are all unloaded.
  7. Add NavMeshBoundsVolume to the scene, scale it up to cover the whole area
  8. Activate First Plugin
  9. Set the external data layer from this plugin as active
  10. Build paths from the menu
  11. Notice: RecastNavmesh-Default is generated but it is not in the activated data layer
  12. Right click, EDL, Move actor to this layer
  13. Press p in view to show navmesh (it is properly visible)
  14. Move the plugin current state to “Registered”
  15. Notice navmesh debug draw properly disappear
  16. Activate the second plugin
  17. Build Paths again, new RecastNavmesh-Default is generated
  18. Move it again to the second data layer(owned by the currently active plugin)

At this point expectation would be that the navmesh in plugin 2 is distinct from navmesh in plugin 1 but it seems like this is not the case.

Hello,

I apologize for the delay. There does seem to be some issues here with using it with EDLs. We’ll need some additional time to investigate this. I’ll try to report back early next week after discussing this further with the team(s).

Thanks,

Ryan

I’ve sent this over to the AI team to take a look at and share their input on the matter.

-Ryan

This is something that we have not tested or experimented with saving navmesh to plugins or external data layers. Navigation support of data layers in general is still minimal currently.

Are you using a WP navmesh with this or a standard navmesh? Are you using static navmesh or dynamic modifiers only? Does anything show up in the logs when attempting to load the navmesh from the plugin? Will the navmesh load from a plugin if only one plugin/navmesh has been built? Are there warnings or errors? Do you have options enabled for discard sublevel nav data or to auto create navigation data?

-James

Hi James,

putting breakpoints there certainly helped understand it a bit better. With that I managed to progress a bit. I am able to have navigation in external data layer. When switching between them I just manually UnregisterNavData after deactivating the plugin and before activating the new one.

Unfortunately I got stuck on next step, it seems that with this approach navmesh is just not present in PIE. (I didn’t test cooked game yet, as that would be next step)

In PIE situation, even if the GameFeature is activated before I start PIE the sequence of actions is

  • UGameInstance::StartPlayInEditorGameInstance
    • This registers navmeshes
  • Much much later my external data layer finally gets to create my NavigationData

So in this scenario my data won’t get registered. I tried inheriting from RecastNavmesh and overload BeginPlay and call RequestRegistration() there. This led to sometimes have Navigation data, but unfortunately sometimes leads to a crash (which leads me to believe something is not safe)

But I think core of the issue is that the BlockTillLevelStreamingCompleted is just not respecting assets in external data layers. I am not that familiar with the code around it. I’ll keep poking around but I am again at a point where help would be appreciated.

Do you have the callstack from the crash when registering your NavigationData? Is there any data in the logs about what happened when registering?

There is nothing interesting in the log during registration. I think the problem is really because all of this comes way too late in the process and the system is not ready for navigation data to appear.

Callstack and state

[Image Removed]

> [Inline Frame] UnrealEditor-Navmesh.dll!dtNavMesh::getTileCountAt(const int) Line 2011 C++ UnrealEditor-Navmesh.dll!dtNavMeshQuery::queryPolygons(const double * center, const double * extents, const dtQueryFilter * filter, unsigned __int64 * polys, int * polyCount, const int maxPolys) Line 1544 C++ UnrealEditor-Navmesh.dll!dtNavMeshQuery::findNearestPoly(const double * center, const double * extents, const dtQueryFilter * filter, unsigned __int64 * nearestRef, double * nearestPt, const double * referencePt) Line 1156 C++ UnrealEditor-Navmesh.dll!dtCrowd::checkPathValidity(dtCrowdAgent * * agents, const int nagents, const double dt) Line 1114 C++ UnrealEditor-Navmesh.dll!dtCrowd::updateStepPaths(const double dt, dtCrowdAgentDebugInfo * __formal) Line 1241 C++ UnrealEditor-AIModule.dll!UCrowdManager::Tick(float DeltaTime) Line 264 C++ UnrealEditor-NavigationSystem.dll!UNavigationSystemV1::Tick(float DeltaSeconds) Line 1763 C++ UnrealEditor-Engine.dll!UWorld::Tick(ELevelTick TickType, float DeltaSeconds) Line 1396 C++ UnrealEditor-UnrealEd.dll!UEditorEngine::Tick(float DeltaSeconds, bool bIdleMode) Line 2140 C++ UnrealEditor-UnrealEd.dll!UUnrealEdEngine::Tick(float DeltaSeconds, bool bIdleMode) Line 550 C++

Well, I finally got it to the somewhat working state. The crash above was caused by a fun issue we had bShouldDiscardSubLevelNavData set to True. Which unfortunately led to unloading of all of my object from the external data layer shortly after they were loaded.

Currently the way that it is somewhat working

  • Manually unregister navigation data after unloading the plugin having the navigation data.
  • Inherit ARecastNavMesh, overload BeginPlay and call RequestRegistration() there. (This was needed for PIE, because PIE registers navigation data before my layer gets activated)
  • Create GameFeaturePlugin for each combination, put external data layer in and push the navmesh in it.

This is not ideal workflow but that is what I am settling for right now.

Thank you for sharing back how you got it working. We are beginning to pick up work again on WP navmesh. I will share this out with the team as potential things to be investigated. I know we have had a few discussions for how to best handle data layers with regards to static navmesh, but with the addition of external data layers, it adds more to think about in terms of support. I can’t promise this use case gets attention, but I will make sure it is discussed as we prioritize items to address.

Hi James,

all answers to those questions are visible in the repro I provided.

  • It is World Partition navmesh
  • Static navmesh
  • No warnings when loading the plugin for first time
  • Yes, if only one plugin has been loaded it seemingly works. So I can boot up editor, load version1 -> works. Boot editor again, load version2 -> works. But as soon as I try to load/unload versions in one run things to crazy
  • When loading V1, Unloading V1 then on Load of V2 I get the following, which leads me to believe something is not being unloaded

LogNavigation: Warning: NavData RegistrationFailed_AgentAlreadySupported, specified agent type already has its navmesh implemented.

  • Auto create navigation data is set to true (default)
  • Should Discard Sub Level Nav Data is set to true (default)

Cheers

Jan

Sorry for double post, just doublechecked and those last two options doesn’t have obvious impact on the behavior (auto create and discard sub level)

From the logs, it seems that the navmesh is not being unregistered as part of unloading the plugin. If you only unload the plugin, does it show the navmesh as removed and unregistered in the navigation system? You can break inside the RegisterNavData function and possibly UnregisterNavData to see if they are being called when changing from one plugin to the next. You may need to add in a call to unregister the navmesh for your given agent (or all navmeshes if all should be changed) when unloading a plugin. That should prevent the issue of failing to register the navmesh as the agent is already supported.

I know we use Game Feature Plugins heavily for FN, but our maps never use multiple plugins for navmesh and certainly not within the same session if it has ever been tried.