[Wiki] Authoritative Networked Character Movement Tutorial

Are you missing some headers in your MyCharacterMovement.cpp file? Can you show us some source via haste bin or something?

If someone can double check what I’m doing here because it doesn’t seem to be working great.

The only major difference I can tell is that I don’t run my AirMove logic inside HiddenCharacterMovement, I just do it in my CharacterClass, I can’t see any real reason for moving the logic into the Custom Movement Component. In the example they just use a bool to execute their dodge logic and know when to stop, I already know when and to start and stop my air move logic, (when in the air for example and when not).

Here is my code as it is, right now the air move works but it still is just as laggy as before I started the tutorial with a latency of 30 or more.

https://hastebin.com/kabemomumu.cpp

I should note, my tutorials are a few years old so there could be some information changed and i honestly don’t remember what i even did in those tutorials. lol

Make sure in the Cpp file you have also changed the constructor to match the header define. (i only say this for completeness sake, since you said only header was changed).
Usually, an error of ‘use of undefined in SomeUnrealClass’ means the header file of SomeUnrealClass isn’t included. just as Nonlin said above, make sure you have the correct header file included. Although, i cannot be for certain this is the problem as I can’t view your code. Also make sure the constructor of your character has the proper movement component passed into its constructor.

I believe the correct include is


I glanced at it, but I’m not exactly sure what you’re trying to achieve with the custom air control. If you are just trying to implement lateral movement while in air, the control is already implemented in the default character movement component from the AirControl variable, 0 = off, 1 = full air control movement. note this is a float var. there is even other variables like AirControlBoostMultiplier and AirControlBoostVelocityThreshold so you can fine tune specifics.


I should add, custom networked character movements are in my opinion very advanced topics, so if not familiar with unreal’s architecture and networking/relevancy/prediction it can be a very hard thing to learn from the get go. As there are many many things to know and be aware of. I am by no means an expert or even an advanced user.

I’ve implemented my own quake style air control. I zero out unreals air control so it just uses mine.

I have since moved the airmove logic to the OnMovementUpdated of the movement component but things don’t feel much different if at all.

An another thing I would like to note is I can’t find anything on UExtendedCharacterMovement, if you notice my current code just uses my class. IDK if that was supposed to be a generic name, you do something similar for dodge, but I find it more misleading than helpful FYI.

And you don’t have to but if you look at the quake III source for AirMove (https://github.com/id-Software/Quake…ame/bg_pmove.c) lines 612 and 613 are the MoveDirection Vector I replicate inside My custom character move component. Based on that source I can’t see or think of any other input I’d have to replicate and store into a “pending moves” list which is what I believe your example sets out to do.

The only other thing I can think of trying is to sneak my air control logic into Unreal’s native air Control by overriding their Air Control but I really don’t think that should be needed but its all I can think to do atm.

Any thoughts?

Hmm, I see. Error454 has a tutorial also on this topic, it might be of some use. it even has a sample project to look at. Error454 used the the UT code as a base so It might be more beneficial to take a gander at Unreal Tournament’s code base as i am pretty sure they do something similar to what you are looking to do. I wouldn’t copy anything verbatim just use it as a reference as how one might do something with the engine. You should be wary thought that there is a licensing agreement that restrict what you can and cannot do with the UT code. Im not exactly sure if looking at the code base as a reference is legally allowed, since IANAL, but from my interpretation of the license, it seems looking at it as a reference would be allowed, but again im not a lawyer, so I would check with epic if you are worried about understanding the license.

I’m sorry i cant be much of help :frowning: my character movement implementation is quite simple compare to what you are trying to do.

You’ve been of great help so far! I will look into those resources you recommended and be weary of any UT code I may look at.

ATM I’m just looking for clarity to make sure I understand correctly your tutorial.
It seems essentially all you have to do is replicate your input and make sure you store said input via SetMoveFor and then allow for it to be loaded back in via PrepMoveFor correct?
So this would smooth out inputs as far as I understand it? But lets assume high velocity changes, like what I’m doing for air control. No amount of smoothing of the direction the users wants to go in would smooth out the big jumps in velocity I get from compounding it with my acceleration I take it? Also I edited my previous comment to include this comment

“An another thing I would like to note is I can’t find anything on UExtendedCharacterMovement, if you notice my current code just uses my class. IDK if that was supposed to be a generic name, you do something similar for dodge, but I find it more misleading than helpful FYI.”

Any bit of clarification as to the scope and reasoning in functionality of this tutorial will certainly let me know if I’m on the right path or not.

Thanks again.

Hi guys, me again,

You were right, and thank you. It was a problem with both the header file matching and the includes.

Nonlin, I’m reading through what you’re stuggling with. First of all, the UExtendedCharacterMovement in 3 or 4 places I concur is a typo. 99% sure it’s just meant to be “UMyCharacterMovement”. Someone else also caught this and came to the same conclusion on the first page.

About your bigger problem, the network jitter: I’m finished implementing through the end of the tutorial’s Unlimited Sprint section. I’ve tested on client and server with simulated 300 ping (github’s Clumsy) at 10x Sprint Speed/Acceleration Multipliers, and I can safely say the movement and transitions are very smooth. There’s a little (very little) inherent jitter, but no more at 10x than there is at 2x multipliers. I’ve followed this tutorial to the T so far (I haven’t based it off the Shooter Game framework as you did), so either that’s the difference and you should redo it the way the tutorial did (did you implement the SavedMove stuff the same way?), or I’ll come to your situation when I get to the air movement, which may be an issue caused by the character being in the Jumping/Flying, rather than Walking, state.

Also, have you tried altering the character movement networking settings? To do this, create a Blueprint inherited from your custom character, then in the Blueprint select CharacterMovement component on the left, and on the right scroll down to Character Movement (Networking). Take note of the dropdown arrow there too. This may help as there are many tweakable variables in there such as “Network Max Smooth Update Distance” and “Network Simulated Smooth Location Time”.

I’m not sure if any of this is helpful, but know that you’re not the only one plugging away at this. Sooner or later, we’ll figure this out.

Ok, I’ve implemented the Dodge ability now as well. I had to add flags for it (exactly like with the Sprint ability) to get it to work on the client at all. I see the issue which has been talked about in this thread: on the server, it works perfectly. On the client, it works occasionally. After tinkering, I believe this is why:

Notice how the boolean bWantsToDodge is set to false immediately after the Launch. The client-side behavior alters when I play around with this. I’m trying to do the following, which I believe this may solve the issue:

However, I’m not using the SetTimerForNextTick correctly and get the following errors:

Does anyone know why? Alternately, has anyone got the Dodge ability to work client-side, or any ability where you’re firing an input rather than holding it down?

If someone wouldn’t mind enlightening me up, as I’m far from being familiar with the UMovementComponent:

  • Why exactly is it that MovementComponent needs to differ for non-permanent movement changes? I have seen quite a lot of projects, multiplayer projects, which do not resort to such technique to get their movement changes (whether they’re temporary or permanent) to achieve their goal. Everything from replicated ledge engines (where movement is quite different), to even Epic projects, e.g., the ability system does predict the ability to change movement speeds, but it doesn’t seem to implement their own MovementComponent (I might be dead wrong here as I barely looked at it).

I know these are fairly dumb questions, but I’m failing to grasp the concept of MovementComponent, as lot of the logic seems to be implemented in Pawns and not MovementComponents.

EDIT: I eventually got it working. The problem was with the line
check(PawnOwner->Role < ROLE_Authority); I cut it out and now it works as expected.
Does it work on 4.18? I got some serious problem with running this. I can’t PIE with server and client. When in PIE with number of players set to 1 it works fine (i got to unlimited sprint) but when i set number of players to 2 editor crashes on start. I tried many configurations and none of them worked. Here is what I’ve done. :
Version 1:
Copied first MyCharacterMovement.h/.cpp listing, and added proper constructor to MyCharacter.cpp (had to edit header too) i added proper header files so it compiled.
Version 2:
Version 1 + unlimited sprinting
Version 3:
Version 2 with some changes
-Changed friend class in UMyCharacterMovement.h FSavedMove_ExtendedMyMovement on FSavedMove_MyMovement

  • In MyCharacterMovement there are Clear and SetMoveFor methods form FSavedMove_MyMovement:: but GetCompressedFlags() and CanCombineWith() are from FSavedMove_ExtendedMovement:: so I changed them on _MyMovement::
    None of them worked. I couldn’t even play with client opened.

Hi,

what do I do if I need more than 8 bits provided by the compressed flags? I have more than 8 abilities and even if each just used one bit, it would not be enough.

Can I increase the number of uint8 flag bytes used?

Cheers,
Univise

Hello all, good evening.

Has anyone by chance made this tutorial work with 4.18? I’m trying to replicate it and getting massive compile errors.
If so, would it be a hassle to show how to fix them? Here is one of the errors found by following the sprint section.

1>L:\UEProjects\MoveCompTest\Source\MoveCompTest\MCT_CharacterMovementComponent.cpp(93): error C2065: ‘FSavedMove_ExtendedMovement’: undeclared identifier

Edit: DarthCoder named in his snippets code with different name. Double-check them and you should be golden.

Hey dude, i found the fix.
Treat the bWantsToDodge the same as sprint. Compress and uncompress it where sprint is being done. And it will work :smiley:

Were you able to fix this issue? I’m having it as well =/

Edit: It seems to be related when the server is a Listener as has a pawn of this own. In this case, the check fails. Now the reason that Darth Coder did this is beyond me. For now…

Good Tutorial!

Very Very good job ^^

I did the tutorial and when i finished the “Cooldown” part i found a bug. Pressing 2 times the Dodge button did 1dodge and after the 2sec, the character did the 2nd dodge. It’s just a lil bug. To fix it I change:

void UMyCharacterMovementComponent::OnMovementUpdated(float DeltaSeconds, const FVector& OldLocation, const FVector& OldVelocity)
{
//… if (bWantsToDodge && DodgeCooldownTimer <= 0.0f) { MoveDirection.Normalize(); FVector DodgeVel = MoveDirection*DodgeStrength; DodgeVel.Z = 0.0f; if (IsMovingOnGround()) { DodgeVel *= GroundDodgeStrengthMultiplier; } Launch(DodgeVel); bWantsToDodge = false; //Reset cooldown timer DodgeCooldownTimer = DodgeCooldown; } //…
}

to…

//…
if (bWantsToDodge)
{
if (DodgeCooldownTimer <= 0.0f)
{
MoveDirection.Normalize();
FVector DodgeVel = MoveDirection*DodgeStrength;
DodgeVel.Z = 0.0f;

        if (IsMovingOnGround())
        {
            DodgeVel *= GroundDodgeStrengthMultiplier;
        }

        Launch(DodgeVel);

        //Reset cooldown timer
        DodgeCooldownTimer = DodgeCooldown;
    }

    bWantsToDodge = false;
}

//…

Hey, I have the same question. It’s quite important for me and it irritates me. What did Epic think designing the movement component? Can someone tell us the answer finally?

I posted a question on AnswerHub, but no interest from people so far. Here it is:

I had to remove the authority check from “GetPredictionData_Client()”, because it caused a crash. Could someone explain me, why was this function called on the server side?

After implementing simple dash function from code in the tutorial, I found that Server viewport has all replicated clients moving at around 30 fps without any smoothing.

In simple scenario, Player 1 is server, Player 2 is client.

  • On screen of Player 2 (client), Player 1 (server) is moving at solid 144fps.
  • On screen of Player 1 (server), Player 2 (client) is moving at 30fps.

With dedicated server, all clients see other clients with smoothing (144fps). So as long as Server->Client is the last step, all smoothing and prediction works as it should.

Since there is still basically no documentation, I can only guess it has to do with FNetworkPredictionData_Server_Character not being overridden? Any ideas? Is there any better documentation in 2018?

Any help appreciated!!

Would anyone know if Teleportation should be done here as well and if so, how to go about it?
All of these moves in the tutorial are settings within the MovementComponent, but teleportation is changing the loc/rot of the character, which isn’t a MovementComponent setting.

Hey does this work on listen servers too? because i tried something like this before and the editor just crashed on a listen server :confused: