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

View File

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

View File

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