The Lobbies API lets you create multiplayer rooms where players can gather before or during gameplay. Lobbies support real-time messaging, metadata storage, and automatic P2P connection setup.
Listening for LOBBY_JOINED
Both createLobby() and joinLobby() put the current player into a lobby, and in both cases the SDK fires a LOBBY_JOINED event once membership is confirmed. This is your single source of truth for "I'm now in a lobby" — subscribe before you call create or join, then drive your UI from the event handler.
func _ready():
WavedashSDK.lobby_joined.connect(_on_lobby_joined)
func _on_lobby_joined(payload):
var lobby_id = payload["lobbyId"]
var users = payload["users"]
var host_id = payload["hostId"]
print("Joined ", lobby_id, " with ", users.size(), " players")
void Awake()
{
Wavedash.SDK.OnLobbyJoined += OnLobbyJoined;
}
void OnLobbyJoined(Dictionary<string, object> payload)
{
string lobbyId = (string)payload["lobbyId"];
var users = (List<object>)payload["users"];
string hostId = (string)payload["hostId"];
Debug.Log($"Joined {lobbyId} with {users.Count} players");
}
Wavedash.on(Wavedash.Events.LOBBY_JOINED, (payload) => {
console.log(`Joined ${payload.lobbyId} with ${payload.users.length} players`);
});
Creating a lobby already joins it. Do not call joinLobby() with the ID returned by createLobby() — the player is in the lobby as soon as LOBBY_JOINED fires, and calling join again will error.
Creating a lobby
Make sure your LOBBY_JOINED listener is wired up first (see above), then call create. The returned lobby ID is useful for invite links and logging, but you do not need to call joinLobby() with it.
func create_lobby():
await WavedashSDK.create_lobby(WavedashConstants.LOBBY_TYPE_PUBLIC, 4)
# lobby_joined signal fires once the player is in — handle your UI there
public async void CreateLobby()
{
// OnLobbyJoined (wired up in Awake) fires once the player is in.
await Wavedash.SDK.CreateLobby(
WavedashConstants.LobbyVisibility.PUBLIC,
maxPlayers: 4);
}
// LOBBY_JOINED fires once the player is in — handle your UI there.
await Wavedash.createLobby(Wavedash.LobbyVisibility.PUBLIC, 4);
Visibility options
| Value | Constant | Description |
|---|---|---|
0 | PUBLIC | Anyone can find and join |
1 | FRIENDS_ONLY | Only friends can see and join |
2 | PRIVATE | Only joinable with the lobby ID |
In JavaScript use Wavedash.LobbyVisibility.PUBLIC / FRIENDS_ONLY / PRIVATE.
Joining and listing
Same rule as creating: set up the LOBBY_JOINED listener first, then call joinLobby().
# Make sure lobby_joined is connected before calling join_lobby (see above).
var response = await WavedashSDK.list_available_lobbies()
if response.success and response.data.size() > 0:
WavedashSDK.join_lobby(response.data[0].lobbyId)
// Make sure OnLobbyJoined is subscribed before calling JoinLobby (see above).
var lobbies = await Wavedash.SDK.ListAvailableLobbies();
if (lobbies != null && lobbies.Count > 0)
await Wavedash.SDK.JoinLobby((string)lobbies[0]["lobbyId"]);
// Make sure LOBBY_JOINED is listened for before calling joinLobby (see above).
const response = await Wavedash.listAvailableLobbies(); // pass true for friends only
if (response.success && response.data.length > 0) {
await Wavedash.joinLobby(response.data[0].lobbyId);
}
Leaving a lobby
Call leaveLobby() when the player intentionally exits — returning to the main menu, disconnecting, or swapping rooms. The server removes them from the lobby and notifies the remaining members via LOBBY_USERS_UPDATED. If the player was the host, hosting transfers to the next member automatically.
await WavedashSDK.leave_lobby(lobby_id)
await Wavedash.SDK.LeaveLobby(lobbyId);
await Wavedash.leaveLobby(lobbyId);
You do not need to call leaveLobby() when the tab closes — the session ends and the server cleans up membership automatically.
Lobby users
var users = WavedashSDK.get_lobby_users(lobby_id)
var host_id = WavedashSDK.get_lobby_host_id(lobby_id)
var count = WavedashSDK.get_num_lobby_users(lobby_id)
var users = Wavedash.SDK.GetLobbyUsers(lobbyId);
var hostId = Wavedash.SDK.GetLobbyHostId(lobbyId);
int count = Wavedash.SDK.GetNumLobbyUsers(lobbyId);
const users = Wavedash.getLobbyUsers(lobbyId);
const hostId = Wavedash.getLobbyHostId(lobbyId);
const count = Wavedash.getNumLobbyUsers(lobbyId);
Messaging
WavedashSDK.send_lobby_chat_message(lobby_id, message)
func _ready():
WavedashSDK.lobby_message.connect(_on_lobby_message)
func _on_lobby_message(payload):
print(payload["username"], ": ", payload["message"])
Wavedash.SDK.SendLobbyChatMessage(lobbyId, message);
void Awake() { Wavedash.SDK.OnLobbyMessage += HandleMessage; }
void HandleMessage(Dictionary<string, object> data)
{
Debug.Log($"{data["username"]}: {data["message"]}");
}
Wavedash.sendLobbyMessage(lobbyId, "Hello everyone!");
Wavedash.on(Wavedash.Events.LOBBY_MESSAGE, (payload) => {
console.log(`${payload.username}: ${payload.message}`);
});
Messages have a maximum length of 500 characters.
Invites
WavedashSDK.invite_user_to_lobby(lobby_id, user_id)
func _ready():
WavedashSDK.sent_lobby_invite.connect(func(response): print("Sent: ", response.success))
WavedashSDK.lobby_invite.connect(_on_lobby_invite)
func _on_lobby_invite(data):
WavedashSDK.join_lobby(data["lobbyId"])
await Wavedash.SDK.InviteUserToLobby(lobbyId, userId);
void Awake() { Wavedash.SDK.OnLobbyInvite += HandleInvite; }
void HandleInvite(Dictionary<string, object> data)
{
Debug.Log($"Invited by: {data["inviterUsername"]}");
}
await Wavedash.inviteUserToLobby(lobbyId, friendUserId);
Wavedash.on(Wavedash.Events.LOBBY_INVITE, (payload) => {
Wavedash.joinLobby(payload.lobbyId);
});
Metadata
Only the host can set metadata. Any member can read it.
Godot and Unity expose typed getters and setters (one per value type). JavaScript passes values through a single polymorphic pair.
# Strings
WavedashSDK.set_lobby_data_string(lobby_id, "gameMode", "deathmatch")
var mode = WavedashSDK.get_lobby_data_string(lobby_id, "gameMode")
# Ints
WavedashSDK.set_lobby_data_int(lobby_id, "round", 3)
var round = WavedashSDK.get_lobby_data_int(lobby_id, "round")
# Floats
WavedashSDK.set_lobby_data_float(lobby_id, "matchTimer", 120.0)
var timer = WavedashSDK.get_lobby_data_float(lobby_id, "matchTimer")
WavedashSDK.delete_lobby_data(lobby_id, "gameMode")
// Strings
Wavedash.SDK.SetLobbyData(lobbyId, "gameMode", "deathmatch");
string mode = Wavedash.SDK.GetLobbyDataString(lobbyId, "gameMode");
// Ints
Wavedash.SDK.SetLobbyData(lobbyId, "round", 3);
int round = Wavedash.SDK.GetLobbyDataInt(lobbyId, "round");
// Floats
Wavedash.SDK.SetLobbyData(lobbyId, "matchTimer", 120.0f);
float timer = Wavedash.SDK.GetLobbyDataFloat(lobbyId, "matchTimer");
Wavedash.SDK.DeleteLobbyData(lobbyId, "gameMode");
Wavedash.setLobbyData(lobbyId, "gameMode", "deathmatch");
Wavedash.setLobbyData(lobbyId, "round", 3);
Wavedash.setLobbyData(lobbyId, "matchTimer", 120.0);
const mode = Wavedash.getLobbyData(lobbyId, "gameMode");
Wavedash.deleteLobbyData(lobbyId, "gameMode");
SetLobbyData is overloaded in Unity — the correct typed variant is picked at compile time based on the value argument. For reads, use the GetLobbyData{String,Int,Float} variant that matches the stored type.
Invite links
Generate a shareable invite link for the current lobby. Pass true to also copy it to the user's clipboard.
func _ready():
WavedashSDK.got_lobby_invite_link.connect(_on_invite_link)
func copy_link():
WavedashSDK.get_lobby_invite_link(true)
func _on_invite_link(response):
if response.get("success", false):
print("Invite link: ", response["data"])
string link = await Wavedash.SDK.GetLobbyInviteLink(copyToClipboard: true);
Debug.Log($"Invite link: {link}");
const response = await Wavedash.getLobbyInviteLink(true);
if (response.success) {
console.log("Invite link:", response.data);
}
When a player opens an invite link, the lobby ID is passed to your game as a launch param. Your game must check for it on startup and join the lobby — it does not happen automatically:
var params = WavedashSDK.get_launch_params()
if params.has("lobby"):
WavedashSDK.join_lobby(params["lobby"])
var parameters = Wavedash.SDK.GetLaunchParams();
if (parameters.TryGetValue("lobby", out var lobbyId))
await Wavedash.SDK.JoinLobby(lobbyId);
const params = Wavedash.getLaunchParams();
if (params.lobby) {
await Wavedash.joinLobby(params.lobby);
}
Events
| Event | Description |
|---|---|
LOBBY_JOINED | Successfully joined a lobby |
LOBBY_USERS_UPDATED | A user joined or left |
LOBBY_MESSAGE | New message received |
LOBBY_DATA_UPDATED | Metadata changed |
LOBBY_KICKED | Removed from lobby |
LOBBY_INVITE | Received lobby invitation |
Handling lifecycle events
Subscribe to lobby-lifecycle events so your UI stays in sync with membership and metadata changes.
func _ready():
WavedashSDK.lobby_users_updated.connect(_on_users_updated)
WavedashSDK.lobby_data_updated.connect(_on_data_updated)
WavedashSDK.lobby_kicked.connect(_on_kicked)
func _on_users_updated(payload):
print("User ", payload["username"], " ", payload["changeType"])
func _on_data_updated(metadata):
print("Lobby metadata: ", metadata)
func _on_kicked(payload):
print("Kicked: ", payload["reason"])
void Awake()
{
Wavedash.SDK.OnLobbyUsersUpdated += data =>
Debug.Log($"User {data["username"]} {data["changeType"]}");
Wavedash.SDK.OnLobbyDataUpdated += metadata =>
Debug.Log($"Lobby metadata: {metadata}");
Wavedash.SDK.OnLobbyKicked += data =>
Debug.Log($"Kicked: {data["reason"]}");
}
Wavedash.on(Wavedash.Events.LOBBY_USERS_UPDATED, (payload) => {
console.log(`User ${payload.username} ${payload.changeType}`);
});
Wavedash.on(Wavedash.Events.LOBBY_DATA_UPDATED, (payload) => {
console.log("Lobby metadata:", payload);
});
Wavedash.on(Wavedash.Events.LOBBY_KICKED, (payload) => {
console.log("Kicked:", payload.reason);
});