From 188be9ead0b2bca3739015b9d7526f305feeadfb Mon Sep 17 00:00:00 2001 From: vis2k Date: Wed, 7 Jul 2021 22:22:15 +0800 Subject: [PATCH] fix: serialization precision over days by using frameCount instead of single precision time (#2815) * fix: serialization precision over days by saving a double timestamp at the start of Broadcast() once * use tick instead --- Assets/Mirror/Runtime/NetworkIdentity.cs | 16 +++++++++------- Assets/Mirror/Runtime/NetworkServer.cs | 4 ++-- .../Mirror/Tests/Runtime/NetworkIdentityTests.cs | 13 +++++++------ 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/Assets/Mirror/Runtime/NetworkIdentity.cs b/Assets/Mirror/Runtime/NetworkIdentity.cs index 74c2a5405..763a8ad34 100644 --- a/Assets/Mirror/Runtime/NetworkIdentity.cs +++ b/Assets/Mirror/Runtime/NetworkIdentity.cs @@ -24,7 +24,8 @@ public enum Visibility { Default, ForceHidden, ForceShown } public struct NetworkIdentitySerialization { - public float tickTimeStamp; + // IMPORTANT: int tick avoids floating point inaccuracy over days/weeks + public int tick; public NetworkWriter ownerWriter; public NetworkWriter observersWriter; // TODO there is probably a more simple way later @@ -940,11 +941,12 @@ internal void OnSerializeAllSafely(bool initialState, NetworkWriter ownerWriter, } // get cached serialization for this tick (or serialize if none yet) - // IMPORTANT: needs FRAME TIME which doesn't change during THIS FRAME! - internal NetworkIdentitySerialization GetSerializationAtTick(float tickTimeStamp) + // IMPORTANT: int tick avoids floating point inaccuracy over days/weeks + internal NetworkIdentitySerialization GetSerializationAtTick(int tick) { - // serialize fresh if tick is newer than last one - if (lastSerialization.tickTimeStamp < tickTimeStamp) + // reserialize if tick is different than last changed. + // NOTE: != instead of < because int.max+1 overflows at some point. + if (lastSerialization.tick != tick) { // reset lastSerialization.ownerWriter.Position = 0; @@ -957,8 +959,8 @@ internal NetworkIdentitySerialization GetSerializationAtTick(float tickTimeStamp lastSerialization.observersWriter, out lastSerialization.observersWritten); - // set timestamp - lastSerialization.tickTimeStamp = tickTimeStamp; + // set tick + lastSerialization.tick = tick; //Debug.Log($"{name} (netId={netId}) serialized for tick={tickTimeStamp}"); } diff --git a/Assets/Mirror/Runtime/NetworkServer.cs b/Assets/Mirror/Runtime/NetworkServer.cs index 165cf3ebf..235b09ff7 100644 --- a/Assets/Mirror/Runtime/NetworkServer.cs +++ b/Assets/Mirror/Runtime/NetworkServer.cs @@ -1432,8 +1432,8 @@ public static void RebuildObservers(NetworkIdentity identity, bool initialize) static NetworkWriter GetEntitySerializationForConnection(NetworkIdentity identity, NetworkConnectionToClient connection) { // get serialization for this entity (cached) - // IMPORTANT: needs FRAME TIME which doesn't change during THIS FRAME! - NetworkIdentitySerialization serialization = identity.GetSerializationAtTick(Time.time); + // IMPORTANT: int tick avoids floating point inaccuracy over days/weeks + NetworkIdentitySerialization serialization = identity.GetSerializationAtTick(Time.frameCount); // is this entity owned by this connection? bool owned = identity.connectionToClient == connection; diff --git a/Assets/Mirror/Tests/Runtime/NetworkIdentityTests.cs b/Assets/Mirror/Tests/Runtime/NetworkIdentityTests.cs index 8b2e6f6fe..e92433b73 100644 --- a/Assets/Mirror/Tests/Runtime/NetworkIdentityTests.cs +++ b/Assets/Mirror/Tests/Runtime/NetworkIdentityTests.cs @@ -64,14 +64,15 @@ public IEnumerator OnDestroyIsServerTrueWhenNetworkServerDestroyIsCalled() public IEnumerator TestSerializationWithLargeTimestamps() { // 14 * 24 hours per day * 60 minutes per hour * 60 seconds per minute = 14 days - float time = 14 * 24 * 60 * 60; - NetworkIdentitySerialization serialization = identity.GetSerializationAtTick(time); - // advance time by 50ms (20 fps) - time += 0.05f; - NetworkIdentitySerialization serializationNew = identity.GetSerializationAtTick(time); + // NOTE: change this to 'float' to see the tests fail + int tick = 14 * 24 * 60 * 60; + NetworkIdentitySerialization serialization = identity.GetSerializationAtTick(tick); + // advance tick + ++tick; + NetworkIdentitySerialization serializationNew = identity.GetSerializationAtTick(tick); // if the serialization has been changed the tickTimeStamp should have moved - Assert.That(serialization.tickTimeStamp == serializationNew.tickTimeStamp, Is.False); + Assert.That(serialization.tick == serializationNew.tick, Is.False); yield break; } }