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
This commit is contained in:
vis2k 2021-07-07 22:22:15 +08:00 committed by GitHub
parent 9ac3cf9534
commit 188be9ead0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 18 additions and 15 deletions

View File

@ -24,7 +24,8 @@ public enum Visibility { Default, ForceHidden, ForceShown }
public struct NetworkIdentitySerialization public struct NetworkIdentitySerialization
{ {
public float tickTimeStamp; // IMPORTANT: int tick avoids floating point inaccuracy over days/weeks
public int tick;
public NetworkWriter ownerWriter; public NetworkWriter ownerWriter;
public NetworkWriter observersWriter; public NetworkWriter observersWriter;
// TODO there is probably a more simple way later // 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) // get cached serialization for this tick (or serialize if none yet)
// IMPORTANT: needs FRAME TIME which doesn't change during THIS FRAME! // IMPORTANT: int tick avoids floating point inaccuracy over days/weeks
internal NetworkIdentitySerialization GetSerializationAtTick(float tickTimeStamp) internal NetworkIdentitySerialization GetSerializationAtTick(int tick)
{ {
// serialize fresh if tick is newer than last one // reserialize if tick is different than last changed.
if (lastSerialization.tickTimeStamp < tickTimeStamp) // NOTE: != instead of < because int.max+1 overflows at some point.
if (lastSerialization.tick != tick)
{ {
// reset // reset
lastSerialization.ownerWriter.Position = 0; lastSerialization.ownerWriter.Position = 0;
@ -957,8 +959,8 @@ internal NetworkIdentitySerialization GetSerializationAtTick(float tickTimeStamp
lastSerialization.observersWriter, lastSerialization.observersWriter,
out lastSerialization.observersWritten); out lastSerialization.observersWritten);
// set timestamp // set tick
lastSerialization.tickTimeStamp = tickTimeStamp; lastSerialization.tick = tick;
//Debug.Log($"{name} (netId={netId}) serialized for tick={tickTimeStamp}"); //Debug.Log($"{name} (netId={netId}) serialized for tick={tickTimeStamp}");
} }

View File

@ -1432,8 +1432,8 @@ public static void RebuildObservers(NetworkIdentity identity, bool initialize)
static NetworkWriter GetEntitySerializationForConnection(NetworkIdentity identity, NetworkConnectionToClient connection) static NetworkWriter GetEntitySerializationForConnection(NetworkIdentity identity, NetworkConnectionToClient connection)
{ {
// get serialization for this entity (cached) // get serialization for this entity (cached)
// IMPORTANT: needs FRAME TIME which doesn't change during THIS FRAME! // IMPORTANT: int tick avoids floating point inaccuracy over days/weeks
NetworkIdentitySerialization serialization = identity.GetSerializationAtTick(Time.time); NetworkIdentitySerialization serialization = identity.GetSerializationAtTick(Time.frameCount);
// is this entity owned by this connection? // is this entity owned by this connection?
bool owned = identity.connectionToClient == connection; bool owned = identity.connectionToClient == connection;

View File

@ -64,14 +64,15 @@ public IEnumerator OnDestroyIsServerTrueWhenNetworkServerDestroyIsCalled()
public IEnumerator TestSerializationWithLargeTimestamps() public IEnumerator TestSerializationWithLargeTimestamps()
{ {
// 14 * 24 hours per day * 60 minutes per hour * 60 seconds per minute = 14 days // 14 * 24 hours per day * 60 minutes per hour * 60 seconds per minute = 14 days
float time = 14 * 24 * 60 * 60; // NOTE: change this to 'float' to see the tests fail
NetworkIdentitySerialization serialization = identity.GetSerializationAtTick(time); int tick = 14 * 24 * 60 * 60;
// advance time by 50ms (20 fps) NetworkIdentitySerialization serialization = identity.GetSerializationAtTick(tick);
time += 0.05f; // advance tick
NetworkIdentitySerialization serializationNew = identity.GetSerializationAtTick(time); ++tick;
NetworkIdentitySerialization serializationNew = identity.GetSerializationAtTick(tick);
// if the serialization has been changed the tickTimeStamp should have moved // 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; yield break;
} }
} }