From 3c3c5c56fd24b4fff9f80547a018c29bcb1c85fd Mon Sep 17 00:00:00 2001 From: mischa Date: Wed, 24 Jan 2024 12:47:42 +0100 Subject: [PATCH] fix(Prediction): when copying child Colliders, copy their relative position/rotation/scale too --- .../PredictedRigidbody/PredictedRigidbody.cs | 44 ++++++++++++++++--- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs index 8e1e10a5d..99e19dd94 100644 --- a/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs +++ b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs @@ -118,6 +118,24 @@ protected static void MoveRigidbody(GameObject source, GameObject destination) Destroy(original); } + // helper function: if a collider is on a child, copy that child first. + // this way child's relative position/rotation/scale are preserved. + protected static GameObject CopyRelativeTransform(GameObject source, Transform sourceChild, GameObject destination) + { + // is this on the source root? then we want to put it on the destination root. + if (sourceChild == source.transform) return destination; + + // is this on a child? then create the same child with the same transform on destination. + // note this is technically only correct for the immediate child since + // .localPosition is relative to parent, but this is good enough. + GameObject child = new GameObject(sourceChild.name); + child.transform.SetParent(destination.transform, true); + child.transform.localPosition = sourceChild.localPosition; + child.transform.localRotation = sourceChild.localRotation; + child.transform.localScale = sourceChild.localScale; + return child; + } + // move all BoxColliders + settings from one GameObject to another. protected static void MoveBoxColliders(GameObject source, GameObject destination) { @@ -125,7 +143,11 @@ protected static void MoveBoxColliders(GameObject source, GameObject destination BoxCollider[] sourceColliders = source.GetComponentsInChildren(); foreach (BoxCollider sourceCollider in sourceColliders) { - BoxCollider colliderCopy = destination.AddComponent(); + // copy the relative transform: + // if collider is on root, it returns destination root. + // if collider is on a child, it creates and returns a child on destination. + GameObject target = CopyRelativeTransform(source, sourceCollider.transform, destination); + BoxCollider colliderCopy = target.AddComponent(); colliderCopy.center = sourceCollider.center; colliderCopy.size = sourceCollider.size; colliderCopy.isTrigger = sourceCollider.isTrigger; @@ -140,7 +162,11 @@ protected static void MoveSphereColliders(GameObject source, GameObject destinat SphereCollider[] sourceColliders = source.GetComponentsInChildren(); foreach (SphereCollider sourceCollider in sourceColliders) { - SphereCollider colliderCopy = destination.AddComponent(); + // copy the relative transform: + // if collider is on root, it returns destination root. + // if collider is on a child, it creates and returns a child on destination. + GameObject target = CopyRelativeTransform(source, sourceCollider.transform, destination); + SphereCollider colliderCopy = target.AddComponent(); colliderCopy.center = sourceCollider.center; colliderCopy.radius = sourceCollider.radius; colliderCopy.isTrigger = sourceCollider.isTrigger; @@ -155,7 +181,11 @@ protected static void MoveCapsuleColliders(GameObject source, GameObject destina CapsuleCollider[] sourceColliders = source.GetComponentsInChildren(); foreach (CapsuleCollider sourceCollider in sourceColliders) { - CapsuleCollider colliderCopy = destination.AddComponent(); + // copy the relative transform: + // if collider is on root, it returns destination root. + // if collider is on a child, it creates and returns a child on destination. + GameObject target = CopyRelativeTransform(source, sourceCollider.transform, destination); + CapsuleCollider colliderCopy = target.AddComponent(); colliderCopy.center = sourceCollider.center; colliderCopy.radius = sourceCollider.radius; colliderCopy.height = sourceCollider.height; @@ -172,7 +202,11 @@ protected static void MoveMeshColliders(GameObject source, GameObject destinatio MeshCollider[] sourceColliders = source.GetComponentsInChildren(); foreach (MeshCollider sourceCollider in sourceColliders) { - MeshCollider colliderCopy = destination.AddComponent(); + // copy the relative transform: + // if collider is on root, it returns destination root. + // if collider is on a child, it creates and returns a child on destination. + GameObject target = CopyRelativeTransform(source, sourceCollider.transform, destination); + MeshCollider colliderCopy = target.AddComponent(); colliderCopy.sharedMesh = sourceCollider.sharedMesh; colliderCopy.convex = sourceCollider.convex; colliderCopy.isTrigger = sourceCollider.isTrigger; @@ -268,7 +302,7 @@ protected virtual void CreateGhosts() // cache components to avoid GetComponent calls at runtime physicsCopyRigidbody = physicsCopy.GetComponent(); - physicsCopyCollider = physicsCopy.GetComponent(); + physicsCopyCollider = physicsCopy.GetComponentInChildren(); if (physicsCopyRigidbody == null) throw new Exception("SeparatePhysics: couldn't find final Rigidbody."); if (physicsCopyCollider == null) throw new Exception("SeparatePhysics: couldn't find final Collider."); }