Hour 22. Networking
    What You’ll Learn in This Hour:
    Basic concepts about networking for games and how to use UDP and TCP protocols to compete
    Godot high-level networking
    RPC system
    Master and slave synchronization
    With this 22nd hour, it’s time to deal with networking. Synchronizing players across the world to make them feel they play the same game at the
    same time has always appeared as a daunting task. Having a multiplayer mode feature has to be considered early on in the game
    development process to avoid long and painful rewriting of core components. Fortunately, Godot once again saves the day thanks to a shiny
    high-level networking interface!
    TCP, UDP, and Why It Matters
    First things first: when talking about networking protocol, what immediately comes to mind is the TCP/IP stack that powers basically all of the
    internet. The reason behind this is clear: TCP works well with the complexity of the internet (remember, it is not called “the web” for nothing!)
    and makes you feel like everything is simple in the first place:
    It is connection-based, so your server won’t mix the requests sent by multiple clients.
    It guarantees reliability, so you’re sure to get notified if requests cannot reach their destination.
    It guarantees in-order receiving.
    A request can be almost as big as you want, because TCP takes care of splitting them into packets of the correct size.
    All of these points are pretty awesome, but they come at a cost: latency. When a packet is lost, TCP asks the sender again, and when packet n
    arrives, TPC cannot process it if packet n-1 is still in the wild. This is not a big concern for most applications on the internet (you just wait a bit
    longer to get your webpage loaded), but not for a real-time application such as a game!
    Enter UDP, a much rawer protocol that sends a packet to a remote computer: packet lost, ordering, sender identity, and multiple receptions of
    the same packets are none of its concerns. You can use UDP for fine-tuning over handling networking. This allows you to go much faster at the
    price of complexity.
    This is where Godot’s high-level networking system comes in: it handles UDP complexity for us and integrates it inside its Scene system,
    making a multiplayer game seem like a single-player game where you set each node to either synchronize with a remote player or send
    synchronization information about its current state to other players.
    NOTE
    Use Raw UDP/TCP
    In addition to its high-level networking system, Godot also offers classical UDP and TCP client/server capability with StreamPeerTCP,
    TCP_Server, and PacketPeerUDP classes. This is useful if you want to write your custom game server or connect to a third-party API.
    Managing Connections
    Enough with theory! To connect multiple Godot instances, we need to configure one of them as a server and connect the others as clients to it
    (Listing 22.1).
    LISTING22.1 Creating Connection
    Click here to view code image
    # For the server
    func hostgame(port):
    var host = NetworkedMultiplayerENet.new()
    host.create_server(port)
    get_tree().set_network_peer(host)
    # For the clients
    func join_game(ip, port):
    var host = NetworkedMultiplayerENet.new()
    host.create_client(ip, port)
    get_tree().set_network_peer(host)
    We create a NetworkedMultiplayerENet instance, configure it as a server or client, and define it as the one to use for our Scene Tree. Note
    that the Godot network API is defined in the abstract NetworkedMultiplayerPeer class, from which NetworkedMultiplayerENet is an
    implementation using the ENet library.
    Once our network peer is defined on eachGodot instance, we are notified of network activity by signals:
    network_peer_connected: A new Godot instance joins the server. This signal is triggered on each peer (not only on the server) and
    111111111
    22222222the newly connected ones get this signal numerous times (one per peer is already connected before it arrives).
    network_peer_disconnected: Triggered on each peer when someone left (except on the leaving peer).
    connected_to_server: Triggered on the newly connected peer once connection has been achieved.
    connection_failed: Triggered when the connection has failed with the server.
    server_disconnected: Connection with the server has been lost, so other peers get a network_peer_disconnected signal.
    NOTE
    Beware of Firewalls
    Be careful when choosing a port for your game! While it is easy to remember, low number ports (like TCP 80 used by HTTP) are most of the
    time only accessible to users with advanced privileges (e.g., administrator). So, you should choose a port higher than 1023 and make sure it is
    not already in use by some other application.
    Finally, when you want to close the connection, simply remove the network peer from the Scene Tree (Listing 22.2).
    LISTING22.2 Closing Connection
    Click here to view code image
    func finish_game(port):
    get_tree().set_network_peer(null)
    Note that this works the same for both the client and server sides.
    Remote Procedure Call
    Let’s make our multiple Godot instances talk! For this, we can use what is called RPC (Remote Procedure Call), which consists of triggering
    from a peer the call of a procedure on one or multiple other peers. Be careful that you are talking of “procedure” and not “function,” because the
    second procedure doesn’t return any value to the caller (so it’s a fire-and-forget call). Godot provides the following RPC methods:
    Node.rpc: Regular RPC call; use it to call one of the node’s procedure.
    Node.rset: Same as RPC, but used to remotely set a node’s property.
    Node.rpc_id/rset_id: Instead of sending the procedure to all of the peers, we can use those methods to only send the procedure on a
    given peer by providing its network ID.
    Node.rpc_unreliable/rset_unreliable/rpc_unreliable_id/rset
    **

    unreliable_id: Finally, these are the unreliable versions of the
    precedent methods. This means it’s possible your procedure won’t be received at all (remember how UDP works?).
    Remote and Sync Keywords
    That said, RPC can be a dangerous tool if not well controlled: what would happen if you allowed a complete stranger from across the globe to
    call any function of your Godot instance? (Remember Hour 12, when you had access to the entire user’s filesystem from Godot?) To prevent
    anything like that, a function (or a property) must be explicitly flagged as allowed to be called by RPC with a keyword (Listing 22.3):
    sync: the procedure is called by all peers (including the caller).
    remote: the procedure is only called on the remote peer and not on the caller.
    LISTING22.3 Using Remote and Sync Keywords
    Click here to view code image
    var speed = Vector2(0, -200)
    sync var alive = true
    remote func update_pos_for_remotes(new_pos):
    position = new_pos
    func _process(delta):
    if is_network_master():
    position += speed * delta
    if position.y < 0:
    position.y = 0
    rset(“alive”, false)
    rpc_unreliable(“update_pos_for_remotes”, position)
    Note: Beware of network congestion.
    Keep in mind that using RPC, even unreliable, on each frame is costly and won’t scale well beyond the local network or a few player games, so
    use the fixed timer for such a task.
    Listing 22.3 illustrates how to use these keywords: we have a node falling down, and when it hits the ground, it gets killed. Once per frame,
    process gets called to update the state of the node on the peer responsible for it (that’s what is_network_master() tells you, but more on this
    later).
    Now this peer needs to tell the other ones about the new position of this node. Thus, it uses the RPC call on
    update_pos_for_remotes, which
    updates all of the peers except itself. Note that we use
    rpc_unreliable here given that the call is done for every frame, so missing one is not as
    much of a concern.
    111111111
    22222222Finally, when the node hits the ground, we need to set the property
    alive to false. This time, even the peer responsible for the node must have
    this property updated, so we flag it as
    sync and let the rset call update every peer, including ourselves at the same time.
    Slaves and Masters
    Even if
    remote and sync are pretty cool, they fall short on something: exploit protection. Given that any peer can do a RPC on remote or sync
    procedure that will impact all the other peers, it’s pretty easy for a client to impersonate the server and trick the game.
    In our previous example, we could have a malicious client using the
    rset (alive, false) to kill a node even if it is not responsible for it.
    To solve this, Godot has a concept of master/slave that is set on a per-node basis for each peer. Remember the
    is_network_master() from
    the last paragraph? It returns
    true if the peer on which the code is executed is in charge (i.e., the master) of the current node.
    By default, the server is set as master of all the nodes in the
    Scene Tree. Later on, when clients start connecting, they can agree that a node is
    managed by a specific peer. This means you should make sure a node has only a single peer declared as master; otherwise, strange things
    will happen.
    Also note that the default
    set_network_master() configures a node slave/master property (Listing 22.4) as well as all of its children in the
    Scene Tree, but you can disable this behavior by setting false as a second parameter.
    LISTING22.4 Declaring a Peer Master of a Node
    Click here to view code image
    var player_scene = preload(“res://scenes/player.tscn”)
    func peer_joined(peer_id)
    var player = player_scene.instance()
    get_tree().get_root().add_child(player)
    player.set_network_master(peer_id)
    Now you can
    use is_network_master() (Listing 22.5) to separate the task that should only run on the master, typically processing a player’s
    user input.
    LISTING22.5 Filtering Input Processing Depending on Node’s Master Property
    Click here to view code image
    func _update(delta)
    if is_network_master():
    if Input.is_action_pressed(“ui_up”):
    # Do something
    Mixing
    sync/remote and is_network_master() can be cumbersome, so the master and slave keywords have been created to simplify
    things. As you can guess from their names, a procedure flagged with
    master is only executed on the peer declared as master for the node. On
    the other hand,
    slave is executed on the other peers (Figure 22.1).
    FIGURE 22.1
    Typical live Scene Tree view of each peer with master (in green) and slave (in red) nodes.
    This allows really powerful synchronization patterns in which a master gets notification from slaves (with the latter using RPC on a
    master
    procedure) and sends a synchronization command to them (RPC on a slave procedure) while being sure no malicious slave can impersonate
    himself (a slave using RPC on
    slave procedure gets only called on itself!).
    In noncompetitive or co-op games, exploits are a small concern. Depending on your use case, it can be necessary to avoid using
    remote and
    sync keywords, given how they can be used by any slave and offer no protection against malicious use.
    LISTING22.6 Replacing Sync by Slave
    Click here to view code image
    slave func update_score(new_score)
    score = new_score
    func _on_player_killed():
    if is_network_master(): # Score should be handled only by the master
    rpc(“update_score”, score + 100)
    update_score(score + 100)
    A common pattern to replace
    sync is to declare your procedure as a slave (Listing 22.6), then call it both as RPC (to synchronize all of the
    slave peers) and directly as a regular function (to execute the function locally). This way, you’ll get the procedure called everywhere when
    triggered from the master without the risk of exploits when used by a malicious slave.
    TRY IT YOURSELF
    Test the Synchronization
    A great way to understand networking is to try it on a really simple project:
    111111111
    22222222
    1. Create a very basic GUIwith a couple of buttons and a label. See Figure 22.2.
    FIGURE 22.2
    A basic GUI.
    2. Connect the functions provided in Listing 22.1 to the client/server buttons.
    3. Create a _update_text function, adding a line of log to the Label and multiple functions calling this _update_text, while flagging
    with different network attributes. See Figure 22.3.
    FIGURE 22.3
    Finding a static mesh asset in the content browser.
    4. Connect the ping button to a function making rpc, rpc_id or direct call of our network function.
    5. Finally, launch your project and test with multiple configurations. It’s really informative to mess around to see what happens (like
    having multiple servers or setting multiple peers as master).
    Visual Script
    As you just saw, networking is a lot about scripting: you must dynamically configure who is slave and master (given peers are not known
    beforehand), then use RPC to call script functions as a procedure. So far, we’ve only showed examples withGDScript because it is the most
    common way to script withGodot, but this doesn’t mean you cannot use VisualScript for networking (Figure 22.4).
    FIGURE 22.4
    Using networking with VisualScript.
    As you can see in Figure 22.4, VisualScript provides an RPC dropdown menu to configure the network attribute on a function. To call the
    procedure, you can use the
    CallSelf box configured on the RPC method (this is exactly the same as calling Node.rpc withGDScript).
    Summary
    In this hour, you learned about networking and how Godot simplifies this area through its high-level networking system. You saw how to
    configure and connect client and server. Then you learned how to use RPC to synchronize across network peers. Finally, you learned how to
    use the keywords
    sync, remote, master, and slave to decorate your procedures and use more powerful synchronization patterns by using the
    per-peer and per-node master/slave properties. Networking is a complex beast with many concerns (typically designing your procedures to
    avoid exploits from malicious clients, or keeping the amount of data low to synchronize and avoid latency), but you already have a good
    overview of what Godot has to offer.
    Q&A
    Q. Is there a way to determine ahead of time the network ID of the peers?
    A. Server ID is always 1, so it can be safely hardcoded in your game; however, clients get unique, randomly generated IDs at connection
    time.
    Q. How can you determine if the current node is master or slave?
    A. You can use the Node.is_network_master() method, which returns a Boolean.
    Q. Can I set up a dedicated server for my game with Godot?
    A. By default, Godot ships as a full-grown game engine with 2D/3D renderer and audio engine. This is perfectly normal when used by a
    player, but gets really annoying when you want to make it run on a headless server without GPU and a fraction of the CPU and RAM of a
    modern gaming PC.
    However, a server version of Godot is available on the official website (it currently supports Linux 64bits, which is a great choice as a
    server).
    Workshop
    See if you can answer the following questions to fix your knowledge.
    Quiz
    1. What happens if you do a RPC on a sync procedure from a slave node?
    2. What is the difference between master/slave and client/server?
    111111111
    22222222
    3. Can I have two masters on the same node in my game?
    4. What happens if I don’t explicitly define who’s the master for a node?
    5. Given a sync func foo() function, what is the difference between foo(), rpc(‘foo’), and rpc_id(1, ‘foo’)?
    Answers
    1. The procedure gets called on all the peers (including ourselves).
    2. Server/client is only a matter of a network connection. Master/slave defines which peer manages a given node and sends synchronization
    to the others.
    3. Strictly speaking, you can, but both peers will refuse to execute slave RPC and won’t send master RPC through the network, so your
    game will desynchronize pretty fast. So don’t do that.
    4. By default, the server is the master of all nodes.
    5. foo() calls the function locally only, rpc(‘foo’) calls the function locally and on each peer (given function is marked sync), and rpc_id(1,
    ‘foo’) calls the function only on the remote peer with ID 1 (i.e., the server).
    Exercises
    The best way to work with networking is to take an existing single-player game and convert it to a multiplayer game:
    1. Modify the space shooter from Hour 5 to add a lobby so that the game only starts when a client connects to a server. Once started, client
    and server each have their own game independent from each other.
    2. Now start synchronizing by providing a spectator mode so that only the server process with which the player inputs and synchronizes
    game state is a connected client. This is done by flagging its functions as sync and using RPC instead of direct calls.
    3. Finally, provide a co-op mode: when a peer connects, add a new ship to the scene (a new peer should be master of this ship node).
    Don’t forget to check
    is_network_master() **before processing player input to have a peer controlling only its own ship.
    111111111
    22222222