A minimal Godot project with cross-platform authentication and matchmaking.
Set up the Godot project as usual. Some export platforms require extra configuration.
We manage a custom fork of the official godot-ios-plugins
repo in plugins/godot-ios-plugins
, built for Godot 4.2.
Refer to the iOS build document.
We manage a custom fork of Iakobs
/godot-play-games-services
to reduce global namespace conflicts in plugins/godot-play-games-services
.
Refer to the Android build document.
We currently manage our services internally with Docker Compose, with an NGINX reverse proxy on top of the whole layer for TLS.
Refer to this guide on deploying the services to a remote host using Docker Contexts.
docker compose build
docker compose push
docker context create {context_name} --docker "host=ssh://{remote_user}@{remote_ip}"
The secrets/
directory needs to be copied to all remote hosts with the exact same absolute location before deploying the project due to the bind mount requirement.
# On the remote host
sudo mkdir -p {absolute_path_to_secrets}/secrets
# Change the owner of the newly created directory
sudo chown -R {remote_user} {absolute_path_to_secrets}
# On the local host
scp -r secrets/ {remote_user}@{remote_ip}:{absolute_path_to_secrets}/
Then, deploy the services in the remote context.
docker --context {context_name} compose up --detach
# Check the processes
docker --context {context_name} ps
Lastly, refer to the proxy setup document to setup the proxy for the remote host.
We use an NGINX proxy that acts as the main entrypoint to the multiplayer system and provides TLS.
Refer to the proxy setup document.
Different platforms require different authentication strategies, including Steam, Apple Game Center, Google Play Games Services, and OAuth 2.0. All authentication strategies are consolidated and managed by our authentication server.
Refer to the client-side authentication document and the authentication server document.
An NGINX proxy provides TLS by forwarding ports defined below:
Internal service port | External proxy port | Protocol | Description |
---|---|---|---|
18000 |
8000 |
HTTP | The authentication API. |
The matchmaking service matches users together based on several factors.
An NGINX proxy provides TLS by forwarding ports defined below:
Internal service port | External proxy port | Protocol | Description |
---|---|---|---|
18100 |
8100 |
HTTP | The matchmaking API. |
A single host can host multiple game matches by running multiple Docker containers for each game match. The game server manager facilitates the spawning and killing of these containers, assigning an available port for each game.
Communication to the manager service is prohibited from outside the internal network, so a service key is sufficient.
Internal service port | External proxy port | Protocol | Description |
---|---|---|---|
8200 |
- | HTTP | The game server manager. |
Every game match is run as a subprocess spawned and managed by the game server manager.
An NGINX proxy provides TLS by forwarding ports defined below:
Internal service port | External proxy port | Protocol | Description |
---|---|---|---|
19000-19249 |
9000-9249 |
WebSocket | The game server. |
Argument | Description | Default value |
---|---|---|
--server-id |
The unique ID to identify the server in logs. | randi() |
--port |
The port that the server listens for clients on. | 9000 |
The game has exports for Windows, macOS, Linux, iOS, Android, and the Web.
The web client is hosted on a simple webpage and acts like a local game client when its assets are downloaded.
An NGINX proxy provides TLS by forwarding ports defined below:
Internal service port | External proxy port | Protocol | Description |
---|---|---|---|
10443 |
443 |
HTTP | The web client. |
- WebRTC Multiplayer Setup
- Server Authoritative Synchronization
- WebSocket Multiplayer Setup
- Game Server Deployment
- Client-side Authentication
- Steam for Desktop
- Apple Game Center for iOS
- Google Play Games for Android
- OAuth 2.0 / OpenID for Web
-
Scalable Server-Authoritative Multiplayer - Server-side Authentication
- Authentication Server
- Steam for Desktop
- Apple Game Center for iOS
- Google Play Games for Android
- OAuth 2.0 / OpenID for Web
- Game Server Management
- Matchmaking
We initially did use WebRTC for its ability to provide low-latency, real-time, and secure communication between peers across all platforms. Most notably, WebRTC is the only two-way UDP-like protocol that is available on the web platform, since WebSockets rely on a TCP connection.
Our initial approach was to setup a WebRTC peer in the mesh network that was controlled by the game authority. However, deploying the server proved to be a challenge due to failing connectivity establishment for the server's WebRTC peer.
Furthermore, WebRTC required expensive TURN relay servers for the common case where connectivity cannot be directly established, either due to NAT forwarding or firewalls.
The scalability of WebRTC was also a challenge since bandwidth throughout the network scaled polynomially as the number of players increased. If we want to support multiplayer games with more than 4 players, WebRTC will struggle to maintain connectivity and bandwidth efficiency.
Lastly, the complexity of establishing the WebRTC network makes debugging and future maintenance difficult.
If a code example is needed, refer to the webrtc-game-authoritative
tag in the commit history of this repo.
In the future, we could still leverage WebRTC for proximity voice chat or any other non-authoritative system using SceneTree::set_multiplayer
.