From a593ba7c58b3c1e2f0d69681bbc172701d9eb07c Mon Sep 17 00:00:00 2001 From: Ashton Meuser Date: Sat, 5 Sep 2026 15:31:26 -0700 Subject: [PATCH] Include component ID in all physics events --- .../Scripts/Scenarios/BounceProbe.cs | 2 +- .../Scripts/Scenarios/SmokeZoneTracker.cs | 14 ++---- .../PurrDiction/Examples/ProjectileShooter.cs | 2 +- .../PhysicsEvents/Predicted2DPhysics.cs | 15 +++--- .../PhysicsEvents/Predicted3DPhysics.cs | 15 +++--- .../IPredictedPhysicsCallbacks.cs | 15 +++--- .../UnityPhysics/PredictedPhysicsCallbacks.cs | 21 ++++++--- .../UnityPhysics/PredictedProjectile3D.cs | 25 +++++++--- .../UnityPhysics/PredictedRigidbody.cs | 47 +++++++++++-------- .../UnityPhysics/PredictedRigidbody2D.cs | 29 +++++++----- .../EditorTests/IdentityRegistrationTests.cs | 4 +- Assets/PurrDictionTests/OhYeahBaby.cs | 8 +++- .../SimpleRotatingPlatform.cs | 5 +- 13 files changed, 122 insertions(+), 80 deletions(-) diff --git a/Assets/PredictionTests/Scripts/Scenarios/BounceProbe.cs b/Assets/PredictionTests/Scripts/Scenarios/BounceProbe.cs index 7825c7b3..acf157ea 100644 --- a/Assets/PredictionTests/Scripts/Scenarios/BounceProbe.cs +++ b/Assets/PredictionTests/Scripts/Scenarios/BounceProbe.cs @@ -73,7 +73,7 @@ protected override void OnDestroy() /// private const float MinCountedImpactSpeed = 1f; - private void OnBounce(GameObject other, PhysicsCollision collision) + private void OnBounce(GameObject other, PredictedComponentID otherId, PhysicsCollision collision) { if (!predictionManager.isVerifiedView) return; diff --git a/Assets/PredictionTests/Scripts/Scenarios/SmokeZoneTracker.cs b/Assets/PredictionTests/Scripts/Scenarios/SmokeZoneTracker.cs index f1f17f7a..2db7b268 100644 --- a/Assets/PredictionTests/Scripts/Scenarios/SmokeZoneTracker.cs +++ b/Assets/PredictionTests/Scripts/Scenarios/SmokeZoneTracker.cs @@ -62,24 +62,18 @@ private void OnDisable() instances.Remove(this); } - private void OnPredictedTriggerEnter(GameObject other) + private void OnPredictedTriggerEnter(GameObject other, PredictedComponentID otherId) { - if (!PredictionManager.TryGetClosestPredictedID(other, out var pid)) - return; - enterFires++; - var id = pid.objectId; + var id = otherId.objectId; if (!currentState.insideIds.Contains(id)) currentState.insideIds.Add(id); } - private void OnPredictedTriggerExit(GameObject other) + private void OnPredictedTriggerExit(GameObject other, PredictedComponentID otherId) { - if (!PredictionManager.TryGetClosestPredictedID(other, out var pid)) - return; - exitFires++; - var id = pid.objectId; + var id = otherId.objectId; if (currentState.insideIds.Contains(id)) currentState.insideIds.Remove(id); } diff --git a/Assets/PurrDiction/Examples/ProjectileShooter.cs b/Assets/PurrDiction/Examples/ProjectileShooter.cs index ba1ecc7b..bc6d83a1 100644 --- a/Assets/PurrDiction/Examples/ProjectileShooter.cs +++ b/Assets/PurrDiction/Examples/ProjectileShooter.cs @@ -35,7 +35,7 @@ private void Shoot() projectile.AddImpulse(transform.forward * _initialForce); if(projectile.isTrigger) - projectile.onTriggerEnter += (other) => OnProjectileTriggerEnter(projectile, other); + projectile.onTriggerEnter += (other, _) => OnProjectileTriggerEnter(projectile, other); } private void OnProjectileTriggerEnter(PredictedProjectile3D projectile, GameObject other) diff --git a/Assets/PurrDiction/Runtime/PhysicsEvents/Predicted2DPhysics.cs b/Assets/PurrDiction/Runtime/PhysicsEvents/Predicted2DPhysics.cs index cb5de92d..a4ff5193 100644 --- a/Assets/PurrDiction/Runtime/PhysicsEvents/Predicted2DPhysics.cs +++ b/Assets/PurrDiction/Runtime/PhysicsEvents/Predicted2DPhysics.cs @@ -121,20 +121,21 @@ private static void TriggerEvent(PredictionManager predictionManager, Physics2DE if (ev.me.TryGetIdentity(predictionManager, out var me)) { var otherGo = ev.other.GetGameObject(predictionManager); - if (!otherGo && ev.other.objectId.instanceId.value != 0) + if (!otherGo && ev.type != PhysicsEventType.Exit && + ev.other.objectId.instanceId.value != 0) return; if (ev.isTrigger) { switch (ev.type) { case PhysicsEventType.Enter: - me.RaiseTriggerEnter(otherGo); + me.RaiseTriggerEnter(otherGo, ev.other); break; case PhysicsEventType.Exit: - me.RaiseTriggerExit(otherGo); + me.RaiseTriggerExit(otherGo, ev.other); break; case PhysicsEventType.Stay: - me.RaiseTriggerStay(otherGo); + me.RaiseTriggerStay(otherGo, ev.other); break; default: throw new ArgumentOutOfRangeException(); } @@ -144,13 +145,13 @@ private static void TriggerEvent(PredictionManager predictionManager, Physics2DE switch (ev.type) { case PhysicsEventType.Enter: - me.RaiseCollisionEnter(otherGo, ev.contacts); + me.RaiseCollisionEnter(otherGo, ev.other, ev.contacts); break; case PhysicsEventType.Exit: - me.RaiseCollisionExit(otherGo, ev.contacts); + me.RaiseCollisionExit(otherGo, ev.other, ev.contacts); break; case PhysicsEventType.Stay: - me.RaiseCollisionStay(otherGo, ev.contacts); + me.RaiseCollisionStay(otherGo, ev.other, ev.contacts); break; default: throw new ArgumentOutOfRangeException(); } diff --git a/Assets/PurrDiction/Runtime/PhysicsEvents/Predicted3DPhysics.cs b/Assets/PurrDiction/Runtime/PhysicsEvents/Predicted3DPhysics.cs index 8f30db26..db1b96d8 100644 --- a/Assets/PurrDiction/Runtime/PhysicsEvents/Predicted3DPhysics.cs +++ b/Assets/PurrDiction/Runtime/PhysicsEvents/Predicted3DPhysics.cs @@ -59,20 +59,21 @@ private static void TriggerEvent(PredictionManager predictionManager, PhysicsEve if (ev.me.TryGetIdentity(predictionManager, out var me)) { var otherGo = ev.other.GetGameObject(predictionManager); - if (!otherGo && ev.other.objectId.instanceId.value != 0) + if (!otherGo && ev.type != PhysicsEventType.Exit && + ev.other.objectId.instanceId.value != 0) return; if (ev.isTrigger) { switch (ev.type) { case PhysicsEventType.Enter: - me.RaiseTriggerEnter(otherGo); + me.RaiseTriggerEnter(otherGo, ev.other); break; case PhysicsEventType.Exit: - me.RaiseTriggerExit(otherGo); + me.RaiseTriggerExit(otherGo, ev.other); break; case PhysicsEventType.Stay: - me.RaiseTriggerStay(otherGo); + me.RaiseTriggerStay(otherGo, ev.other); break; default: throw new ArgumentOutOfRangeException(); } @@ -82,13 +83,13 @@ private static void TriggerEvent(PredictionManager predictionManager, PhysicsEve switch (ev.type) { case PhysicsEventType.Enter: - me.RaiseCollisionEnter(otherGo, ev.collision); + me.RaiseCollisionEnter(otherGo, ev.other, ev.collision); break; case PhysicsEventType.Exit: - me.RaiseCollisionExit(otherGo, ev.collision); + me.RaiseCollisionExit(otherGo, ev.other, ev.collision); break; case PhysicsEventType.Stay: - me.RaiseCollisionStay(otherGo, ev.collision); + me.RaiseCollisionStay(otherGo, ev.other, ev.collision); break; default: throw new ArgumentOutOfRangeException(); } diff --git a/Assets/PurrDiction/Runtime/UnityPhysics/IPredictedPhysicsCallbacks.cs b/Assets/PurrDiction/Runtime/UnityPhysics/IPredictedPhysicsCallbacks.cs index 23dafa9f..b2d027e7 100644 --- a/Assets/PurrDiction/Runtime/UnityPhysics/IPredictedPhysicsCallbacks.cs +++ b/Assets/PurrDiction/Runtime/UnityPhysics/IPredictedPhysicsCallbacks.cs @@ -4,16 +4,19 @@ namespace PurrNet.Prediction { public interface IPredictedPhysicsCallbacks { - public void RaiseTriggerEnter(GameObject other); + public void RaiseTriggerEnter(GameObject other, PredictedComponentID otherId); - public void RaiseTriggerExit(GameObject other); + public void RaiseTriggerExit(GameObject other, PredictedComponentID otherId); - public void RaiseTriggerStay(GameObject other); + public void RaiseTriggerStay(GameObject other, PredictedComponentID otherId); - public void RaiseCollisionEnter(GameObject other, PhysicsCollision evContacts); + public void RaiseCollisionEnter(GameObject other, PredictedComponentID otherId, + PhysicsCollision evContacts); - public void RaiseCollisionExit(GameObject other, PhysicsCollision evContacts); + public void RaiseCollisionExit(GameObject other, PredictedComponentID otherId, + PhysicsCollision evContacts); - public void RaiseCollisionStay(GameObject other, PhysicsCollision evContacts); + public void RaiseCollisionStay(GameObject other, PredictedComponentID otherId, + PhysicsCollision evContacts); } } diff --git a/Assets/PurrDiction/Runtime/UnityPhysics/PredictedPhysicsCallbacks.cs b/Assets/PurrDiction/Runtime/UnityPhysics/PredictedPhysicsCallbacks.cs index 6b04ed54..e0f49d60 100644 --- a/Assets/PurrDiction/Runtime/UnityPhysics/PredictedPhysicsCallbacks.cs +++ b/Assets/PurrDiction/Runtime/UnityPhysics/PredictedPhysicsCallbacks.cs @@ -17,17 +17,26 @@ public class PredictedPhysicsCallbacks : StatelessPredictedIdentity, IPredictedP public event OnControllerColliderHitDelegate onControllerColliderHit; - public void RaiseTriggerEnter(GameObject other) => onTriggerEnter?.Invoke(other); + public void RaiseTriggerEnter(GameObject other, PredictedComponentID otherId) + => onTriggerEnter?.Invoke(other, otherId); - public void RaiseTriggerExit(GameObject other) => onTriggerExit?.Invoke(other); + public void RaiseTriggerExit(GameObject other, PredictedComponentID otherId) + => onTriggerExit?.Invoke(other, otherId); - public void RaiseTriggerStay(GameObject other) => onTriggerStay?.Invoke(other); + public void RaiseTriggerStay(GameObject other, PredictedComponentID otherId) + => onTriggerStay?.Invoke(other, otherId); - public void RaiseCollisionEnter(GameObject other, PhysicsCollision evContacts) => onCollisionEnter?.Invoke(other, evContacts); + public void RaiseCollisionEnter(GameObject other, PredictedComponentID otherId, + PhysicsCollision evContacts) + => onCollisionEnter?.Invoke(other, otherId, evContacts); - public void RaiseCollisionExit(GameObject other, PhysicsCollision evContacts) => onCollisionExit?.Invoke(other, evContacts); + public void RaiseCollisionExit(GameObject other, PredictedComponentID otherId, + PhysicsCollision evContacts) + => onCollisionExit?.Invoke(other, otherId, evContacts); - public void RaiseCollisionStay(GameObject other, PhysicsCollision evContacts) => onCollisionStay?.Invoke(other, evContacts); + public void RaiseCollisionStay(GameObject other, PredictedComponentID otherId, + PhysicsCollision evContacts) + => onCollisionStay?.Invoke(other, otherId, evContacts); public void RaiseControllerColliderHit(GameObject other, PhysicsControllerHit hit) => onControllerColliderHit?.Invoke(other, hit); diff --git a/Assets/PurrDiction/Runtime/UnityPhysics/PredictedProjectile3D.cs b/Assets/PurrDiction/Runtime/UnityPhysics/PredictedProjectile3D.cs index b9b81d39..320be57e 100644 --- a/Assets/PurrDiction/Runtime/UnityPhysics/PredictedProjectile3D.cs +++ b/Assets/PurrDiction/Runtime/UnityPhysics/PredictedProjectile3D.cs @@ -366,13 +366,26 @@ public void AddImpulse(Vector3 impulse) currentState.velocity += impulse; } - public void RaiseTriggerEnter(GameObject other) => onTriggerEnter?.Invoke(other); - public void RaiseTriggerExit(GameObject other) => onTriggerExit?.Invoke(other); - public void RaiseTriggerStay(GameObject other) => onTriggerStay?.Invoke(other); + public void RaiseTriggerEnter(GameObject other, PredictedComponentID otherId) + => onTriggerEnter?.Invoke(other, otherId); - public void RaiseCollisionEnter(GameObject other, PhysicsCollision evContacts) => onCollisionEnter?.Invoke(other, evContacts); - public void RaiseCollisionExit(GameObject other, PhysicsCollision evContacts) => onCollisionExit?.Invoke(other, evContacts); - public void RaiseCollisionStay(GameObject other, PhysicsCollision evContacts) => onCollisionStay?.Invoke(other, evContacts); + public void RaiseTriggerExit(GameObject other, PredictedComponentID otherId) + => onTriggerExit?.Invoke(other, otherId); + + public void RaiseTriggerStay(GameObject other, PredictedComponentID otherId) + => onTriggerStay?.Invoke(other, otherId); + + public void RaiseCollisionEnter(GameObject other, PredictedComponentID otherId, + PhysicsCollision evContacts) + => onCollisionEnter?.Invoke(other, otherId, evContacts); + + public void RaiseCollisionExit(GameObject other, PredictedComponentID otherId, + PhysicsCollision evContacts) + => onCollisionExit?.Invoke(other, otherId, evContacts); + + public void RaiseCollisionStay(GameObject other, PredictedComponentID otherId, + PhysicsCollision evContacts) + => onCollisionStay?.Invoke(other, otherId, evContacts); protected override ProjectileState3D Interpolate(ProjectileState3D from, ProjectileState3D to, float t) { diff --git a/Assets/PurrDiction/Runtime/UnityPhysics/PredictedRigidbody.cs b/Assets/PurrDiction/Runtime/UnityPhysics/PredictedRigidbody.cs index 6db9ef1e..d568af87 100644 --- a/Assets/PurrDiction/Runtime/UnityPhysics/PredictedRigidbody.cs +++ b/Assets/PurrDiction/Runtime/UnityPhysics/PredictedRigidbody.cs @@ -26,8 +26,9 @@ public enum FloatAccuracy Low = 2 } - public delegate void OnCollisionDelegate(GameObject other, PhysicsCollision physicsEvent); - public delegate void OnTriggerDelegate(GameObject other); + public delegate void OnCollisionDelegate(GameObject other, PredictedComponentID otherId, + PhysicsCollision physicsEvent); + public delegate void OnTriggerDelegate(GameObject other, PredictedComponentID otherId); public delegate void OnControllerColliderHitDelegate(GameObject other, PhysicsControllerHit physicsEvent); #if UNITY_PHYSICS_3D @@ -746,62 +747,68 @@ public void Move(Vector3 position, Quaternion rotation) } - public void RaiseTriggerEnter(GameObject other) + public void RaiseTriggerEnter(GameObject other, PredictedComponentID otherId) { - onTriggerEnter?.Invoke(other); + onTriggerEnter?.Invoke(other, otherId); } - public void RaiseTriggerExit(GameObject other) + public void RaiseTriggerExit(GameObject other, PredictedComponentID otherId) { - onTriggerExit?.Invoke(other); + onTriggerExit?.Invoke(other, otherId); } - public void RaiseTriggerStay(GameObject other) + public void RaiseTriggerStay(GameObject other, PredictedComponentID otherId) { - onTriggerStay?.Invoke(other); + onTriggerStay?.Invoke(other, otherId); } - public void RaiseCollisionEnter(GameObject other, PhysicsCollision evContacts) + public void RaiseCollisionEnter(GameObject other, PredictedComponentID otherId, + PhysicsCollision evContacts) { - onCollisionEnter?.Invoke(other, evContacts); + onCollisionEnter?.Invoke(other, otherId, evContacts); } - public void RaiseCollisionExit(GameObject other, PhysicsCollision evContacts) + public void RaiseCollisionExit(GameObject other, PredictedComponentID otherId, + PhysicsCollision evContacts) { - onCollisionExit?.Invoke(other, evContacts); + onCollisionExit?.Invoke(other, otherId, evContacts); } - public void RaiseCollisionStay(GameObject other, PhysicsCollision evContacts) + public void RaiseCollisionStay(GameObject other, PredictedComponentID otherId, + PhysicsCollision evContacts) { - onCollisionStay?.Invoke(other, evContacts); + onCollisionStay?.Invoke(other, otherId, evContacts); } #else - public void RaiseTriggerEnter(GameObject other) + public void RaiseTriggerEnter(GameObject other, PredictedComponentID otherId) { throw new NotImplementedException(); } - public void RaiseTriggerExit(GameObject other) + public void RaiseTriggerExit(GameObject other, PredictedComponentID otherId) { throw new NotImplementedException(); } - public void RaiseTriggerStay(GameObject other) + public void RaiseTriggerStay(GameObject other, PredictedComponentID otherId) { throw new NotImplementedException(); } - public void RaiseCollisionEnter(GameObject other, PhysicsCollision evContacts) + public void RaiseCollisionEnter(GameObject other, PredictedComponentID otherId, + PhysicsCollision evContacts) { throw new NotImplementedException(); } - public void RaiseCollisionExit(GameObject other, PhysicsCollision evContacts) + public void RaiseCollisionExit(GameObject other, PredictedComponentID otherId, + PhysicsCollision evContacts) { throw new NotImplementedException(); } - public void RaiseCollisionStay(GameObject other, PhysicsCollision evContacts) + public void RaiseCollisionStay(GameObject other, PredictedComponentID otherId, + PhysicsCollision evContacts) { throw new NotImplementedException(); } diff --git a/Assets/PurrDiction/Runtime/UnityPhysics/PredictedRigidbody2D.cs b/Assets/PurrDiction/Runtime/UnityPhysics/PredictedRigidbody2D.cs index fe603ff8..1391c9d1 100644 --- a/Assets/PurrDiction/Runtime/UnityPhysics/PredictedRigidbody2D.cs +++ b/Assets/PurrDiction/Runtime/UnityPhysics/PredictedRigidbody2D.cs @@ -15,8 +15,9 @@ public class PredictedRigidbody2D : PredictedIdentity [SerializeField, Min(0f)] private float _softVelocityCorrectionRate = 8f; #if UNITY_PHYSICS_2D - public delegate void OnCollisionDelegate(GameObject other, DisposableList evContacts); - public delegate void OnTriggerDelegate(GameObject other); + public delegate void OnCollisionDelegate(GameObject other, PredictedComponentID otherId, + DisposableList evContacts); + public delegate void OnTriggerDelegate(GameObject other, PredictedComponentID otherId); [SerializeField] private Rigidbody2D _rigidbody; [SerializeField] private PhysicsEventMask _eventMask = (PhysicsEventMask)0x3F; @@ -503,25 +504,31 @@ private void OnTriggerStay2D(Collider2D other) predictionManager.physics2d.RegisterEvent(PhysicsEventType.Stay, this, other); } - public void RaiseTriggerEnter(GameObject other) => onTriggerEnter?.Invoke(other); + public void RaiseTriggerEnter(GameObject other, PredictedComponentID otherId) + => onTriggerEnter?.Invoke(other, otherId); - public void RaiseTriggerExit(GameObject other) => onTriggerExit?.Invoke(other); + public void RaiseTriggerExit(GameObject other, PredictedComponentID otherId) + => onTriggerExit?.Invoke(other, otherId); - public void RaiseTriggerStay(GameObject other) => onTriggerStay?.Invoke(other); + public void RaiseTriggerStay(GameObject other, PredictedComponentID otherId) + => onTriggerStay?.Invoke(other, otherId); - public void RaiseCollisionEnter(GameObject other, DisposableList evContacts) + public void RaiseCollisionEnter(GameObject other, PredictedComponentID otherId, + DisposableList evContacts) { - onCollisionEnter?.Invoke(other, evContacts); + onCollisionEnter?.Invoke(other, otherId, evContacts); } - public void RaiseCollisionExit(GameObject other, DisposableList evContacts) + public void RaiseCollisionExit(GameObject other, PredictedComponentID otherId, + DisposableList evContacts) { - onCollisionExit?.Invoke(other, evContacts); + onCollisionExit?.Invoke(other, otherId, evContacts); } - public void RaiseCollisionStay(GameObject other, DisposableList evContacts) + public void RaiseCollisionStay(GameObject other, PredictedComponentID otherId, + DisposableList evContacts) { - onCollisionStay?.Invoke(other, evContacts); + onCollisionStay?.Invoke(other, otherId, evContacts); } public Vector2 position diff --git a/Assets/PurrDictionTests/EditorTests/IdentityRegistrationTests.cs b/Assets/PurrDictionTests/EditorTests/IdentityRegistrationTests.cs index 0f3b2106..90ca960e 100644 --- a/Assets/PurrDictionTests/EditorTests/IdentityRegistrationTests.cs +++ b/Assets/PurrDictionTests/EditorTests/IdentityRegistrationTests.cs @@ -73,7 +73,8 @@ public void UnregisteringLiveIdentityClearsRegistration() } finally { - Object.DestroyImmediate(identityObject); + if (identityObject) + Object.DestroyImmediate(identityObject); Object.DestroyImmediate(managerObject); } } @@ -116,5 +117,6 @@ private static void SetField( Assert.That(field, Is.Not.Null, $"missing field {name}"); field.SetValue(manager, value); } + } } diff --git a/Assets/PurrDictionTests/OhYeahBaby.cs b/Assets/PurrDictionTests/OhYeahBaby.cs index 457b7708..ee30e740 100644 --- a/Assets/PurrDictionTests/OhYeahBaby.cs +++ b/Assets/PurrDictionTests/OhYeahBaby.cs @@ -19,10 +19,12 @@ protected override void OnDestroy() _rb.onTriggerExit -= OnPTriggerExit; } - private void OnPTriggerEnter(GameObject other) + private void OnPTriggerEnter(GameObject other, PredictedComponentID otherId) { if (!isServer) return; + if (!other) + return; if (other.TryGetComponent(out var controller)) { var players = predictionManager.players.players; @@ -34,10 +36,12 @@ private void OnPTriggerEnter(GameObject other) } } - private void OnPTriggerExit(GameObject other) + private void OnPTriggerExit(GameObject other, PredictedComponentID otherId) { if (!isServer) return; + if (!other) + return; if (other.TryGetComponent(out var controller)) { var players = predictionManager.players.players; diff --git a/Assets/PurrDictionTests/SimpleRotatingPlatform.cs b/Assets/PurrDictionTests/SimpleRotatingPlatform.cs index afaaa333..788e2020 100644 --- a/Assets/PurrDictionTests/SimpleRotatingPlatform.cs +++ b/Assets/PurrDictionTests/SimpleRotatingPlatform.cs @@ -55,12 +55,13 @@ protected override void Simulate(ref State data, float delta) predictionManager.hierarchy.Delete(gameObject);*/ } - private void OnUnityTriggerEnter(GameObject other) + private void OnUnityTriggerEnter(GameObject other, PredictedComponentID otherId) { PurrLogger.Log($"Triggered with {other} on {gameObject.name}"); } - private void OnUnityCollisionEnter(GameObject other, PhysicsCollision collision) + private void OnUnityCollisionEnter(GameObject other, PredictedComponentID otherId, + PhysicsCollision collision) { PurrLogger.Log($"Collided with {other} on {gameObject.name}"); currentState.collisionCount += 1;