diff --git a/Assets/Mirror/Components/NetworkTransform/NetworkTransformBase.cs b/Assets/Mirror/Components/NetworkTransform/NetworkTransformBase.cs index cff87f3f67d..4478ff87aa8 100644 --- a/Assets/Mirror/Components/NetworkTransform/NetworkTransformBase.cs +++ b/Assets/Mirror/Components/NetworkTransform/NetworkTransformBase.cs @@ -439,6 +439,8 @@ public virtual void Reset() // default to ClientToServer so this works immediately for users syncDirection = SyncDirection.ClientToServer; + NetworkTime.highPingComponents = 0UL; + // default to 20Hz, 20 sends per second if data has changed. syncInterval = 0.05f; } @@ -446,6 +448,7 @@ public virtual void Reset() protected virtual void OnEnable() { ResetState(); + NetworkTime.highPingComponents++; if (NetworkServer.active) NetworkIdentity.clientAuthorityCallback += OnClientAuthorityChanged; @@ -455,6 +458,9 @@ protected virtual void OnDisable() { ResetState(); + if (NetworkTime.highPingComponents > 0UL) + NetworkTime.highPingComponents--; + if (NetworkServer.active) NetworkIdentity.clientAuthorityCallback -= OnClientAuthorityChanged; } diff --git a/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs index 02abda30781..d3a61e6d975 100644 --- a/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs +++ b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs @@ -145,6 +145,17 @@ protected virtual void Awake() positionCorrectionThresholdSqr = positionCorrectionThreshold * positionCorrectionThreshold; } + protected virtual void OnEnable() + { + NetworkTime.highPingComponents++; + } + + protected virtual void OnDisable() + { + if (NetworkTime.highPingComponents > 0UL) + NetworkTime.highPingComponents--; + } + protected virtual void CopyRenderersAsGhost(GameObject destination, Material material) { // find the MeshRenderer component, which sometimes is on a child. diff --git a/Assets/Mirror/Core/NetworkClient.cs b/Assets/Mirror/Core/NetworkClient.cs index ab160c155e8..294d5fdf203 100644 --- a/Assets/Mirror/Core/NetworkClient.cs +++ b/Assets/Mirror/Core/NetworkClient.cs @@ -1753,7 +1753,8 @@ static void Broadcast(bool unreliableBaselineElapsed) if (NetworkServer.active) return; // send time snapshot every sendInterval. - Send(new TimeSnapshotMessage(), Channels.Unreliable); + if (NetworkTime.highPingComponents > 0UL) + Send(new TimeSnapshotMessage(), Channels.Unreliable); // broadcast client state to server BroadcastToServer(unreliableBaselineElapsed); diff --git a/Assets/Mirror/Core/NetworkConnectionToClient.cs b/Assets/Mirror/Core/NetworkConnectionToClient.cs index d80749c13ed..8e04cf9671c 100644 --- a/Assets/Mirror/Core/NetworkConnectionToClient.cs +++ b/Assets/Mirror/Core/NetworkConnectionToClient.cs @@ -136,6 +136,8 @@ protected virtual void UpdatePing() // localTime (double) instead of Time.time for accuracy over days if (NetworkTime.localTime >= lastPingTime + NetworkTime.PingInterval) { + //Debug.Log("NetworkConnectionToClient SendPing"); + // TODO it would be safer for the server to store the last N // messages' timestamp and only send a message number. // This way client's can't just modify the timestamp. diff --git a/Assets/Mirror/Core/NetworkServer.cs b/Assets/Mirror/Core/NetworkServer.cs index 554851e452a..91849c49560 100644 --- a/Assets/Mirror/Core/NetworkServer.cs +++ b/Assets/Mirror/Core/NetworkServer.cs @@ -2276,7 +2276,8 @@ static void Broadcast(bool unreliableBaselineElapsed) // make sure Broadcast() is only called every sendInterval, // even if targetFrameRate isn't set in host mode (!) // (done via AccurateInterval) - connection.Send(new TimeSnapshotMessage(), Channels.Unreliable); + if (NetworkTime.highPingComponents > 0UL) + connection.Send(new TimeSnapshotMessage(), Channels.Unreliable); // broadcast world state to this connection BroadcastToConnection(connection, unreliableBaselineElapsed); diff --git a/Assets/Mirror/Core/NetworkTime.cs b/Assets/Mirror/Core/NetworkTime.cs index 6319970c45b..02de2609095 100644 --- a/Assets/Mirror/Core/NetworkTime.cs +++ b/Assets/Mirror/Core/NetworkTime.cs @@ -16,11 +16,17 @@ namespace Mirror /// Synchronizes server time to clients. public static class NetworkTime { + // Incremented / decremented by components that need higher ping frequency. + // Also used to determine if we need to send TimeSnapshotMessage by + // NetworkServer and NetworkClient. + internal static ulong highPingComponents = 0UL; + const float highPingInterval = 0.1f; + /// Ping message interval, used to calculate latency / RTT and predicted time. - // 2s was enough to get a good average RTT. - // for prediction, we want to react to latency changes more rapidly. - const float DefaultPingInterval = 0.1f; // for resets - public static float PingInterval = DefaultPingInterval; + // 2s is enough to get a good average RTT. + // For snapshot interpolation and prediction, we need to react to latency changes more rapidly. + internal static float defaultPingInterval = 2.0f; // internal for tests + public static float PingInterval => highPingComponents > 0UL ? highPingInterval : defaultPingInterval; /// Average out the last few results from Ping // const because it's used immediately in _rtt constructor. @@ -129,7 +135,8 @@ public static double predictedTime [RuntimeInitializeOnLoadMethod] public static void ResetStatics() { - PingInterval = DefaultPingInterval; + defaultPingInterval = 2.0f; + highPingComponents = 0UL; lastPingTime = 0; _rtt = new ExponentialMovingAverage(PingWindowSize); #if !UNITY_2020_3_OR_NEWER @@ -147,6 +154,8 @@ internal static void UpdateClient() // Separate method so we can call it from NetworkClient directly. internal static void SendPing() { + //Debug.Log("NetworkTime SendPing"); + // send raw predicted time without the offset applied yet. // we then apply the offset to it after. NetworkPingMessage pingMessage = new NetworkPingMessage diff --git a/Assets/Mirror/Tests/Editor/NetworkConnection/NetworkConnectionToClientTests.cs b/Assets/Mirror/Tests/Editor/NetworkConnection/NetworkConnectionToClientTests.cs index 75b349c92e3..1b6c59ed86f 100644 --- a/Assets/Mirror/Tests/Editor/NetworkConnection/NetworkConnectionToClientTests.cs +++ b/Assets/Mirror/Tests/Editor/NetworkConnection/NetworkConnectionToClientTests.cs @@ -35,7 +35,7 @@ public void Send_BatchesUntilUpdate() { // create connection and send NetworkConnectionToClient connection = new NetworkConnectionToClient(42); - NetworkTime.PingInterval = float.MaxValue; // disable ping for this test + NetworkTime.defaultPingInterval = float.MaxValue; // disable ping for this test byte[] message = {0x01, 0x02}; connection.Send(new ArraySegment(message)); @@ -64,7 +64,7 @@ public void SendBatchingResetsPreviousWriter() // create connection NetworkConnectionToClient connection = new NetworkConnectionToClient(42); - NetworkTime.PingInterval = float.MaxValue; // disable ping for this test + NetworkTime.defaultPingInterval = float.MaxValue; // disable ping for this test // send and update big message byte[] message = {0x01, 0x02}; diff --git a/Assets/Mirror/Tests/Runtime/NetworkServerRuntimeTest.cs b/Assets/Mirror/Tests/Runtime/NetworkServerRuntimeTest.cs index 3587003a640..0fcca35a9e0 100644 --- a/Assets/Mirror/Tests/Runtime/NetworkServerRuntimeTest.cs +++ b/Assets/Mirror/Tests/Runtime/NetworkServerRuntimeTest.cs @@ -87,8 +87,7 @@ NetworkIdentity SpawnPrefab(GameObject prefab) [UnityTest] public IEnumerator DisconnectTimeoutTest() { - // Set low ping frequency so no NetworkPingMessage is generated - NetworkTime.PingInterval = 5f; + NetworkTime.defaultPingInterval = float.MaxValue; // disable ping for this test // Set a short timeout for this test and enable disconnectInactiveConnections NetworkServer.disconnectInactiveConnections = true;