This document is about: FUSION 2
SWITCH TO

Network Collections

概要

Fusionが提供する構造体ベースのコレクション型は、ネットワークプロパティに使用できます。

  • NetworkArray<T>
  • NetworkDictionary<K, V>
  • NetworkLinkedList<T>
  • NetworkString<Size>

これらのコレクションは構造体であり、参照型ではないことに注意してください。FusionのコレクションとC#のコレクションとの間で、細かい使用方法の違いがあります。(INetworkStructでの使用方法をご覧ください)

使用できるT/K/Vタイプは以下の通りです。

Blittable Primitives
byte sbyte short (Int16) int (Int32) long (Int64)
ushort (UInt16) uint (UInt32) ulong (UInt64) float (Single) double
Blittable Unity Struct Types
Vector2 Vector3 Vector4 Quaternion Matrix4x4
Vector2Int Vector3Int BoundingSphere Bounds Rect
BoundsInt RectInt Color Color32  
System and User Defined Blittable Types
Enums System Types such as System.Guid Structs Other INetworkStructs  
Fusion Defined INetworkStructs
NetworkString<IFixedStorage> NetworkBool Ptr Angle TickTimer
PlayerRef PlayerRefSet SceneRef NetworkId NetworkObjectGuid
NetworkObjectHeader NetworkPrefabRef NetworkPrefabId NetworkRNG NetworkButtons
BitSet64 BitSet128 BitSet192 BitSet256  
IFixedStorage (_2, _4, _8, _16, _32, _64, _128, _256, _512)

宣言

NetworkArray/NetworkDictionary/NetworkLinkedListは、[Networked]属性を付けたプロパティで定義する必要があります。[Networked]属性が付いたコレクションでは、そのコレクションが紐づいているNetworkRunnerSimulationインスタンスのバッキングメモリに接続するコードが、ILWeaverによって生成されます。

[Capacity]属性で最大要素数を指定します。使用量にかかわらず、指定した分のメモリが割り当てられるため、想定する最大要素数をカバーするのに十分なだけの数を選択してください。要素の値が変わらなければ、ネットワークのトラフィックは発生しません。

C#

// A basic Network Collection declaration
[Networked, Capacity(4)]
NetworkArray<int> NetArray => default;

初期化

NetworkArray/NetworkDictionary/NetworkLinkedListNetworkBehaviourのネットワークプロパティとして宣言している場合、MakeInitializer()を使用して初期値を定義できます。

C#

[Networked]
[Capacity(4)] // Sets the fixed capacity of the collection
NetworkArray<int> NetArray { get; }
  // Optional initialization
  = MakeInitializer(new int[] { 0, 1, 2, 3 });

[Networked, Capacity(4)]
NetworkLinkedList<int> NetLList { get; }
  // Optional initialization
  = MakeInitializer(new int[] { 0, 1, 2, 3 });

[Networked, Capacity(2)]
NetworkDictionary<int, int> NetDict { get; }
  // Optional initialization
  = MakeInitializer(new Dictionary<int, int> { { 0, 0 }, { 1, 1 } });

NetworkArray<T>

NetworkArrayは、C#の配列を代替する構造体で、ネットワークプロパティに使用できます。C#の配列と完全に同等ではありませんが、NetworkArrayIEnumerableコレクションで、値の取得/設定や、他のコレクションからのコピーメソッドを持ちます。

主なメソッド:

  • Get(int index)
  • Set(int, T)

C#

public class CollectionTestsArray : NetworkBehaviour
{
  [Networked]
  [Capacity(4)] // Sets the fixed capacity of the collection
  NetworkArray<NetworkString<_32>> NetArray { get; } =
    MakeInitializer(new NetworkString<_32>[] { "#0", "#1", "#2", "#3" });

  public override void FixedUpdateNetwork()
  {
    NetArray.Set(0, "Zero");
    NetArray.Set(1, "One");
    NetArray.Set(2, "Two");

    // This is invalid with a NetworkDictionary property, use Set() instead.
    // NetArray[3] = "Three";

    NetArray.Set(0, NetArray[0].ToUpper());
    NetArray.Set(1, NetArray.Get(1).ToLower());
    NetArray.Set(2, default);

    for (int i = 0; i < NetArray.Length; ++i)
    {
      Debug.Log($"{i}: '{NetArray[i]}''");
    }
  }
}

NetworkDictionary<K, V>

NetworkDictionaryは、C#のDictionaryを代替する構造体で、ネットワークプロパティに使用できます。IDictionaryを完全に実装していませんが、主要なメンバーは全て使用可能で、Dictionaryと類似しています。

主なメソッドとプロパティ:

  • Clear()
  • Add(K, V)
  • Remove(k)
  • ContainsKey(K)
  • ContainsValue(V)
  • Get(K)
  • Set(K, V)
  • this[K]
  • Capacity
  • Count

C#

public class NetworkDictionaryExample : NetworkBehaviour
{  
  [Networked]
  [Capacity(4)] // Sets the fixed capacity of the collection
  [UnitySerializeField] // Show this private property in the inspector.
  private NetworkDictionary<int, NetworkString<_32>> NetDict => default;

  public override void FixedUpdateNetwork()
  {
    NetDict.Clear();
    NetDict.Add(0, "Zero");
    NetDict.Add(2, "Two");
    NetDict.Add(5, "Five");

    // Setting values with the indexer are not valid, this is one of the cases
    // where the struct based NetworkDictionary differs in usage from Dictionary.
    // NetDict[0] = "Foo"; // this is not valid.

    if (NetDict.ContainsKey(0))
    {
      NetDict.Set(0, NetDict[0].ToUpper());
    }

    if (NetDict.TryGet(5, out var value))
    {
      NetDict.Set(5, value.ToLower());
    }

    NetDict.Remove(2);

    foreach(var kvp in NetDict)
    {
      Debug.Log($"{NetDict.Count}/{NetDict.Capacity} Key:{kvp.Key} Value:{kvp.Value}");
    }
  }
}

NetworkLinkedList<T>

NetworkLinkedListは、NetworkArrayを代替する構造体で、。要素を追加すると、要素はバッキングデータの空きスロットに追加され、要素を削除しても、バッキングデータ配列の他の要素はシフトされません。このコレクションは、データを要素順ではなく、構造体の一部として格納します。列挙子(Enumerator)やインデクサー(Indexer)が要素を返す順序は、バッキングデータ配列に格納されている順ではなく、要素が追加された順です。

C#

public class NetworkLinkedListExample : NetworkBehaviour
{
  [Networked]
  [Capacity(4)] // Sets the fixed capacity of the collection
  [UnitySerializeField] // Show this private property in the inspector.
  private NetworkLinkedList<NetworkString<_32>> NetList { get; }
    = MakeInitializer(new NetworkString<_32>[] { "Zero", "One", "Two", "Four"});

  public override void Spawned()
  {
    // Remove the second entry, leaving one open capacity.
    NetList.Remove("One");

    // Find an entry by value
    NetList.Set(NetList.IndexOf("Two"), "TWO");

    // Add a new entry. In memory it backfills the now open memory position.
    NetList.Add("Five");

    // The indexed order however remains in sequence,
    // so only the changed memory position is dirty and networked.
    Debug.Log($"List {NetList.Count}/{NetList.Capacity}" +
      $"0:'{NetList[0]}' 1:'{NetList[1]}' 2:'{NetList[2]} 3:'{NetList[3]}'");
  }
}

NetworkString<Size>

NetworkStringは、文字列データ用の固定サイズのコレクションです。サイズは、定義済みのIFixedStorage型のいずれかを指定できます。サイズ型の名前は_Xで、Xがコレクションのサイズになります。例えば_32は、uint[32]でバッキングされ、最大32文字の文字列を格納できます。

C#

public class NetworkStringExample : NetworkBehaviour
{
  [Networked]
  public NetworkString<_16> NetString { get; set; }

  public override void FixedUpdateNetwork()
  {
    if (Runner.IsServer) {
      NetString = System.IO.Path.GetRandomFileName();
    }
  }
}

INetworkStructでの使用方法

INetworkStruct型のネットワークプロパティの値は、かならず以下のどちらかの方法で変更してください。

  • INetworkStructのコピーを作成し、変更したコピーをネットワークプロパティに代入する
  • ネットワークプロパティをrefで定義する(ネットワークプロパティをrefで宣言すると、値のコピーが不要になり、参照を直接変更できる)

INetworkStruct型のネットワークプロパティは、初期化することができます。(以下のコードの例をご覧ください)

ネットワークコレクションは、INetworkStruct内のネットワークプロパティで使用できます。

C#

public class NetworkDictionaryTest : NetworkBehaviour
{
  [System.Serializable]
  struct NetworkStruct : INetworkStruct
  {
    [Networked, Capacity(16)]
    public NetworkDictionary<int, int> NestedDict => default;

    // NetworkString is a normal struct, so it doesn't require any Fusion attributes
    public NetworkString<_16> NestedString;

    // Define default initialization as a property if needed.
    public static NetworkStruct Defaults
    {
      get
      {
        var result = new NetworkStruct();
        result.NestedDict.Add(0, 0);
        result.NestedString = "Initialized";
        return result;
      }
    }
  }

  // Property declared normally as a value type
  [Networked]
  [UnitySerializeField]
  private NetworkStruct NestedStruct { get; set; } = NetworkStruct.Defaults;

  public void ModifyValues()
  {
    // NestedStruct is a value type, so modifications need to be performed on a copy,
    // and the modified result must be applied back to the property.
    var copy = NestedStruct;
    copy.NestedDict.Add(copy.NestedDict.Count, default);
    copy.NestedString = System.IO.Path.GetRandomFileName();
    NestedStruct = copy;
  }
}

また、ネットワークコレクションは、INetworkStruct内のネットワークプロパティでrefが使用できます。

C#

public class NetworkDictionaryTest : NetworkBehaviour
{
  [System.Serializable]
  struct NetworkStruct : INetworkStruct
  {
    [Networked, Capacity(16)]
    public NetworkDictionary<int, int> NestedDict => default;

    // NetworkString is a normal struct, so it doesn't require any Fusion attributes
    public NetworkString<_16> NestedString;

    public static NetworkStruct Defaults
    {
      get
      {
        var result = new NetworkStruct();
        result.NestedDict.Add(0, 0);
        result.NestedString = "Initialized";
        return result;
      }
    }
  }

  // Property declared as ref type, allowing direct modification of values
  [Networked]
  [UnitySerializeField]
  private ref NetworkStruct NestedStruct => ref MakeRef(NetworkStruct.Defaults);

  public void ModifyValues()
  {
    // NestedStruct was declared as a ref above, so modifications
    // may be made directly to the reference, without need for copies.
    NestedStruct.NestedDict.Add(NestedStruct.NestedDict.Count, default);
    NestedStruct.NestedString = System.IO.Path.GetRandomFileName();
  }
}
Back to top