Data Sync Helpers
Data Sync Helpersについて
Data Sync Helpersアドオンは、特別なニーズのユースケース用に、データを同期を簡略化するヘルパークラスを提供しています。
ターゲットとなる典型的なユースケースは、以下のようなものです。
- 高頻度で小さなデータを送信し、その完全なリストが途中参加者にも必要になる場合(例:3Dペンでの描画の完全な点を、途中参加者にも共有する)
- 高頻度で小さなデータを送信し、その完全なリストを保持する必要はないが、次のデータを受信する前に何度か送信される場合(例:魔法の杖の一時的な軌跡や、銃から発射された全ての弾の確認など)
- 1度限りの大きなデータを同期する場合(例:アプリケーションで撮った写真を他のユーザーに送信する)
RingBufferLossLessSyncBehaviourクラス
概要
Projectiles Essentialsに見られるように、リングバッファは連続した小さいデータを保存するのに適しています。データを受信する前に複数のデータが送信されても、リングバッファはそれらのデータを失わずに保持できます。
ただし、途中参加者もアクセスできる必要がある情報(描画の点など)は、リングバッファだけでは次第に古いデータが失われていくことになります。
RingBufferLossLessSyncBehaviour<TEntry>
は、この問題を解決します。
- 標準的なリングバッファに加えて、内部ストレージで共有されたデータ数が記録されます
- そのため、途中参加者は足りないデータがあるかを知ることができます
- その際、このクラスはRPCを通して他のユーザーにメッセージを送信します(クラスはどのユーザーがデータを送信できるかを探す処理も制御します)
- 足りないデータを持っている他のユーザーは、
Runner.SendReliableDataToPlayer
メソッドを通してデータを共有します
内部的には、このクラスはNetworkArray<byte>
に依存していて、リングバッファのデータ(開始インデックス、次の書き込み場所)、総データ数、実際のデータを保持しています。
データ不足が発生するのは、リングバッファがすぐに埋まってしまった時か、途中から参加した時です。その際は、足りないデータ範囲のリクエストメッセージが送信されます。
RingBufferLosslessSyncBehaviour<TEntry>
は、NetworkBehaviour
を継承したジェネリッククラスで、型引数はTEntry
である必要があります。
TEntry
は共有データを表現する構造体で、RingBuffer.IRingBufferEntry
インターフェースを実装して、バイト列への変換(AsByteArray
)とバイト列からのコンテンツのロード(FillFromBytes
)を定義します。
これらのメソッドの実装を支援するための静的メソッドがSerializationTools
に含まれています。
使用方法
データの追加
状態権限者は、AddEntry(TEntry)
を使用して、同期するデータにオブジェクトを追加します。
コールバックメソッドのオーバーライド
コールバックをオーバーライドして、例えば、リアルタイムのデータ受信や、足りないデータの復元の完了に反応できます。
C#
// newEntries will contain the new TEntry structs detected in the last data update.The received data at start might not be long enough to form an entry (for late joiners first ring reception, ...), those additional bytes are stored in newPaddingStartBytes
public virtual void OnNewEntries(byte[] newPaddingStartBytes, TEntry[] newEntries) { }
// OnDataLoss will warn of data loss: no need to handle the loss, the request are sent automatically
public virtual void OnDataloss(RingBuffer.LossRange lossRange) { }
// Called when one loss is restored
protected virtual void OnLossRestored(LossRequest request, byte[] receivedData) { }
// When all loss in the total data remains. SplitCompleteData() can be called to retrieve all the TEntry
protected virtual void OnNoLossRemaining() { }
// When a loss is permanent (no one having the data is still in the room
public virtual void OnNoAnswerForALossRequest(LossRequest request) { }
IRingBufferEntryの実装
SerializationTools
クラスは、IRingBufferEntry
のメソッドの実装を簡略化します。
構造体をバイト列(AsByteArray
)にするには、単純にすべての基本的なサポート型(float
・Vector3
・byte
・Quaternion
・int
)をSerializationTools.AsByteArray
に渡すことで、バイト列が返されます。
例えば、以下のような構造体を考えてみましょう。
C#
[System.Serializable]
public struct DrawPoint : RingBuffer.IRingBufferEntry
{
public Vector3 localPosition;
public float drawPressure;
/* ... */
}
AsByteArray
の実装は以下の通りです。
C#
public byte[] AsByteArray => SerializationTools.AsByteArray(localPosition, drawPressure);
バイト列から構造体をロードするには、SerializationTools.Unserialize
メソッドが基本的なサポート型(float
・Vector3
・byte
・Quaternion
・int
)の復元を制御し、同時にバイト列の位置を追跡します。
サンプルの構造体のFillFromBytes
の実装では、上記のAsByteArray
でシリアライズされたデータをロードします。
C#
public void FillFromBytes(byte[] entryBytes)
{
int unserializePosition = 0;
SerializationTools.Unserialize(entryBytes, ref unserializePosition, out localPosition);
SerializationTools.Unserialize(entryBytes, ref unserializePosition, out drawPressure);
}
RingBufferSyncBehaviourクラス
RingBufferSyncBehaviour
はRingBufferLossLessSyncBehaviour
の親クラスで、リングバッファを管理します。リングバッファのデータ復元メッセージは含まれません。
これはRingBufferLossLessSyncBehaviour
のように使用可能ですが、不足データの復元は行われません(不足の検知はできますが、復元はできません)。
このクラスは、標準的なリングバッファが必要なケース(銃の弾など)に使用できます。
リングバッファのインデックスはRingbuffer
と呼ばれる構造体で追跡され、開始位置と次の書き込み位置を更新し、実際のデータ追加とストレージの更新が可能です。
StreamingSyncBehaviourクラス
概要
StreamSynchedBehaviour
では、任意のデータチャンクを他のプレイヤーに送信できます。
これはFusionのSendReliableDataToPlayer
APIを使用しています。
4つのうちの最初のキーは、ObjectのIDを保持してメッセージの識別に使用されるため、ルーム内の複数のオブジェクトがデータを送受信しても、間違ったオブジェクトにデータが送信されることはありません。
StreamSynchedBehaviour
は途中参加者の処理で主に使用できます。特に共有モードや、状態権限者がルームから退出した時に、ユーザーに不足分の初期データを送信します。
これは途中参加者から送信されるRPCメッセージで行われ、状態権限者か他のプレイヤーに完全なキャッシュをリクエストします。
使用方法
データの送信
データの送信はSend(byte[] data)
を呼び出すことで行います。
データはチャンクとして受信し保存され、必要に応じてサブクラスでマージする必要があります。
コールバックメソッドのオーバーライド
コールバックをオーバーライドして、例えば、リアルタイムのデータ受信や、足りないデータの復元の完了に反応できます。
C#
// Provides the 0-1 download progress of a currently received chunk of data
protected virtual void OnDataProgress(float progress) { }
// Called on complete reception of a chunk of data
protected virtual void OnNewBytes(byte[] newData) { }
// Called to know the client is a late joiner, waiting for data
protected virtual void OnLateJoinersWaitingForData() { }
// Called if missing data for a late joiner are unavailable anywhere
protected virtual void OnMissingData() { }
デモ
アドオンには、継承方法のサンプルクラスが存在します。
TestStreamSynchedBehaviour
(StreamingSyncBehaviour
)TestLosslessRingBufferSync
(RingBufferLossLessSyncBehaviour
)TestRingBufferSync
(RingBufferSyncBehaviour
)
DemoStreaminghelpers
シーンは、StreamingSyncBehaviour
の実装のTestStreamSynchedBehaviour
が含まれます。
シーンにはこのコンポーネントが2つあり、適切なStreamSynchedBehaviour
オブジェクトにデータが送信されることを示します。
「SendRandomData」ボタンを押すと、データチャンクが接続中のユーザーに送信され、「All data」属性が表示されます。
これは途中参加者でも利用可能です。
DemoRingBuffer
には、TestLosslessRingBufferSync
とTestRingBufferSync
が含まれ、ロスレス版と標準的なリングバッファを示します。
「AddSingleEntry」「AddRandomEntry」「AddSeveralRandomEntries」のどれかを押すと、インスペクター上の要素フィールドに要素が追加されます。
これは、接続中でも途中参加のクライアントでも表示されます。
ログレベルに「Data loss recovery」があり、コンソール上で不足データ復元メッセージを確認することができます。
途中参加者では体系的にこのメッセージがトリガーされ、「AddSeveralRandomEntries」で故意にリングバッファを埋めてもこのメッセージが表示されます。
最終的に、すべてのユーザーは同じ要素を持つことになります。
ダウンロード
このアドオンの最新バージョンは、Industries アドオンのプロジェクトに含まれています。
また、無料のXR アドオンのプロジェクトにも含まれています。
対応するトポロジー
- 共有モード
StreamingSyncBehaviour
はホストモードでも使用できることに留意してください。
更新履歴
- Version 2.0.6:
- Add RingBufferLosslessSyncBehaviour.TryGetInterpolationTotalEntryCount, to find the entry count interpolated between each interpolation state entry count (from and to)
- Version 2.0.5:
- Add RingBuffer.PositionInfo to simplify finding the current position in a from/to buffer
- Version 2.0.4:
- Add sample drawing code
- Version 2.0.3:
- Allow demo CameraPicture to forward to a specific RenderTexture
- Add solutions (StreamingAPIConfiguration and overridable TargetId methods) if a NetworkObject contains 2 components using streaming API at the same time
- Version 2.0.2: Add support for NetworkBehaviourId serialization in tools
- Version 2.0.1:
- Add Vector2 and uint support in serialization tools
- add flexibility to ring buffer entry size determination
- Version 2.0.0: First release