Characters on client constantly falling in place

Hi.

I ran into a weird problem with replicated character movement. I have character agents walking on a navmesh and all movement orders are called from the server. The movement works perfectly on the server but on the client something weird happens. The Characters’ movement components constantly switch between MOVE_NavWalking and MOVE_Falling resulting in a jittering animations swapping between falling and walking every frame. This video shows the problem:

client-movement-error.mkv (8.0 MB)

I stepped through the engine code with a debugger and it seems the sweep which is performed to find the floor beneath the characters works correctly while they are in MOVE_Falling state but does not find the floor when they are in MOVE_NavWalking which puts it back in the falling state.

Any help would be greatly appreciated. Let me know if I can provide any more usefull information.

So I found that using regular MOVE_Walking instead of MOVE_NavWalking as the default floor movement mode fixed it. There really should be some more documentation to these things…

I’d like a solution that keeps Navmesh_Walking movement mode, as I need that for better performance. If anyone has another solution, please share.

In my testing, the client keeps switching between Falling and NavmeshWalking every frame. Checking “Allow client side navigation” doesn’t fixes it.

1 Like

Since this seems to be the only reference to this topic I could find I thought I’d provide my solution in case it helps someone.

The key issue we discovered is that when NavWalking on a client the capsule stops colliding against WorldStatic/Dynamic and it uses the collision parameters of the capsule to detect the floor, so Unreal decides that it must be falling. But once it starts falling the collisions are restored, so it starts NavWalking again. So it loses it’s collisions again, and must be falling, etc. This only happens on SimulatedProxies though, because of Unreal reasons.

In our project we use a custom movement component so our solutions involve overriding functions in C++. I’ll add a potential blueprint solution to the end but I haven’t tested that.

The solution we used is to override UCharacterMovementComponent::FloorSweepTest() and force it to use the correct FCollisionResponseParams when performing a test while the owner role is ROLE_SimulatedProxy and the movement mode is MOVE_NavWalking. Here’s a bare bones example:

bool UCustomCharacterMovementComponent::FloorSweepTest(FHitResult& OutHit, const FVector& Start, const FVector& End,
	ECollisionChannel TraceChannel, const FCollisionShape& CollisionShape, const FCollisionQueryParams& Params,
	const FCollisionResponseParams& ResponseParam) const
{
	// If we aren't a client or NavWalking
	if (GetOwnerRole() != ROLE_SimulatedProxy || MovementMode != MOVE_NavWalking)
	{
		// Continue normally
		return Super::FloorSweepTest(OutHit, Start, End, TraceChannel, CollisionShape, Params, ResponseParam);
	}

	// Otherwise use different response params
	return Super::FloorSweepTest(OutHit, Start, End, TraceChannel, CollisionShape, Params, FCollisionResponseParams::DefaultResponseParam);
}

Another solution is to override UCharacterMovementComponent::SetNavWalkingPhysics so it doesn’t set the collision response to the ECC_WorldStatic and ECC_WorldDynamic channels to ECR_Ignore. If you also want to stop them from phasing through solid geometry then this might be best for you, but it comes at a performance cost.

Finally, if you can only use blueprints you can potentially fake the last solution by implementing the OnMovementModeChanged event, and then blocking the correct channels in response. I’m not 100% sure on that one though because I haven’t tested it myself. Something like this:

YMMV

5 Likes

wow thank you very much dude!! Finally was able to solve it (by overriding the FloorSweepTest) - UE 5.1.1
The other solution caused issues for me (the AI sometimes stopped moving)