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

Managing P2P Sessions with Session Browser

Last updated on August 9, 2023

概要

このガイドでは、AccelByte のオンラインサブシステム (OSS) for Unreal Engine を使用したピアツーピアセッションのホスティング、参加、閲覧の基本について説明します。これにより、ゲームクライアントは専用サーバーなしで接続して一緒にプレイすることができます。さらに、セッションブラウザの実装により、プレイヤーはホストプレイヤーを知ることなく、既存のオープンなピアツーピア (P2P) セッションを見つけて参加できます。

目標

  • AccelByte Unreal Engine プラグインを設定する。
  • ピアツーピアセッションをホストする。
  • P2P セッションを閲覧して参加する。

前提条件

このガイドを読む前に、以下を用意しておく必要があります。

  • オンラインサブシステム (OSS) の使用など、Unreal Engine の知識
  • AccelByte SDK、NetworkUtilities、OnlineSubsystem プラグイン
  • AccelByte 管理者ポータルとゲームの名前空間へのアクセス権
  • タイプが P2P に設定され、参加可能性が OPEN (オープン) に設定されたセッションテンプレート

プラグインの設定方法

最初に、DefaultEngine.iniファイル内の V2 セッションを有効にする必要があります。

[OnlineSubsystemAccelByte]
bEnableV2Sessions=true

次に、TURN サーバーと Net Driver を設定します。

[AccelByteNetworkUtilities]
UseTurnManager=true
TurnServerSecret=<your-turn-secret>

[/Script/AccelByteNetworkUtilities.IpNetDriverAccelByte]
NetConnectionClassName=AccelByteNetworkUtilities.IpConnectionAccelByte

プラットフォームごとに Net Driver の定義を設定する必要があります。たとえば、Windows の場合、以下をWindowsEngine.iniに追加します。

[/Script/Engine.GameEngine]
!NetDriverDefinitions=ClearArray
+NetDriverDefinitions=(DefName="GameNetDriver",DriverClassName="AccelByteNetworkUtilities.IpNetDriverAccelByte",DriverClassNameFallback="OnlineSubsystemUtils.IpNetDriver")
+NetDriverDefinitions=(DefName="DemoNetDriver",DriverClassName="/Script/Engine.DemoNetDriver",DriverClassNameFallback="/Script/Engine.DemoNetDriver")

P2P セッションをホストする方法

ここでは、前のステップの新しいセッションテンプレートを使用してセッションを作成する例を示します。まず、いくつかの設定を行う必要があります。その後、OSS セッションインターフェイスでCreateSessionを呼び出します。

まず、AccelByte セッションインターフェイスを取得します。

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

FOnlineSessionV2AccelBytePtr SessionInterface;
if (!FOnlineSessionV2AccelByte::GetFromSubsystem(Subsystem, SessionInterface))
{
return;
}

次に、セッション設定を編集します。

FOnlineSessionSettings NewSessionSettings;

// This would be the name of the session template created in the Admin Portal
NewSessionSettings.Set(SETTING_SESSION_TEMPLATE_NAME, TEXT("P2PSession"));

// We want the new session to be a game session, as opposed to a party
// session
NewSessionSettings.Set(SETTING_SESSION_TYPE, SETTING_SESSION_TYPE_GAME_SESSION);

// We need some kind of parameter that the session browser can later use
// to query for sessions
NewSessionSettings.Set(FName(TEXT("IS_P2P_SESSION")), TEXT("true"));

// At this point, any other custom settings can be applied. For example, we
// can add a map name that we'll later use when we're hosting the P2P session
NewSessionSettings.Set(SETTING_MAPNAME, TEXT("MapName"));

最後に、実際にセッションを作成するための呼び出しを行います。

// We create a delegate which will be triggered when session creation is
// complete, inside of which we'll call StartSession and perform a travel
const FOnCreateSessionCompleteDelegate OnCreateSessionCompleteDelegate =
FOnCreateSessionCompleteDelegate::CreateUObject(this,
&MyClass::OnCreateSessionComplete);
FDelegateHandle CreateSessionDelegateHandle =
SessionInterface->AddOnCreateSessionCompleteDelegate_Handle(
OnCreateSessionCompleteDelegate);
// Here `PlayerId` is an FUniqueNetIdPtr for the player
SessionInterface->CreateSession(
PlayerId.ToSharedRef().Get(), NAME_GameSession, NewSessionSettings);

上記のコードで、セッション作成完了デリゲートのハンドラを追加します。そのハンドラ内で、次のことを行う必要があります。

まず、SessionName デリゲートパラメータを使用して、これが正しいセッションであることを素早く確認します。

if(SessionName != NAME_GameSession)
{
return;
}
注記

上記のサニティーチェックを、パラメータとしてセッション名を受け取るすべてのデリゲートハンドラで実行することをお勧めします。

上記のように、セッションインターフェイスを再び取得します。その後、実際のセッションインスタンスを取得して、セッションを開始としてマークすることができます。

FNamedOnlineSession* Session = SessionInterface->GetNamedSession(SessionName);
if (!ensure(Session != nullptr))
{
return;
}

SessionInterface->StartSession(SessionName);

最後に、トラベル URL を構築しトラベルを実行します。

// We'll use our previously set map name for traveling
FString MapName;
Session->SessionSettings.Get(SETTING_MAPNAME, MapName);

// Constructing the travel URL with "?listen" appended to the map name so that we
// host a listen server
const FString TravelUrl = FString::Printf(TEXT("%s?listen"), *MapName);

// Here `PlayerController` is a pointer to an APlayerController for the
// local player
Controller->ClientTravel(TravelUrl, TRAVEL_Absolute);
注記

一般的に、他のプレイヤーをセッションに受け入れる準備が整っているかどうかを示すセッション設定を追加すると便利です。これは、マップのロード後に何らかの指標値に設定されます。

P2P セッションを閲覧し、参加する方法

P2P セッションを閲覧するために、前のステップのIS_P2P_SESSION設定でセッションインターフェイスのFindSessionsメソッドを使用します。まず、AccelByte セッションインターフェイスをもう一度取得する必要があります。次に、クエリを実行する属性を設定します。

TSharedPtr<FOnlineSessionSearch> QuerySessionsHandle =
MakeShared<FOnlineSessionSearch>();

// We'll set the maximum search results to some arbitrary value
QuerySessionsHandle->MaxSearchResults = 100;

// Search for sessions with the P2P setting we used earlier
QuerySessionsHandle->QuerySettings.Set(
FName(TEXT("IS_P2P_SESSION")), TEXT("true"));

// We can also query for other session settings, such as MAPNAME
QuerySessionsHandle->QuerySettings.Set(SETTING_MAPNAME, TEXT("MapName"));
注記

検索結果が含まれるので、FindSessions完了デリゲートで使用するためにFOnlineSessionSearchハンドルを用意しておきます。

次に、FindSessionsを呼び出します。

const FOnFindSessionsCompleteDelegate OnFindSessionsCompleteDelegate = 
FOnFindSessionsCompleteDelegate::CreateUObject(
this, &MyClass::OnFindSessionsComplete);
FDelegateHandle FindSessionsCompleteDelegateHandle =
SessionInterface->AddOnFindSessionsCompleteDelegate_Handle(
OnFindSessionsCompleteDelegate);
// Here `PlayerId` is an FUniqueNetIdPtr for the player
SessionInterface->FindSessions(
PlayerId.ToSharedRef().Get(), QuerySessionsHandle.ToSharedRef());

OnFindSessionsCompleteデリゲートのハンドラ内で、FOnlineSessionSearchResultの配列にアクセスできます。これは、セッションブラウザ UI でセッションのリストを表示するために使用できます。たとえば、ハンドラはしばしばこの配列を別のデリゲートに渡し、検索ハンドルをリセットします。

SomeSessionBrowserListingDelegate.Broadcast(QuerySessionsHandle->SearchResults);
QuerySessionsHandle.Reset();

これらのセッションのいずれかに参加するために、クライアントはJoinSessionメソッドを呼び出すだけで、上記の配列からセッションの検索結果のいずれかを渡せます。まず、セッションインターフェイスをもう一度取得し、次に参加を実行します。

const FOnJoinSessionCompleteDelegate OnJoinSessionCompleteDelegate = 
FOnJoinSessionCompleteDelegate::CreateUObject(
this, &MyClass::OnJoinSessionComplete);
FDelegateHandle JoinSessionDelegateHandle =
SessionInterface->AddOnJoinSessionCompleteDelegate_Handle(
OnJoinSessionCompleteDelegate);

// Here `PlayerId` is an FUniqueNetIdPtr for the player, and Session is
// simply an instance of FOnlineSessionSearchResult
return SessionInterface->JoinSession(
PlayerId.ToSharedRef().Get(), NAME_GameSession, Session);
注記

一般的に、参加の前に、プレイヤーがGetNamedSessionを使用して既にセッションに参加しているかどうかを確認することをお勧めします。参加していた場合、DestroySessionを呼び出し、そのメソッドのデリゲートがトリガーされたらセッションに参加します。

JoinSessionCompleteデリゲートハンドラ内で、トラベルを実行します。もう一度セッションインターフェイスを取得してから、トラベル URL を取得してクライアントの移動を実行します。

FString TravelUrl{};
// Here SessionName is a parameter from the join delegate
if (SessionInterface->GetResolvedConnectString(SessionName, TravelUrl,
NAME_GamePort) && !TravelUrl.IsEmpty())
{
// Here `PlayerController` is a pointer to an APlayerController for
// the local player
PlayerController->ClientTravel(TravelUrl, TRAVEL_Absolute);
}
注記

P2P セッションの場合、トラベル URL はaccelbyte.<host_user_id>:<port>の形式になります。この場合、解決された接続文字列を取得する呼び出しは、ローカルセッション情報からトラベル URL を生成しています。

トラブルシューティング

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

プレイヤーの参加が早すぎる

マップがロードされる前に、参加プレイヤー(ホスト以外)がサーバーに移動しようとする問題が発生することがあります。

推奨される対応

これを解決するには、FCoreUObjectDelegates::PostLoadMapWithWorldに追加されたデリゲート内に「true」などと指定されるセッション設定 (例:SETTING_JOIN_READY) を追加します。

FOnlineSessionSettings* SessionSettings = 
SessionInterface->GetSessionSettings(NAME_GameSession);
SessionSettings->Set(FName(TEXT("JOIN_READY")), TEXT("true"));

SessionInterface->UpdateSession(NAME_GameSession, *SessionSettings);

それから、参加者側で、セッションインターフェイスのUpdateReceivedデリゲートをリッスンして、参加を試みる前にそのセッション設定を探します。また、セッションブラウザでFindSessionsを使用して、このパラメータをクエリ設定に追加し、ブラウザに参加を受け入れる準備ができているセッションのみが表示されるようにすると便利です。