Skip to main content

Implement Lobby using the Unity SDK

Last updated on October 29, 2024

Quick reference

AGS Shared Cloud

This topic is specific to the AccelByte Gaming Services (AGS) Shared Cloud tier.

References
using AccelByte.Api;
using AccelByte.Core;
using AccelByte.Models;
Get Lobby Service
Lobby lobby = AccelByteSDK.GetClientRegistry().GetApi().GetLobby();
Connection Notification Events
lobby.Connected += delegate { };
lobby.Disconnecting += result => { };
lobby.Disconnected += result => { };
Lobby Connect
lobby.Connect();
Lobby Disconnect
lobby.Disconnect();
Check if Lobby is Connected
bool isLobbyConnected = lobby.IsConnected;

Quickstart Guide

In this tutorial, you will learn how to use the Lobby Services. This guide assumes that you have already implemented Login IAM.

  1. Create a new script called LobbyHandler.cs and attach it to the AccelByteHandler gameObject.

  2. Add the following AccelByte libraries to the top of the script:

using AccelByte.Api;
using AccelByte.Core;
  1. Create a function called ConnectToLobby() and add a reference of the Lobby (even though the Lobby is not connected at this point).
// Get a reference to the instance of the Lobby
Lobby lobby = AccelByteSDK.GetClientRegistry().GetApi().GetLobby();
  1. Add the following functions to notify the player when the Lobby has been Connected, Disconnected, or is Disconnecting.
// Connection
lobby.Connected += () =>{ Debug.Log("Lobby Connected"); };
lobby.Disconnecting += result => { Debug.Log($"Lobby Disconnecting {result.Value.message}");};
lobby.Disconnected += result => { Debug.Log($"Lobby Disconnected: {result}");};

The Lobby system is built around actions and callbacks, so be sure to check the signatures of the Event you're subscribing to. For more information, you can find these models in LobbyModels.cs within the Plugin folder.

In this example, you only need to log a message or, in the case of Disconnecting and Disconnected, use the result to give the player more information.

  1. Once this basic functionality is incorporated, connect the Lobby. This action opens a WebSocket that you will want to tightly control the lifecycle of. At the end of this function, add the following code:
//Connect to the Lobby
if (!lobby.IsConnected)
{
lobby.Connect();
}
  1. To disconnect from the Lobby, use a reusable function to check if the Lobby is Connected, and if it is, Disconnect:
public void DisconnectFromLobby()
{
if (lobby != null && lobby.IsConnected)
{
lobby.Disconnect();
}
}

To ensure the WebSocket is closed when the game stops or when you stop using the Unity Editor, add DisconnectFromLobby() to the OnApplicationQuit() function.

private void OnApplicationQuit()
{
DisconnectFromLobby();
}
  1. Add the other callbacks to the ConnectToLobby() function. Your final function should look like this:
public void ConnectToLobby()
{
lobby = AccelByteSDK.GetClientRegistry().GetApi().GetLobby();

// Connection
lobby.Connected += () => { Debug.Log("Lobby Connected"); };
lobby.Disconnecting += result => { Debug.Log($"Lobby Disconnecting {result.Value.message}");};
lobby.Disconnected += result => { Debug.Log($"Lobby Disconnected: {result}"); };

// Connect to the Lobby
lobby.Connect();
}
  1. Test your code by running the function after successfully connecting to the Lobby.

Return to LoginHandler.cs and add the following code to the success section of the user.LoginWithUsername() delegate:

...
else
{
Debug.Log("Login successful");

// Attempt to Connect to Lobby
GetComponent<LobbyHandler>().ConnectToLobby();
...
}

Return to the Unity Editor and press Play. If you have configured your code correctly, you should see the message "Lobby Connected" after successfully logging in.

Congratulations! You have successfully connected to the Lobby.

Continue on for a step-by-step example of the UI and code implementation. Otherwise, you are now ready to move on to the Friends Service.

Step-by-step guide

Code Implementation

Now that you have some basic Lobby functionalities in place, it's time to tidy up your code. Follow the Singleton Pattern for this and all future handler classes.

  1. Add the following code to the top of your LobbyHandler.cs class:

    /// Private Instance
    static LobbyHandler instance;

    /// The Instance Getter
    public static LobbyHandler Instance => instance;

    /// Reference to Lobby in Handler
    public Lobby lobby;

    private void Awake()
    {
    // Check if another Instance is already created, and if so delete this one, otherwise destroy the object
    if (instance != null && instance != this)
    {
    Destroy(this);
    return;
    }
    else
    {
    instance = this;
    }
    }
  2. Open your LoginHandler.cs class. In the OnLoginClick() function, replace GetComponent<LobbyHandler>().ConnectToLobby; with LobbyHandler.Instance.ConnectToLobby();.

    ...
    else
    {
    Debug.Log("Login successful");

    // Attempt to Connect to Lobby
    LobbyHandler.Instance.ConnectToLobby();
    ...
    }
  3. Create a new script called NotificationHandler.cs and add the AccelByte libraries to the top of the script:

    using AccelByte.Models;
    using AccelByte.Core;
  4. While still in NotificationHandler.cs, create new functions for each notification:

    public class NotificationHandler : MonoBehaviour
    {
    // Collection of connection notifications
    #region Connections
    /// Called when lobby is connected
    public void OnConnected()
    {
    Debug.Log("Lobby Connected");
    }

    /// Called when connection is disconnecting
    /// <param name="result"> Contains data of message</param>
    public void OnDisconnecting(Result<DisconnectNotif> result)
    {
    Debug.Log($"Lobby Disconnecting {result.Value.message}");
    }

    /// Called when connection is being disconnected
    /// <param name="result"> Contains data of websocket close code</param>
    public void OnDisconnected(WsCloseCode result)
    {
    Debug.Log($"Lobby Disconnected: {result}");
    }
    #endregion
    }
  5. In LobbyHandler.cs, add the following code to obtain the NotificationHandler's component.

    ...
    [HideInInspector]
    public NotificationHandler notificationHandler;

    private void Awake()
    {
    ...

    // Get the the object handler
    notificationHandler = gameObject.GetComponent<NotificationHandler>();
    }
  6. In LobbyHandler.cs, change the delegate in ConnectToLobby() by calling the functions you created earlier in NotificationHandler.cs.

    public void ConnectToLobby()
    {
    ...

    // Connection
    lobby.Connected += notificationHandler.OnConnected;
    lobby.Disconnecting += notificationHandler.OnDisconnecting;
    lobby.Disconnected += notificationHandler.OnDisconnected;

    ...
    }
  7. While still in LobbyHandler.cs, add a new function to remove the delegate to reset the listener:

    public void RemoveLobbyListeners()
    {
    //Remove delegate from Lobby
    //Connection
    lobby.Connected -= notificationHandler.OnConnected;
    lobby.Disconnecting -= notificationHandler.OnDisconnecting;
    lobby.Disconnected -= notificationHandler.OnDisconnected;
    }

Congratulations! You have now fully implemented the Lobby connection, which is the gateway to many of services in AGS using WebSocket.

Proceed to the next section to learn how to implement the Friends Service.

Full code for reference

LobbyHandler.cs
using UnityEngine;
using AccelByte.Api;
using AccelByte.Core;

public class LobbyHandler : MonoBehaviour
{
/// <summary>
/// Private Instance
/// </summary>
static LobbyHandler instance;

/// <summary>
/// The Instance Getter
/// </summary>
public static LobbyHandler Instance => instance;

/// <summary>
/// The Instance Getter
/// </summary>
private Lobby lobby;

[HideInInspector]
public NotificationHandler notificationHandler;

private void Awake()
{
// Check if another Instance is already created, and if so delete this one, otherwise destroy the object
if (instance != null && instance != this)
{
Destroy(this);
return;
}
else
{
instance = this;
}

// Get the the object handler
notificationHandler = gameObject.GetComponent<NotificationHandler>();
}

/// <summary>
/// Connect to the <see cref="Lobby"/> and setup CallBacks
/// </summary>
public void ConnectToLobby()
{
//Get a reference to the instance of the Lobby
lobby = AccelByteSDK.GetClientRegistry().GetApi().GetLobby();

//Connection
lobby.Connected += notificationHandler.OnConnected;
lobby.Disconnecting += notificationHandler.OnDisconnecting;
lobby.Disconnected += notificationHandler.OnDisconnected;

//Connect to the Lobby
if (!lobby.IsConnected)
{
lobby.Connect();
}
}

public void RemoveLobbyListeners()
{
//Remove delegate from Lobby
//Connection
lobby.Connected -= notificationHandler.OnConnected;
lobby.Disconnecting -= notificationHandler.OnDisconnecting;
lobby.Disconnected -= notificationHandler.OnDisconnected;
}

public void DisconnectFromLobby()
{
if (lobby != null && lobby.IsConnected)
{
lobby.Disconnect();
}
}

private void OnApplicationQuit()
{
// Attempt to Disconnect from the Lobby when the Game Quits
DisconnectFromLobby();
}
}
NotificationHandler.cs
using UnityEngine;
using AccelByte.Models;
using AccelByte.Core;

public class NotificationHandler : MonoBehaviour
{
#region Notifications

// Collection of connection notifications
#region Connections
/// <summary>
/// Called when lobby is connected
/// </summary>
public void OnConnected()
{
Debug.Log("Lobby Connected");
}

/// <summary>
/// Called when connection is disconnecting
/// </summary>
/// <param name="result"> Contains data of message</param>
public void OnDisconnecting(Result<DisconnectNotif> result)
{
Debug.Log($"Lobby Disconnecting {result.Value.message}");
}

/// <summary>
/// Called when connection is being disconnected
/// </summary>
/// <param name="result"> Contains data of websocket close code</param>
public void OnDisconnected(WsCloseCode result)
{
Debug.Log($"Lobby Disconnected: {result}");
}
#endregion

#endregion
}
LoginHandler.cs
using UnityEngine;
using AccelByte.Api;
using AccelByte.Models;
using AccelByte.Core;
using UnityEngine.UI;

public class LoginHandler : MonoBehaviour
{
/// <summary>
/// Private Instance
/// </summary>
static LoginHandler instance;
/// <summary>
/// The Instance Getter
/// </summary>
public static LoginHandler Instance => instance;
private void Awake()
{
// Check if another Instance is already created, and if so delete this one, otherwise destroy the object
if (instance != null && instance != this)
{
Destroy(this);
return;
}
else
{
instance = this;
}
}

[SerializeField]
Button loginButton;
[SerializeField]
Text statusText;
[SerializeField]
InputField usernameInputField;
[SerializeField]
InputField passwordInputField;
[SerializeField]
RectTransform loginPanel;

private void OnEnable()
{
// When we Activate, set the Text of the Login Status
// and add the Login Call to the Button's listener
statusText.text = "Please Login";
loginButton.onClick.AddListener(() =>
{
statusText.text = "Attempting Login";
OnLoginClick(usernameInputField.text, passwordInputField.text);
});
}

private void OnDisable()
{
//When we disable, clear all of the Listeners from the Login Button
loginButton.onClick.RemoveAllListeners();
}

public void OnLoginClick(string username, string password)
{
// Disable Interaction with the Login button so the player cannot spam click it and send multiple requests
loginButton.interactable = false;
statusText.text = "Logging in...";
// Grab a reference to the current user, even though they have not been logged in yet
// This also acts as the initialization point for the AGS plug-in
User user = AccelByteSDK.GetClientRegistry().GetApi().GetUser();
// Calling the login function and supplying a callback to act upon based upon success or failure
// You will almost certainly want to extend this functionality further
// Note that this callback is asynchronous
ResultCallback<TokenData, OAuthError> loginCallback = loginResult =>
{
if (loginResult.IsError)
{
// If there is an error, grab the error code and message to print in the log
Debug.Log($"Login failed : {loginResult.Error.error}: {loginResult.Error.error_description}");
// Set the Status Text to display any errors
statusText.text = $"Login failed : {loginResult.Error.error}: {loginResult.Error.error_description}";
}
else
{
Debug.Log("Login successful");

// Attempt to Connect to Lobby
LobbyHandler.Instance.ConnectToLobby();

loginPanel.gameObject.SetActive(false);
}
//Enable interaction with the button again
loginButton.interactable = true;
};
user.LoginWithUsernameV3(username, password, loginCallback);
}
}