The following explains the differences of high- and low-level networking in Godot as well as some fundamentals. If you want to jump in head-first and add networking to your first nodes, skip to `Initializing the network`_ below. But make sure to read the rest later on!
Godot always supported standard low-level networking via UDP, TCP and some higher level protocols such as SSL and HTTP.
These protocols are flexible and can be used for almost anything. However, using them to synchronize game state manually can be a large amount of work. Sometimes that work can't be avoided or is worth it, for example when working with a custom server implementation on the backend. But in most cases, it's worthwhile to consider Godot's high-level networking API, which sacrifices some of the fine-grained control of low-level networking for greater ease of use.
This is due to the inherent limitations of the low-level protocols:
- TCP ensures packets will always arrive reliably and in order, but latency is generally higher due to error correction.
It's also quite a complex protocol because it understands what a "connection" is, and optimizes for goals that often don't suit applications like multiplayer games. Packets are buffered to be sent in larger batches, trading less per-packet overhead for higher latency. This can be useful for things like HTTP, but generally not for games. Some of this can be configured and disabled (e.g. by disabling "Nagle's algorithm" for the TCP connection).
- UDP is a simpler protocol, which only sends packets (and has no concept of a "connection"). No error correction
makes it pretty quick (low latency), but packets may be lost along the way or received in the wrong order.
Added to that, the MTU (maximum packet size) for UDP is generally low (only a few hundred bytes), so transmitting
larger packets means splitting them, reorganizing them and retrying if a part fails.
In general, TCP can be thought of as reliable, ordered, and slow; UDP as unreliable, unordered and fast.
Because of the large difference in performance, it often makes sense to re-build the parts of TCP wanted for games (optional reliability and packet order), while avoiding the unwanted parts (congestion/traffic control features, Nagle's algorithm, etc). Due to this, most game engines come with such an implementation, and Godot is no exception.
In summary, you can use the low-level networking API for maximum control and implement everything on top of bare network protocols or use the high-level API based on `SceneTree` that does most of the heavy lifting behind the scenes in a generally optimized way.
It can make your application vulnerable if done wrong and may lead to cheats or exploits.
It may even allow an attacker to compromise the machines your application runs on
and use your servers to send spam, attack others or steal your users data if they play your game.
This is always the case when networking is involved and has nothing to do with Godot.
You can of course experiment, but when you release a networked application,
always take care of any possible security concerns.
Mid level abstraction
---------------------
Before going into how we would like to synchronize a game across the network, it can be helpful to understand how the base network API for synchronization works.
This object extends from `PacketPeer`, so it inherits all the useful methods for serializing, sending and receiving data. On top of that, it adds methods to set a peer, transfer mode, etc. It also includes signals that will let you know when peers connect or disconnect.
To initialize high-level networking, the SceneTree must be provided a NetworkedMultiplayerPeer object.
To create that object, it first has to be initialized as a server or client.
Initializing as a server, listening on the given port, with a given maximum number of peers:
::
var peer = NetworkedMultiplayerENet.new()
peer.create_server(SERVER_PORT, MAX_PLAYERS)
get_tree().network_peer = peer
Initializing as a client, connecting to a given IP and port:
::
var peer = NetworkedMultiplayerENet.new()
peer.create_client(SERVER_IP, SERVER_PORT)
get_tree().network_peer = peer
Get the previously set network peer:
::
get_tree().get_network_peer()
Checking whether the tree is initialized as a server or client:
::
get_tree().is_network_server()
Terminating the networking feature:
::
get_tree().network_peer = null
(Although it may make sense to send a message first to let the other peers know you're going away instead of letting the connection close or timeout, depending on your game.)
connections at any point (see `set_refuse_new_network_connections(bool)` and related methods on `SceneTree`). To manage who connects, Godot provides the following signals in SceneTree:
These IDs will be useful mostly for lobby management and should generally be stored, as they identify connected peers and thus players. You can also use IDs to send messages only to certain peers.
- Reliable: when the function call arrives, an acknowledgement will be sent back; if the acknowledgement isn't received after a certain amount of time, the function call will be re-transmitted.
- Unreliable: the function call is sent only once, without checking to see if it arrived or not, but also without any extra overhead.
In most cases, reliable is desired. Unreliable is mostly useful when synchronizing object positions (sync must happen constantly,
and if a packet is lost, it's not that bad because a new one will eventually arrive and it would likely be outdated because the object moved further in the meantime, even if it was resent reliably).
In most games, the goal of multiplayer networking is that the game runs synchronized on all the peers playing it.
Besides supplying an RPC and remote member variable set implementation, Godot adds the concept of network masters.
Network master
^^^^^^^^^^^^^^
The network master of a node is the peer that has the ultimate authority over it.
When not explicitly set, the network master is inherited from the parent node, which if not changed, is always going to be the server (ID 1). Thus the server has authority over all nodes by default.
with the function `Node.set_network_master(id, recursive)` (recursive is `true` by default and means the network master is recursively set on all child nodes of the node as well).
Checking that a specific node instance on a peer is the network master for this node for all connected peers is done by calling `Node.is_network_master()`. This will return `true` when executed on the server and `false` on all client peers.
If you have paid attention to the previous example, it's possible you noticed that each peer was set to have network master authority for their own player (Node) instead of the server:
::
[...]
# Load my player
var my_player = preload("res://player.tscn").instance()
my_player.set_name(str(selfPeerID))
my_player.set_network_master(selfPeerID) # The player belongs to this peer; it has the authority.
var player = preload("res://player.tscn").instance()
player.set_name(str(p))
player.set_network_master(p) # Each other connected peer has authority over their own player.
get_node("/root/world/players").add_child(player)
[...]
Each time this piece of code is executed on each peer, the peer makes itself master on the node it controls, and all other nodes remain as puppets with the server being their network master.
To clarify, here is an example of how this looks in the