Skip to content

Commit

Permalink
fix: Allow sync objects to be re-used (#1744)
Browse files Browse the repository at this point in the history
fixes #1714
  • Loading branch information
James-Frowen committed Apr 21, 2020
1 parent 8798cd1 commit 58c89a3
Show file tree
Hide file tree
Showing 10 changed files with 300 additions and 3 deletions.
8 changes: 8 additions & 0 deletions Assets/Mirror/Runtime/NetworkBehaviour.cs
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,14 @@ internal void DeSerializeObjectsDelta(NetworkReader reader)
}
}

internal void ResetSyncObjects()
{
foreach (SyncObject syncObject in syncObjects)
{
syncObject.Reset();
}
}

// Deprecated 04/20/2020
/// <summary>
/// Obsolete: Use <see cref="OnStopClient()"/> instead
Expand Down
11 changes: 11 additions & 0 deletions Assets/Mirror/Runtime/NetworkIdentity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1267,6 +1267,9 @@ public void RemoveClientAuthority()
// of invoking reset after OnDestroy is called.
internal void Reset()
{
// make sure to call this before networkBehavioursCache is cleared below
ResetSyncObjects();

clientStarted = false;
isClient = false;
isServer = false;
Expand Down Expand Up @@ -1368,5 +1371,13 @@ internal void ClearDirtyComponentsDirtyBits()
}
}
}

void ResetSyncObjects()
{
foreach (NetworkBehaviour comp in NetworkBehaviours)
{
comp.ResetSyncObjects();
}
}
}
}
8 changes: 8 additions & 0 deletions Assets/Mirror/Runtime/SyncDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ struct Change
// so we need to skip them
int changesAhead;

public void Reset()
{
IsReadOnly = false;
changes.Clear();
changesAhead = 0;
objects.Clear();
}

protected virtual void SerializeKey(NetworkWriter writer, TKey item) { }
protected virtual void SerializeItem(NetworkWriter writer, TValue item) { }
protected virtual TKey DeserializeKey(NetworkReader reader) => default;
Expand Down
8 changes: 8 additions & 0 deletions Assets/Mirror/Runtime/SyncList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ protected SyncList(IList<T> objects, IEqualityComparer<T> comparer = null)
// this should be called after a successfull sync
public void Flush() => changes.Clear();

public void Reset()
{
IsReadOnly = false;
changes.Clear();
changesAhead = 0;
objects.Clear();
}

void AddOperation(Operation op, int itemIndex, T oldItem, T newItem)
{
if (IsReadOnly)
Expand Down
5 changes: 5 additions & 0 deletions Assets/Mirror/Runtime/SyncObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,10 @@ public interface SyncObject

// deserialize changes since last sync
void OnDeserializeDelta(NetworkReader reader);

/// <summary>
/// Resets the SyncObject so that it can be re-used
/// </summary>
void Reset();
}
}
8 changes: 8 additions & 0 deletions Assets/Mirror/Runtime/SyncSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ protected SyncSet(ISet<T> objects)
this.objects = objects;
}

public void Reset()
{
IsReadOnly = false;
changes.Clear();
changesAhead = 0;
objects.Clear();
}

protected virtual void SerializeItem(NetworkWriter writer, T item) { }
protected virtual T DeserializeItem(NetworkReader reader) => default;

Expand Down
77 changes: 77 additions & 0 deletions Assets/Mirror/Tests/Editor/SyncDictionaryTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -301,5 +301,82 @@ public void ReadonlyTest()
Assert.That(clientList.IsReadOnly, Is.True);
Assert.Throws<InvalidOperationException>(() => clientList.Add(50, "fail"));
}

[Test]
public void ObjectCanBeReusedAfterReset()
{
SyncDictionaryIntString serverList = new SyncDictionaryIntString();
SyncDictionaryIntString clientList = new SyncDictionaryIntString();

serverList.Add(20, "yay");
serverList.Add(30, "hello");
serverList.Add(35, "world");
SerializeDeltaTo(serverList, clientList);

clientList.Reset();

// make old client the host
SyncDictionaryIntString hostList = clientList;
SyncDictionaryIntString clientList2 = new SyncDictionaryIntString();

Assert.That(hostList.IsReadOnly, Is.False);

hostList.Add(20, "yay");
hostList.Add(30, "hello");
hostList.Add(35, "world");
SerializeDeltaTo(hostList, clientList2);

Assert.That(hostList.IsReadOnly, Is.False);
}

[Test]
public void ResetShouldSetReadOnlyToFalse()
{
SyncDictionaryIntString serverList = new SyncDictionaryIntString();
SyncDictionaryIntString clientList = new SyncDictionaryIntString();

serverList.Add(20, "yay");
serverList.Add(30, "hello");
serverList.Add(35, "world");
SerializeDeltaTo(serverList, clientList);

Assert.That(clientList.IsReadOnly, Is.True);

clientList.Reset();

Assert.That(clientList.IsReadOnly, Is.False);
}

[Test]
public void ResetShouldClearChanges()
{
SyncDictionaryIntString serverList = new SyncDictionaryIntString();

serverList.Add(20, "yay");
serverList.Add(30, "hello");
serverList.Add(35, "world");

Assert.That(serverList.GetChangeCount(), Is.GreaterThan(0));

serverList.Reset();

Assert.That(serverList.GetChangeCount(), Is.Zero);
}

[Test]
public void ResetShouldClearItems()
{
SyncDictionaryIntString serverList = new SyncDictionaryIntString();

serverList.Add(20, "yay");
serverList.Add(30, "hello");
serverList.Add(35, "world");

Assert.That(serverList.Count, Is.GreaterThan(0));

serverList.Reset();

Assert.That(serverList, Is.Empty);
}
}
}
100 changes: 97 additions & 3 deletions Assets/Mirror/Tests/Editor/SyncListTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public void TestFind()
string element = serverSyncList.Find(entry => entry == "World");
Assert.That(element, Is.EqualTo("World"));
}

[Test]
public void TestNoFind()
{
Expand All @@ -132,9 +132,9 @@ public void TestNoFind()
public void TestFindAll()
{
List<string> results = serverSyncList.FindAll(entry => entry.Contains("l"));
Assert.That(results, Is.EquivalentTo( new [] {"Hello", "World"}));
Assert.That(results, Is.EquivalentTo(new[] { "Hello", "World" }));
}

[Test]
public void TestFindAllNonExistent()
{
Expand Down Expand Up @@ -318,7 +318,101 @@ public void ReadonlyTest()
// should produce an InvalidOperationException
Assert.That(clientList.IsReadOnly, Is.True);
Assert.Throws<InvalidOperationException>(() => { clientList.Add(5U); });
}

[Test]
public void ObjectCanBeReusedAfterReset()
{
SyncListUInt serverList = new SyncListUInt();
SyncListUInt clientList = new SyncListUInt();

serverList.Add(1U);
serverList.Add(2U);
serverList.Add(3U);
SerializeDeltaTo(serverList, clientList);

clientList.Reset();

// make old client the host
SyncListUInt hostList = clientList;
SyncListUInt clientList2 = new SyncListUInt();

Assert.That(hostList.IsReadOnly, Is.False);

hostList.Add(1U);
hostList.Add(2U);
hostList.Add(3U);
SerializeDeltaTo(hostList, clientList2);

Assert.That(hostList.IsReadOnly, Is.False);
}

[Test]
public void ResetShouldSetReadOnlyToFalse()
{
SyncListUInt serverList = new SyncListUInt();
SyncListUInt clientList = new SyncListUInt();

serverList.Add(1U);
serverList.Add(2U);
serverList.Add(3U);
SerializeDeltaTo(serverList, clientList);

Assert.That(clientList.IsReadOnly, Is.True);

clientList.Reset();

Assert.That(clientList.IsReadOnly, Is.False);
}

[Test]
public void ResetShouldClearChanges()
{
SyncListUInt serverList = new SyncListUInt();

serverList.Add(1U);
serverList.Add(2U);
serverList.Add(3U);

Assert.That(serverList.GetChangeCount(), Is.GreaterThan(0));

serverList.Reset();

Assert.That(serverList.GetChangeCount(), Is.Zero);
}

[Test]
public void ResetShouldClearItems()
{
SyncListUInt serverList = new SyncListUInt();

serverList.Add(1U);
serverList.Add(2U);
serverList.Add(3U);

Assert.That(serverList.Count, Is.GreaterThan(0));

serverList.Reset();

Assert.That(serverList, Is.Empty);
}
}

public static class SyncObjectTestMethods
{
public static uint GetChangeCount(this SyncObject syncObject)
{
using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter())
{
syncObject.OnSerializeDelta(writer);

using (PooledNetworkReader reader = NetworkReaderPool.GetReader(writer.ToArraySegment()))
{
uint count = reader.ReadPackedUInt32();

return count;
}
}
}
}
}
77 changes: 77 additions & 0 deletions Assets/Mirror/Tests/Editor/SyncSetTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -270,5 +270,82 @@ public void TestUnionWithSelf()
SerializeDeltaTo(serverSyncSet, clientSyncSet);
Assert.That(clientSyncSet, Is.EquivalentTo(new[] { "World", "Hello", "!" }));
}

[Test]
public void ObjectCanBeReusedAfterReset()
{
SyncSetString serverList = new SyncSetString();
SyncSetString clientList = new SyncSetString();

serverList.Add("1");
serverList.Add("2");
serverList.Add("3");
SerializeDeltaTo(serverList, clientList);

clientList.Reset();

// make old client the host
SyncSetString hostList = clientList;
SyncSetString clientList2 = new SyncSetString();

Assert.That(hostList.IsReadOnly, Is.False);

hostList.Add("1");
hostList.Add("2");
hostList.Add("3");
SerializeDeltaTo(hostList, clientList2);

Assert.That(hostList.IsReadOnly, Is.False);
}

[Test]
public void ResetShouldSetReadOnlyToFalse()
{
SyncSetString serverList = new SyncSetString();
SyncSetString clientList = new SyncSetString();

serverList.Add("1");
serverList.Add("2");
serverList.Add("3");
SerializeDeltaTo(serverList, clientList);

Assert.That(clientList.IsReadOnly, Is.True);

clientList.Reset();

Assert.That(clientList.IsReadOnly, Is.False);
}

[Test]
public void ResetShouldClearChanges()
{
SyncSetString serverList = new SyncSetString();

serverList.Add("1");
serverList.Add("2");
serverList.Add("3");

Assert.That(serverList.GetChangeCount(), Is.GreaterThan(0));

serverList.Reset();

Assert.That(serverList.GetChangeCount(), Is.Zero);
}

[Test]
public void ResetShouldClearItems()
{
SyncSetString serverList = new SyncSetString();

serverList.Add("1");
serverList.Add("2");
serverList.Add("3");

Assert.That(serverList.Count, Is.GreaterThan(0));

serverList.Reset();

Assert.That(serverList, Is.Empty);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public class SyncObjImplementer : SyncObject
public void OnSerializeDelta(NetworkWriter writer) {}
public void OnDeserializeAll(NetworkReader reader) {}
public void OnDeserializeDelta(NetworkReader reader) {}
public void Reset() {}
}

class MirrorTestPlayer : NetworkBehaviour
Expand Down

0 comments on commit 58c89a3

Please sign in to comment.