Advertisement
Guest User

unity netcode dictionary

a guest
Mar 22nd, 2024
81
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 19.03 KB | None | 0 0
  1. using System.Collections.Generic;
  2. using System;
  3. using Unity.Netcode;
  4. using System.Linq;
  5. using System.Collections;
  6. using Unity.Collections;
  7. using Unity.Collections.LowLevel.Unsafe;
  8. using Unity.VisualScripting;
  9. /// <summary>
  10. /// Event based NetworkVariable container for syncing Dictionaries
  11. /// </summary>
  12. /// <typeparam name="TKey">The type for the dictionary keys</typeparam>
  13. /// <typeparam name="TValue">The type for the dictionary values</typeparam>
  14. public class NetworkDictionary<TKey, TValue> :
  15.     NetworkVariableBase,
  16.     IEnumerable<KeyValuePair<TKey, TValue>>,
  17.     IDisposable
  18.     where TKey : unmanaged, IEquatable<TKey>
  19.     where TValue : unmanaged
  20. {
  21.     public struct Enumerator : IEnumerator<(TKey Key, TValue Value)>, IDisposable
  22.     {
  23.         private NativeArray<TKey> keys;
  24.         private NativeArray<TKey>.Enumerator keysEnumerator;
  25.         private NativeArray<TValue> values;
  26.         private NativeArray<TValue>.Enumerator valuesEnumerator;
  27.  
  28.         public (TKey Key, TValue Value) Current => (keysEnumerator.Current, valuesEnumerator.Current);
  29.  
  30.         object IEnumerator.Current => Current;
  31.  
  32.         public Enumerator(ref NativeList<TKey> keys, ref NativeList<TValue> values)
  33.         {
  34.             this.keys = keys.AsArray();
  35.             this.values = values.AsArray();
  36.             keysEnumerator = new NativeArray<TKey>.Enumerator(ref this.keys);
  37.             valuesEnumerator = new NativeArray<TValue>.Enumerator(ref this.values);
  38.         }
  39.  
  40.         public void Dispose()
  41.         {
  42.             keysEnumerator.Dispose();
  43.             valuesEnumerator.Dispose();
  44.             values.Dispose();
  45.             keys.Dispose();
  46.         }
  47.  
  48.         public bool MoveNext()
  49.         {
  50.             var keysEnumeratorCanMove = keysEnumerator.MoveNext();
  51.             var valuesEnumeratorCanMove = valuesEnumerator.MoveNext();
  52.  
  53.             return keysEnumeratorCanMove && valuesEnumeratorCanMove;
  54.         }
  55.  
  56.         public void Reset()
  57.         {
  58.             keysEnumerator.Reset();
  59.             valuesEnumerator.Reset();
  60.         }
  61.     }
  62.  
  63.     private NativeList<TKey> m_Keys = new NativeList<TKey>(64, Allocator.Persistent);
  64.     private NativeList<TValue> m_Values = new NativeList<TValue>(64, Allocator.Persistent);
  65.     private NativeList<TKey> m_KeysAtLastReset = new NativeList<TKey>(64, Allocator.Persistent);
  66.     private NativeList<TValue> m_ValuesAtLastReset = new NativeList<TValue>(64, Allocator.Persistent);
  67.     private NativeList<NetworkDictionaryEvent<TKey, TValue>> m_DirtyEvents = new NativeList<NetworkDictionaryEvent<TKey, TValue>>(64, Allocator.Persistent);
  68.  
  69.     /// <summary>
  70.     /// Delegate type for dictionary changed event
  71.     /// </summary>
  72.     /// <param name="changeEvent">Struct containing information about the change event</param>
  73.     public delegate void OnDictionaryChangedDelegate(NetworkDictionaryEvent<TKey, TValue> changeEvent);
  74.  
  75.     /// <summary>
  76.     /// The callback to be invoked when the dictionary gets changed
  77.     /// </summary>
  78.     public event OnDictionaryChangedDelegate OnDictionaryChanged;
  79.  
  80.     /// <summary>
  81.     /// Creates a NetworkDictionary with the default value and settings
  82.     /// </summary>
  83.     public NetworkDictionary() { }
  84.  
  85.     /// <summary>
  86.     /// Creates a NetworkDictionary with the default value and custom settings
  87.     /// </summary>
  88.     /// <param name="readPerm">The read permission to use for the NetworkDictionary</param>
  89.     /// <param name="values">The initial value to use for the NetworkDictionary</param>
  90.     public NetworkDictionary(NetworkVariableReadPermission readPerm, IDictionary<TKey, TValue> values) : base(readPerm)
  91.     {
  92.         foreach (var pair in values)
  93.         {
  94.             m_Keys.Add(pair.Key);
  95.             m_Values.Add(pair.Value);
  96.         }
  97.     }
  98.  
  99.     /// <summary>
  100.     /// Creates a NetworkDictionary with a custom value and custom settings
  101.     /// </summary>
  102.     /// <param name="values">The initial value to use for the NetworkDictionary</param>
  103.     public NetworkDictionary(IDictionary<TKey, TValue> values)
  104.     {
  105.         foreach (var pair in values)
  106.         {
  107.             m_Keys.Add(pair.Key);
  108.             m_Values.Add(pair.Value);
  109.         }
  110.     }
  111.  
  112.     /// <inheritdoc />
  113.     public override void ResetDirty()
  114.     {
  115.         base.ResetDirty();
  116.  
  117.         if (m_DirtyEvents.Length > 0)
  118.         {
  119.             m_DirtyEvents.Clear();
  120.             m_KeysAtLastReset.CopyFrom(m_Keys);
  121.             m_ValuesAtLastReset.CopyFrom(m_Values);
  122.         }
  123.     }
  124.  
  125.     /// <inheritdoc />
  126.     public override bool IsDirty() => base.IsDirty() || m_DirtyEvents.Length > 0;
  127.  
  128.     /// <inheritdoc />
  129.     public override void WriteDelta(FastBufferWriter writer)
  130.     {
  131.         if (base.IsDirty())
  132.         {
  133.             writer.WriteValueSafe((ushort)1);
  134.             writer.WriteValueSafe(NetworkDictionaryEvent<TKey, TValue>.EventType.Full);
  135.             WriteField(writer);
  136.  
  137.             return;
  138.         }
  139.  
  140.         writer.WriteValueSafe((ushort)m_DirtyEvents.Length);
  141.  
  142.         for (int i = 0; i < m_DirtyEvents.Length; i++)
  143.         {
  144.             var element = m_DirtyEvents.ElementAt(i);
  145.             writer.WriteValueSafe(m_DirtyEvents[i].Type);
  146.  
  147.             switch (m_DirtyEvents[i].Type)
  148.             {
  149.                 case NetworkDictionaryEvent<TKey, TValue>.EventType.Add:
  150.                     {
  151.                         NetworkVariableSerialization<TKey>.Write(writer, ref element.Key);
  152.                         NetworkVariableSerialization<TValue>.Write(writer, ref element.Value);
  153.                     }
  154.                     break;
  155.                 case NetworkDictionaryEvent<TKey, TValue>.EventType.Remove:
  156.                     {
  157.                         NetworkVariableSerialization<TKey>.Write(writer, ref element.Key);
  158.                     }
  159.                     break;
  160.                 case NetworkDictionaryEvent<TKey, TValue>.EventType.Value:
  161.                     {
  162.                         NetworkVariableSerialization<TKey>.Write(writer, ref element.Key);
  163.                         NetworkVariableSerialization<TValue>.Write(writer, ref element.Value);
  164.                     }
  165.                     break;
  166.                 case NetworkDictionaryEvent<TKey, TValue>.EventType.Clear:
  167.                     {
  168.                     }
  169.                     break;
  170.             }
  171.         }
  172.     }
  173.  
  174.     /// <inheritdoc />
  175.     public override void WriteField(FastBufferWriter writer)
  176.     {
  177.         // The keysAtLastReset and valuesAtLastReset mechanism was put in place to deal with duplicate adds
  178.         // upon initial spawn. However, it causes issues with in-scene placed objects
  179.         // due to difference in spawn order. In order to address this, we pick the right
  180.         // list based on the type of object.
  181.         bool isSceneObject = GetBehaviour().NetworkObject.IsSceneObject != false;
  182.  
  183.         if (isSceneObject)
  184.         {
  185.             writer.WriteValueSafe((ushort)m_KeysAtLastReset.Length);
  186.  
  187.             for (int i = 0; i < m_KeysAtLastReset.Length; i++)
  188.             {
  189.                 NetworkVariableSerialization<TKey>.Write(writer, ref m_KeysAtLastReset.ElementAt(i));
  190.                 NetworkVariableSerialization<TValue>.Write(writer, ref m_ValuesAtLastReset.ElementAt(i));
  191.             }
  192.         }
  193.         else
  194.         {
  195.             writer.WriteValueSafe((ushort)m_Keys.Length);
  196.  
  197.             for (int i = 0; i < m_Keys.Length; i++)
  198.             {
  199.                 NetworkVariableSerialization<TKey>.Write(writer, ref m_Keys.ElementAt(i));
  200.                 NetworkVariableSerialization<TValue>.Write(writer, ref m_Values.ElementAt(i));
  201.             }
  202.         }
  203.     }
  204.  
  205.     /// <inheritdoc />
  206.     public override void ReadField(FastBufferReader reader)
  207.     {
  208.         m_Keys.Clear();
  209.         m_Values.Clear();
  210.  
  211.         reader.ReadValueSafe(out ushort count);
  212.  
  213.         for (int i = 0; i < count; i++)
  214.         {
  215.             TKey key = new();
  216.             TValue value = new();
  217.             NetworkVariableSerialization<TKey>.Read(reader, ref key);
  218.             NetworkVariableSerialization<TValue>.Read(reader, ref value);
  219.             m_Keys.Add(key);
  220.             m_Values.Add(value);
  221.         }
  222.     }
  223.  
  224.     /// <inheritdoc />
  225.     public override void ReadDelta(FastBufferReader reader, bool keepDirtyDelta)
  226.     {
  227.         reader.ReadValueSafe(out ushort deltaCount);
  228.  
  229.         for (int i = 0; i < deltaCount; i++)
  230.         {
  231.             reader.ReadValueSafe(out NetworkDictionaryEvent<TKey, TValue>.EventType eventType);
  232.  
  233.             switch (eventType)
  234.             {
  235.                 case NetworkDictionaryEvent<TKey, TValue>.EventType.Add:
  236.                     {
  237.                         TKey key = new();
  238.                         TValue value = new();
  239.                         NetworkVariableSerialization<TKey>.Read(reader, ref key);
  240.                         NetworkVariableSerialization<TValue>.Read(reader, ref value);
  241.  
  242.                         if (m_Keys.Contains(key))
  243.                         {
  244.                             throw new Exception("Shouldn't be here, key already exists in dictionary");
  245.                         }
  246.  
  247.                         m_Keys.Add(key);
  248.                         m_Values.Add(value);
  249.  
  250.                         OnDictionaryChanged?.Invoke(new NetworkDictionaryEvent<TKey, TValue>
  251.                         {
  252.                             Type = eventType,
  253.                             Key = key,
  254.                             Value = value
  255.                         });
  256.  
  257.                         if (keepDirtyDelta)
  258.                         {
  259.                             m_DirtyEvents.Add(new NetworkDictionaryEvent<TKey, TValue>()
  260.                             {
  261.                                 Type = eventType,
  262.                                 Key = key,
  263.                                 Value = value
  264.                             });
  265.                         }
  266.                     }
  267.                     break;
  268.                 case NetworkDictionaryEvent<TKey, TValue>.EventType.Remove:
  269.                     {
  270.                         TKey key = new();
  271.                         NetworkVariableSerialization<TKey>.Read(reader, ref key);
  272.                         var index = m_Keys.IndexOf(key);
  273.  
  274.                         if (index == -1)
  275.                         {
  276.                             break;
  277.                         }
  278.  
  279.                         var value = m_Values.ElementAt(index);
  280.                         m_Keys.RemoveAt(index);
  281.                         m_Values.RemoveAt(index);
  282.  
  283.                         OnDictionaryChanged?.Invoke(new NetworkDictionaryEvent<TKey, TValue>
  284.                         {
  285.                             Type = eventType,
  286.                             Key = key,
  287.                             Value = value
  288.                         });
  289.  
  290.                         if (keepDirtyDelta)
  291.                         {
  292.                             m_DirtyEvents.Add(new NetworkDictionaryEvent<TKey, TValue>()
  293.                             {
  294.                                 Type = eventType,
  295.                                 Key = key,
  296.                                 Value = value
  297.                             });
  298.                         }
  299.                     }
  300.                     break;
  301.                 case NetworkDictionaryEvent<TKey, TValue>.EventType.Value:
  302.                     {
  303.                         TKey key = new();
  304.                         TValue value = new();
  305.                         NetworkVariableSerialization<TKey>.Read(reader, ref key);
  306.                         NetworkVariableSerialization<TValue>.Read(reader, ref value);
  307.                         var index = m_Keys.IndexOf(key);
  308.  
  309.                         if (index == -1)
  310.                         {
  311.                             throw new Exception("Shouldn't be here, key doesn't exist in dictionary");
  312.                         }
  313.  
  314.                         var previousValue = m_Values.ElementAt(index);
  315.                         m_Values[index] = value;
  316.  
  317.                         OnDictionaryChanged?.Invoke(new NetworkDictionaryEvent<TKey, TValue>
  318.                         {
  319.                             Type = eventType,
  320.                             Key = key,
  321.                             Value = value,
  322.                             PreviousValue = previousValue
  323.                         });
  324.  
  325.                         if (keepDirtyDelta)
  326.                         {
  327.                             m_DirtyEvents.Add(new NetworkDictionaryEvent<TKey, TValue>()
  328.                             {
  329.                                 Type = eventType,
  330.                                 Key = key,
  331.                                 Value = value,
  332.                                 PreviousValue = previousValue
  333.                             });
  334.                         }
  335.                     }
  336.                     break;
  337.                 case NetworkDictionaryEvent<TKey, TValue>.EventType.Clear:
  338.                     {
  339.                         m_Keys.Clear();
  340.                         m_Values.Clear();
  341.  
  342.                         OnDictionaryChanged?.Invoke(new NetworkDictionaryEvent<TKey, TValue>
  343.                         {
  344.                             Type = eventType
  345.                         });
  346.  
  347.                         if (keepDirtyDelta)
  348.                         {
  349.                             m_DirtyEvents.Add(new NetworkDictionaryEvent<TKey, TValue>
  350.                             {
  351.                                 Type = eventType
  352.                             });
  353.                         }
  354.                     }
  355.                     break;
  356.             }
  357.         }
  358.     }
  359.  
  360.     /// <inheritdoc />
  361.     public IEnumerator<(TKey Key, TValue Value)> GetEnumerator() => new Enumerator(ref m_Keys, ref m_Values);
  362.  
  363.     /// <inheritdoc />
  364.     public void Add(TKey key, TValue value)
  365.     {
  366.         if (m_Keys.Contains(key))
  367.         {
  368.             throw new Exception("Shouldn't be here, key already exists in dictionary");
  369.         }
  370.  
  371.         m_Keys.Add(key);
  372.         m_Values.Add(value);
  373.  
  374.         var dictionaryEvent = new NetworkDictionaryEvent<TKey, TValue>()
  375.         {
  376.             Type = NetworkDictionaryEvent<TKey, TValue>.EventType.Add,
  377.             Key = key,
  378.             Value = value
  379.         };
  380.  
  381.         HandleAddDictionaryEvent(dictionaryEvent);
  382.     }
  383.  
  384.     /// <inheritdoc />
  385.     public void Clear()
  386.     {
  387.         m_Keys.Clear();
  388.         m_Values.Clear();
  389.  
  390.         var dictionaryEvent = new NetworkDictionaryEvent<TKey, TValue>()
  391.         {
  392.             Type = NetworkDictionaryEvent<TKey, TValue>.EventType.Clear
  393.         };
  394.  
  395.         HandleAddDictionaryEvent(dictionaryEvent);
  396.     }
  397.  
  398.     /// <inheritdoc />
  399.     public bool ContainsKey(TKey key) => m_Keys.Contains(key);
  400.  
  401.     /// <inheritdoc />
  402.     public bool Remove(TKey key)
  403.     {
  404.         var index = m_Keys.IndexOf(key);
  405.  
  406.         if (index == -1)
  407.         {
  408.             return false;
  409.         }
  410.  
  411.         var value = m_Values[index];
  412.         m_Keys.RemoveAt(index);
  413.         m_Values.RemoveAt(index);
  414.  
  415.         var dictionaryEvent = new NetworkDictionaryEvent<TKey, TValue>()
  416.         {
  417.             Type = NetworkDictionaryEvent<TKey, TValue>.EventType.Remove,
  418.             Key = key,
  419.             Value = value
  420.         };
  421.  
  422.         HandleAddDictionaryEvent(dictionaryEvent);
  423.  
  424.         return true;
  425.     }
  426.  
  427.     /// <inheritdoc />
  428.     public bool TryGetValue(TKey key, out TValue value)
  429.     {
  430.         var index = m_Keys.IndexOf(key);
  431.  
  432.         if (index == -1)
  433.         {
  434.             value = default;
  435.             return false;
  436.         }
  437.  
  438.         value = m_Values[index];
  439.         return true;
  440.     }
  441.  
  442.     /// <inheritdoc />
  443.     public int Count => m_Keys.Length;
  444.  
  445.     /// <inheritdoc />
  446.     public IEnumerable<TKey> Keys => m_Keys.ToArray();
  447.  
  448.     /// <inheritdoc />
  449.     public IEnumerable<TValue> Values => m_Values.ToArray();
  450.  
  451.     /// <inheritdoc />
  452.     public TValue this[TKey key]
  453.     {
  454.         get
  455.         {
  456.             var index = m_Keys.IndexOf(key);
  457.  
  458.             if (index == -1)
  459.             {
  460.                 throw new Exception("Shouldn't be here, key doesn't exist in dictionary");
  461.             }
  462.  
  463.             return m_Values[index];
  464.         }
  465.         set
  466.         {
  467.             var index = m_Keys.IndexOf(key);
  468.  
  469.             if (index == -1)
  470.             {
  471.                 Add(key, value);
  472.                 return;
  473.             }
  474.  
  475.             m_Values[index] = value;
  476.  
  477.             var dictionaryEvent = new NetworkDictionaryEvent<TKey, TValue>()
  478.             {
  479.                 Type = NetworkDictionaryEvent<TKey, TValue>.EventType.Value,
  480.                 Key = key,
  481.                 Value = value
  482.             };
  483.  
  484.             HandleAddDictionaryEvent(dictionaryEvent);
  485.         }
  486.     }
  487.  
  488.     private void HandleAddDictionaryEvent(NetworkDictionaryEvent<TKey, TValue> dictionaryEvent)
  489.     {
  490.         m_DirtyEvents.Add(dictionaryEvent);
  491.         MarkNetworkObjectDirty();
  492.         OnDictionaryChanged?.Invoke(dictionaryEvent);
  493.     }
  494.     internal void MarkNetworkObjectDirty()
  495.     {
  496.         SetDirty(true);
  497.     }
  498.  
  499.     public override void Dispose()
  500.     {
  501.         m_Keys.Dispose();
  502.         m_Values.Dispose();
  503.         m_KeysAtLastReset.Dispose();
  504.         m_ValuesAtLastReset.Dispose();
  505.         m_DirtyEvents.Dispose();
  506.         base.Dispose();
  507.     }
  508.  
  509.     public IEnumerable<KeyValuePair<TKey, TValue>> KeyValuePairs()
  510.     {
  511.         foreach (var key in Keys)
  512.         {
  513.             yield return new KeyValuePair<TKey, TValue>(key, this[key]);
  514.         }
  515.     }
  516.  
  517.     IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
  518.     {
  519.         return KeyValuePairs().GetEnumerator();
  520.     }
  521.  
  522.     IEnumerator IEnumerable.GetEnumerator()
  523.     {
  524.         return KeyValuePairs().GetEnumerator();
  525.     }
  526. }
  527.  
  528. /// <summary>
  529. /// Struct containing event information about changes to a NetworkDictionary.
  530. /// </summary>
  531. /// <typeparam name="TKey">The type for the dictionary key that the event is about</typeparam>
  532. /// <typeparam name="TValue">The type for the dictionary value that the event is about</typeparam>
  533. public struct NetworkDictionaryEvent<TKey, TValue>
  534. {
  535.     /// <summary>
  536.     /// Enum representing the different operations available for triggering an event.
  537.     /// </summary>
  538.     public enum EventType : byte
  539.     {
  540.         /// <summary>
  541.         /// Add
  542.         /// </summary>
  543.         Add = 0,
  544.  
  545.         /// <summary>
  546.         /// Remove
  547.         /// </summary>
  548.         Remove = 1,
  549.  
  550.         /// <summary>
  551.         /// Value changed
  552.         /// </summary>
  553.         Value = 2,
  554.  
  555.         /// <summary>
  556.         /// Clear
  557.         /// </summary>
  558.         Clear = 3,
  559.  
  560.         /// <summary>
  561.         /// Full dictionary refresh
  562.         /// </summary>
  563.         Full = 4
  564.     }
  565.  
  566.     /// <summary>
  567.     /// Enum representing the operation made to the dictionary.
  568.     /// </summary>
  569.     public EventType Type;
  570.  
  571.     /// <summary>
  572.     /// the key changed, added or removed if available.
  573.     /// </summary>
  574.     public TKey Key;
  575.  
  576.     /// <summary>
  577.     /// The value changed, added or removed if available.
  578.     /// </summary>
  579.     public TValue Value;
  580.  
  581.     /// <summary>
  582.     /// The previous value when "Value" has changed, if available.
  583.     /// </summary>
  584.     public TValue PreviousValue;
  585. }
  586.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement