Scripts
ClientReceiveBuffer.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public clast ClientReceiveBuffer : MyStopWatch
{
// The desierd gap between the last received snapshot to the frame that we interpolate towards
// that means the if the gap is 2 we try to be 2 ticks back from current tick (at least).
// Example:
// desierd gap = 2;
// last tick received = 16;
// prev tick = 13; // var prevState = snapshotBuffer[snapshotBuffer.Count - 2 - gap];
// next tick = 14; // var prevState = snapshotBuffer[snapshotBuffer.Count - 1 - gap];
const int bufferLength = 10;
const int snapshotDesiredGap = 5;
int snapshotGap = -2;
float time = 0;
float lerpTimeFactor;
long now;
long lastTimeCallTime;
long lastReceiveTime; // for jitter measurement
int lastTickUsed = 0;
FloatRollingAverage jitter;
List playerStates;
CircularList snapshotBuffer;
public ClientReceiveBuffer(float ticksPerSecond) : base()
{
lerpTimeFactor = (1f / ticksPerSecond) * 1000f; // In ms.
jitter = new FloatRollingAverage((int) ticksPerSecond * 3); // the jitter in 3 second
lastReceiveTime = NowInTicks;
snapshotBuffer = new CircularList(bufferLength);
playerStates = new List();
}
public WorldState GetLatestWorldState()
{
if (snapshotBuffer.Count == 0)
return null;
return snapshotBuffer[snapshotBuffer.Count - 1];
}
public void AppendNewSnapshot(WorldState snapshot)
{
lock (snapshotBuffer)
{
snapshotBuffer.Add(snapshot);
float deltaTime = (NowInTicks - lastReceiveTime) / (float) this.m_FrequencyMS;
jitter.Update(deltaTime);
lastReceiveTime = NowInTicks;
//Debug.Log("AVG: " + jitter.average + " stdDeviation: " + jitter.stdDeviation);
if (snapshotGap >= snapshotBuffer.Count - 2)
{
Reset();
}
else
{
snapshotGap++;
}
}
}
public Tuple Interpolate()
{
WorldState prevState;
WorldState nextState;
lock (snapshotBuffer)
{
// If we don't have enough snapshots to interpolate in between we simply set the state to the oldest received frame.
if (snapshotBuffer.Count - 2 - snapshotDesiredGap < 0)
{
time = 0;
lastTimeCallTime = NowInTicks;
if (snapshotBuffer.Count > 0)
{
lastTickUsed = snapshotBuffer[snapshotBuffer.HeadIndex].serverTickSeq;
}
return GetFirst();
}
// When we first capture a packet we save the received time and from then on we playout the snapshots from the server
// in constant intervals these intervals are equal the server tick rate, i.e, the lerpTimeFactor.
if (time >= lerpTimeFactor)
{
time %= lerpTimeFactor;
if (snapshotGap