Peer-to-peer via WebRTC

Peer-to-peer networking means creating a "mesh" of connections between all the players in the game, as opposed to having a central server that all the players connect to.

WebRTC is a protocol for peer-to-peer networking that's supported natively in Godot.

The main advantage of using WebRTC over Dedicated Servers, is that it's frequently much cheaper, given that you don't need to host game servers.

How does WebRTC work?

Even though the goal is for the players computers to connect directly without a central server, the game clients need to figure out how to find a route to each other. In order to do this, you need access to (at minimum) two different servers:

  • WebRTC signaling server

  • STUN server

The STUN server provides a way for the game clients to open up a port (through any routers that exist in-between) that other game clients can connect to. And the WebRTC signalling server allows one game client to pass this information to another.

W4 Cloud includes a WebRTC signalling server and STUN servers at no additional cost!

However, if two game clients aren't able to connect directly to each other (this can be due to certain kinds of routers that STUN can't punch through), then you'll also need access TURN servers to relay the traffic.

Due to the higher bandwidth requirement, TURN servers do have an additional cost. However, since the majority of your traffic will probably won't need to be relayed through a TURN server, this will still likely be dramatically cheaper than hosting dedicated game servers.

Connecting to a WebRTC lobby

A player can create a WebRTC lobby like this:

var result = await W4GD.matchmaker.create_lobby(
    W4GD.matchmaker.LobbyType.WEBRTC,
    {
        "props": {
            "game_mode": "deathmatch"
        }
    }
).async()

if result.is_error():
    print("ERROR: ", result.message)
    return

var lobby = result.get_data()

Any WebRTC lobby (whether the player created it, or joined another one) will emit a pair of additional signals:

func setup_lobby(lobby):
    lobby.webrtc_mesh_created.connect(_on_webrtc_mesh_created)
    lobby.webrtc_peers_ready.connect(_on_webrtc_peers_ready)

# Emitted when the multiplayer peer is created.
func _on_webrtc_mesh_created(p_multiplayer_peer: WebRTCMultiplayerPeer):
    multiplayer.multiplayer_peer = p_multiplayer_peer

# After it's been created, it can take some time before all the peers
# have successfully connected to each other, and are ready to communicate.
func _on_webrtc_peers_ready():
    # Register ourselves with the "host": the peer arbitrarily selected to be peer id 1,
    # which will be responsible for setting up the match.
    register_player.rpc_id(1)

@rpc(any_peer)
func register_player():
    # This function will be called on the host. We now know that peer_id is ready!
    var peer_id = multiplayer.get_remote_sender_id()

    # Once all peers are ready, tell them to start the match!

Using alternative STUN and TURN servers

If you want to provide your own list of STUN and TURN servers (collectively known as ICE servers), run the following code before creating or joining a WebRTC lobby:

var my_ice_servers := [
    {
        "urls": [
            "stun:global.stun.twilio.com:3478"
        ]
    }
]

W4GD.matchmaker.set_webrtc_ice_servers(my_ice_servers)