Connecting essential signals

In this part, we will wrap up the code by setting up our database using the W4 mapper. Then, we will connect the necessary signals to know when a connection was established, failed, or lost.

Let's start by adding two additional signals accessible from anywhere in our codebase (through the GameState autoload). They let us know when a connection failed or succeeded.

Add these two signals near the top of game_state.gd:

## Emitted when the player could not connect.
signal connection_failed()
## Emitted when the player could connect successfully.
signal connection_succeeded()

Then, let's wire things together in the _ready() function. Add the following code to your script:

func _ready() -> void:

    # This sets up the database using the code we wrote a couple of parts ago.
    DatabaseManager.setup_mapper(W4GD.mapper)

    # Here, we detect if we failed to authenticate with the server,
    # using Godot's built-in MultiplayerAPI.peer_authentication_failed signal.
    multiplayer.peer_authentication_failed.connect(
        func _peer_authentication_failed(p_peer_id: int) -> void:
            if p_peer_id == 1:
                connection_failed.emit()
    )

    # We connect W4's signals to the lobby functions we wrote when adding the lobby and matchmaking code.
    W4GD.game_server.player_joined.connect(_on_player_joined)
    W4GD.game_server.player_left.connect(_on_player_left)

    # On the players' machines, we need to know when the connection succeeds or fails.
    if not is_server():
        multiplayer.connected_to_server.connect(
            func _connected_ok() -> void:
                connection_succeeded.emit()
        )
        multiplayer.connection_failed.connect(
            func _connected_fail() -> void:
                # If the connection failed, we clear the multiplayer peer.
                multiplayer.multiplayer_peer = null
                connection_failed.emit()
        )
        # If the player gets disconnected during a game round, we instantly close the game,
        # sending back to the lobby selection screen.
        multiplayer.server_disconnected.connect(
            func _server_disconnected() -> void:
                game_error.emit("Server disconnected")
                close_game()
        )


## Returns `true` if the current Godot instance is a server
func is_server() -> bool:
    return W4GD.game_server.is_server()

Here's a breakdown of the important parts:

  1. First, we run the W4 database mapper with DatabaseManager.setup_mapper(W4GD.mapper). This ensures that querying a Profile from the database will return an instance of the Profile class we defined in database_manager.gd.

  2. Then, we connect to W4's W4GD.game_server.player_joined and W4GD.game_server.player_left signals, which emit when a player joins or leaves a lobby.

  3. Finally, we make sure that clients can get feedback on their connection status. The if statement is not strictly necessary since those signals never run on the server, but it makes the code clearer for fellow developers.

You may wonder why this small is_server() method exists. With it, the rest of the game only ever needs to know about our GameState autoload, which encapsulates W4 functionality neatly. If we wanted to add unit tests to the game's networking code, we would only have to do so in the GameState class.

And with that, you're done with the code! Congratulations!

It's time to try it out! In the next part, we'll export the game and upload it to the W4 servers, which will allow you to play online with friends.