Howdy!
Welcome back to my blog series on the exploratory Networking Project that I have been working on over these last few weeks.
This week marks the start of the implementation phase of the project and I have spent my time this week setting up the Unreal project and repositories as well as creating a simple custom Player Controller that implements a Naive approach to networked movement.
The Issues with Networked Movement
As a refresher, in modern games that utilize a client-server architecture, the server is the ultimate authority of the simulation and has control over the entire game's state. This is to prevent any one player from gaining an unfair advantage by manipulating the simulation. Thus, the ideal situation would be if each client simply sent their inputs to this neutral server which then would update each client's position once its input has been validated. However, all networked environments have some amount of latency and this latency causes the problem shown below:
The client presses their input, and then ... nothing ...for 100ms until the server confirms the movement and sends it back across the internet to the client. This is obviously not ideal for player movement but it will serve as the foundation of what I will be building off of for the next several weeks as I continue to improve the latency mitigation techniques that I am implementing.
The Simple Player Controller
Say hello to our beautiful player controller:
Isn't it glorious? This may not look like much (and to be honest it really is not much at the moment), but this is the foundation on top of which I will be building the different latency mitigation strategies that I described in the previous week's post. But first, we need to be able to move:
The image above shows the super simple movement code that I wrote for this custom player controller. These functions are called from input callbacks through Unreal's input system. I wanted to keep the movement options simple so that I can focus on the networking aspect of this task and not so much on all of the other amazing ways that I could improve this character controller. So in other words, it's not much, but it'll get the job done, which you can see below:
I may play around with some additional quality-of-life features like the ability to switch between first and third person perspectives in order to better illustrate the latency mitigation but for now, this is about all we need out of a player controller, on to networking!
Networking the Player Controller
With a networked player controller, we need to package our input each frame and send that off to the server to be validated. To do this, I created a simple struct that stores information about the player's input:
Player input now is no longer applied on input, but rather it sets a flag that marks that new input should be sent to the server this tick (camera/player rotation is maintained locally):
In the Player Controller's Tick, a FPlayerMove struct is built up from the player's input that frame and is sent to the server's instance of the Player Controller via a server RPC call (ServerMove):
This FPlayerMove struct is read by the server and is applied to the server's version of the Player Pawn:
The new position of the player is set on the server and a replicated variable, PawnLocation, is updated which invokes a callback on the client-side version of the player controller:
This callback simply updates the client's position based on the validated position that was calculated on the server... and that's it!
With that simple code, we now have a "dumb" client that records its inputs and then sends them to the server to be validated. The client then applies this movement once it receives confirmation from the server that the move was valid.
Below you will see two videos of this naive networked player controller in action, the first that was run with the Average network emulation settings and the second with Bad network emulation settings:
Average:
Bad:
As you can see, the effect of this naive approach is pretty immediately noticeable. Even with average network conditions, there are still frequent visual artifacts from the latency. But, that is a problem for next week when I implement client-side prediction and server reconciliation.
You can find my GitHub page for this project here: https://github.com/notis404/LatencyMitigation
Comments