fix: #3576 Pings are now stamped with a scene hash so we can drop messages before a (potentially long) scene load. fixes a bug where RTT would be very high after a long scene load. (#3650)

* fix: #3576 Pings are now stamped with a scene hash so we can drop messages before a (potentially long) scene load. fixes a bug where RTT would be very high after a long scene load.

* 16 bit hash fakebyte
This commit is contained in:
mischa 2023-11-15 11:25:37 +01:00 committed by mischa
parent d34a046264
commit 26ae2becc2
3 changed files with 34 additions and 3 deletions

View File

@ -105,6 +105,13 @@ public struct EntityStateMessage : NetworkMessage
// whoever wants to measure rtt, sends this to the other end. // whoever wants to measure rtt, sends this to the other end.
public struct NetworkPingMessage : NetworkMessage public struct NetworkPingMessage : NetworkMessage
{ {
// ping messages are stamped with scene name (as hash).
// this way we can disregard messages from before a scene change.
// otherwise a 30s loading pause would cause super high RTT after:
// https://github.com/MirrorNetworking/Mirror/issues/3576
// (2 byte hash instead of N byte string to minimize bandwidth)
public ushort sceneHash;
// local time is used to calculate round trip time, // local time is used to calculate round trip time,
// and to calculate the predicted time offset. // and to calculate the predicted time offset.
public double localTime; public double localTime;
@ -112,8 +119,9 @@ public struct NetworkPingMessage : NetworkMessage
// predicted time is sent to compare the final error, for debugging only // predicted time is sent to compare the final error, for debugging only
public double predictedTimeAdjusted; public double predictedTimeAdjusted;
public NetworkPingMessage(double localTime, double predictedTimeAdjusted) public NetworkPingMessage(ushort sceneHash, double localTime, double predictedTimeAdjusted)
{ {
this.sceneHash = sceneHash;
this.localTime = localTime; this.localTime = localTime;
this.predictedTimeAdjusted = predictedTimeAdjusted; this.predictedTimeAdjusted = predictedTimeAdjusted;
} }
@ -123,6 +131,13 @@ public NetworkPingMessage(double localTime, double predictedTimeAdjusted)
// we can use this to calculate rtt. // we can use this to calculate rtt.
public struct NetworkPongMessage : NetworkMessage public struct NetworkPongMessage : NetworkMessage
{ {
// ping messages are stamped with scene name (as hash).
// this way we can disregard messages from before a scene change.
// otherwise a 30s loading pause would cause super high RTT after:
// https://github.com/MirrorNetworking/Mirror/issues/3576
// (2 byte hash instead of N byte string to minimize bandwidth)
public ushort sceneHash;
// local time is used to calculate round trip time. // local time is used to calculate round trip time.
public double localTime; public double localTime;
@ -130,8 +145,9 @@ public struct NetworkPongMessage : NetworkMessage
public double predictionErrorUnadjusted; public double predictionErrorUnadjusted;
public double predictionErrorAdjusted; // for debug purposes public double predictionErrorAdjusted; // for debug purposes
public NetworkPongMessage(double localTime, double predictionErrorUnadjusted, double predictionErrorAdjusted) public NetworkPongMessage(ushort sceneHash, double localTime, double predictionErrorUnadjusted, double predictionErrorAdjusted)
{ {
this.sceneHash = sceneHash;
this.localTime = localTime; this.localTime = localTime;
this.predictionErrorUnadjusted = predictionErrorUnadjusted; this.predictionErrorUnadjusted = predictionErrorUnadjusted;
this.predictionErrorAdjusted = predictionErrorAdjusted; this.predictionErrorAdjusted = predictionErrorAdjusted;

View File

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using UnityEngine; using UnityEngine;
using UnityEngine.SceneManagement;
namespace Mirror namespace Mirror
{ {
@ -129,7 +130,8 @@ protected virtual void UpdatePing()
// messages' timestamp and only send a message number. // messages' timestamp and only send a message number.
// This way client's can't just modify the timestamp. // This way client's can't just modify the timestamp.
// predictedTime parameter is 0 because the server doesn't predict. // predictedTime parameter is 0 because the server doesn't predict.
NetworkPingMessage pingMessage = new NetworkPingMessage(NetworkTime.localTime, 0); ushort sceneHash = SceneManager.GetActiveScene().name.GetStableHashCode16();
NetworkPingMessage pingMessage = new NetworkPingMessage(sceneHash, NetworkTime.localTime, 0);
Send(pingMessage, Channels.Unreliable); Send(pingMessage, Channels.Unreliable);
lastPingTime = NetworkTime.localTime; lastPingTime = NetworkTime.localTime;
} }

View File

@ -7,6 +7,7 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using UnityEngine; using UnityEngine;
using UnityEngine.SceneManagement;
#if !UNITY_2020_3_OR_NEWER #if !UNITY_2020_3_OR_NEWER
using Stopwatch = System.Diagnostics.Stopwatch; using Stopwatch = System.Diagnostics.Stopwatch;
#endif #endif
@ -144,8 +145,11 @@ internal static void UpdateClient()
{ {
// send raw predicted time without the offset applied yet. // send raw predicted time without the offset applied yet.
// we then apply the offset to it after. // we then apply the offset to it after.
// include scene name (as hash)
ushort sceneHash = SceneManager.GetActiveScene().name.GetStableHashCode16();
NetworkPingMessage pingMessage = new NetworkPingMessage NetworkPingMessage pingMessage = new NetworkPingMessage
( (
sceneHash,
localTime, localTime,
predictedTime predictedTime
); );
@ -175,6 +179,7 @@ internal static void OnServerPing(NetworkConnectionToClient conn, NetworkPingMes
// Debug.Log($"OnServerPing conn:{conn}"); // Debug.Log($"OnServerPing conn:{conn}");
NetworkPongMessage pongMessage = new NetworkPongMessage NetworkPongMessage pongMessage = new NetworkPongMessage
( (
message.sceneHash,
message.localTime, message.localTime,
unadjustedError, unadjustedError,
adjustedError adjustedError
@ -190,6 +195,13 @@ internal static void OnClientPong(NetworkPongMessage message)
// prevent attackers from sending timestamps which are in the future // prevent attackers from sending timestamps which are in the future
if (message.localTime > localTime) return; if (message.localTime > localTime) return;
// ping messages are stamped with scene name (as hash).
// this way we can disregard messages from before a scene change.
// otherwise a 30s loading pause would cause super high RTT after:
// https://github.com/MirrorNetworking/Mirror/issues/3576
int sceneHash = SceneManager.GetActiveScene().name.GetStableHashCode();
if (message.sceneHash != sceneHash) return;
// how long did this message take to come back // how long did this message take to come back
double newRtt = localTime - message.localTime; double newRtt = localTime - message.localTime;
_rtt.Add(newRtt); _rtt.Add(newRtt);
@ -210,6 +222,7 @@ internal static void OnClientPing(NetworkPingMessage message)
// Debug.Log($"OnClientPing conn:{conn}"); // Debug.Log($"OnClientPing conn:{conn}");
NetworkPongMessage pongMessage = new NetworkPongMessage NetworkPongMessage pongMessage = new NetworkPongMessage
( (
message.sceneHash,
message.localTime, message.localTime,
0, 0 // server doesn't predict 0, 0 // server doesn't predict
); );