同期タイミングの変更

目次

  概要
  事前設定
  MonobitEngine.MonobitNetwork.sendRate プロパティ
  MonobitEngine.MonobitNetwork.updateStreamRate プロパティ
  テストモデル


概要

同期通信制御自体は、自動的にMUNで管理している

  MUNの同期通信自体については、その機能がほぼ自動化されていますが、
  そのタイミングは MUN 内部で管理しています。

  オブジェクトの同期については、MonobitView, MonobitTransformView, MonobitAnimatorView
  3つのコンポーネントを登録さえすれば、あとは自動的に行なってくれますが、
  同期通信自体は MUN 側で独自で行なっており、その処理自体を直接制御することはできません。

  RPCの実行、サーバへの接続切断、ルーム入室退室といった各種通信データについても、
  呼び出し実行したタイミングと「サーバへの送信タイミング」は、厳密に言えば異なります。
  この通信処理自体についても上記と同様、MUN 側で独自に行なっているもので、直接制御することはできません。

  MUN では、できるだけ通信負荷(オーバーヘッド)を抑えるように、
  これらのネットワーク制御についてある程度のメッセージをまとめて、一定タイミングで送信しています。

同期通信のタイミングを調整する

  上述の通り、同期通信の実行処理自体をカスタマイズすることはできませんが、
  作りたいゲームの内容によって、同期通信のタイミングを調整することが必要なケースもあるでしょう。

  例えば、2人対戦での格闘ゲームであれば、出来る限りフレームレートと一致させた状態で同期を取るべきですし、
  多人数が参加するMMORPGのようなゲームであれば、高負荷を抑えるために、1秒間に1回の同期くらいで十分な場合もあります。

  このページでは、同期通信のタイミングの調整方法について触れます。


事前設定

特に必要ありません

  MUNを利用できる環境かであれば、どのクラス・メソッドからも設定可能です。


MonobitEngine.MonobitNetwork.sendRate プロパティ

機能

  RPCメッセージの送信間隔を設定します。

入出力型

内容
int 1秒間における、1クライアントあたりの送信回数を設定します。
初期値は20です。

単位は「送信回数÷秒」であり、「送信回数×1秒間におけるフレーム数÷送信フレーム間隔」です。
例えば 60fps のゲームで、1フレームに1回送信するのであれば、この値を 60 と設定します。
同様に、30fps のゲームで、2フレームに1回送信するのであれば、この値を 15 としてください。

なお、この値で設定された値を元にメッセージ送信回数が定義されますので、例えば sendRate = 10 とした場合における
  a) 30FPS で動作するゲームで、1フレームあたり 10 回のRPC送信処理を実行(1クライアントあたりの秒間実行数 300 回)
  b) 30FPS で動作するゲームで、1フレームあたり 30 回のRPC送信処理を実行(1クライアントあたりの秒間実行数 900 回)
をしたとしても、1クライアントあたりの秒間RPC送信メッセージ数は a), b) ともに 10 です。
これは sendRate に指定した回数に合わせた時間間隔中で実行されたRPCは「送信キュー」に蓄積され、
送信回数のタイミングに合わせて蓄積された送信キューをひとまとめにして「1つのメッセージ」として送信するからです。

記述例

// 1秒間に60回のタイミングで同期通信を実行します。
MonobitEngine.MonobitNetwork.sendRate = 60;


MonobitEngine.MonobitNetwork.updateStreamRate プロパティ

機能

  MonobitView, MonobitTransformView, MonobitAnimatorView の3種類の同期通信情報のストリーミング処理、
  および、MonobitEngine.MonoBehaviour で宣言している接続コールバック「OnMonobitSerializeView」のストリーミング処理を
  実行するタイミングを調整します。

入出力型

内容
int 1秒間における、同期オブジェクト単位でのストリーミングメッセージ送信回数を設定します。
初期値は10です。

単位は「送信回数÷秒」であり、「送信回数×1秒間におけるフレーム数÷送信フレーム間隔」です。
例えば 60fps のゲームで、1フレームに1回ストリーミング処理を実行するのであれば、この値を 60 と設定します。
同様に、30fps のゲームで、2フレームに1回ストリーミング処理を実行するのであれば、この値を 15 としてください。

なお、この値は同期オブジェクト単位でメッセージが分割されますので、1クライアントあたりの秒間ストリーミングメッセージ送信総数は、
「updateStreamRate × そのクライアントが所有権を持つ同期オブジェクト数」と一致します。

記述例

// 1秒間に30回のタイミングで、ストリーミング処理を実行します。
MonobitEngine.MonobitNetwork.updateStreamRate = 30;


テストモデル

全体的な負荷を考慮して設定する

  上記について簡潔に述べれば、sendRate および updateStreamRate の 2つの要素は、以下の同期タイミングを図っています。
 ・MonobitEngine.MonobitNetwork.sendRate
    → 1秒間における、1クライアントがRPCメッセージを送信する回数

 ・MonobitEngine.MonobitNetwork.updateStreamRate
    → 1秒間における、1オブジェクトが同期情報を送信する回数
  この2つの要素は、直接「ルーム内における総トラフィック量」に影響を及ぼします。
  ネットワークやサーバのリソースは限られていますので、あらかじめトラフィックを意識したテストモデルを考えて設定してください。

テストモデルの一例

  一般的なテストモデルとして、例えば「2対2で行なう対戦ゲーム」を作ることを考えてみます。
  まず、総トラフィック量について、以下のように定義づけます。
・ホストとクライアントが、サーバを介して、互いに情報をやり取りする「メッセージ」を、1単位とする。

・送信するRPCメッセージは「MonobitTargets.All」で送信することを想定する。
   ※ MonobitTargets.All とは
       → 自身が送信したメッセージをサーバ側で受け取った際に、「自身を除くルーム内のプレイヤー全員」に受信するようにする。

・各クライアントともに、ルーム入室時から退室するまでの間に、同期するオブジェクトを1つ所有する。

  1ルームあたりのメッセージ数として、一例として秒間2000メッセージまで許容できるルームを作成する、とします。
  ここから、「ホスト」および「クライアント」が最大どれだけメッセージを送れるのか、以下の数式から逆算で求めます。
メッセージの総数 = サーバの受信RPCメッセージ数 + サーバの送信RPCメッセージ数 + サーバの受信オブジェクト同期メッセージ受数+サーバの送信オブジェクト同期メッセージ数
サーバの受信RPCメッセージ数 = sendRate × クライアントの数
サーバの送信RPCメッセージ数 = サーバの受信RPCメッセージ数 × (クライアントの数-1)
サーバの受信オブジェクト同期メッセージ数 = updateStreamRate × 1シーン上に存在する同期オブジェクトの総数
サーバの送信オブジェクト同期メッセージ数 = サーバの受信オブジェクト同期メッセージ数 × (クライアントの数-1)
  以上から
メッセージの総数 = ((sendRate × クライアントの数) + (updateStreamRate × 1シーン上に存在する同期オブジェクトの総数)) × (クライアント数-1)
  が導き出せます。
  クライアントの数は「2対2=4」、同期オブジェクト数が「4×1=4」ですので、
2000 ÷ ((4client+4object)×(4client-1)) = 35.714285...
  となり、sendRate と updateStreamRate の合計が 35 を超えないように 調整する必要があります。

sendRate と updateStreamRate の比重

  あとは「キャラクタ同期」と「RPCメッセージ」の比重の問題ですが、ユースケースに応じて異なります。
  アクションゲームなどの場合であれば「updateSteamRate」に比重を置くべきですし、
  逆にチャットなどのアプリケーションであれば「sendRate」に比重を置くべきです。

  一般的な対戦ゲームであれば、比重はsendRate:updateStreamRate = 1:2 くらいが
  丁度良いかと思いますので、まずはその設定で試してみてください。