Upload
-epic-games-japan
View
2.135
Download
13
Embed Size (px)
Citation preview
© 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 AddressETravelType::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 ではエラーとして処理する
Serverver. 1.1
Clientver. 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.
原 龍