オンラインサブシステムを使用してログインする - デバイス ID でログインする - (Unreal Engine モジュール)
Unwrap the Online Subsystem
In this tutorial, you will learn how to implement logins with device IDs using the AccelByte Gaming Services (AGS) Online Subsystem (OSS).
Byte Wars uses the Game Instance Subsystem named UAuthEssentialsSubsystem
to act as the wrapper to cache and handle login-related functions when using the AGS OSS. Because it's derived from the Game Instance Subsystem, it's easy to access, has the same lifetime of the game instance, and provides modularity without overriding engine classes.
For more info about Subsystems, read Unreal Engine Programming Subsystems.
The UAuthEssentialsSubsystem
will mainly be using the Identity Interface from the AGS OSS. The Identity Interface handles account-related interactions with AGS as a service providing the ability to authenticate users and obtain access tokens, which will later allow a user to utilize the AGS features if they authenticated properly.
Read more on Identity Interface from Unreal Engine Online Subsystem Documentation.
The diagram below explains how the UAuthEssentialsSubsystem
will connect the login widget to the AGS OSS.
What's in the starter pack
The starter class UAuthEssentialsSubsystem
for you to modify is provided for you in the Resources section and consists of:
- A Header file:
/Source/AccelByteWars/TutorialModules/Access/AuthEssentials/AuthEssentialsSubsystem_Starter.h
- A CPP file:
/Source/AccelByteWars/TutorialModules/Access/AuthEssentials/AuthEssentialsSubsystem_Starter.cpp
The starter class includes the following functionalities:
Include Online Identity Interface in the Header file:
#include "OnlineIdentityInterfaceAccelByte.h"
A pointer to AccelByte Identity Interface declared in the Header file:
protected:
FOnlineIdentityAccelBytePtr IdentityInterface;A multicast delegate for the widget class to bind on when a login completes is called from AGS OSS:
DECLARE_MULTICAST_DELEGATE_TwoParams(FAuthOnLoginComplete_Starter, bool /*bWasSuccessful*/, const FString& /*ErrorMessage*/);
typedef FAuthOnLoginComplete_Starter::FDelegate FAuthOnLoginCompleteDelegate_Starter;Account Credentials declaration in the Header file:
protected:
FOnlineAccountCredentials Credentials;Helper functions to set and clear Credentials:
void UAuthEssentialsSubsystem_Starter::SetAuthCredentials(const EAccelByteLoginType& LoginMethod, const FString& Id, const FString& Token)
{
Credentials.Type = (LoginMethod == EAccelByteLoginType::None) ? TEXT("") : FAccelByteUtilities::GetUEnumValueAsString(LoginMethod);
Credentials.Id = Id;
Credentials.Token = Token;
}
void UAuthEssentialsSubsystem_Starter::ClearAuthCredentials()
{
Credentials.Type = TEXT("");
Credentials.Id = TEXT("");
Credentials.Token = TEXT("");
}A login function to trigger the login:
public:
void Login(const APlayerController* PC, const FAuthOnLoginCompleteDelegate_Starter& OnLoginComplete);At this state, the function won't do anything, since it has no implementation. You will be adding that implementation in the next section.
Validation of both the Online Subsystem and Identity Interface in
UAuthEssentialsSubsystem_Starter::Initialize()
:const IOnlineSubsystem* Subsystem = Online::GetSubsystem(GetWorld());
if (!ensure(Subsystem)) return;
IdentityInterface = StaticCastSharedPtr<FOnlineIdentityAccelByte>(Subsystem->GetIdentityInterface());
if (!ensure(IdentityInterface.IsValid())) return;
Implement login using AGS OSS
Open
AccelByteWars.sln
using Visual Studio and open theAuthEssentialsSubsystem_Starter
class Header file. Create a new function declaration calledOnLoginComplete
as the callback that is used when the login request is completed. This callback function will later be bound to theFOnLoginCompleteDelegate
delegate provided by the Identity Interface. We will also pass our own eventFAuthOnLoginCompleteDelegate_Starter
that will later be triggered, so the login widget can set the UI based on the login result.private:
void OnLoginComplete(int32 LocalUserNum, bool bLoginWasSuccessful, const FUniqueNetId& UserId, const FString& LoginError, const FAuthOnLoginCompleteDelegate_Starter OnLoginComplete);Next, open the
AuthEssentialsSubsystem_Starter
class CPP file and navigate to theUAuthEssentialsSubsystem_Starter::Login()
function. Then, replace the logging in code with the code below. This function will perform a login using theIdentityInterface
:void UAuthEssentialsSubsystem_Starter::Login(const APlayerController* PC, const FAuthOnLoginCompleteDelegate_Starter& OnLoginComplete)
{
if (!ensure(IdentityInterface.IsValid()))
{
FString Message = TEXT("Cannot login. Identiy interface is not valid.");
UE_LOG_AUTH_ESSENTIALS(Warning, TEXT("%s"), *Message);
OnLoginComplete.ExecuteIfBound(false, *Message);
return;
}
// Get local user number
const ULocalPlayer* LocalPlayer = PC->GetLocalPlayer();
ensure(LocalPlayer != nullptr);
int32 LocalUserNum = LocalPlayer->GetControllerId();
// Perform login using IdentityInterface
IdentityInterface->AddOnLoginCompleteDelegate_Handle(LocalUserNum, FOnLoginCompleteDelegate::CreateUObject(this, &ThisClass::OnLoginComplete, OnLoginComplete));
IdentityInterface->Login(LocalUserNum, Credentials);
// Helper to logout the user when the game shutdown in play in editor mode.
if (UAccelByteWarsGameInstance* ByteWarsGameInstance = Cast<UAccelByteWarsGameInstance>(GetGameInstance()); ensure(ByteWarsGameInstance))
{
ByteWarsGameInstance->OnGameInstanceShutdownDelegate.AddWeakLambda(this, [this, LocalUserNum]()
{
IdentityInterface->Logout(LocalUserNum);
UE_LOG_AUTH_ESSENTIALS(Warning, TEXT("Logging out local player %d"), LocalUserNum);
});
}
}Then, create the
OnLoginComplete()
function definition. This function will invoke theFAuthOnLoginCompleteDelegate_Starter
to inform whether the login process was successful or not.void UAuthEssentialsSubsystem_Starter::OnLoginComplete(int32 LocalUserNum, bool bLoginWasSuccessful, const FUniqueNetId& UserId, const FString& LoginError, const FAuthOnLoginCompleteDelegate_Starter OnLoginComplete)
{
if (bLoginWasSuccessful)
{
UE_LOG_AUTH_ESSENTIALS(Log, TEXT("Login user successful."));
}
else
{
UE_LOG_AUTH_ESSENTIALS(Warning, TEXT("Login user failed. Message: %s"), *LoginError);
}
IdentityInterface->ClearOnLoginCompleteDelegates(LocalUserNum, this);
OnLoginComplete.ExecuteIfBound(bLoginWasSuccessful, LoginError);
}Build the AccelByteWars project and make sure there is no compile errors.
Resources
- The files used in this tutorial section are available in the Byte Wars Unreal GitHub repository.