Skip to content

A minimal Godot project with cross-platform authentication and matchmaking

Notifications You must be signed in to change notification settings

bryanmylee/godot-multiplayer

Repository files navigation

Godot Multiplayer

A minimal Godot project with cross-platform authentication and matchmaking.

Development Setup

Set up the Godot project as usual. Some export platforms require extra configuration.

iOS and Game Center

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.

Android and Google Play Games Services

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.

Deployment

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.

Network Architecture

Proxy Server

We use an NGINX proxy that acts as the main entrypoint to the multiplayer system and provides TLS.

Refer to the proxy setup document.

Authentication

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.

Matchmaking

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.

Game Server Manager

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.

Game Server

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.

Configuration

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

Game Client

The game has exports for Windows, macOS, Linux, iOS, Android, and the Web.

Web Client

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.

Roadmap

  • 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

Design considerations

Why not use WebRTC for game state replication?

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.