feat(SyncDictionary): Add individual Actions for operations (#3791)

This commit is contained in:
MrGadget 2024-03-22 22:44:52 -04:00 committed by GitHub
parent b59fa3511e
commit 81238b69d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 145 additions and 14 deletions

View File

@ -6,6 +6,20 @@ namespace Mirror
{ {
public class SyncIDictionary<TKey, TValue> : SyncObject, IDictionary<TKey, TValue>, IReadOnlyDictionary<TKey, TValue> public class SyncIDictionary<TKey, TValue> : SyncObject, IDictionary<TKey, TValue>, IReadOnlyDictionary<TKey, TValue>
{ {
/// <summary>This is called after the item is added with TKey</summary>
public Action<TKey> OnAdd;
/// <summary>This is called after the item is changed with TKey. TValue is the OLD item</summary>
public Action<TKey, TValue> OnSet;
/// <summary>This is called after the item is removed with TKey. TValue is the OLD item</summary>
public Action<TKey, TValue> OnRemove;
/// <summary>This is called before the data is cleared</summary>
public Action OnClear;
// Deprecated 2024-03-22
[Obsolete("Use individual Actions, which pass OLD values where appropriate, instead.")]
public Action<Operation, TKey, TValue> Callback; public Action<Operation, TKey, TValue> Callback;
protected readonly IDictionary<TKey, TValue> objects; protected readonly IDictionary<TKey, TValue> objects;
@ -83,7 +97,25 @@ void AddOperation(Operation op, TKey key, TValue item, TValue oldItem, bool chec
OnDirty?.Invoke(); OnDirty?.Invoke();
} }
switch (op)
{
case Operation.OP_ADD:
OnAdd?.Invoke(key);
break;
case Operation.OP_SET:
OnSet?.Invoke(key, oldItem);
break;
case Operation.OP_REMOVE:
OnRemove?.Invoke(key, oldItem);
break;
case Operation.OP_CLEAR:
OnClear?.Invoke();
break;
}
#pragma warning disable CS0618 // Type or member is obsolete
Callback?.Invoke(op, key, item); Callback?.Invoke(op, key, item);
#pragma warning restore CS0618 // Type or member is obsolete
} }
public override void OnSerializeAll(NetworkWriter writer) public override void OnSerializeAll(NetworkWriter writer)

View File

@ -58,7 +58,9 @@ IEnumerator AddPlayersToMatchController()
public override void OnStartClient() public override void OnStartClient()
{ {
matchPlayerData.Callback += UpdateWins; #pragma warning disable CS0618 // Type or member is obsolete
matchPlayerData.Callback = UpdateWins;
#pragma warning restore CS0618 // Type or member is obsolete
canvasGroup.alpha = 1f; canvasGroup.alpha = 1f;
canvasGroup.interactable = true; canvasGroup.interactable = true;

View File

@ -80,72 +80,131 @@ public void CurlyBracesConstructor()
public void TestAdd() public void TestAdd()
{ {
// Adds a new entry with index of 4 using .Add method // Adds a new entry with index of 4 using .Add method
#pragma warning disable 618 // Type or member is obsolete
bool called = false;
clientSyncDictionary.Callback = (op, key, item) =>
{
called = true;
Assert.That(op, Is.EqualTo(SyncDictionary<int, string>.Operation.OP_ADD));
Assert.That(key, Is.EqualTo(4));
Assert.That(item, Is.EqualTo("yay"));
Assert.That(clientSyncDictionary[key], Is.EqualTo("yay"));
};
#pragma warning restore 618 // Type or member is obsolete
bool actionCalled = false;
clientSyncDictionary.OnAdd = (key) =>
{
actionCalled = true;
Assert.That(key, Is.EqualTo(4));
Assert.That(clientSyncDictionary[key], Is.EqualTo("yay"));
};
serverSyncDictionary.Add(4, "yay"); serverSyncDictionary.Add(4, "yay");
SerializeDeltaTo(serverSyncDictionary, clientSyncDictionary); SerializeDeltaTo(serverSyncDictionary, clientSyncDictionary);
Assert.That(clientSyncDictionary.ContainsKey(4)); Assert.That(clientSyncDictionary.ContainsKey(4));
Assert.That(clientSyncDictionary[4], Is.EqualTo("yay")); Assert.That(clientSyncDictionary[4], Is.EqualTo("yay"));
Assert.That(called, Is.True);
Assert.That(actionCalled, Is.True);
} }
[Test] [Test]
public void TestClear() public void TestClear()
{ {
// Verifies that the clear method works and that the data is still present for the Callback. // Verifies that the clear method works and that the data is still present for the Callback.
#pragma warning disable 618 // Type or member is obsolete
bool called = false; bool called = false;
clientSyncDictionary.Callback = (op, index, item) => clientSyncDictionary.Callback = (op, key, item) =>
{ {
called = true; called = true;
Assert.That(op, Is.EqualTo(SyncDictionary<int, string>.Operation.OP_CLEAR)); Assert.That(op, Is.EqualTo(SyncDictionary<int, string>.Operation.OP_CLEAR));
Assert.That(clientSyncDictionary.Count, Is.EqualTo(3)); Assert.That(clientSyncDictionary.Count, Is.EqualTo(3));
}; };
#pragma warning restore 618 // Type or member is obsolete
bool actionCalled = false;
clientSyncDictionary.OnClear = () =>
{
actionCalled = true;
Assert.That(clientSyncDictionary.Count, Is.EqualTo(3));
};
serverSyncDictionary.Clear(); serverSyncDictionary.Clear();
SerializeDeltaTo(serverSyncDictionary, clientSyncDictionary); SerializeDeltaTo(serverSyncDictionary, clientSyncDictionary);
Assert.That(serverSyncDictionary, Is.EquivalentTo(new SyncDictionary<int, string>())); Assert.That(serverSyncDictionary, Is.EquivalentTo(new SyncDictionary<int, string>()));
Assert.That(called, Is.True); Assert.That(called, Is.True);
Assert.That(actionCalled, Is.True);
} }
[Test] [Test]
public void TestSet() public void TestSet()
{ {
// Overwrites an existing entry // Overwrites an existing entry
#pragma warning disable 618 // Type or member is obsolete
bool called = false; bool called = false;
clientSyncDictionary.Callback = (op, index, item) => clientSyncDictionary.Callback = (op, key, item) =>
{ {
called = true; called = true;
Assert.That(op, Is.EqualTo(SyncDictionary<int, string>.Operation.OP_SET)); Assert.That(op, Is.EqualTo(SyncDictionary<int, string>.Operation.OP_SET));
Assert.That(index, Is.EqualTo(1)); Assert.That(key, Is.EqualTo(1));
Assert.That(item, Is.EqualTo("yay")); Assert.That(item, Is.EqualTo("yay"));
Assert.That(clientSyncDictionary[index], Is.EqualTo("yay")); Assert.That(clientSyncDictionary[key], Is.EqualTo("yay"));
}; };
#pragma warning restore 618 // Type or member is obsolete
bool actionCalled = false;
clientSyncDictionary.OnSet = (key, oldItem) =>
{
actionCalled = true;
Assert.That(key, Is.EqualTo(1));
Assert.That(oldItem, Is.EqualTo("World"));
Assert.That(clientSyncDictionary[key], Is.EqualTo("yay"));
};
serverSyncDictionary[1] = "yay"; serverSyncDictionary[1] = "yay";
SerializeDeltaTo(serverSyncDictionary, clientSyncDictionary); SerializeDeltaTo(serverSyncDictionary, clientSyncDictionary);
Assert.That(clientSyncDictionary.ContainsKey(1)); Assert.That(clientSyncDictionary.ContainsKey(1));
Assert.That(clientSyncDictionary[1], Is.EqualTo("yay")); Assert.That(clientSyncDictionary[1], Is.EqualTo("yay"));
Assert.That(called, Is.True); Assert.That(called, Is.True);
Assert.That(actionCalled, Is.True);
} }
[Test] [Test]
public void TestBareSet() public void TestBareSet()
{ {
// Adds a new entry with index of 4 without using .Add method // Adds a new entry with index of 4 without using .Add method
#pragma warning disable 618 // Type or member is obsolete
bool called = false; bool called = false;
clientSyncDictionary.Callback = (op, index, item) => clientSyncDictionary.Callback = (op, key, item) =>
{ {
called = true; called = true;
Assert.That(op, Is.EqualTo(SyncDictionary<int, string>.Operation.OP_ADD)); Assert.That(op, Is.EqualTo(SyncDictionary<int, string>.Operation.OP_ADD));
Assert.That(index, Is.EqualTo(4)); Assert.That(key, Is.EqualTo(4));
Assert.That(item, Is.EqualTo("yay")); Assert.That(item, Is.EqualTo("yay"));
Assert.That(clientSyncDictionary[index], Is.EqualTo("yay")); Assert.That(clientSyncDictionary[key], Is.EqualTo("yay"));
}; };
#pragma warning restore 618 // Type or member is obsolete
bool actionCalled = false;
clientSyncDictionary.OnAdd = (key) =>
{
actionCalled = true;
Assert.That(key, Is.EqualTo(4));
Assert.That(clientSyncDictionary[key], Is.EqualTo("yay"));
};
serverSyncDictionary[4] = "yay"; serverSyncDictionary[4] = "yay";
SerializeDeltaTo(serverSyncDictionary, clientSyncDictionary); SerializeDeltaTo(serverSyncDictionary, clientSyncDictionary);
Assert.That(clientSyncDictionary.ContainsKey(4)); Assert.That(clientSyncDictionary.ContainsKey(4));
Assert.That(clientSyncDictionary[4], Is.EqualTo("yay")); Assert.That(clientSyncDictionary[4], Is.EqualTo("yay"));
Assert.That(called, Is.True); Assert.That(called, Is.True);
Assert.That(actionCalled, Is.True);
} }
[Test] [Test]
@ -209,52 +268,90 @@ public void TestContains()
[Test] [Test]
public void CallbackTest() public void CallbackTest()
{ {
#pragma warning disable 618 // Type or member is obsolete
bool called = false; bool called = false;
clientSyncDictionary.Callback = (op, index, item) => clientSyncDictionary.Callback = (op, key, item) =>
{ {
called = true; called = true;
Assert.That(op, Is.EqualTo(SyncDictionary<int, string>.Operation.OP_ADD)); Assert.That(op, Is.EqualTo(SyncDictionary<int, string>.Operation.OP_ADD));
Assert.That(index, Is.EqualTo(3)); Assert.That(key, Is.EqualTo(3));
Assert.That(item, Is.EqualTo("yay")); Assert.That(item, Is.EqualTo("yay"));
Assert.That(clientSyncDictionary[index], Is.EqualTo("yay")); Assert.That(clientSyncDictionary[key], Is.EqualTo("yay"));
}; };
#pragma warning restore 618 // Type or member is obsolete
bool actionCalled = false;
clientSyncDictionary.OnAdd = (key) =>
{
actionCalled = true;
Assert.That(key, Is.EqualTo(3));
Assert.That(clientSyncDictionary[key], Is.EqualTo("yay"));
};
serverSyncDictionary.Add(3, "yay"); serverSyncDictionary.Add(3, "yay");
SerializeDeltaTo(serverSyncDictionary, clientSyncDictionary); SerializeDeltaTo(serverSyncDictionary, clientSyncDictionary);
Assert.That(called, Is.True); Assert.That(called, Is.True);
Assert.That(actionCalled, Is.True);
} }
[Test] [Test]
public void ServerCallbackTest() public void ServerCallbackTest()
{ {
#pragma warning disable 618 // Type or member is obsolete
bool called = false; bool called = false;
serverSyncDictionary.Callback = (op, index, item) => serverSyncDictionary.Callback = (op, key, item) =>
{ {
called = true; called = true;
Assert.That(op, Is.EqualTo(SyncDictionary<int, string>.Operation.OP_ADD)); Assert.That(op, Is.EqualTo(SyncDictionary<int, string>.Operation.OP_ADD));
Assert.That(index, Is.EqualTo(3)); Assert.That(key, Is.EqualTo(3));
Assert.That(item, Is.EqualTo("yay")); Assert.That(item, Is.EqualTo("yay"));
Assert.That(serverSyncDictionary[index], Is.EqualTo("yay")); Assert.That(serverSyncDictionary[key], Is.EqualTo("yay"));
}; };
#pragma warning restore 618 // Type or member is obsolete
bool actionCalled = false;
serverSyncDictionary.OnAdd = (key) =>
{
actionCalled = true;
Assert.That(key, Is.EqualTo(3));
Assert.That(serverSyncDictionary[key], Is.EqualTo("yay"));
};
serverSyncDictionary[3] = "yay"; serverSyncDictionary[3] = "yay";
Assert.That(called, Is.True); Assert.That(called, Is.True);
Assert.That(actionCalled, Is.True);
} }
[Test] [Test]
public void CallbackRemoveTest() public void CallbackRemoveTest()
{ {
#pragma warning disable 618 // Type or member is obsolete
bool called = false; bool called = false;
clientSyncDictionary.Callback = (op, key, item) => clientSyncDictionary.Callback = (op, key, item) =>
{ {
called = true; called = true;
Assert.That(op, Is.EqualTo(SyncDictionary<int, string>.Operation.OP_REMOVE)); Assert.That(op, Is.EqualTo(SyncDictionary<int, string>.Operation.OP_REMOVE));
Assert.That(key, Is.EqualTo(1));
Assert.That(item, Is.EqualTo("World")); Assert.That(item, Is.EqualTo("World"));
}; };
#pragma warning restore 618 // Type or member is obsolete
bool actionCalled = false;
clientSyncDictionary.OnRemove = (key, oldItem) =>
{
actionCalled = true;
Assert.That(key, Is.EqualTo(1));
Assert.That(oldItem, Is.EqualTo("World"));
Assert.That(!clientSyncDictionary.ContainsKey(1));
};
serverSyncDictionary.Remove(1); serverSyncDictionary.Remove(1);
SerializeDeltaTo(serverSyncDictionary, clientSyncDictionary); SerializeDeltaTo(serverSyncDictionary, clientSyncDictionary);
Assert.That(called, Is.True); Assert.That(called, Is.True);
Assert.That(actionCalled, Is.True);
} }
[Test] [Test]