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]