Skip to main content

Lobby

1. Overview

The Lobby Service works with the DS Hosting and Management service and provides a way for the game to gather players together to start a battle. A player can create a private lobby to play battles with specific people or create an open lobby which anyone can join. The Lobby Service also provides lobby management, search, text chat, and other features.

2. Architecture Diagram

The Lobby Service includes two types of interactions:

  • Calling lobby interfaces using the PGOS SDK.
  • Receiving lobby notifications pushed by the Lobby Service when specific events happen.

lobby.drawio

tip

A lobby will only be destroyed when the following event happens:

  • The lobby owner dismissed the lobby
  • The last member has left the lobby
  • The lobby has been unactive for more than 7 days

A player can only leave lobby in the following ways:

  • The client explicitly invokes LeaveLobby function
  • The lobby owner can remove any member out of lobby
  • When player get disconnected from PGOS, he will be automatically removed from lobby

Please note that when a battle is started by lobby, players are all treated as still in lobby and core lobby features still work as normal.

3. Create a Lobby Configuration

You must create a Lobby Configuration before using the Lobby Service to implement your own features. A lobby configuration defines the basic lobby rules and is required by the PGOS SDK to create a lobby.

Since the Lobby Service works with the DS Hosting and Management service, make sure there is an available DS placer for placing battle sessions. If not, create one first. Refer to the following link for more details: Create a Placer.

Next, follow the steps below:

  1. Open the PGOS Web Portal and enter Lobby page. Create a new lobby configuration or clone from an existing one.

    image-20230105195322334

  2. Fill in the configuration details.

    image-20240626104140445

    • Name: The configuration name, which must start with a letter and have a maximum of 128 characters. The name must be unique within the title region.
    • Preparing Timeout: The maximum length of time for the Preparing stage before all the lobby players enter into battle. 0s means preparation does not time out. The maximum value is 3600s.
    • Default Placer: Choose a default placer for battle placement.
    • Flexible Placer: You can set up various game modes and assign a specific placer to each mode. After initiating a battle, the system will determine the corresponding placer based on the game modes provided by the lobby. if the lobby's game modes are not specified, or if the game mode configuration cannot be found on the portal, the default placer will be used.
  3. Teams Configuration [Simple Mode]

    image-20240626104255767

    • Start Battle Condition: The action when the lobby owner invokes the StartBattle interface depends on the Ready flag of lobby members:

      • All Ready Otherwise Waiting: The lobby will enter the Preparing stage, waiting for unready players to get ready.
      • All Ready Otherwise Error: StartBattle interface will get an error if not all players are ready.
      • Ignoring Ready Flag: The lobby will enter the Playing stage directly, ignoring the players' Ready flag.
    • Team Selection Strategy: Decide how to select slots for new lobby members between teams.

      • Balance player count: To ensure a balanced number of players, prioritize joining the team with the fewest members and available slots.
      • Concentrate players: To concentrate the players, prioritize joining the team with the most members and available slots.
    • Teams: The team configurations in the lobby.

      • Name: Name of the team. Must be unique in the lobby.
      • Capacity: Maximum number of players in the team. The sum of the capacities of all the teams is the lobby capacity.
  1. Teams Configuration [Advanced Mode]

    In Advanced mode, you can create multiple team groups, and each team group can have its own configuration for the Start Battle Condition.

    20240621104840

    • Team Selection Strategy: Same as simple mode. Decide how to select slots between teams with the same priority.
    • Team Groups: Allow to configure multiple team groups. Each group can configure multiple teams.
    • Start Battle Condition: The action of the lobby owner when invoking the StartBattle interface depends on the Ready flag of lobby members. You can set up ‘start battle conditions' for each group.
      • Ignoring Ready Flag: The lobby will disregard the ready status of this group's members.
      • All Ready Otherwise Waiting/All Ready Otherwise Error: The lobby will enter the Preparing stage or receive an error if not all members in this group are ready. When these two conditions occur simultaneously, the priority of 'All Ready Otherwise Error' is higher, so the lobby will receive an error.

4. Core Features

This section demonstrates basic functions of lobby service, for the error handling steps, please refer the last section.

4.1 Create a Lobby

In the API for lobby creation, the following options can be set:

  • lobby_config (required): The name of a lobby configuration created via the PGOS Web Portal.
  • name (required): The name of the lobby.
  • privacy (required): LobbyPrivacy::Visible or LobbyPrivacy::Invisible. If set to Invisible, the lobby can only be accessed using the lobby id.
  • enable_chatting (optional): Pass true to create a chat channel for the lobby, or false to not.
  • password (optional): password needed to join the lobby.
  • kv_data (optional): A map containing global custom lobby data.
  • protection (optional, since v0.23.0): the access protection policy of the lobby. Enumerated values are:
    • PasswordNeeded: Player need to give the password when joining a lobby. If this policy is selected, the password must not be null or the create lobby interface will return a failure.
    • FreeAccess: No restrictions on players joining.
    • ApplicationNeeded: A join request will be sent to the owner after calling the JoinLobby interface, and the owner's approval is required to successfully join the lobby.
    • game_mode (optional): the game mode of the lobby. After starting the battle, the placer corresponding to the game mode on the portal will be used. If this game mode does not have a placer configured, the default placer configured on the portal will be used.

Call CreateLobby from Lobby module as follows:

#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"

void SomeUObjectClass::CreateLobby()
{
FClientCreateLobbyParams Params;
Params.lobby_config = TEXT("config_name");
Params.name = TEXT("A Lobby");
Params.privacy = EClientLobbyPrivacy::LobbyPrivacy_Visible;
Params.enable_chatting = true;

auto lobby = IPgosSDKCpp::Get().GetClientLobbyAPI();
if (lobby)
{
lobby->CreateLobby(Params, [](const FPgosResult& Ret, const FClientLobbyDetailInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("CreateLobbySuccess"))
}
else
{
UE_LOG(LogTemp, Log, TEXT("CreateLobbyFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}

4.2 Team Slot

There are multiple teams with ordered player slots in each lobby,. PGOS's Lobby service starts indexing these slots from 1.

  • The team structure can be set in the lobby configuration.

  • When a lobby is created, the lobby owner is assigned to the first slot in the first team.

  • New players entering the lobby will automatically assigned to a team slot.

  • Lobby members can freely switch to unoccupied slots by calling API SwitchTeamSlot.

  • Lobby members can send slot switch requests to others by calling API RequestSwitchTeamSlot.

  • If the lobby is in the Preparing stage, switching the team slot will cause the lobby to fall back to the Waiting stage.

4.2.1 Switch to Unoccupied Slot

sequenceDiagram participant A as Player A participant B as Player B participant C as Player C participant L as Lobby Service A->>L:SwitchTeamSlot(teamName, teamSlot) L-->>A: OnLobbyTeamUpdated L-->>B: OnLobbyTeamUpdated L-->>C: OnLobbyTeamUpdated

Events:

  • OnLobbyTeamUpdated: Sent to all members in the lobby if the API call SwitchTeamSlot is successful.

Call SwitchTeamSlot from Lobby module as follows:

#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"

void SomeUObjectClass::SwitchTeamSlot()
{
FString TargetTeamName = ObtainFromSomeWhere();
int32 TargetTeamSlot = ObtainFromSomeWhere();

auto lobby = IPgosSDKCpp::Get().GetClientLobbyAPI();
if (lobby)
{
lobby->SwitchTeamSlot(TargetTeamName, TargetTeamSlot, [](const FPgosResult& Ret, const FClientLobbyDetailInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("OnSwitchTeamSlotSuccess"))
}
else
{
UE_LOG(LogTemp, Log, TEXT("OnSwitchTeamSlotFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}

4.2.2 Request Switch to Occupied Slot

sequenceDiagram participant A as Player A participant B as Player B participant C as Player C participant L as Lobby Service A->>L:RequestSwitchTeamSlot(teamName(PlayerB), teamSlot(PlayerB)) L-->>B:OnLobbySwitchTeamSlotRequest(from PlayerA) B->>L:ConfirmSwitchTeamSlot(teamName(PlayerA), teamSlot(PlayerA)) L->>L:Switch PlayerA and PlayerB L-->>A:OnLobbyTeamUpdated L-->>B:OnLobbyTeamUpdated L-->>C:OnLobbyTeamUpdated

Events:

  • OnLobbySwitchTeamSlotRequest: This event will be sent to the requested member.
  • OnLobbyTeamUpdated: Sent to all members in the lobby if the slot-switch request has been confirmed.

Call SwitchTeamSlot from Lobby module as follows:

#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"

void SomeUObjectClass::RequestSwitchTeamSlot()
{
FString TargetTeamName = ObtainFromSomeWhere();
int32 TargetTeamSlot = ObtainFromSomeWhere();

auto lobby = IPgosSDKCpp::Get().GetClientLobbyAPI();
if (lobby)
{
lobby->RequestSwitchTeamSlot(TargetTeamName, TargetTeamSlot, [](const FPgosResult& Ret, const FClientLobbyDetailInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("OnRequestSwitchTeamSlotSuccess"))
}
else
{
UE_LOG(LogTemp, Log, TEXT("OnRequestSwitchTeamSlotFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}

4.3 Lobby Custom Data

We provide two types of custom lobby data to assist in extending the lobby functionality for games.

  • Lobby global data: These key-value pairs apply to the entire game lobby.

    • Only the owner of the a lobby can modify these properties.
    • All players can read this data, whether or not they have joined the lobby.
    • The lifetime of the lobby global data is consistent with the lobby.
    • The lobby global data will write into battle properties when a battle session is started through the lobby.
  • Lobby player data: Each member in the game lobby has a unique set of member properties.

    • This data is visible only to lobby members.
    • Members can only modify their own member properties.
    • Lobby player data will be removed when a player leaves the lobby.

Both the two type lobby custom data can be updated without modifying other lobby options.

  • SetLobbyGlobalData: This interface is used for a complete update of the lobby global data. The data update operation will be notified to all lobby members through the OnLobbyGlobalCustomDataUpdated event.
  • SetLobbyPlayerData: This interface is used for updating the custom data of a lobby member. The data update operation will be notified to all lobby members through the OnLobbyPlayerCustomDataUpdated event.
Note

Event OnLobbyDataUpdated is deprecated since v0.23.0. Please use event OnLobbyGlobalCustomDataUpdated and OnLobbyPlayerCustomDataUpdated instead.

4.4 Join/Leave a Lobby

4.4.1 Join a Freely Accessible Lobby

Players are free to join lobbies which the protection option is LobbyProtection::FreeAccess by calling JoinLobby:

#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"

void SomeUObjectClass::JoinLobby()
{
FClientJoinLobbyParams Params;
Params.lobby_id = TEXT("123456");
Params.password = "";
Params.join_token = "";
Params.payload = "";

auto lobby = IPgosSDKCpp::Get().GetClientLobbyAPI();
if (lobby)
{
lobby->JoinLobby(Params, [](const FPgosResult& Ret, const FClientLobbyDetailInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("OnJoinLobbySuccess"))
}
else
{
UE_LOG(LogTemp, Log, TEXT("OnJoinLobbyFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}

4.4.2 Join a Lobby with Password

Players need to provide a password to join lobbies which the protection option is LobbyProtection::PasswordNeeded by calling JoinLobby:

#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"

void SomeUObjectClass::JoinLobby()
{
FClientJoinLobbyParams Params;
Params.lobby_id = TEXT("123456");
Params.password = "password";
Params.join_token = "";
Params.payload = "";

auto lobby = IPgosSDKCpp::Get().GetClientLobbyAPI();
if (lobby)
{
lobby->JoinLobby(Params, [](const FPgosResult& Ret, const FClientLobbyDetailInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("OnJoinLobbySuccess"))
}
else
{
UE_LOG(LogTemp, Log, TEXT("OnJoinLobbyFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}

4.4.3 Join a Lobby by Invitation

The join_token obtained in the OnLobbyInvitation event can be used as the token for joining the invited lobby, which can be used to successfully join a lobby if the lobby protection option is not FreeAccess.

The workflow of lobby invitation is as fellows:

sequenceDiagram participant A as Player A participant B as Player B participant C as Player C participant L as Lobby Service A->>L:JoinLobby L-->>B: OnLobbyMemberJoined L-->>C: OnLobbyMemberJoined

The sample code is as follows:

#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"

void SomeUObjectClass::JoinLobby()
{
FClientJoinLobbyParams Params;
Params.lobby_id = TEXT("123456");
Params.password = "";
Params.join_token = "join token";
Params.payload = "";

auto lobby = IPgosSDKCpp::Get().GetClientLobbyAPI();
if (lobby)
{
lobby->JoinLobby(Params, [](const FPgosResult& Ret, const FClientLobbyDetailInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("OnJoinLobbySuccess"))
}
else
{
UE_LOG(LogTemp, Log, TEXT("OnJoinLobbyFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}

4.4.4 Join a Application Needed Lobby

A player can send a join request to a lobby owner by calling the JoinLobby interface when the lobby's protection policy is LobbyProtection::ApplicationNeeded, and the house owner will decide whether to approve the join request.

#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"

void SomeUObjectClass::JoinLobby()
{
FClientJoinLobbyParams Params;
Params.lobby_id = TEXT("123456");
Params.password = "";
Params.join_token = "";
Params.payload = "custom payload data";

auto lobby = IPgosSDKCpp::Get().GetClientLobbyAPI();
if (lobby)
{
lobby->JoinLobby(Params, [](const FPgosResult& Ret, const FClientLobbyDetailInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("OnJoinLobbySuccess"))
}
else
{
UE_LOG(LogTemp, Log, TEXT("OnJoinLobbyFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}

The OnLobbyJoinRequest event will be pushed to the lobby owner and JoinLobbyParams::payload data will be written to the event.

Lobby owner can call the ApproveJoinRequest/RejectJoinRequest interface to handle join requests from players.

#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"

void SomeUObjectClass::ApproveJoinRequest()
{
FApproveJoinRequestParams Params;
Params.lobby_id = TEXT("123456");
Params.player_id = "";
Params.token = "token from event OnLobbyJoinRequest";

auto lobby = IPgosSDKCpp::Get().GetClientLobbyAPI();
if (lobby)
{
lobby->ApproveJoinRequest(Params, [](const FPgosResult& Ret) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("ApproveJoinRequest"))
}
else
{
UE_LOG(LogTemp, Log, TEXT("ApproveJoinRequest: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}

void SomeUObjectClass::RejectJoinRequest()
{
FRejectJoinRequestParams Params;
Params.lobby_id = TEXT("123456");
Params.player_id = "";
Params.token = "token from event OnLobbyJoinRequest";

auto lobby = IPgosSDKCpp::Get().GetClientLobbyAPI();
if (lobby)
{
lobby->RejectJoinRequest(Params, [](const FPgosResult& Ret) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("RejectJoinRequest"))
}
else
{
UE_LOG(LogTemp, Log, TEXT("RejectJoinRequest: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}

Event OnLobbyJoinRequestApproved/OnLobbyJoinRequestRejected will be triggered to the game client once the request has been processed by the lobby owner.

If the lobby owner approves the request, PGOS will immediately add the request initiato to the lobby.

It is important to note that there are a number of scenarios that can cause the OnLobbyJoinRequestApproved calling to fail:

  • The request has expired. Each request token has a validity period of 10min.
  • The player is offline. PGOS will not add offline players to lobby.

4.4.5 Join a Lobby with Groups

Try to join the specified groups in the lobby according to the specified priority value from small to large. If no available slots are found in all specified groups, the interface will return a failure. Slot selection within a group will follow the Team Selection Strategy configuration on the lobby configuration.

Teams Configuration of the lobby configuration needs to be switched to advanced mode to enable team groups.

image-20240701154204561

Interface prototype:

/**
* Join the specified group in the specified lobby. Try to join the specified groups in the lobby according to the specified priority value from small to large.
* Slot selection within the group follows the Team Selection Strategy configuration on the portal.
* The portal's lobby configuration needs to be switched to advanced mode.
*
* @param Params The information needed when join the lobby.
*/
void JoinLobbyWithGroups(
const FClientJoinLobbyWithGroupsParams& Params,
TFunction<void(const FPgosResult& Ret, const FClientLobbyDetailInfo* Data)> Callback) const;

struct FClientJoinLobbyWithGroupsParams : public FClientJoinLobbyParams
{
/** Try to join the specified groups in the lobby according to the specified priority value from small to large. key: group, value: priority. (priority cannot be less than 0) */
TMap<FString, int32> selected_groups;
};

struct FClientJoinLobbyParams
{
/** The lobby id to join */
FString lobby_id;
/** The lobby password. If the lobby is not encrypted, it doesn't need to be filled. */
FString password;
/**
* It is from the event of 'OnLobbyInvitation' if the player is invited to join a lobby,
* Otherwise it doesn't need to be filled.
*/
FString join_token;
/** Join request payload will be passed to the lobby owner in OnLobbyJoinRequest event for a lobby with LobbyProtection::ApplicationNeeded. */
FString payload;
};

Example Code:

#include "PgosSDKCpp.h"

void SomeUObjectClass::SomeFunction()
{
auto Lobby = IPgosSDKCpp::Get().GetClientLobbyAPI();
if (Lobby)
{
FClientJoinLobbyWithGroupsParams Params;
// Fill Params
Lobby->JoinLobbyWithGroups(Params, [](const FPgosResult& Ret, const FClientLobbyDetailInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("JoinLobbyWithGroups Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("JoinLobbyWithGroups Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}

4.4.6 Join a Lobby with Teams

Try to join the specified teams in a lobby according to the specified priority value from small to large. If no available slots are found in all specified teams, the interface will return a failure. When multiple teams have the same priority, slot selection follows the Team Selection Strategy configuration on the portal.

The portal's lobby configuration needs to be switched to advanced mode.

Interface prototype:

/**
* Join the specified team in the specified lobby. Try to join the specified teams in the lobby according to the specified priority value from small to large.
* When multiple teams have the same priority, slot selection follows the Team Selection Strategy configuration on the portal.
* The portal's lobby configuration needs to be switched to advanced mode.
*
* @param Params The information needed when join the lobby.
*/
void JoinLobbyWithTeams(
const FClientJoinLobbyWithTeamsParams& Params,
TFunction<void(const FPgosResult& Ret, const FClientLobbyDetailInfo* Data)> Callback) const;

struct FClientJoinLobbyWithTeamsParams : public FClientJoinLobbyParams
{
/** Try to join the specified teams in the lobby according to the specified priority value from small to large. key: team name, value: priority. (priority cannot be less than 0) */
TMap<FString, int32> selected_teams;
};

Example Code:

#include "PgosSDKCpp.h"

void SomeUObjectClass::SomeFunction()
{
auto Lobby = IPgosSDKCpp::Get().GetClientLobbyAPI();
if (Lobby)
{
FClientJoinLobbyWithTeamsParams Params;
// Fill Params
Lobby->JoinLobbyWithTeams(Params, [](const FPgosResult& Ret, const FClientLobbyDetailInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("JoinLobbyWithTeams Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("JoinLobbyWithTeams Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}

4.4.7 Quick join with filter data

PGOS will attempt to place the player into a lobby instance that meets the lobby global kv data filtering conditions, note that this operation does not guarantee success. If the QuickJoin interface returns a failure, the game can perform several automatic retries or allow the player to initiate a retry request.

Lobbies that meet any of the following conditions CANNT be joined via the QuickJoin interface:

  • Lobby with none Waiting status.
  • Invisible lobby.
  • Lobby with none FreeAccess protection strategy.
#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"

void SomeUObjectClass::TryQuickJoin()
{
FQuickJoinLobbyParams Params;
Params.lobby_config = TEXT("123456");
Params.lobby_data;
Params.selected_groups;
Params.selected_teams;

auto lobby = IPgosSDKCpp::Get().GetClientLobbyAPI();
if (lobby)
{
lobby->QuickJoinLobby(Params, [](const FPgosResult& Ret, const FClientLobbyDetailInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("OnQuickJoinSuccess"))
}
else
{
UE_LOG(LogTemp, Log, TEXT("OnQuickJoinFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}

4.4.8 Leave Lobby

The player leaves the lobby with the following scenarios:

  • Leave a lobby by calling LeaveLobby.
  • Players already in a lobby who join a new lobby will leave their previous lobby.
  • Players offline.
#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"

void SomeUObjectClass::LeaveLobby()
{
auto lobby = IPgosSDKCpp::Get().GetClientLobbyAPI();
if (lobby)
{
lobby->LeaveLobby([](const FPgosResult& Ret) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("OnLeaveLobbySuccess"))
}
else
{
UE_LOG(LogTemp, Log, TEXT("OnLeaveLobbyFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
Event NameEvent Description
OnLobbyMemberJoinedThe event will be triggered when someone joined current lobby.
OnLobbyMemberLeftThe event will be triggered when someone left current lobby.
OnLobbyInvitationThe event will be triggered when receive lobby invitations.
OnLobbyJoinRequestThe event will be triggered when a player request to join a lobby with protection type LobbyProtection::ApplicationNeeded.
OnLobbyJoinRequestApprovedThe event will be triggered when a join request has been approved by lobby owner.
OnLobbyJoinRequestRejectedThe event will be triggered when a join request has been reject by lobby owner.

4.5 Lobby Invitations

Anyone who has joined a lobby can invite other players to join the lobby. When a player receives a lobby invitation, they can either accept the invitation to join the lobby or ignore it.

sequenceDiagram participant A as Player A participant B as Player B participant C as Player C participant L as Lobby Service A->>L:InvitePlayer(PlayerB) L-->>B:OnLobbyInvitation B->>L:JoinLobby L-->>A:OnLobbyMemberJoined L-->>C:OnLobbyMemberJoined

Events:

  • OnLobbyInvitation: Sent to the invited player. The player can accept the invitation to join the lobby or ignore it.

Call InvitePlayer from Lobby module as follows:

#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"

void SomeUObjectClass::InvitePlayer()
{
FString PlayerId = ObtainFromSomeWhere();

auto lobby = IPgosSDKCpp::Get().GetClientLobbyAPI();
if (lobby)
{
lobby->InvitePlayer(PlayerId, [](const FPgosResult& Ret) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("OnInviteToLobbySuccess"))
}
else
{
UE_LOG(LogTemp, Log, TEXT("OnInviteToLobbyFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}

4.6 Search for a Lobby

4.6.1 Basic Search Capabilities

Lobbies can be searched using one or more of the options below:

  • lobby_config: The name of a lobby configuration.

  • status: You can search lobbies by status: LobbyStatus::Waiting, LobbyStatus::Preparing or LobbyStatus::Playing. Alternatively, pass LobbyStatus::Dummy to the API to search lobbies with any status.

  • protection: You can search lobbies by the protection type LobbyProtection::PasswordNeeded or LobbyProtection::PasswordUnneeded. Alternatively, pass LobbyProtection::Dummy to the API to search lobbies with any type of protection.

  • order_by: Various sorting options are available for search results,

    • LOBBY_ORDER_BY_DEFAULT: Sorting by status, then sorting by create time.
    • LOBBY_ORDER_BY_CREATE_TIME: Sort by lobby create time.
    • LOBBY_ORDER_BY_UPDATE_TIME: Sort by lobby last update time.
    • LOBBY_ORDER_BY_JOINED_MEMBER_COUNT: Sort by joined member count.
    • LOBBY_ORDER_BY_MISSING_MEMBER_COUNT: Sort by empty slot count.
  • order_type: Order direction of the search result,

    • LOBBY_ORDER_TYPE_ASCENDING: Ascending order for search result.
    • LOBBY_ORDER_TYPE_DESCENDING: Descending order for search result.

❗Note

  • Lobbies where privacy is set to LobbyPrivacy::Invisible can only be found using the exact lobby_id.
  • Set count in FClientSearchLobbyParams to 0 to only query the number of lobbies meeting the search criteria.
  • Set count in FClientSearchLobbyParams to a non-zero value to query both the count and a list of lobbies that meet the search criteria up to the number set in count.

Call SearchLobby from Lobby module as follows:

#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"

void SomeUObjectClass::SearchLobby()
{
FClientSearchLobbyParams Params;
Params.offset = 0;
Params.count = 20;
Params.protection = EClientLobbyProtection::LobbyProtection_PasswordUnneeded;

auto lobby = IPgosSDKCpp::Get().GetClientLobbyAPI();
if (lobby)
{
lobby->SearchLobby(Params, [](const FPgosResult& Ret, const FClientSearchLobbyResult* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("OnSearchLobbySuccess"))
}
else
{
UE_LOG(LogTemp, Log, TEXT("OnSearchLobbyFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}

4.6.2 Custom Filter Options

The SearchLobby interface allows filtering searching result with Lobby Global Data. Games can freely modify the lobby global data within the lobby instance and configure the fields that need to be filtered in the SearchLobbyParams::lobby_data parameter of the SearchLobby interface.

Two types of filtering are supported,

  • SearchLobbyDataFilter::equal_values: means to filter lobby instances that match any value in the values list for given key.
  • SearchLobbyDataFilter::not_equal_values: lobby instances that match any value in the value list for given key will not appear in the search results.

4.6.3 Example for Custom Filter Options

Here is a typical example of defining and filtering game modes using global data.

First, define the lobby instance data set:

lobby: 001
kv_data:
"game_mode":"solo_adventure"

lobby: 002
kv_data:
"game_mode":"co_adventure"

lobby: 003
kv_data:
"game_mode":"royale"

lobby: 004
kv_data:
"game_mode":"roguelike"

Here're examples of SearchLobbyDataFilter and the corresponding filtered results.

Filter all lobbies with game modes being roguelike and royale:

# Show case of SearchLobbyParams::lobby_data
"game_mode":
equal_values: ["roguelike", "royale"]
not_equal_values: []

Filter all lobbies with game modes not being roguelike and royale:

# Show case of SearchLobbyParams::lobby_data
"game_mode":
equal_values: []
not_equal_values: ["roguelike", "royale"]

4.7 Lobby Management

The owner of the lobby is able to:

  • Modify lobby options
  • Kick out members
  • Dismiss the lobby
  • Start a battle
  • Transfer ownership to other members

4.7.1 Modify Lobby Options

After the lobby is created, the lobby owner can modify the following lobby options:

  • name
  • password
  • privacy
  • kv_data
  • game_mode

Note

All the values passed to the API will replace the existing values, except kv_data. kv_data will only be valid if it is not empty. To clear kv_data, use the SetLobbyData API and pass an empty map to it.

sequenceDiagram participant A as Player A(Owner) participant B as Player B participant C as Player C participant L as Lobby Service A->>L:EditLobbyInfo L-->>A:OnLobbyInfoUpdated L-->>B:OnLobbyInfoUpdated L-->>C:OnLobbyInfoUpdated

Events:

  • OnLobbyInfoUpdated: Sent to all members of the lobby when the lobby owner updates the lobby options.

Call EditLobbyInfo from Lobby module as follows:

#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"

void SomeUObjectClass::EditLobbyInfo()
{
FClientEditLobbyInfoParams Params;
Params.name = TEXT("New Name");

auto lobby = IPgosSDKCpp::Get().GetClientLobbyAPI();
if (lobby)
{
lobby->EditLobbyInfo(Params, [](const FPgosResult& Ret, const FClientLobbyDetailInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("OnEditLobbySuccess"))
}
else
{
UE_LOG(LogTemp, Log, TEXT("OnEditLobbyFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}

4.7.2 Set Lobby Data

Lobby data can be updated without modifying other lobby options. Please note that the data passed to the SetLobbyData API will replace the existing data, that is, if you pass an empty map to the API, the lobby data will be cleared.

Tip:

You can use lobby data to store custom lobby options such as the game mode and game map.

sequenceDiagram participant A as Player A(Owner) participant B as Player B participant C as Player C participant L as Lobby Service A->>L:SetLobbyData L-->>A:OnLobbyDataUpdated L-->>B:OnLobbyDataUpdated L-->>C:OnLobbyDataUpdated

Events:

  • OnLobbyDataUpdated: Sent to all members of the lobby when the lobby owner updates the custom lobby data.

Call SetLobbyData from Lobby module as follows:

#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"

void SomeUObjectClass::SetLobbyData()
{
TMap<FString, FString> CustomData;
CustomData.Add(TEXT("GameMode"), TEXT("5v5"));

auto lobby = IPgosSDKCpp::Get().GetClientLobbyAPI();
if (lobby)
{
lobby->SetLobbyData(CustomData, [](const FPgosResult& Ret, const FClientLobbyDetailInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("OnSetLobbyDataSuccess"))
}
else
{
UE_LOG(LogTemp, Log, TEXT("OnSetLobbyDataFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}

4.7.3 Kick out Members

The lobby owner can kick out any other lobby member to make more team slots available.

sequenceDiagram participant A as Player A(Owner) participant B as Player B participant C as Player C participant L as Lobby Service A->>L:KickOutMember(Player B) L->>L:Remove player B L-->>A:OnLobbyMemberLeft(is_kick_out=true) L-->>C:OnLobbyMemberLeft(is_kick_out=true)

Events:

  • OnLobbyMemberLeft: Sent to the remaining members of the lobby when the lobby owner kicks someone out of the lobby.

Call KickOutMember from Lobby module as follows:

#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"

void SomeUObjectClass::KickOutMember()
{
FString MemberPlayerID = ObtainFromSomeWhere();

auto lobby = IPgosSDKCpp::Get().GetClientLobbyAPI();
if (lobby)
{
lobby->KickOutMember(MemberPlayerID, [](const FPgosResult& Ret, const FClientLobbyDetailInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("OnKickOutMemberSuccess"))
}
else
{
UE_LOG(LogTemp, Log, TEXT("OnKickOutMemberFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}

4.7.4 Dismiss the Lobby

A lobby will be dismissed in the following situations:

  • The owner dismisses the lobby.
  • Automatically if all the members have left or logged out.
sequenceDiagram participant A as Player A(Owner) participant B as Player B participant C as Player C participant L as Lobby Service A->>L:DismissLobby L-->>A:OnLobbyDismiss L-->>B:OnLobbyDismiss L-->>C:OnLobbyDismiss

Events:

  • OnLobbyDismiss: Sent to all the members of the lobby when the lobby owner dismisses the lobby.

Call DismissLobby from Lobby module as follows:

#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"

void SomeUObjectClass::DismissLobby()
{
auto lobby = IPgosSDKCpp::Get().GetClientLobbyAPI();
if (lobby)
{
lobby->DismissLobby([](const FPgosResult& Ret) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("OnDismissLobbySuccess"))
}
else
{
UE_LOG(LogTemp, Log, TEXT("OnDismissLobbyFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}

4.7.5 Start a Battle

4.7.5.1 Player Status

There is a ready flag for every lobby member. Players can update this flag at any point.

sequenceDiagram participant A as Player A participant B as Player B participant C as Player C participant L as Lobby Service A->>L:ReadyForBattle(true/false) L-->>A:OnLobbyTeamUpdated L-->>B:OnLobbyTeamUpdated L-->>C:OnLobbyTeamUpdated

Events:

  • OnLobbyTeamUpdated: Sent to all members of the lobby when players update their ready flags.

Call ReadyForBattle from Lobby module as follows:

#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"

void SomeUObjectClass::ReadyForBattle()
{
auto lobby = IPgosSDKCpp::Get().GetClientLobbyAPI();
if (lobby)
{
lobby->ReadyForBattle(true, [](const FPgosResult& Ret, const FClientLobbyDetailInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("OnReadyForBattleSuccess"))
}
else
{
UE_LOG(LogTemp, Log, TEXT("OnReadyForBattleFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
4.7.5.2 Lobby Status

A lobby can have one of the following statuses:

  1. Waiting: The battle has not started or has finished
  2. Preparing: Waiting for players to flag themselves ready to start a battle
  3. Playing: The battle has successfully started

The following chart shows how the lobby status changes from one to another:

image-20210115112531754

  1. Waiting -> Preparing: The lobby owner starts a battle, but not all players are ready.
  2. Preparing -> Waiting: Preparing times out or members join or leave the lobby interrupting the Preparing state.
  3. Waiting -> Playing: The lobby owner starts a battle, and all members in the lobby are ready.
  4. Playing -> Waiting: A battle is finished.
  5. Preparing -> Playing: The players who are not ready update their ready flags to true.

If the StartBattle API receives a successful response, it means that a new battle session will be placed on the dedicated server. When the battle session becomes ACTIVE, the player can connect to the dedicated server.

sequenceDiagram participant A as Player A(Owner) participant B as Player B participant C as Player C participant L as Lobby Service A->>L:StartBattle L-->>A:OnLobbyStatusChanged L-->>B:OnLobbyStatusChanged L-->>C:OnLobbyStatusChanged

Events:

  • OnLobbyStatusChanged: Sent to all members of the lobby when the lobby owner starts a battle.
  • OnBattleSessionUpdated: Sent to all members in the lobby when the status of the battle session updates.

Call StartBattle from Lobby module as follows:

#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"

void SomeUObjectClass::StartBattle()
{
auto lobby = IPgosSDKCpp::Get().GetClientLobbyAPI();
if (lobby)
{
lobby->StartBattle([](const FPgosResult& Ret, const FClientLobbyDetailInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("OnStartBattleSuccess"))
}
else
{
UE_LOG(LogTemp, Log, TEXT("OnStartBattleFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
4.7.5.3 Handle Battle Sessions in the Dedicated Server

When a battle is started on the client side, the dedicated server is notified of the details of the battle through the callback OnStartBattleSession.

#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"

void SomeUObjectClass::SomeFunction()
{
auto Hosting = IPgosSDKCpp::Get().GetServerHostingAPI();
if (Hosting)
{
HostingAPI->OnHealthCheck().AddUObject(this, &APGOSBattleGameMode::OnHealthCheck);
HostingAPI->OnStartBattleSession().AddUObject(this, &APGOSBattleGameMode::OnStartBattleSession);
HostingAPI->OnProcessTerminate().AddUObject(this, &APGOSBattleGameMode::OnProcessTerminate);
HostingAPI->OnTerminateBattleSession().AddUObject(this, &APGOSBattleGameMode::OnTerminateBattleSession);

// Notify PGOS that a server process is ready to host a battle session
FPgosResult Result = HostingAPI->ProcessReady(Port, LogPathes,
OnHealthCheckCallback, OnStartBattleSessionCallback, OnProcessTerminateCallback);
}
}

bool SomeUObjectClass::OnHealthCheck()
{
...
}

void SomeUObjectClass::OnStartBattleSession(const FServerBattleSession& BattleSession)
{
...
for (const FServerBattleTeam& TeamData: BattleSession.battle_data.teams)
{
...
for (const FServerPlayerDesc& PlayerDesc: TeamData.players)
{
// PlayerDesc.player_info.player_id may be empty then the team slot has no player
}
}
}

void SomeUObjectClass::OnProcessTerminate(int64 TerminationTime)
{
...
}

void SomeUObjectClass::OnTerminateBattleSession(pgos::pstring battle_session_id)
{
...
}

As you can see from the above code, the dedicated server can retrieve all the team and player information from the OnStartBattleSession. Unlike with matchmaking, the Lobby Service can start a battle when there are empty slots in the lobby. On the dedicated server, an empty player_id in a PlayerDesc means an empty slot in the lobby.

4.8.6 Transfer Ownership to other Members

Lobby ownership will be transferred to another player if:

  • The lobby owner transfers ownership to a specific player.
  • The lobby owner leaves the lobby and there are still players in the lobby. In this case, ownership will be randomly transferred to another player in the lobby.
sequenceDiagram participant A as Player A(Owner) participant B as Player B participant C as Player C participant L as Lobby Service A->>L:TransferOwnerShip(PlayerB) L-->>A:OnLobbyOwnerTransferred L-->>B:OnLobbyOwnerTransferred L-->>C:OnLobbyOwnerTransferred

Events:

  • OnLobbyOwnerTransferred: Sent to all members of the lobby when ownership of the lobby is transferred to another player.

Call TransferOwnership from Lobby module as follows:

#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"

void SomeUObjectClass::TransferOwnership()
{
FString NewOwnerPlayerId = ObtainFromSomeWhere();

auto lobby = IPgosSDKCpp::Get().GetClientLobbyAPI();
if (lobby)
{
lobby->TransferOwnership(NewOwnerPlayerId, [](const FPgosResult& Ret, const FClientLobbyDetailInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("OnTransferSuccess"))
}
else
{
UE_LOG(LogTemp, Log, TEXT("OnTransferFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}

4.8 Lobby Chat

The Lobby Service has built-in chat functions which can be used directly. However, these services are valid only if enable_chatting is set to true when Creating a Lobby.

  • Any member of the lobby can send chat messages
  • Any member of the lobby can receive chat messages
  • Members will not receive chat messages from themselves
sequenceDiagram participant A as PlayerA participant B as PlayerB participant C as PlayerC participant Chat as Lobby Service A->>Chat:SendLobbyChatTextMsg(Message) Chat-->>A:return success(ClientChatMsgInfo) or failed Chat-->>B:OnReceiveLobbyChatMsg:ChatMsgInfo Chat-->>C:OnReceiveLobbyChatMsg:ChatMsgInfo

Events:

  • OnReceiveLobbyChatMsg: Sent to all members of the lobby except the sender.

Call SendLobbyChatTextMsg/SendLobbyChatCustomMsg from Lobby module as follows:

  #include "PgosSDKCpp.h"

void SomeUObjectClass::SendLobbyChatTextMsg()
{
auto Lobby = IPgosSDKCpp::Get().GetClientLobbyAPI();
if (Lobby)
{
FClientSendLobbyChatMsgParams Params;
Lobby->SendLobbyChatTextMsg(Params, [](const FPgosResult& Ret, const FClientChatMsgInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("SendLobbyChatTextMsg Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("SendLobbyChatTextMsg Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}

void SomeUObjectClass::SendLobbyChatCustomMsg()
{
auto Lobby = IPgosSDKCpp::Get().GetClientLobbyAPI();
if (Lobby)
{
FClientSendLobbyChatMsgParams Params;
Lobby->SendLobbyChatCustomMsg(Params, [](const FPgosResult& Ret, const FClientChatMsgInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("SendLobbyChatCustomMsg Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("SendLobbyChatCustomMsg Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}

4.9 Lobby Events

To summarize, the events that will be sent to lobby members are listed below:

Event NameEvent Description
OnLobbyTeamUpdatedSent when players update their ready flags or change their team slots.
OnLobbyMemberJoinedSent when a new player joins a lobby.
OnLobbyMemberLeftSent when a member leaves a lobby or is kicked out of a lobby by the owner.
OnLobbyInvitationSent when a player sends a lobby invitation to another player.
OnLobbyInfoUpdatedSent when lobby options are updated.
OnLobbyDataUpdatedSent when custom lobby data is updated.
OnLobbyDismissSent when a lobby is dismissed.
OnLobbyStatusChangedSent when the lobby status is updated.
OnBattleSessionUpdatedSent when the battle session status is updated.
OnLobbyOwnerTransferredSent when lobby ownership is transferred.
OnReceiveLobbyChatMsgSent when a player sends a chat message in the lobby.
OnLobbySwitchTeamSlotRequestSent when another lobby member send a team-slot switch request.
OnLobbySwitchTeamSlotRequestConfirmedSent when a team-slot switch request has been confirmed.
OnLobbySwitchTeamSlotRequestRejectedSent when a team-slot switch request has been rejected.
OnLobbyJoinRequestSent when a player request to join a lobby with protection type LobbyProtection::ApplicationNeeded.
OnLobbyJoinRequestApprovedSent when a join request has been approved by lobby owner.
OnLobbyJoinRequestRejectedSent when a join request has been reject by lobby owner.
OnLobbyGlobalCustomDataUpdatedSent when lobby global custom data updated.
OnLobbyPlayerCustomDataUpdatedSent when lobby player custom data updated.
Note

This section discusses a special event OnLobbyInfoUpdated, which is triggered when there is a change in the lobby info.

Normally, changes in lobby info are indicated by more specific events. For example, the OnLobbyMemberLeft event is triggered when a member leaves a lobby, the OnLobbyMemberJoined event is triggered when new players join the lobby, and the OnLobbyInfoUpdated event is triggered when the lobby owner calls EditLobbyInfo to modify lobby info.

However, due to network issues or other reasons that may cause disruptions in the persistent connection, there might be changes in the lobby info (such as players entering or leaving the lobby) that the server cannot communicate to the client through the persistent connection. If the client is unable to detect changes in the lobby info for an extended period, it could lead to functional anomalies in the game. To address this issue, the PGOS SDK periodically (usually every 30 to 60 seconds) retrieves the latest lobby info when it detects a disruption in the persistent connection and then notifies the game through the OnLobbyInfoUpdated event.

Therefore, when the game receives the OnLobbyInfoUpdated event, it could be due to the lobby owner calling EditLobbyInfo, or it could be due to changes associated with the following events:

  • OnLobbyTeamUpdated
  • OnLobbyMemberJoined
  • OnLobbyMemberLeft
  • OnLobbyInfoUpdated
  • OnLobbyDataUpdated
  • OnLobbyStatusChanged
  • OnLobbyOwnerTransferred
  • OnLobbyGlobalCustomDataUpdated
  • OnLobbyPlayerCustomDataUpdated

You can use UPgosClientEventDispatcher to handle event binding issues for these events.

Bind dynamic delegate to OnLobbyMemberJoined as follows:

#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"

void SomeUObjectClass::SomeFunction()
{
auto lobby = IPgosSDKCpp::Get().GetClientLobbyAPI();
if (lobby)
{
lobby->OnLobbyMemberJoined().AddUObject(this, &SomeUObjectClass::OnLobbyMemberJoined);
}
}

void SomeUObjectClass::OnLobbyMemberJoined(const FClientLobbyMemberJoinedEvt& event)
{
UE_LOG(LogTemp, Log, TEXT("OnLobbyMemberJoined"));
}

5. Lobby Logs on the Web Portal

When a lobby is created, the PGOS backend automatically generates and stores a log that you can find in the PGOS Web Portal. On the console page, select the Title you want to query and navigate to Battle > Lobby to see a list of lobby logs:

The logs can be filtered by the following fields:

  • Lobby id or uuid
  • Creator id of a lobby
  • Lobby configuration name
  • Lobby status

Click a lobby id to view more details of the log:

img

  • Lobby ID: A unique lobby ID which was displayed on the game client.
  • Lobby UUID: An unique lobby ID used by the PGOS backend.
  • Name: The name of the lobby.
  • Lobby Configuration: The name of the lobby configuration.
  • Status: The current lobby status.
  • Owner: The name of the lobby owner.
  • Battlesession: Details of the current battle; this is empty if the battle has not started.
  • Chat Channel ID: An unique chat channel ID for the lobby's chat channel; empty if enable_chatting was set to false when the lobby was created.
  • Members: The actions of lobby members, such as joining, leaving, and dismissing the lobby.
  • Status Changes: Changes of the lobby status.
  • Created Time: The time the lobby was created.
  • Dismissed Time: The time the lobby was dismissed; empty if lobby has not been dismissed.

6. Key Errors Handling

These are key errors but not all of them. For the errors not on the list, the error message should already indicate the problem. Please contact us if you encounter obscure error messages or any other critical errors.

Error CodeRelevant APIHandling Suggestion
kBackendAcquireLockFailedAll APIs on a specified lobby.
Except for CreateLobby or SearchLobby.
It means that the operation on lobby failed. The concurrency safety is guaranteed by distributed lock mechanism. It's recommended to retry for limited times until it succeeds.
kBackendHasNoWritePermissionLobby management related APIsIt means that the operator has no write permission on the lobby. The game can prompt the player a message like "You need to be lobby owner to do this".
kBackendPlayerNotInLobbyAll APIs on a specified lobby.
Except for JoinLobby.
It means that the operator is not in the lobby, thus has no permission to perform any operations on it.
kBackendInvalidLobbyConfigCreateLobbyIt means the lobby config name does not exist. Developers should check on web portal if the lobby config had been removed or renamed accidentally.
kBackendLobbyPasswordIsEmptyCreateLobbyIt means the protection indicates that the lobby is protected by password, but no password is specified.
kBackendLobbyInvalidGameModeCreateLobby
EditLobbyInfo
It means the specified game mode is not pre-defined on lobby config.
kBackendIllegalCredentialJoinLobbyIt means the player entered the wrong password when joining lobby. The game can prompt the player a message like "Wrong password".
kBackendNotEnoughSlotsJoinLobbyIt means the lobby has no empty slot for new joiner. The game can prompt the player a message like "Lobby is full".
kBackendLobbyWaitForApprovalJoinLobbyIt means the player should wait for the lobby owner to approve his join request.
kBackendFailedToNotifyLobbyOwnerJoinLobbyIt means the system failed to notify lobby owner about the player's join request.
kBackendLobbyGroupNotExistJoinLobbyWithGroupIt means the lobby doesn't contain any one of selected groups.
kBackendLobbyTeamNotExistJoinLobbyWithTeamIt means the lobby doesn't contain any one of selected teams.
kBackendAlreadyInBattleStartBattleIt means the lobby is already has an active battle session. The lobby cannot start a new battle until the current battle session ended. The game can provide the player an entrance to rejoin the current battle session.
kBackendAlreadyPreparingStartBattleIt means the lobby is in preparing stage, thus the owner cannot start battle again.
kBackendTitleRegionIsClosedStartBattleIt means the title region is closed. The game should prompt the player a message like "Server is in maintenance, please come back later".
kBackendLobbyStartBattleConditionNotMatchStartBattleIt means not all members are ready to start battle. This error only occurs when preparing stage is disabled in lobby config.
kBackendLobbyNameContainProfanityWordsCreateLobby
EditLobbyInfo
It means the lobby name to change contains profanity words. The game can prompt the player a message like "Please remove profanity words in lobby name".
kBackendLobbyPlayerBlockedInvitationInviteMemberIt means the operation is blocked by peer player.
kBackendCannotSwitchToEmptySlotRequestSwitchTeamSlotIt means the player cannot request switch to an empty slot. Should call SwitchTeamSlot directly.
kBackendLobbyInvalidRequestIdConfirmSwitchTeamSlotIt means the request id of switching slot is invalid.
kBackendLobbyOutdatedRequestIdConfirmSwitchTeamSlotIt means the player who requested switching slot has moved.
kBackendLobbyCustomDataLengthExceededSetGlobalCustomData
SetPlayerCustomData
It means the custom data exceeded the length limit.
kBackendLobbyPlayerIsOfflineApproveJoinLobbyIt means the player who requested to join lobby has been offline.
kBackendLobbyJoinTokenInvalidApproveJoinLobbyIt means the token of the approve request is invalid.