LoginSignup
10
1

More than 1 year has passed since last update.

Netcode for GameObjectsの通信量過剰時の挙動と対策

Last updated at Posted at 2022-12-03

この記事は、KLab Engineer Advent Calendar 2022 の4日目の記事です。
こんにちは。KLabでエンジニアをしている @tsune2ne です。

最近はNetcode for GameObjectsを中心に技術記事を書いています。

今回は通信を投げまくったときにどうなるか・どうするべきかを調べました。

本題

同期通信ではRPCを送って他端末に同じイベントを起こしたり
変数をレプリケーションすることで他端末で同じ状態にしたりします。
ですが同期通信の量を過剰に増やした場合、どういう挙動になるかはライブラリの実装によります。

今回は Netcode for GameObjects で実際にサンプルを作りながらどういう挙動になるかを見ていきます。

バージョン情報

Unity : 2021.3.11f1
Netcode for GameObjects : 1.0.2

通常サンプル

上下左右円形に移動するCubeを用意しました。

builds_1x1.gif

この縦移動をレプリケーション、横移動をRPCでLateUpdateで同期します。

RPC:100個,レプリケーション:100個のVector3を同期

builds_10x10.gif

問題なく動きました。

RPC:900個,レプリケーション:900個のVector3を同期

builds_30x30.gif

とても重いです。どんどん同期が遅れていきます。
自動的にパケットを減らして次のフレームを軽くするなどの処理は入ってなさそうに見えます。

RPC:2500個,レプリケーション2500個のVector3を同期

builds_50x50.gif

Hostはカクつきながらも動きますが、ClientはCubeを表示することさえできませんでした。
また一定時間経つと自動でNetworkMangerがShutdownされる挙動をみせています。

実験結果

どうもNetcode for GameObjectsにはRPC/レプリケーションが増えすぎた場合の自動制御はまだ入っていないようです。
同期過多のままPJを進めると後半になって同期が始まらない、同期が遅れたまま追いついてこないなどの問題が起こるので注意しましょう。

RPCオーバーフローの図.png

非信頼性RPCサンプル

さて、デフォルトの設定では通信量が1フレームの閾値を超えると次のフレームに持ち越されるのがサンプル1でわかりました。
じゃあ信頼性の低い通信を捨てて同期が追い付くように調整してみましょう。

信頼性の設定には RpcDelivery.Unreliable を利用します

[ClientRpc(Delivery = RpcDelivery.Unreliable)]
void UpdateRightClientRpc(Vector3 right) { /*...*/ }

これは通信の信頼性を下げるための設定です。
Unreliableでは専用のNetworkPipelineで処理されており、1回の通信量が大きく制限されています。

builds_30x30_unreliable.gif

縦軸移動のRPCが捨てられて、横軸移動のレプリケーションだけ適用されるようになりました。

RPCオーバーフローの図_unreliable.png

まとめ

Netcode for GameObjectsでは通信が量が過剰になった場合の自動制限処理は入っていなさそうです。
これはRPCがデフォルトで 信頼性あり で通信しているためです。

PJの後半で一気にチューニングしようと考えていると、
PJの途中で通信遅延が追い付かなくなる・通信が勝手に切れるなど
大きなしっぺ返しがくるので気をつけましょう。

・開発初期から通信データは最小限にする
・信頼性の設定をしてオーバーフローしても最適化される処理を入れる

同期データ量が最小になる努力はこれからも必要そうです。

おまけ

ソースコードを読んでみる

Netcode for GameObjectsのコードは公開されています

RPCもレプリケーションも
・NetworkBehaviourで同期命令を取得
・FastBufferにまとめる
・MessagingSystemでキュー管理
・NetworkTransport(UnityTransport)で送信
という流れです。多分。

息まいてコード読み始めたんですが
ぱっと見ではUnityTransport.Sendのqueue.PushMessage(payload)でパケット量を制限してるようには見えますが
ここを調整したら優先度を決められるわけではなさそうです

UnrealEngine4ではどうなっているか

通信量が増えてくるとRPCを優先し、レプリケーションはあえて送信しないようになるようです。
非常に参考になるります。

参考資料

10
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
1