I’m using Godot 4.2.1-stable Linux, Nakama 3.21.1, and the nakama-webrtc godot addon.
The game I’m trying to make is real-time competitive multiplayer with 2, 4, 6, or 8 players (2 teams).
I have followed along with the tutorials I could find but am not satisfied with the “click a button and automagically get put in a game” user experience of the matchmaking. Or the “copy paste match ID” thing. So I definitely want to go the “match listing” route.
I envisioned a panel on the right that keeps polling the API for matches and displays a custom control for each showing some basic data. Most importantly, the number of players joined over the maximum/ desired number of players- but also the username of the hosting player, how many seconds ago it was created, and a couple of lines of player-entered descriptive text.
Then you click one, and it loads more info about it on the left side- all the players’ names and avatars, maybe map choices and game rule options, the latest chat messages, and a “join” button. When you join, then you can chat with other players, and when the player count is full, you get a “ready” button where the join button was.
Then once everyone clicks “ready”, the lobby match goes away and everyone who was in it is now in a new match that is peer-to-peer over WebRTC.
So I got to trying to populate the UI listing these MatchListItem controls I just made
func set_content( _match_id : String, _players_joined: int, _players_max: int,
_created_by: String, _tick_started: int, _notes ) -> void:
created_by = _created_by
players_max = _players_max
players_joined = _players_joined
seconds_old = round((Time.get_ticks_msec() - _tick_started) / 1000)
match_id = _match_id
notes = _notes
player_count_label.text = str( players_joined ) + "/" + str( players_max )
host_name_label.text = created_by
elapsed_time_label.text = str( seconds_old ) + " s"
match_description.text = notes
Each one has its own match id as a property on the instance so clicking it joins that match by ID, as if you’d pasted it in manually.
func _update_match_list() -> void:
#p_session : NakamaSession, p_min : int, p_max : int, p_limit : int, p_authoritative : bool, p_label : String, p_query : String):
var _latest_match_list = await Online.nakama_client.list_matches_async( Online.nakama_session, 1, 7, 50, false, "","" )
for child in open_matches_list.get_children():
child.queue_free()
for _each_match in _latest_match_list.matches:
var _list_item = list_item.instantiate()
open_matches_list.add_child( _list_item )
_list_item.set_content(
"4815162342",
3,
6,
"SomePlayer",
5318008,
"This is a test."
)
And immediately realized I couldn’t get any of the data I wanted to feed to _list_item.set_content. I originally thought I could add a JSON ‘label’ to each match as it was created, but that only works for authoritative server matches- which isn’t what I want. The client-relayed matches have no information on them to list and so are basically only good for doing the blind automatic matchmaking.
So it looks like what I have to do is have the match list list lobbies which are authoritative but are not the actual game matches, which no one needs to find because they aren’t joinable once they’ve started. And the gameplay matches need to be client-relayed, taking advantage of WebRTC, so that the ‘server’ can just be one of the players’ Godot client; not the whole gameplay logic written in Typescript on the backend. So I just need to put all the players from the lobby into a new match.
Am I confused here? I feel like this must be either basically impossible or far easier to do than I’m presuming it to be and I can’t tell which.