Skip to content

Commit f59e691

Browse files
pkaminskiTwoTenPvP
authored andcommitted
fix(core): improve accuracy of NetworkTime and smear changes on resync. (#228)
1 parent 7f0d80c commit f59e691

File tree

5 files changed

+45
-18
lines changed

5 files changed

+45
-18
lines changed

MLAPI-Editor/NetworkingManagerEditor.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public class NetworkingManagerEditor : Editor
3232
private SerializedProperty connectionApprovalProperty;
3333
private SerializedProperty secondsHistoryProperty;
3434
private SerializedProperty enableTimeResyncProperty;
35+
private SerializedProperty timeResyncIntervalProperty;
3536
private SerializedProperty enableNetworkedVarProperty;
3637
private SerializedProperty ensureNetworkedVarLengthSafetyProperty;
3738
private SerializedProperty forceSamePrefabsProperty;
@@ -108,6 +109,7 @@ private void Init()
108109
connectionApprovalProperty = networkConfigProperty.FindPropertyRelative("ConnectionApproval");
109110
secondsHistoryProperty = networkConfigProperty.FindPropertyRelative("SecondsHistory");
110111
enableTimeResyncProperty = networkConfigProperty.FindPropertyRelative("EnableTimeResync");
112+
timeResyncIntervalProperty = networkConfigProperty.FindPropertyRelative("TimeResyncInterval");
111113
enableNetworkedVarProperty = networkConfigProperty.FindPropertyRelative("EnableNetworkedVar");
112114
ensureNetworkedVarLengthSafetyProperty = networkConfigProperty.FindPropertyRelative("EnsureNetworkedVarLengthSafety");
113115
forceSamePrefabsProperty = networkConfigProperty.FindPropertyRelative("ForceSamePrefabs");
@@ -144,6 +146,7 @@ private void CheckNullProperties()
144146
connectionApprovalProperty = networkConfigProperty.FindPropertyRelative("ConnectionApproval");
145147
secondsHistoryProperty = networkConfigProperty.FindPropertyRelative("SecondsHistory");
146148
enableTimeResyncProperty = networkConfigProperty.FindPropertyRelative("EnableTimeResync");
149+
timeResyncIntervalProperty = networkConfigProperty.FindPropertyRelative("TimeResyncInterval");
147150
enableNetworkedVarProperty = networkConfigProperty.FindPropertyRelative("EnableNetworkedVar");
148151
ensureNetworkedVarLengthSafetyProperty = networkConfigProperty.FindPropertyRelative("EnsureNetworkedVarLengthSafety");
149152
forceSamePrefabsProperty = networkConfigProperty.FindPropertyRelative("ForceSamePrefabs");
@@ -277,7 +280,8 @@ public override void OnInspectorGUI()
277280
}
278281

279282
EditorGUILayout.PropertyField(enableTimeResyncProperty);
280-
283+
EditorGUILayout.PropertyField(timeResyncIntervalProperty);
284+
281285
EditorGUILayout.LabelField("Performance", EditorStyles.boldLabel);
282286
EditorGUILayout.PropertyField(receiveTickrateProperty);
283287
EditorGUILayout.PropertyField(maxReceiveEventsPerTickRateProperty);

MLAPI/Configuration/NetworkConfig.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@ public class NetworkConfig
9696
[Tooltip("Enable this to resync the NetworkedTime after the initial sync")]
9797
public bool EnableTimeResync = false;
9898
/// <summary>
99+
/// If time resync is turned on, this specifies the interval between syncs in seconds.
100+
/// </summary>
101+
[Tooltip("The amount of seconds between resyncs of NetworkedTime, if enabled")]
102+
public int TimeResyncInterval = 30;
103+
/// <summary>
99104
/// Whether or not to enable the NetworkedVar system. This system runs in the Update loop and will degrade performance, but it can be a huge convenience.
100105
/// Only turn it off if you have no need for the NetworkedVar system.
101106
/// </summary>

MLAPI/Core/NetworkingManager.cs

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,12 @@ namespace MLAPI
3232
public class NetworkingManager : MonoBehaviour
3333
{
3434
/// <summary>
35-
/// A syncronized time, represents the time in seconds since the server application started. Is replicated across all clients
35+
/// A synchronized time, represents the time in seconds since the server application started. Is replicated across all clients
3636
/// </summary>
37-
public float NetworkTime { get; internal set; }
37+
public float NetworkTime => Time.unscaledTime + currentNetworkTimeOffset;
38+
private float networkTimeOffset;
39+
private float currentNetworkTimeOffset;
40+
private bool networkTimeInitialized;
3841
/// <summary>
3942
/// Gets or sets if the NetworkingManager should be marked as DontDestroyOnLoad
4043
/// </summary>
@@ -297,7 +300,9 @@ private void Init(bool server)
297300
if (LogHelper.CurrentLogLevel <= LogLevel.Developer) LogHelper.LogInfo("Init()");
298301

299302
LocalClientId = 0;
300-
NetworkTime = 0f;
303+
networkTimeOffset = 0f;
304+
currentNetworkTimeOffset = 0f;
305+
networkTimeInitialized = false;
301306
lastSendTickTime = 0f;
302307
lastEventTickTime = 0f;
303308
lastReceiveTickTime = 0f;
@@ -733,19 +738,35 @@ private void Update()
733738
NetworkProfiler.EndTick();
734739
}
735740

736-
if (IsServer && NetworkConfig.EnableTimeResync && NetworkTime - lastTimeSyncTime >= 30)
741+
if (IsServer && NetworkConfig.EnableTimeResync && NetworkTime - lastTimeSyncTime >= NetworkConfig.TimeResyncInterval)
737742
{
738743
NetworkProfiler.StartTick(TickType.Event);
739744
SyncTime();
740745
lastTimeSyncTime = NetworkTime;
741746
NetworkProfiler.EndTick();
742747
}
743748

744-
NetworkTime += Time.unscaledDeltaTime;
749+
if (!Mathf.Approximately(networkTimeOffset, currentNetworkTimeOffset)) {
750+
// Smear network time adjustments by no more than 200ms per second. This should help code deal with
751+
// changes more gracefully, since the network time will always flow forward at a reasonable pace.
752+
float maxDelta = Mathf.Max(0.001f, 0.2f * Time.unscaledDeltaTime);
753+
currentNetworkTimeOffset += Mathf.Clamp(networkTimeOffset - currentNetworkTimeOffset, -maxDelta, maxDelta);
754+
}
745755
}
746756
}
747757

748-
internal void SendConnectionRequest()
758+
internal void UpdateNetworkTime(ulong clientId, float netTime)
759+
{
760+
float rtt = NetworkConfig.NetworkTransport.GetCurrentRtt(clientId) / 1000f;
761+
networkTimeOffset = netTime - Time.realtimeSinceStartup + rtt / 2f;
762+
if (!networkTimeInitialized) {
763+
currentNetworkTimeOffset = networkTimeOffset;
764+
networkTimeInitialized = true;
765+
}
766+
if (LogHelper.CurrentLogLevel <= LogLevel.Developer) LogHelper.LogInfo($"Received network time {netTime}, RTT to server is {rtt}, setting offset to {networkTimeOffset} (delta {networkTimeOffset - currentNetworkTimeOffset})");
767+
}
768+
769+
internal void SendConnectionRequest()
749770
{
750771
using (PooledBitStream stream = PooledBitStream.Get())
751772
{
@@ -997,8 +1018,8 @@ private void SyncTime()
9971018
{
9981019
using (PooledBitWriter writer = PooledBitWriter.Get(stream))
9991020
{
1000-
writer.WriteSinglePacked(NetworkTime);
1001-
InternalMessageSender.Send(MLAPIConstants.MLAPI_TIME_SYNC, "MLAPI_TIME_SYNC", stream, SecuritySendFlags.None, null);
1021+
writer.WriteSinglePacked(Time.realtimeSinceStartup);
1022+
InternalMessageSender.Send(MLAPIConstants.MLAPI_TIME_SYNC, "MLAPI_TIME_SYNC", stream, SecuritySendFlags.None, null, true);
10021023
}
10031024
}
10041025
}
@@ -1049,7 +1070,7 @@ internal void HandleApproval(ulong clientId, ulong? prefabHash, bool approved, V
10491070
writer.WriteUInt32Packed(NetworkSceneManager.currentSceneIndex);
10501071
writer.WriteByteArray(NetworkSceneManager.currentSceneSwitchProgressGuid.ToByteArray());
10511072

1052-
writer.WriteSinglePacked(NetworkTime);
1073+
writer.WriteSinglePacked(Time.realtimeSinceStartup);
10531074

10541075
writer.WriteUInt32Packed((uint)_observedObjects.Count);
10551076

MLAPI/Messaging/InternalMessageHandler.cs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,7 @@ internal static void HandleConnectionApproved(ulong clientId, Stream stream)
206206
Guid sceneSwitchProgressGuid = new Guid(reader.ReadByteArray());
207207

208208
float netTime = reader.ReadSinglePacked();
209-
ulong msDelay = NetworkingManager.Singleton.NetworkConfig.NetworkTransport.GetCurrentRtt(clientId);
210-
211-
NetworkingManager.Singleton.NetworkTime = netTime + (msDelay / 1000f);
209+
NetworkingManager.Singleton.UpdateNetworkTime(clientId, netTime);
212210

213211
NetworkingManager.Singleton.ConnectedClients.Add(NetworkingManager.Singleton.LocalClientId, new NetworkedClient() { ClientId = NetworkingManager.Singleton.LocalClientId });
214212

@@ -430,9 +428,7 @@ internal static void HandleTimeSync(ulong clientId, Stream stream)
430428
using (PooledBitReader reader = PooledBitReader.Get(stream))
431429
{
432430
float netTime = reader.ReadSinglePacked();
433-
ulong msDelay = NetworkingManager.Singleton.NetworkConfig.NetworkTransport.GetCurrentRtt(clientId);
434-
435-
NetworkingManager.Singleton.NetworkTime = netTime + (msDelay / 1000f);
431+
NetworkingManager.Singleton.UpdateNetworkTime(clientId, netTime);
436432
}
437433
}
438434

@@ -644,5 +640,6 @@ internal static void HandleCustomMessage(ulong clientId, Stream stream)
644640
{
645641
NetworkingManager.Singleton.InvokeOnIncomingCustomMessage(clientId, stream);
646642
}
643+
647644
}
648645
}

MLAPI/Messaging/InternalMessageSender.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ internal static void Send(ulong clientId, byte messageType, string channelName,
3333
}
3434
}
3535

36-
internal static void Send(byte messageType, string channelName, BitStream messageStream, SecuritySendFlags flags, NetworkedObject targetObject)
36+
internal static void Send(byte messageType, string channelName, BitStream messageStream, SecuritySendFlags flags, NetworkedObject targetObject, bool skipQueue = false)
3737
{
3838
bool encrypted = ((flags & SecuritySendFlags.Encrypted) == SecuritySendFlags.Encrypted) && NetworkingManager.Singleton.NetworkConfig.EnableEncryption;
3939
bool authenticated = ((flags & SecuritySendFlags.Authenticated) == SecuritySendFlags.Authenticated) && NetworkingManager.Singleton.NetworkConfig.EnableEncryption;
@@ -63,7 +63,7 @@ internal static void Send(byte messageType, string channelName, BitStream messag
6363
continue;
6464
}
6565

66-
NetworkingManager.Singleton.NetworkConfig.NetworkTransport.Send(NetworkingManager.Singleton.ConnectedClientsList[i].ClientId, new ArraySegment<byte>(stream.GetBuffer(), 0, (int)stream.Length), channelName, false);
66+
NetworkingManager.Singleton.NetworkConfig.NetworkTransport.Send(NetworkingManager.Singleton.ConnectedClientsList[i].ClientId, new ArraySegment<byte>(stream.GetBuffer(), 0, (int)stream.Length), channelName, skipQueue);
6767
}
6868
NetworkProfiler.EndEvent();
6969
}

0 commit comments

Comments
 (0)