From 2b92ac76740803b24cbad0f3bd7e0a86e72b34eb Mon Sep 17 00:00:00 2001 From: mischa Date: Sun, 28 Jan 2024 12:36:17 +0100 Subject: [PATCH] perf(Prediction): optimize ghosts. deep profiling: 93 objects before=0.08ms after =0.03ms! --- .../PredictedRigidbody/PredictedRigidbody.cs | 4 ++-- .../PredictedRigidbodyPhysicsGhost.cs | 12 ++++++++---- .../PredictedRigidbodyRemoteGhost.cs | 12 +++++++++--- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs index 38dabf49d..3f86cab6f 100644 --- a/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs +++ b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs @@ -156,7 +156,7 @@ protected virtual void CreateGhosts() // add the PredictedRigidbodyPhysical component PredictedRigidbodyPhysicsGhost physicsGhostRigidbody = physicsCopy.AddComponent(); - physicsGhostRigidbody.target = this; + physicsGhostRigidbody.target = tf; physicsGhostRigidbody.ghostDistanceThreshold = ghostDistanceThreshold; physicsGhostRigidbody.ghostEnabledCheckInterval = ghostEnabledCheckInterval; @@ -186,7 +186,7 @@ protected virtual void CreateGhosts() remoteCopy.transform.rotation = tf.rotation; // world rotation! remoteCopy.transform.localScale = tf.lossyScale; // world scale! PredictedRigidbodyRemoteGhost predictedGhost = remoteCopy.AddComponent(); - predictedGhost.target = this; + predictedGhost.target = tf; predictedGhost.ghostDistanceThreshold = ghostDistanceThreshold; predictedGhost.ghostEnabledCheckInterval = ghostEnabledCheckInterval; CopyRenderersAsGhost(remoteCopy, remoteGhostMaterial); diff --git a/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyPhysicsGhost.cs b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyPhysicsGhost.cs index 5e4674987..3168f15bd 100644 --- a/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyPhysicsGhost.cs +++ b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyPhysicsGhost.cs @@ -7,8 +7,10 @@ namespace Mirror { public class PredictedRigidbodyPhysicsGhost : MonoBehaviour { + // this is performance critical, so store target's .Transform instead of + // PredictedRigidbody, this way we don't need to call the .transform getter. [Tooltip("The predicted rigidbody owner.")] - public PredictedRigidbody target; + public Transform target; // ghost (settings are copyed from PredictedRigidbody) MeshRenderer ghost; @@ -16,13 +18,15 @@ public class PredictedRigidbodyPhysicsGhost : MonoBehaviour public float ghostEnabledCheckInterval = 0.2f; double lastGhostEnabledCheckTime = 0; - // cache + // cache components because this is performance critical! + Transform tf; Collider co; // we add this component manually from PredictedRigidbody. // so assign this in Start. target isn't set in Awake yet. void Start() { + tf = transform; co = GetComponent(); ghost = GetComponent(); } @@ -43,7 +47,7 @@ void UpdateGhostRenderers() // otherwise it just looks like z-fighting the whole time. // => iterated the renderers we found when creating the visual copy. // we don't want to GetComponentsInChildren every time here! - bool insideTarget = Vector3.Distance(transform.position, target.transform.position) <= ghostDistanceThreshold; + bool insideTarget = Vector3.Distance(tf.position, target.position) <= ghostDistanceThreshold; ghost.enabled = !insideTarget; } @@ -53,7 +57,7 @@ void UpdateGhostRenderers() void LateUpdate() { // if owner gets network destroyed for any reason, destroy visual - if (target == null || target.gameObject == null) Destroy(gameObject); + if (target == null) Destroy(gameObject); } // also show a yellow gizmo for the predicted & corrected physics. diff --git a/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyRemoteGhost.cs b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyRemoteGhost.cs index 24b37b624..4e1127c38 100644 --- a/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyRemoteGhost.cs +++ b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyRemoteGhost.cs @@ -5,8 +5,10 @@ namespace Mirror { public class PredictedRigidbodyRemoteGhost : MonoBehaviour { + // this is performance critical, so store target's .Transform instead of + // PredictedRigidbody, this way we don't need to call the .transform getter. [Tooltip("The predicted rigidbody owner.")] - public PredictedRigidbody target; + public Transform target; // ghost (settings are copyed from PredictedRigidbody) MeshRenderer ghost; @@ -14,10 +16,14 @@ public class PredictedRigidbodyRemoteGhost : MonoBehaviour public float ghostEnabledCheckInterval = 0.2f; double lastGhostEnabledCheckTime = 0; + // cache components because this is performance critical! + Transform tf; + // we add this component manually from PredictedRigidbody. // so assign this in Start. target isn't set in Awake yet. void Start() { + tf = transform; ghost = GetComponent(); } @@ -37,7 +43,7 @@ void UpdateGhostRenderers() // otherwise it just looks like z-fighting the whole time. // => iterated the renderers we found when creating the visual copy. // we don't want to GetComponentsInChildren every time here! - bool insideTarget = Vector3.Distance(transform.position, target.transform.position) <= ghostDistanceThreshold; + bool insideTarget = Vector3.Distance(tf.position, target.position) <= ghostDistanceThreshold; ghost.enabled = !insideTarget; } @@ -47,7 +53,7 @@ void UpdateGhostRenderers() void LateUpdate() { // if owner gets network destroyed for any reason, destroy visual - if (target == null || target.gameObject == null) Destroy(gameObject); + if (target == null) Destroy(gameObject); } } }