[Wiki] Authoritative Networked Character Movement Tutorial

Hi everyone. I’ve been bashing my head against my desk for the last few weeks trying to figure out the character movement component and how to properly extend it in a networked game. I decided I’d write a tutorial on it to save other developers a bit of trouble. I’ve implemented 3 different movement abilities so far and included them in the tutorial.

If anyone has feedback or suggestions I’d be happy to hear them.

3 Likes

Also, just noticed this on the wiki A new, community-hosted Unreal Engine Wiki - Announcements - Epic Developer Community Forums
This is a good resource for setting up the character movement component.

the ue4 forums have been on a roll with sharing things right as i need them, i was just about to mess around with adding double jump in my own custom movement component :smiley: TY

Glad to hear it was helpful!

This is great! Thanks man!

In the function GetPredictionData_Client()
the line:
MutableThis->ClientPredictionData = new FNetworkPredictionData_Client_MyMovement();

gives this error:
error C2280: ‘FNetworkPredictionData_Client_MyMovement::FNetworkPredictionData_Client_MyMovement(void)’: attempting to reference a deleted function

I am using 4.11.2. I don’t think it likes the default constructor.

Hey, I’ve actually got a bunch of university research projects, so I haven’t tested with 4.11 yet. Something might have changed since I wrote the article. In fact, I hope something changed since I wrote it, because I heard there were some relatively major improvements coming to the networked character movement. If you do end up figuring out the problem then would you mind posting here again so I can update the article? Otherwise I’ll have to see if I can find time to update it on a weekend.

Here’s how to fix:

  1. Create a new constructor for FNetworkPredictionData_Client_MyMovement like so:
    FNetworkPredictionData_Client_MyMovement::FNetworkPredictionData_Client_MyMovement(const UCharacterMovementComponent& ClientMovement)
    : Super(ClientMovement)
    {
    }

  2. Change the line I referenced in above post like so:
    MutableThis->ClientPredictionData = new FNetworkPredictionData_Client_MyMovement(*this);

  3. Thats pretty much it.

Basically you just change the constructor to take the appropriate parm and call the super. Then you pass in the appropriate parm. It seems to work now. Thanks for the wiki!

Awesome, updated now.

Hey DarthCoder,
This wiki is great, I’ve been bashing my head with this issue as well. I’m implementing the boost/dodge feature and I noticed that when I actually run it on a network, I get a lot of client corrections from the server. As in, the client is visibly moved back a couple steps do to replaying the moves. I’m finding this to happen on anything above 100ms ping, are you noticing similar “warping” issues with the feature in practice? Any suggestions?

I haven’t got a chance to work on it much more, but how aggressive are your boosts? I didn’t seem to be getting the same issues when I was building it, but I ended up changing my boosts to more of a sidestep before I tested much under real network conditions. Although just to throw ideas out there, I wonder if sending the position at the start of the boost and then setting it before applying the boost velocity on the server would help.

It turned out to be an error in our dedicated server code! We have a system that allows us to override datatables with data from remote servers, and I didn’t realize that the values were being updated to different movement speeds on the server than the client. Also, I noticed a bug in the wiki?



//Store movement vector
	if (PawnOwner->IsLocallyControlled())
	{
		MoveDirection = PawnOwner->GetLastMovementInputVector();
	}
	//Send movement vector to server
	if (PawnOwner->Role < ROLE_Authority)
	{
		ServerSetMoveDirection(MoveDirection);
	}


should be



//Store movement vector
	if (PawnOwner->IsLocallyControlled())
	{
		MoveDirection = PawnOwner->GetLastMovementInputVector();
                if (GetNetMode() == ENetMode::NM_Client)
                {
                    ServerSetMoveDirection(MoveDirection);
                }
	}
	


Only checking for authority will lead to “UIpNetDriver::ProcesRemoteFunction: No owning connection for actor” warnings running amuck, since in a networked game the server / authority actor doesn’t need to call the server replicated function. By checking to make sure you are not only locally controlled but also a client, you ensure that in non-network situations the server function doesn’t get called as well.

Oh, I didn’t catch that before. I’ll update the wiki when I get a chance, cause that’s a good improvement.

I was messing around with this, and trying to get it to work with a “double tap” dodge implementation and it doesn’t seem to work. I don’t think it is replicating the direction vector. It works, sometimes, but is very inconsistent. Any ideas?

EDIT:

Also, I’d like it to still dodge forward if dodge forward is executed while strafing or moving backward. In this implementation, that doesn’t seem to work. Same goes for being able to dodge left/right/backward while moving in a different direction

If anyone is still active that has used DarthCoder’s helpful tutorial (or if DarthCoder is still around) I’d really appreciate some help on the dodge/boost ability from the linked tutorial.

Problem: The boost ability seems to be corrected by the server. When boosting, the screen shudders and I catch a glimpse of where I should be going but then I snap back.

On single player I verified the boost works just fine, it only stops working when networked.

Background: I’ve been trying to get as much experience as I can implementing networked move abilities like dodge, sprint, double jump, ect. so that eventually I can use all of that to finally properly network a teleport ability.

TLDR:
I’ve implemented the tutorials to the T except for a couple change I had to make to get it to run. The first was in:

void UMyCharacterMovement::ServerSetMoveDirection_Implementation(const FVector& MoveDir)
{
MoveDirection = DodgeDir;
}

MoveDir doesn’t seem to be used anywhere and DodgeDir is undefined so I figure it was a typo and replaced DodgeDir with MoveDir.

The second change is in:

UExtendedCharacterMovement* CharMov = Cast<UExtendedCharacterMovement>(Character->GetCharacterMovement());

UExtendedCharacterMovement is not referenced anywhere else except for being the listed later as the class possessing the CanJump method later on in the tutorial.

I’m using 4.15 so I don’t know if this is a class that has been deprecated or if this was a typo. Because of the verbiage I assumed that it was supposed to be UMyCharacterMovement instead, which worked fine for the sprint ability.

My guess is either something in 4.15 is different enough to mess with the mechanic or one of the changes I mentioned is wrong.

Could anyone shed any light on what is going on here? This stuff is thick and hard to follow behind the scenes - not sure why the server isn’t recognizing the boost as valid.

Thanks!

Hey I’m looking to smooth out my own custom air control for an online FPS game I’m making based on the Shooter Game Project and I came across this guide.

I’m a bit confused since I’m using Shooter Game, they seem to do a lot of their bWantsToSprint stuff inside the ShooterCharacter class.
And my custom air control I wrote is inside the shootercharacter class as well. My custom air control works great btw and it even replicates online it’s just not very smooth when there is a latency of 30ms or more.

So I’m wondering, do I absolutely have to make my own CharacterMovementComponent (CMC) to smooth out my custom air control or can I call some existing methods from the native CMC and leverage it that way?

Also am I missing the entire scope here and nothing from this tutorial will well help with smoothing out custom movement behavior when theirs lag?

In my experience, yes. Anything modifying the way a character will move over the network should modify their character movement component in C++. It seems to me that if you don’t it’s feels very wrong in terms of game feel and in terms of smoothness. It probably has to do with the network prediction system.

Thanks! Just as I feared lol. Well I am excited at the prospect of getting this solved finally but I’ll just have to churn out my own movement component it seems which will just be a bit of a headache of its own to integrate into Shootergames existing framework I suspect.

So after actually attempting to implement this I’m a bit confused as to the connection between the Character Class and what it needs to execute from the custom Movement Component.

It seems as though all you need to do is Set the bools from Character Class (via input binding of sorts) to the Custom Movement Component and… that is it?

After actually trying to execute the code I get Error: Assertion failed: PawnOwner->Role < ROLE_Authority inside the GetPredictionData_Client().

EDIT:
I’m confused because is that method only supposed to happen client side? If that were the case then the check shouldn’t fail, so for it to fail means it does natively happen for both client and server? Can someone help me understand this?

Hey guys,

I’ve been killing myself for weeks now trying to do this. I was noob at c++, but I’ve been devouring all the material I can to learn it. I even watched your youtube series, SaxonRah. But to no avail!! This is where I’m stuck:

I followed to tutorial through the Initial Setup and get the compiler errors in the pic below. It’s a fresh project, I kept the script names the same as in the tutorial, and I also changed the header file’s constructor to “AMyCharacter(const FObjectInitializer& ObjectInitializer);”

What the heck am I doing wrong here?!