From 824712df9c39b4af33a2cb6a8fe3c34784e02a28 Mon Sep 17 00:00:00 2001
From: MrGadget <9826063+MrGadget1024@users.noreply.github.com>
Date: Sat, 23 Mar 2024 14:54:38 -0400
Subject: [PATCH] feat(SyncList): Add individual Actions for operations (#3794)
---
Assets/Mirror/Core/SyncList.cs | 38 ++++++
.../SyncCollections/SyncListStructTest.cs | 2 +
.../Editor/SyncCollections/SyncListTest.cs | 120 +++++++++++++++++-
3 files changed, 154 insertions(+), 6 deletions(-)
diff --git a/Assets/Mirror/Core/SyncList.cs b/Assets/Mirror/Core/SyncList.cs
index 81d0e4066..20775ad91 100644
--- a/Assets/Mirror/Core/SyncList.cs
+++ b/Assets/Mirror/Core/SyncList.cs
@@ -15,6 +15,23 @@ public enum Operation : byte
OP_CLEAR
}
+ /// This is called after the item is added with index
+ public Action OnAdd;
+
+ /// This is called after the item is inserted with inedx
+ public Action OnInsert;
+
+ /// This is called after the item is set with index and OLD Value
+ public Action OnSet;
+
+ /// This is called after the item is removed with index and OLD Value
+ public Action OnRemove;
+
+ /// This is called before the list is cleared so the list can be iterated
+ public Action OnClear;
+
+ // Deprecated 2024-03-23
+ [Obsolete("Use individual Actions, which pass OLD values where appropriate, instead.")]
public Action Callback;
readonly IList objects;
@@ -85,7 +102,28 @@ void AddOperation(Operation op, int itemIndex, T oldItem, T newItem, bool checkA
OnDirty?.Invoke();
}
+ switch (op)
+ {
+ case Operation.OP_ADD:
+ OnAdd?.Invoke(itemIndex);
+ break;
+ case Operation.OP_INSERT:
+ OnInsert?.Invoke(itemIndex);
+ break;
+ case Operation.OP_SET:
+ OnSet?.Invoke(itemIndex, oldItem);
+ break;
+ case Operation.OP_REMOVEAT:
+ OnRemove?.Invoke(itemIndex, oldItem);
+ break;
+ case Operation.OP_CLEAR:
+ OnClear?.Invoke();
+ break;
+ }
+
+#pragma warning disable CS0618 // Type or member is obsolete
Callback?.Invoke(op, itemIndex, oldItem, newItem);
+#pragma warning restore CS0618 // Type or member is obsolete
}
public override void OnSerializeAll(NetworkWriter writer)
diff --git a/Assets/Mirror/Tests/Editor/SyncCollections/SyncListStructTest.cs b/Assets/Mirror/Tests/Editor/SyncCollections/SyncListStructTest.cs
index d65aaa7be..63ba7cbe4 100644
--- a/Assets/Mirror/Tests/Editor/SyncCollections/SyncListStructTest.cs
+++ b/Assets/Mirror/Tests/Editor/SyncCollections/SyncListStructTest.cs
@@ -47,6 +47,7 @@ public void OldValueShouldNotBeNewValue()
player.item.price = 15;
serverList[0] = player;
+#pragma warning disable 618 // Type or member is obsolete
bool callbackCalled = false;
clientList.Callback = (SyncList.Operation op, int itemIndex, TestPlayer oldItem, TestPlayer newItem) =>
{
@@ -56,6 +57,7 @@ public void OldValueShouldNotBeNewValue()
Assert.That(newItem.item.price, Is.EqualTo(15));
callbackCalled = true;
};
+#pragma warning restore 618 // Type or member is obsolete
SyncListTest.SerializeDeltaTo(serverList, clientList);
Assert.IsTrue(callbackCalled);
diff --git a/Assets/Mirror/Tests/Editor/SyncCollections/SyncListTest.cs b/Assets/Mirror/Tests/Editor/SyncCollections/SyncListTest.cs
index f68b1d991..752237979 100644
--- a/Assets/Mirror/Tests/Editor/SyncCollections/SyncListTest.cs
+++ b/Assets/Mirror/Tests/Editor/SyncCollections/SyncListTest.cs
@@ -97,6 +97,7 @@ public void TestAddRange()
[Test]
public void TestClear()
{
+#pragma warning disable 618 // Type or member is obsolete
bool called = false;
clientSyncList.Callback = (op, index, oldItem, newItem) =>
{
@@ -105,16 +106,26 @@ public void TestClear()
Assert.That(op, Is.EqualTo(SyncList.Operation.OP_CLEAR));
Assert.That(clientSyncList.Count, Is.EqualTo(3));
};
+#pragma warning restore 618 // Type or member is obsolete
+
+ bool actionCalled = false;
+ clientSyncList.OnClear = () =>
+ {
+ actionCalled = true;
+ Assert.That(clientSyncList.Count, Is.EqualTo(3));
+ };
serverSyncList.Clear();
SerializeDeltaTo(serverSyncList, clientSyncList);
Assert.That(clientSyncList, Is.EquivalentTo(new string[] { }));
Assert.That(called, Is.True);
+ Assert.That(actionCalled, Is.True);
}
[Test]
public void TestInsert()
{
+#pragma warning disable 618 // Type or member is obsolete
bool called = false;
clientSyncList.Callback = (op, index, oldItem, newItem) =>
{
@@ -124,11 +135,20 @@ public void TestInsert()
Assert.That(index, Is.EqualTo(0));
Assert.That(newItem, Is.EqualTo("yay"));
};
+#pragma warning restore 618 // Type or member is obsolete
+
+ bool actionCalled = false;
+ clientSyncList.OnInsert = (index) =>
+ {
+ actionCalled = true;
+ Assert.That(index, Is.EqualTo(0));
+ };
serverSyncList.Insert(0, "yay");
SerializeDeltaTo(serverSyncList, clientSyncList);
Assert.That(clientSyncList, Is.EquivalentTo(new[] { "yay", "Hello", "World", "!" }));
Assert.That(called, Is.True);
+ Assert.That(actionCalled, Is.True);
}
[Test]
@@ -142,6 +162,7 @@ public void TestInsertRange()
[Test]
public void TestSet()
{
+#pragma warning disable 618 // Type or member is obsolete
bool called = false;
clientSyncList.Callback = (op, index, oldItem, newItem) =>
{
@@ -152,17 +173,28 @@ public void TestSet()
Assert.That(oldItem, Is.EqualTo("World"));
Assert.That(newItem, Is.EqualTo("yay"));
};
+#pragma warning restore 618 // Type or member is obsolete
+
+ bool actionCalled = false;
+ clientSyncList.OnSet = (index, oldItem) =>
+ {
+ actionCalled = true;
+ Assert.That(index, Is.EqualTo(1));
+ Assert.That(oldItem, Is.EqualTo("World"));
+ };
serverSyncList[1] = "yay";
SerializeDeltaTo(serverSyncList, clientSyncList);
Assert.That(clientSyncList[1], Is.EqualTo("yay"));
Assert.That(clientSyncList, Is.EquivalentTo(new[] { "Hello", "yay", "!" }));
Assert.That(called, Is.True);
+ Assert.That(actionCalled, Is.True);
}
[Test]
public void TestSetNull()
{
+#pragma warning disable 618 // Type or member is obsolete
bool called = false;
clientSyncList.Callback = (op, index, oldItem, newItem) =>
{
@@ -173,15 +205,30 @@ public void TestSetNull()
Assert.That(oldItem, Is.EqualTo("World"));
Assert.That(newItem, Is.EqualTo(null));
};
+#pragma warning restore 618 // Type or member is obsolete
+
+ bool actionCalled = false;
+ clientSyncList.OnSet = (index, oldItem) =>
+ {
+ actionCalled = true;
+ Assert.That(index, Is.EqualTo(1));
+ Assert.That(oldItem, Is.EqualTo("World"));
+ };
serverSyncList[1] = null;
SerializeDeltaTo(serverSyncList, clientSyncList);
Assert.That(clientSyncList[1], Is.EqualTo(null));
Assert.That(clientSyncList, Is.EquivalentTo(new[] { "Hello", null, "!" }));
Assert.That(called, Is.True);
+ Assert.That(actionCalled, Is.True);
+#pragma warning disable 618 // Type or member is obsolete
// clear callback so we don't get called again
clientSyncList.Callback = null;
+#pragma warning restore 618 // Type or member is obsolete
+
+ // clear handlers so we don't get called again
+ clientSyncList.OnSet = null;
serverSyncList[1] = "yay";
SerializeDeltaTo(serverSyncList, clientSyncList);
@@ -191,6 +238,7 @@ public void TestSetNull()
[Test]
public void TestRemoveAll()
{
+#pragma warning disable 618 // Type or member is obsolete
bool called = false;
clientSyncList.Callback = (op, index, oldItem, newItem) =>
{
@@ -201,12 +249,22 @@ public void TestRemoveAll()
Assert.That(oldItem, Is.Not.EqualTo("!"));
Assert.That(newItem, Is.EqualTo(default(string)));
};
+#pragma warning restore 618 // Type or member is obsolete
+
+ bool actionCalled = false;
+ clientSyncList.OnRemove = (index, item) =>
+ {
+ actionCalled = true;
+ Assert.That(index, Is.EqualTo(0));
+ Assert.That(item, Is.Not.EqualTo("!"));
+ };
// This will remove "Hello" and "World"
serverSyncList.RemoveAll(entry => entry.Contains("l"));
SerializeDeltaTo(serverSyncList, clientSyncList);
Assert.That(clientSyncList, Is.EquivalentTo(new[] { "!" }));
Assert.That(called, Is.True);
+ Assert.That(actionCalled, Is.True);
}
[Test]
@@ -220,6 +278,7 @@ public void TestRemoveAllNone()
[Test]
public void TestRemoveAt()
{
+#pragma warning disable 618 // Type or member is obsolete
bool called = false;
clientSyncList.Callback = (op, index, oldItem, newItem) =>
{
@@ -230,16 +289,27 @@ public void TestRemoveAt()
Assert.That(oldItem, Is.EqualTo("World"));
Assert.That(newItem, Is.EqualTo(default(string)));
};
+#pragma warning restore 618 // Type or member is obsolete
+
+ bool actionCalled = false;
+ clientSyncList.OnRemove = (index, oldItem) =>
+ {
+ actionCalled = true;
+ Assert.That(index, Is.EqualTo(1));
+ Assert.That(oldItem, Is.EqualTo("World"));
+ };
serverSyncList.RemoveAt(1);
SerializeDeltaTo(serverSyncList, clientSyncList);
Assert.That(clientSyncList, Is.EquivalentTo(new[] { "Hello", "!" }));
Assert.That(called, Is.True);
+ Assert.That(actionCalled, Is.True);
}
[Test]
public void TestRemove()
{
+#pragma warning disable 618 // Type or member is obsolete
bool called = false;
clientSyncList.Callback = (op, index, oldItem, newItem) =>
{
@@ -250,11 +320,21 @@ public void TestRemove()
Assert.That(oldItem, Is.EqualTo("World"));
Assert.That(newItem, Is.EqualTo(default(string)));
};
+#pragma warning restore 618 // Type or member is obsolete
+
+ bool actionCalled = false;
+ clientSyncList.OnRemove = (index, oldItem) =>
+ {
+ actionCalled = true;
+ Assert.That(index, Is.EqualTo(1));
+ Assert.That(oldItem, Is.EqualTo("World"));
+ };
serverSyncList.Remove("World");
SerializeDeltaTo(serverSyncList, clientSyncList);
Assert.That(clientSyncList, Is.EquivalentTo(new[] { "Hello", "!" }));
Assert.That(called, Is.True);
+ Assert.That(actionCalled, Is.True);
}
[Test]
@@ -362,8 +442,8 @@ public void SyncListFloatTest()
[Test]
public void CallbackTest()
{
+#pragma warning disable 618 // Type or member is obsolete
bool called = false;
-
clientSyncList.Callback = (op, index, oldItem, newItem) =>
{
called = true;
@@ -373,18 +453,27 @@ public void CallbackTest()
Assert.That(oldItem, Is.EqualTo(default(string)));
Assert.That(newItem, Is.EqualTo("yay"));
};
+#pragma warning restore 618 // Type or member is obsolete
+
+ bool actionCalled = false;
+ clientSyncList.OnAdd = (index) =>
+ {
+ actionCalled = true;
+ Assert.That(index, Is.EqualTo(3));
+ Assert.That(clientSyncList[index], Is.EqualTo("yay"));
+ };
serverSyncList.Add("yay");
SerializeDeltaTo(serverSyncList, clientSyncList);
-
Assert.That(called, Is.True);
+ Assert.That(actionCalled, Is.True);
}
[Test]
public void CallbackRemoveTest()
{
+#pragma warning disable 618 // Type or member is obsolete
bool called = false;
-
clientSyncList.Callback = (op, index, oldItem, newItem) =>
{
called = true;
@@ -393,17 +482,27 @@ public void CallbackRemoveTest()
Assert.That(oldItem, Is.EqualTo("World"));
Assert.That(newItem, Is.EqualTo(default(string)));
};
+#pragma warning restore 618 // Type or member is obsolete
+
+ bool actionCalled = false;
+ clientSyncList.OnRemove = (index, oldItem) =>
+ {
+ actionCalled = true;
+ Assert.That(index, Is.EqualTo(1));
+ Assert.That(oldItem, Is.EqualTo("World"));
+ };
+
serverSyncList.Remove("World");
SerializeDeltaTo(serverSyncList, clientSyncList);
-
Assert.That(called, Is.True);
+ Assert.That(actionCalled, Is.True);
}
[Test]
public void CallbackRemoveAtTest()
{
+#pragma warning disable 618 // Type or member is obsolete
bool called = false;
-
clientSyncList.Callback = (op, index, oldItem, newItem) =>
{
called = true;
@@ -413,11 +512,20 @@ public void CallbackRemoveAtTest()
Assert.That(oldItem, Is.EqualTo("World"));
Assert.That(newItem, Is.EqualTo(default(string)));
};
+#pragma warning restore 618 // Type or member is obsolete
+
+ bool actionCalled = false;
+ clientSyncList.OnRemove = (index, oldItem) =>
+ {
+ actionCalled = true;
+ Assert.That(index, Is.EqualTo(1));
+ Assert.That(oldItem, Is.EqualTo("World"));
+ };
serverSyncList.RemoveAt(1);
SerializeDeltaTo(serverSyncList, clientSyncList);
-
Assert.That(called, Is.True);
+ Assert.That(actionCalled, Is.True);
}
[Test]