Skip to main content

Unity Netcode

Netcode for Game Objects on Arbitrium

This guide will help you create a headless server on Edgegap for a Unity project using Netcode for GameObjects as its networking solution.

We will use the open-source sample project 2DSpaceShooter from Unity Bitesize Samples as an example.

This guide was written using Unity 2021.3.8f1 LTS on Windows to produce all Unity builds. The Docker part was made using Linux Mint Cinnamon 20.3.

Get the base project

To begin, copy the sample project. This guide uses the project at this commit.

git clone https://github.com/Unity-Technologies/com.unity.multiplayer.samples.bitesize/
cd com.unity.multiplayer.samples.bitesize
git checkout 2ac6a9a38f9dd4ff1e748d1a73b3086f986f6d75

Open the project in Unity, open scene Assets/Scenes/network. Hit play in the editor and choose Host (Server + Client) to test the game locally.

Adapt your game to support Dedicated Game Server (DGS) mode

Dedicated Game Server (DGS) mode is the mode used by Netcode when you call NetworkManager.StartServer().

Add automatic server start

We need to change the sample HUD provided. The idea is to automatically start Netcode server if the build is a Unity server.

  • Server doesn't need HUD, so in Assets/Scripts/NetworkManagerHud.cs, enclose function void OnGUI() with preprocessor directive #if !UNITY_SERVER and #endif.

  • Add a new Start() method, and a call to m_NetworkManager.StartServer(); inside. Enclose the call with preprocessor directive #if UNITY_SERVER and #endif. We will also add a log to show that the server started.

At the end, modifed part of NetworkManagerHud.cs should look like this:

...

void Awake()
{
// Only cache networking manager but not transport here because transport could change anytime.
m_NetworkManager = GetComponent<NetworkManager>();
m_LabelTextStyle = new GUIStyle(GUIStyle.none);
m_Transport = (UnityTransport)m_NetworkManager.NetworkConfig.NetworkTransport;
}

private void Start()
{
#if UNITY_SERVER
m_NetworkManager.StartServer();
Debug.Log($"Started server on {m_Transport.ConnectionData.ServerListenAddress}:{m_Transport.ConnectionData.Port}");
#endif
}

#if !UNITY_SERVER
void OnGUI()
{
m_LabelTextStyle.normal.textColor = LabelColor;

GUILayout.BeginArea(new Rect(DrawOffset, new Vector2(200, 200)));

if (IsRunning(m_NetworkManager))
{
DrawStatusGUI();
}
else
{
DrawConnectGUI();
}

GUILayout.EndArea();
}
#endif

...
  • To allow the server to receive connection from all IP, add the value 0.0.0.0 on the GameObject NetworkManager in UnityTransport -> Connection Data -> Server Listen Address.

img

(OPTIONNAL) Making a windows server build to test locally

Build for Windows server. This build target is available since Unity 2021.2 (see Unity forum post).

  • If you use an older Unity version, add the variable UNITY_SERVER in Projects Settings -> Player -> Scripting Define Symbols, and check Headless Mode and Server Build.

  • Otherwise, simply select the Dedicated Server platform option.

img

  • Start the executable. You might have errors and warnings about shaders not being supported, this is not an issue.

  • Allow Windows defender to let incoming connections from the outside

img

  • Start the editor, click on Client to connect to 127.0.0.1 (localhost)

  • You should have a spaceship and be able to control it!

  • If you have another computer, you can build an executable, and connect to the server with its local IP.

note

The sample as latency issue, game might have a different feeling when running the server on an other machine, even with very low local network latency. Unity Documentation

This method of running physics makes sure that there are no desyncs or other physics issues between the client and server, but it introduces more latency. With future prediction support of Netcode, the latency will no longer be an issue which makes this the best choice of a movement model for a game like this.

Contenerizing the dedicated game server

In this part, we will create a docker image containing the dedicated game server. You might also be interested in reading Unity on Docker.

  • Make a build for linux server. Our build executable name will be 2d.x86_64, inside a Linux_server folder.

img

  • Transfert Linux_server folder to a Linux system, in a empty folder, along the given Dockerfile.

Dockerfile

FROM debian:11.4

# Update root CA to ensure outbound HTTPS requests don't fail
RUN apt-get update && \
apt-get install -y ca-certificates && \
apt-get clean && \
update-ca-certificates

# Copy server file from host into the image
COPY Linux_server /Linux_server

# Gave permission in the image to run the executable
RUN chmod u+x /Linux_server/2d.x86_64

EXPOSE 7777/udp

ENTRYPOINT /Linux_server/2d.x86_64
  • Start a command prompt in the new folder, then run the folowing Docker commands:
warning

For ARM CPU (Mac M1, M2, etc.) user, see the dedicated page : ARM CPU

# build the image
docker build . -t <IMAGE_NAME>:<IMAGE_VERSION>

# login, a prompt will ask the password
docker login -u '<REGISTRY_USERNAME>' <REGISTRY_URL>

# add another tag to your image corresponding to the registry
docker image tag <IMAGE_NAME>:<IMAGE_VERSION> <REGISTRY_URL>/<PROJECT_NAME>/<IMAGE_NAME>:<IMAGE_VERSION>

#push the image
docker push <REGISTRY_URL>/<PROJECT_NAME>/<IMAGE_NAME>:<IMAGE_VERSION>

See this documentation if you want to use the Edgegap Registry. You can also use another private registry.

Deploying to Edgegap

img

  • You have to open UDP on port 7777. When deploying the application, the port 7777 in your container will be bound to another random host port, accessible publicly. Edgegap API can give you the host IP and port binding for each deployment.

  • After finished creating your application, click on 🚀 Deploy button to make your first manual deployment. Let the default settings (random players IP) and deploy.

  • When the deployment is ready, open the Port Mapping tab.

img

We can see that we deployed on 90bcde677d11.pr.edgegap.net, and the publicly accessible port is 30588.

  • Netcode sample HUD can't resolve host IP from hostname, so we will manualy get the server IP.
nslookup 90bcde677d11.pr.edgegap.net

In our case, IP was 45.76.225.155.

  • Start a Unity client, enter IP and port, click on Client, and your client application is connected to your Edgegap deployment!

img

Of course, a player won't do all these steps, so let's automate this!

Add sample HUD in your client application

  • Import the script EdgegapSampleHUD.cs from our Github.

  • Add this script to the NetworkManager GameObject. This will provide an in-app GUI to manage your deployments.

  • Fill application informations in the editor

note

This HUD is great for this sample, but you should not send your credentials in a player build. You should have your own API to be sure a player doesn't abuse the system and launch too many deployments or kill other players' deployments.

Feel free to look inside EdgegapSampleHUD.cs.

The most important thing is to get your deployment server IP and port from Edgegap API, and then put the value automatically in your transport, before starting the client.

private void Connect(string ip, ushort port, string fqdn)
{
transport.ConnectionData.Address = ip;
transport.ConnectionData.Port = port;
pendingStatus = null;
Debug.Log($"Connecting to {fqdn} [{ip}:{port}]");
networkManager.StartClient();
}

You can get the complete project sample on our GitHub.