Skip to main content

AccelByte OSS for Unreal Engine

Last updated on

Overview

This tutorial will walk you through how to install the AccelByte Online Subsystem (OSS) and integrate it in your game.

NOTE

The AccelByte Online Subsystem is still under development, with a full release expected around Q2 2023.

Prerequisites

Plugin Set up Guide

Before using AccelByte OSS, you need to set up all the required plugins (Accelbyte OSS, SDK, and Network Utilities). This tutorial uses a sample project named OssTutorialProject.

  1. Create a new UE project, or open an existing one.

  2. Add the AccelByte UE’s OSS, SDK, and Network Utilities Github repositories as part of the submodule or download the repository manually, then put them inside the Plugins/AccelByte folder.

    Path Examples:

    i. …/Plugins/AccelByte/AccelByteOSS for AccelByte OSS.

    ii. …/Plugins/AccelByte/AccelByteUe4Sdk for AccelByte SDK.

    iii. …/Plugins/AccelByte/AccelByteNetwork for AccelByte Network Utilities.

    TIP

    If you are cloning our tutorial project, you can run our Setup.bat directly to update the plugins submodule.

  1. Still in your UE project directory, right-click on your .uproject file, then click Generate Visual Studio project files.

    OSS

  2. Open your .sln file with your preferred IDE.

    OSS

  3. Add the following OSS and Network Utilities configurations to your DefaultEngine.ini file:

    ...
    [OnlineSubsystem]
    DefaultPlatformService=AccelByte
    ...
    [OnlineSubsystemAccelByte]
    bEnabled=true

    [/Script/AccelByteNetworkUtilities.IpNetDriverAccelByte]
    NetConnectionClassName=AccelByteNetworkUtilities.IpConnectionAccelByte
  1. In the same DefaultEngine.ini file, we will enable the AccelByte NetDriver:

    ...
    [/Script/Engine.GameEngine]
    !NetDriverDefinitions=ClearArray
    +NetDriverDefinitions=(DefName="GameNetDriver",DriverClassName="AccelByteNetworkUtilities.IpNetDriverAccelByte",DriverClassNameFallback="OnlineSubsystemUtils.IpNetDriver")
    +NetDriverDefinitions=(DefName="DemoNetDriver",DriverClassName="/Script/Engine.DemoNetDriver",DriverClassNameFallback="/Script/Engine.DemoNetDriver")
    ...
  1. Edit your platform-specific config .ini file located inside your platform’s folder (e.g., Config/Windows/WindowsEngine.ini).

    ; Set the OSS configs for Windows to use the AccelByte OSS as the default subsystem, and Steam as the native
    [OnlineSubsystem]
    NativePlatformService=Steam

    [OnlineSubsystemSteam]
    bEnabled=true
    bUseSteamNetworking=false
    SteamDevAppId=<game_app_id>
  1. Add all of the AccelByte UE Plugins (AccelByteUe4Sdk, OnlineSubsystemAccelByte, AccelByteNetworkUtilities) to the following files:

    "Plugins": [
    {
    "Name": "AccelByteUe4Sdk",
    "Enabled": true
    },
    {
    "Name": "OnlineSubsystemAccelByte",
    "Enabled": true
    },
    {
    "Name": "AccelByteNetworkUtilities",
    "Enabled": true
    },
    ...
    ]
    public OssTutorialProjectTarget( TargetInfo Target) : base(Target)
    {
    Type = TargetType.Game;
    DefaultBuildSettings = BuildSettingsVersion.V2;

    ExtraModuleNames.AddRange( new string[] { "OssTutorialProject", "AccelByteUe4Sdk", "OnlineSubsystemAccelByte", "AccelByteNetworkUtilities"
    });
    }
    public OssTutorialProjectEditorTarget( TargetInfo Target) : base(Target)
    {
    Type = TargetType.Editor;
    DefaultBuildSettings = BuildSettingsVersion.V2;
    ExtraModuleNames.AddRange( new string[] { "OssTutorialProject", "AccelByteUe4Sdk", "OnlineSubsystemAccelByte", "AccelByteNetworkUtilities" });
    }
    public OssTutorialProject(ReadOnlyTargetRules Target) : base(Target)
    {
    PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;

    PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", ... , "AccelByteUe4Sdk", "AccelByteNetworkUtilities", "OnlineSubsystemAccelByte", ... });

    PrivateDependencyModuleNames.AddRange(new string[] { "Json", "JsonUtilities", "OnlineSubsystem", ...});
    }
  1. Make sure you have configured the AccelByte SDK to be able to use the AccelByte OSS. If you haven’t, follow these following guides to configure the AccelByte Client and AccelByte Server of the AccelByte SDK.

    TIP

    If you don't have any clients created yet, you can follow this guide. Contact our support or your Account Manager if you're still unsure about the clients' credentials.

  2. And then, to make sure UE has detected all of the required AccelByte Plugins, you can open Edit > Plugins in the UE editor. See if the AccelByte Unreal Engine SDK, AccelByteNetworkUtilities, and Online Subsystem AccelByte have been set as Enabled.

    OSS

Step by Step Guide

Now, you are ready to integrate AccelByte OSS in your game. In this part, we are going to give you an example on how to implement it. We are still going to be using the same sample project named “OssTutorialProject”.

OSS Implementation

In this implementation, we are going to show how to implement login feature which is included inside the OSS interface. If you want to see other classes or functions that are included, you can find it in the ‘AccelByteOSS\Source\OnlineSubsystemAccelByte\Public’.

Create a Login UI

  1. Create a widget blueprint class and name it WB_LoginMenu.

  2. Create a user widget C++ class and name it AccelByteAuth, which is used to accommodate functions for the WB_LoginMenu widget.

  3. Create a UI with the following login components:

    • Editable Text Box named Etb_Username for username input

    • Editable Text Box named Etb_Password for password input.

    • Button named Btn_Login for the login action.

    OSS

  4. Reparent the WB_LoginMenu widget blueprint to the AccelByteAuth C++ class.

Implement the Code

In this class we are going to create several login functions to accommodate players when they want to log into your game.

  1. Add the following header into AccelByteAuth class to ensure the OSS functions work:

    ..
    #include "OnlineSubsystem.h"
    #include "OnlineSubsystemUtils.h"
    #include "OnlineSubsystemAccelByteDefines.h"
    ..
  2. Let’s create a function named AccelByteOssLogin() to handle the login process using AccelByte OSS. Declare an IOnlineIdentityPtr variable named IdentityInterface as an identity interface pointer and use it to call Login(). Inside the Login(), we need to put the player number with 0 value as a single player and FOnlineAccountCredentials to save the player credentials.

    void UAccelByteAuth::AccelByteOssLogin()
    {
    const IOnlineSubsystem* OnlineSub = Online::GetSubsystem(GetWorld(),
    ACCELBYTE_SUBSYSTEM);

    if (OnlineSub)
    {
    const IOnlineIdentityPtr IdentityInterface = OnlineSub->GetIdentityInterface();

    if (IdentityInterface.IsValid())
    {
    FOnlineAccountCredentials AccountCredentials;

    AccountCredentials.Type = "AccelByte";
    AccountCredentials.Id = Etb_Username->GetText().ToString();
    AccountCredentials.Token = Etb_Password->GetText().ToString();

    //Login
    IdentityInterface->Login(0, AccountCredentials);
    }
    else
    {
    // Log Identity Interface is Invalid
    }
    }
    else
    {
    // Log "Online Subsystem is Invalid"
    }
    }
  3. Next, we need to handle successful and failed responses.

    a. To handle a successful response, create a function called LoginSuccess() and specify the action that occurs after a login is successful.

    void UAccelByteAuth::LoginSuccess()
    {
    // Log "Login Success"
    }

    b. To handle a failed response, create a function called LoginFailed() and specify the action that occurs after a login fails.

    void UAccelByteAuth::LoginFailed(const FString& ErrorMessage)
    {
    // Log "Login Failed : [ErrorMessage]"
    }
  4. Then create a delegate function to handle after the login process is complete. This delegate function will contain whether the process is successful or not. The process is a success if the credentials are right, otherwise the process will likely fail. This function can be called LoginComplete(). In this function, we are using a variable named bIsSuccess to determine whether the login process is successful or failed. If it is successful, then we need to call LoginSuccess(). Otherwise, we need to call LoginFailed().

    void UAccelByteAuth::LoginComplete(int32 PlayerNumber, bool bIsSuccess, const FUniqueNetId& UserId, const FString& ErrorMessage)
    {
    if (bIsSuccess)
    {
    LoginSuccess();
    }
    else
    {
    LoginFailed(ErrorMessage);
    }
    }
  5. Finally, create a function called OnClickLoginButton() to accommodate the login function. Bind the LoginComplete() as a delegate function to call it after the login process inside AccelByteOssLogin() is complete.

    void UAccelByteAuth::OnClickLoginButton()
    {
    //Login Delegate
    const IOnlineSubsystem* OnlineSub = Online::GetSubsystem(GetWorld(), ACCELBYTE_SUBSYSTEM);
    if (!OnlineSub->GetIdentityInterface()->OnLoginCompleteDelegates->IsBoundToObject(this))
    {
    OnlineSub->GetIdentityInterface()->OnLoginCompleteDelegates->AddUObject(this, &UAccelByteAuth::LoginComplete);
    AccelByteOssLogin();
    }
    else
    {
    AccelByteOssLogin();
    }
    }

  6. Finally, test your login implementation after following the guidelines above. If your client game log shows that the player is logged in successfully, then you can move to the next section.

    IMPORTANT

    To test or use an Online Subsystem (OSS), you must run the client game in Standalone mode or any other mode BUT the Play In Editor (PIE) mode. Unreal Engine naturally doesn’t detect the OSS if it’s being run in PIE.

SDK Implementation

This section contains an example on how to use the AccelByte SDK for the functions that are not included in the OSS. If you decide to use OSS and need an SDK at some point to cover some features, then you should use FMultiRegistry.

Implement the Code

FMultiRegistry can be used to call related feature APIs from the AccelByte Service, such as Login. In this guide, we will give you an example on how to implement the login feature using FMultiRegistry and modify AccelByteAuth that we have used before.

  1. Similar with OSS Implementation, we will be using the Login UI.

  2. Add the following header into AccelByteAuth.cpp to ensure the SDK functions work:

    ..
    #include "Api/AccelByteUserApi.h"
    #include "Core/AccelByteMultiRegistry.h"
    ..
  3. Create a function to contain FMultiRegistry. In these steps we will use the same function, AccelByteOssLogin.

  4. After a new function is created. Then, declare and initialize the FApiClientPtr variable named ApiClient. This variable contains the API Client from FMultiRegistry.

    void UAccelByteAuth::AccelByteOssLogin()
    {
    FApiClientPtr ApiClient = FMultiRegistry::GetApiClient();
    }
  5. Use the ApiClient variable to call what functions you want to use. For this guide we will be using LoginWithUsername. Commonly, LoginWithUsername is used to login with a username or email.

    void UAccelByteAuth::AccelByteOssLogin()
    {
    FApiClientPtr ApiClient = FMultiRegistry::GetApiClient();

    ApiClient->User.LoginWithUsername(
    Etb_Username->GetText().ToString(),
    Etb_Password->GetText().ToString(),
    FVoidHandler::CreateUObject(this, &UAccelByteAuth::LoginSuccess),
    FErrorHandler::CreateUObject(this, &UAccelByteAuth::LoginFailed));
    }

  6. And finally, notice that there are FVoidHandler and FErrorHandler inside the LoginWithUsername. Both functions are used as delegates, so when the Login returns success or failure in the process, we can modify these functions for the players.

    a. FVoidHandler

    This delegate will be triggered when the login result returns success.

    void UAccelByteAuth::LoginSuccess()
    {
    // [Line of Code] Log("Login Success")
    }

    b. FErrorHandler

    This delegate will be triggered when the login result returns failed.

    void UAccelByteAuth::LoginFailed(const FString& ErrorMessage)
    {
    // [Line of Code] Log("Login Failed : [ErrorCode] [ErrorMessage]")
    }

Congratulations! You have learned how to use the AccelByte OSS, which is the gateway to use P2P service.

Proceed to the next section to learn how to implement AccelByte P2P Service.

Full Code

AccelByteAuth.h
// Copyright (c) 2022 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.

#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "AccelByteAuth.generated.h"

class UEditableTextBox;
class UButton;
class AOssTutorialMenuHUD;
class UCanvasPanel;

/**
* Authentication Games Setup
* This code covers AccelByte sevices including:
*
* - Login using AccelByte Account using OSS
*/
UCLASS()
class OSSTUTORIALPROJECT_API UAccelByteAuth : public UUserWidget
{
GENERATED_BODY()

public:
/**
* @brief Logout a session using AccelByte OSS.
* Executed automatically on component construction
*/
UFUNCTION()
void OnClickLogoutButton();

protected:

virtual void NativeConstruct() override;

/**
* @brief Log In Menu Canvas Panel inside MainMenu Widget.
*/
UPROPERTY(meta = (BindWidget))
UCanvasPanel* CP_LoginMenu;

/**
* @brief Editable Text Box for Username inside MainMenu Widget.
*/
UPROPERTY(meta = (BindWidget))
UEditableTextBox* Etb_Username;

/**
* @brief Editable Text Box for Password inside MainMenu Widget.
*/
UPROPERTY(meta = (BindWidget))
UEditableTextBox* Etb_Password;

/**
* @brief Take Button Log In inside MainMenu Widget.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_Login;

/**
* @brief Instantiate all casting to the main menu HUD
*/
AOssTutorialMenuHUD* TutorialMenuHUD;

/**
* @brief Logging in with AccelByte OSS
*/
void AccelByteOssLogin();

/**
* @brief Logging out with AccelByte OSS
*/
void AccelByteOssLogout();

/**
* @brief The number of user in local client.
*/
const int PlayerNum = 0;

private:
/**
* @brief Log an account in using AccelByte OSS.
*/
UFUNCTION()
void OnClickLoginButton();

/**
* @brief Called after Log In process is complete.
*/
void LoginComplete(int32 PlayerNumber, bool bIsSuccess, const FUniqueNetId& UserId, const FString& ErrorMessage);

/**
* @brief Function behavior when Log In process is succeeded.
*/
void LoginSuccess(bool bIsSuccess);

/**
* @brief Function behavior when Log In process is failed.
*/
void LoginFailed(const FString& ErrorMessage);

/**
* @brief Called after Log Out process is complete.
*/
void LogoutComplete(int32 PlayerNumber, bool bIsSuccess);

/**
* @brief Function behavior when Log Out process is succeeded.
*/
void LogoutSuccess(bool bIsSuccess);

/**
* @brief Function behavior when Log Out process is succeeded.
*/
void LogoutFailed();
};
AccelByteAuth.cpp
// Copyright (c) 2022 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.

#include "AccelByteAuth.h"
#include "OnlineSubsystem.h"
#include "OnlineSubsystemUtils.h"
#include "Components/Button.h"
#include "Components/EditableTextBox.h"
#include "OssTutorialProject/HUD/OssTutorialMenuHUD.h"
#include "OnlineSubsystemAccelByte/Public/OnlineSubsystemAccelByteDefines.h"

void UAccelByteAuth::NativeConstruct()
{
Super::NativeConstruct();

TutorialMenuHUD = Cast<AOssTutorialMenuHUD>(GetWorld()->GetFirstPlayerController()->GetHUD());

Btn_Login->OnClicked.AddUniqueDynamic(this, &UAccelByteAuth::OnClickLoginButton);
}

void UAccelByteAuth::AccelByteOssLogin()
{
const IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get(ACCELBYTE_SUBSYSTEM);

if (OnlineSub)
{
const IOnlineIdentityPtr IdentityInterface = OnlineSub->GetIdentityInterface();

if (IdentityInterface.IsValid())
{
FOnlineAccountCredentials AccountCredentials;

AccountCredentials.Type = "AccelByte";
AccountCredentials.Id = Etb_Username->GetText().ToString();
AccountCredentials.Token = Etb_Password->GetText().ToString();

//Login
IdentityInterface->Login(PlayerNum, AccountCredentials);
}
else
{
GEngine->AddOnScreenDebugMessage(-1, 1.0f, FColor::Red, TEXT("Identity Interface is Invalid"));
}
}
else
{
GEngine->AddOnScreenDebugMessage(-1, 1.0f, FColor::Red, TEXT("Online Subsystem is Invalid"));
}
}

void UAccelByteAuth::AccelByteOssLogout()
{
const IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get(ACCELBYTE_SUBSYSTEM);

if (OnlineSub)
{
const IOnlineIdentityPtr IdentityInterface = OnlineSub->GetIdentityInterface();

if (IdentityInterface.IsValid())
{
//Log out
IdentityInterface->Logout(PlayerNum);
}
else
{
GEngine->AddOnScreenDebugMessage(-1, 1.0f, FColor::Red, TEXT("Identity Interface is Invalid"));
}
}
else
{
GEngine->AddOnScreenDebugMessage(-1, 1.0f, FColor::Red, TEXT("Online Subsystem is Invalid"));
}
}

void UAccelByteAuth::OnClickLoginButton()
{
//Login Delegate
const IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get(ACCELBYTE_SUBSYSTEM);
if (!OnlineSub->GetIdentityInterface()->OnLoginCompleteDelegates->IsBoundToObject(this))
{
OnlineSub->GetIdentityInterface()->OnLoginCompleteDelegates->AddUObject(this, &UAccelByteAuth::LoginComplete);
}
AccelByteOssLogin();
}

void UAccelByteAuth::OnClickLogoutButton()
{
//Logout Delegate
const IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get(ACCELBYTE_SUBSYSTEM);
if (!OnlineSub->GetIdentityInterface()->OnLogoutCompleteDelegates->IsBoundToObject(this))
{
OnlineSub->GetIdentityInterface()->OnLogoutCompleteDelegates->AddUObject(this, &UAccelByteAuth::LogoutComplete);
}
AccelByteOssLogout();
}

void UAccelByteAuth::LoginComplete(int32 PlayerNumber, bool bIsSuccess, const FUniqueNetId& UserId, const FString& ErrorMessage)
{
if (bIsSuccess)
{
LoginSuccess(bIsSuccess);
}
else
{
LoginFailed(ErrorMessage);
}
}

void UAccelByteAuth::LoginSuccess(bool bIsSuccess)
{
GEngine->AddOnScreenDebugMessage(-1, 1.0f, FColor::Cyan, TEXT("Login with Username via AB OSS is Success"));

TutorialMenuHUD->OnLoginRequest.Broadcast(bIsSuccess);
}

void UAccelByteAuth::LoginFailed(const FString& ErrorMessage)
{
GEngine->AddOnScreenDebugMessage(-1, 1.0f, FColor::Red, FString::Printf(TEXT("Login with Username via AB OSS is Failed, Message: %s"), *ErrorMessage));
}

void UAccelByteAuth::LogoutComplete(int32 PlayerNumber, bool bIsSuccess)
{
if (bIsSuccess)
{
LogoutSuccess(bIsSuccess);
}
else
{
LogoutFailed();
}
}

void UAccelByteAuth::LogoutSuccess(bool bIsSuccess)
{
GEngine->AddOnScreenDebugMessage(-1, 1.0f, FColor::Cyan, TEXT("Logout via AB OSS is Success"));

if (TutorialMenuHUD == nullptr)
{
TutorialMenuHUD = Cast<AOssTutorialMenuHUD>(GetWorld()->GetFirstPlayerController()->GetHUD());
}

TutorialMenuHUD->OnLogoutRequest.Broadcast(bIsSuccess);
}

void UAccelByteAuth::LogoutFailed()
{
GEngine->AddOnScreenDebugMessage(-1, 1.0f, FColor::Red, TEXT("Logout via AB OSS is Failed"));
}