Description

Function UNavMoverComponent::GetFeetLocationBased() on file "NavMoverComponent.cpp" returns an FBasedPosition built from an FRelativeBaseInfo. The "MovementBaseInfo" is read from key "CommonBlackboard::LastFoundDynamicMovementBase" on the simulation blackboard. As of UE 5.6 and latest source versions, this blackboard key is only set by WalkingMode and FallingMode (not by NavWalkingMode), and only if the controlled actor is based on a floor marked as Movable (not Static). Here's the relevant simplified call chain:

UWalkingMode::SimulationTick_Implementation()
UFloorQueryUtils::FindFloor()
UWalkingMode::CaptureFinalState()
UWalkingMode::UpdateFloorAndBaseInfo()
FRelativeBaseInfo::SetFromFloorResult()

In the call chain above, the results from UFloorQueryUtils::FindFloor() are passed on to FRelativeBaseInfo::SetFromFloorResult(), which fills out the "ContactLocalPosition" member by converting "HitResult.ImpactPoint" from world space to a space relative to "HitResult.Component" using UBasedMovementUtils::TransformWorldLocationToBased().

Back to UNavMoverComponent::GetFeetLocationBased(), it converts FRelativeBaseInfo to FBasedPosition as follows:

BasedPosition.Base = MovementBaseInfo.MovementBase->GetOwner();
BasedPosition.Position = MovementBaseInfo.Location;
BasedPosition.CachedBaseLocation = MovementBaseInfo.ContactLocalPosition;
BasedPosition.CachedBaseRotation = MovementBaseInfo.Rotation.Rotator();

However, members "Position" and "CachedBaseLocation" seem to be swapped. As a result, FBasedPosition's operator* will recalculate the world-space position of the controlled actor, and will do it using the wrong relative position. The most useful information, ContactLocalPosition, ends up lost.

The structure returned from UNavMoverComponent::GetFeetLocationBased() is used by UPathFollowingComponent::UpdateBlockDetection() on file "PathFollowingComponent.cpp". If the floor where the controlled actor is based is not moving, the samples acquired by that function will all be at the same location. After some samples are acquired, UPathFollowingComponent::IsBlocked() will interpret this as a blocked movement.

Note that UNavMoverComponent::GetFeetLocationBased() not only swaps "BasedPosition.Position" and "BasedPosition.CachedBaseLocation", but it also fails to capture the fact that "MovementBaseInfo.ContactLocalPosition" is relative to a primitive component, while "BasedPosition.Position" is relative to its owning actor (which might have a different location). The linked EPS case attempts to fix this with the following code to set "BasedPosition", but it notes that these back-and-forth conversions might not be ideal:

AActor* Base = MovementBaseInfo.MovementBase->GetOwner();
FVector WorldPosition;
UBasedMovementUtils::TransformBasedLocationToWorld(
MovementBaseInfo.MovementBase.Get(),
MovementBaseInfo.BoneName,
MovementBaseInfo.ContactLocalPosition,
WorldPosition);
BasedPosition.Set(Base, WorldPosition);

 

Steps to Reproduce

1. Enable the "Mover" and "Mover Examples" plugins. Restart the engine.
2. Make a copy of map "Engine/Plugins/Mover Examples/Maps/L_PathfindingMovement" and open it.
3. Select the ground of the arena (Arena/Terrain_Floor) and set its Mobility to "Movable"
4. Select actor "AIObstacleCourseWaypoint" and make 2 duplicates
5. Place the two duplicates on opposite corners of the arena:
5.1. One near its original location
5.2. One on the opposite corner, near the "Ledge*" actors
5.3. Make sure the path between them is clear of ramps and other floor actors
6. Select actor "PathFollowingMannyPawn8" (or duplicate it and select the duplicate)
7. On the Details Panel:
7.1. Make sure that "AI Behavior" is "Patrol" and that "Should Nab Walk" is disabled
7.2. Clear array "Waypoint – Waypoint Actors"
7.3. Add the two waypoints created before to the array
8. PIE or Simulate
8.1. About 5 seconds after starting the movement from waypoint to the next, the character will abort its movement and select a new waypoint
9. Open blueprint "PathFollowingMannyPawn"
9.1. On event "MovePawn", under the "Patrol" branch, after the node "AI MoveTo" returns "On Fail", print the "Movement Result".
9.2. PIE or Simulate. The printed movement result will be "Blocked".

Have Comments or More Details?

There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-353449 in the post.

0
Login to Vote

Unresolved
CreatedNov 12, 2025
UpdatedDec 8, 2025
View Jira Issue