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

Integrate Matchmaking into your Unreal game client

Last updated on May 17, 2024

概要

マッチメイキングは、2 人以上のプレイヤーがマッチするか評価され、マッチしたらゲームセッションに参加して一緒にプレイするためのプロセスです。マッチメイキングプロセス中にサービスが対話するコンポーネントは複数あります。

  • セッションテンプレート:作成されるセッションの特性を定義します。これには、[joinability (参加可能性)]、使用するゲームサーバーのデプロイメント、プレイヤーの要件、チーム構成などが含まれます。

  • Match Ticket (マッチチケット)]:ソロプレイヤーまたはパーティのいずれかによるマッチメイキングのリクエストを定義します。プレイヤー情報が評価のために添付されています。

  • *Backfill Ticket (バックフィルチケット)]:マッチチケットと似ていますが、マッチルールセットで自動バックフィルが有効になっている場合にのみ作成されます。その場合、2 人以上のプレイヤーがマッチすると、セッションに参加しますが、マッチメイキングサービスに提出されたバックフィルチケットは、最小人数のプレイヤーがセッションに接続するまでマッチングを継続します。

  • Match Pool (マッチプール)]:有効なマッチに対してサービスが評価できるマッチチケットの集合を定義します。チケットは、該当する場合、選択されたゲームモードと設定に基づいて同じプールに移動します。

  • Match Ruleset (マッチルールセット)]:チケットが有効なマッチになるかを判断するために、デフォルトのマッチ関数が使用する属性と比較基準を定義します。マッチ関数が上書きされた場合でも、ルールセットで、評価に必要な 統計データ サービスに保存されている属性を使用して設定する必要があります。

  • Match Function (マッチ関数)]:サービスがマッチチケットを評価するために使用するロジックを定義します。デフォルトで、サービスは関連付けられたマッチルールセットで定義された条件を使用します。

注記

この記事では、Unreal Engine ゲームの設定について説明します。別のエンジンを使用したい場合は、お問い合わせください。

このガイドでは、Unreal OnlineSubsystem (OSS) V2 プラグインを使用して、AccelByte マッチメイキングサービスをゲームクライアントに統合する方法を説明します。これには、マッチメイキングを開始する方法、マッチ結果をリッスンする方法、マッチングが成功したときにゲームセッションに参加する方法などがあります。

目標

このガイドを読むと、次のことを理解できます。

  • プレイヤーが体験するマッチメイキングフロー
  • ソロプレイヤーとパーティのマッチメイキングを開始する方法
  • マッチが見つかる前にマッチメイキングをキャンセルする方法
  • マッチ結果をリッスンして処理する方法
  • ゲームセッションの招待をリッスンしてセッションに参加する方法

前提条件

このガイドを読む前に、次のことを理解しておく必要があります。

  • ロビーセッション、マッチメイキングサービス
  • OnlineSubsystem (OSS)を含むUnreal Engine
  • ゲームプロジェクトにUnreal OSS V2 プラグインを追加する方法
  • 管理者ポータルでゲームの名前空間へのアクセス権を取得する方法
  • ゲームモードのセッションテンプレート、マッチルールセット、マッチプールを設定する方法

設定

ゲームの実装でマッチメイキングを開始するには、最初に次のことを設定する必要があります。

  • 以下をDefaultEngine.iniファイルを追加することで、AccelByte OSS のセッション V2 を有効にする必要があります。

    [OnlineSubsystemAccelByte]
    bEnableV2Sessions=true
  • 管理者ポータルで、マッチメイキングとセッション V2 に必要な権限を、ゲームクライアントに追加する必要があります。

  • ゲームクライアントは、AccelByte バックエンドで認証され、ロビーサービスに接続されている必要があります。

マッチメイキングのフロー

このセクションでは、ソロプレイヤーとパーティ両方のマッチメイキングフローについて説明します。

AGS Overview

  1. プレイヤーがパーティを作成し、フレンドを招待します。次に、目的のゲームモードを選択し、利用可能な設定を設定します。

  2. プレイを開始する準備ができたら、プレイヤー (またはパーティリーダー) がマッチメイキングを開始し、マッチチケットを作成してマッチプールで待機させます。パーティリーダーがマッチメイキングを開始すると、すべてのプレイヤーが添付されたマッチチケットが1枚送信されます。

  3. サービスは、最適なマッチを見つけるために、関連するマッチルールセットで定義されたロジックに基づいてチケットを評価します。

  4. マッチが見つかった場合、サービスはセッションサービスからゲームセッションを要求し、チケット情報をセッションに添付します。

  5. このサービスは、ゲームセッションのバックフィルチケットも作成するため、指定された最小人数のプレイヤー要件が満たされるまで、追加のマッチを見つけることができます。

  6. プレイヤーは、マッチとして選択され、接続できるようになると、ゲームセッションに参加するための招待を受け取ります。

マッチメイキングの開始

マッチメイキングを開始するには、サービスをゲームプロジェクトに統合するために知っておくべき複数の OSS コンポーネントがあります。

  • セッションインターフェイス:マッチメイキングとセッション管理を実行するために使用される機能を提供します。

  • Session Search Handle (セッション検索ハンドル)]:マッチングが成功した場合に返されるゲームセッションを保存するために、マッチメイキング中に必要なセッション検索の結果を保存します。

  • Matchmaking Callback Functions (マッチメイキングコールバック関数)]:マッチングの開始やマッチングの完了など、特定のマッチメイキングイベントをリッスンします。

  • Join Session Callback Functions (セッション参加のコールバック関数)]:セッションの破棄やセッションの参加など、特定のセッションイベントをリッスンします。

準備が整い、上記の前提条件を満たし、設定手順を完了したら、マッチメイキングをリクエストするために必要なコードの追加を開始できます。

マッチメイキングを開始する予定の関数で、AccelByte OSS からセッションインターフェイスを取得する必要があります。マッチメイキングをリクエストするために使用するカスタムの AccelByte セッションインターフェイスがあり、タイプはFOnlineSessionAccelBytePtrです。

const IOnlineSubsystem* Subsystem = Online::GetSubsystem(GetWorld());
if (!ensure(Subsystem != nullptr))
{
return;
}

const FOnlineSessionAccelBytePtr SessionInterface = StaticCastSharedPtr<FOnlineSessionV2AccelByte>(Subsystem->GetSessionInterface());
if (!ensure(SessionInterface.IsValid()))
{
return;
}
注記

コールバック結果を処理するために後でアクセスする必要があるので、セッションインターフェイスをクラスメンバーとして保存することをお勧めします。

マッチメイキング開始リクエストの一部としてPlayer Controller IDを渡すために後から使用できるよう、ゲームクライアントのPlayer IDを取得する必要があります。コールバック結果を処理するときに、Player Controller IDも後で使用します。

const FUniqueNetIdPtr LocalPlayerId = GetUniquePlayerId();
if (!ensure(LocalPlayerId.IsValid()))
{
return false;
}

マッチが正常に見つかった場合、マッチメイキングプロセス中に作成されたセッション結果を保存するためのセッション検索ハンドルFOnlineSessionSearchを作成する必要があります。セッション検索ハンドルを作成する場合は、次のパラメータを使用してクエリ設定を設定する必要があります。

  • Player Controller ID (プレイヤーコントローラー ID)]:マッチメイキング中にマッチチケットが送信されるプレイヤーの OSS ID。
  • Match Pool Session Settings(マッチプールセッション設定)]:マッチメイキング中に使用される OSS セッション設定SETTING_SESSION_MATCHPOOL。これを渡すと、次のパラメータとして指定した[Match Pool Name(マッチプール名)]で更新されます。
  • Match Pool Name(マッチプール名)]:指定されたゲームモードの前提条件の一部として定義したマッチプールの名前。これにより、マッチメイキングサービスに通知され、評価のために新しく作成されたマッチチケットがそのマッチプールに追加されます。
  • Comparison Operator (比較演算子)]:セッション検索の一部として使用される OSS 演算子。この場合はEOnlineComparisonOp::Equals
// Create a new search handle instance for matchmaking. Importantly, you will need to set the match pool that you are searching for with SETTING_SESSION_MATCHPOOL, as shown below.

TSharedRef<FOnlineSessionSearch> MatchmakingSearchHandle = MakeShared<FOnlineSessionSearch>();
MatchmakingSearchHandle->QuerySettings.Set(SETTING_SESSION_MATCHPOOL, FString(TEXT("YOUR_MATCHPOOL_NAME_GOES_HERE")), EOnlineComparisonOp::Equals);
注記

セッション検索ハンドルをクラスメンバーとして保存し、そのタイプを保持してから、マッチが正常に見つかった後に返された結果を割り当てることをお勧めします。

マッチ結果をリッスンするには、FOnMatchmakingCompleteDelegateコールバックデリゲートを登録する必要があります。これはマッチメイキングが完了するとトリガーされます。コールバック関数のサンプルコードについては、このガイドにある「マッチ結果コールバックの処理」セクションを参照してください。

  • セッション名:マッチが成功した場合に作成されるゲームセッションの名前です。
  • 成功値:マッチメイキングサービスがマッチを見つけることに成功したかどうかを示すブール値です。
// Bind a function that has a return type of void and these parameters:
// FName SessionName, bool bWasSuccessful
const FOnMatchmakingCompleteDelegate OnMatchmakingCompleteDelegate = /* Bind to lambda or class method */;
SessionInterface->AddOnMatchmakingCompleteDelegate_Handle(OnMatchmakingCompleteDelegate);

上記を取得したら、セッションインターフェイスからStartMatchmaking()を呼び出して、マッチメイキングの開始をリクエストできます。この関数は次のパラメータを取得します。

  • Player Controller ID (プレイヤーコントローラー ID)]:マッチメイキング中にマッチチケットが送信されるプレイヤーの OSS ID。
  • セッション名:マッチメイキングが成功した場合に作成されるセッションの名前。通常、NAME_GameSessionを渡します。
  • セッション設定:セッションサービスがゲームセッションを作成するために使用するセッション設定FOnlineSessionSettings()。この場合は、空のオブジェクトを渡して設定の割り当てをセッションサービスに任せます。
  • Session Search Handle (セッション検索ハンドル)]:このセクションの前半で作成した[Session Search Handle (セッション検索ハンドル)]。マッチメイキングが成功した場合に作成されるゲームセッションを保存します。

StartMatchmaking()へのリクエストが行われたら、呼び出しが true を返すと想定して、このセクションで先ほど定義した[Session Search Handle (セッション検索ハンドル)]を今後アクセスするためにクラスメンバーにバインドする必要があります。StartMatchmaking()が false を返した場合は、マッチメイキングサービスへの呼び出しに問題があったことを意味します。

if (SessionInterface->StartMatchmaking(USER_ID_TO_MATCHMAKING_USER_ARRAY(LocalPlayerId.ToSharedRef()), NAME_GameSession, FOnlineSessionSettings(), MatchmakingSearchHandle, OnStartMatchmakingCompleteDelegate))
{
// Update the current search result handle class member with the search handle passed to the matchmaking service.
CurrentMatchmakingSearchHandle = MatchmakingSearchHandle;
}
注記

OnlineSubsystemV2 では、パーティに参加している場合、StartMatchmaking 呼び出しが、作成中にマッチチケットの一部として添付さ れるPartyID を自動的に送信します。

ゲームセッションへの参加

マッチメイキングが完了すると、マッチメイキングを開始する前にバインドしたOnMatchmakingCompleteDelegateが発動し、以下の手順に従って結果を処理できます。

セッション検索ハンドルのSearchResultsメンバー配列に格納されているゲームセッション結果を取得する必要があります。配列が空の場合は、トラブルシューティング を参照してください。

// Ensure that we have a valid session search result in the array before continuing
if (!CurrentMatchmakingSearchHandle->SearchResults.IsValidIndex(0))
{
return false;
}

FOnlineSessionSearchResult MatchResult = CurrentMatchmakingSearchHandle->SearchResults[0];
EOnlineSessionTypeAccelByte SessionType = SessionInterface->GetSessionTypeFromSettings(MatchResult.Session.SessionSettings);
if (SessionType != EOnlineSessionTypeAccelByte::GameSession)
{
return false;
}

プレイヤーが既にゲームセッションに参加しているかどうかを確認する必要があります。既に参加している場合は、マッチメイキングで返された新しいセッションに参加できるように、参加済みのゲームセッションは破棄する必要があります。FOnDestroySessionCompleteDelegateコールバックデリゲートを登録して、結果をリッスンできます。

// Check if we already have a game session, if so, destroy it to join this one
if (SessionInterface->GetNamedSession(NAME_GameSession) != nullptr)
{
const FOnDestroySessionCompleteDelegate OnDestroySessionForJoinCompleteDelegate = FOnDestroySessionCompleteDelegate::CreateUObject(this, &UOSSDemoGameSessionSubsystem::OnDestroySessionForJoinComplete, Session);
return SessionInterface->DestroySession(NAME_GameSession, OnDestroySessionForJoinCompleteDelegate);
}

参加結果をリッスンするには、FOnJoinSessionCompleteDelegateコールバックデリゲートを登録する必要があります。これは参加リクエストが完了するとトリガーされます。ゲームサーバーへの参加をリクエストできる段階でのコールバック関数のサンプルコードについては、本ガイドの ホストサーバーへの参加 セクションを参照してください。

// Register a delegate for joining the specified session
const FOnJoinSessionCompleteDelegate OnJoinSessionCompleteDelegate = FOnJoinSessionCompleteDelegate::CreateUObject(this, &UOSSDemoGameSessionSubsystem::OnJoinSessionComplete);
JoinSessionDelegateHandle = SessionInterface->AddOnJoinSessionCompleteDelegate_Handle(OnJoinSessionCompleteDelegate);

上記を取得すると、セッションインターフェイスからJoinSession()を呼び出して、返されたセッションに参加できます。この関数は次のパラメータを使用します。

  • プレイヤーコントローラー ID:マッチメイキング中にマッチチケットが送信されるプレイヤーの OSS ID です。
  • セッション名:マッチメイキングが成功した場合に作成されるゲームセッションの名前です。
  • セッション:後でアクセスするためにセッションサービスがゲームセッション情報を割り当てる OSS セッションオブジェクトです。
SessionInterface->JoinSession(LocalPlayerId.ToSharedRef().Get(), NAME_GameSession, Session);

以下は、OnMatchmakingComplete結果をリッスンするためのデリゲートとして使用できるコールバック関数の例です。

void OnMatchmakingCompleteDelegate(FName SessionName, bool bWasSuccessful)
{
if (SessionName != NAME_GameSession)
{
return;
}

EOnlineSessionTypeAccelByte SessionType = SessionInterface->GetSessionTypeFromSettings(MatchResult.Session.SessionSettings);
if (SessionType != EOnlineSessionTypeAccelByte::GameSession)
{
return false;
}

// Ensure that we have a valid session search result in the array before continuing
if (!CurrentMatchmakingSearchHandle->SearchResults.IsValidIndex(0))
{
return false;
}

FOnlineSessionSearchResult MatchResult = CurrentMatchmakingSearchHandle->SearchResults[0];

// Check if we already have a game session that we are in, if so, destroy it to join this one
if (SessionInterface->GetNamedSession(NAME_GameSession) != nullptr)
{
const FOnDestroySessionCompleteDelegate OnDestroySessionForJoinCompleteDelegate = FOnDestroySessionCompleteDelegate::CreateUObject(this, &UOSSDemoGameSessionSubsystem::OnDestroySessionForJoinComplete, Session);
return SessionInterface->DestroySession(NAME_GameSession, OnDestroySessionForJoinCompleteDelegate);
}

// Register a delegate for joining the specified session
const FOnJoinSessionCompleteDelegate OnJoinSessionCompleteDelegate = FOnJoinSessionCompleteDelegate::CreateUObject(this, &UOSSDemoGameSessionSubsystem::OnJoinSessionComplete);


JoinSessionDelegateHandle = SessionInterface->AddOnJoinSessionCompleteDelegate_Handle(OnJoinSessionCompleteDelegate);

const FUniqueNetIdPtr LocalPlayerId = GetUniquePlayerId();
if (!ensure(LocalPlayerId.IsValid()))
{
return false;
}

return SessionInterface->JoinSession(LocalPlayerId.ToSharedRef().Get(), NAME_GameSession, Session);
}

ゲームホストへの参加

ゲームセッションへの参加が完了すると、セッションへの参加をリクエストする前にバインドしたOnJoinSessionCompleteが発動し、次の手順に従って結果を処理できます。

参加リクエストが正常に完了してゲームセッションに参加したかどうかを判断するには、デリゲートに渡された列挙型の結果を確認する必要があります。

if (Result != EOnJoinSessionCompleteResult::Success)
{
return;
}

参加に成功している場合は、ゲームセッションに参加しているので、GetResolvedConnectString()を呼び出すことでセッションインターフェイスから関連するホスト接続を抽出できます。関数は次のパラメータを取得します。

  • セッション名:マッチメイキングが成功した場合に作成されるゲームセッションの名前。
  • TravelURL:セッションがホストに接続されている場合、接続文字列が含まれます。
  • Game Port (ゲームポート)]:接続のホストポート。

接続文字列をリクエストした後、TravelURLは有効な接続文字列を含むか、または空になります。有効な接続文字列が含まれている場合、ゲームセッションが接続されていることを意味し、文字列を使用してプレイヤーをホストに接続できます。

空の場合、ゲームセッションはまだ接続を待機しています。ホストの参加結果をリッスンし、ゲームセッションがホストに正常に接続するのを待つには、OnSessionServerUpdateコールバックデリゲートを登録する必要があります。

FString TravelUrl{};

if (SessionInterface->GetResolvedConnectString(SessionName, TravelUrl, NAME_GamePort) && !TravelUrl.IsEmpty())
{
// If we successfully got a connect string from the session, then this is where you would connect to it
}
else
{
// Otherwise, bind a delegate to OnSessionServerUpdate to wait for a server to be spun up. Once this
const FOnSessionServerUpdateDelegate OnSessionServerUpdateDelegate = FOnSessionServerUpdateDelegate::CreateUObject(this, &UOSSDemoGameSessionSubsystem::OnSessionServerUpdate);

SessionInterface->AddOnSessionServerUpdateDelegate_Handle(OnSessionServerUpdateDelegate);
}

以下は、OnJoinSessionComplete結果をリッスンするためのデリゲートとして使用できるコールバック関数の例です。

void OnJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result)
{
if (SessionName != NAME_GameSession)
{
return;
}

if (Result != EOnJoinSessionCompleteResult::Success)
{
return;
}

const FOnlineSessionAccelBytePtr SessionInterface = GetSessionInterface();
check(SessionInterface.IsValid());

// Remove our delegate handler for join session, we will rebind if we join another session
SessionInterface->ClearOnJoinSessionCompleteDelegate_Handle(JoinSessionDelegateHandle);
JoinSessionDelegateHandle.Reset();

FNamedOnlineSession* Session = SessionInterface->GetNamedSession(SessionName);
check(Session != nullptr)

TSharedPtr<FOnlineSessionInfoAccelByteV2> SessionInfo = StaticCastSharedPtr<FOnlineSessionInfoAccelByteV2>(Session->SessionInfo);
check(SessionInfo.IsValid());

FString TravelUrl{};
if (SessionInterface->GetResolvedConnectString(SessionName, TravelUrl, NAME_GamePort) && !TravelUrl.IsEmpty())
{
// If we successfully got a connect string from the session, then this is where you would connect to it
}
else
{
// Otherwise, bind a delegate to OnSessionServerUpdate to wait for a server to be spun up. Once this
// delegate is fired, you may call the same GetResolvedConnectString to get the server address to
// connect to.
const FOnSessionServerUpdateDelegate OnSessionServerUpdateDelegate = FOnSessionServerUpdateDelegate::CreateUObject(this, &UOSSDemoGameSessionSubsystem::OnSessionServerUpdate);
SessionInterface->AddOnSessionServerUpdateDelegate_Handle(OnSessionServerUpdateDelegate);
}
}

マッチメイキングのキャンセル

プロセスが完了する前またはタイムアウトが発生する前にマッチメイキングをキャンセルする必要がある場合は、FOnlineSessionV2Accelbyte::CancelMatchmaking()を呼び出して、マッチメイキングの開始をリクエストしたときに入力したプレイヤーコントローラー IDセッション名NAME_GameSession を渡せます。

サポートされている告知

マッチメイキングサービスはそのプロセスの一環として、ロビーサービスを介してゲームクライアントに次の告知を送信します。告知はログファイルで表示可能です。

告知詳細
OnSessionInvitedゲームクライアントに送信される告知で、保留中のセッションの招待があることを知らせます。
OnSessionJoinedゲームクライアントに送信される告知で、セッションに正常に参加したことを知らせます。
OnSessionKickedゲームクライアントに送信される告知で、セッションからキックアウトされたことを知らせます。
OnSessionEndedゲームクライアントに送信される告知で、セッションが終了したことを知らせます。
OnSessionMembersChanged接続されているすべてのゲームクライアントに送信される告知で、プレイヤーの接続や切断など、メンバーシップに変更があったことを知らせます。
OnSessionDataChanged接続されているすべてのゲームクライアントに送信される告知で、セッションの情報に変更があったことを知らせます。
dsNotif接続されているすべてのゲームクライアントに送信される告知で、専用サーバーのステータスを提供します。
OnMatchmakingTicketExpiredゲームクライアントに送信される告知で、マッチメイキングのリクエストがマッチプールの定義された期間を超えて、タイムアウトしたことを知らせます。

トラブルシューティング

このセクションには、サービス使用時に発生しうる一般的なエラーや問題、およびそれらを解決する方法についての推奨事項を記載しています。

ロビーサービスからの OnMatchmakingTicketExpired 告知

ロビーサービスからOnMatchmakingTicketExpired告知を受信した場合、これはチケットがタイムアウト制限に達し、プレイヤーがマッチメイキングから削除されたことを意味します。これは、マッチプール設定で定義したタイムアウトが短すぎるか、マッチルールセットでプレイヤーが他のプレイヤーとマッチングできるようにルールの十分なフレキシングが許可されていない場合によく発生します。

  • マッチプールの設定を確認して、マッチまたはバックフィルチケットのタイムアウトが短すぎるかどうかを判断します。
  • マッチルールセットを見直して、プレイヤー/チームの最小要件が正しく設定されていることを確認します。

OnMatchmakingComplete SearchResults 配列が空

マッチメイキングが完了したことを告知するマッチ結果をリッスンすると、[Session Search Handle(セッション検索ハンドル)]に空のSearchResults配列がある場合があります。これは、ハンドルがTSharedRefとして保存されていないことを意味し、マッチメイキングセッションの結果を取得できなくなります。

  • [Session Search Handle(セッション検索ハンドル)]がタイプTSharedRefをずっと維持していることを確認してください。