This document is about: FUSION 2
SWITCH TO

네트워크 컬렉션

개요

Fusion은 네트워크 속성으로 사용할 수 있는 구조체 기반의 컬렉션 타입을 제공합니다.

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

이 컬렉션들은 참조 타입이 아닌 구조체이므로, C# 컬렉션과 약간의 사용 차이가 있을 수 있습니다. (자세한 내용은 Usage In INetworkStructs 참조)

허용되는 T/K/V 타입은 다음과 같습니다:

  • 기본 타입
    • byte, sbyte
    • Int16, Int32, Int64
    • UInt16, UInt32, UInt64
    • float
    • double
  • 유니티 구조체 타입 (ILWeaver.cs에서 정의)
    • Vector2, Vector3, Vector4
    • Quaternion
    • Matrix4x4
    • Vector2Int, Vector3Int
    • BoundingSphere
    • Bounds
    • Rect
    • BoundsInt
    • RectInt
    • Color, Color32
  • System.Guid
  • 사용자 정의 INetworkStruct
  • Fusion 정의 INetworkStruct
    • 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] 속성과 함께 속성(Property)으로 정의되어야 합니다. [Networked] 속성은 ILWeaver가 이 컬렉션을 관련 NetworkRunnerSimulation 인스턴스의 메모리에 연결하는 코드를 생성하도록 지시합니다.

[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는 Fusion에서 네트워크 속성으로 사용할 수 있는 C# 배열의 구조체 대체입니다. NetworkArray는 C# 배열과 완전히 동일하지는 않지만, 값을 가져오고 설정하는 메소드 및 다른 컬렉션과의 복사를 위한 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는 Fusion에서 네트워크 속성으로 사용할 수 있는 C# Dictionary의 구조체 대체입니다. NetworkDictionary는 완전한 IDictionary 구현은 아니지만, 주요 멤버는 대부분 제공됩니다.

주요 메소드 및 속성:

  • 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)와 인덱서는 요소가 백업 배열에 저장된 순서가 아니라 추가된 순서대로 요소를 반환합니다.

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은 문자열 데이터를 위한 고정 크기 컬렉션입니다. 크기(Size)는 미리 정의된 IFixedStorage 타입 중 하나를 사용할 수 있으며, 예를 들어 _32는 크기가 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의 복사본을 작업하여 수정된 복사본을 네트워크 속성에 적용하거나,
  • 네트워크 속성을 ref로 정의하십시오. 네트워크 속성이 ref로 선언되면, 값을 복사할 필요 없이 참조를 직접 수정할 수 있습니다.

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();
  }
}
Back to top