Lobby Browsing: Examples of Implementation¶
Browsing Lobbies and Joining a Lobby¶
User Experience¶
When the user enters Online→Server Browser menu, a list of all available lobbies is displayed along with their names and buttons for joining them. We show only lobbies that are not full and in this demo the maximum number of players in a lobby is 2.
When the user clicks Join button next to the lobby name, they will be taken to the lobby view.
Solution¶
The main implementation of displaying multiplayer lobbies list is contained in the OnlineBrowserController script. Listeners to manage callbacks can be found in the Matchmaking script.
Methods and Usage¶
OnlineBrowserController Class¶
void OnEnable()
{
// Initialize the required listeners
GalaxyManager.Instance.Matchmaking.LobbyBrowsingListenersInit();
RequestLobbyList(false);
}
When the user enters the Server Browser menu, the OnlineBrowserController script is enabled, since it is a component of OnlineBrowserScreen. It initializes the lobby browsing listeners in Matchmaking and calls the RequestLobbyList(false)
method.
OnlineBrowserController.RequestLobbyList¶
public void RequestLobbyList(bool refresh)
{
waitingCircularArrow.SetActive(true);
if (refresh)
{
DisposeLobbiesList();
}
GalaxyManager.Instance.Matchmaking.RequestLobbyList();
}
RequestLobbyList(bool refresh)
activates the waitingCircularArrow GameObject, which is shown while the lobby list is being requested and prepared to be displayed.
If the refresh
argument was true
, the lobby list displayed previously would be flushed with the DisposeLobbiesList()
method. In the end, the list of lobbies is requested with Matchmaking.RequestLobbyList()
.
LobbyListListenerBrowsing¶
public override void OnLobbyList(uint count, LobbyListResult result)
{
if (result != LobbyListResult.LOBBY_LIST_RESULT_SUCCESS)
{
Debug.LogWarning("OnLobbyList failure reason: " + result);
return;
}
Debug.Log(count + " lobbies OnLobbyList");
matchmaking.lobbyCount = count;
if (count == 0)
{
GameObject.Find("OnlineBrowserScreen").GetComponent<OnlineBrowserController>().DisplayLobbyList(null);
return;
}
for (uint i = 0; i < count; i++)
{
GalaxyID lobbyID = GalaxyInstance.Matchmaking().GetLobbyByIndex(i);
Debug.Log("Requesting lobby data for lobby " + i + " with lobbyID " + lobbyID.ToString());
matchmaking.RequestLobbyData(lobbyID);
}
}
The callback on retrieving a lobby list comes to the LobbyListListenerBrowsing()
listener and then LobbyListListenerBrowsing().OnLobbyList()
is called. If the request was successful, this method checks whether there is at least one lobby on the list. If this is the case, it requests lobby data for all lobbies using a for
loop, which gets the GalaxyID of each lobby, stores it in the lobbyID
variable, and then requests data for this particular lobby with the Matchmaking.RequestLobbyData(lobbyID)
method.
LobbyDataRetrieveListenerBrowsing¶
Callback to Matchmaking.RequestLobbyData(lobbyID)
comes to LobbyDataRetrieveListenerBrowsing.OnLobbyDataRetrieveSuccess()
:
public override void OnLobbyDataRetrieveSuccess(GalaxyID lobbyID)
{
Debug.Log("Data retrieved for " + lobbiesWithDataRetrievedCount + " lobbies out of " + matchmaking.lobbyCount);
string name = GalaxyManager.Instance.Matchmaking.GetLobbyData(lobbyID, "name");
string ping = GalaxyManager.Instance.Matchmaking.GetPingWith(lobbyID).ToString();
object[] lobbyWithDetails = {name, ping, lobbyID};
lobbyListWithDetails.Add(lobbyWithDetails);
lobbiesWithDataRetrievedCount ++;
if (lobbiesWithDataRetrievedCount >= matchmaking.lobbyCount)
{
GameObject.Find("OnlineBrowserScreen").GetComponent<OnlineBrowserController>().DisplayLobbyList(lobbyListWithDetails);
lobbiesWithDataRetrievedCount = 0;
matchmaking.lobbyCount = 0;
lobbyListWithDetails.Clear();
lobbyListWithDetails.TrimExcess();
}
}
Within this method we:
- Retrieve the lobby data — its
name
,ping
andlobbyID
— using theMatchmaking.GetLobbyData()
andMatchmaking.GetPingWith()
methods (these methods are wrappers forGetLobbyData()
and theGetPingWith()
methods, respectively, from the GOG GALAXY SDK) and store them in thelobbyWithDetails
variable. - Add the
lobbyWithDetails
object, which stores the retrieved lobby data, to the lobby list (lobbyListWithDetails
). - Increment the
lobbiesWithDataRetrievedCount
value every time the listener receives a callback. - Check if
lobbiesWithDataRetrievedCount
is bigger than or equal tomatchmaking.lobbyCount
(the total number of lobbies retrieved by theLobbyListListenerBrowsing
listener). If it is, display the list usingOnlineBrowserController.DisplayLobbyList()
, setlobbiesWithDataRetrievedCount
andmatchmaking.lobbyCount
values back to zero, and lastly clear and trimlobbyListWithDetails
.
Joining the Game¶
public void DisplayLobbyList(List<object[]> lobbyList)
{
Debug.Log("Displaying lobby list");
waitingCircularArrow.SetActive(false);
GameObject currentEntry;
if (lobbyList == null) return;
foreach (object[] lobby in lobbyList)
{
Debug.Log("Current lobby ID " + lobby[2].ToString());
currentEntry = Instantiate(entryPrefab, entriesContainer.transform);
currentEntry.transform.GetChild(0).GetComponent<Text>().text = lobby[0].ToString();
currentEntry.transform.GetChild(1).GetComponent<Text>().text = lobby[1].ToString();
currentEntry.transform.GetChild(2).GetComponent<Button>().onClick.AddListener(() =>
{
JoinLobby((GalaxyID)lobby[2]);
});
entriesList.Add(currentEntry);
}
}
When the lobby list is displayed, we assign the OnlineBrowserController.JoinLobby(lobbyID)
method to the event of clicking the Join button inside the Server Browser entry prefab.
The OnlineBrowserController.JoinLobby(lobbyID)
method allows the user to join the lobby using Matchmaking.JoinLobby(lobbyID)
and displays OnlineJoiningScreen menu:
public void JoinLobby(GalaxyID lobbyID)
{
Debug.Log("Joining lobby " + lobbyID);
GalaxyManager.Instance.Matchmaking.JoinLobby(lobbyID);
GameObject.Find("MainMenu").GetComponent<MainMenuController>().SwitchMenu(MainMenuController.MenuEnum.OnlineJoining);
}
LobbyEnteredListenerBrowsing¶
A callback to the Matchmaking.JoinLobby(lobbyID)
method comes to LobbyEnteredListenerBrowsing, where the OnLobbyEntered
method checks if the entry was successful or not:
public override void OnLobbyEntered(GalaxyID lobbyID, LobbyEnterResult _result)
{
if (_result != LobbyEnterResult.LOBBY_ENTER_RESULT_SUCCESS)
{
Debug.Log("LobbyEnteredListenerBrowsing failed");
GameObject.Find("MainMenu").GetComponent<MainMenuController>().SwitchMenu(MainMenuController.MenuEnum.OnlineBrowser);
GameObject.Find("PopUps").GetComponent<PopUps>().PopUpWithClosePopUpsButton("Could not join lobby\nReason: " +
_result.ToString(), "Back");
return;
}
Debug.Log("LobbyEnteredListenerBrowsing succeded");
matchmaking.CurrentLobbyID = lobbyID;
matchmaking.LobbyOwnerID = matchmaking.GetLobbyOwner(lobbyID);
matchmaking.SetLobbyMemberData("state", "notReady");
GameObject.Find("MainMenu").GetComponent<MainMenuController>().SwitchMenu(MainMenuController.MenuEnum.OnlineWait);
friends.SetRichPresence("status", "In online lobby");
friends.SetRichPresence("connect", "--JoinLobby=" + lobbyID);
matchmaking.LobbyManagmentMainMenuListenersInit();
matchmaking.LobbyChatListenersInit();
matchmaking.LobbyBrowsingListenersDispose();
}
First, we check if the result of entering a lobby was anything else but successful.
If this is the case, it means we did not succeed at entering the lobby, therefore we want to inform the user about that:
- We go back to lobby browsing menu.
- Display a pop up informing that we could not join the lobby and why.
- Use the
return
keyword to prevent the rest of the code within theOnLobbyEntered()
callback from executing.
Otherwise, it means we did succeed at entering the lobby, and we have to ensure that everything is ready:
- Set the
CurrentLobbyID
variable within the GalaxyManager.Instance.Matchmaking instance to the lobby ID of the currently joined lobby. TheCurrentLobbyID
variable is later used to streamline the usage of methods in the Matchmaking class. - Set the
LobbyOwnerID
variable within the GalaxyManager.Instance.Matchmaking instance to the Galaxy ID of the owner of the currently joined lobby. TheLobbyOwnerID
variable is later used to check if the current user is the lobby owner. - Set the lobby member data of current users under the
state
key tonotReady
. This data is later used to verify whether the lobby members are ready to start a game or not. - Switch to the OnlineWait screen, which serves as a pre-game lobby where players can chat and set their state to
ready
, once they are ready to start the game. Additionally, the owner of the lobby can start the game, when both players are ready. - Set the rich presence
status
key of the users toIn online lobby
(this will be visible to GOG friends of the users in the GOG GALAXY friends list and chat) and theconnect
key to"--JoinLobby=" + lobbyID
(this allows GOG friends of the users to join the lobby they are in via the GOG GALAXY friends list or chat). - Finally, we make sure that the required LobbyManagmentMainMenu and LobbyChat listeners are initialized, and the no longer needed LobbyBrowsingListeners are disposed of.