diff --git a/Assets/Mirror/Components/Experimental/Oumuamua/OumuamuaBase.cs b/Assets/Mirror/Components/Experimental/Oumuamua/OumuamuaBase.cs index eea2f8586..54bfd35a9 100644 --- a/Assets/Mirror/Components/Experimental/Oumuamua/OumuamuaBase.cs +++ b/Assets/Mirror/Components/Experimental/Oumuamua/OumuamuaBase.cs @@ -3,6 +3,8 @@ // Base class for NetworkTransform and NetworkTransformChild. // => simple unreliable sync without any interpolation for now. // => which means we don't need teleport detection either + +using System.Collections.Generic; using UnityEngine; namespace Mirror.Experimental @@ -44,9 +46,26 @@ public abstract class OumuamuaBase : NetworkBehaviour public int bufferTimeMultiplier = 3; public float bufferTime => sendInterval * bufferTimeMultiplier; - // snapshot buffers - SnapshotBuffer serverBuffer = new SnapshotBuffer(); - SnapshotBuffer clientBuffer = new SnapshotBuffer(); + // snapshots sorted by timestamp + // in the original article, glenn fiedler drops any snapshots older than + // the last received snapshot. + // -> instead, we insert into a sorted buffer + // -> the higher the buffer information density, the better + // -> we still drop anything older than the first element in the buffer + SortedList serverBuffer = new SortedList(); + SortedList clientBuffer = new SortedList(); + + // insert into snapshot buffer if newer than first entry + static void InsertIfNewEnough(Snapshot snapshot, SortedList buffer) + { + // drop it if it's older than the first snapshot + if (buffer.Count > 0 && + buffer.Values[0].timestamp > snapshot.timestamp) + return; + + // otherwise sort it into the list + buffer.Add(snapshot.timestamp, snapshot); + } // local authority client sends sync message to server for broadcasting [Command(channel = Channels.Unreliable)] @@ -56,7 +75,7 @@ void CmdClientToServerSync(Snapshot snapshot) if (clientAuthority) { // add to buffer (or drop if older than first element) - serverBuffer.InsertIfNewEnough(snapshot); + InsertIfNewEnough(snapshot, serverBuffer); } } @@ -68,7 +87,7 @@ void RpcServerToClientSync(Snapshot snapshot) if (!IsClientWithAuthority) { // add to buffer (or drop if older than first element) - clientBuffer.InsertIfNewEnough(snapshot); + InsertIfNewEnough(snapshot, clientBuffer); } } @@ -95,7 +114,7 @@ void ApplySnapshot(Snapshot snapshot) // helper function to apply snapshots. // we use the same one on server and client. // => called every Update() depending on authority. - void ApplySnapshots(ref float remoteTime, SnapshotBuffer buffer) + void ApplySnapshots(ref float remoteTime, SortedList buffer) { Debug.Log($"{name} snapshotbuffer={buffer.Count}"); @@ -120,8 +139,9 @@ void ApplySnapshots(ref float remoteTime, SnapshotBuffer buffer) if (remoteTime == 0) { // then set it to first snapshot received (if any) - if (buffer.Peek(out Snapshot first)) + if (buffer.Count > 0) { + Snapshot first = buffer.Values[0]; remoteTime = first.timestamp; Debug.LogWarning("remoteTime initialized to " + first.timestamp); } @@ -134,8 +154,19 @@ void ApplySnapshots(ref float remoteTime, SnapshotBuffer buffer) // (probably need to speed this up based on buffer size later) remoteTime += Time.deltaTime; - if (buffer.DequeueIfOldEnough(remoteTime, bufferTime, out Snapshot snapshot)) - ApplySnapshot(snapshot); + // apply first snapshot if old enough + if (buffer.Count > 0) + { + // snapshot needs to be older than currentTime - bufferTime + float threshold = remoteTime - bufferTime; + Snapshot first = buffer.Values[0]; + if (first.timestamp <= threshold) + { + ApplySnapshot(first); + // remove it, now that we have applied it + buffer.RemoveAt(0); + } + } } void Update() diff --git a/Assets/Mirror/Components/Experimental/Oumuamua/SnapshotBuffer.cs b/Assets/Mirror/Components/Experimental/Oumuamua/SnapshotBuffer.cs deleted file mode 100644 index a5af7c53c..000000000 --- a/Assets/Mirror/Components/Experimental/Oumuamua/SnapshotBuffer.cs +++ /dev/null @@ -1,86 +0,0 @@ -// the snapshot buffer's job is to hold for example 100ms worth of snapshots. -// -// from the article: -// "What we do is instead of immediately rendering snapshot data received is -// that we buffer snapshots for a short amount of time in an interpolation -// buffer. This interpolation buffer holds on to snapshots for a period of time -// such that you have not only the snapshot you want to render but also, -// statistically speaking, you are very likely to have the next snapshot as -// well." -// -// SnapshotBuffer simply wraps a sorted list with some time functions. -// it's nothing special and we could do the time math in NetworkTransform, -// but this way we shield ourselves from life's complexities and it's testable! -using System.Collections.Generic; - -namespace Mirror.Experimental -{ - public class SnapshotBuffer - { - // snapshots sorted by timestamp - // in the original article, glenn fiedler drops any snapshots older than - // the last received snapshot. - // -> instead, we insert into a sorted buffer - // -> the higher the buffer information density, the better - // -> we still drop anything older than the first element in the buffer - SortedList list = new SortedList(); - - // insert a snapshot if it's new enough. - // sorts it into the right position. - public void InsertIfNewEnough(Snapshot snapshot) - { - // drop it if it's older than the first snapshot - if (list.Count > 0 && - list.Values[0].timestamp > snapshot.timestamp) - { - return; - } - - // otherwise sort it into the list - list.Add(snapshot.timestamp, snapshot); - } - - // dequeue the first snapshot if it's older enough. - // for example, currentTime = 100, bufferInterval = 0.3 - // so any snapshot before time = 99.7 - public bool DequeueIfOldEnough(float currentTime, float bufferInterval, out Snapshot snapshot) - { - if (list.Count > 0) - { - // snapshot needs to be older than currentTime - bufferTime - float thresholdTime = currentTime - bufferInterval; - - // compare time of first entry (oldest snapshot) - Snapshot first = list.Values[0]; - if (first.timestamp <= thresholdTime) - { - snapshot = first; - list.RemoveAt(0); - return true; - } - } - snapshot = default; - return false; - } - - // peek - public bool Peek(out Snapshot snapshot) - { - if (list.Count > 0) - { - snapshot = list.Values[0]; - return true; - } - snapshot = default; - return false; - } - - // count queue size independent of time - public int Count => list.Count; - - // get all snapshots. useful for testing. - public IList All() => list.Values; - - public void Clear() => list.Clear(); - } -} diff --git a/Assets/Mirror/Components/Experimental/Oumuamua/SnapshotBuffer.cs.meta b/Assets/Mirror/Components/Experimental/Oumuamua/SnapshotBuffer.cs.meta deleted file mode 100644 index ff3a7c7f6..000000000 --- a/Assets/Mirror/Components/Experimental/Oumuamua/SnapshotBuffer.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 889afb8fc95244b0a38f4eefffa7e643 -timeCreated: 1615886688 \ No newline at end of file diff --git a/Assets/Mirror/Tests/Editor/SnapshotInterpolation.meta b/Assets/Mirror/Tests/Editor/SnapshotInterpolation.meta deleted file mode 100644 index e6350e74b..000000000 --- a/Assets/Mirror/Tests/Editor/SnapshotInterpolation.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 5eb7a798032d4ae8b5bf22d14a60bcd9 -timeCreated: 1615958523 \ No newline at end of file diff --git a/Assets/Mirror/Tests/Editor/SnapshotInterpolation/SnapshotBufferTests.cs b/Assets/Mirror/Tests/Editor/SnapshotInterpolation/SnapshotBufferTests.cs deleted file mode 100644 index a0f791be1..000000000 --- a/Assets/Mirror/Tests/Editor/SnapshotInterpolation/SnapshotBufferTests.cs +++ /dev/null @@ -1,106 +0,0 @@ -using System.Collections.Generic; -using Mirror.Experimental; -using NUnit.Framework; - -namespace Mirror.Tests -{ - public class SnapshotBufferTests - { - SnapshotBuffer buffer; - - [SetUp] - public void SetUp() - { - buffer = new SnapshotBuffer(); - } - - [Test] - public void Insert_Empty() - { - buffer.InsertIfNewEnough(new Snapshot()); - Assert.That(buffer.Count, Is.EqualTo(1)); - } - - [Test] - public void Insert_NotNewEnough() - { - // insert snapshot at time = 1 - buffer.InsertIfNewEnough(new Snapshot{timestamp = 1}); - Assert.That(buffer.Count, Is.EqualTo(1)); - - // insert snapshot at time = 0.5 (too old, should be dropped) - buffer.InsertIfNewEnough(new Snapshot{timestamp = 0.5f}); - Assert.That(buffer.Count, Is.EqualTo(1)); - } - - [Test] - public void Insert_NewEnough() - { - // insert snapshot at time = 1 - buffer.InsertIfNewEnough(new Snapshot{timestamp = 1}); - Assert.That(buffer.Count, Is.EqualTo(1)); - - // insert snapshot at time = 1.5 (newer than first = ok) - buffer.InsertIfNewEnough(new Snapshot{timestamp = 1.5f}); - Assert.That(buffer.Count, Is.EqualTo(2)); - } - - [Test] - public void Insert_Inbetween() - { - // insert snapshot at time = 1 - Snapshot first = new Snapshot{timestamp = 1}; - buffer.InsertIfNewEnough(first); - - // insert snapshot at time = 2 - Snapshot last = new Snapshot{timestamp = 2}; - buffer.InsertIfNewEnough(last); - - // insert snapshot at time = 1.5 (inbetween) - Snapshot between = new Snapshot{timestamp = 1.5f}; - buffer.InsertIfNewEnough(between); - - // check if sorted properly - IList all = buffer.All(); - Assert.That(all.Count, Is.EqualTo(3)); - Assert.That(all[0], Is.EqualTo(first)); - Assert.That(all[1], Is.EqualTo(between)); - Assert.That(all[2], Is.EqualTo(last)); - } - - [Test] - public void Dequeue_NotOldEnough() - { - // add snapshot at time=1 - Snapshot snapshot = new Snapshot{timestamp = 1}; - buffer.InsertIfNewEnough(snapshot); - - // dequeue at time = 2 with buffer time = 1.5 - // in other words, anything older than 0.5 should dequeue (nothing) - bool result = buffer.DequeueIfOldEnough(2, 1.5f, out Snapshot value); - Assert.That(result, Is.False); - } - - [Test] - public void Dequeue_OldEnough() - { - // add snapshot at time=1 - Snapshot snapshot = new Snapshot{timestamp = 1}; - buffer.InsertIfNewEnough(snapshot); - - // dequeue at time = 2 with buffer time = 0.5 - // in other words, anything older than 1.5 should dequeue - bool result = buffer.DequeueIfOldEnough(2, 0.5f, out Snapshot value); - Assert.That(result, Is.True); - Assert.That(value, Is.EqualTo(snapshot)); - } - - [Test] - public void Clear() - { - buffer.InsertIfNewEnough(new Snapshot()); - buffer.Clear(); - Assert.That(buffer.Count, Is.EqualTo(0)); - } - } -} diff --git a/Assets/Mirror/Tests/Editor/SnapshotInterpolation/SnapshotBufferTests.cs.meta b/Assets/Mirror/Tests/Editor/SnapshotInterpolation/SnapshotBufferTests.cs.meta deleted file mode 100644 index 7c9054a48..000000000 --- a/Assets/Mirror/Tests/Editor/SnapshotInterpolation/SnapshotBufferTests.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 9df6ec4155e2423e8b95a49f4d07add4 -timeCreated: 1615958523 \ No newline at end of file