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; } } }