using System;
using UnityEngine;
using UnityEngine.Assertions;
namespace Unity.Netcode
{
///
/// A struct to represent a point of time in a networked game.
/// Time is stored as a combination of amount of passed ticks + a duration offset.
/// This struct is meant to replace the Unity API for multiplayer gameplay.
///
public struct NetworkTime
{
private double m_TimeSec;
private uint m_TickRate;
private double m_TickInterval;
private int m_CachedTick;
private double m_CachedTickOffset;
///
/// Gets the amount of time which has passed since the last network tick.
///
public double TickOffset => m_CachedTickOffset;
///
/// Gets the current time. This is a non fixed time value and similar to .
///
public double Time => m_TimeSec;
///
/// Gets the current time as a float.
///
public float TimeAsFloat => (float)m_TimeSec;
///
/// Gets he current fixed network time. This is the time value of the last network tick. Similar to .
///
public double FixedTime => m_CachedTick * m_TickInterval;
///
/// Gets the fixed delta time. This value is based on the and stays constant.
/// Similar to There is no equivalent to .
///
public float FixedDeltaTime => (float)m_TickInterval;
///
/// Gets the amount of network ticks which have passed until reaching the current time value.
///
public int Tick => m_CachedTick;
///
/// Gets the tickrate of the system of this .
/// Ticks per second.
///
public uint TickRate => m_TickRate;
///
/// Creates a new instance of the struct.
///
/// The tickrate.
public NetworkTime(uint tickRate)
{
Assert.IsTrue(tickRate > 0, "Tickrate must be a positive value.");
m_TickRate = tickRate;
m_TickInterval = 1f / m_TickRate; // potential floating point precision issue, could result in different interval on different machines
m_CachedTickOffset = 0;
m_CachedTick = 0;
m_TimeSec = 0;
}
///
/// Creates a new instance of the struct.
///
/// The tickrate.
/// The time will be created with a value where this many tick have already passed.
/// Can be used to create a with a non fixed time value by adding an offset to the given tick value.
public NetworkTime(uint tickRate, int tick, double tickOffset = 0d)
: this(tickRate)
{
Assert.IsTrue(tickOffset < 1d / tickRate);
m_CachedTickOffset = tickOffset;
m_CachedTick = tick;
m_TimeSec = tick * m_TickInterval + tickOffset;
}
///
/// Creates a new instance of the struct.
///
/// The tickrate.
/// The time value as a float.
public NetworkTime(uint tickRate, double timeSec)
: this(tickRate)
{
this += timeSec;
}
///
/// Converts the network time into a fixed time value.
///
/// A where Time is the FixedTime value of this instance.
public NetworkTime ToFixedTime()
{
return new NetworkTime(m_TickRate, m_CachedTick);
}
///
/// Returns the time a number of ticks in the past.
///
/// The number of ticks ago we're querying the time
///
public NetworkTime TimeTicksAgo(int ticks)
{
return this - new NetworkTime(TickRate, ticks);
}
private void UpdateCache()
{
double d = m_TimeSec / m_TickInterval;
m_CachedTick = (int)d;
// This check is needed due to double division imprecision of large numbers
if ((d - m_CachedTick) >= 0.999999999999)
{
m_CachedTick++;
}
m_CachedTickOffset = ((d - Math.Truncate(d)) * m_TickInterval);
// This handles negative time, decreases tick by 1 and makes offset positive.
if (m_CachedTick < 0 && m_CachedTickOffset != 0d)
{
m_CachedTick--;
m_CachedTickOffset = m_TickInterval + m_CachedTickOffset;
}
}
///
/// Computes the time difference between two ticks
///
/// End time
/// Start time
/// The time difference between start and end
public static NetworkTime operator -(NetworkTime a, NetworkTime b)
{
return new NetworkTime(a.TickRate, a.Time - b.Time);
}
///
/// Computes the sum of two times
///
/// First time
/// Second time
/// The sum of the two times passed in
public static NetworkTime operator +(NetworkTime a, NetworkTime b)
{
return new NetworkTime(a.TickRate, a.Time + b.Time);
}
///
/// Computes the time a number of seconds later
///
/// The start time
/// The number of seconds to add
/// The resulting time
public static NetworkTime operator +(NetworkTime a, double b)
{
a.m_TimeSec += b;
a.UpdateCache();
return a;
}
///
/// Computes the time a number of seconds before
///
/// The start time
/// The number of seconds to remove
/// The resulting time
public static NetworkTime operator -(NetworkTime a, double b)
{
return a + -b;
}
}
}