I’ve made a NavLinkObject class which is just a NavLinkProxy without the simple links and sprite/navLinkRendering components so that we can build doors and windows and things like that. We want our AI to be able to go through these links to unconnected nav zones without having to recalculate nav mesh all the time. It works perfectly when I put it in a door for example, and throw that into a level directly, but when it’s set as a child actor on another object, the link doesn’t exist in the nav tree until I jiggle or move its parent actor to force a nav update. Additionally, it works just fine when first placing the object into the world for the same reason, since it forces a nav update.
The object I’m using that’s causing this is a blueprint actor created by adding mesh and other components. It’s a small house with a front and back door which are themselves actors, in this case NavLinkObject actors with logic for locking, opening, etc. When first running the editor no AI can path into or out of the house, and running a Find Path to Actor Synchronously check in the level blueprint fails to cross the doorways. If I adjust something in the house actor, like adjusting a light position, and recompile it the nav link displays where the doors are disappear from the view. As soon as I slightly move the house’s position to force a nav update the link visualization comes back and pathing works correctly. This has to be done to each instance of the house actor every time the editor is closed and restarted.
Are there any known workarounds for this? Prefab-like actors are kind of a pain to use right now, as child actor components with any sort of complexity don’t play very nicely with each other without a lot of scripting workaround. Is there a way to force a construction script to re-run on an actor only in editor mode when it’s first loaded up, or something like that?
Edit: This is in 4.7.3
Hi TheNoonicorn,
I have been attempting to reproduce this, but I am not having much luck. Can you explain exactly what you mean when you say “I’ve made a NavLinkObject class which is just a NavLinkProxy without the simple links and sprite/navLinkRendering components”? Are you doing this in C++ or purely blueprints? If this was done in C++, please post your .cpp and .h files for the custom NavLinkObject. If you turn on “Rebuild at runtime” does that affect the outcome? Any additional information about the actor may help. Thanks!
The CustomNavLinkObject is a new code class, literally just NavLinkProxy with the simple link stuff ripped out. Code is at the end of this post.
We have a blueprint actor called Rotating_Door which is a child of that class, with mesh and other things our game needs.
And here it is as a child actor of a dummy object
Placed in world they look the same, both get the Nav Link arrows. The Rotating_Door is placed on the left, the BadNavActor on the right
The AI spawns off to the right of the screen. The first time you load up the editor the AI will never use the BadNavActor door on the right because its link isn’t included in the nav mesh
But once you slightly move the actor to force it to rebuild all its components the AI will be able to use that link for pathing
From stepping into the code my best understanding is that when the BadNavActor is spawned and its component actors created there is no current UNavigationSystem, so it can never call UpdateNavOctreeElement. I’ve not been able to discover yet what the non-child actor is doing that the child actor component version of the door isn’t, or vice versa, to understand what order of operations the problem is.
I think I’ve found part of the problem, UpdateNavOctreeElement wasn’t ever checking if an actor had child actors that implemented INavReleventInterface. I’ve updated the function;
void UNavigationSystem::UpdateNavOctree(AActor* Actor)
{
SCOPE_CYCLE_COUNTER(STAT_DebugNavOctree);
UNavigationSystem* NavSys = Actor ? UNavigationSystem::GetCurrent(Actor->GetWorld()) : NULL;
if (NavSys)
{
INavRelevantInterface* NavElement = Cast<INavRelevantInterface>(Actor);
if (NavElement)
{
NavSys->UpdateNavOctreeElement(Actor, NavElement, OctreeUpdate_Modifiers);
}
else
{
TArray<UActorComponent*> OwnedComponents = Actor->GetComponents();
for (UActorComponent* Component : OwnedComponents)
{
if (UChildActorComponent* ChildActorComp = Cast<UChildActorComponent>(Component))
{
UpdateNavOctree(ChildActorComp->ChildActor);
}
}
}
}
}
and now child actors are getting sent through, but they’re still not showing up as acceptable links until the parent actor is moved, forcing the components to be destroyed and recreated
Also, neither Rebuild at Runtime nor Force Rebuild on Load have any effect, probably due to whatever’s checking for the INavRelevantInterface skipping child actors
Hi TheNoonicorn,
I apologize for the delay in getting back to you on this issue. I have been trying to reproduce the issue you described using 4.7.3, but have so far been unable to do so. I created a code class using the code that you provided, then created a Blueprint based on that class. The Blueprint’s Components window only showed the NavLinkComp component though, so I added the rest of the items that were shown in your first screenshot. This is how it ended up:
It’s not quite the same as what you showed, so my class may be a bit different from what you have. I then added a simple cube to the StaticClass component and placed it into a gap between two nav volumes. There did not appear to be any link that I could set up between the two nav volumes, and Smart Link didn’t seem to be doing anything either. Do you happen to have a small test project that shows this issue that you might be able to upload?
Here’s an empty project with two examples of this thing, both set up identically except for the floor material it’s on, as far as I can tell, but producing two different results. I was able to reproduce it in 4.7.6 without any additional code by making a blueprint object descended from NavLinkProxy. Here’s the setup:
In the level blueprint I’m finding a path to the locations synchronously from the rightmost point to each of the other points. The obstacle on the right is the NavLinkProxy-descended object all on its own, the obstacle on the left is an actor with the NavLinkProxy object as a ChildActorComponent.
And the result of hitting play immediately on loading without touching anything:
And after quitting and jiggling one of the blockers on the bottom platform:
Attached is the empty project in a zip file:
[link text][4]
Hi TheNoonicorn,
Thank you for providing the sample project. The setup there was actually quite a bit simpler than I was attempting, and I was easily able to reproduce the issue. I have submitted a report of my observations to have this investigated further (UE-16445). I also tried testing this in version 4.8 and our latest internal version, but was unable to do so due to other issues.