mirror of
https://github.com/MirrorNetworking/Mirror.git
synced 2024-11-18 02:50:32 +00:00
remove SnapshotBuffer. use list directly for easier interpolation.
This commit is contained in:
parent
4ed9c6443f
commit
063ae9553a
@ -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<float, Snapshot> serverBuffer = new SortedList<float, Snapshot>();
|
||||
SortedList<float, Snapshot> clientBuffer = new SortedList<float, Snapshot>();
|
||||
|
||||
// insert into snapshot buffer if newer than first entry
|
||||
static void InsertIfNewEnough(Snapshot snapshot, SortedList<float, Snapshot> 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<float, Snapshot> 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()
|
||||
|
@ -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<float, Snapshot> list = new SortedList<float, 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 (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<Snapshot> All() => list.Values;
|
||||
|
||||
public void Clear() => list.Clear();
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 889afb8fc95244b0a38f4eefffa7e643
|
||||
timeCreated: 1615886688
|
@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5eb7a798032d4ae8b5bf22d14a60bcd9
|
||||
timeCreated: 1615958523
|
@ -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<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.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));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9df6ec4155e2423e8b95a49f4d07add4
|
||||
timeCreated: 1615958523
|
Loading…
Reference in New Issue
Block a user