© historia Inc. #UE4DD
Multiplayer Online Deep Dive
- Traveling -
historia Inc.
原 龍
© historia Inc. #UE4DD
Traveling ?
 Listen Server を開始したり、Server に接続したり、
各プレイヤーの接続やレベル移動周りの話です
 今回は OnlineSubsystem の Session 等は解説しません
© historia Inc. #UE4DD
Standalone
Server Map A で Listen 開始Map A
Map X
Listen Server としてレベルを開始する → Listen 付き OpenLevel
© historia Inc. #UE4DD
Standalone
Server Map A
Client として接続リクエスト
Client として Server に接続する → ClientTravel
接続させて
Map X
© historia Inc. #UE4DD
Client
Server Map A
Map A
Client として Server に接続する → ClientTravel
いいよ
読み込むレベルを通知
© historia Inc. #UE4DD
Client
Server Map B
Map A
Server がレベル移動する → ServerTravel
移動します
移動先のレベルを通知
© historia Inc. #UE4DD
Client
Server Map B
Map B
Server がレベル移動する → ServerTravel
移動しました
© historia Inc. #UE4DD
Listen Server としてレベルを開始する
© historia Inc. #UE4DD
Standalone
Server Map A で Listen 開始Map A
Map X
Listen Server としてレベルを開始する → Listen 付き OpenLevel
© historia Inc. #UE4DD
Listen Server としてレベルを開始する
C++
/** Start Server */
UGameplayStatics::OpenLevel(GetWorld(), “LevelName", true, "listen");
© historia Inc. #UE4DD
Listen Server としてレベルを開始する
Blueprint
© historia Inc. #UE4DD
Server
UGameplayStatics::OpenLevel Listen Server 開始リクエスト
UEngine::Browse
UWorld::Listen
UEngine::CreateNamedNetDriver
UNetDriver::InitListen
Listen Server 開始
NetDriver 作成
© historia Inc. #UE4DD
Client として Server に接続する
© historia Inc. #UE4DD
Standalone
Server Map A
Client として Server に接続する → ClientTravel
接続させて
Map X Client
Server Map A
Map A
いいよ
© historia Inc. #UE4DD
Client として Server に接続する
C++
APlayerController* PlayerController =
UGameplayStatics::GetPlayerController(GetWorld(), 0);
/** Start Client */
PlayerController->ClientTravel(
“XXX.XXX.XXX.XXX”, // IP Address
ETravelType::TRAVEL_Absolute, // トラベルタイプ
false); // シームレストラベル有効フラグ
© historia Inc. #UE4DD
Client として Server に接続する
Blueprint
© historia Inc. #UE4DD
UPendingNetGame::InitNetDriver
UEngine::CreateNamedNetDriver
UNetDriver::InitConnect
APlayerController::ClientTravel Server 接続リクエスト
NetDriver 作成
UEngine::Browse
Client
接続開始
© historia Inc. #UE4DD
FNetControlMessage<NMT_Hello>::Send
UNetDriver::InitConnect 接続開始
UConnection::CreateChannel ※CHTYPE_Control
Client
Control Channel 作成
Server へ Hello メッセージ送信
© historia Inc. #UE4DD
UPendingNetGame ?
 Control Channel で Server に Hello メッセージして待っている間、
UPendingNetGame オブジェクトが Server からの返答待ち及び、
Server が Closed になっていないかどうかの監視を行う
© historia Inc. #UE4DD
Control Channel ?
 C/S 間の接続の制御に利用されるチャンネル
 UConnection 生成時に一つ生成される
© historia Inc. #UE4DD
ServerClient
Hello
ServerClient
Challenge
ServerClient
Login
ServerClient
Welcome
1 2
3 4
© historia Inc. #UE4DD
Server
UWorld::NotifyControlMessage Hello メッセージ受信
FNetworkVersion::IsNetworkCompatible
FNetControlMessage<NMT_Challenge>::Send Client へ Challenge メッセージ送信
Network Version チェック
© historia Inc. #UE4DD
Network Version ?
 C/S 間でアプリケーションの Network Version の照合を行うことができる
 Server で Hello 受信時にバージョンチェックを行い、問題があれば
Upgrade メッセージを Client に送信し、Client ではエラーとして処理する
Server
ver. 1.1
Client
ver. 1.0
Hello
Upgrade
更新して出直して来いこんにちは
© historia Inc. #UE4DD
Network Version ?
 デフォルトだとバージョン情報は下記を繋げた文字列のハッシュ値
– Game Name
– Project Version
– ENGINE_NET_VERSION
– Engine Network Protocol Version
– Game Network Protocol Version
© historia Inc. #UE4DD
Network Version を制御するには ?
 Game Network Protocol Version をアップデートに合わせて変更する
– FNetworkVersion::GameCompatibleNetworkProtocolVersion
 もしバージョン違いをある程度許容したい場合は下記をバインドして独自制御する
/** Called in GetLocalNetworkVersion if bound */
DECLARE_DELEGATE_RetVal( uint32, FGetLocalNetworkVersionOverride );
static FGetLocalNetworkVersionOverride GetLocalNetworkVersionOverride;
/** Called in IsNetworkCompatible if bound */
DECLARE_DELEGATE_RetVal_TwoParams( bool, FIsNetworkCompatibleOverride, uint32, uint32 );
static FIsNetworkCompatibleOverride IsNetworkCompatibleOverride;
FNetworkVersion
© historia Inc. #UE4DD
UPendingNetGame::NotifyControlMessage Challenge メッセージ受信
ULocalPlayer::GetPreferredUniqueNetId
FNetControlMessage<NMT_Login>::Send Server へ Login メッセージ送信
OnlineSubsystem から Net ID を取得
Client
© historia Inc. #UE4DD
Server
UWorld::NotifyControlMessage Login メッセージ受信
AGameModeBase::PreLogin
UWorld::WelcomPlayer
ログイン前処理
AGameModeBase::GameWelcomPlayer
FNetControlMessage<NMT_Welcome>::Send Client へ Welcome メッセージ
© historia Inc. #UE4DD
PreLogin でログイン許可判定
 AGameModeBase::PreLogin では ErrorMessage を返すことができる
 規定人数に達していたり、何らかの要因でログインさせたくない場合は
ErrorMessage に何らかの文字を入れることで、
Client には Control Channel から Failure メッセージが飛ぶ
ServerClient
Login
Failure
お前はダメログインしたい
© historia Inc. #UE4DD
UPendingNetGame::NotifyControlMessage Welcome メッセージ受信
Map 名を受け取る
UEngine::TickWorldTravel
UEngine::LoadMap Map 読み込み
Client
UPendingNetGame::LoadMapCompleted
FNetControlMessage<NMT_Join>::Send Server へ Join メッセージ送信
© historia Inc. #UE4DD
Server
UWorld::NotifyControlMessage Join メッセージ受信
UWorld::SpawnPlayActor PlayerController をスポーン
AGameModeBase::Login
AGameModeBase::PostLogin
ログイン受け入れ
© historia Inc. #UE4DD
ここまでの内容をまとめると
© historia Inc. #UE4DD
• AGameModeBase
• UNetDriver
• UNetDriver• UNetDriver
Client 1
Server
Client 2
• UNetConnection
• UControlChannel
Server / Client
• UNetConnection
• UControlChannel
Server / Client
© historia Inc. #UE4DD
Server がレベル移動する
© historia Inc. #UE4DD
Client
Server Map B
Map A
Server がレベル移動する → ServerTravel
移動します
Client
Server Map B
Map B
移動しました
© historia Inc. #UE4DD
Server がレベル移動する
C++
/** Start ServerTravel */
GetWorld()->ServerTravel(“LevelName”, false);
© historia Inc. #UE4DD
Server がレベル移動する
Blueprint
© historia Inc. #UE4DD
Server
UWorld::ServerTravel ServerTravel 開始
AGameModeBase::CanServerTravel
AGameModeBase::ProcessServerTravel
ServerTravel 可否判定
AGameModeBase::ProcessClientTravel
NextURL 設定
(後に UEngine::Browse でレベル移動する)
APlayerController::ClientTravel
各 Client で ClientTravel を実行
(Run on Owning Client & Reliable)
© historia Inc. #UE4DD
APlayerController::ClientTravel Server 接続リクエスト
Client
以下、前述した ClientTravel の流れと同じ
Control Channel を介してログイン処理を行う
© historia Inc. #UE4DD
つまり、ServerTravel でレベル移動を行うと、
移動する度に Server へのログイン処理が実行される
© historia Inc. #UE4DD
接続を維持したままレベル移動を行いたい場合は?
→ SeamlessTravel を利用する
© historia Inc. #UE4DD
SeamlessTravel ?
 レベルをストリーミングで読み込み、Transition Map を経由しながら GameMode
等の Actor を引き継いだままレベル遷移する事で、オーバーヘッドを小さくできる
 非 Seamless な ServerTravel と違い、Client との接続は保持したまま
BeforeMap AfterMapTransition Map
© historia Inc. #UE4DD
SeamlessTravel を有効にする
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=GameMode)
uint32 bUseSeamlessTravel : 1;
AGameModeBase
© historia Inc. #UE4DD
Transition Map ?
 ワールドを保持したままレベル遷移するため、古いレベルがオンメモリのまま
新しいレベルが読み込まれる
 つまり瞬間的に二つのレベルが共存するため、メモリに優しくない
 そのため小さな Transition Map を間に挟むことで、古いレベルを解放してから
新しいレベルのロードが始まるように処理されている
© historia Inc. #UE4DD
Transition Map を設定する
© historia Inc. #UE4DD
Server
AGameModeBase::ProcessServerTravel
UWorld::SeamlessTravel
NextURL は 設定しない
(UEngine::Browse されない)
FSeamlessTravelHander::StartTravel SeamlessTravel 開始
FSeamlessTravelHander::LoadPackageAsync レベルストリーミング開始
© historia Inc. #UE4DD
FSeamlessTravelHander ?
 SeamlessTravel 時のシーケンス管理用オブジェクト
 TransitionMap を LoadAsync して完了待ちを行い、完了したら古いレベルを
PendingKill してから CollectGarbage する
 TransitionMap への移行が完了したら、新しいレベルへの移行シーケンスを開始する
© historia Inc. #UE4DD
Server
Client
SeamlessTravel
SeamlessTravel
ServerTravel
- PreClientTravel
ClientTravel
- PreClientTravel
Client / Reliable Server / Reliable
ServerNotifyLoadedWorld
NotifyLoadedWorld
PostSeamlessTravel
NotifyLoadedWorld
© historia Inc. #UE4DD
Server
Client
SeamlessTravel
SeamlessTravel
ServerTravel
- PreClientTravel
ClientTravel
- PreClientTravel
ServerNotifyLoadedWorld
NotifyLoadedWorld
PostSeamlessTravel
NotifyLoadedWorld
開始 / 終了のトリガー
Client / Reliable Server / Reliable
© historia Inc. #UE4DD
SeamlessTravel 時に引き継がれるアクターは?
 [Server] GameMode / GameState
 [Server] 有効な PlayerState を持つ全ての Controller
 [Server] 全ての PlayerController
 [Server / Client] 各 Server / Client が所持する PlayerController
© historia Inc. #UE4DD
ゲーム都合で引き継ぐアクターを追加したい場合は?
 下記関数をオーバーライドして ActorList に追加する
– AGameModeBase
 GetSeamlessTravelActorList(bool bToTransition, TArray<AActor*>& ActorList)
– APlayerController
 GetSeamlessTravelActorList(bool bToEntry, TArray<class AActor*>& ActorList)
© historia Inc. #UE4DD
と、ドキュメントには記載があり、大体合ってるが…
© historia Inc. #UE4DD
SpawnPlayerController
新規に PlayerController を
スポーンして Swap している
© historia Inc. #UE4DD
PlayerController で引き継がれるプロパティは?
 Location, Rotation
 保持する PlayerState の全プロパティ(コピーされる)
 RemoteRole 等、Online 系のプロパティ
© historia Inc. #UE4DD
ゲーム都合で引き継ぐプロパティを追加したい場合は?
/** Called when a PlayerController is swapped to a new one during seamless travel */
UFUNCTION(BlueprintImplementableEvent, Category=Game, meta=(DisplayName="OnSwapPlayerControllers"))
void K2_OnSwapPlayerControllers(APlayerController* OldPC, APlayerController* NewPC);
AGameModeBase
イベント呼び出し時に
必要なものをコピーする
© historia Inc. #UE4DD
OnSwapPlayerControllers の注意点
 PlayerController が Local or Remote で Swap タイミングが異なる
– Local PlayerController は Swap -> BeginPlay の順番
– Remote PlayerController は BeginPlay -> Swap の順番
 Swap が呼び出されるのは Server のみ
© historia Inc. #UE4DD
SeamlessTravel をデバッグする
© historia Inc. #UE4DD
SeamlessTravel をデバッグする時の注意点
 PIE は現状だと非サポート
 デバッグするためには Standalone で起動する必要がある
– イテレーション速度の低下
– そもそもエディタからは複数プロセスで Standalone 起動はできない
 game オプション付きで起動するバッチファイルを作るのがオススメ
© historia Inc. #UE4DD
Visual Studio でデバッグする
 エディタもしくはバッチファイルから Standalone 起動した場合、
Visual Studio でデバッグしたいなら Attach to Process するしかない
 デバッグする度に、検索窓も無いプロセス一覧から特定のプロセスを探して
アタッチして…、というのは非常に面倒
© historia Inc. #UE4DD
UnrealVS を使ってコマンドラインに渡す引数を追加する
[ProjectName] [起動したいMap] –game [その他オプション]
と設定して Start Debugging すると、デバッグしながら起動できる
実行したコマンドラインオプションは履歴が残り、プルダウンで設定できるので便利
© historia Inc. #UE4DD
UnrealVS で楽にはなるが、それでも PIE 非対応は辛い…
// NOTE - This is a temp check while we work on a long term fix
// There are a few issues with seamless travel using single process PIE, so
we're disabling that for now while working on a fix
AGameModeBase::CanServerTravel
SeamlessTravel + PIE は現状だといくつかのバグを抱えていて、
将来的にこれは解決される見込みとのことなので、今後に期待
© historia Inc. #UE4DD
まとめ
 Server としてレベル移動する時、Client として Server に接続する
初回のレベル移動はブロッキングが発生する
 C/S 間接続のキモは UControlChannel で、メッセージタイプも多くないので
何がサポートされているのかを最初に眺めてみると良い
 SeamlessTravel はデバッグが辛いので早期改善を希望
© historia Inc. #UE4DD
まとめ
 色々困ったら下記クラスの実装を追うと良い
– UWorld
– AGameModeBase
– APlayerController
– UNetConnection
– UControlChannel
– FSeamlessTravelHandler
© historia Inc. #UE4DD
ご清聴ありがとうございました
historia Inc.
原 龍

UE4 MultiPlayer Online Deep Dive 基礎編2 -Traveling- (historia様ご講演) #ue4dd

  • 1.
    © historia Inc.#UE4DD Multiplayer Online Deep Dive - Traveling - historia Inc. 原 龍
  • 2.
    © historia Inc.#UE4DD Traveling ?  Listen Server を開始したり、Server に接続したり、 各プレイヤーの接続やレベル移動周りの話です  今回は OnlineSubsystem の Session 等は解説しません
  • 3.
    © historia Inc.#UE4DD Standalone Server Map A で Listen 開始Map A Map X Listen Server としてレベルを開始する → Listen 付き OpenLevel
  • 4.
    © historia Inc.#UE4DD Standalone Server Map A Client として接続リクエスト Client として Server に接続する → ClientTravel 接続させて Map X
  • 5.
    © historia Inc.#UE4DD Client Server Map A Map A Client として Server に接続する → ClientTravel いいよ 読み込むレベルを通知
  • 6.
    © historia Inc.#UE4DD Client Server Map B Map A Server がレベル移動する → ServerTravel 移動します 移動先のレベルを通知
  • 7.
    © historia Inc.#UE4DD Client Server Map B Map B Server がレベル移動する → ServerTravel 移動しました
  • 8.
    © historia Inc.#UE4DD Listen Server としてレベルを開始する
  • 9.
    © historia Inc.#UE4DD Standalone Server Map A で Listen 開始Map A Map X Listen Server としてレベルを開始する → Listen 付き OpenLevel
  • 10.
    © historia Inc.#UE4DD Listen Server としてレベルを開始する C++ /** Start Server */ UGameplayStatics::OpenLevel(GetWorld(), “LevelName", true, "listen");
  • 11.
    © historia Inc.#UE4DD Listen Server としてレベルを開始する Blueprint
  • 12.
    © historia Inc.#UE4DD Server UGameplayStatics::OpenLevel Listen Server 開始リクエスト UEngine::Browse UWorld::Listen UEngine::CreateNamedNetDriver UNetDriver::InitListen Listen Server 開始 NetDriver 作成
  • 13.
    © historia Inc.#UE4DD Client として Server に接続する
  • 14.
    © historia Inc.#UE4DD Standalone Server Map A Client として Server に接続する → ClientTravel 接続させて Map X Client Server Map A Map A いいよ
  • 15.
    © historia Inc.#UE4DD Client として Server に接続する C++ APlayerController* PlayerController = UGameplayStatics::GetPlayerController(GetWorld(), 0); /** Start Client */ PlayerController->ClientTravel( “XXX.XXX.XXX.XXX”, // IP Address ETravelType::TRAVEL_Absolute, // トラベルタイプ false); // シームレストラベル有効フラグ
  • 16.
    © historia Inc.#UE4DD Client として Server に接続する Blueprint
  • 17.
    © historia Inc.#UE4DD UPendingNetGame::InitNetDriver UEngine::CreateNamedNetDriver UNetDriver::InitConnect APlayerController::ClientTravel Server 接続リクエスト NetDriver 作成 UEngine::Browse Client 接続開始
  • 18.
    © historia Inc.#UE4DD FNetControlMessage<NMT_Hello>::Send UNetDriver::InitConnect 接続開始 UConnection::CreateChannel ※CHTYPE_Control Client Control Channel 作成 Server へ Hello メッセージ送信
  • 19.
    © historia Inc.#UE4DD UPendingNetGame ?  Control Channel で Server に Hello メッセージして待っている間、 UPendingNetGame オブジェクトが Server からの返答待ち及び、 Server が Closed になっていないかどうかの監視を行う
  • 20.
    © historia Inc.#UE4DD Control Channel ?  C/S 間の接続の制御に利用されるチャンネル  UConnection 生成時に一つ生成される
  • 21.
    © historia Inc.#UE4DD ServerClient Hello ServerClient Challenge ServerClient Login ServerClient Welcome 1 2 3 4
  • 22.
    © historia Inc.#UE4DD Server UWorld::NotifyControlMessage Hello メッセージ受信 FNetworkVersion::IsNetworkCompatible FNetControlMessage<NMT_Challenge>::Send Client へ Challenge メッセージ送信 Network Version チェック
  • 23.
    © historia Inc.#UE4DD Network Version ?  C/S 間でアプリケーションの Network Version の照合を行うことができる  Server で Hello 受信時にバージョンチェックを行い、問題があれば Upgrade メッセージを Client に送信し、Client ではエラーとして処理する Server ver. 1.1 Client ver. 1.0 Hello Upgrade 更新して出直して来いこんにちは
  • 24.
    © historia Inc.#UE4DD Network Version ?  デフォルトだとバージョン情報は下記を繋げた文字列のハッシュ値 – Game Name – Project Version – ENGINE_NET_VERSION – Engine Network Protocol Version – Game Network Protocol Version
  • 25.
    © historia Inc.#UE4DD Network Version を制御するには ?  Game Network Protocol Version をアップデートに合わせて変更する – FNetworkVersion::GameCompatibleNetworkProtocolVersion  もしバージョン違いをある程度許容したい場合は下記をバインドして独自制御する /** Called in GetLocalNetworkVersion if bound */ DECLARE_DELEGATE_RetVal( uint32, FGetLocalNetworkVersionOverride ); static FGetLocalNetworkVersionOverride GetLocalNetworkVersionOverride; /** Called in IsNetworkCompatible if bound */ DECLARE_DELEGATE_RetVal_TwoParams( bool, FIsNetworkCompatibleOverride, uint32, uint32 ); static FIsNetworkCompatibleOverride IsNetworkCompatibleOverride; FNetworkVersion
  • 26.
    © historia Inc.#UE4DD UPendingNetGame::NotifyControlMessage Challenge メッセージ受信 ULocalPlayer::GetPreferredUniqueNetId FNetControlMessage<NMT_Login>::Send Server へ Login メッセージ送信 OnlineSubsystem から Net ID を取得 Client
  • 27.
    © historia Inc.#UE4DD Server UWorld::NotifyControlMessage Login メッセージ受信 AGameModeBase::PreLogin UWorld::WelcomPlayer ログイン前処理 AGameModeBase::GameWelcomPlayer FNetControlMessage<NMT_Welcome>::Send Client へ Welcome メッセージ
  • 28.
    © historia Inc.#UE4DD PreLogin でログイン許可判定  AGameModeBase::PreLogin では ErrorMessage を返すことができる  規定人数に達していたり、何らかの要因でログインさせたくない場合は ErrorMessage に何らかの文字を入れることで、 Client には Control Channel から Failure メッセージが飛ぶ ServerClient Login Failure お前はダメログインしたい
  • 29.
    © historia Inc.#UE4DD UPendingNetGame::NotifyControlMessage Welcome メッセージ受信 Map 名を受け取る UEngine::TickWorldTravel UEngine::LoadMap Map 読み込み Client UPendingNetGame::LoadMapCompleted FNetControlMessage<NMT_Join>::Send Server へ Join メッセージ送信
  • 30.
    © historia Inc.#UE4DD Server UWorld::NotifyControlMessage Join メッセージ受信 UWorld::SpawnPlayActor PlayerController をスポーン AGameModeBase::Login AGameModeBase::PostLogin ログイン受け入れ
  • 31.
    © historia Inc.#UE4DD ここまでの内容をまとめると
  • 32.
    © historia Inc.#UE4DD • AGameModeBase • UNetDriver • UNetDriver• UNetDriver Client 1 Server Client 2 • UNetConnection • UControlChannel Server / Client • UNetConnection • UControlChannel Server / Client
  • 33.
    © historia Inc.#UE4DD Server がレベル移動する
  • 34.
    © historia Inc.#UE4DD Client Server Map B Map A Server がレベル移動する → ServerTravel 移動します Client Server Map B Map B 移動しました
  • 35.
    © historia Inc.#UE4DD Server がレベル移動する C++ /** Start ServerTravel */ GetWorld()->ServerTravel(“LevelName”, false);
  • 36.
    © historia Inc.#UE4DD Server がレベル移動する Blueprint
  • 37.
    © historia Inc.#UE4DD Server UWorld::ServerTravel ServerTravel 開始 AGameModeBase::CanServerTravel AGameModeBase::ProcessServerTravel ServerTravel 可否判定 AGameModeBase::ProcessClientTravel NextURL 設定 (後に UEngine::Browse でレベル移動する) APlayerController::ClientTravel 各 Client で ClientTravel を実行 (Run on Owning Client & Reliable)
  • 38.
    © historia Inc.#UE4DD APlayerController::ClientTravel Server 接続リクエスト Client 以下、前述した ClientTravel の流れと同じ Control Channel を介してログイン処理を行う
  • 39.
    © historia Inc.#UE4DD つまり、ServerTravel でレベル移動を行うと、 移動する度に Server へのログイン処理が実行される
  • 40.
    © historia Inc.#UE4DD 接続を維持したままレベル移動を行いたい場合は? → SeamlessTravel を利用する
  • 41.
    © historia Inc.#UE4DD SeamlessTravel ?  レベルをストリーミングで読み込み、Transition Map を経由しながら GameMode 等の Actor を引き継いだままレベル遷移する事で、オーバーヘッドを小さくできる  非 Seamless な ServerTravel と違い、Client との接続は保持したまま BeforeMap AfterMapTransition Map
  • 42.
    © historia Inc.#UE4DD SeamlessTravel を有効にする public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=GameMode) uint32 bUseSeamlessTravel : 1; AGameModeBase
  • 43.
    © historia Inc.#UE4DD Transition Map ?  ワールドを保持したままレベル遷移するため、古いレベルがオンメモリのまま 新しいレベルが読み込まれる  つまり瞬間的に二つのレベルが共存するため、メモリに優しくない  そのため小さな Transition Map を間に挟むことで、古いレベルを解放してから 新しいレベルのロードが始まるように処理されている
  • 44.
    © historia Inc.#UE4DD Transition Map を設定する
  • 45.
    © historia Inc.#UE4DD Server AGameModeBase::ProcessServerTravel UWorld::SeamlessTravel NextURL は 設定しない (UEngine::Browse されない) FSeamlessTravelHander::StartTravel SeamlessTravel 開始 FSeamlessTravelHander::LoadPackageAsync レベルストリーミング開始
  • 46.
    © historia Inc.#UE4DD FSeamlessTravelHander ?  SeamlessTravel 時のシーケンス管理用オブジェクト  TransitionMap を LoadAsync して完了待ちを行い、完了したら古いレベルを PendingKill してから CollectGarbage する  TransitionMap への移行が完了したら、新しいレベルへの移行シーケンスを開始する
  • 47.
    © historia Inc.#UE4DD Server Client SeamlessTravel SeamlessTravel ServerTravel - PreClientTravel ClientTravel - PreClientTravel Client / Reliable Server / Reliable ServerNotifyLoadedWorld NotifyLoadedWorld PostSeamlessTravel NotifyLoadedWorld
  • 48.
    © historia Inc.#UE4DD Server Client SeamlessTravel SeamlessTravel ServerTravel - PreClientTravel ClientTravel - PreClientTravel ServerNotifyLoadedWorld NotifyLoadedWorld PostSeamlessTravel NotifyLoadedWorld 開始 / 終了のトリガー Client / Reliable Server / Reliable
  • 49.
    © historia Inc.#UE4DD SeamlessTravel 時に引き継がれるアクターは?  [Server] GameMode / GameState  [Server] 有効な PlayerState を持つ全ての Controller  [Server] 全ての PlayerController  [Server / Client] 各 Server / Client が所持する PlayerController
  • 50.
    © historia Inc.#UE4DD ゲーム都合で引き継ぐアクターを追加したい場合は?  下記関数をオーバーライドして ActorList に追加する – AGameModeBase  GetSeamlessTravelActorList(bool bToTransition, TArray<AActor*>& ActorList) – APlayerController  GetSeamlessTravelActorList(bool bToEntry, TArray<class AActor*>& ActorList)
  • 51.
    © historia Inc.#UE4DD と、ドキュメントには記載があり、大体合ってるが…
  • 52.
    © historia Inc.#UE4DD SpawnPlayerController 新規に PlayerController を スポーンして Swap している
  • 53.
    © historia Inc.#UE4DD PlayerController で引き継がれるプロパティは?  Location, Rotation  保持する PlayerState の全プロパティ(コピーされる)  RemoteRole 等、Online 系のプロパティ
  • 54.
    © historia Inc.#UE4DD ゲーム都合で引き継ぐプロパティを追加したい場合は? /** Called when a PlayerController is swapped to a new one during seamless travel */ UFUNCTION(BlueprintImplementableEvent, Category=Game, meta=(DisplayName="OnSwapPlayerControllers")) void K2_OnSwapPlayerControllers(APlayerController* OldPC, APlayerController* NewPC); AGameModeBase イベント呼び出し時に 必要なものをコピーする
  • 55.
    © historia Inc.#UE4DD OnSwapPlayerControllers の注意点  PlayerController が Local or Remote で Swap タイミングが異なる – Local PlayerController は Swap -> BeginPlay の順番 – Remote PlayerController は BeginPlay -> Swap の順番  Swap が呼び出されるのは Server のみ
  • 56.
    © historia Inc.#UE4DD SeamlessTravel をデバッグする
  • 57.
    © historia Inc.#UE4DD SeamlessTravel をデバッグする時の注意点  PIE は現状だと非サポート  デバッグするためには Standalone で起動する必要がある – イテレーション速度の低下 – そもそもエディタからは複数プロセスで Standalone 起動はできない  game オプション付きで起動するバッチファイルを作るのがオススメ
  • 58.
    © historia Inc.#UE4DD Visual Studio でデバッグする  エディタもしくはバッチファイルから Standalone 起動した場合、 Visual Studio でデバッグしたいなら Attach to Process するしかない  デバッグする度に、検索窓も無いプロセス一覧から特定のプロセスを探して アタッチして…、というのは非常に面倒
  • 59.
    © historia Inc.#UE4DD UnrealVS を使ってコマンドラインに渡す引数を追加する [ProjectName] [起動したいMap] –game [その他オプション] と設定して Start Debugging すると、デバッグしながら起動できる 実行したコマンドラインオプションは履歴が残り、プルダウンで設定できるので便利
  • 60.
    © historia Inc.#UE4DD UnrealVS で楽にはなるが、それでも PIE 非対応は辛い… // NOTE - This is a temp check while we work on a long term fix // There are a few issues with seamless travel using single process PIE, so we're disabling that for now while working on a fix AGameModeBase::CanServerTravel SeamlessTravel + PIE は現状だといくつかのバグを抱えていて、 将来的にこれは解決される見込みとのことなので、今後に期待
  • 61.
    © historia Inc.#UE4DD まとめ  Server としてレベル移動する時、Client として Server に接続する 初回のレベル移動はブロッキングが発生する  C/S 間接続のキモは UControlChannel で、メッセージタイプも多くないので 何がサポートされているのかを最初に眺めてみると良い  SeamlessTravel はデバッグが辛いので早期改善を希望
  • 62.
    © historia Inc.#UE4DD まとめ  色々困ったら下記クラスの実装を追うと良い – UWorld – AGameModeBase – APlayerController – UNetConnection – UControlChannel – FSeamlessTravelHandler
  • 63.
    © historia Inc.#UE4DD ご清聴ありがとうございました historia Inc. 原 龍