diff --git a/Assets/NetworkPositionSync/Runtime/InterpolationTime.cs b/Assets/NetworkPositionSync/Runtime/InterpolationTime.cs index af1487e..2021d81 100644 --- a/Assets/NetworkPositionSync/Runtime/InterpolationTime.cs +++ b/Assets/NetworkPositionSync/Runtime/InterpolationTime.cs @@ -66,7 +66,7 @@ public class InterpolationTime /// /// The time value that the client uses to interpolate /// - private float _clientTime; + private double _clientTime; /// /// The client will multiply deltaTime by this scale time value each frame @@ -97,12 +97,12 @@ public class InterpolationTime private float _clientDelay; // Used for debug purposes. Move along... - private float _latestServerTime; + private double _latestServerTime; /// /// Timer that follows server time /// - public float ClientTime + public double ClientTime { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _clientTime; @@ -110,14 +110,14 @@ public float ClientTime /// /// Returns the last time received by the server /// - public float LatestServerTime + public double LatestServerTime { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _latestServerTime; } [System.Obsolete("Use Time instead")] - public float InterpolationTimeField + public double InterpolationTimeField { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Time; @@ -126,7 +126,7 @@ public float InterpolationTimeField /// /// Current time to use for interpolation /// - public float Time + public double Time { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _clientTime - _clientDelay; @@ -170,7 +170,7 @@ public void OnUpdate(float deltaTime) _clientTime += deltaTime * clientScaleTime; } - public bool IsMessageOutOfOrder(float newServerTime) + public bool IsMessageOutOfOrder(double newServerTime) { return newServerTime < _latestServerTime; } @@ -179,7 +179,7 @@ public bool IsMessageOutOfOrder(float newServerTime) /// Updates to keep in line with /// /// - public void OnMessage(float serverTime) + public void OnMessage(double serverTime) { // only check this if we are initialized if (initialized) @@ -231,7 +231,7 @@ public void Reset() /// /// Initializes and resets the system. /// - private void InitNew(float serverTime) + private void InitNew(double serverTime) { _clientTime = serverTime; clientScaleTime = 1; @@ -261,7 +261,7 @@ private float CalculateTimeScale(float diff) 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; + return 1 - (_scaleModifier * 4); else // Server and client are on par ("close enough"). Run at normal speed. return 1; diff --git a/Assets/NetworkPositionSync/Runtime/SyncPositionBehaviour.cs b/Assets/NetworkPositionSync/Runtime/SyncPositionBehaviour.cs index 3e5315d..4e3f0a1 100644 --- a/Assets/NetworkPositionSync/Runtime/SyncPositionBehaviour.cs +++ b/Assets/NetworkPositionSync/Runtime/SyncPositionBehaviour.cs @@ -59,7 +59,7 @@ internal bool NeedsUpdate() /// Applies a state update on the server instance. /// Called on server. /// - internal void ApplyOnServer(TransformState state, float time) + internal void ApplyOnServer(TransformState state, double time) { // This should not happen. throw an Exception to disconnect the attacker if (!clientAuthority) @@ -80,7 +80,7 @@ internal void ApplyOnServer(TransformState state, float time) /// Applies a state update on the client instance. /// Called on client. /// - internal void ApplyOnClient(TransformState state, float time) + internal void ApplyOnClient(TransformState state, double time) { // Not host. // Host will have already handled movement in servers code @@ -311,7 +311,7 @@ public void OnStopClient() public void OnStopServer() { // null check incase OnStopClient is called first - if (_system !=null) + if (_system != null) _system.Behaviours.RemoveBehaviour(this); _system = null; } @@ -335,7 +335,7 @@ private void Update() /// Adds to buffer for interpolation /// /// - private void AddSnapShotToBuffer(TransformState state, float serverTime) + private void AddSnapShotToBuffer(TransformState state, double serverTime) { // dont apply on local owner if (IsLocalClientInControl) diff --git a/Assets/NetworkPositionSync/Runtime/SyncPositionBehaviour_Debug.cs b/Assets/NetworkPositionSync/Runtime/SyncPositionBehaviour_Debug.cs index 1e14795..f8f7344 100644 --- a/Assets/NetworkPositionSync/Runtime/SyncPositionBehaviour_Debug.cs +++ b/Assets/NetworkPositionSync/Runtime/SyncPositionBehaviour_Debug.cs @@ -60,11 +60,11 @@ private void Update() markers[i].SetActive(true); markers[i].transform.SetPositionAndRotation(snapshot.state.position, snapshot.state.rotation); var pos = snapshot.state.position; - var hash = pos.x * 501 + pos.z; - markers[i].GetComponent().material.color = Color.HSVToRGB((hash * 20) % 1, 1, 1); + var hash = (pos.x * 501) + pos.z; + markers[i].GetComponent().material.color = Color.HSVToRGB(hash * 20 % 1, 1, 1); var snapshotTime = _system.TimeSync.InterpolationTimeField; - var absTimeDiff = Mathf.Abs(snapshotTime - (float)snapshot.time); + var absTimeDiff = Mathf.Abs((float)(snapshotTime - snapshot.time)); var sizeFromDiff = Mathf.Clamp01((maxTime - absTimeDiff) / maxTime); var scale = sizeFromDiff * MaxScale; markers[i].transform.localScale = Vector3.one * scale; diff --git a/Assets/NetworkPositionSync/Runtime/SyncPositionSystem.cs b/Assets/NetworkPositionSync/Runtime/SyncPositionSystem.cs index 88ed66c..77fecbb 100644 --- a/Assets/NetworkPositionSync/Runtime/SyncPositionSystem.cs +++ b/Assets/NetworkPositionSync/Runtime/SyncPositionSystem.cs @@ -160,10 +160,10 @@ public class SyncPositionSystem : MonoBehaviour [Header("Snapshot Interpolation")] [Tooltip("Number of ticks to delay interpolation to make sure there is always a snapshot to interpolate towards. High delay can handle more jitter, but adds latancy to the position.")] public float TickDelayCount = 2; - + [Tooltip("How much to modify the timescale of interpolation clock when ahead or behind the server")] public float TimeScaleModifier = 0.01f; - + [Tooltip("SendToAll option skips visibility and sends position to all ready connections.")] public SyncMode syncMode = SyncMode.SendToAll; @@ -270,7 +270,7 @@ public void Update() ClientUpdate(timer.Delta); } - private void ServerUpdate(float time) + private void ServerUpdate(double time) { if (!ServerActive) return; @@ -309,7 +309,7 @@ private void ClientUpdate(float deltaTime) TimeSync.OnUpdate(deltaTime); } - internal void SendUpdateToAll(float time) + internal void SendUpdateToAll(double time) { // dont send message if no behaviours if (Behaviours.Dictionary.Count == 0) @@ -343,7 +343,7 @@ internal void SendUpdateToAll(float time) /// Loops through all players, followed by all dirty objects and checks if the player object can see each one /// /// - internal void SendUpdateToObservers_PlayerDirty(float time) + internal void SendUpdateToObservers_PlayerDirty(double time) { // dont send message if no behaviours if (Behaviours.Dictionary.Count == 0) @@ -382,7 +382,7 @@ internal void SendUpdateToObservers_PlayerDirty(float time) /// ...except this one packs data once. /// /// - internal void SendUpdateToObservers_PlayerDirty_PackOnce(float time) + internal void SendUpdateToObservers_PlayerDirty_PackOnce(double time) { // dont send message if no behaviours if (Behaviours.Dictionary.Count == 0) @@ -441,7 +441,7 @@ private PooledNetworkWriter GetWriterFromPool_Behaviours(SyncPositionBehaviour b /// Loops through all dirty objects, and then their observers and then writes that behaviouir to a cahced writer /// /// - internal void SendUpdateToObservers_DirtyObservers(float time) + internal void SendUpdateToObservers_DirtyObservers(double time) { // dont send message if no behaviours if (Behaviours.Dictionary.Count == 0) @@ -477,7 +477,7 @@ internal void SendUpdateToObservers_DirtyObservers(float time) /// But Packs once and copies bytes /// /// - internal void SendUpdateToObservers_DirtyObservers_PackOnce(float time) + internal void SendUpdateToObservers_DirtyObservers_PackOnce(double time) { // dont send message if no behaviours if (Behaviours.Dictionary.Count == 0) @@ -518,7 +518,7 @@ internal void SendUpdateToObservers_DirtyObservers_PackOnce(float time) private Dictionary writerPool = new Dictionary(); - private PooledNetworkWriter GetWriterFromPool(float time, INetworkPlayer player) + private PooledNetworkWriter GetWriterFromPool(double time, INetworkPlayer player) { if (!writerPool.TryGetValue(player, out var writer)) { @@ -606,30 +606,30 @@ internal void ServerHandleNetworkPositionMessage(INetworkPlayer _, NetworkPositi public class Timer { private readonly Stopwatch stopwatch = Stopwatch.StartNew(); - private float _previous; + private double _previous; private float _delta; - private float _now; + private double _now; public float Delta { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _delta; } - public float Now + public double Now { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _now; } - private float GetNow() + private double GetNow() { - return (float)(stopwatch.Elapsed.TotalMilliseconds / 1000f); + return (double)(stopwatch.Elapsed.TotalMilliseconds / 1000.0); } public void Update() { _now = GetNow(); - _delta = _now - _previous; + _delta = (float)(_now - _previous); _previous = _now; } } diff --git a/Assets/NetworkPositionSync/Runtime/SyncSettings.cs b/Assets/NetworkPositionSync/Runtime/SyncSettings.cs index 2403b27..5b2753e 100644 --- a/Assets/NetworkPositionSync/Runtime/SyncSettings.cs +++ b/Assets/NetworkPositionSync/Runtime/SyncSettings.cs @@ -26,6 +26,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE using Mirage; using Mirage.Serialization; using UnityEngine; +using static JamesFrowen.PositionSync.SyncPacker; namespace JamesFrowen.PositionSync { @@ -55,9 +56,9 @@ public class SyncSettings public int bitCount = 10; // Data Packers. - public VarFloatPacker CreateTimePacker() + public VarDoublePacker CreateTimePacker() { - return new VarFloatPacker(timePrecision, blockSize); + return new VarDoublePacker(timePrecision, blockSize); } public VarVector3Packer CreatePositionPacker() { @@ -72,7 +73,7 @@ public QuaternionPacker CreateRotationPacker() public class SyncPacker { // packers - private readonly VarFloatPacker timePacker; + private readonly VarDoublePacker timePacker; private readonly VarVector3Packer positionPacker; private readonly QuaternionPacker rotationPacker; private readonly int blockSize; @@ -87,7 +88,7 @@ public SyncPacker(SyncSettings settings) includeCompId = settings.IncludeComponentIndex; } - public void PackTime(NetworkWriter writer, float time) + public void PackTime(NetworkWriter writer, double time) { timePacker.Pack(writer, time); } @@ -110,7 +111,7 @@ public void PackNext(NetworkWriter writer, SyncPositionBehaviour behaviour) } - public float UnpackTime(NetworkReader reader) + public double UnpackTime(NetworkReader reader) { return timePacker.Unpack(reader); } @@ -150,6 +151,39 @@ internal bool TryUnpackNext(PooledNetworkReader reader, out NetworkBehaviour.Id return false; } } + + + + /// + /// Packs a float using and + /// + public sealed class VarDoublePacker + { + private readonly int _blockSize; + private readonly double _precision; + private readonly double _inversePrecision; + + public VarDoublePacker(double precision, int blockSize) + { + _precision = precision; + _blockSize = blockSize; + _inversePrecision = 1 / precision; + } + + public void Pack(NetworkWriter writer, double value) + { + var scaled = (int)Math.Round(value * _inversePrecision); + var zig = ZigZag.Encode(scaled); + VarIntBlocksPacker.Pack(writer, zig, _blockSize); + } + + public double Unpack(NetworkReader reader) + { + var zig = (uint)VarIntBlocksPacker.Unpack(reader, _blockSize); + var scaled = ZigZag.Decode(zig); + return scaled * _precision; + } + } } //[Serializable]