287.3K Views
September 30, 19
スライド概要
2019年9月6日に行われた「CEDEC2019」で登壇した際に使用した資料です。
Unreal Engineを開発・提供しているエピック ゲームズ ジャパンによる公式アカウントです。 勉強会や配信などで行った講演資料を公開しています。 公式サイトはこちら https://www.unrealengine.com/ja/
UE4でマルチプレイゲームをつくろう Epic Games Japan Support Engineer Takashi Suzuki V1.0 Sep 2019
自己紹介 エピックゲームズジャパン サポートエンジニア 鈴木孝司 2019年6月から現職 アーケード向け、家庭用、VR向けなどいろいろなゲームを 作ってきました UnrealEngineは無料化直後から触っています #UE4 | @UNREALENGINE
マルチプレイヤーゲーム 楽しんでますか? #UE4 | @UNREALENGINE
昨今は様々なマルチプレイ対応ゲームが リリースされ、 老若男女地域を問わず楽しまれています #UE4 | @UNREALENGINE
Fortniteも 絶賛サービス中です #UE4 | @UNREALENGINE
eSportsにとっても マルチプレイは 重要な要素です #UE4 | @UNREALENGINE
マルチプレイは楽しい #UE4 | @UNREALENGINE
UE4を使えば ある程度エンジンが 面倒を見てくれます #UE4 | @UNREALENGINE
実際に作ってみると #UE4 | @UNREALENGINE
一人用ゲームでは起きない様々な問題が ローカルでは動いたのに、いざマルチで実際に動かしたら上手く動かない こっちではドアが開いてるのに、あっちでは開いてない ラグい!!! このタイミングで接続/切断されるとバグる どこまでテストすればいいの? 再生されるモーションが違うんですが・・・ #UE4 | @UNREALENGINE
ソロゲームのX倍 テストや実装コストが かかります #UE4 | @UNREALENGINE
ネットワーク通信帯域は 有限です #UE4 | @UNREALENGINE
トラブルや疑問が あったときの技術情報も 見つけにくい気がします #UE4 | @UNREALENGINE
正しい情報、問題点、 セオリーがわかれば かなり負担を軽減できます #UE4 | @UNREALENGINE
本講演の目標 #UE4 | @UNREALENGINE
みなさまが 楽しいマルチプレイゲームを もっと楽しく 作ってもらえるようにする #UE4 | @UNREALENGINE
学習用リソース 機能ウォークスルー お品書き UE4で マルチプレイゲームを作ろう #UE4 | @UNREALENGINE 動作検証方法 ネット処理の流れと単語帳 CharacterMovement ReplicationGraph
学習用リソース 機能ウォークスルー お品書き UE4で マルチプレイゲームを作ろう #UE4 | @UNREALENGINE 動作検証方法 ネット処理の流れと単語帳 CharacterMovement ReplicationGraph
学習用リソース UE4にはエンジンに組み込まれた マルチプレイヤー用の機能が あります。 マルチプレイ可能なテンプレートプ ロジェクトやサンプルプロジェクト でそれらについてを学習することが できます。 #UE4 | @UNREALENGINE
はじめに ちょっとだけボリュームが多くなってしまったので、 発展的なトピックや詳細に関してはざっと流して進みます スライドはCEDILやSlideShareなどで公開いたしますので、公開後に目を通して 頂けると幸いです スライド中にこのような暗い色の文章がありますが、 公開スライドは明るく調整したものを用意します 中辛 #UE4 | @UNREALENGINE 辛口 激辛
実際触れるサンプル紹介 #UE4 | @UNREALENGINE
ThirdPersonテンプレート #UE4 | @UNREALENGINE
Vehicle Advanced テンプレート Net PktLag=200を設定した状態 #UE4 | @UNREALENGINE
他のテンプレートも マルチプレイ対応のものが 多いです #UE4 | @UNREALENGINE
機能別サンプル ( Contents Example ) #UE4 | @UNREALENGINE
#UE4 | @UNREALENGINE
ShooterGame #UE4 | @UNREALENGINE
ドキュメント ⚫ UE4公式ドキュメント ⚫ https://docs.unrealengine.com/jp/index.html ⚫ http://cedric-neukirchen.net/Downloads/Compendium/UE4_Network_Compendium_by_Cedric_eXi_Neukirchen.pdf ⚫ ⚫ https://wiki.unrealengine.com/index.php?title=Main_Page ⚫ 'Unreal Engine 4' Network Compendium ⚫ EpicWiki ⚫ ⚫ DedicatedServerGuide ⚫ https://wiki.unrealengine.com/index.php?title=Dedicated_Server_Guide_(Windows_%26_Linux) 他多数 ⚫ https://www.slideshare.net/EpicGamesJapan/online-multiplay-game-design SlideShare #UE4 | @UNREALENGINE
学習用リソース 機能ウォークスルー お品書き UE4で マルチプレイゲームを作ろう #UE4 | @UNREALENGINE 動作検証方法 ネット処理の流れと単語帳 CharacterMovement ReplicationGraph
機能 ウォークスルー #UE4 | @UNREALENGINE UE4にはどんな機能が組み込 まれているか見てみましょう
エンジンに統合された通信機能 アクターやブループリントといった エンジンの基本的なしくみは すべてネットワークに対応しています 特殊な処理を除き、大半を ブループリントを用いて ネットワーク対応のタイトルを 開発することができます #UE4 | @UNREALENGINE
サーバークライアントモデル UE4が提供するネットワークの構造はサーバークライアントモデルです サーバー権限を持ったプロセスは一つです #UE4 | @UNREALENGINE
大まかに 二つの実現方法があります #UE4 | @UNREALENGINE
兼業サーバー - ListenServer #UE4 | @UNREALENGINE
兼業サーバー - ListenServer プレイヤーの誰かがサーバーを兼ねる方法 コンソールゲームでよく利用されます ⚫ メリット ⚫ サーバーの維持費がかからない ⚫ ⚫ ⚫ ⚫ サーバー役のCPU/通信負荷が高く、通信品質が求められる サーバー役とクライアントで有利不利の差がどうしても出てしまう サーバー役がいなくなると解散になってしまう NAT問題(いわゆるルーター越え問題) ⚫ デメリット #UE4 | @UNREALENGINE
専業サーバー - DedicatedServer #UE4 | @UNREALENGINE
専業サーバー - DedicatedServer 余計なものを削ぎ落した専用サーバーを、コンピューターに配置して実行します 製品版ではデータセンターに配置されます プレイヤーはすべてクライアントとして接続されます ⚫ メリット ⚫ ⚫ ⚫ ⚫ グラフィックスやサウンドなどの処理を省けるので負荷が低い NATの問題が無く、通信障害などが無い限り接続に成功する プレイヤー間の優劣が無い データセンターへの経路はよく調整されており通信品質が期待できる ⚫ 運用コストがかかる ⚫ デメリット #UE4 | @UNREALENGINE
OnlineSubsystem プラットフォームが提供するマッチングやリーダーボードなどの機能を 抽象化して制御できるようにする仕組みです。 #UE4 | @UNREALENGINE
リプレイ UE4が提供するリプレイ機能はマルチプレイでやりとりされている パケットデータをストレージに記録して、後でそれを再生する仕組みです。 #UE4 | @UNREALENGINE
NetworkProfiler [InstallFolder]¥Engine¥Binaries¥DotNET¥NetworkProfiler.exe #UE4 | @UNREALENGINE
NetworkProfilerでキャプチャする ConsoleCommand netprofileでON/OFFを切り替える netprofile CommandLineOption MyProjServer.exe -networkprofiler=true -log #UE4 | @UNREALENGINE
エンジンが提供する 枠組みとしては こんな感じです #UE4 | @UNREALENGINE
DedicatedServerの 話が出たのでちょっと脇道 #UE4 | @UNREALENGINE
DedicatedServerのホスティング Dedicatedサーバーを検討する時はサーバー数をユーザーの要求に合わせて 自動で増減させること(オートスケーリング)を検討してください 弊社Fortniteも社内開発のオートスケーリングシステムをもちいて サーバーをクラウド上で管理運営しています #UE4 | @UNREALENGINE
オートスケーリングソリューション #UE4 | @UNREALENGINE
DedicatedServerの運用コストTIPS 一つのVMインスタンス上にCPUやメモリ、ネットワーク帯域/パケット数が許す 限り複数のサーバープロセスを起動させる事が可能です CPUの使用率とパケット数はサーバーのフレームレートに 大きく影響を受けます。 クライアントとサーバーのフレームレートは一致している必要は無いのでゲーム に影響が無い範囲でフレームレートを絞るとコスト的に有利です。 Engine.ini NetServerMaxTickRate=30 60FPSクライアント 20FPSサーバー 30FPSクライアント #UE4 | @UNREALENGINE
DedicatedServerの作り方 RunUATやBuildGraphなどを使ってビルドすることができます ビルドの前にサーバー用のターゲットスクリプトを確認してください UATを使う場合は以下の様に serverオプションとサーバー用の設定を渡します RunUAT BuildCookRun -project=W:/workspace/MyProj/MyProj.uproject -noP4 -ue4exe=UE4Editor-Cmd.exe -targetplatform=Win64 -clientconfig=Development -noclient -serverplatform=Win64 -serverconfig=Development+Shipping -server -compile -build -cook -compressed -stage -package -pak -nocompileeditor -utf8output 参考ページ→ #UE4 | @UNREALENGINE https://wiki.unrealengine.com/Dedicated_Server_Guide_(Windows_%26_Linux)
【参考】 Epic Online Service (EOS) #UE4 | @UNREALENGINE
Epic Online Service Unreal Engine とは別にエピックゲームズが提供している ゲームサーバーサービス ● 特徴 ● 一般的にプラットフォーム向けのSDKが提供している、マッチング、ユーザー管理、分析、 ランキングなどのサービスをプラットフォームに依存しない形(クロスプラットフォーム)で 提供し、無料で利用できます ● 現在提供されている機能はまだ一部で、鋭意開発中です ● オープンソースソフトウェアではありません ● このサービスを利用するに当たって、UE4を使う必要はありません 他のゲームエンジンやミドルウェアを使用しないタイトルでも問題無く利用可能です ● サーバーは弊社が管理しており、この利用料も発生しません ● DedicatedServerのホスティングは含まれません ● 詳しくはEOSのポータルをご覧ください ● https://dev.epicgames.com/ja/services #UE4 | @UNREALENGINE
学習用リソース 機能ウォークスルー お品書き UE4で マルチプレイゲームを作ろう #UE4 | @UNREALENGINE 動作検証方法 ネット処理の流れと単語帳 CharacterMovement ReplicationGraph
ThirdPersonTemplateで 動作検証方法 #UE4 | @UNREALENGINE 新規プロジェクトを 作った場合を見てみます
#UE4 | @UNREALENGINE
かんたん! #UE4 | @UNREALENGINE
Play In Editor (PIE) エディタ上でメモリに読み込まれているアセットを 利用できるので、素早くマルチプレイでのレベルを 確認するのに有効です。 エディタのプロセス上で指定した分のプレイヤー (+DedicatedServer)のワールドを複数生成し 直列に処理します。 ※UseSingleProcess : ON 時 #UE4 | @UNREALENGINE
New Editor Window 実行の注意点 ⚫ シームレストラベルは無視されます ⚫ ウィンドウを閉じるとすべてのセッションが終わります ⚫ Statsファイルやカウンタがすべてのクライアント分まとまってしまいます #UE4 | @UNREALENGINE
シームレストラベルの 動作確認 ※「シームレストラベル」とは通信を維持したまま スムーズにレベルを遷移するUE4の仕組みです #UE4 | @UNREALENGINE
#UE4 | @UNREALENGINE
SeamlessTravelはPIE非対応 #UE4 | @UNREALENGINE
大丈夫! 確認方法があります! Use Single Process : OFF #UE4 | @UNREALENGINE
#UE4 | @UNREALENGINE
Use Single Process OFF 一つのクライアントをPIEで起動し、残りをStandaloneで起動します PIEで起動する一つをクライアントして立ち上げるかサーバーとして立ち上げるか を選択するのがEditorMultiplayerModeです。 PIEで起動しているクライアントはブループリントのデバッグが可能です #UE4 | @UNREALENGINE
任意タイミングの ログイン検証 #UE4 | @UNREALENGINE
#UE4 | @UNREALENGINE
Auto Connect To Server OFF NewEditorWindow では、 指定したプレイヤー数分、ネットワーク非接続の状態 でクライアントが起動します。以下の手順でログインのテストが可能です。 1.サーバーになるウィンドウで?listen オプション付きでレベル移動 open ?listen または open ThirdPersonExample?listen 2.クライアントウィンドウで open 127.0.0.1 と入力しサーバーに接続 open 127.0.0.1 #UE4 | @UNREALENGINE
Standalone起動 #UE4 | @UNREALENGINE
Standalone起動 注意点! EditorMultiplayerModeが 「Play Offline」だと強制シングルプレイ になってしまいます UseSingleProcessのチェックを外して Play Offline以外に変更してください #UE4 | @UNREALENGINE
Standalone起動でのマルチプレイ確認 複数のプロセスを立ち上げてパッケージビルドに近い形でテストが可能です SeamlessTravelなども確認可能です AutoConnectServerオプションやUseDedicatedServerなどにも対応しています サーバーのポートはAdvancedOption内で指定したものが使われるので (デフォルトで 17777)、任意の接続を試したい場合は Open 127.0.01:17777 などでポートを指定して接続します 欠点としては開発PCのメモリやCPUのリソースを大量に消費することと、 それに関連して起動が遅いことです。 #UE4 | @UNREALENGINE
学習用リソース 機能ウォークスルー お品書き UE4で マルチプレイゲームを作ろう #UE4 | @UNREALENGINE 動作検証方法 ネット処理の流れと単語帳 CharacterMovement ReplicationGraph
ネット処理の流れと 用語集 #UE4 | @UNREALENGINE
まず1Tickの中で ネットワークがどう処理され ているのか見てみます #UE4 | @UNREALENGINE
Tickのながれ 受信して配達 インターネット ゲームの更新! 情報を集める #UE4 | @UNREALENGINE 送信!
文字で起こしてみる 1. UWorld::Tick 1. UNetworkDriver::TickDispatch 1. Packet受信 > Bunchに分解 1. BunchをActorChannelに流して、プロパティをレプリケート+RPCの実行 2. PostReceivedBunch > RepNotifyを処理 2. タスクグラフのループ 1. RPCの呼び出し (ServerMoveなど) 3. UNetworkDriver::TickFlush 1. BuildConsiderList 考慮するべきNetActorのリストを作る 2. Connection毎のループ 1. PrioritizeActors 2. ProcessePrioritizedActors 1. ActorChannel毎にプロパティの差分を抽出してBunchを書き出す 3. Connection毎のループ - UNetConnection::Tick 1. UNetConnection::FlushNet() こちらもお勧め https://docs.unrealengine.com/ja/Gameplay/Networking/Actors/ReplicationFlow/index.html #UE4 | @UNREALENGINE
はじめましての 単語が多くて辛い! #UE4 | @UNREALENGINE
単語解説 ・・・というわけで マルチプレイヤーゲームを作成する 上で遭遇する謎の単語達をすこし掘 り込んで解説していきます 各単語の意味を理解することでより 適切な設計を行えるようになります #UE4 | @UNREALENGINE Actor編 NetworkDriver編
単語解説 Actor編 NetworkDriver編 #UE4 | @UNREALENGINE
Actor #UE4 | @UNREALENGINE
Actor UE4の基本的なオブジェクト レプリケーション(状態の複製)は このActor単位で行われます これらのうちbReplicateフラグが 立っているものがエンジンによって 複製の対象として処理されます #UE4 | @UNREALENGINE
レプリケートフラグ ONで サーバーからクライアントに アクターが複製されます #UE4 | @UNREALENGINE
双方向には 同期されていないことに注意 #UE4 | @UNREALENGINE
#UE4 | @UNREALENGINE
bReplicatesフラグの動的切り替え レプリケーションのフラグは 実行中に切り替える事が可能です ● False -> True に切り替えた場合 ● リストに登録されて、クライアント上に複製されていなかった アクターがクライアント上に登場します ● True -> False に切り替えた場合 ● リストから削除されてレプリケート対象から除外され CPU負荷と帯域負荷を軽減できます ● 生成されてしまったアクターチャンネルはそのまま維持されます ● 一度複製されたクライアント上のキャラクターは消えません! ● アクターが破壊された時にレプリケーションフラグが落ちていたとしても ActorChannelの破壊に連動してクライアント上でもアクターは破壊されます #UE4 | @UNREALENGINE
Server Client サーバー クライアント 3秒ごとにフラグ切り替え 15秒後に破壊 TimeはGetGameTImeSinceCreationの値 #UE4 | @UNREALENGINE
アクターを削除するときは サーバー上で消せばOK #UE4 | @UNREALENGINE
Role #UE4 | @UNREALENGINE
役割は大雑把に3種類 #UE4 | @UNREALENGINE
Authority(権利者) 超えらい 会社でいうと社長 サーバー上に居て いろんな事を 言ってくる これはイメージです(強調) #UE4 | @UNREALENGINE
AutonomousProxy(自立代理人) ちょっと裁量権がある 会社でいうと係長 社長にすこし モノ言うことができる グレイマン係長 #UE4 | @UNREALENGINE
SimulateProxy(したっぱ) 裁量権が無く 社長の言う通り動く 会社でいうと社員 社長に直接なにかを 進言することはできない 写真はイメージです #UE4 | @UNREALENGINE
サーバー クライアント displayall Pawn Role #UE4 | @UNREALENGINE
サーバー クライアント displayall Pawn Role #UE4 | @UNREALENGINE
PlayerController &Pawn Replicateが設定されて いるActor Replicateが設定されて いない静的なアクター Replicateナシ ローカルで生成 #UE4 | @UNREALENGINE ローカルか否か Server Client Role Authority AutonomousProxy RemoteRole AutonomousProxy Authority Role Authority SimulateProxy RemoteRole SimulateProxy Authority Role Authority None RemoteRole None Authority Role Authority Authority RemoteRole None None
サーバーにバレずに 作ったアクターは クライアントのもの #UE4 | @UNREALENGINE
NetDormancy 休眠状態 #UE4 | @UNREALENGINE
用がない場合は休む #UE4 | @UNREALENGINE
3分 #UE4 | @UNREALENGINE 3分
3分 3分 プロパティが変更されると、 変更情報がクライアントに送信されます 変更がないときは・・・? #UE4 | @UNREALENGINE
要 チ ェ ッ ク や !! 3分 3分 変化していないのに関わらず、 変更がないことを何回も何回もチェックされています #UE4 | @UNREALENGINE
3分 休眠中 #UE4 | @UNREALENGINE 3分 休眠中
休眠状態 NetDormant/NetDormancy サーバー上でAActror::SetNetDormancyなどを利用して休眠状態を設定し、 レプリケーション処理のチェック対象から除外し負荷を軽減する最適化用の機能 実際に休眠状態に入るためには、レプリケートするべきプロパティが無い状態を 作る必要があります。 #UE4 | @UNREALENGINE
休眠状態 NetDormancy 一度休眠状態に入ったアクターはFlushNetDormancy()が呼ばれると 眠りから覚めます この関数ははプロパティの変更などによってエンジンから呼び出されます つまり休眠状態はある程度自動で動作します 一定時間変更が加わらない可能性があるアクターは休眠状態への移行を要求する ことでレプリケーションの処理時間を軽減することができます。 プロパティの変化が激しいアクターに適用すると状態移行チェックの負荷が加わ ってしまうだけになります #UE4 | @UNREALENGINE
休眠状態の設定値 備考 DORM_Never DORM_Awakeと同等 DORM_Awake(Default) 休眠状態なら復帰し休眠状態に入らない。 DORM_DormantAll 休眠状態へのチェックを行い条件を満たせば休眠状態に移行する DORM_DormantPartial Connection毎に挙動を切り替えることができる模様 AActor::GetNetDormancyの実装が必要 DORM_Initial 初期状態でNetActorListから除外され休眠状態に入る FlushNetDormancyが呼ばれるとDORM_DormantAllに移行する #UE4 | @UNREALENGINE
ほとんど変化が無いアクター はDormantAll さらにレベル配置物は Initialがお勧め #UE4 | @UNREALENGINE
NetRelevancy 関係性 #UE4 | @UNREALENGINE
興味がないものは 省いて省エネする #UE4 | @UNREALENGINE
関連性 NetRelevancy サーバー上でConnection毎に距離などを考慮して そのアクターをレプリケートするべきか判断する仕組み。 レプリケーション処理の中では、アクターが列挙されて優先順位別にならんだあ と、実際にプロパティを調べる直前にAActor::IsNetRelevantForを通じてチェッ クされます。 NetActor リスト生成 #UE4 | @UNREALENGINE 優先順位 ソート 関連性チェック 変更差分の取得と 送信
距離カリングとAlwaysRelevant AActor::IsNetRelevantFor()では 距離ベースのカリングが行われます そのパラメータがNetCullDistancSquaredです 225,000,000 cm^2 = 15,000 cm = 150m この距離カリングなどすべて無効にして常にカリ ングされないようにするプロパティが AlwaysRelevantです。 #UE4 | @UNREALENGINE
NetPriority 通信優先度 #UE4 | @UNREALENGINE
限られたパイプに なにを優先して流すか #UE4 | @UNREALENGINE
NetPriority レプリケートされる優先順位を決めるパラメータ 値が高いほど処理列の先頭側にソートされ、 相対的に高頻度でレプリケートされます 実際にソートに使われる値は NetPriority値 × (前回送信時からの経過時間+向きや距離などの係数) 「特定の条件時は、今回のTickの中でパケットに乗るようにしたい」というよう な要求に答える場合は、後述のForceNetUpdateに加えて、NetPriorityを変更す るかAActor::GetNetPriorityをオーバーライドして実現することが可能です #UE4 | @UNREALENGINE
送信! 次のTickに持ち越し Frame 1 Pawn P:4 t:1 = 4 Pawn P:4 t:1 = 4 A P:1 t:4 = 4 B P:1 t:3 = 3 C P:1 t:2 = 2 C P:1 t:1 = 1 Frame 2 Pawn P:4 t:1 = 4 Pawn P:4 t:1 = 4 B P:1 t:4 = 4 C P:1 t:3 = 3 C P:1 t:2 = 2 A P:1 t:1 = 1 Frame 3 Pawn P:4 t:1 = 4 Pawn P:4 t:1 = 4 C P:1 t:4 = 4 C P:1 t:3 = 3 A P:1 t:2 = 2 B P:1 t:1 = 1 Frame 4 Pawn P:4 t:1 = 4 Pawn P:4 t:1 = 4 C P:1 t:4 = 4 A P:1 t:3 = 3 B P:1 t:2 = 2 C P:1 t:1 = 1 #UE4 | @UNREALENGINE
NetUpdateFrequency 送信チェック頻度 #UE4 | @UNREALENGINE
遅れても良いものは 毎Tick送らなくてよいです #UE4 | @UNREALENGINE
サーバー クライアント #UE4 | @UNREALENGINE
NetUpdateFrequency アクターのレプリケーション頻度 単位は 「回/s」 です 一度アクターのレプリケーションが行われると、このパラメータの逆数時間、 レプリケーション考慮リストから除外されます 素早い反応が不要なアクターはこの頻度を下げることで CPUおよび帯域幅を削減可能です 混乱しやすいのですが、AActor::ForceNetUpdateは このインターバル時間をリセットする関数です。 #UE4 | @UNREALENGINE
Min Net Update Frequency とは MinNetUpdateFrequencyは「AdaptiveNetUpdateFrequency」が 有効なときだけ使われるパラメータです この機能はデフォルトでOFFです これは実際にレプリケートされた間隔の 実績値に合わせて、 Min~とNetUpdateFrequencyの間で パラメータを自動調節する機能です #UE4 | @UNREALENGINE
NetLoadOnClient #UE4 | @UNREALENGINE
レベルに 配置されているものを クライアント上で 作るかどうか #UE4 | @UNREALENGINE
NetLoadOnClient レベルに含まれるアクターのうち、クライアント上でアクターをワールドに生成 するかどうかを示すフラグ クライアント上に居てほしくない時にfalseにします 代表的なものはGameModeです NetLoadOnClient bReplicates AGameMode false false ANavigationData false false APlayerState false true AGameState false true #UE4 | @UNREALENGINE クライアント上では生まれない レベル初期化時にクライアント上から削 除され、サーバーからのレプリケーショ ンで複製される
Actor編まとめ ⚫ Actorにはネットワーク上での振る舞いを設定したり、パフォーマンスを調 整するための設定があります ⚫ 重要なのは複製設定を立てることでサーバーからクライアントにアクターが 複製されるということです #UE4 | @UNREALENGINE
単語解説 Actor編 NetworkDriver編 #UE4 | @UNREALENGINE
ここからNetworkDriverと その中身の解説します #UE4 | @UNREALENGINE
NetworkDriver #UE4 | @UNREALENGINE
アンリアル島 #UE4 | @UNREALENGINE
アンリアル島 #UE4 | @UNREALENGINE
アンリアル島 #UE4 | @UNREALENGINE
NetworkDriver ネットワーク処理の大元です。 マルチプレイが要求されると生成されてWorldに紐づけられます クライアントとサーバーの両方がそれぞれNetworkDriverを持ちます #UE4 | @UNREALENGINE
NetConnection #UE4 | @UNREALENGINE
サーバー NetworkDriver NetConnection NetConnection NetConnection NetConnection NetConnection NetConnection NetworkDriver NetworkDriver NetworkDriver クライアントA クライアントB クライアントC #UE4 | @UNREALENGINE
NetConnection NetworkDriverとNetworkDriverをつなぐ経路です クライアントは一つ、サーバーには接続しているプレイヤー数分作られます #UE4 | @UNREALENGINE
PlayerController #UE4 | @UNREALENGINE
リッスンサーバー NetConnection NetConnection NetConnection LocalPlayer NetConnection NetConnection NetConnection クライアントA クライアントB クライアントC #UE4 | @UNREALENGINE
APlayerController サーバーにログインしたときに作られます プロパティとしてPlayerというメンバ変数に NetworkConnectionが設定されて1対1でつながります displayall PlayerController Player #UE4 | @UNREALENGINE
PlayerController Advanced ServerRPCやClientRPCが特定の対象だけに届くのは、 有効なNetConnectionをPlayerプロパティを持っているかどうかです PawnはPlayerControllerに所持(Possess)されている場合のみ所持元の PlayerControllerがもつNetConnectionを使えます ( APawn::GetNetConnection & APlayerController::GetNetConnection 参照 ) #UE4 | @UNREALENGINE
PlayerController RPC GetNetConnection RPC Pawn PlayerController GetNetConnection GetNetConnection NetConnection NetConnection Actor RPC GetNetConnection #UE4 | @UNREALENGINE 送信されない!
NetworkObjectList #UE4 | @UNREALENGINE
アンリアル島 #UE4 | @UNREALENGINE
NetworkObjectList NetworkDriverの中にあるネットワークでやりとりしたいアクターのリスト NetworkObjectInfoはその要素の型。 前述の通信頻度(NetUpdateFrequency)の計算に用いる変数を持っています NetConnection毎にはもっていない事に注意してください #UE4 | @UNREALENGINE
UActorChannel ChannelIndex FNetworkGUID #UE4 | @UNREALENGINE
NetConnection 35番 8番 10番 #UE4 | @UNREALENGINE 35番 8番 10番
35番 35番 8番 8番 ChannelIndex 10番 #UE4 | @UNREALENGINE ActorChannel 10番
ChannelIndexは ActorChannelの 配列番号 #UE4 | @UNREALENGINE
ActorChannelとChannelIndex ActorChannelは複製対象のアクター1つに付き1つ割り当てられる経路 ChannelIndexは静的に確保されているチャンネル配列中の配列番号 通信先のアクターと、この配列番号で紐づけています net.MaxChannelSize 32768 #UE4 | @UNREALENGINE
35番 35番 8番 8番 FNetworkGUID 10番 #UE4 | @UNREALENGINE 10番
FNetworkGUID 32ビット整数のID。これを使ってプロセス間のオブジェクトを紐づけます レベルに配置されているような静的なものは奇数、 動的なものは偶数が割り当てられます サーバー側で初めてプロパティとして扱う必要が出たときにObjectに対して割り 当てられます 複製対象のActorに限らずに、通信内容に含まれるすべてオブジェクトが 対象になります。(例えばプレイヤーが立っている床など) net.ListNetGUIDsでどのアクターが登録されているか確認することができます #UE4 | @UNREALENGINE
Blueprintで見てみます #UE4 | @UNREALENGINE
#UE4 | @UNREALENGINE
#UE4 | @UNREALENGINE
動かしてみると・・・ Server: PlayerCameraManager1 Client 1: Server: ThirdPersonCharacter Client 1: ThirdPersonCharacter1 Server: Linear_Stair_StaticMesh Client 1: Linear_Stair_StaticMesh Server: Wall11 Client 1: Wall11 Server: LeftArm_StaticMesh Client 1: LeftArm_StaticMesh Server: PlayerState1 Client 1: PlayerState Server: GameNetworkManager Client 1: Server: AbstractNavData-1 Client 1: Server: WorldInfo Client 1: WorldInfo #UE4 | @UNREALENGINE 送り先のワールドに 存在しないアクターは NULLになる
Bunch 束 #UE4 | @UNREALENGINE
パケット #UE4 | @UNREALENGINE
Bunch UE4のレプリケーション処理から出力されたデータの単位 基本的に1ReplicatedActor=1Bunch 一つのパケットに複数のBunchが格納されています 各Bunchには前述のChannelIndexが格納されていて、 然るべきアクターに届けられます ( UNetConnection::ReceivedPacket 参照) ネットワークに送信されるパケットには複数のBunchが含まれます #UE4 | @UNREALENGINE
受信応答 ACK/NAK #UE4 | @UNREALENGINE
受信返答OK/NG - ACK / NAK ACK - ACKnowledgement NAK - Negative-AcKnowledgement ネットワーク処理の中での一般的な単語で UE4の専門用語ではありません パケットが受信されたかどうかを表します ビット列の形でパケットのヘッダに書き込まれていて、重要なパケットのやり取 りが行われたかどうかの確認や、Reliableなやり取りの再送信などに利用される ます #UE4 | @UNREALENGINE
変数の複製 と 遠隔関数呼び出し #UE4 | @UNREALENGINE
#UE4 | @UNREALENGINE
遠隔関数呼び出し( RPC ) #UE4 | @UNREALENGINE
Multicast 「うまく動かないからRPC」 は後で困りがちです #UE4 | @UNREALENGINE
まず変数の複製で 出来ないか熟慮しましょう #UE4 | @UNREALENGINE
こういうものはRPC向け ⚫ RPCは「イベント」です ⚫ 10秒後に無くてもいいもの ⚫ 回数が重要なもの ⚫ ⚫ 音声 VFX生成 #UE4 | @UNREALENGINE
ReliableRPC 関数呼び出しの直後にいきなり、パケットのバッファに乗ります その分、他の情報が乗るスペースが減るので注意してください 非ReliableRPCは呼び出しが間引かれる可能性がありますが、 ReliableRPCは呼び出し回数分かならず処理されます 相手からのNak返答によりパケットを再送します Reliableであったとしても距離などでActorChannelが開いていない場合、 RPCは送信されません #UE4 | @UNREALENGINE
RPC RPC RPC レプ #UE4 | @UNREALENGINE RPC レプ レプ レプ レプ
RPC 残り RPC RPC RPC #UE4 | @UNREALENGINE レプ レプ レプ レプ レプ
RPC レプ レプ RPC RPC RPC #UE4 | @UNREALENGINE レプ レプ レプ
変数の複製 PropertyReplication #UE4 | @UNREALENGINE
「変数の複製」は裏切らない #UE4 | @UNREALENGINE
こういうものは変数の複製向け ⚫ アクターの状態を表す変数 ⚫ 途中参加したときに復元しないと困るプロパティ ⚫ 10秒後に失われては困るもの ⚫ ⚫ ⚫ ライフ 所持アイテム キャラクターの見た目 #UE4 | @UNREALENGINE
変数の書き換えは慎重に //アクセサを経由して変数を操作するのをオススメします Void ASampleActor::SetReplicatedVariable( float InValue ) { check( HasAuthority() ); //不正な操作が起きないように ReplicatedValue = InValue; } //またはAutonomousProxyからは自動でServerRPCを飛ばすなど Void ASampleActor::SetReplicatedVariable( float InValue ) { if( HasAuthority() ) { ReplicatedValue = InValue; return; } check( Role == ROLE_AutonomousProxy ); //Simulate や None の場合サーバーRPCは送信できない ServerSetReplicatedVariable( InValue ); //ServerRPC } #UE4 | @UNREALENGINE
Driver編まとめ ● Stat netを実行した時に表示されるよう なパラメータがドライバーの中で制御さ れている ● NetworkDriverがレベルに紐づくことに よってマルチプレイが実現されている #UE4 | @UNREALENGINE
学習用リソース 機能ウォークスルー お品書き UE4で マルチプレイゲームを作ろう #UE4 | @UNREALENGINE 動作検証方法 ネット処理の流れと単語帳 CharacterMovement ReplicationGraph
キャラクター ムーブメント #UE4 | @UNREALENGINE 一人用ならうまく移動できる のにマルチにすると 挙動がおかしい・・・ なにが起きているのか見てみ ましょう
サーバー #UE4 | @UNREALENGINE クライアント
ガクガクしすぎて 気分が悪くなってきました #UE4 | @UNREALENGINE
クライアントで アクターの移動 移動情報を元に サーバー上で実際に 移動してみる 移動結果の座標が クライアントが送って 来た座標と全然違う! 移動情報 うそつき! 移動情報を収集して サーバーに送る うわ・・・ サーバーめっちゃ 怒ってる! 座標を戻す アクターの移動 #UE4 | @UNREALENGINE
サーバー上でも 「移動」します! #UE4 | @UNREALENGINE
移動情報の送信 void ServerMove( float TimeStamp, FVector_NetQuantize10 InAccel, //量子化された加速度 精度は 1mm/s^2 FVector_NetQuantize100 ClientLoc, //量子化された位置 精度は 0.1mm uint8 CompressedMoveFlags, //移動フラグ ジャンプ上昇中とか uint8 ClientRoll, //オイラー表現 ControlRotationのRoll uint32 View, //オイラー表現 ControlRotationのYawとPitch UPrimitiveComponent* ClientMovementBase,//どのプリミティブ上に立っているか FName ClientBaseBoneName, //MovementBaseのどのBoneに立っているか uint8 ClientMovementMode //クライアント上でのMovementMode ); #UE4 | @UNREALENGINE
移動情報の送信 void ServerMove( クライアント上のワールド時間 float TimeStamp, FVector_NetQuantize10 InAccel, //量子化された加速度 精度は 1mm/s^2 FVector_NetQuantize100 ClientLoc, //量子化された位置 精度は 0.1mm 加速ベクトル uint8 CompressedMoveFlags, //移動フラグ ジャンプ上昇中とか uint8 ClientRoll, //オイラー表現 ControlRotationのRoll uint32 View, //オイラー表現 ControlRotationのYawとPitch UPrimitiveComponent* ClientMovementBase,//どのプリミティブ上に立っているか ボタン入力など FName ClientBaseBoneName, //MovementBaseのどのBoneに立っているか uint8 ClientMovementMode //クライアント上でのMovementMode ); カメラの向き #UE4 | @UNREALENGINE
移動情報の送信 void ServerMove( float TimeStamp, 位置(不正移動チェック用) FVector_NetQuantize10 InAccel, //量子化された加速度 精度は 1mm/s^2 FVector_NetQuantize100 ClientLoc, //量子化された位置 精度は 0.1mm uint8 CompressedMoveFlags, //移動フラグ ジャンプ上昇中とか 地面(不正移動チェック用) uint8 ClientRoll, //オイラー表現 ControlRotationのRoll uint32 View, //オイラー表現 ControlRotationのYawとPitch UPrimitiveComponent* ClientMovementBase,//どのプリミティブ上に立っているか FName ClientBaseBoneName, //MovementBaseのどのBoneに立っているか uint8 ClientMovementMode //クライアント上でのMovementMode 地面の関節名(不正移動チェック用) ); 移動モード(不正移動チェック用) #UE4 | @UNREALENGINE
加速度と 操作用カメラ角度から 移動を復元せざるを得ない #UE4 | @UNREALENGINE
パラメータの解説 #UE4 | @UNREALENGINE
MoveFlag 移動に影響を与えるプレイヤーのボタン入力をビットであらわしたもの エンジンはFLAG_JumpPressedおよびFLAG_WantsToCrouchに加えて 2ビットの計4bitを予約しています FLAG_Custom_0~3はタイトルで利用可能です 拡張は以下の関数をオーバーライドして行います FSavedMove_Character::GetCompressedFlags() エンコード処理 void UCharacterMovementComponent::UpdateFromCompressedFlags() デコードおよびにキャラクターへのフラグの適用 #UE4 | @UNREALENGINE
MoveFlag 例えばShooterGameではダッシュと構え移動が実装されていますが、 MoveFlagは使わずにServerRPCによるステート変更を行っています 大きな移動を伴わない場合、RPCによる実装でも許容範囲のエラーにとどまる可 能性があります まずRPCで実装して、大きな位置エラーがでるようならMoveFlagを検討するのが 良いかもしれません MoveFlagは複雑ですがネットワーク上の特殊な移動にまつわる問題を ラグを感じさせずにスマートに解決できる可能性があります 詳しくはDocs.Unrealengineの「キャラクターの移動コンポーネント」の 最後のセクションを参照してください https://docs.unrealengine.com/ja/Gameplay/Networking/CharacterMovementComponent/index.html #UE4 | @UNREALENGINE
MovementMode エンジンの組み込みで「歩いている」、「落下している」など、複数のステート があります StartNewPhysicsやGetMaxSpeed関数の内部で分岐し様々な運動を再現します SetMovementModeで切り替えることができますが、Authorityの無いプロセス 上で書き換えてもサーバーには自動反映されません さらにMovementModeの差はサーバーからズレと認識されて怒られるので 正しく処理するのをオススメします CustomMovementModeを用いて拡張が可能です #UE4 | @UNREALENGINE
移動速度の書き換え 同様の理由で移動速度の書き換えも 同期エラーを生み出しがちです たとえば歩く方向によって速度を変えたい というような実装をしたい場合、 ServerRPCを毎Tick呼び出すのは 現実的ではないので、 UCharacterMovementComponent::GetMaxSpeedをオーバーライドし、 加速度とカメラから速度を計算して返すようにするのをお勧めします #UE4 | @UNREALENGINE
ClientCorrection調査 p.NetShowCorrections 1 を入力すると移動速度やコリジョンの差などに よって補正が発生した場合に 図のようなデバッグ表示を行うことができます またCharacterMovementComponent.cppには これらの調整を助けるための CVarがいくつか定義されているので 見てみてください #UE4 | @UNREALENGINE
ClientAuthorativePosition Iniファイルで設定します サーバーでの移動後クライアントエラーが無かった時に、 ServerMoveで送られてきた位置やMovementなどをサーバー上に適用します これによって細かい誤差の蓄積を無効化し、 補正問題を解決できる可能性があります。 #UE4 | @UNREALENGINE
Networkに関係したログやini https://www.slideshare.net/EpicGamesJapan/online-multiplay-game-design #UE4 | @UNREALENGINE
学習用リソース 機能ウォークスルー お品書き UE4で マルチプレイゲームを作ろう #UE4 | @UNREALENGINE 動作検証方法 ネット処理の流れと単語帳 CharacterMovement ReplicationGraph
ReplicationGraph UE4.20で登場 UE4.23でもまだBETAバージョン #UE4 | @UNREALENGINE
Unreal Engine Tech-blog https://www.unrealengine.com/ja/tech-blog/replication-graph-overview-and-proper-replication-methods?lang=ja #UE4 | @UNREALENGINE
3つのコンセプト #UE4 | @UNREALENGINE
1.毎回毎回、一から名簿を 作るのはやめよう #UE4 | @UNREALENGINE
2.グリッド分割済みリスト を作る #UE4 | @UNREALENGINE
3.NetworkDriverの レプリケーション処理を カスタマイズしやすいように 切り出す #UE4 | @UNREALENGINE
サンプルを用意しました #UE4 | @UNREALENGINE
サンプル概要 50000個の2m四方キューブを動的に生成 横100個x奥500個 200m * 1000m Developmentビルド Editorからスタンドアローン、 リッスンサーバー+5クライアント で起動 ( xeon gold 6128 @3.4GHz ) #UE4 | @UNREALENGINE
まずはReplicationGraph無し #UE4 | @UNREALENGINE
サーバー クライアント #UE4 | @UNREALENGINE
結果 stat game ● Server ReplicateActrors Time ● 138ms ● Prioritize Actors Time ● 98ms ● Consider Actors Time ● 38ms ● Replicate Actor Time ● 70calls 0.5ms ● 5つのクライアントは60fpsで動作 #UE4 | @UNREALENGINE
結果 stat net Num Actors : 50,000 Num ConsideredActors : 48,000 #UE4 | @UNREALENGINE
次はReplicationGraphあり #UE4 | @UNREALENGINE
サーバー クライアント #UE4 | @UNREALENGINE
結果ReplicationGraphアリ ● ServerReplicateActorsTime ● 5.2ms ● Prioritize Actors Time ● statには出てこない ● Consider Actors Time ● 無し ● Replicate Actor Time : 0.5ms ● 5つのクライアントは60fpsで動作 #UE4 | @UNREALENGINE
Stats : ReplicationGraph有効 (参考) #UE4 | @UNREALENGINE
比較 プライオリティ付けされる前にグリッド分割によって列挙されるアクターが大幅 に減っていて、列挙の負荷が無い その影響でプライオリティ付け処理とソートの負荷が大きく減った。 RepGraphナシ RepGraphアリ 改善率 考慮されたActor数 48,000 2,740 / connection x17.5 Server ReplicateActrors Time 138ms 5.2ms x26.5 Prioritize Actors Time 98ms N/A N/A Consider Actors Time 38ms 0 ∞ Replicate Actor Time 0.5ms 0.5ms 変化なし #UE4 | @UNREALENGINE
CPUが喜んでる! #UE4 | @UNREALENGINE
ReplicationGraph導入 まず先にお断りしますが、c++による実装が不可欠です エンジン側の実装は基本的なものだけが定義されています カスタマイズできるのが特徴なので、タイトルに応じて 適切なリストが生成できればより効果的です はじめはShooterGameサンプルにに含まれる UShooterReplicationGraph を 持ってきて動かしてみるのがお勧めです #UE4 | @UNREALENGINE
まずは自分の レプリケーショングラフを プログラムします #UE4 | @UNREALENGINE
プラグインの有効化 [YOURPROJECT].uprojectに対するプラグインの追加します [YOURMODULE].build.csの PrivateDevendencyModule (or PublicDependencyModule) に、 ”ReplicationGraph” モジュールを追加します #UE4 | @UNREALENGINE
クラス定義 UReplicationGraphまたは その親のUReplicationDriverを継承したクラスを定義します #UE4 | @UNREALENGINE
ReplicationGraphに書くべき処理 ⚫ クラス毎にどのノードに振り分けるか事前準備 ⚫ アクターが追加された時に呼ばれる関数を独自実装 ⚫ RouteAddNetworkActorToNodes ⚫ アクターが削除された時にノードから削除する関数を独自実装 ⚫ RouteRemoveNetworkActorToNodes #UE4 | @UNREALENGINE
各ReplicationGraphNode それぞれのノードには以下の実装が必要です ⚫ 毎Tickごとに事前準備用に一回呼ばれる ⚫ PrepareForReplication ⚫ コネクション毎にレプリケート対象のアクターを抽出する処理 ⚫ GatherActorListsForConnection ⚫ ReplicationGraphからルーティングされたアクターの追加と削除処理 ⚫ ⚫ NotifyAddNetworkActor NotifyRemoveNetworkActor #UE4 | @UNREALENGINE
PreAllocateRepList ReplicationGraph中で使うアクターリストを 格納するための配列を事前に確保してプールに 用意し、ランタイムでのアロケーションや Resize/Memcopyなどのオーバーヘッドを避け ます void USampleReplicationGraph::InitGlobalGraphNodes() { // Preallocate some replication lists. PreAllocateRepList(3, 12); PreAllocateRepList(6, 12); PreAllocateRepList(128, 64); PreAllocateRepList(512, 16); タイトルに合わせて調整する事が望ましいです 超過した場合はDevelopmentビルドであれば 右のようなReplicationGraphの ログが出力されます #UE4 | @UNREALENGINE Very large replication list size requested. NewExpectedSize: 513
組み込みノード : GridSpatialization2D アクターの現在位置にあわせて グリッドに投入します 境界付近のアクターは2つ以上のセルに 投入されます ActorのCullDistanceSquaredの値を参照して 投入範囲を設定します #UE4 | @UNREALENGINE
組み込みノード : Grid_Dynmic 移動するアクターはGridSpatialization2D下のDynamicに配置します 毎TickのPrepareForReplication()で、 格納されるセルの範囲が変わっていないかチェックが入ります ※50000actorで20ms以上かかります 移動するアクターが極端に多い場合は、ここを仕様に合わせて調整したり 独自実装をおススメします。 #UE4 | @UNREALENGINE
組み込みノード : Grid_Staic 移動しないアクター静的なリストを生成して返すだけなのでとても早いです。 #UE4 | @UNREALENGINE
組み込みノード : Grid_Dormancy Dormancyに状態にあわせて、DynamicとStaticを行ったり来たりします。 #UE4 | @UNREALENGINE
自分のReplicationGraphが実装できたら DefaultEngine.iniに、実装したクラスのパスを設定して マルチプレイゲーム開始時にインスタンスを作ってもらうようにします #UE4 | @UNREALENGINE
実装完了! 思う存分動かしてください #UE4 | @UNREALENGINE
あれ? 私のレプリケーショングラフ 挙動があやしくない??? #UE4 | @UNREALENGINE
StandAloneモードでレプリケーション グラフを一時的に無効化 -ini:Engine:[ConsoleVariables]:Net.RepDriver.Enable=0 をCommand Line Arguments に書く レプリケートグラフが原因で通信バグが 出てるのでは? と思った時に試してください。 PIEではコンソールコマンドを入力した後 PIEを立ち上げなおせばOKです #UE4 | @UNREALENGINE
参考リンク LiveStreaming https://www.youtube.com/watch?v=CDnNAAzgltw UnrealFestEurope Using Replication Graph For Optimizing Real-Time Strategy Games https://www.youtube.com/watch?v=VusAHXoHF3Y #UE4 | @UNREALENGINE
ReplicationGraphまとめ ⚫ こんなプロジェクトにお勧め ⚫ ⚫ ⚫ ⚫ 大人数マルチプレイを実現したい 大量の動的なアクターを処理したい サーバーの負荷を0.1msでも速くしたい 巨大なワールドでマルチプレイを行いたい ⚫ タイトルに合わせて適切なレプリケーショングラフを作るとより効果的 #UE4 | @UNREALENGINE
さいごに 今回のスライドで触れられていない 機能や情報もありますが、 別の機会に紹介出来たら!と思っています 皆様是非マルチプレイに チャレンジしてみてください! グレイマン係長 #UE4 | @UNREALENGINE
QiitaへのTips投稿 はじめました #UE4 | @UNREALENGINE
Unreal Fest East 2019 2019 / 10 / 6 パシフィコ横浜 #UE4 | @UNREALENGINE
ご清聴 ありがとうございました! #UE4 | @UNREALENGINE