Skip to main content

Multiple Registries

Last updated on December 21, 2023

Overview

Multiple Registries is a feature designed to support multiple local users logging in to the same game instance in AccelByte Cloud’s services. Having multiple registries allows game developers to create games that can support local multiplayer. It stores player information and progression for each player independently based on the account linked with the game controller.

Multiple registries are effectively containers of API clients that store logged-in player information and act as a player when calling AccelByte Cloud’s APIs.

The current SDK had limitations as it used a singleton class to represent a player, thus only allowing one account to log in at any given time within the same game instance. To overcome these limitations, we created a new class, ApiClient to represent a player. It serves the same purpose and uses the same entry point to access AccelByte Cloud’s APIs. Game developers will need to use this new class and the multiple registries will maintain this class. The benefits of using the ApiClient infrastructure include:

  • Reduces singleton and/or static class usage.
  • Easier to manage for developers, who can easily create and/or delete ApiClient instances.
  • More extensible as the ApiClient is used as the entry point to create custom API classes.

After you have implemented the ApiClient class, the API calls operate in a similar manner to the previous SDK’s. These SDK changes will also impact game server implementation (which was previously mixed between client and server implementation). A new class called ServerApiClient has therefore been created to focus on managing game server-related APIs.

Prerequisites

Before you can implement multiple registries, you will need to install the plugins and modules of the game engine you’re using. Choose either:

note

If you want to use the AccelByte Cloud Online Subsystem (OSS) in Unreal Engine, you will need these additional plugins:

Configuration

You also need to configure the SDK before applying to implement multiple registries in your game. For more information about AGS SDKs, refer to the following guides:

Implement Multiple Registries Using the Client SDKs

How to Implement Multiple Registries

  1. Include the following library in the top of your class before implementing multiple registries.
#include "Core/AccelByteMultiRegistry.h"

The ApiClient represents a player in your game and holds the additional APIs needed to create and send requests to the backend services.

  1. Define each player in this class so each player can be isolated by calling GetApiClient(), using an unique key for each player.

    NOTE

    For the unique key, use the following rule:

    • Unreal: use FString with the default as default.
    • Unreal (OSS): use int with no default value.
    • Unity: use string with the default as default. Make sure to use the same key if you want to call the function in other classes.
// Define User A
FApiClientPtr ApiClientA = FMultiRegistry::GetApiClient(TEXT("0"));
// Define User B
FApiClientPtr ApiClientB = FMultiRegistry::GetApiClient(TEXT("1"));
  1. As this is a gateway, you will need to authenticate each player before they can access any AccelByte Cloud services. To do this, set up AccelByte Cloud’s login method. You can use any login method that AccelByte Cloud allows, such as the username method in the example below:
// Define User
FApiClientPtr ApiClientA = FMultiRegistry::GetApiClient(TEXT("0"));
FApiClientPtr ApiClientB = FMultiRegistry::GetApiClient(TEXT("1"));

// Login with username
ApiClientA->User.LoginWithUsername(
TEXT("user+a@example.com"),
TEXT("Password321"),
FVoidHandler::CreateWeakLambda(this, [this]()
{
UE_LOG(LogTemp, Log, TEXT("Login User A successful"));
}), FCustomErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage, const FJsonObject& ErrorObject)
{
UE_LOG(LogTemp, Error, TEXT("Login User A Failed : %d, %s"), ErrorCode, *ErrorMessage);
}));

ApiClientB->User.LoginWithUsername(
TEXT("user+b@example.com"),
TEXT("Password321"),
FVoidHandler::CreateWeakLambda(this, [this]()
{
UE_LOG(LogTemp, Log, TEXT("Login User B successful"));
}), FCustomErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage, const FJsonObject& ErrorObject)
{
UE_LOG(LogTemp, Error, TEXT("Login User B Failed : %d, %s"), ErrorCode, *ErrorMessage);
}));
NOTE

If you are implementing multiple registries in the OSS, to differentiate each player, you need to use LocalUserNum as a user key in every function call and set delegate.

UI Implementation

The following diagram shows the flow you need to use an API in Unreal Engine to call the Login with Username API.

note

Your UI implementation will may vary depending on your game and the login method you choose.

multiple-registries

Follow the steps below to create this flow:

  1. Call Get Api Client.

  2. On the Return Value, call the API you want to use. In this case, it will be the User API.

  3. Once this API has been successfully called, you can call the Login with Username API.

    Once the Login with Username API has been successfully called, your setup is complete.

Migrate to Multiple Registries

Overview

With the Multiple Registries feature, AccelByte Cloud supports multiplayer in a single game process. Use this guide to migrate your game from a singleton-based registry to multiple registries so your game can support multiple registries.

Unity

First of all, we assume all the APIs called from our SDK are called from singleton interfaces, which are the AccelBytePlugin and AccelByteServerPlugin classes.

This guide will help to transition the following APIs from singleton usage:

  • AccelBytePlugin into ApiClient.
  • AccelByteServerPlugin into ServerApiClient.

Game Client

  1. Choose a key that represents the player identifier if you have multiple players in a single game process/execution (i.e., local co-op game).
  • If there is only one player in one game process/execution, then there is no need to specify a key.
  1. Use Find all to locate all the AccelBytePlugin.* singleton classes in your project and replace AccelBytePlugin. with MultiRegistry.GetApiClient()..
IMPORTANT

If you have multiple local players in the same game instance, replace AccelBytePlugin. with MultiRegistry.GetApiClient("<INSERT_PLAYER_IDENTIFIER_HERE>")..

  1. Check the compilation still runs after renaming.
User user = MultiRegistry.GetApiClient().GetUser();

user.LoginWithUsername(
"user+a@example.com",
"Password321",
(Result<TokenData, OAuthError> result) =>
{
if (!result.IsError)
{
// show the login result
Debug.Log("Login player A successful");
}
else
{
Debug.Log("Login failed:" + result.IsError);
}
});

Game Server

  1. Use Find all to locate all the AccelByteServerPlugin.* singleton classes in your project and replace AccelByteServerPlugin. with MultiRegistry.GetServerApiClient()..
  2. An error will occur on LoginWithClientCredentials(). We recommend replace the function call from AccelByteServerPlugin.GetDedicatedServer().LoginWithClientCredentials(...) to var dsSession = MultiRegistry.GetServerApiClient().session; / yield return dsSession.LoginWithClientCredentials(...);.
yield return MultiRegistry.GetServerApiClient().session.LoginWithClientCredentials(
result =>
{
if (!result.IsError)
{
Debug.Log("Server authenticated");
}
else
{
Debug.Log("Server authentication failed:" + result.IsError);
}
});

Unreal Engine

Game Client

The game client, called FApiClient, is a class that can be created from FMultiRegistry.

You must prepare a key to construct the FApiClient. The key represents the managed user, or acts as an identifier. To handle several users at the same time, you can use this method to create multiple keys. / Leave it empty to use the default user if the game has only one player in one game process/executable.

Follow the steps below to migrate FRegistry to FMultiRegistry:

  1. Use Find all to locate all the FRegistry::* classes in your project and:

    • For singleton classes, replace FRegistry:: with FMultiRegistry::Ge.
    WARNING

    Do not change FRegistry::Settings, FRegistry::Credentials, or FRegistry::HttpRetryScheduler.

  2. Check that the compilation still runs after you have renamed it. If not, undo your previous changes and repeat step 1.

FMultiRegistry::GetApiClient()->User.LoginWithUsername(
TEXT("user+a@example.com"),
TEXT("Password321"),
FVoidHandler::CreateWeakLambda(this, [this]()
{
UE_LOG(LogTemp, Log, TEXT("Login successful"));
}), FCustomErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage, const FJsonObject& ErrorObject)
{
UE_LOG(LogTemp, Error, TEXT("Login Failed : %d, %s"), ErrorCode, *ErrorMessage);
}));

Game Server

The steps to create the game server are similar to those for the game client in that you need to replace the registry The steps to migrate from FRegistry to FMultiRegistry are as follows:

  1. Use Find all to locate all the FRegistry::* singleton classes in your project and replace FRegistry::* with FMultiRegistry::GetServerApiClient()->.

    WARNING

    Do not change FRegistry::ServerSettings.

auto ServerApiClient = FMultiRegistry::GetServerApiClient();

ServerApiClient->ServerOauth2.LoginWithClientCredentials(FVoidHandler::CreateWeakLambda(this, [this]()
{
UE_LOG(LogTemp, Log, TEXT("Login With Credentials success"));
}), FErrorHandler::CreateWeakLambda(this, [this](int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Login With Credentials failed, Error Code: %d Error Message: %s"), ErrorCode, *ErrorMessage);
}));

Use the AccelByte OSS with the Client SDKs

Follow the steps below to get an ApiClient if your game is using OSS to handle logins:

  1. Check the DefaultEngine.ini configuration file. Ensure that bMultipleLocalUsersEnabled is true if there are multiple local players in a single game process.

  2. If necessary, change it to true.

[OnlineSubsystemAccelByte]
bEnabled=true
bAutoLobbyConnectAfterLoginSuccess=false
bMultipleLocalUsersEnabled=true
  1. First log in the user using AccelByte Cloud's Online Identity Interface, which is used for player authentication and profiles.

  2. Login and make note of the LocalUserNum that is passed.

virtual bool Login(int32 LocalUserNum, const FOnlineAccountCredentials& AccountCredentials) override;
  1. Use OnLoginCompleteDelegates to find the login result from the identity interface.

  2. After the user has been logged in, call the following function from AccelByte Cloud’s Identity Interface:

IOnlineSubsystem* SubsystemAB = IOnlineSubsystem::Get(ACCELBYTE_SUBSYSTEM);
const FOnlineIdentityAccelBytePtr IdentityPtr = StaticCastSharedPtr<FOnlineIdentityAccelByte>(SubsystemAB->GetIdentityInterface());
FApiClientPtr ApiClient = IdentityPtr->GetApiClient(in32 LocalUserNum);
  1. Pass the same LocalUserNum that was used for login.

  2. FApiClientPtr will be returned and can be used for various API calls by the specified user.