Configure Lobby with the SDK
Overview
AccelByte Gaming Services (AGS) Lobby provides continuous connection between your game and its players by using The WebSocket Protocol. WebSockets ensure reliable, real-time data transfer by allowing two-way communication between the server and clients. Since AGS Lobby is the main hub of your game, it is connected to many of the other AGS features.
This article covers configuring Lobby with the AGS Game SDK.
Goals
The goals of this article are to show you how to use the AGS Game SDK to:
- Connect to AGS Lobby.
- Handle connect and disconnect events.
- Handle user presence.
- Listen to notifications.
Prerequisites
To be able to complete the steps in this article, you will need the following:
- A familiarity with the Authentication flow that occurs before a player reaches AGS Lobby.
- Access to the AGS Admin Portal.
- The AGS Game SDK installed to your Unreal or Unity project and the following credentials for your game client:
- Client ID
- Client Secret
Connect to Lobby
This section will show you how to connect a user to Lobby.
- OSS
- Unreal Engine
- Unity
There are two ways to connect to Lobby in the AGS Online Subsystem (OSS):
- Setting
bAutoLobbyConnectAfterLoginSuccess
totrue
inDefaultEngine.ini
under the[OnlineSubsystemAccelByte]
section. Once set, the OSS will try to connect to Lobby upon a successful user login. - If it's not automatically connected, you can call
FOnlineIdentityAccelByte::ConnectAccelByteLobby
.
// Manually connect to Lobby
int32 LocalUserNum = 0;
FOnlineIdentityAccelBytePtr IdentityInterface = StaticCastSharedPtr<FOnlineIdentityAccelByte>(OnlineSubsystem->GetIdentityInterface());
AB_TEST_TRUE(IdentityInterface.IsValid());
IdentityInterface->ConnectAccelByteLobby(LocalUserNum);
Use the following code to connect a user to Lobby:
AccelByte::FRegistry::Lobby.Connect();
We strongly recommend connecting to the Lobby service immediately after successful authentication. This practice helps prevent race conditions and ensures accurate CCU metrics tracking. Use the following code to establish the Lobby connection:
AccelByteSDK.GetClientRegistry().GetApi().GetLobby().Connect();
Once you have set up a Lobby connection, you can add features such as Presence, Party, Friends, and Chat.
Disconnect from Lobby
This section explains how to disconnect a user from the Lobby service and best practices for doing so.
- Unity
Only disconnect a user if they log out or if the game client is exiting or crashing. In these cases, use the following code:
User user = AccelByteSDK.GetClientRegistry().GetApi().GetUser();
Lobby lobby = AccelByteSDK.GetClientRegistry().GetApi().GetLobby();
void Logout()
{
user.Logout(logoutResult =>
{
if (logoutResult.IsError)
{
// Handle logout error here
return;
}
lobby.Disconnect();
});
}
void OnApplicationQuit()
{
lobby.Disconnect();
}
Handle connect and disconnect events
For troubleshooting purposes, make sure you call the disconnect function when your player voluntarily quits the game (e.g., through the menu, using Alt+F4, turning off the game console, etc.). You do not need to call the function on accidental shutdowns (e.g., game crashes, power outages, etc.).
You can look up the code of the
Disconnected
callbacks in your developer environment (e.g.,https://prod.gamingservices.accelbyte.io/lobby/v1/messages
).A
SetReconnectingDelegate
will be triggered when the SDK automatically reconnects to Lobby.ConnectionClosed
will be triggered if auto-reconnect times out with the following status code:
EWebsocketErrorTypes::DisconnectFromExternalReconnect (4042)
Reconnection total timeout limit reached
This feature notifies the game of any changes to the Lobby server connection. The SDK already provides an auto-reconnect mechanism, but when the auto-reconnect times out, you must reconnect manually.
- OSS
- Unreal Engine
- Unity
In OSS, Lobby will automatically disconnect when a user logs out.
You can add several delegates to be notified for Lobby connection events.
To access delegates, you need to get the AGS Identity Interface with type FOnlineIdentityAccelBytePtr
. Use the following code:
const IOnlineSubsystem* Subsystem = Online::GetSubsystem(GetWorld());
if (!ensure(Subsystem != nullptr))
{
return;
}
const FOnlineIdentityAccelBytePtr IdentityInterface = StaticCastSharedPtr<FOnlineIdentityAccelByte>(Subsystem->GetIdentityInterface());
if (!ensure(IdentityInterface.IsValid()))
{
return;
}
The following are the delegates that you can use:
Lobby Connected: this delegate will be triggered when successfully connecting to the lobby.
auto Handle = IdentityInterface->AddAccelByteOnConnectLobbyCompleteDelegate_Handle(UserNum, FAccelByteOnConnectLobbyCompleteDelegate::CreateLambda(
[&](int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& UserId, const FOnlineErrorAccelByte& Error)
{
if(bWasSuccessful)
{
// Handle successful lobby connection
}
else
{
// Handle failed connection from Error field
}
}));Lobby Connection Closed: this delegate will be triggered when the lobby connection fails or fails to reconnect.
auto Handle = IdentityInterface->AddAccelByteOnLobbyConnectionClosedDelegate_Handle(UserNum, FAccelByteOnLobbyConnectionClosedDelegate::CreateLambda(
[&](const int32 LocalUserNum, const FUniqueNetId& UserId, const int32 StatusCode, const FString& Reason, const bool bWasClean)
{
// Handle failed lobby connectionLobby Reconnecting: this delegate will be triggered when the lobby connection is temporarily disconnected while the SDK attempts to automatically reconnect. By default, the reconnection is completed within 60 seconds.
auto Handle = IdentityInterface->AddAccelByteOnLobbyReconnectingDelegate_Handle(UserNum, FAccelByteOnLobbyReconnectingDelegate::CreateLambda(
[&](const int32 LocalUserNum, const FUniqueNetId& UserId, const int32 StatusCode, const FString& Reason, const bool bWasClean)
{
// Handle lobby connection when temporarily disconnected
}));Lobby Reconnected: this delegate will be triggered when successfully reconnecting to the lobby.
auto Handle = IdentityInterface->AddAccelByteOnLobbyReconnectedDelegate_Handle(UserNum, FAccelByteOnLobbyReconnectedDelegate::CreateLambda(
[&]
{
// Handle lobby connection when successfully reconnected
}));
In OSS, Lobby will automatically disconnect when a user logs out.
FRegistry::Lobby.Connect();
FRegistry::Lobby.SetConnectSuccessDelegate(AccelByte::Api::Lobby::ConnectSuccess.CreateLambda([]()
{
// Do something when ConnectSuccessDelegate succeeds
}));
FRegistry::Lobby.SetConnectFailedDelegate(AccelByte::Api::Lobby::ConnectError.CreateLambda([]()
{
// Do something when ConnectFailedDelegate succeeds
}));
FRegistry::Lobby.SetConnectionClosedDelegate(AccelByte::Api::Lobby::ConnectionClosed.CreateLambda([]()
{
// Do something when ConnectionClosedDelegate succeeds
}));
var lobby = AccelByteSDK.GetClientRegistry().GetApi().GetLobby();
lobby.Connect();
lobby.Connected += () =>
{
// Do something when Lobby connects
};
lobby.Disconnected += error =>
{
// Do something when Lobby disconnects
Debug.Log($"Lobby Disconnected, Error Code: {(int) error}");
};
Presence
AGS Presence is part of AGS Social. Presence handles the statuses of user presences (Availability and Activity).
The Availability status is how users want to be seen when going online (e.g., online, offline, away, etc.). The Activity status is an arbitrary string value that can be used to show the user's current activity (e.g., idle, playing a game, in a lobby, in matchmaking, in a match, etc.). AGS Presence depends on AGS Friends as a filter to list online friends and get changing presence statuses.
AGS Presence flow:
- Get all friends' presence statuses after the user initializes a connection with Lobby.
- Set the user status every time the user changes activity.
- Listen for friends' presence status updates and update friends' presence status.
- User availability is automatically reset to 0 when the user gets disconnected from the Lobby server.
- User activity is kept when the user gets disconnected from the Lobby server.
Availability represented as an enum integer:
- 0 : offline
- 1 : available
- 2 : busy
- 3 : invisible
Activity can be set as any string. For example:
- "Playing Survival"
- "In Lobby"
- "In Match"
Create a status and view a friend's status
A player's presence can be set by a game, the Player Portal, or a Launcher. This allows the player's friends to see when the player is online and what they are doing.
- OSS
- Unreal Engine
- Unity
OnlineSubsystem = static_cast<FOnlineSubsystemAccelByte*>(IOnlineSubsystem::Get(ACCELBYTE_SUBSYSTEM));
PresenceInterface = OnlineSubsystem->GetPresenceInterface();
// Listen for friend presence change notifications
auto OnPresenceReceived = PresenceInterface->AddOnPresenceReceivedDelegate_Handle(FOnPresenceReceivedDelegate::CreateLambda([](const class FUniqueNetId& UserId, const TSharedRef<FOnlineUserPresence>& Presence)
{
// Do something when a friend presence changes
}));
// Create or change a status
PresenceInterface->SetPresence(*CurrentUser.Get(), Status, IOnlinePresence::FOnPresenceTaskCompleteDelegate::CreateLambda([](const FUniqueNetId& User, bool bWasSuccessful)
{
// Do something when a presence is successfully set
}));
// View a friend's changed status
```cpp
// View Changed Friend's Status
AccelByte::FRegistry::Lobby.SetUserPresenceNotifDelegate(THandler<FAccelByteModelsUsersPresenceNotice>::CreateLambda([](const FAccelByteModelsUsersPresenceNotice Result)
{
UE_LOG(LogTemp, Log, TEXT("Friend %s, Activity: %s | Availability: %s "), Result.UserID, Result.Activity, Result.Availability);
}
));
// Create or change a status
AccelByte::FRegistry::Lobby.SetUserPresenceResponseDelegate(Api::Lobby::FSetUserPresenceResponse::CreateLambda([](FAccelByteModelsSetOnlineUsersResponse result)
{
UE_LOG(LogTemp, Log, TEXT("User Status Changed!"));
}));
FString UserActivity = TEXT("Playing Game");
AccelByte::FRegistry::Lobby.SendSetPresenceStatus(Availability::Busy, UserActivity);
AccelByteSDK.GetClientRegistry().GetApi().GetLobby().FriendsStatusChanged += result =>
{
if (result.IsError)
{
// Do something when an error is received from FriendsStatusChanged
Debug.Log(result.Error.Message);
return;
}
// Do something when FriendsStatusChanged succeeds
Debug.Log("Friend " + result.Value.userID + ", Activity: " + result.Value.activity + " | Availability: " + result.Value.availability);
};
// Create or change a status
string userActivity = "Playing Game";
AccelByteSDK.GetClientRegistry().GetApi().GetLobby().SetUserStatus(
UserStatus.Busy,
userActivity,
result =>
{
if (result.IsError)
{
// Do something when SetUserStatus fails
Debug.Log(result.Error.Message);
return;
}
// Do something when SetUserStatus succeeds
Debug.Log("User Status Changed!");
}
);
Get a list of friends' statuses
Players can also see a list of all of their friends' statuses.
- Unreal Engine
- OSS
- Unity
AccelByte::FRegistry::Lobby.SetGetAllUserPresenceResponseDelegate(Api::Lobby::FGetAllFriendsStatusResponse::CreateLambda([](FAccelByteModelsGetOnlineUsersResponse result)
{
for(int i = 0; i < Result.friendId.Num(); i++)
{
UE_LOG(LogTemp, Log, TEXT("Friend %s, Activity: %s | Availability: %s "), Result.friendId[i], Result.Activity[i], Result.Availability[i]);
}
}));
AccelByte::FRegistry::Lobby.SendGetOnlineUsersRequest();
This feature is not available in OSS.
AccelByteSDK.GetClientRegistry().GetApi().GetLobby().ListFriendsStatus(result =>
{
if (result.IsError)
{
// Do something when ListFriendsStatus fails
Debug.Log(result.Error.Message);
return;
}
// Do something when ListFriendsStatus succeeds
for (int i = 0; i < result.Value.friendsId.Length; i++)
{
Debug.Log("Friend " + result.Value.friendsId[i] + ", Activity: " + result.Value.activity[i] + " | Availability: " + result.Value.availability[i]);
}
});
Not all of the friends' statuses may return. If there are missing friends' statuses, you need to set the availability to offline in the game implementation.
Bulk friends presence
You can retrieve all players' presence information in bulk. This will also count the number of users based on their presence status (such as online, busy, invisible, or offline). You can also set the countOnly
parameter to true
to fetch the count without fetching the users' account data.
- OSS
- Unreal Engine
- Unity
OnlineSubsystem = static_cast<FOnlineSubsystemAccelByte*>(IOnlineSubsystem::Get(ACCELBYTE_SUBSYSTEM));
PresenceInterface = OnlineSubsystem->GetPresenceInterface();
auto OnPresenceReceived = PresenceInterface->AddOnPresenceReceivedDelegate_Handle(FOnPresenceReceivedDelegate::CreateLambda([](const class FUniqueNetId& UserId, const TSharedRef<FOnlineUserPresence>& Presence)
{
// Do something when querying a user presence completes
}));
PresenceInterface->QueryPresence(UserId);
TArray<FString> UserIds = {FString("12345abcd"), FString("abcd12345")};
bool CountOnly = true;
FRegistry::Lobby.Connect();
FRegistry::Lobby.BulkGetUserPresence(UserIds, THandler<FAccelByteModelsBulkUserStatusNotif>::CreateLambda([](const FAccelByteModelsBulkUserStatusNotif& Result)
{
// Do something if BulkGetUserPresence succeeds
}), FErrorHandler::CreateLambda([](int32 ErrorCode, const FString& ErrorMessage)
{
// Do something if BulkGetUserPresence has an error
UE_LOG(LogTemp, Log, TEXT("Error BulkGetUserPresence, Error Code: %d Error Message: %s"), ErrorCode, *ErrorMessage);
}), CountOnly);
var userIds = new List<string>();
userIds.Add("123456789");
userIds.Add("987654321");
bool countOnly = false;
AccelByteSDK.GetClientRegistry().GetApi().GetLobby().BulkGetUserPresence(userIds.ToArray(), result =>
{
if (result.IsError)
{
// Do something when BulkGetUserPresence fails
Debug.Log("Error: " + result.Error.Code + " | Message: " + result.Error.Message);
return;
}
// Do something when the BulkGetUserPresence succeeds
foreach (var user in result.Value.data)
{
Debug.Log("UserId: " + user.userID + " | Availability: " + user.availability.ToString());
}
Debug.Log("User's status count. Online: " + result.Value.online + " | Busy:" + result.Value.busy + " | Invisible:" + result.Value.invisible + " | Offline:" + result.Value.offline);
}, countOnly);
Notifications
There are several tasks involving notifications:
Send freeform notifications
- Call the notification REST API endpoint to send any text notification messages.
- The notification clients listen for new notifications.
Send templated notifications
- An admin will create notification templates with a template slug (identifier), context (template values to be replaced), and template language.
- An admin will publish the template.
- The template slug, context, and language are sent to the service consumer (admin user or other service).
- The service consumer calls the notification REST API endpoint, specifying the template slug, language, and the value of template context.
- The notification clients listen for new notifications.
Send asynchronous notifications
- Follow the workflow of freeform or templated notifications.
- When calling the REST API endpoint, specify the query parameter as asynchronous.
- A message will be immediately sent if the player is online.
- A message will be stored if the player is offline.
Get stored notifications
- A player connects to the Lobby server.
- A notification can be sent to a player.
All notifications sent to users are in a general format. Clients can decide where to place the notifications based on the topic set on the notification. For example, game update notifications can be displayed as a pop up, a game server notifications can be displayed in a system chat box, etc.
WebSocket notification format
A Notification message:
type: messageNotif
topic: updateNotification
from: system
to: user123
payload: message content 123
sentAt: 2018-11-25T23:45:05Z
Retrieve synchronous notifications
To retrieve a synchronous notification using the SDK, you need to add the notification delegate.
- Unreal Engine
- OSS
- Unity
const auto NotificationDelegate = AccelByte::Api::Lobby::FMessageNotif::CreateLambda([](const FAccelByteModelsNotificationMessage& Result)
{
UE_LOG(LogTemp, Log, TEXT("There is an incoming notification."));
UE_LOG(LogTemp, Log, TEXT("From: %s \nTo: %s\nTopic: %s"), *Result.From, *Result.To, *Result.Topic);
UE_LOG(LogTemp, Log, TEXT("Notification: %s"), *Result.Payload);
});
AccelByte::FRegistry::Lobby.SetMessageNotifDelegate(NotificationDelegate);
AccelByte::FRegistry::Lobby.Connect();
This feature is not available in OSS
public static void OnReceiveNotification(Result<Models.Notification> result)
{
if (result.IsError)
{
// Do something when OnReceiveNotification fails
Debug.Log(result.Error.Message);
return;
}
// Do something when OnReceiveNotification succeeds
Debug.Log(result.IsError);
Debug.Log("There is an incoming notification.");
Debug.Log(result.Value.payload);
}
public static void Main(string[] args)
{
var lobby = AccelByteSDK.GetClientRegistry().GetApi().GetLobby();
lobby.OnNotification += OnReceiveNotification;
lobby.Connect();
}
You can also filter notifications by topic:
- Unreal Engine
- OSS
- Unity
const auto NotificationDelegate = AccelByte::Api::Lobby::FMessageNotif::CreateLambda([](const FAccelByteModelsNotificationMessage& Result)
{
UE_LOG(LogTemp, Log, TEXT("There is an incoming notification."));
if(Result.Topic == "INGAME")
{
UE_LOG(LogTemp, Log, TEXT("Game notification: %s"), *result.Payload);
}
Else if(Result.Topic == "EVENT")
{
UE_LOG(LogTemp, Log, TEXT("Event notification: %s"), *result.Payload);
}
});
This feature is not available in OSS
public static void OnReceiveNotification(Result<Models.Notification> result)
{
if (result.IsError)
{
// Do something when OnReceiveNotification fails
Debug.Log(result.Error.Message);
return;
}
// Do something when OnReceiveNotification succeeds
Debug.Log("There is an incoming notification.");
switch (result.Value.topic)
{
case "INGAME" : Debug.Log("Game notification: " +result.Value.payload); break;
case "EVENT" : Debug.Log("Event notification: " +result.Value.payload); break;
}
}