Video

What is it?

  • Engine: Unity
  • Language: C#
  • Goal: To learn multiplayer networking with Unity Netcode for GameObjects.

This is a multiplayer 6-degrees-of-freedom racing prototype developed for university as part of a networking module. Using Unity Netcode for GameObjects as the networking library, we were tasked with making a basic prototype to learn about what goes into networked game architecture, such as RPCs, client/server authority, latency reduction/compensation.

Out of all the prototypes I have made for university, this is by far the most fun to play and I’m very interested in developing it further once I graduate!

How is the movement networked?

The movement was a very important part of the game to get right. Based on the game being a racing title, I identified these goals for the netcode to achieve:

  • Little to no input lag.
  • Fairly accurate results, but not to an extreme degree - this isn’t a fighting game!
  • Smoothness and consistency.

The last two were fairly easy to achieve, as Netcode for GameObjects has NetworkTransform and NetworkRigidBody components built in. These allow me to easily update the ship’s position over a network with very little code, as the API abstracts the whole process. It provides settings to optimise the packet size which reduces bandwidth usage, and even provides interpolation support to make movement updates smoother.

A Client Network Transform component, showing settings that control how much data is sent over the network, as well as interpolation.

While this is a good solution, I could have implemented client-side prediction, which sends the inputs of remote players over the network and has the local machine simulate that movement as if it were being controlled locally. This would further increase the smoothness of the movement, as interpolation still has a small amount of (albeit dampened) jitter.

However, you might have noticed something: the component pictured above is called Client Network Transform. This loops back to the first goal on the list which is input lag.

It is best practice for most multiplayer games to be server-authoritative, which means that the server is the source of truth on the current state of the game. When the player makes an input to move, it is sent to the server before anything happens. The server then simulates the movement and sends the new position back to the player. This means that teleporting or speedhacks will not work effectively, even if the client is modified.

However, this introduces some obvious input lag. After all, the player’s movement is tied to the latency between the client and the server!

One way to get around this is to have the player start moving locally anyway as the input is sent. The server still simulates the player on its own copy of the game, but the two different positions are checked within a threshold to make sure they stay close to each other, accounting for latency.

But as I was new to netcode at the time and found this hard to implement, I decided to go with the easiest but riskiest option: client-authoritative movement. This means the client simulates the movement and sends their new position to the server, who innocently accepts it without questioning it at all. While this solves the input lag problem, this is really bad for cheat prevention as it allows modified clients to go wherever they want to go, and I only did this because I knew this game would not be shipped in its current state. There are anti-cheat methods that watch the movement of client-authoritative players and kick them if they move incorrectly, but it is more complex to do and less efficient.

If I was to implement this again, I would make sure the movement is server-authoritative to stop cheaters from ruining the fun. And also make it in Godot, but that’s more of a personal thing. :>

Watch this space!

Credits