void RigidBody_ContactPointCallback_Destruction(ref HkContactPointEvent value) { ProfilerShort.Begin("Grid Contact counter"); ProfilerShort.End(); MyGridContactInfo info = new MyGridContactInfo(ref value, m_grid); if (info.IsKnown) return; var myEntity = info.CurrentEntity;//value.Base.BodyA.GetEntity() == m_grid.Components ? value.Base.BodyA.GetEntity() : value.Base.BodyB.GetEntity(); if (myEntity == null || myEntity.Physics == null || myEntity.Physics.RigidBody == null) { return; } var myBody = myEntity.Physics.RigidBody; // CH: DEBUG var physicsBody1 = value.GetPhysicsBody(0); var physicsBody2 = value.GetPhysicsBody(1); if (physicsBody1 == null || physicsBody2 == null) return; var entity1 = physicsBody1.Entity; var entity2 = physicsBody2.Entity; if (entity1 == null || entity2 == null || entity1.Physics == null || entity2.Physics == null) return; if (entity1 is MyFracturedPiece && entity2 is MyFracturedPiece) return; var rigidBody1 = value.Base.BodyA; var rigidBody2 = value.Base.BodyB; info.HandleEvents(); if (rigidBody1.HasProperty(HkCharacterRigidBody.MANIPULATED_OBJECT) || rigidBody2.HasProperty(HkCharacterRigidBody.MANIPULATED_OBJECT)) return; if (info.CollidingEntity is Sandbox.Game.Entities.Character.MyCharacter || info.CollidingEntity == null || info.CollidingEntity.MarkedForClose) return; var grid1 = entity1 as MyCubeGrid; var grid2 = entity2 as MyCubeGrid; // CH: TODO: This is a hack Instead, the IMyDestroyableObject should be used and the subpart DoDamage code could delegate it to the grid // The thing is, this approach would probably need a rewrite of this whole method... if (grid2 == null && entity2 is MyEntitySubpart) { while (entity2 != null && !(entity2 is MyCubeGrid)) { entity2 = entity2.Parent; } if (entity2 != null) { physicsBody2 = entity2.Physics as MyPhysicsBody; rigidBody2 = physicsBody2.RigidBody; grid2 = entity2 as MyCubeGrid; } } if (grid1 != null && grid2 != null && (MyCubeGridGroups.Static.Physical.GetGroup(grid1) == MyCubeGridGroups.Static.Physical.GetGroup(grid2))) return; ProfilerShort.Begin("Grid contact point callback"); { var vel = Math.Abs(value.SeparatingVelocity); bool enoughSpeed = vel > 3; //float dot = Vector3.Dot(Vector3.Normalize(LinearVelocity), Vector3.Normalize(info.CollidingEntity.Physics.LinearVelocity)); Vector3 velocity1 = rigidBody1.GetVelocityAtPoint(info.Event.ContactPoint.Position); Vector3 velocity2 = rigidBody2.GetVelocityAtPoint(info.Event.ContactPoint.Position); float speed1 = velocity1.Length(); float speed2 = velocity2.Length(); Vector3 dir1 = speed1 > 0 ? Vector3.Normalize(velocity1) : Vector3.Zero; Vector3 dir2 = speed2 > 0 ? Vector3.Normalize(velocity2) : Vector3.Zero; float mass1 = MyDestructionHelper.MassFromHavok(rigidBody1.Mass); float mass2 = MyDestructionHelper.MassFromHavok(rigidBody2.Mass); float impact1 = speed1 * mass1; float impact2 = speed2 * mass2; float dot1withNormal = speed1 > 0 ? Vector3.Dot(dir1, value.ContactPoint.Normal) : 0; float dot2withNormal = speed2 > 0 ? Vector3.Dot(dir2, value.ContactPoint.Normal) : 0; speed1 *= Math.Abs(dot1withNormal); speed2 *= Math.Abs(dot2withNormal); bool is1Static = mass1 == 0; bool is2Static = mass2 == 0; bool is1Small = entity1 is MyFracturedPiece || (grid1 != null && grid1.GridSizeEnum == MyCubeSize.Small); bool is2Small = entity2 is MyFracturedPiece || (grid2 != null && grid2.GridSizeEnum == MyCubeSize.Small); float dot = Vector3.Dot(dir1, dir2); float maxDestructionRadius = 0.5f; impact1 *= info.ImpulseMultiplier; impact2 *= info.ImpulseMultiplier; MyHitInfo hitInfo = new MyHitInfo(); var hitPos = info.ContactPosition; hitInfo.Normal = value.ContactPoint.Normal; //direct hit if (dot1withNormal < 0.0f) { if (entity1 is MyFracturedPiece) impact1 /= 10; impact1 *= Math.Abs(dot1withNormal); //respect angle of hit if ((impact1 > 2000 && speed1 > 2 && !is2Small) || (impact1 > 500 && speed1 > 10)) //must be fast enought to destroy fracture piece (projectile) { //1 is big hitting if (is2Static || impact1 / impact2 > 10) { hitInfo.Position = hitPos + 0.1f * hitInfo.Normal; impact1 -= mass1; if (Sync.IsServer && impact1 > 0) { if (grid1 != null) { var blockPos = GetGridPosition(value.ContactPoint, rigidBody1, grid1, 0); grid1.DoDamage(impact1, hitInfo, blockPos, grid2 != null ? grid2.EntityId : 0); } else MyDestructionHelper.TriggerDestruction(impact1, (MyPhysicsBody)entity1.Physics, info.ContactPosition, value.ContactPoint.Normal, maxDestructionRadius); hitInfo.Position = hitPos - 0.1f * hitInfo.Normal; if (grid2 != null) { var blockPos = GetGridPosition(value.ContactPoint, rigidBody2, grid2, 1); grid2.DoDamage(impact1, hitInfo, blockPos, grid1 != null ? grid1.EntityId : 0); } else MyDestructionHelper.TriggerDestruction(impact1, (MyPhysicsBody)entity2.Physics, info.ContactPosition, value.ContactPoint.Normal, maxDestructionRadius); ReduceVelocities(info); } MyDecals.HandleAddDecal(entity1, hitInfo); MyDecals.HandleAddDecal(entity2, hitInfo); } } } if (dot2withNormal < 0.0f) { if (entity2 is MyFracturedPiece) impact2 /= 10; impact2 *= Math.Abs(dot2withNormal); //respect angle of hit if (impact2 > 2000 && speed2 > 2 && !is1Small || (impact2 > 500 && speed2 > 10)) //must be fast enought to destroy fracture piece (projectile) { //2 is big hitting if (is1Static || impact2 / impact1 > 10) { hitInfo.Position = hitPos + 0.1f * hitInfo.Normal; impact2 -= mass2; if (Sync.IsServer && impact2 > 0) { if (grid1 != null) { var blockPos = GetGridPosition(value.ContactPoint, rigidBody1, grid1, 0); grid1.DoDamage(impact2, hitInfo, blockPos, grid2 != null ? grid2.EntityId : 0); } else MyDestructionHelper.TriggerDestruction(impact2, (MyPhysicsBody)entity1.Physics, info.ContactPosition, value.ContactPoint.Normal, maxDestructionRadius); hitInfo.Position = hitPos - 0.1f * hitInfo.Normal; if (grid2 != null) { var blockPos = GetGridPosition(value.ContactPoint, rigidBody2, grid2, 1); grid2.DoDamage(impact2, hitInfo, blockPos, grid1 != null ? grid1.EntityId : 0); } else MyDestructionHelper.TriggerDestruction(impact2, (MyPhysicsBody)entity2.Physics, info.ContactPosition, value.ContactPoint.Normal, maxDestructionRadius); ReduceVelocities(info); } MyDecals.HandleAddDecal(entity1, hitInfo); MyDecals.HandleAddDecal(entity2, hitInfo); } } } //float destructionImpact = vel * (MyDestructionHelper.MassFromHavok(Mass) + MyDestructionHelper.MassFromHavok(info.CollidingEntity.Physics.Mass)); //destructionImpact *= info.ImpulseMultiplier; //if (destructionImpact > 2000 && enoughSpeed) //{ // CreateDestructionFor(destructionImpact, LinearVelocity + info.CollidingEntity.Physics.LinearVelocity, this, info, value.ContactPoint.Normal); // CreateDestructionFor(destructionImpact, LinearVelocity + info.CollidingEntity.Physics.LinearVelocity, info.CollidingEntity.Physics, info, value.ContactPoint.Normal); // ReduceVelocities(info); //} } ProfilerShort.End(); }
void RigidBody_ContactPointCallback(ref HkContactPointEvent value) { ProfilerShort.Begin("Grid Contact counter"); ProfilerShort.End(); var entity1 = value.Base.BodyA.GetEntity(); var entity2 = value.Base.BodyB.GetEntity(); if (entity1 == null || entity2 == null) return; //DA used to stop appliyng force when there is planet/ship collisions to increase performance after ship crashes on planet if ((Math.Abs(value.SeparatingVelocity) < 0.3f) && (entity1 is MyTrees || entity1 is MyVoxelPhysics || entity2 is MyVoxelPhysics || entity2 is MyTrees)) { return; } MyGridContactInfo info = new MyGridContactInfo(ref value, m_grid); var myBody = value.Base.BodyA.GetEntity() == m_grid.Components ? value.Base.BodyA : value.Base.BodyB; // CH: DEBUG if (info.CollidingEntity is Sandbox.Game.Entities.Character.MyCharacter || info.CollidingEntity.MarkedForClose) return; if (MyFakes.LANDING_GEAR_IGNORE_DAMAGE_CONTACTS && MyCubeGridGroups.Static.NoContactDamage.HasSameGroupAndIsGrid(entity1, entity2)) return; ProfilerShort.Begin("Grid contact point callback"); bool doSparks = MyPerGameSettings.EnableCollisionSparksEffect && (info.CollidingEntity is MyCubeGrid || info.CollidingEntity is MyVoxelMap); // According to Petr, WasUsed does not work everytime //if (value.ContactProperties.WasUsed) { // Handle callbacks here info.HandleEvents(); } bool deformationPerformed = false; if (Sync.IsServer && value.ContactProperties.ImpulseApplied > MyGridShape.BreakImpulse && info.CollidingEntity != null && info.EnableDeformation && m_grid.BlocksDestructionEnabled) { float deformation = value.SeparatingVelocity; if (info.RubberDeformation) { deformation /= 5; } HkBreakOffPointInfo breakInfo = CreateBreakOffPoint(value, info.ContactPosition, MyGridShape.BreakImpulse); PerformDeformation(ref breakInfo, false, value.SeparatingVelocity); deformationPerformed = true; } else if (doSparks && value.SeparatingVelocity > 2.0f && value.ContactProperties.WasUsed && !m_lastContacts.ContainsKey(value.ContactPointId) && info.EnableParticles) { m_lastContacts[value.ContactPointId] = MySandboxGame.TotalGamePlayTimeInMilliseconds; AddCollisionEffect(info.ContactPosition, value.ContactPoint.Normal); } // Large dynamic ships colliding with floating objects // When low separating velocity or deformation performed, disable contact point // Floating object will still collide with kinematic part of ship and won't push it if (m_grid.GridSizeEnum == MyCubeSize.Large && !myBody.IsFixedOrKeyframed && info.CollidingEntity is MyFloatingObject && (Math.Abs(value.SeparatingVelocity) < 0.2f || deformationPerformed)) { var prop = value.ContactProperties; prop.IsDisabled = true; } ProfilerShort.End(); }
void RigidBody_ContactPointCallback_Destruction(ref HkContactPointEvent value) { ProfilerShort.Begin("Grid Contact counter"); ProfilerShort.End(); MyGridContactInfo info = new MyGridContactInfo(ref value, m_grid); if (info.IsKnown) return; var myBody = info.CurrentEntity.Physics.RigidBody;//value.Base.BodyA.GetEntity() == m_grid.Components ? value.Base.BodyA : value.Base.BodyB; var myEntity = info.CurrentEntity;//value.Base.BodyA.GetEntity() == m_grid.Components ? value.Base.BodyA.GetEntity() : value.Base.BodyB.GetEntity(); // CH: DEBUG var entity1 = value.Base.BodyA.GetEntity(); var entity2 = value.Base.BodyB.GetEntity(); var rigidBody1 = value.Base.BodyA; var rigidBody2 = value.Base.BodyB; if (entity1 == null || entity2 == null || entity1.Physics == null || entity2.Physics == null) return; if (entity1 is MyFracturedPiece && entity2 is MyFracturedPiece) return; info.HandleEvents(); if (rigidBody1.HasProperty(HkCharacterRigidBody.MANIPULATED_OBJECT) || rigidBody2.HasProperty(HkCharacterRigidBody.MANIPULATED_OBJECT)) return; if (info.CollidingEntity is Sandbox.Game.Entities.Character.MyCharacter || info.CollidingEntity == null || info.CollidingEntity.MarkedForClose) return; if (MyFakes.ENABLE_CHARACTER_VIRTUAL_PHYSICS) { MyCharacter character = MySession.ControlledEntity as MyCharacter; if (character != null && character.VirtualPhysics != null) { foreach (var constraint in character.VirtualPhysics.Constraints) { IMyEntity cstrEntityA = constraint.RigidBodyA.GetEntity(); IMyEntity cstrEntityB = constraint.RigidBodyB.GetEntity(); if (info.CurrentEntity == cstrEntityA || info.CurrentEntity == cstrEntityB || info.CollidingEntity == cstrEntityA || info.CollidingEntity == cstrEntityB) return; } } } var grid1 = entity1 as MyCubeGrid; var grid2 = entity2 as MyCubeGrid; if (grid1 != null && grid2 != null && (MyCubeGridGroups.Static.Physical.GetGroup(grid1) == MyCubeGridGroups.Static.Physical.GetGroup(grid2))) return; ProfilerShort.Begin("Grid contact point callback"); if (Sync.IsServer) { var vel = Math.Abs(value.SeparatingVelocity); bool enoughSpeed = vel > 3; //float dot = Vector3.Dot(Vector3.Normalize(LinearVelocity), Vector3.Normalize(info.CollidingEntity.Physics.LinearVelocity)); Vector3 velocity1 = rigidBody1.GetVelocityAtPoint(info.Event.ContactPoint.Position); Vector3 velocity2 = rigidBody2.GetVelocityAtPoint(info.Event.ContactPoint.Position); float speed1 = velocity1.Length(); float speed2 = velocity2.Length(); Vector3 dir1 = speed1 > 0 ? Vector3.Normalize(velocity1) : Vector3.Zero; Vector3 dir2 = speed2 > 0 ? Vector3.Normalize(velocity2) : Vector3.Zero; float mass1 = MyDestructionHelper.MassFromHavok(rigidBody1.Mass); float mass2 = MyDestructionHelper.MassFromHavok(rigidBody2.Mass); float impact1 = speed1 * mass1; float impact2 = speed2 * mass2; float dot1withNormal = speed1 > 0 ? Vector3.Dot(dir1, value.ContactPoint.Normal) : 0; float dot2withNormal = speed2 > 0 ? Vector3.Dot(dir2, value.ContactPoint.Normal) : 0; speed1 *= Math.Abs(dot1withNormal); speed2 *= Math.Abs(dot2withNormal); bool is1Static = mass1 == 0; bool is2Static = mass2 == 0; bool is1Small = entity1 is MyFracturedPiece || (grid1 != null && grid1.GridSizeEnum == MyCubeSize.Small); bool is2Small = entity2 is MyFracturedPiece || (grid2 != null && grid2.GridSizeEnum == MyCubeSize.Small); float dot = Vector3.Dot(dir1, dir2); float maxDestructionRadius = 0.5f; impact1 *= info.ImpulseMultiplier; impact2 *= info.ImpulseMultiplier; MyHitInfo hitInfo = new MyHitInfo(); var hitPos = info.ContactPosition; hitInfo.Normal = value.ContactPoint.Normal; //direct hit if (dot1withNormal < 0.0f) { if (entity1 is MyFracturedPiece) impact1 /= 10; impact1 *= Math.Abs(dot1withNormal); //respect angle of hit if (entity2 is MyFracturedPiece) { } if ((impact1 > 2000 && speed1 > 2 && !is2Small) || (impact1 > 500 && speed1 > 10)) //must be fast enought to destroy fracture piece (projectile) { //1 is big hitting if (is2Static || impact1 / impact2 > 10) { hitInfo.Position = hitPos + 0.1f * hitInfo.Normal; impact1 -= mass1; if (grid1 != null) { var blockPos = GetGridPosition(value, grid1, 0); grid1.DoDamage(impact1, hitInfo, blockPos); } else MyDestructionHelper.TriggerDestruction(impact1, (MyPhysicsBody)entity1.Physics, info.ContactPosition, value.ContactPoint.Normal, maxDestructionRadius); hitInfo.Position = hitPos - 0.1f * hitInfo.Normal; if (grid2 != null) { var blockPos = GetGridPosition(value, grid2, 1); grid2.DoDamage(impact1, hitInfo, blockPos); } else MyDestructionHelper.TriggerDestruction(impact1, (MyPhysicsBody)entity2.Physics, info.ContactPosition, value.ContactPoint.Normal, maxDestructionRadius); ReduceVelocities(info); } } } if (dot2withNormal < 0.0f) { if (entity2 is MyFracturedPiece) impact2 /= 10; impact2 *= Math.Abs(dot1withNormal); //respect angle of hit if (impact2 > 2000 && speed2 > 2 && !is1Small || (impact2 > 500 && speed2 > 10)) //must be fast enought to destroy fracture piece (projectile) { //2 is big hitting if (is1Static || impact2 / impact1 > 10) { hitInfo.Position = hitPos + 0.1f * hitInfo.Normal; impact2 -= mass2; if (grid1 != null) { var blockPos = GetGridPosition(value, grid1, 0); grid1.DoDamage(impact2, hitInfo, blockPos); } else MyDestructionHelper.TriggerDestruction(impact2, (MyPhysicsBody)entity1.Physics, info.ContactPosition, value.ContactPoint.Normal, maxDestructionRadius); hitInfo.Position = hitPos - 0.1f * hitInfo.Normal; if (grid2 != null) { var blockPos = GetGridPosition(value, grid2, 1); grid2.DoDamage(impact2, hitInfo, blockPos); } else MyDestructionHelper.TriggerDestruction(impact2, (MyPhysicsBody)entity2.Physics, info.ContactPosition, value.ContactPoint.Normal, maxDestructionRadius); ReduceVelocities(info); } } } //float destructionImpact = vel * (MyDestructionHelper.MassFromHavok(Mass) + MyDestructionHelper.MassFromHavok(info.CollidingEntity.Physics.Mass)); //destructionImpact *= info.ImpulseMultiplier; //if (destructionImpact > 2000 && enoughSpeed) //{ // CreateDestructionFor(destructionImpact, LinearVelocity + info.CollidingEntity.Physics.LinearVelocity, this, info, value.ContactPoint.Normal); // CreateDestructionFor(destructionImpact, LinearVelocity + info.CollidingEntity.Physics.LinearVelocity, info.CollidingEntity.Physics, info, value.ContactPoint.Normal); // ReduceVelocities(info); //} } ProfilerShort.End(); }
void RigidBody_ContactPointCallback(ref HkContactPointEvent value) { ProfilerShort.Begin("Grid Contact counter"); ProfilerShort.End(); var otherEntity = value.GetOtherEntity(m_grid); var otherPhysicsBody = value.GetPhysicsBody(0); var thisEntity = m_grid; if (otherEntity == null || thisEntity == null) return; //DA used to stop appliyng force when there is planet/ship collisions to increase performance after ship crashes on planet if ((Math.Abs(value.SeparatingVelocity) < 0.3f) && (otherEntity is MyTrees || otherEntity is MyVoxelPhysics)) { return; } MyGridContactInfo info = new MyGridContactInfo(ref value, m_grid); var myBody = RigidBody;// value.Base.BodyA.GetEntity() == m_grid.Components ? value.Base.BodyA : value.Base.BodyB; if (info.CollidingEntity is Sandbox.Game.Entities.Character.MyCharacter || info.CollidingEntity.MarkedForClose) return; if (MyFakes.LANDING_GEAR_IGNORE_DAMAGE_CONTACTS && MyCubeGridGroups.Static.NoContactDamage.HasSameGroupAndIsGrid(otherEntity, thisEntity)) return; ProfilerShort.Begin("Grid contact point callback"); bool hitVoxel = info.CollidingEntity is MyVoxelMap || info.CollidingEntity is MyVoxelPhysics; if(hitVoxel && m_grid.Render != null) { m_grid.Render.ResetLastVoxelContactTimer(); } bool doSparks = MyPerGameSettings.EnableCollisionSparksEffect && (info.CollidingEntity is MyCubeGrid || hitVoxel); // According to Petr, WasUsed does not work everytime //if (value.ContactProperties.WasUsed) { // Handle callbacks here info.HandleEvents(); } if(MyDebugDrawSettings.DEBUG_DRAW_FRICTION) { var pos = ClusterToWorld(value.ContactPoint.Position); var vel = -GetVelocityAtPoint(pos); vel *= 0.1f; var fn = Math.Abs(Gravity.Dot(value.ContactPoint.Normal) * value.ContactProperties.Friction); if (vel.Length() > 0.5f) { vel.Normalize(); MyRenderProxy.DebugDrawArrow3D(pos, pos + fn * vel, Color.Gray, Color.Gray, false); } } if (doSparks && Math.Abs(value.SeparatingVelocity) > 2.0f && value.ContactProperties.WasUsed && !m_lastContacts.ContainsKey(value.ContactPointId) && info.EnableParticles) { ProfilerShort.Begin("AddCollisionEffect"); m_lastContacts[value.ContactPointId] = MySandboxGame.TotalGamePlayTimeInMilliseconds; AddCollisionEffect(info.ContactPosition, value.ContactPoint.Normal); ProfilerShort.End(); } ProfilerShort.Begin("Dust"); bool doDust = MyPerGameSettings.EnableCollisionSparksEffect && hitVoxel; float force = Math.Abs(value.SeparatingVelocity * (Mass / 100000)); if (doDust && force > 0.25f && info.EnableParticles) { float scale = MathHelper.Clamp(force / 10.0f, 0.2f, 4.0f); AddDustEffect(info.ContactPosition, scale); } ProfilerShort.End(); // Large dynamic ships colliding with floating objects // When low separating velocity or deformation performed, disable contact point // Floating object will still collide with kinematic part of ship and won't push it if (m_grid.GridSizeEnum == MyCubeSize.Large && !myBody.IsFixedOrKeyframed && info.CollidingEntity is MyFloatingObject && (Math.Abs(value.SeparatingVelocity) < 0.2f)) { var prop = value.ContactProperties; prop.IsDisabled = true; } ProfilerShort.End(); }