From 12ebd7f722009af4b06f561574b85cf85c10ba16 Mon Sep 17 00:00:00 2001 From: MrGadget <9826063+MrGadget1024@users.noreply.github.com> Date: Mon, 3 Apr 2023 12:39:01 -0400 Subject: [PATCH] fix: NetworkTransformUnreliable: timeStampAdjustment, timelineOffset to fix 2s jitter after tab switching in webgl caused by NT snaps potentially arriving behind timeline snaps (#3441) * NT-U: Implemented sendIntervalMultiplier, timeStampAdjustment, timelineOffset * Update Assets/Mirror/Components/NetworkTransformUnreliable/NetworkTransform.cs Co-authored-by: mischa <16416509+vis2k@users.noreply.github.com> --------- Co-authored-by: mischa <16416509+vis2k@users.noreply.github.com> --- .../NetworkTransform.cs | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/Assets/Mirror/Components/NetworkTransformUnreliable/NetworkTransform.cs b/Assets/Mirror/Components/NetworkTransformUnreliable/NetworkTransform.cs index b789311b5..062c486f4 100644 --- a/Assets/Mirror/Components/NetworkTransformUnreliable/NetworkTransform.cs +++ b/Assets/Mirror/Components/NetworkTransformUnreliable/NetworkTransform.cs @@ -36,6 +36,31 @@ public class NetworkTransform : NetworkTransformBase double lastClientSendTime; double lastServerSendTime; + [Header("Send Interval Multiplier")] + [Tooltip("Check/Sync every multiple of Network Manager send interval (= 1 / NM Send Rate), instead of every send interval.")] + [Range(1, 120)] + const uint sendIntervalMultiplier = 1; // not implemented yet + + [Header("Snapshot Interpolation")] + [Tooltip("Add a small timeline offset to account for decoupled arrival of NetworkTime and NetworkTransform snapshots.\nfixes: https://github.com/MirrorNetworking/Mirror/issues/3427")] + public bool timelineOffset = false; + + // Ninja's Notes on offset & mulitplier: + // + // In a no multiplier scenario: + // 1. Snapshots are sent every frame (frame being 1 NM send interval). + // 2. Time Interpolation is set to be 'behind' by 2 frames times. + // In theory where everything works, we probably have around 2 snapshots before we need to interpolate snapshots. From NT perspective, we should always have around 2 snapshots ready, so no stutter. + // + // In a multiplier scenario: + // 1. Snapshots are sent every 10 frames. + // 2. Time Interpolation remains 'behind by 2 frames'. + // When everything works, we are receiving NT snapshots every 10 frames, but start interpolating after 2. + // Even if I assume we had 2 snapshots to begin with to start interpolating (which we don't), by the time we reach 13th frame, we are out of snapshots, and have to wait 7 frames for next snapshot to come. This is the reason why we absolutely need the timestamp adjustment. We are starting way too early to interpolate. + // + double timeStampAdjustment => NetworkServer.sendInterval * (sendIntervalMultiplier - 1); + double offset => timelineOffset ? NetworkServer.sendInterval * sendIntervalMultiplier : 0; + // update ////////////////////////////////////////////////////////////// // Update applies interpolation void Update() @@ -326,7 +351,7 @@ protected virtual void OnClientToServerSync(Vector3? position, Quaternion? rotat } } #endif - AddSnapshot(serverSnapshots, timestamp, position, rotation, scale); + AddSnapshot(serverSnapshots, connectionToClient.remoteTimeStamp + timeStampAdjustment + offset, position, rotation, scale); } // rpc ///////////////////////////////////////////////////////////////// @@ -365,7 +390,7 @@ protected virtual void OnServerToClientSync(Vector3? position, Quaternion? rotat } } #endif - AddSnapshot(clientSnapshots, timestamp, position, rotation, scale); + AddSnapshot(clientSnapshots, NetworkClient.connection.remoteTimeStamp + timeStampAdjustment + offset, position, rotation, scale); } } }