Skip to content

Commit

Permalink
fix: improving time scaling
Browse files Browse the repository at this point in the history
better time adjusting to ensure that there is always enough snapshots
  • Loading branch information
James-Frowen authored Feb 8, 2024
1 parent 0fd9157 commit b073950
Showing 1 changed file with 33 additions and 23 deletions.
56 changes: 33 additions & 23 deletions Assets/NetworkPositionSync/Runtime/InterpolationTime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ namespace JamesFrowen.PositionSync
public class InterpolationTime
{
private static readonly ILogger logger = LogFactory.GetLogger<InterpolationTime>();
private bool intialized;
private bool initialized;

/// <summary>
/// The time value that the client uses to interpolate
Expand All @@ -83,9 +83,11 @@ public class InterpolationTime
/// How much below the goalOffset difference are we allowed to go before changing the timescale
/// </summary>
private readonly float negativeThreshold;
private readonly float fastScale = 1.01f;
private const float normalScale = 1f;
private readonly float slowScale = 0.99f;

/// <summary>
/// how much to modify time scale by if client is ahead/behind the server
/// </summary>
private readonly float _scaleModifier;

/// <summary>
/// Is the difference between previous time and new time too far apart?
Expand Down Expand Up @@ -141,15 +143,15 @@ public float ClientDelay
public float DebugScale => clientScaleTime;

/// <param name="diffThreshold">How far off client time can be before changing its speed. A good recommended value is half of SyncInterval.</param>
/// <param name="skipThreshold">How many ticks behind before skipping ahead to catch up</param>
/// <param name="movingAverageCount">How many ticks are used for averaging purposes, you may need to increase or decrease with frame rate.</param>
public InterpolationTime(float tickInterval, float diffThreshold = 0.5f, float timeScale = 0.01f, float skipThreshold = 2.5f, float tickDelay = 2, int movingAverageCount = 30)
public InterpolationTime(float tickInterval, float diffThreshold = 0.5f, float timeScale = 0.01f, float skipThreshold = 20f, float tickDelay = 2, int movingAverageCount = 30)
{
positiveThreshold = tickInterval * diffThreshold;
negativeThreshold = -positiveThreshold;
_skipAheadThreshold = tickInterval * skipThreshold;

fastScale = normalScale + timeScale;
slowScale = normalScale - timeScale;
_scaleModifier = timeScale;

_clientDelay = tickInterval * tickDelay;

Expand Down Expand Up @@ -179,8 +181,8 @@ public bool IsMessageOutOfOrder(float newServerTime)
/// <param name="serverTime"></param>
public void OnMessage(float serverTime)
{
// only check this if we are intialized
if (intialized)
// only check this if we are initialized
if (initialized)
logger.Assert(serverTime > _latestServerTime, $"Received message out of order. Server Time: {serverTime} vs New Time: {_latestServerTime}");

_latestServerTime = serverTime;
Expand All @@ -189,7 +191,7 @@ public void OnMessage(float serverTime)
// If we're too far behind, then we should reset things too.

// todo check this is correct
if (!intialized)
if (!initialized)
{
InitNew(serverTime);
return;
Expand All @@ -209,7 +211,8 @@ public void OnMessage(float serverTime)
diffAvg.Add(diff);

// Adjust the client time scale with the appropriate value.
AdjustClientTimeScale((float)diffAvg.Value);
// clamp just incase user given timeScale is a bad value
clientScaleTime = Mathf.Clamp(CalculateTimeScale((float)diffAvg.Value), 0.5f, 2f);

// todo add trace level
if (logger.LogEnabled()) logger.Log($"st: {serverTime:0.00}, ct: {_clientTime:0.00}, diff: {diff * 1000:0.0}, wanted: {diffAvg.Value * 1000:0.0}, scale: {clientScaleTime}");
Expand All @@ -221,7 +224,7 @@ public void OnMessage(float serverTime)
public void Reset()
{
// mark this so first server method will call InitNew
intialized = false;
initialized = false;
_latestServerTime = 0;
}

Expand All @@ -233,28 +236,35 @@ private void InitNew(float serverTime)
_clientTime = serverTime;
clientScaleTime = normalScale;
diffAvg.Reset();
intialized = true;
initialized = true;
}

/// <summary>
/// Adjusts the client time scale based on the provided difference.
/// </summary>
private void AdjustClientTimeScale(float diff)
private float CalculateTimeScale(float diff)
{
// Difference is calculated between server and client.
// So if that difference is positive, we can run the client faster to catch up.
// However, if it's negative, we need to slow the client down otherwise we run out of snapshots.
// Ideally, we want the difference vs the goal to be as close to 0 as possible.

// Server's ahead of us, we need to speed up.
if (diff > positiveThreshold)
clientScaleTime = fastScale;
// Server is falling behind us, we need to slow down.
else if (diff < negativeThreshold)
clientScaleTime = slowScale;
// Server and client are on par ("close enough"). Run at normal speed.
else
clientScaleTime = normalScale;
if (diff > positiveThreshold * 10) // really far ahead,
return 1 + (_scaleModifier * 8);

else if (diff > positiveThreshold) // Server's ahead of us, we need to speed up.
return 1 + _scaleModifier;

else if (diff < negativeThreshold * 10) // really far behind
return 1 - (_scaleModifier * 20);

else if (diff < negativeThreshold) // Server is falling behind us, we need to slow down.
// *2 here because we want to slow down faster,
// if we dont there wont be any new snapshots to interpolate towards and game will be jittery
return 1 - _scaleModifier * 4;

else // Server and client are on par ("close enough"). Run at normal speed.
return 1;
}
}
}

0 comments on commit b073950

Please sign in to comment.