diff --git a/engine/Sandbox.Engine/Scene/Networking/Containers/NetDictionary.cs b/engine/Sandbox.Engine/Scene/Networking/Containers/NetDictionary.cs
index 663fd8db..9c688e62 100644
--- a/engine/Sandbox.Engine/Scene/Networking/Containers/NetDictionary.cs
+++ b/engine/Sandbox.Engine/Scene/Networking/Containers/NetDictionary.cs
@@ -4,6 +4,18 @@ using System.Collections.Specialized;
namespace Sandbox;
+///
+/// Describes a change to a which is passed to
+/// whenever its contents change.
+///
+public struct NetDictionaryChangeEvent
+{
+ public NotifyCollectionChangedAction Type { get; set; }
+ public TKey Key { get; set; }
+ public TValue NewValue { get; set; }
+ public TValue OldValue { get; set; }
+}
+
///
/// A networkable dictionary for use with the and . Only changes will be
/// networked instead of sending the whole dictionary every time, so it's more efficient.
@@ -36,34 +48,39 @@ public sealed class NetDictionary : INetworkSerializer, INetworkRe
public TValue Value { get; set; }
}
- private readonly ObservableDictionary dictionary = new();
- private readonly List changes = new();
+ ///
+ /// Get notified when the dictionary is changed.
+ ///
+ public Action> OnChanged;
+
+ private readonly ObservableDictionary _dictionary = new();
+ private readonly List _changes = new();
bool ICollection>.IsReadOnly => false;
bool IDictionary.IsReadOnly => false;
bool IDictionary.IsFixedSize => false;
bool ICollection.IsSynchronized => false;
object ICollection.SyncRoot => this;
- ICollection IDictionary.Values => (ICollection)dictionary.Values;
- ICollection IDictionary.Keys => (ICollection)dictionary.Keys;
+ ICollection IDictionary.Values => (ICollection)_dictionary.Values;
+ ICollection IDictionary.Keys => (ICollection)_dictionary.Keys;
- IEnumerable IReadOnlyDictionary.Values => dictionary.Values;
- IEnumerable IReadOnlyDictionary.Keys => dictionary.Keys;
+ IEnumerable IReadOnlyDictionary.Values => _dictionary.Values;
+ IEnumerable IReadOnlyDictionary.Keys => _dictionary.Keys;
///
///
///
- public ICollection Values => dictionary.Values;
+ public ICollection Values => _dictionary.Values;
public NetDictionary()
{
- dictionary.CollectionChanged += OnCollectionChanged;
+ _dictionary.CollectionChanged += OnCollectionChanged;
AddResetChange();
}
public void Dispose()
{
- changes.Clear();
+ _changes.Clear();
}
///
@@ -71,7 +88,7 @@ public sealed class NetDictionary : INetworkSerializer, INetworkRe
///
void ICollection.CopyTo( Array array, int index )
{
- (dictionary as ICollection).CopyTo( array, index );
+ (_dictionary as ICollection).CopyTo( array, index );
}
///
@@ -106,7 +123,7 @@ public sealed class NetDictionary : INetworkSerializer, INetworkRe
if ( !CanWriteChanges() )
return;
- dictionary.Add( key, value );
+ _dictionary.Add( key, value );
}
///
@@ -117,7 +134,7 @@ public sealed class NetDictionary : INetworkSerializer, INetworkRe
if ( !CanWriteChanges() )
return;
- dictionary.Add( item );
+ _dictionary.Add( item );
}
///
@@ -128,7 +145,7 @@ public sealed class NetDictionary : INetworkSerializer, INetworkRe
if ( !CanWriteChanges() )
return;
- dictionary.Clear();
+ _dictionary.Clear();
}
///
@@ -136,7 +153,7 @@ public sealed class NetDictionary : INetworkSerializer, INetworkRe
///
public bool ContainsKey( TKey key )
{
- return dictionary.ContainsKey( key );
+ return _dictionary.ContainsKey( key );
}
///
@@ -144,7 +161,7 @@ public sealed class NetDictionary : INetworkSerializer, INetworkRe
///
public bool Contains( KeyValuePair item )
{
- return dictionary.Contains( item );
+ return _dictionary.Contains( item );
}
///
@@ -152,12 +169,12 @@ public sealed class NetDictionary : INetworkSerializer, INetworkRe
///
public void CopyTo( KeyValuePair[] array, int arrayIndex )
{
- dictionary.CopyTo( array, arrayIndex );
+ _dictionary.CopyTo( array, arrayIndex );
}
public bool Remove( KeyValuePair item )
{
- return CanWriteChanges() && dictionary.Remove( item );
+ return CanWriteChanges() && _dictionary.Remove( item );
}
///
@@ -165,7 +182,7 @@ public sealed class NetDictionary : INetworkSerializer, INetworkRe
///
public ICollection Keys
{
- get { return dictionary.Keys; }
+ get { return _dictionary.Keys; }
}
///
@@ -176,31 +193,31 @@ public sealed class NetDictionary : INetworkSerializer, INetworkRe
if ( !CanWriteChanges() )
return false;
- return dictionary.Remove( key );
+ return _dictionary.Remove( key );
}
///
///
///
- public bool TryGetValue( TKey key, out TValue value ) => dictionary.TryGetValue( key, out value );
+ public bool TryGetValue( TKey key, out TValue value ) => _dictionary.TryGetValue( key, out value );
///
///
///
- public int Count => dictionary.Count;
+ public int Count => _dictionary.Count;
public TValue this[TKey key]
{
get
{
- return dictionary[key];
+ return _dictionary[key];
}
set
{
if ( !CanWriteChanges() )
return;
- dictionary[key] = value;
+ _dictionary[key] = value;
}
}
@@ -215,7 +232,7 @@ public sealed class NetDictionary : INetworkSerializer, INetworkRe
///
IDictionaryEnumerator IDictionary.GetEnumerator()
{
- return ((IDictionary)dictionary).GetEnumerator();
+ return ((IDictionary)_dictionary).GetEnumerator();
}
///
@@ -223,7 +240,7 @@ public sealed class NetDictionary : INetworkSerializer, INetworkRe
///
public IEnumerator> GetEnumerator()
{
- return dictionary.GetEnumerator();
+ return _dictionary.GetEnumerator();
}
///
@@ -231,7 +248,7 @@ public sealed class NetDictionary : INetworkSerializer, INetworkRe
///
IEnumerator IEnumerable.GetEnumerator()
{
- return ((IEnumerable)dictionary).GetEnumerator();
+ return ((IEnumerable)_dictionary).GetEnumerator();
}
private INetworkProxy Parent { get; set; }
@@ -244,7 +261,7 @@ public sealed class NetDictionary : INetworkSerializer, INetworkRe
///
/// Do we have any pending changes?
///
- bool INetworkSerializer.HasChanges => changes.Count > 0;
+ bool INetworkSerializer.HasChanges => _changes.Count > 0;
///
/// Write any changed items to a .
@@ -255,9 +272,9 @@ public sealed class NetDictionary : INetworkSerializer, INetworkRe
{
// We are sending changes, not a full update. This flag indicates that.
data.Write( false );
- data.Write( changes.Count );
+ data.Write( _changes.Count );
- foreach ( var change in changes )
+ foreach ( var change in _changes )
{
data.Write( change.Type );
WriteValue( change.Key, ref data );
@@ -269,7 +286,7 @@ public sealed class NetDictionary : INetworkSerializer, INetworkRe
Log.Warning( e, $"Error when writing NetDictionary changes - {e.Message}" );
}
- changes.Clear();
+ _changes.Clear();
}
///
@@ -292,7 +309,7 @@ public sealed class NetDictionary : INetworkSerializer, INetworkRe
}
// Clear changes whenever we read data. We don't want to keep local changes.
- changes.Clear();
+ _changes.Clear();
}
///
@@ -304,9 +321,9 @@ public sealed class NetDictionary : INetworkSerializer, INetworkRe
{
// We are sending a full update. This flag indicates that.
data.Write( true );
- data.Write( dictionary.Count );
+ data.Write( _dictionary.Count );
- foreach ( var (k, v) in dictionary )
+ foreach ( var (k, v) in _dictionary )
{
WriteValue( k, ref data );
WriteValue( v, ref data );
@@ -323,7 +340,7 @@ public sealed class NetDictionary : INetworkSerializer, INetworkRe
///
private void ReadAll( ref ByteStream data )
{
- dictionary.Clear();
+ _dictionary.Clear();
var count = data.Read();
@@ -334,7 +351,7 @@ public sealed class NetDictionary : INetworkSerializer, INetworkRe
if ( key is null ) continue;
- dictionary[key] = value;
+ _dictionary[key] = value;
}
}
@@ -353,7 +370,7 @@ public sealed class NetDictionary : INetworkSerializer, INetworkRe
if ( type == NotifyCollectionChangedAction.Reset )
{
- dictionary.Clear();
+ _dictionary.Clear();
}
else if ( key is null )
{
@@ -361,21 +378,42 @@ public sealed class NetDictionary : INetworkSerializer, INetworkRe
}
else if ( type == NotifyCollectionChangedAction.Add )
{
- dictionary.Add( key, value );
+ _dictionary.Add( key, value );
}
else if ( type == NotifyCollectionChangedAction.Remove )
{
- dictionary.Remove( key );
+ _dictionary.Remove( key );
}
else if ( type == NotifyCollectionChangedAction.Replace )
{
- dictionary[key] = value;
+ _dictionary[key] = value;
}
}
}
private void OnCollectionChanged( object sender, NotifyCollectionChangedEventArgs e )
{
+ var changeEvent = new NetDictionaryChangeEvent
+ {
+ Type = e.Action
+ };
+
+ if ( e.OldItems is not null && e.OldItems.Count > 0 )
+ {
+ var (k, oldValue) = (KeyValuePair)e.OldItems[0];
+ changeEvent.OldValue = oldValue;
+ changeEvent.Key = k;
+ }
+
+ if ( e.NewItems is not null && e.NewItems.Count > 0 )
+ {
+ var (k, newValue) = (KeyValuePair)e.NewItems[0];
+ changeEvent.NewValue = newValue;
+ changeEvent.Key = k;
+ }
+
+ OnChanged?.InvokeWithWarning( changeEvent );
+
if ( !CanWriteChanges() )
return;
@@ -383,13 +421,13 @@ public sealed class NetDictionary : INetworkSerializer, INetworkRe
{
var (k, v) = (KeyValuePair)e.NewItems[0];
var change = new Change { Key = k, Value = v, Type = e.Action };
- changes.Add( change );
+ _changes.Add( change );
}
else if ( e.Action == NotifyCollectionChangedAction.Remove )
{
- var (k, v) = (KeyValuePair)e.NewItems[0];
+ var (k, v) = (KeyValuePair)e.OldItems[0];
var change = new Change { Key = k, Type = e.Action };
- changes.Add( change );
+ _changes.Add( change );
}
else if ( e.Action == NotifyCollectionChangedAction.Reset )
{
@@ -397,19 +435,19 @@ public sealed class NetDictionary : INetworkSerializer, INetworkRe
}
else if ( e.Action == NotifyCollectionChangedAction.Replace )
{
- var (k, v) = (KeyValuePair)e.NewItems[0];
- var change = new Change { Key = k, Type = e.Action, Value = v };
- changes.Add( change );
+ var (k, newValue) = (KeyValuePair)e.NewItems[0];
+ var change = new Change { Key = k, Type = e.Action, Value = newValue };
+ _changes.Add( change );
}
}
- private T ReadValue( ref ByteStream data )
+ private static T ReadValue( ref ByteStream data )
{
var value = Game.TypeLibrary.FromBytes