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:
First, we run the W4 database mapper with
DatabaseManager.setup_mapper(W4GD.mapper)
. This ensures that querying aProfile
from the database will return an instance of theProfile
class we defined indatabase_manager.gd
.Then, we connect to W4's
W4GD.game_server.player_joined
andW4GD.game_server.player_left
signals, which emit when a player joins or leaves a lobby.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.