63
© historia Inc. #UE4DD Multiplayer Online Deep Dive - Traveling - historia Inc.

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

Embed Size (px)

Citation preview

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

© historia Inc. #UE4DD

Multiplayer Online Deep Dive

- Traveling -

historia Inc.

原 龍

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

© historia Inc. #UE4DD

Traveling ?

Listen Server を開始したり、Server に接続したり、

各プレイヤーの接続やレベル移動周りの話です

今回は OnlineSubsystem の Session 等は解説しません

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

© historia Inc. #UE4DD

Standalone

Server Map A で Listen 開始Map A

Map X

Listen Server としてレベルを開始する → Listen 付き OpenLevel

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

© historia Inc. #UE4DD

Standalone

Server Map A

Client として接続リクエスト

Client として Server に接続する → ClientTravel

接続させて

Map X

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

© historia Inc. #UE4DD

Client

Server Map A

Map A

Client として Server に接続する → ClientTravel

いいよ

読み込むレベルを通知

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

© historia Inc. #UE4DD

Client

Server Map B

Map A

Server がレベル移動する → ServerTravel

移動します

移動先のレベルを通知

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

© historia Inc. #UE4DD

Client

Server Map B

Map B

Server がレベル移動する → ServerTravel

移動しました

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

© historia Inc. #UE4DD

Listen Server としてレベルを開始する

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

© historia Inc. #UE4DD

Standalone

Server Map A で Listen 開始Map A

Map X

Listen Server としてレベルを開始する → Listen 付き OpenLevel

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

© historia Inc. #UE4DD

Listen Server としてレベルを開始する

C++

/** Start Server */UGameplayStatics::OpenLevel(GetWorld(), “LevelName", true, "listen");

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

© historia Inc. #UE4DD

Listen Server としてレベルを開始する

Blueprint

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

© historia Inc. #UE4DD

Server

UGameplayStatics::OpenLevel Listen Server 開始リクエスト

UEngine::Browse

UWorld::Listen

UEngine::CreateNamedNetDriver

UNetDriver::InitListen

Listen Server 開始

NetDriver 作成

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

© historia Inc. #UE4DD

Client として Server に接続する

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

© historia Inc. #UE4DD

Standalone

Server Map A

Client として Server に接続する → ClientTravel

接続させて

Map X Client

Server Map A

Map A

いいよ

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

© historia Inc. #UE4DD

Client として Server に接続する

C++

APlayerController* PlayerController = UGameplayStatics::GetPlayerController(GetWorld(), 0);

/** Start Client */PlayerController->ClientTravel(

“XXX.XXX.XXX.XXX”, // IP AddressETravelType::TRAVEL_Absolute, // トラベルタイプfalse); // シームレストラベル有効フラグ

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

© historia Inc. #UE4DD

Client として Server に接続する

Blueprint

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

© historia Inc. #UE4DD

UPendingNetGame::InitNetDriver

UEngine::CreateNamedNetDriver

UNetDriver::InitConnect

APlayerController::ClientTravel Server 接続リクエスト

NetDriver 作成

UEngine::Browse

Client

接続開始

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

© historia Inc. #UE4DD

FNetControlMessage<NMT_Hello>::Send

UNetDriver::InitConnect 接続開始

UConnection::CreateChannel ※CHTYPE_Control

Client

Control Channel 作成

Server へ Hello メッセージ送信

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

© historia Inc. #UE4DD

UPendingNetGame ?

Control Channel で Server に Hello メッセージして待っている間、

UPendingNetGame オブジェクトが Server からの返答待ち及び、

Server が Closed になっていないかどうかの監視を行う

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

© historia Inc. #UE4DD

Control Channel ?

C/S 間の接続の制御に利用されるチャンネル

UConnection 生成時に一つ生成される

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

© historia Inc. #UE4DD

ServerClient

Hello

ServerClient

Challenge

ServerClient

Login

ServerClient

Welcome

1 2

3 4

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

© historia Inc. #UE4DD

Server

UWorld::NotifyControlMessage Hello メッセージ受信

FNetworkVersion::IsNetworkCompatible

FNetControlMessage<NMT_Challenge>::Send Client へ Challenge メッセージ送信

Network Version チェック

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

© historia Inc. #UE4DD

Network Version ?

C/S 間でアプリケーションの Network Version の照合を行うことができる

Server で Hello 受信時にバージョンチェックを行い、問題があれば

Upgrade メッセージを Client に送信し、Client ではエラーとして処理する

Serverver. 1.1

Clientver. 1.0

Hello

Upgrade

更新して出直して来いこんにちは

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

© historia Inc. #UE4DD

Network Version ?

デフォルトだとバージョン情報は下記を繋げた文字列のハッシュ値

– Game Name

– Project Version

– ENGINE_NET_VERSION

– Engine Network Protocol Version

– Game Network Protocol Version

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

© 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

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

© historia Inc. #UE4DD

UPendingNetGame::NotifyControlMessage Challenge メッセージ受信

ULocalPlayer::GetPreferredUniqueNetId

FNetControlMessage<NMT_Login>::Send Server へ Login メッセージ送信

OnlineSubsystem から Net ID を取得

Client

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

© historia Inc. #UE4DD

Server

UWorld::NotifyControlMessage Login メッセージ受信

AGameModeBase::PreLogin

UWorld::WelcomPlayer

ログイン前処理

AGameModeBase::GameWelcomPlayer

FNetControlMessage<NMT_Welcome>::Send Client へ Welcome メッセージ

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

© historia Inc. #UE4DD

PreLogin でログイン許可判定

AGameModeBase::PreLogin では ErrorMessage を返すことができる

規定人数に達していたり、何らかの要因でログインさせたくない場合は

ErrorMessage に何らかの文字を入れることで、

Client には Control Channel から Failure メッセージが飛ぶ

ServerClient

Login

Failure

お前はダメログインしたい

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

© historia Inc. #UE4DD

UPendingNetGame::NotifyControlMessage Welcome メッセージ受信

Map 名を受け取る

UEngine::TickWorldTravel

UEngine::LoadMap Map 読み込み

Client

UPendingNetGame::LoadMapCompleted

FNetControlMessage<NMT_Join>::Send Server へ Join メッセージ送信

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

© historia Inc. #UE4DD

Server

UWorld::NotifyControlMessage Join メッセージ受信

UWorld::SpawnPlayActor PlayerController をスポーン

AGameModeBase::Login

AGameModeBase::PostLogin

ログイン受け入れ

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

© historia Inc. #UE4DD

ここまでの内容をまとめると

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

© historia Inc. #UE4DD

• AGameModeBase

• UNetDriver

• UNetDriver• UNetDriver

Client 1

Server

Client 2

• UNetConnection

• UControlChannel

Server / Client

• UNetConnection

• UControlChannel

Server / Client

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

© historia Inc. #UE4DD

Server がレベル移動する

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

© historia Inc. #UE4DD

Client

Server Map B

Map A

Server がレベル移動する → ServerTravel

移動します

Client

Server Map B

Map B

移動しました

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

© historia Inc. #UE4DD

Server がレベル移動する

C++

/** Start ServerTravel */GetWorld()->ServerTravel(“LevelName”, false);

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

© historia Inc. #UE4DD

Server がレベル移動する

Blueprint

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

© 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)

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

© historia Inc. #UE4DD

APlayerController::ClientTravel Server 接続リクエスト

Client

以下、前述した ClientTravel の流れと同じ

Control Channel を介してログイン処理を行う

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

© historia Inc. #UE4DD

つまり、ServerTravel でレベル移動を行うと、

移動する度に Server へのログイン処理が実行される

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

© historia Inc. #UE4DD

接続を維持したままレベル移動を行いたい場合は?

→ SeamlessTravel を利用する

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

© historia Inc. #UE4DD

SeamlessTravel ?

レベルをストリーミングで読み込み、Transition Map を経由しながら GameMode

等の Actor を引き継いだままレベル遷移する事で、オーバーヘッドを小さくできる

非 Seamless な ServerTravel と違い、Client との接続は保持したまま

BeforeMap AfterMapTransition Map

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

© historia Inc. #UE4DD

SeamlessTravel を有効にする

public:UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=GameMode)uint32 bUseSeamlessTravel : 1;

AGameModeBase

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

© historia Inc. #UE4DD

Transition Map ?

ワールドを保持したままレベル遷移するため、古いレベルがオンメモリのまま

新しいレベルが読み込まれる

つまり瞬間的に二つのレベルが共存するため、メモリに優しくない

そのため小さな Transition Map を間に挟むことで、古いレベルを解放してから

新しいレベルのロードが始まるように処理されている

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

© historia Inc. #UE4DD

Transition Map を設定する

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

© historia Inc. #UE4DD

Server

AGameModeBase::ProcessServerTravel

UWorld::SeamlessTravel

NextURL は 設定しない

(UEngine::Browse されない)

FSeamlessTravelHander::StartTravel SeamlessTravel 開始

FSeamlessTravelHander::LoadPackageAsync レベルストリーミング開始

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

© historia Inc. #UE4DD

FSeamlessTravelHander ?

SeamlessTravel 時のシーケンス管理用オブジェクト

TransitionMap を LoadAsync して完了待ちを行い、完了したら古いレベルを

PendingKill してから CollectGarbage する

TransitionMap への移行が完了したら、新しいレベルへの移行シーケンスを開始する

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

© historia Inc. #UE4DD

Server

Client

SeamlessTravel

SeamlessTravel

ServerTravel

- PreClientTravel

ClientTravel

- PreClientTravel

Client / Reliable Server / Reliable

ServerNotifyLoadedWorld

NotifyLoadedWorld

PostSeamlessTravel

NotifyLoadedWorld

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

© historia Inc. #UE4DD

Server

Client

SeamlessTravel

SeamlessTravel

ServerTravel

- PreClientTravel

ClientTravel

- PreClientTravel

ServerNotifyLoadedWorld

NotifyLoadedWorld

PostSeamlessTravel

NotifyLoadedWorld

開始 / 終了のトリガー

Client / Reliable Server / Reliable

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

© historia Inc. #UE4DD

SeamlessTravel 時に引き継がれるアクターは?

[Server] GameMode / GameState

[Server] 有効な PlayerState を持つ全ての Controller

[Server] 全ての PlayerController

[Server / Client] 各 Server / Client が所持する PlayerController

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

© historia Inc. #UE4DD

ゲーム都合で引き継ぐアクターを追加したい場合は?

下記関数をオーバーライドして ActorList に追加する

– AGameModeBase

GetSeamlessTravelActorList(bool bToTransition, TArray<AActor*>& ActorList)

– APlayerController

GetSeamlessTravelActorList(bool bToEntry, TArray<class AActor*>& ActorList)

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

© historia Inc. #UE4DD

と、ドキュメントには記載があり、大体合ってるが…

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

© historia Inc. #UE4DD

SpawnPlayerController

新規に PlayerController を

スポーンして Swap している

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

© historia Inc. #UE4DD

PlayerController で引き継がれるプロパティは?

Location, Rotation

保持する PlayerState の全プロパティ(コピーされる)

RemoteRole 等、Online 系のプロパティ

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

© 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

イベント呼び出し時に

必要なものをコピーする

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

© historia Inc. #UE4DD

OnSwapPlayerControllers の注意点

PlayerController が Local or Remote で Swap タイミングが異なる

– Local PlayerController は Swap -> BeginPlay の順番

– Remote PlayerController は BeginPlay -> Swap の順番

Swap が呼び出されるのは Server のみ

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

© historia Inc. #UE4DD

SeamlessTravel をデバッグする

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

© historia Inc. #UE4DD

SeamlessTravel をデバッグする時の注意点

PIE は現状だと非サポート

デバッグするためには Standalone で起動する必要がある

– イテレーション速度の低下

– そもそもエディタからは複数プロセスで Standalone 起動はできない

game オプション付きで起動するバッチファイルを作るのがオススメ

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

© historia Inc. #UE4DD

Visual Studio でデバッグする

エディタもしくはバッチファイルから Standalone 起動した場合、

Visual Studio でデバッグしたいなら Attach to Process するしかない

デバッグする度に、検索窓も無いプロセス一覧から特定のプロセスを探して

アタッチして…、というのは非常に面倒

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

© historia Inc. #UE4DD

UnrealVS を使ってコマンドラインに渡す引数を追加する

[ProjectName] [起動したいMap] –game [その他オプション]

と設定して Start Debugging すると、デバッグしながら起動できる

実行したコマンドラインオプションは履歴が残り、プルダウンで設定できるので便利

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

© 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 は現状だといくつかのバグを抱えていて、

将来的にこれは解決される見込みとのことなので、今後に期待

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

© historia Inc. #UE4DD

まとめ

Server としてレベル移動する時、Client として Server に接続する

初回のレベル移動はブロッキングが発生する

C/S 間接続のキモは UControlChannel で、メッセージタイプも多くないので

何がサポートされているのかを最初に眺めてみると良い

SeamlessTravel はデバッグが辛いので早期改善を希望

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

© historia Inc. #UE4DD

まとめ

色々困ったら下記クラスの実装を追うと良い

– UWorld

– AGameModeBase

– APlayerController

– UNetConnection

– UControlChannel

– FSeamlessTravelHandler

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

© historia Inc. #UE4DD

ご清聴ありがとうございました

historia Inc.

原 龍