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

Implement Subsystem - Login Queue - (Unreal Engine module)

Last updated on February 4, 2026

注釈:本資料はAI技術を用いて翻訳されています。

サブシステムの概要

Byte Warsは、AccelByte Gaming Services (AGS) OSSのラッパーとして機能するLoginQueueSubsystem_Starterという名前のGame Instance Subsystemを使用します。これは、Identity Interfaceから派生したAGS OSSが提供するFOnlineIdentityAccelByteのみを使用します。

AGS OSSのログインキューAsyncTaskはタイムアウトを有効にしていません。理由は、ログインキューの待機時間がAsyncTaskのタイムアウト時間を超える可能性があるためです。したがって、操作はプレイヤーがログインを試みるか、プレイヤーがログインキューをキャンセルするまで待機します。

以下の図は、Login Queue機能がOSSとどのように連携するかを説明しています。

Starter Packの内容

変更するためのスタータークラスLoginQueueSubsystem_Starterは、Resourcesセクションで提供されており、以下で構成されています:

  • Headerファイル: /Source/AccelByteWars/TutorialModules/Access/LoginQueue/LoginQueueSubsystem_Starter.h
  • CPPファイル: /Source/AccelByteWars/TutorialModules/Access/LoginQueue/LoginQueueSubsystem_Starter.cpp
  • Modelファイル: /Source/AccelByteWars/TutorialModules/Access/LoginQueue/LoginQueueModel.h

スタータークラスには以下の機能が含まれています:

  • Headerファイルに、AccelByteのOnline Identity Interfaceとそのポインタをインクルード:

    // ...
    #include "OnlineIdentityInterfaceAccelByte.h"
    protected:
    FOnlineIdentityAccelBytePtr IdentityInterface;
  • CPPファイルでOnline Identityポインタを取得するコード:

    void ULoginQueueSubsystem_Starter::Initialize(FSubsystemCollectionBase& Collection)
    {
    Super::Initialize(Collection);

    // Get Online Subsystem and make sure it's valid.
    FOnlineSubsystemAccelByte* Subsystem = static_cast<FOnlineSubsystemAccelByte*>(Online::GetSubsystem(GetWorld()));
    if (!ensure(Subsystem))
    {
    UE_LOG_LOGIN_QUEUE(Warning, TEXT("The online subsystem is invalid. Please make sure OnlineSubsystemAccelByte is enabled and the DefaultPlatformService under [OnlineSubsystem] in the Engine.ini file is set to AccelByte."));
    return;
    }

    // Grab the reference of AccelByte Identity Interface and make sure it's valid.
    IdentityInterface = StaticCastSharedPtr<FOnlineIdentityAccelByte>(Subsystem->GetIdentityInterface());
    if (!ensure(IdentityInterface.IsValid()))
    {
    UE_LOG_LOGIN_QUEUE(Warning, TEXT("Identity interface is not valid."));
    return;
    }
    // ...
    }
  • Modelファイルで、ゲームのロジックをIdentity Interfaceのデリゲートに接続するためのマルチキャストデリゲート宣言:

    DECLARE_MULTICAST_DELEGATE_TwoParams(FOnLoginQueueCancelCompleted, const APlayerController*, const FOnlineError&)
    DECLARE_MULTICAST_DELEGATE_TwoParams(FOnLoginQueued, const APlayerController*, const FAccelByteModelsLoginQueueTicketInfo& TicketInfo)
    DECLARE_MULTICAST_DELEGATE_ThreeParams(FOnLoginTicketStatusUpdated, const APlayerController*, const FAccelByteModelsLoginQueueTicketInfo&, const FOnlineError&)
  • Player Controllerからローカルプレイヤー番号を取得する、またはその逆を行うヘルパー関数。これらの関数は、UIとIdentity Interface間のやり取りを簡素化するために作成されました。ゲームUIには、所有するPlayer Controllerを返すGetOwningPlayer()関数がありますが、Identity Interfaceはローカルプレイヤー番号を受け入れます。

    int32 ULoginQueueSubsystem_Starter::GetLocalUserNumFromPlayerController(const APlayerController* PlayerController) const
    {
    if (!PlayerController)
    {
    return INDEX_NONE;
    }

    const ULocalPlayer* LocalPlayer = PlayerController->GetLocalPlayer();
    if (!LocalPlayer)
    {
    return INDEX_NONE;
    }

    return LocalPlayer->GetControllerId();
    }
    APlayerController* ULoginQueueSubsystem_Starter::GetPlayerControllerByLocalUserNum(const int32 LocalUserNum) const
    {
    APlayerController* MatchedPC = nullptr;
    for (FConstPlayerControllerIterator It = GetWorld()->GetPlayerControllerIterator(); It; ++It)
    {
    if (!It->IsValid())
    {
    continue;
    }

    if (APlayerController* PC = It->Get(); PC)
    {
    if (LocalUserNum == GetLocalUserNumFromPlayerController(PC))
    {
    MatchedPC = PC;
    break;
    }
    }
    }
    return MatchedPC;
    }

Login Queueコールバックの実装

  1. LoginQueueSubsystem_Starter Headerファイルを開き、これら2つのデリゲートを追加します。これらのデリゲートは、OSSのデリゲートとByte WarsのUI間の接続ポイントになります。

    public:
    // ...
    FOnLoginQueued OnLoginQueuedDelegates;
    FOnLoginTicketStatusUpdated OnLoginTicketStatusUpdatedDelegates;
  2. 引き続きHeaderファイルで、OSSのデリゲートにバインドする以下の関数を追加します。

    protected:
    void OnLoginQueued(const int32 PlayerNum, const FAccelByteModelsLoginQueueTicketInfo& TicketInfo) const;
    void OnLoginTicketStatusUpdated(
    const int32 PlayerNum,
    bool bWasSuccessful,
    const FAccelByteModelsLoginQueueTicketInfo& TicketInfo,
    const FOnlineErrorAccelByte& Error) const;
  3. 次に、LoginQueueSubsystem_Starter CPPファイルを開き、OnLoginQueued()関数を実装します。名前が示すように、これはログイン試行後にプレイヤーがキューに入れられたときのコールバックになります。ここでは、OSSのデリゲートから受け取ったPlayerNumPlayerControllerに変更してUI側のコードを簡素化し、OnLoginQueuedDelegatesをトリガーします。

    void ULoginQueueSubsystem_Starter::OnLoginQueued(const int32 PlayerNum, const FAccelByteModelsLoginQueueTicketInfo& TicketInfo) const
    {
    OnLoginQueuedDelegates.Broadcast(GetPlayerControllerByLocalUserNum(PlayerNum), TicketInfo);
    }
  4. 引き続きCPPファイルで、OnLoginTicketStatusUpdated()関数を実装します。この関数は、ポーリングレスポンスが受信されたときのコールバックになります。前の関数と同様に、この関数は単にPlayerNumPlayerControllerに変更し、OnLoginTicketStatusUpdatedDelegatesをトリガーします。

    void ULoginQueueSubsystem_Starter::OnLoginTicketStatusUpdated(
    const int32 PlayerNum,
    bool bWasSuccessful,
    const FAccelByteModelsLoginQueueTicketInfo& TicketInfo,
    const FOnlineErrorAccelByte& Error) const
    {
    // bWasSuccessful false means the player still in the queue, not that the request has failed.
    OnLoginTicketStatusUpdatedDelegates.Broadcast(GetPlayerControllerByLocalUserNum(PlayerNum), TicketInfo, Error);
    }
    備考

    ポーリングリクエスト自体は、Admin Portal(Login Queue Configuration)のPolling Time設定に基づいた遅延でOSSによって実行されます。 これが何らかの理由で0に設定されている場合、OSSはバックエンドから取得したEstimatedWaitingTimeInSeconds + -10から10秒のランダムな数値を使用し、最小3秒、最大40秒に制限されます。

  5. 引き続きCPPファイルで、実装した関数をOSSのデリゲートにバインドします。Initialize()関数に移動し、以下のコードを追加します。

    void ULoginQueueSubsystem_Starter::Initialize(FSubsystemCollectionBase& Collection)
    {
    // ...
    IdentityInterface->AccelByteOnLoginQueuedDelegates->AddUObject(this, &ThisClass::OnLoginQueued);
    IdentityInterface->AccelByteOnLoginTicketStatusUpdatedDelegates->AddUObject(this, &ThisClass::OnLoginTicketStatusUpdated);
    }
  6. Deinitialize()関数でデリゲートをアンバインドします。

    void ULoginQueueSubsystem_Starter::Deinitialize()
    {
    // ...
    IdentityInterface->AccelByteOnLoginQueuedDelegates->RemoveAll(this);
    IdentityInterface->AccelByteOnLoginTicketStatusUpdatedDelegates->RemoveAll(this);
    }

Cancel Loginの実装

  1. LoginQueueSubsystem_Starter Headerファイルを開き、キャンセル関数をトリガーする関数と、レスポンスのコールバックとしてのデリゲートを追加します。

    public:
    void CancelLoginQueue(const APlayerController* PlayerController) const;

    FOnLoginQueueCancelCompleted OnLoginQueueCancelCompletedDelegates;
  2. 引き続きHeaderファイルで、OSSデリゲートにバインドされるコールバックとして以下の関数を宣言します。

    protected:
    // ...
    void OnLoginQueueCancelCompleted(const int32 PlayerNum, bool bWasSuccessful, const FOnlineErrorAccelByte& Error) const;
  3. LoginQueueSubsystem_Starter CPPファイルを開き、CancelLoginQueue()関数を実装します。PlayerControllerパラメータを関連するローカルプレイヤーインデックスに変換し、ログインキャンセル機能を呼び出します。

    void ULoginQueueSubsystem_Starter::CancelLoginQueue(const APlayerController* PlayerController) const
    {
    IdentityInterface->CancelLoginQueue(GetLocalUserNumFromPlayerController(PlayerController));
    }
  4. 引き続きCPPファイルで、コールバック関数OnLoginQueueCancelCompletedを実装します。この関数は、Cancel Loginの実装ステップで作成したOnLoginQueueCancelCompletedDelegatesをトリガーします。これに加えて、このコールバックがトリガーされた直後にOnLoginCompleteもトリガーされることに注意してください。

    void ULoginQueueSubsystem_Starter::OnLoginQueueCancelCompleted(
    const int32 PlayerNum,
    bool bWasSuccessful,
    const FOnlineErrorAccelByte& Error) const
    {
    // OnLoginComplete will also be triggered after this is triggered

    FOnlineError OutError = Error;
    OutError.bSucceeded = bWasSuccessful;

    OnLoginQueueCancelCompletedDelegates.Broadcast(GetPlayerControllerByLocalUserNum(PlayerNum), OutError);
    }
  5. 関数を実装したので、コールバックをOSSのデリゲートにバインドする必要があります。引き続きCPPファイルで、Initialize()関数に移動し、以下のコードを追加します。

    void ULoginQueueSubsystem_Starter::Initialize(FSubsystemCollectionBase& Collection)
    {
    // ...
    IdentityInterface->AccelByteOnLoginQueueCancelCompleteDelegates->AddUObject(this, &ThisClass::OnLoginQueueCancelCompleted);
    // ...
    }
  6. 最後に、Deinitialize()関数で前のデリゲートをアンバインドします。

    void ULoginQueueSubsystem_Starter::Deinitialize()
    {
    // ...
    IdentityInterface->AccelByteOnLoginQueueCancelCompleteDelegates->RemoveAll(this);
    // ...
    }
  7. AccelByteWarsプロジェクトをビルドし、コンパイルエラーがないことを確認します。

Resources