using System.Runtime.CompilerServices; namespace FishNet.Managing.Timing { public struct EstimatedTick { /// /// How to handle old ticks, specifically related to EstimatedTick. /// public enum OldTickOption : byte { /// /// Completely ignore old ticks. /// Discard = 0, /// /// Set LastRemoteTick but do not update RemoteTick. /// SetLastRemoteTick = 1, /// /// Set LastRemoteTick and RemoteTick. /// SetRemoteTick = 2, } /// /// Local tick when this was last updated. /// public uint LocalTick; /// /// Last remote tick this was updated with that was not out of order or a duplicate. /// public uint RemoteTick; /// /// Last remote tick received regardless if it was out of order or a duplicate. /// public uint LastRemoteTick; /// /// True if the value was updated this tick. /// public bool IsCurrent(TimeManager tm) => (!IsUnset && LocalTick == tm.LocalTick); /// /// True if value is unset. /// //Only need to check one value for unset as they all would be if not set. public bool IsUnset => (LocalTick == 0); /// /// Number of ticks LocalTick is being current LocalTick. /// public uint LocalTickDifference(TimeManager tm) { long value = (tm.LocalTick - LocalTick); //Shouldn't be possible to be less than 0. if (value < 0) return 0; else if (value > uint.MaxValue) value = uint.MaxValue; return (uint)value; } /// /// Updates values. /// /// NetworkManager to use. /// Remote tick being updated. /// True to not update if remote tick is older or equal to the last updated value. /// True if was able to update values. public bool Update(TimeManager tm, uint remoteTick, OldTickOption oldTickOption = OldTickOption.Discard) { //Always set LastRemoteTick even if out of order. LastRemoteTick = remoteTick; //If cannot update with old values return. if (oldTickOption != OldTickOption.SetRemoteTick && remoteTick <= RemoteTick) return false; //nm is assumed set here. LocalTick = tm.LocalTick; RemoteTick = remoteTick; return true; } /// /// Current estimated value. /// /// NetworkManager to use. When null default value will be returned. [MethodImpl(MethodImplOptions.AggressiveInlining)] public uint Value(TimeManager tm) { return Value(tm, out _); } /// /// Current estimated value. Outputs if value is current. /// /// NetworkManager to use. When null default value will be returned. /// True if the value was updated this local tick. public uint Value(TimeManager tm, out bool isCurrent) { isCurrent = IsCurrent(tm); if (tm == null) return 0; if (IsUnset) return 0; uint diff = (tm.LocalTick - LocalTick); return (diff + RemoteTick); } /// /// Resets values to unset. /// public void Reset() { LocalTick = 0; RemoteTick = 0; LastRemoteTick = 0; } } }