mirror of
https://github.com/MirrorNetworking/Mirror.git
synced 2024-11-18 02:50:32 +00:00
SnapshotBuffer: store snapshots in a list sorted by time; it's also responsible for dropping too old snapshots now. makes NT easier.
This commit is contained in:
parent
75b8801b67
commit
79fb69c064
@ -25,14 +25,6 @@ public abstract class OumuamuaBase : NetworkBehaviour
|
||||
float lastClientSendTime;
|
||||
float lastServerSendTime;
|
||||
|
||||
// keep track of last received timestamps and throw out any snapshots
|
||||
// older than that (according to the article).
|
||||
// TODO seems like any snapshot that still fits in the buffer before we
|
||||
// process it seems worth keeping?
|
||||
// TODO consider double for precision over days
|
||||
float serverLastReceivedTimestamp;
|
||||
float clientLastReceivedTimestamp;
|
||||
|
||||
// snapshot timestamps are _remote_ time
|
||||
// we need to interpolate and calculate buffer lifetimes based on it.
|
||||
// -> we don't know remote's current time
|
||||
@ -63,13 +55,8 @@ void CmdClientToServerSync(Snapshot snapshot)
|
||||
// apply if in client authority mode
|
||||
if (clientAuthority)
|
||||
{
|
||||
// newer than most recent received snapshot?
|
||||
if (snapshot.timestamp > serverLastReceivedTimestamp)
|
||||
{
|
||||
// add to buffer
|
||||
serverBuffer.Enqueue(snapshot);
|
||||
serverLastReceivedTimestamp = snapshot.timestamp;
|
||||
}
|
||||
// add to buffer (or drop if older than first element)
|
||||
serverBuffer.InsertIfNewEnough(snapshot);
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,13 +67,8 @@ void RpcServerToClientSync(Snapshot snapshot)
|
||||
// apply for all objects except local player with authority
|
||||
if (!IsClientWithAuthority)
|
||||
{
|
||||
// newer than most recent received snapshot?
|
||||
if (snapshot.timestamp > clientLastReceivedTimestamp)
|
||||
{
|
||||
// add to buffer
|
||||
clientBuffer.Enqueue(snapshot);
|
||||
clientLastReceivedTimestamp = snapshot.timestamp;
|
||||
}
|
||||
// add to buffer (or drop if older than first element)
|
||||
clientBuffer.InsertIfNewEnough(snapshot);
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,7 +88,6 @@ void ApplySnapshots(ref float remoteTime, SnapshotBuffer buffer)
|
||||
{
|
||||
Debug.Log($"{name} snapshotbuffer={buffer.Count}");
|
||||
|
||||
|
||||
// we buffer snapshots for 'bufferTime'
|
||||
// for example:
|
||||
// * we buffer for 3 x sendInterval = 300ms
|
||||
|
@ -1,27 +1,52 @@
|
||||
// the snapshot buffer's job is to hold for example 100ms worth of snapshots.
|
||||
// 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
|
||||
{
|
||||
Queue<Snapshot> queue = new Queue<Snapshot>();
|
||||
// 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<float, Snapshot> list = new SortedList<float, Snapshot>();
|
||||
|
||||
public void Enqueue(Snapshot snapshot) => queue.Enqueue(snapshot);
|
||||
// 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 (queue.Count > 0)
|
||||
if (list.Count > 0)
|
||||
{
|
||||
// snapshot needs to be older than currentTime - bufferTime
|
||||
float thresholdTime = currentTime - bufferInterval;
|
||||
|
||||
// peek and compare time
|
||||
if (queue.Peek().timestamp <= thresholdTime)
|
||||
// compare time of first entry (oldest snapshot)
|
||||
Snapshot first = list.Values[0];
|
||||
if (first.timestamp <= thresholdTime)
|
||||
{
|
||||
snapshot = queue.Dequeue();
|
||||
snapshot = first;
|
||||
list.RemoveAt(0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -32,9 +57,9 @@ public bool DequeueIfOldEnough(float currentTime, float bufferInterval, out Snap
|
||||
// peek
|
||||
public bool Peek(out Snapshot snapshot)
|
||||
{
|
||||
if (queue.Count > 0)
|
||||
if (list.Count > 0)
|
||||
{
|
||||
snapshot = queue.Peek();
|
||||
snapshot = list.Values[0];
|
||||
return true;
|
||||
}
|
||||
snapshot = default;
|
||||
@ -42,8 +67,11 @@ public bool Peek(out Snapshot snapshot)
|
||||
}
|
||||
|
||||
// count queue size independent of time
|
||||
public int Count => queue.Count;
|
||||
public int Count => list.Count;
|
||||
|
||||
public void Clear() => queue.Clear();
|
||||
// get all snapshots. useful for testing.
|
||||
public IList<Snapshot> All() => list.Values;
|
||||
|
||||
public void Clear() => list.Clear();
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using Mirror.Experimental;
|
||||
using NUnit.Framework;
|
||||
|
||||
@ -14,18 +15,65 @@ public void SetUp()
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Enqueue()
|
||||
public void Insert_Empty()
|
||||
{
|
||||
buffer.Enqueue(new Snapshot());
|
||||
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<Snapshot> 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.Enqueue(snapshot);
|
||||
buffer.InsertIfNewEnough(snapshot);
|
||||
|
||||
// dequeue at time = 2 with buffer time = 1.5
|
||||
// in other words, anything older than 0.5 should dequeue (nothing)
|
||||
@ -38,7 +86,7 @@ public void Dequeue_OldEnough()
|
||||
{
|
||||
// add snapshot at time=1
|
||||
Snapshot snapshot = new Snapshot{timestamp = 1};
|
||||
buffer.Enqueue(snapshot);
|
||||
buffer.InsertIfNewEnough(snapshot);
|
||||
|
||||
// dequeue at time = 2 with buffer time = 0.5
|
||||
// in other words, anything older than 1.5 should dequeue
|
||||
@ -50,7 +98,7 @@ public void Dequeue_OldEnough()
|
||||
[Test]
|
||||
public void Clear()
|
||||
{
|
||||
buffer.Enqueue(new Snapshot());
|
||||
buffer.InsertIfNewEnough(new Snapshot());
|
||||
buffer.Clear();
|
||||
Assert.That(buffer.Count, Is.EqualTo(0));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user