注釈:本資料はAI技術を用いて翻訳されています。
OSS を使用したマッチメイキングのセットアップ
ゲームにマッチメイキングを実装するには、以下の手順に従ってください。
プラグインの依存関係
OSS を使用した P2P には、P2P 機能のための Network Utilities プラグインを含む AccelByte OSS プラグインスイート一式が必要です。このガイドでは、必要なすべてのプラグインの設定について説明します。詳細な依存関係情報については、UE プラグイン依存関係ガイドを参照してください。
前提条件
-
DefaultEngine.iniファイルに以下を追加して、AccelByte Online Subsystem (OSS) で Sessions V2 を有効にします。[OnlineSubsystemAccelByte]
bEnableV2Sessions=true -
DefaultEngine.iniに以下を追加してAccelByteNetworkUtilitiesを有効にします。[AccelByteNetworkUtilities]
UseTurnManager=true
HostCheckTimeout=5
[/Script/AccelByteNetworkUtilities.IpNetDriverAccelByte]
NetConnectionClassName=AccelByteNetworkUtilities.IpConnectionAccelByte
AllowDownloads=false
[/Script/Engine.Engine]
!NetDriverDefinitions=ClearArray
+NetDriverDefinitions=(DefName="GameNetDriver",DriverClassName="/Script/AccelByteNetworkUtilities.IpNetDriverAccelByte",DriverClassNameFallback="/Script/OnlineSubsystemUtils.IpNetDriver")
+NetDriverDefinitions=(DefName="DemoNetDriver",DriverClassName="/Script/Engine.DemoNetDriver",DriverClassNameFallback="/Script/Engine.DemoNetDriver") -
Admin Portal でゲームクライアントにマッチメイキングと Session V2 に必要なパーミッションを追加します。
-
ゲームクライアントが AccelByte バックエンドで認証済みであり、Lobby サービスに接続済みである必要があります。
非シームレストラベル失敗の回避策
非シームレストラベル中、Unreal Engine のベースネットワーキングクラス(UIpConnection)は AccelByte IP 形式で DNS 解決を試みますが、この形式は有効な DNS ホスト名ではありません。その結果、解決に失敗しネットワークエラーが発生します。
この問題を回避するには、DefaultEngine.ini ファイルの [AccelByteNetworkUtilities] セクションに bNonSeamlessTravelUseNewConnection=true を設定してください。このオプションを有効にすると、ベース接続の初期化前に DisableAddressResolution() が呼び出され、Unreal Engine が AccelByte アドレスで DNS 解決を試みないようにします。
例:
...
[AccelByteNetworkUtilities]
bNonSeamlessTravelUseNewConnection=true
...
マッチメイキングの開始
マッチメイキングを開始する予定の関数で、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: マッチメイキング中にマッチチケットが送信されるプレイヤーの OSS ID。
- Match Pool Session Settings: マッチメイキング中に使用される OSS セッション設定
SETTING_SESSION_MATCHPOOL。これを渡すことで、次のパラメーターとして提供するマッチプール名で更新されます。 - Match Pool Name: 指定したゲームモードの前提条件として定義したマッチプールの名前。これにより、マッチメイキングサービスは新しく作成されたマッチチケットをそのマッチプールに追加して評価します。
- Comparison Operator: セッション検索の一部として使用される OSS オペレーター。この場合は
EOnlineComparisonOp::Equalsです。
マッチ結果をリッスンするために FOnMatchmakingCompleteDelegate コールバックデリゲートを登録する必要があります。これはマッチメイキング完了時にトリガーされます。サンプルコードについてはサンプルコールバック関数セクションを参照してください。
- Session Name: マッチが成功した場合に作成されるゲームセッションの名前。
- Success Value: マッチメイキングがマッチを正常に見つけたかどうかを示すブール値。
// 戻り値が void でこれらのパラメーターを持つ関数をバインドします:
// FName SessionName, bool bWasSuccessful
const FOnMatchmakingCompleteDelegate OnMatchmakingCompleteDelegate = /* ラムダまたはクラスメソッドにバインド */;
SessionInterface->AddOnMatchmakingCompleteDelegate_Handle(OnMatchmakingCompleteDelegate);
上記が揃ったら、セッションインターフェースから StartMatchmaking() を呼び出してマッチメイキングの開始をリクエストできます。この関数は以下のパラメーターを受け取ります。
-
Player Controller ID: マッチメイキング中にマッチチケットが送信されるプレイヤーの OSS ID。
-
Session Name: マッチメイキングが成功した場合に作成されるセッションの名前。通常は
NAME_GameSessionを渡します。 -
Session Settings: ゲームセッションを作成するために Session サービスが使用するセッション設定
FOnlineSessionSettings()。この場合、空のオブジェクトを渡してセッションサービスに設定を割り当てさせます。 -
Session Search Handle: マッチメイキングが成功した場合に作成されるゲームセッションを保存するために、このセクションで先ほど作成したセッション検索ハンドル。
StartMatchmaking() へのリクエストが完了し、呼び出しが true を返したとみなして、このセクションで先ほど定義したセッション検索ハンドルを将来のアクセスのためにクラスメンバーにバインドする必要があります。StartMatchmaking() が false を返す場合、マッチメイキングサービスへの呼び出しに問題があったことを示します。
if (SessionInterface->StartMatchmaking(USER_ID_TO_MATCHMAKING_USER_ARRAY(LocalPlayerId.ToSharedRef()), NAME_GameSession, FOnlineSessionSettings(), MatchmakingSearchHandle, OnStartMatchmakingCompleteDelegate))
{
// マッチメイキングサービスに渡された検索ハンドルで現在の検索結果ハンドルクラスメンバーを更新します。
CurrentMatchmakingSearchHandle = MatchmakingSearchHandle;
}
Turn Server QoS を使用したマッチメイキングの開始
この機能は AGS バージョン 3.75 でのみ利用可能です。
この実装は、マッチチケットを作成してレイテンシ情報を提供する前に Turn Server QoS を取得するための低レベルタスクを自動的に処理します。
SetIsP2PMatchmaking のカスタム関数にアクセスするには、まず FOnlineSessionSearchAccelByte クラスを使用して新しいマッチメイキング検索ハンドルを指定します。次に、マッチが P2P セッション用であることを示すためにパラメーターを true に設定します。最後に、マッチを開始するためにマッチメイキング検索ハンドルを StartMatchmaking 関数に渡します。
TSharedRef<FOnlineSessionSearchAccelByte> MatchmakingSearchHandle = MakeShared<FOnlineSessionSearchAccelByte>();
MatchmakingSearchHandle->QuerySettings.Set(SETTING_SESSION_MATCHPOOL, MatchPoolName, EOnlineComparisonOp::Equals);
MatchmakingSearchHandle->SetIsP2PMatchmaking(true);
if (SessionInterface_User1->StartMatchmaking(USER_ID_TO_MATCHMAKING_USER_ARRAY(LocalUserId1.ToSharedRef()), NAME_GameSession, FOnlineSessionSettings(), MatchmakingSearchHandle, OnStartMatchmakingCompleteDelegate))
{
CurrentMatchmakingSearchHandle = MatchmakingSearchHandle;
}
P2P 接続を使用したゲームセッションへの参加とトラベル
マッチメイキングが完了すると、マッチメイキング開始前にバインドした OnMatchmakingCompleteDelegate が発火し、以下の手順に従って結果を処理できます。
セッション検索ハンドルの SearchResults メンバー配列に保存されたゲームセッション結果を取得します。配列が空の場合はトラブルシューティングを参照してください。
// 続行する前に配列に有効なセッション検索結果があることを確認します
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 コールバックデリゲートを登録できます。
// すでにゲームセッションがある場合は、このセッションに参加するために破棄します
if (SessionInterface->GetNamedSession(NAME_GameSession) != nullptr)
{
const FOnDestroySessionCompleteDelegate OnDestroySessionForJoinCompleteDelegate = FOnDestroySessionCompleteDelegate::CreateUObject(this, &UOSSDemoGameSessionSubsystem::OnDestroySessionForJoinComplete, Session);
return SessionInterface->DestroySession(NAME_GameSession, OnDestroySessionForJoinCompleteDelegate);
}
参加リクエストが完了したときにトリガーされる参加結果をリッスンするために FOnJoinSessionCompleteDelegate コールバックデリゲートを登録します。このデリゲートでは P2P 接続も処理する必要があります。ユーザーがゲームセッションリーダーかどうかを確認する必要があります。ユーザーがゲームセッションリーダー(ゲームセッションに最初に参加したユーザー)であれば、このユーザーをリッスンサーバーとして設定する必要があります。ユーザーが通常のメンバーであれば、ゲームセッションリーダーへの接続を開始する必要があります。
// 指定されたセッションに参加するためのデリゲートを登録します
const FOnJoinSessionCompleteDelegate OnJoinSessionCompleteDelegate = FOnJoinSessionCompleteDelegate::CreateUObject(this, &UOSSDemoGameSessionSubsystem::OnJoinSessionComplete);
JoinSessionDelegateHandle = SessionInterface->AddOnJoinSessionCompleteDelegate_Handle(OnJoinSessionCompleteDelegate);
以下は P2P 接続を処理するための OnJoinSessionCompleteDelegate のサンプルです。
void UOSSDemoGameSessionSubsystem::OnJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result)
{
// ゲームセッション以外の参加結果は無視します
if (SessionName != NAME_GameSession)
{
return;
}
if (Result != EOnJoinSessionCompleteResult::Success)
{
return;
}
const FOnlineSessionAccelBytePtr SessionInterface = GetSessionInterface();
ensure(SessionInterface.IsValid());
FNamedOnlineSession* Session = SessionInterface->GetNamedSession(SessionName);
if (!ensure(Session != nullptr))
{
return;
}
TSharedPtr<FOnlineSessionInfoAccelByteV2> SessionInfo = StaticCastSharedPtr<FOnlineSessionInfoAccelByteV2>(Session->SessionInfo);
if (!ensure(SessionInfo.IsValid()))
{
return;
}
ULocalPlayer* LocalPlayer = GetLocalPlayer();
if (!ensure(LocalPlayer != nullptr))
{
return;
}
APlayerController* Controller = LocalPlayer->GetPlayerController(GetWorld());
if (!ensure(Controller != nullptr))
{
return;
}
// 作成されたセッションのサーバータイプが NONE(ローカル)の場合、接続情報はセッション属性にあります
const EAccelByteV2SessionConfigurationServerType ServerType = SessionInfo->GetServerType();
if (ServerType != EAccelByteV2SessionConfigurationServerType::P2P)
{
// これは P2P セッションではありません
return;
}
FString TravelUrl{};
if (SessionInterface->GetResolvedConnectString(SessionName, TravelUrl, NAME_GamePort) && !TravelUrl.IsEmpty())
{
if(SessionInterface->IsPlayerP2PHost(LocalPlayerId, SessionName))
{
// リッスンサーバーとしてトラベルします
FString MapName;
Session->SessionSettings.Get(SETTING_MAPNAME, MapName);
Controller->ClientTravel(FString::Printf(TEXT("%s?listen"), *MapName), TRAVEL_Absolute);
}
else
{
Controller->ClientTravel(TravelUrl, TRAVEL_Absolute);
}
}
}
上記が揃ったら、セッションインターフェースから JoinSession() を呼び出して返されたセッションに参加できます。この関数は以下のパラメーターを受け取ります。
-
Player Controller ID: マッチメイキング中にマッチチケットが送信されるプレイヤーの OSS ID。
-
Session Name: マッチメイキングが成功した場合に作成されるゲームセッションの名前。
-
Session: Session サービスが後のアクセスのためにゲームセッション情報を割り当てる 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;
}
// 続行する前に配列に有効なセッション検索結果があることを確認します
if (!CurrentMatchmakingSearchHandle->SearchResults.IsValidIndex(0))
{
return false;
}
FOnlineSessionSearchResult MatchResult = CurrentMatchmakingSearchHandle->SearchResults[0];
// 参加しているゲームセッションがすでにある場合は、このセッションに参加するために破棄します
if (SessionInterface->GetNamedSession(NAME_GameSession) != nullptr)
{
const FOnDestroySessionCompleteDelegate OnDestroySessionForJoinCompleteDelegate = FOnDestroySessionCompleteDelegate::CreateUObject(this, &UOSSDemoGameSessionSubsystem::OnDestroySessionForJoinComplete, Session);
return SessionInterface->DestroySession(NAME_GameSession, OnDestroySessionForJoinCompleteDelegate);
}
// 指定されたセッションに参加するためのデリゲートを登録します
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);
}
デバッグ目的では、ゲーム起動時に追加パラメーター -iceforcerelay を渡すことで、Interactive Connectivity Establishment (ICE) 接続として Relay (TURN) を使用できます。