From 9458fdda69b25fe8009f0846df8506c80b76215f Mon Sep 17 00:00:00 2001 From: Chayce Date: Mon, 26 Feb 2024 02:21:21 -0600 Subject: [PATCH 1/7] May or may not work. done without ReSharper, so there may be mistakes. --- .../LagCompensation/LagCompensator.cs | 169 +++++++----------- 1 file changed, 61 insertions(+), 108 deletions(-) diff --git a/Assets/Mirror/Components/LagCompensation/LagCompensator.cs b/Assets/Mirror/Components/LagCompensation/LagCompensator.cs index b5ae3f815c..560338aefb 100644 --- a/Assets/Mirror/Components/LagCompensation/LagCompensator.cs +++ b/Assets/Mirror/Components/LagCompensation/LagCompensator.cs @@ -1,44 +1,59 @@ -// Add this component to a Player object with collider. +// Add this component to every Player // Automatically keeps a history for lag compensation. +// Then create a dummy player with everything removed exept colliders. +// put in normal player position and rotation for tracked, +// then the dummy position and orientation for compensated. +// all you have to do after is call UpdateColliders() whenever a player fires. using System; using System.Collections.Generic; using UnityEngine; namespace Mirror { + using System.Collections; + using System.Collections.Generic; + using UnityEngine; + using Mirror; + public struct Capture3D : Capture { public double timestamp { get; set; } public Vector3 position; - public Vector3 size; + public Quaternion rotation; - public Capture3D(double timestamp, Vector3 position, Vector3 size) + public Capture3D(double timestamp, Vector3 position, Quaternion rotation) { this.timestamp = timestamp; this.position = position; - this.size = size; + this.rotation = rotation; } - public void DrawGizmo() - { - Gizmos.DrawWireCube(position, size); - } + public void DrawGizmo() { } public static Capture3D Interpolate(Capture3D from, Capture3D to, double t) => new Capture3D( 0, // interpolated snapshot is applied directly. don't need timestamps. Vector3.LerpUnclamped(from.position, to.position, (float)t), - Vector3.LerpUnclamped(from.size, to.size, (float)t) + Quaternion.LerpUnclamped(from.rotation, to.rotation, (float)t), ); - public override string ToString() => $"(time={timestamp} pos={position} size={size})"; + public override string ToString() => $"(time={timestamp} pos={position} size={rotation})"; } + public class LagCompensator : NetworkBehaviour { [Header("Components")] - [Tooltip("The collider to keep a history of.")] - public Collider trackedCollider; // assign this in inspector + [Tooltip("The GameObject to enable / disable. NOTE: compensatedPosition & compensatedOrientation can both be compensatedGameobject. those are simply for more control.")] + public Transform compensatedGameObject; + [Tooltip("The Transform to Apply the tracked position")] + public Transform compensatedPosition; + [Tooltip("The Transform to Apply the tracked rotation.")] + public Transform compensatedOrientation; + [Tooltip("The position to keep track of.")] + public Transform trackedPosition; + [Tooltip("The rotation to keep track of.")] + public Transform trackedOrientation; [Header("Settings")] public LagCompensationSettings lagCompensationSettings = new LagCompensationSettings(); @@ -64,14 +79,10 @@ protected virtual void Update() } } - protected virtual void Capture() + void Capture() { // capture current state - Capture3D capture = new Capture3D( - NetworkTime.localTime, - trackedCollider.bounds.center, - trackedCollider.bounds.size - ); + Capture3D capture = new Capture3D(NetworkTime.localTime, trackedPosition.position, trackedOrientation.rotation); // insert into history LagCompensation.Insert(history, lagCompensationSettings.historyLimit, NetworkTime.localTime, capture); @@ -84,32 +95,6 @@ protected virtual void OnDrawGizmos() LagCompensation.DrawGizmos(history); } - // sampling //////////////////////////////////////////////////////////// - // sample the sub-tick (=interpolated) history of this object for a hit test. - // 'viewer' needs to be the player who fired! - // for example, if A fires at B, then call B.Sample(viewer, point, tolerance). - [Server] - public virtual bool Sample(NetworkConnectionToClient viewer, out Capture3D sample) - { - // never trust the client: estimate client time instead. - // https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking - // the estimation is very good. the error is as low as ~6ms for the demo. - // note that passing 'rtt' is fine: EstimateTime halves it to latency. - double estimatedTime = LagCompensation.EstimateTime(NetworkTime.localTime, viewer.rtt, NetworkClient.bufferTime); - - // sample the history to get the nearest snapshots around 'timestamp' - if (LagCompensation.Sample(history, estimatedTime, lagCompensationSettings.captureInterval, out Capture3D resultBefore, out Capture3D resultAfter, out double t)) - { - // interpolate to get a decent estimation at exactly 'timestamp' - sample = Capture3D.Interpolate(resultBefore, resultAfter, t); - return true; - } - else Debug.Log($"CmdClicked: history doesn't contain {estimatedTime:F3}"); - - sample = default; - return false; - } - // convenience tests /////////////////////////////////////////////////// // there are multiple different ways to check a hit against the sample: // - raycasting @@ -123,73 +108,41 @@ public virtual bool Sample(NetworkConnectionToClient viewer, out Capture3D sampl // for example, if A fires at B, then call B.Sample(viewer, point, tolerance). // this is super simple and fast, but not 100% physically accurate since we don't raycast. [Server] - public virtual bool BoundsCheck( - NetworkConnectionToClient viewer, - Vector3 hitPoint, - float toleranceDistance, - out float distance, - out Vector3 nearest) + public async void UpdateColliders(NetworkConnectionToClient localCon) { - // first, sample the history at -rtt of the viewer. - if (Sample(viewer, out Capture3D capture)) - { - // now that we know where the other player was at that time, - // we can see if the hit point was within tolerance of it. - // TODO consider rotations??? - // TODO consider original collider shape?? - Bounds bounds = new Bounds(capture.position, capture.size); - nearest = bounds.ClosestPoint(hitPoint); - distance = Vector3.Distance(nearest, hitPoint); - return distance <= toleranceDistance; - } - nearest = hitPoint; - distance = 0; - return false; - } + // never trust the client: estimate client time instead. + // https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking + // the estimation is very good. the error is as low as ~6ms for the demo. + double buffertime = (NetworkManager.singleton.sendRate / 100) * 9; + double rtt = localCon.rtt; // the function needs rtt, which is latency * 2 + double estimatedTime = LagCompensation.EstimateTime(NetworkTime.localTime, rtt, buffertime); + Dictionary resultInterp = new Dictionary(); - // raycast check: creates a collider the sampled position and raycasts to hitPoint. - // 'viewer' needs to be the player who fired! - // for example, if A fires at B, then call B.Sample(viewer, point, tolerance). - // this is physically accurate (checks against walls etc.), with the cost - // of a runtime instantiation. - // - // originPoint: where the player fired the weapon. - // hitPoint: where the player's local raycast hit. - // tolerance: scale up the sampled collider by % in order to have a bit of a tolerance. - // 0 means no extra tolerance, 0.05 means 5% extra tolerance. - // layerMask: the layer mask to use for the raycast. - [Server] - public virtual bool RaycastCheck( - NetworkConnectionToClient viewer, - Vector3 originPoint, - Vector3 hitPoint, - float tolerancePercent, - int layerMask, - out RaycastHit hit) - { - // first, sample the history at -rtt of the viewer. - if (Sample(viewer, out Capture3D capture)) + var tasks = NetworkServer.connections.Values.Select(async netcon => { - // instantiate a real physics collider on demand. - // TODO rotation?? - // TODO different collier types?? - GameObject temp = new GameObject("LagCompensatorTest"); - temp.transform.position = capture.position; - BoxCollider tempCollider = temp.AddComponent(); - tempCollider.size = capture.size * (1 + tolerancePercent); - - // raycast - Vector3 direction = hitPoint - originPoint; - float maxDistance = direction.magnitude * 2; - bool result = Physics.Raycast(originPoint, direction, out hit, maxDistance, layerMask); - - // cleanup - Destroy(temp); - return result; - } - - hit = default; - return false; + LagCompensator conPlayer = netcon.identity.GetComponent(); + + // sample the history to get the nearest snapshots around 'timestamp' + if (LagCompensation.Sample(conPlayer.history, estimatedTime, lagCompensationSettings.captureInterval, out resultBefore, out resultAfter, out double t)) + { + // interpolate to get a decent estimation at exactly 'timestamp' + resultInterp.Add(conPlayer, Capture3D.Interpolate(resultBefore, resultAfter, t)); + resultTime = NetworkTime.localTime; + } + else Debug.Log($"CmdClicked: history doesn't contain {estimatedTime:F3}, netcon: {netcon}, history: {conPlayer.history.Count}"); + + if (netcon == localCon) + { + conPlayer.trackedGameObject.SetActive(false); + return; + } + if(!conPlayer.trackedGameObject.activeInHierarchy) + conPlayer.trackedGameObject.SetActive(true); + + conPlayer.compensatedPosition.position = resultInterp[conPlayer].position; + conPlayer.compensatedOrientation.rotation = resultInterp[conPlayer].rotation; + }); + Task.WhenAll(tasks); } } } From 67d955776313bd92c9351f162fdd1aa2210f49c5 Mon Sep 17 00:00:00 2001 From: Chayce Date: Mon, 26 Feb 2024 08:39:46 -0600 Subject: [PATCH 2/7] renamed size to rotation --- Assets/Mirror/Components/LagCompensation/LagCompensator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Mirror/Components/LagCompensation/LagCompensator.cs b/Assets/Mirror/Components/LagCompensation/LagCompensator.cs index 560338aefb..67f18c98f2 100644 --- a/Assets/Mirror/Components/LagCompensation/LagCompensator.cs +++ b/Assets/Mirror/Components/LagCompensation/LagCompensator.cs @@ -37,7 +37,7 @@ public static Capture3D Interpolate(Capture3D from, Capture3D to, double t) => Quaternion.LerpUnclamped(from.rotation, to.rotation, (float)t), ); - public override string ToString() => $"(time={timestamp} pos={position} size={rotation})"; + public override string ToString() => $"(time={timestamp} position={position} rotation={rotation})"; } From df8226ef0477f52783d29d72b6d4e0a28fb7b6fd Mon Sep 17 00:00:00 2001 From: Chayce Date: Mon, 26 Feb 2024 09:07:15 -0600 Subject: [PATCH 3/7] Fixed a ton of errors, it should actually work now. will test --- .../LagCompensation/LagCompensator.cs | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/Assets/Mirror/Components/LagCompensation/LagCompensator.cs b/Assets/Mirror/Components/LagCompensation/LagCompensator.cs index 67f18c98f2..c724dbf379 100644 --- a/Assets/Mirror/Components/LagCompensation/LagCompensator.cs +++ b/Assets/Mirror/Components/LagCompensation/LagCompensator.cs @@ -4,14 +4,12 @@ // put in normal player position and rotation for tracked, // then the dummy position and orientation for compensated. // all you have to do after is call UpdateColliders() whenever a player fires. -using System; -using System.Collections.Generic; -using UnityEngine; namespace Mirror { - using System.Collections; using System.Collections.Generic; + using System.Threading.Tasks; + using System.Linq; using UnityEngine; using Mirror; @@ -34,7 +32,7 @@ public static Capture3D Interpolate(Capture3D from, Capture3D to, double t) => new Capture3D( 0, // interpolated snapshot is applied directly. don't need timestamps. Vector3.LerpUnclamped(from.position, to.position, (float)t), - Quaternion.LerpUnclamped(from.rotation, to.rotation, (float)t), + Quaternion.LerpUnclamped(from.rotation, to.rotation, (float)t) ); public override string ToString() => $"(time={timestamp} position={position} rotation={rotation})"; @@ -45,7 +43,7 @@ public class LagCompensator : NetworkBehaviour { [Header("Components")] [Tooltip("The GameObject to enable / disable. NOTE: compensatedPosition & compensatedOrientation can both be compensatedGameobject. those are simply for more control.")] - public Transform compensatedGameObject; + public GameObject compensatedGameObject; [Tooltip("The Transform to Apply the tracked position")] public Transform compensatedPosition; [Tooltip("The Transform to Apply the tracked rotation.")] @@ -64,6 +62,12 @@ public class LagCompensator : NetworkBehaviour [Header("Debugging")] public Color historyColor = Color.white; + public double resultDuration = 0.5; + double resultTime; + Capture3D resultBefore; + Capture3D resultAfter; + Capture3D resultInterpolated; + protected virtual void Update() { @@ -111,11 +115,11 @@ protected virtual void OnDrawGizmos() public async void UpdateColliders(NetworkConnectionToClient localCon) { // never trust the client: estimate client time instead. - // https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking - // the estimation is very good. the error is as low as ~6ms for the demo. double buffertime = (NetworkManager.singleton.sendRate / 100) * 9; double rtt = localCon.rtt; // the function needs rtt, which is latency * 2 double estimatedTime = LagCompensation.EstimateTime(NetworkTime.localTime, rtt, buffertime); + + // Honestly, couldnt tell you why this is a dictionary. Dictionary resultInterp = new Dictionary(); var tasks = NetworkServer.connections.Values.Select(async netcon => @@ -133,16 +137,16 @@ public async void UpdateColliders(NetworkConnectionToClient localCon) if (netcon == localCon) { - conPlayer.trackedGameObject.SetActive(false); + conPlayer.compensatedGameObject.SetActive(false); return; } - if(!conPlayer.trackedGameObject.activeInHierarchy) - conPlayer.trackedGameObject.SetActive(true); + if(!conPlayer.compensatedGameObject.activeInHierarchy) + conPlayer.compensatedGameObject.SetActive(true); conPlayer.compensatedPosition.position = resultInterp[conPlayer].position; conPlayer.compensatedOrientation.rotation = resultInterp[conPlayer].rotation; }); - Task.WhenAll(tasks); + await Task.WhenAll(tasks); } } } From 02480cac9b2801f509b5667b3fb492c52cb4cd04 Mon Sep 17 00:00:00 2001 From: Chayce Date: Mon, 26 Feb 2024 11:06:21 -0600 Subject: [PATCH 4/7] Added optional animation tracking. Doesn't track or compensate for blend trees. This is impossible to automate, and has to be added manually by the user. --- .../LagCompensation/LagCompensator.cs | 87 +++++++++++++++---- 1 file changed, 68 insertions(+), 19 deletions(-) diff --git a/Assets/Mirror/Components/LagCompensation/LagCompensator.cs b/Assets/Mirror/Components/LagCompensation/LagCompensator.cs index c724dbf379..1931f30a7d 100644 --- a/Assets/Mirror/Components/LagCompensation/LagCompensator.cs +++ b/Assets/Mirror/Components/LagCompensation/LagCompensator.cs @@ -19,11 +19,20 @@ public struct Capture3D : Capture public Vector3 position; public Quaternion rotation; - public Capture3D(double timestamp, Vector3 position, Quaternion rotation) + public struct animParams + { + public string animname; + public int layer; + public float time; + } + public animParams[] animparam; + + public Capture3D(double timestamp, Vector3 position, Quaternion rotation, animParams[] parameter) { this.timestamp = timestamp; this.position = position; this.rotation = rotation; + this.animparam = parameter; } public void DrawGizmo() { } @@ -32,15 +41,32 @@ public static Capture3D Interpolate(Capture3D from, Capture3D to, double t) => new Capture3D( 0, // interpolated snapshot is applied directly. don't need timestamps. Vector3.LerpUnclamped(from.position, to.position, (float)t), - Quaternion.LerpUnclamped(from.rotation, to.rotation, (float)t) + Quaternion.LerpUnclamped(from.rotation, to.rotation, (float)t), + interpAnim(from.animparam, to.animparam, t) ); + private static animParams[] interpAnim(animParams[] from, animParams[] to, double t) + { + animParams[] interped = from; + + for (int i = 0; i < interped.Length; i++) + { + Mathf.LerpUnclamped(interped[i].time, to[i].time, (float) t); + } + + return interped; + } + public override string ToString() => $"(time={timestamp} position={position} rotation={rotation})"; } - + [Obsolete("This is a preview version. Community feedback is welcome!")] public class LagCompensator : NetworkBehaviour { + [Header("Config")] + [Tooltip("Toggle to track & compensate for animation. Doesnt compensate blend tree variables. you have to manually set those on the server.")] + public bool useAnimator; + [Header("Components")] [Tooltip("The GameObject to enable / disable. NOTE: compensatedPosition & compensatedOrientation can both be compensatedGameobject. those are simply for more control.")] public GameObject compensatedGameObject; @@ -48,10 +74,14 @@ public class LagCompensator : NetworkBehaviour public Transform compensatedPosition; [Tooltip("The Transform to Apply the tracked rotation.")] public Transform compensatedOrientation; + [Tooltip("Only needed if useAnimator is enabled")] + public Animator compensatedAnimator; [Tooltip("The position to keep track of.")] public Transform trackedPosition; [Tooltip("The rotation to keep track of.")] public Transform trackedOrientation; + [Tooltip("Only needed if useAnimator is enabled")] + public Animator trackedAnimator; [Header("Settings")] public LagCompensationSettings lagCompensationSettings = new LagCompensationSettings(); @@ -86,10 +116,29 @@ protected virtual void Update() void Capture() { // capture current state - Capture3D capture = new Capture3D(NetworkTime.localTime, trackedPosition.position, trackedOrientation.rotation); + if (useAnimator) + { + Capture3D.animParams[] animParamsArray = new Capture3D.animParams[trackedAnimator.layerCount]; + for (int i = 0; i < trackedAnimator.layerCount; i++) + { + animParamsArray[i].layer = i; + animParamsArray[i].animname = trackedAnimator.GetCurrentAnimatorClipInfo(i)[0].clip.name; + animParamsArray[i].time = trackedAnimator.GetCurrentAnimatorStateInfo(i).normalizedTime; + } - // insert into history - LagCompensation.Insert(history, lagCompensationSettings.historyLimit, NetworkTime.localTime, capture); + Capture3D capture = new Capture3D(NetworkTime.localTime, trackedPosition.position, trackedOrientation.rotation, animParamsArray); + + // insert into history + LagCompensation.Insert(history, lagCompensationSettings.historyLimit, NetworkTime.localTime, capture); + } + else + { + // capture current state + Capture3D capture = new Capture3D(NetworkTime.localTime, trackedPosition.position, trackedOrientation.rotation, Array.Empty()); + + // insert into history + LagCompensation.Insert(history, lagCompensationSettings.historyLimit, NetworkTime.localTime, capture); + } } protected virtual void OnDrawGizmos() @@ -99,20 +148,9 @@ protected virtual void OnDrawGizmos() LagCompensation.DrawGizmos(history); } - // convenience tests /////////////////////////////////////////////////// - // there are multiple different ways to check a hit against the sample: - // - raycasting - // - bounds.contains - // - increasing bounds by tolerance and checking contains - // - threshold to bounds.closestpoint - // let's offer a few solutions directly and see which users prefer. - - // bounds check: checks distance to closest point on bounds in history @ -rtt. - // 'viewer' needs to be the player who fired! - // for example, if A fires at B, then call B.Sample(viewer, point, tolerance). - // this is super simple and fast, but not 100% physically accurate since we don't raycast. + // Updates every players compensated colliders with the Callers estimated time. [Server] - public async void UpdateColliders(NetworkConnectionToClient localCon) + public async void UpdateColliders(NetworkConnectionToClient localCon = null) { // never trust the client: estimate client time instead. double buffertime = (NetworkManager.singleton.sendRate / 100) * 9; @@ -145,6 +183,17 @@ public async void UpdateColliders(NetworkConnectionToClient localCon) conPlayer.compensatedPosition.position = resultInterp[conPlayer].position; conPlayer.compensatedOrientation.rotation = resultInterp[conPlayer].rotation; + + // Animation Compensation + if (useAnimator) + { + for (int i = 0; i < resultInterp[conPlayer].animparam.Length; i++) + { + conPlayer.compensatedAnimator.Play(resultInterp[conPlayer].animparam[i].animname, resultInterp[conPlayer].animparam[i].layer, resultInterp[conPlayer].animparam[i].time); + } + // NOTE: Doesnt set the variables of BLEND TREES. you will have to set the blend tree variables manually on the server. + // OR add them to Capture3d and interpolate. this HAS to be done manually. + } }); await Task.WhenAll(tasks); } From 1a05edfd5a58322ab4316986090fa3806448799f Mon Sep 17 00:00:00 2001 From: Chayce Date: Mon, 26 Feb 2024 12:49:36 -0600 Subject: [PATCH 5/7] Added UpdateTargetCollider() and DisableColldiers(). These would be used if you want greater perf at the cost of more manual scripting. --- .../LagCompensation/LagCompensator.cs | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/Assets/Mirror/Components/LagCompensation/LagCompensator.cs b/Assets/Mirror/Components/LagCompensation/LagCompensator.cs index 1931f30a7d..91dc64fdb5 100644 --- a/Assets/Mirror/Components/LagCompensation/LagCompensator.cs +++ b/Assets/Mirror/Components/LagCompensation/LagCompensator.cs @@ -197,5 +197,56 @@ public async void UpdateColliders(NetworkConnectionToClient localCon = null) }); await Task.WhenAll(tasks); } + + [Server] + // Your going to want to await this method. + public void UpdateTargetCollider(NetworkConnectionToClient targetcon, + NetworkConnectionToClient localCon = null) + { + // never trust the client: estimate client time instead. + double buffertime = (NetworkManager.singleton.sendRate / 100) * 9; + double rtt = localCon.rtt; // the function needs rtt, which is latency * 2 + double estimatedTime = LagCompensation.EstimateTime(NetworkTime.localTime, rtt, buffertime); + + LagCompensator conPlayer = targetcon.identity.GetComponent(); + Capture3D capture = new Capture3D(); + + // sample the history to get the nearest snapshots around 'timestamp' + if (LagCompensation.Sample(conPlayer.history, estimatedTime, lagCompensationSettings.captureInterval, out resultBefore, out resultAfter, out double t)) + { + // interpolate to get a decent estimation at exactly 'timestamp' + capture = Capture3D.Interpolate(resultBefore, resultAfter, t); + resultTime = NetworkTime.localTime; + } + else Debug.Log($"CmdClicked: history doesn't contain {estimatedTime:F3}, netcon: {targetcon}, history: {conPlayer.history.Count}"); + + if(!conPlayer.compensatedGameObject.activeInHierarchy) + conPlayer.compensatedGameObject.SetActive(true); + + conPlayer.compensatedPosition.position = capture.position; + conPlayer.compensatedOrientation.rotation = capture.rotation; + + // Animation Compensation + if (useAnimator) + { + for (int i = 0; i < capture.animparam.Length; i++) + { + conPlayer.compensatedAnimator.Play(capture.animparam[i].animname, capture.animparam[i].layer, capture.animparam[i].time); + } + // NOTE: Doesnt set the variables of BLEND TREES. you will have to set the blend tree variables manually on the server. + } + } + + [Server] + // To be used after you have shot your Raycast. only needed if using UpdateTargetCollider. UpdateColliders automatically does this. + public async void DisableColliders() + { + var tasks = NetworkServer.connections.Values.Select(async netcon => + { + LagCompensator conPlayer = netcon.identity.GetComponent(); + conPlayer.gameObject.SetActive(false); + }); + await Task.WhenAll(tasks); + } } } From 38fc462a322999ac652bedaba66b6dc90f283e87 Mon Sep 17 00:00:00 2001 From: Chayce Date: Mon, 26 Feb 2024 13:20:39 -0600 Subject: [PATCH 6/7] Added comments --- .../Components/LagCompensation/LagCompensator.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Assets/Mirror/Components/LagCompensation/LagCompensator.cs b/Assets/Mirror/Components/LagCompensation/LagCompensator.cs index 91dc64fdb5..ddf32cd742 100644 --- a/Assets/Mirror/Components/LagCompensation/LagCompensator.cs +++ b/Assets/Mirror/Components/LagCompensation/LagCompensator.cs @@ -149,6 +149,7 @@ protected virtual void OnDrawGizmos() } // Updates every players compensated colliders with the Callers estimated time. + // Your going to want to await this method before firing the servers raycast. [Server] public async void UpdateColliders(NetworkConnectionToClient localCon = null) { @@ -157,7 +158,7 @@ public async void UpdateColliders(NetworkConnectionToClient localCon = null) double rtt = localCon.rtt; // the function needs rtt, which is latency * 2 double estimatedTime = LagCompensation.EstimateTime(NetworkTime.localTime, rtt, buffertime); - // Honestly, couldnt tell you why this is a dictionary. + // Honestly, couldnt tell you why this is a dictionary. i'd think this would work without it. but im not sure. Dictionary resultInterp = new Dictionary(); var tasks = NetworkServer.connections.Values.Select(async netcon => @@ -198,8 +199,9 @@ public async void UpdateColliders(NetworkConnectionToClient localCon = null) await Task.WhenAll(tasks); } + // Updates the Target's compensated colliders with the Callers estimated time. + // Your going to want to await this method before firing the servers raycast. [Server] - // Your going to want to await this method. public void UpdateTargetCollider(NetworkConnectionToClient targetcon, NetworkConnectionToClient localCon = null) { @@ -237,8 +239,10 @@ public void UpdateTargetCollider(NetworkConnectionToClient targetcon, } } + + // To be used after you have shot the servers raycast. only needed if using UpdateTargetCollider. UpdateColliders automatically does this. + // No need to await this method, you can if wanted. [Server] - // To be used after you have shot your Raycast. only needed if using UpdateTargetCollider. UpdateColliders automatically does this. public async void DisableColliders() { var tasks = NetworkServer.connections.Values.Select(async netcon => From 30cafdabb27a6d9e1eecc442dbb80262a4da9079 Mon Sep 17 00:00:00 2001 From: Chayce Date: Fri, 15 Mar 2024 12:49:15 -0500 Subject: [PATCH 7/7] Added [ServerCallback] to Update() method. --- Assets/Mirror/Components/LagCompensation/LagCompensator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Mirror/Components/LagCompensation/LagCompensator.cs b/Assets/Mirror/Components/LagCompensation/LagCompensator.cs index ddf32cd742..277862c8bd 100644 --- a/Assets/Mirror/Components/LagCompensation/LagCompensator.cs +++ b/Assets/Mirror/Components/LagCompensation/LagCompensator.cs @@ -98,7 +98,7 @@ public class LagCompensator : NetworkBehaviour Capture3D resultAfter; Capture3D resultInterpolated; - + [ServerCallback] protected virtual void Update() { // only capture on server