So you want to make a multiplayer game? It’s one of the hardest types of game to make. But if you’re a fan of multiplayer games, then you know you just can’t beat playing directly with players all around the world.
Unreal is a very powerful game engine, with fantastic multiplayer support right out of the box. We made this ‘Getting Started Guide’ to help you map out the territory and take your first steps towards a multiplayer game of your own.
This article gives you an overview of the topics we cover in our highly detailed Udemy course. With over 23 hours of videos and exercises, we’re able to teach these concepts in MUCH more detail in the course (see the end of the post for more info).
Use the Right Tool
Multiplayer games are very different and have different requirements. Unreal is optimised for certain types of multiplayer game. This doesn’t mean it can’t do others, it just means you will need some other tools as well.
* For MMO type games, checkout Improbable.io. They integrate with Unreal and make some of the harder bits of MMO easier.
Unreal makes short session games with synchronous game play ridiculously easy. This means FPS, Battle Royale, Racing Games, Fighting Games, even a Minecraft-inspired sandbox game if you wish! So the possibilities are far from limited.
Let’s break down Unreal’s multiplayer support into 3 steps: the lifetime of a multiplayer game.
How Easy Unreal Can Be
Unreal makes testing connections super easy, even though it’s really hard. To get started with the FPS example, press play, select the number of players required, then hit “New Editor Window (PIE)”.
Why does this work? Because many components in Unreal are doing all the heavy lifting.
Here’s a taste of what Unreal is doing for you:
- Unreal loads the Map
- The Map specifies a GameMode
- The PlayerController joins the Map
- It asks the GameMode to spawn a Pawn
- The Pawn is linked to the PlayerController.
Oh, and by the way, it will do that over a network connection too.
Setting Up a Network Connection
Network connections are almost as easy with Unreal. One easy way to get started is by launching your game on the commandline. For this you can use Command Prompt or Powershell on Windows and the Terminal App on Mac.
To launch a server you can use the following line. Replace the port with the one you want and give it the correct path to your uproject and map.
"C:\Program Files\UE_4.17\Engine\Binaries\Win64\UE4Editor.exe" "C:\PATH_TO_MY_PROJECT.uproject" /Game/ThirdPersonCPP/Maps/ThirdPersonExampleMap -server -log -port=8003
Once a server is launched, you can connect a client to it very easily too. Notice here you don’t need to provide a map but instead you give it an IP address for the PlayerController to connect itself to. Make sure to replace the IP address and port with the correct ones.
"C:\Program Files\UE_4.17\Engine\Binaries\Win64\UE4Editor.exe" "C:\PATH_TO_MY_PROJECT.uproject" 192.168.1.90:8003 -game -log
The paths will be slightly different on a Mac, but the rest will be mostly the same.
Now, we don’t expect our users to do a thing like that, so you can create UI that does the same thing by driving the ServerTravel and ClientTravel functions.
The basic idea is that we want to disconnect a player controller from one map, and reconnect to another. The difference is that ServerTravel will move all connected PlayerController (including those connected over the network) to the new map. ClientTravel is a method on the PlayerController and as such will only move that controller across.
In practice, we use the ServerTravel to host a match by adding the “?listen” string to the end of the map URL. We then use the ClientTravel function to allow clients to join the match.
This is all well and good if you have a publicly accessible IP address, but in practice, you will be stuck behind a NAT. So if you want any of this to work, you will need to set up port forwarding or use a virtual VPN solution such as Hamachi which is free and easy to use.
Still, we wouldn’t want our players to have to mess around with IP addresses, let alone a virtual VPN. So we need a service that can do something called NAT traversal.
Fortunately, Steam provides NAT traversal as a free services as part of its Steamworks SDK. This SDK has some tight integrations with Unreal via a platform agnostic layer called the Online Sub-System (or OSS for short).
Steamworks also provides solutions to our first step of a multiplayer game: Discovery. It allows us to advertise games and displayer server lists. Below you can see a server list UI we create in the course displaying a server named “Donkey”.
The Authoritative Server Model
So if that’s Discovery and Connection sorted, what about Synchronisation?
You may have heard of a server before but never actually figured out what it does. In an Unreal game, it’s the most important part of the puzzle because it’s responsible for making sure that everybody agrees and nobody is trying to cheat. Think of it as a referee!
In the diagram above, you can see the server is receiving an action from one of the clients (marked with a red thunderbolt), modifying its state, then sending this out to all the clients.
When we use the character movement component, all this synchronisation is already written for us. However, if we want a different sort of movement, we have to understand what is going on under the hood.
Basic Synchronisation Tools
Actors are the basic unit of synchronisation. They exist on both the client and server, but the server is said to have the Authority Role. This means, its version of the Actor is the correct one. The other clients are said to have the SimulatedProxy role, unless the Actor is controlled by that particular client. If it’s controlled locally, then the Actor role is AutonomousProxy. The reason for these roles is to allow the Actor code to behave differently on different machines.
To synchronise it’s important that AutonomousProxy clients can send data to the server. The server can then update its state and finally, that state needs to get pushed down to the clients. The first is done with RPC calls and the last is done with replicated properties. Now there is a lot to be said about both, which we won’t cover here. But each is given a full treatment in the course.
RPC calls are methods that we'll call locally (on the client) but the function gets executed on the server. This allows it to change state on the server. It doesn’t allow cheating because these calls are carefully policed by the rules of the game using validation function. More on that in the course.
Property replication is even simpler than RPC. All you have to do is add the “Replicated” attribute to a UPROPERTY and add some boilerplate to the GetLifetimeReplicatedProps virtual method. Detailed instructions of the procedure can be followed from the wiki page.
This automatically does some magic for you. Now whenever that property changes, it will be updated on the client to match. However, this doesn’t happen instantly (after all, light does take time to travel around the world). So the client needs to have something to do while it waits for the server to update it.
Where the real hard work begins…
Lag is a horrible thing if you have experienced it as a gamer. Dealing with it is also a nightmare if you’re a game programmer.
Lag is introduced by all the processing that goes on between you and the server. Routers have to process and copy your packets around, the server itself needs to do calculations and then there’s that pesky speed of light! So in practice, it might take 100ms (in the bad times) to get a reply from the server.
100ms is an unacceptable delay between pressing a key and seeing the results of your actions. It makes games unplayable. For this reason, there are lots of techniques that can be used to make sure the clients see a much smoother and lag free view of the game. Which technique you use depends on the gameplay experience you want to create, as all of them require some trade-offs.
In fact, the CharacterMovementComponent implements one of these techniques to ensure the FPS example works exceptionally well, even with high lag. However, if you want a custom type of movement, you will need to know how to implement these for yourself.
Sadly, those techniques are beyond the scope of a single blog post but are dealt with in much more detail in the final section of the course. There we build a go-kart actor that moves around entirely free from lag.
I hope this introduction has been helpful. Please let me know in the comments what you think.
Clearly a blog post can only cover so much. However, in our Udemy course we cover everything in minute detail, leaving no stone unturned. We build up your knowledge over 20 hours of video content, guiding you through every step of building two fun multiplayer games.
At the end of the course you will:
- Gain a fundamental understanding of the challenges of networking (e.g. latency, packet drop, NAT traversal, etc).
- Understand the architecture of Unreal’s Multiplayer features.
- Be able to connect game instances over local networks.
- Use the Steam plugin and APIs to connect players over the internet.
- Architect your games to avoid cheating.
- Communicate between machines using RPC and property replication.
- Build lag compensation systems for custom movement systems.
- Understand how to read engine code to clarify API usage.
This course builds on our experience teaching Unreal to over 100,000 beginners in our first Udemy course. We bring that experience and enthusiasm to bare on the new Unreal Multiplayer course. We expect you to be able to use Unreal to build simple games but require no prior knowledge of networking concept.
Although the C++ multiplayer course hasn't had rigorous internal review at Epic, more than 4,000 students are enrolled in the course, which has a 4.8 out of 5 rating. This is where you can learn the fundamentals of networking and multiplayer games.
This course is on sale for $10 right now during a special New Year's offer. Hurry, this sale won't last long!