Network Collections
概述
Fusion提供基於結構的集合類型,可用於已連網屬性。
- NetworkArray<T>
- NetworkDictionary<K, V>
- NetworkLinkedList<T>
- NetworkString<Size>
請注意,這些集合是結構,而不是參照類型。這些集合和C#集合之間存在一些細微的C#用途差異(請參閱INetworkStructs中的用途中的用法)
允許的T/K/V類型是:
- 基本類型
- byte, sbyte
- Int16, Int32, Int64
- UInt16, UInt32, UInt64
- float
- double
 
- Unity架構類型(在ILWeaver.cs中定義)
- Vector2, Vector3, Vector4
- Quaternion
- Matrix4x4
- Vector2Int, Vector3Int
- BoundingSphere
- Bounds
- Rect
- BoundsInt
- RectInt
- Color, Color32
 
- System.Guid
- 使用者定義的INetworkStructs
- Fusion定義的INetworkStructs
- NetworkString<IFixedStorage>
- NetworkBool
- Ptr
- Angle
- BitSet64, BitSet128, BitSet192, BitSet256
- PlayerRefSet
- NetworkId
- NetworkButtons
- NetworkRNG
- NetworkObjectGuid
- NetworkPrefabRef
- NetworkObjectHeader
- NetworkPrefabId
- SceneRef
- TickTimer
- IFixedStorage (_2, _4, _8, _16, _32, _64, _128, _256, _512)
 
宣告
NetworkArray、NetworkDictionary和NetworkLinkedList必須定義為具有[Networked]屬性的屬性。[Networked]屬性指示ILWeaver生成屬性程式碼,該程式碼將這些集合連接到其關聯的NetworkRunner和Simultation執行個體中的後備記憶體。
[Capacity]屬性還應用於指定元素的最大數量。無論用途如何,都會為這麼多元素分配記憶體,因此請選擇足以覆蓋您預期的最大數量的元素的最小的數量。除非元素改變值,否則它們不會產生網路流量。
C#
// A basic Network Collection declaration
[Networked, Capacity(4)]
NetworkArray<int> NetArray => default;
初始化
當NetworkArray、NetworkDictionary和NetworkLinkedList在NetworkBehaviour中宣告為已連網屬性時,可以使用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#陣列的替代結構,可以在Fusion中作為已連網屬性。雖然與C#陣列不完全相同,但NetworkArray是一個IEnumerable集合,具有獲取和設定值的方法,以及向其他集合複製和從其他集合複製的方法。
主要方法是:
- 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的替代結構,可以在Fusion中作為已連網屬性。雖然不是完整的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的替代結構,它允許使用容量的子集。新增的項目將新增到後備資料中的開啟槽中。移除項目時,後備陣列資料不會移動記憶體中的其他元素。取而代之地,集合將有關元素順序的資料作為結構的一部分存儲,並且列舉器和索引器將按元素新增的順序傳回元素,而不是按元素在後備陣列中的駐留順序傳回。
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();
    }
  }
}
INetworkStructs中的用途
修改INetworkStruct已連網屬性的值時,請確保:
- 使用INetworkStruct的副本,並將更改後的副本應用於已連網屬性,
- 或者,將已連網屬性定義為參照。當已連網屬性被宣告為參照時,不需要複製值,因為可以直接修改參照。
可以初始化INetworkStruct類型的已連網屬性(例如,請參閱下方的程式碼)。
將INetworkStructs中的這些已連網集合用作已連網屬性:
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中的這些已連網集合用作 參照的 已連網屬性:
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();
  }
}