メインコンテンツまでスキップ

オンラインサブシステムを使用してログインする - デバイス ID でログインする - (Unreal Engine モジュール)

Last updated on May 30, 2024

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

  1. Open AccelByteWars.sln using Visual Studio and open the AuthEssentialsSubsystem_Starter class Header file. Create a new function declaration called OnLoginComplete as the callback that is used when the login request is completed. This callback function will later be bound to the FOnLoginCompleteDelegate delegate provided by the Identity Interface. We will also pass our own event FAuthOnLoginCompleteDelegate_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);
  2. Next, open the AuthEssentialsSubsystem_Starter class CPP file and navigate to the UAuthEssentialsSubsystem_Starter::Login() function. Then, replace the logging in code with the code below. This function will perform a login using the IdentityInterface:

    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);
    });
    }
    }
  3. Then, create the OnLoginComplete() function definition. This function will invoke the FAuthOnLoginCompleteDelegate_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);
    }
  4. Build the AccelByteWars project and make sure there is no compile errors.

Resources