This document is about: FUSION 2
SWITCH TO

Data Sync Helpers

Fusion XR プロトタイピングモジュール

Data Sync Helpersについて

Data Sync Helpersアドオンは、特別なニーズのユースケース用に、データを同期を簡略化するヘルパークラスを提供しています。

ターゲットとなる典型的なユースケースは、以下のようなものです。

  • 高頻度で小さなデータを送信し、その完全なリストが途中参加者にも必要になる場合(例:3Dペンでの描画の完全な点を、途中参加者にも共有する)
  • 高頻度で小さなデータを送信し、その完全なリストを保持する必要はないが、次のデータを受信する前に何度か送信される場合(例:魔法の杖の一時的な軌跡や、銃から発射された全ての弾の確認など)
  • 1度限りの大きなデータを同期する場合(例:アプリケーションで撮った写真を他のユーザーに送信する)

RingBufferLossLessSyncBehaviourクラス

概要

Projectiles Essentialsに見られるように、リングバッファは連続した小さいデータを保存するのに適しています。データを受信する前に複数のデータが送信されても、リングバッファはそれらのデータを失わずに保持できます。

ただし、途中参加者もアクセスできる必要がある情報(描画の点など)は、リングバッファだけでは次第に古いデータが失われていくことになります。

RingBufferLossLessSyncBehaviour<TEntry>は、この問題を解決します。

  • 標準的なリングバッファに加えて、内部ストレージで共有されたデータ数が記録されます
  • そのため、途中参加者は足りないデータがあるかを知ることができます
  • その際、このクラスはRPCを通して他のユーザーにメッセージを送信します(クラスはどのユーザーがデータを送信できるかを探す処理も制御します)
  • 足りないデータを持っている他のユーザーは、Runner.SendReliableDataToPlayerメソッドを通してデータを共有します

内部的には、このクラスはNetworkArray<byte>に依存していて、リングバッファのデータ(開始インデックス、次の書き込み場所)、総データ数、実際のデータを保持しています。

Fusion Industries Addon Data Sync Helpers NetworkArray

データ不足が発生するのは、リングバッファがすぐに埋まってしまった時か、途中から参加した時です。その際は、足りないデータ範囲のリクエストメッセージが送信されます。

Fusion Industries Addon Data Sync Helpers NetworkArray 2

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)にするには、単純にすべての基本的なサポート型(floatVector3byteQuaternionint)を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メソッドが基本的なサポート型(floatVector3byteQuaternionint)の復元を制御し、同時にバイト列の位置を追跡します。

サンプルの構造体の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クラス

RingBufferSyncBehaviourRingBufferLossLessSyncBehaviourの親クラスで、リングバッファを管理します。リングバッファのデータ復元メッセージは含まれません。

これはRingBufferLossLessSyncBehaviourのように使用可能ですが、不足データの復元は行われません(不足の検知はできますが、復元はできません)。

このクラスは、標準的なリングバッファが必要なケース(銃の弾など)に使用できます。

リングバッファのインデックスはRingbufferと呼ばれる構造体で追跡され、開始位置と次の書き込み位置を更新し、実際のデータ追加とストレージの更新が可能です。

StreamingSyncBehaviourクラス

概要

StreamSynchedBehaviourでは、任意のデータチャンクを他のプレイヤーに送信できます。
これはFusionのSendReliableDataToPlayerAPIを使用しています。
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() { }

デモ

アドオンには、継承方法のサンプルクラスが存在します。

  • TestStreamSynchedBehaviourStreamingSyncBehaviour
  • TestLosslessRingBufferSyncRingBufferLossLessSyncBehaviour
  • TestRingBufferSyncRingBufferSyncBehaviour

DemoStreaminghelpersシーンは、StreamingSyncBehaviourの実装のTestStreamSynchedBehaviourが含まれます。
シーンにはこのコンポーネントが2つあり、適切なStreamSynchedBehaviourオブジェクトにデータが送信されることを示します。
「SendRandomData」ボタンを押すと、データチャンクが接続中のユーザーに送信され、「All data」属性が表示されます。
これは途中参加者でも利用可能です。

DemoRingBufferには、TestLosslessRingBufferSyncTestRingBufferSyncが含まれ、ロスレス版と標準的なリングバッファを示します。
「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
Back to top