public virtual void FracturedBody_AfterReplaceBody(ref HkdReplaceBodyEvent e) { System.Diagnostics.Debug.Assert(Sync.IsServer, "Client must not simulate destructions"); if (!Sandbox.Game.Multiplayer.Sync.IsServer) { return; } ProfilerShort.Begin("DestructionFracture.AfterReplaceBody"); Debug.Assert(BreakableBody != null); e.GetNewBodies(m_tmpLst); if (m_tmpLst.Count == 0)// || e.OldBody != DestructionBody) { ProfilerShort.End(); return; } MyPhysics.RemoveDestructions(RigidBody); foreach (var b in m_tmpLst) { var bBody = MyFracturedPiecesManager.Static.GetBreakableBody(b); MatrixD m = bBody.GetRigidBody().GetRigidBodyMatrix(); m.Translation = ClusterToWorld(m.Translation); var piece = MyDestructionHelper.CreateFracturePiece(bBody, ref m, (Entity as MyFracturedPiece).OriginalBlocks); if (piece == null) { MyFracturedPiecesManager.Static.ReturnToPool(bBody); continue; } } m_tmpLst.Clear(); BreakableBody.AfterReplaceBody -= FracturedBody_AfterReplaceBody; MyFracturedPiecesManager.Static.RemoveFracturePiece(Entity as MyFracturedPiece, 0); ProfilerShort.End(); }
/// <summary> /// Sets default values for ragdoll bodies and constraints - useful if ragdoll model is not correct /// </summary> public void SetRagdollDefaults() { if (MyFakes.ENABLE_RAGDOLL_DEBUG) { Debug.WriteLine("MyPhysicsBody.SetRagdollDefaults"); MyLog.Default.WriteLine("MyPhysicsBody.SetRagdollDefaults"); } var wasKeyframed = Ragdoll.IsKeyframed; Ragdoll.SetToDynamic(); // Compute total mass of the character and distribute it amongs ragdoll bodies var definedMass = (Entity as MyCharacter).Definition.Mass; if (definedMass <= 1) { definedMass = 80; } float totalVolume = 0f; foreach (var body in Ragdoll.RigidBodies) { float bodyLength = 0; var shape = body.GetShape(); Vector4 min, max; shape.GetLocalAABB(0.01f, out min, out max); bodyLength = (max - min).Length(); totalVolume += bodyLength; } // correcting the total volume if (totalVolume <= 0) { totalVolume = 1; } // bodies default settings foreach (var body in Ragdoll.RigidBodies) { body.MaxLinearVelocity = 1000.0f; body.MaxAngularVelocity = 1000.0f; var shape = body.GetShape(); Vector4 min, max; shape.GetLocalAABB(0.01f, out min, out max); float bodyLength = (max - min).Length(); float computedMass = definedMass / totalVolume * bodyLength; body.Mass = MyPerGameSettings.Destruction ? MyDestructionHelper.MassToHavok(computedMass) : computedMass; float radius = shape.ConvexRadius; if (shape.ShapeType == HkShapeType.Capsule) { HkCapsuleShape capsule = (HkCapsuleShape)shape; HkMassProperties massProperties = HkInertiaTensorComputer.ComputeCapsuleVolumeMassProperties(capsule.VertexA, capsule.VertexB, radius, body.Mass); body.InertiaTensor = massProperties.InertiaTensor; } else { HkMassProperties massProperties = HkInertiaTensorComputer.ComputeBoxVolumeMassProperties(Vector3.One * bodyLength * 0.5f, body.Mass); body.InertiaTensor = massProperties.InertiaTensor; } Debug.Assert(body.Mass != 0.0f, "Body's mass was set to 0!"); body.AngularDamping = 0.005f; body.LinearDamping = 0.0f; body.Friction = 6f; body.AllowedPenetrationDepth = 0.1f; body.Restitution = 0.05f; } Ragdoll.OptimizeInertiasOfConstraintTree(); if (wasKeyframed) { Ragdoll.SetToKeyframed(); } // Constraints default settings foreach (var constraint in Ragdoll.Constraints) { if (constraint.ConstraintData is HkRagdollConstraintData) { var constraintData = constraint.ConstraintData as HkRagdollConstraintData; constraintData.MaxFrictionTorque = MyPerGameSettings.Destruction ? MyDestructionHelper.MassToHavok(0.5f) : 3f; } else if (constraint.ConstraintData is HkFixedConstraintData) { var constraintData = constraint.ConstraintData as HkFixedConstraintData; constraintData.MaximumLinearImpulse = 3.40282e28f; constraintData.MaximumAngularImpulse = 3.40282e28f; } else if (constraint.ConstraintData is HkHingeConstraintData) { var constraintData = constraint.ConstraintData as HkHingeConstraintData; constraintData.MaximumAngularImpulse = 3.40282e28f; constraintData.MaximumLinearImpulse = 3.40282e28f; } else if (constraint.ConstraintData is HkLimitedHingeConstraintData) { var constraintData = constraint.ConstraintData as HkLimitedHingeConstraintData; constraintData.MaxFrictionTorque = MyPerGameSettings.Destruction ? MyDestructionHelper.MassToHavok(0.5f) : 3f; } } if (MyFakes.ENABLE_RAGDOLL_DEBUG) { Debug.WriteLine("MyPhysicsBody.SetRagdollDefaults FINISHED"); MyLog.Default.WriteLine("MyPhysicsBody.SetRagdollDefaults FINISHED"); } }
/// <summary> /// Returns true when block is destroyed /// </summary> public void DoDamage(float damage, MyDamageType damageType, bool addDirtyParts = true, MyDestructionHelper.HitInfo? hitInfo = null) { if (!MySession.Static.DestructibleBlocks) return; damage *= DamageRatio; // Low-integrity blocks get more damage ProfilerShort.Begin("FatBlock.DoDamage"); try { if (FatBlock != null && CubeGrid.Physics != null && CubeGrid.Physics.Enabled) //Fatblock dont have physics { var destroyable = FatBlock as IMyDestroyableObject; if (destroyable != null) destroyable.DoDamage(damage, damageType, false); } } finally { ProfilerShort.End(); } MySession.Static.NegativeIntegrityTotal += damage; AccumulatedDamage += damage; if (m_componentStack.Integrity - AccumulatedDamage <= MyComponentStack.MOUNT_THRESHOLD) { if (MyPerGameSettings.Destruction && hitInfo.HasValue) { AccumulatedDamage = 0; var gridPhysics = CubeGrid.Physics; float maxDestructionRadius = CubeGrid.GridSizeEnum == MyCubeSize.Small ? 0.5f : 3; Sandbox.Engine.Physics.MyDestructionHelper.TriggerDestruction(damage, gridPhysics, hitInfo.Value.Position, hitInfo.Value.Normal, maxDestructionRadius); } else { ApplyAccumulatedDamage(addDirtyParts); } CubeGrid.RemoveFromDamageApplication(this); } else if (MyFakes.SHOW_DAMAGE_EFFECTS && FatBlock != null && BlockDefinition.RationEnoughForDamageEffect((Integrity-damage) / MaxIntegrity)) FatBlock.SetDamageEffect(true); return; }