This guide is intended to be a one-stop shop for anyone who wants to integrate PlayFab into their Unity Multiplayer game. I’m going to be using and referencing Mirror, the open-source networking library in a lot of these examples, but all of this probably applies to whatever networking library you’re using (such as Unity’s official solution: Netcode for game objects, or Darkrift etc)
Also note that even though this is for Unity, the same principles can be applied while building for Unreal or even your custom game engine.
Hey folks, I’m Rohan Mayya. I have experience with Web, App and Unity development and am fond of Open Source. I spent a good 4 months wrangling around with PlayFab’s Multiplayer Servers trying to get it to work with the multiplayer game I was building (Using Unity + Mirror). This guide will always remain free, so I would really appreciate it if you reached out on Twitter with feedback on how this guide can be improved, or if you can contribute yourself!
- Introduction
- Getting Started
- Locally Debugging your Game Server Build
- Deploying your Container
- Hosting your Game Server
- Standard Hosting
- Hosting for WebGL Games
Hosting in web development has never been easier. Usually, things happen in one click, or push to your GitHub repository. Nearly everything is automated, and it is dead easy to get started quickly. Tools like Vercel, Heroku, Netlify make doing this a breeze.
However, I’ve seen people in the games industry continuously reinvent the wheel. Between using services like Vultr, AWS’s VPS etc, everyone’s rolling their own logic + scripts for creating and shutting down servers. Everyone’s rolling out their own system for reasons I do not fully understand.
PlayFab abstracts away a lot of this and can easily save you 3+ months of development time (especially if you’re new to all of this), so follow along and we’ll get you up and running in a few hours.
Also, PlayFab gives you multiple options to do certain things (such as choosing between Windows and Linux containers). My guide is, however, very opinionated. I will choose the quickest and easiest path that works for me. Convention over configuration, to get up and running fast.
Before we begin, if you’re a visual learner, you might prefer watching my YouTube videos instead.
- Part 1 - https://www.youtube.com/watch?v=YTNdsvTBEcA
- Part 2 - https://www.youtube.com/watch?v=9O_tN7pM9v0
Here are the initial steps:
- Grab the PlayFab Editor Extension for Unity here,
- Follow the steps to add the Editor Extension as a package in your Unity project,
- Create an account on Playfab.com,
- Login to the extension with your PlayFab account,
- Choose the title you created in the PlayFab Editor Extension, after creating a title in PlayFab’s dashboard,
- Hit "Install PlayFab SDK",
- Add
ENABLE_PLAYFABSERVER_API
to your Scripting Define symbols in your Unity’s player settings
PlayFab allows you to create different types of servers: Either a Windows or Linux based server. With Windows, you can run your server as either a process or a container. With Linux, you can only run it as a linux container.
I discourage using Windows (either process or containers) for starting out, unless you’re really familiar with it. Anything Unix based is easier to use and cheaper (especially by way of servers).
In this guide, I’ll be sticking to Linux containers.
If you’re not familiar with what Docker is, here’s a guide. In essence, it’s a way to containerize your code (Read: packing all of your application’s code + its dependencies in 1 bucket) so it can be used in any environment easily.
Here's the link to the official documentation on local debugging. However, it is tech-stack agnostic and gives you multiple options (Choosing between Windows & Linux containers.) My guide focuses explicity on Unity server builds with Linux containers.
Necessities
- Assuming you've already installed the PlayFab SDK from the Editor Extension above (if not, do it now),
- Grab the PlayFab GSDK from here. Place the MultiplayerAgent folder in your own PlayFab SDK folder,
- Make sure you have Mirror’s NetworkManager (or the equivalent if you’re not using Mirror) attached to a GameObject of your choice.
Create a new GameObject, call it AgentListener
(or whatever you like). Add a script named AgentListener.cs
on it as well.
public class AgentListener : MonoBehaviour {
private void Start ()
{
#if UNITY_SERVER
PlayFabMultiplayerAgentAPI.Start();
StartCoroutine(ReadyForPlayers());
#endif
}
}
You can also add these callbacks if you want. I personally had something like this (Set this up in Start()
again):
private void Start() {
// Rest of the code from above
PlayFabMultiplayerAgentAPI.IsDebugging = Debugging;
PlayFabMultiplayerAgentAPI.OnMaintenanceCallback += OnMaintenance;
PlayFabMultiplayerAgentAPI.OnShutDownCallback += OnShutdown;
PlayFabMultiplayerAgentAPI.OnServerActiveCallback += OnServerActive;
PlayFabMultiplayerAgentAPI.OnAgentErrorCallback += OnAgentError;
}
public void OnMaintenance() { }
public void OnShutdown() { }
public void OnServerActive() { }
public void OnAgentError() { }
Setup the transport of your choice (for example in Mirror, a popular one is KCP transport). Set 7777 in the Port
field of the transport you're using.
Build your server. (Make sure it’s PC, Mac & Linux Standalone
->Linux x86_64
).
Go to the folder where your game server is present.
Add a Dockerfile like so:
touch Dockerfile
Your folder should now look like this:
Add the following to your Dockerfile:
FROM ubuntu:18.04
RUN apt-get update && apt-get install -y ca-certificates
ADD . .
CMD ["/game/UnityServer.x86_64", "-nographics", "-batchmode"]
You need the second line to install certificates, in case you want to be able to talk to SDKs that talk over HTTPS, such as AWS (I had to do this in my case).
You’re all setup now. If you build this folder as a docker image and run it as a container, you’re free to connect as a client (either from your Unity Editor, or a standalone build on your machine) on IP 127.0.0.1
and port 56100
.
Remember, when you build your server, port must be the server port you want to expose (in our case, 7777). When you connect as a client, use the Connecting Port (in our case, 56100).
To test, you want to grab the PlayFabVMAgent from here. This is used to test running your container locally. If your client (let’s assume your Unity Editor) is able to connect to this, then that confirms your integration is working.
cd
into your PlayFabVM agent folder in PowerShell, and run SetupLinuxContainersOnWindows.ps1
. This sets up the docker network you need for PlayFab to run.
After extracting the VM agent, cd
into the folder and open the Multiplayersettings.json
file. Make sure it looks like this:
"RunContainer": true,
"OutputFolder": "C:\\output\\UnityServerLinux",
"NumHeartBeatsForActivateResponse": 5,
"NumHeartBeatsForTerminateResponse": 150,
"AgentListeningPort": 56001,
"GameCertificateDetails": [],
"PortMappingsList": [
[
{
"NodePort": 56100,
"GamePort": {
"Name": "game_port",
"Number": 7777,
"Protocol": "UDP"
}
},
{
"NodePort": 56200,
"GamePort": {
"Name": "game_port_2",
"Number": 7778,
"Protocol": "TCP"
}
}
]
],
"ContainerStartParameters": {
"ImageDetails": {
"Registry": "myregistry.io",
"ImageName": "linuxgameserver",
"ImageTag": "0.1",
"Username": "",
"Password": ""
}
},
"SessionConfig": {
"SessionId": "ba67d671-512a-4e7d-a38c-2329ce181946",
"SessionCookie": null,
"InitialPlayers": ["Player1", "Player2"]
},
"TitleId": "",
"BuildId": "00000000-0000-0000-0000-000000000000",
"Region": "WestUs"
}
Note the PortMappingsList
. If your game server runs with multiple transports (in my case, Mirror's KCP (UDP-based) for all devices and Mirror's SimpleWebTransport (TCP-based) for WebGL clients).
Then build your docker image, after cd
ing into your game server folder.
docker build -t myregistry.io/linuxgameserver:0.1 .
Since you ran SetupLinuxContainersOnWindows.ps1
, a new docker network will be created.
You can verify this worked by typing docker network ls
. You will see playfab
as a network that was just created.
Finally, you can run LocalMultiplayerAgent.exe -lcow
. This starts your image as a container, which is responsible for starting your game server locally.
You can now connect to it from your Unity Editor. Use IP address 127.0.0.1
and port 56100
in your hostname field and transport’s port field respectively of your Network Manager.
You should see your PowerShell transitioning between the following states:
- Initialized,
- StandingBy
- Active
- Terminated
When your container is in the Active
state, that’s when you can connect as a client.
Microsoft's link to deploying a game build is here. You can continue to follow this guide to get up and running quickly, but use theirs for a detailed breakdown of things you may need information of.
Requirements
- WSL2,
- Azure Container Registry details,
- Docker
You can get your customer id, username and password under Server Details
when creating a new build. Search for “Upload to container registry”.
You need WSL2 setup to be able to push your docker image onto Microsoft's Azure container registry. There are plenty of guides online to set it up, I will leave it to you, the reader.
Assuming you’ve setup WSL2 at this point, navigate to where you have your game server’s image in an Ubuntu (or other Linux-distro based) terminal, and run the following:
Open your Windows Terminal, and open a new Ubuntu 20.04 (or whatever distro you setup for WSL) shell. Navigate to where your game server build is. Will look like this:
When here, run the following commands: Commands to build and host your new server:
Login to your Azure Container Registry:
docker login yourcustomerid.azurecr.io
Build your local container:
docker build -t yourcustomerid.azurecr.io/containername:v1 .
Push your container into their container registry:
docker push yourcustomerid.azurecr.io/containername:v1
To enable the Multiplayer Servers feature, you need a credit card first. Once you put in your details, you will be allowed to create new server builds.
Next, we shall create a build.
In here, do the following steps:
- Give your build a suitable name,
- Pick Linux Containers,
- Pick the virtual machine type (Dasv4 — 2 cores is fine for now) and pick 1 server per machine (You can vary these after you do significant load testing.),
- Pick the container you just deployed onto the Azure Container Registry,
- You can set Standby and Max servers to 1 for now, for testing purposes,
- Expose ports 7777 on UDP, (this will vary depending on what you chose the port to be when creating your server build),
- Add a region. North Europe/America is fine since you get 750 free hours for testing purposes,
- Hit “Add Build”!
Once your build is created (and assuming you have at least 1 server available), head over to the Servers
tab in your build, and hit “Request Server” on the top right corner. This will immediately spin up a server for you in one of your existing available VMs.
Grab the IP and Port that it gives you, start your game client in your Editor or wherever else, use the IP to populate the host name, and port for the port field, (Assuming you’re using KCP/Telepathy/SimpleWebTransport here), and you should be able to connect!
Standard hosting requires that you connect to an IP (or Fully Qualified Domain Name [FQDN]) and Port given to you by PlayFab’s newly spun up server as a client. This is achievable on all types of devices, including but not limited to phone, consoles, PC etc.
When you create a Unity WebGL client however (to put your game on the web), you’ll have an issue because a client cannot connect directly to an IP and Port on an https domain. (You can connect if your website is not Secure, however).
You also cannot use the FQDN here because PlayFab’s Fully Qualified Domain Names are not SSL secured by default.
This poses a problem, because most legitimate websites will want to have SSL/TLS security, so you cannot compromise by connecting to a WebSocket server that is not secure.
Your end goal is to connect to a url like this: wss://mydomain.xyz/{data}
where data
decides which server is picked to connect to.
First off, In Mirror, you want to use Simple Web Transport for your client. In case you are supporting multiple platforms (WebGL, phone etc) you want to use a Multiplexer
in Mirror, and use that as the Transport in your NetworkManager
. You can follow similar steps for whatever other networking library you are using, but the point is that your server executable can serve a WebSocket connection over a domain if configured correctly.
This problem can be solved by using a Reverse Proxy.
This link substantiates the problem and my conversation with Austin ended up yielding fruitful results. Setting up a reverse proxy is out of the scope of this guide, but I will leave you with a few useful links: https://www.nginx.com/blog/websocket-nginx/ (I used NGINX in my working example)
https://github.com/PlayFab/MultiplayerServerSecureWebsocket
As discussed in the PlayFab Community post above, scale is going to be a problem, because all your clients are going to talk to your reverse proxy. Luckily, nginx and YARP both are built for scale, so it’s up to you, the reader, to figure it out. (If you hit big scale, you’re lucky enough to have that problem in the first place, and you’re bound to figure out a better solution for it than I am.)
Also, don’t be afraid of using a Reverse Proxy here. One of the core features of Nginx and other Reverse Proxies is SSL/TLS Termination, which means that they are meant to talk to the internal servers (in this case, PlayFab’s servers) without the overhead of SSL for performance purposes. Your connection is still secure because from the client’s perspective, you’re only talking to the secured reverse proxy.