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();
        }
        public override void FracturedBody_AfterReplaceBody(ref HkdReplaceBodyEvent e)
        {
            if (!MyFakes.ENABLE_AFTER_REPLACE_BODY)
                return;

            System.Diagnostics.Debug.Assert(Sync.IsServer, "Client must not simulate destructions");

            if (!Sync.IsServer)
                return;
            Debug.Assert(!m_recreateBody, "Only one destruction per entity per frame");
            if (m_recreateBody)
                return;
            ProfilerShort.Begin("DestructionFracture.AfterReplaceBody");
            HavokWorld.DestructionWorld.RemoveBreakableBody(e.OldBody); // To remove from HkpWorld rigidBodies list
            m_oldLinVel = RigidBody.LinearVelocity;
            m_oldAngVel = RigidBody.AngularVelocity;
            MyPhysics.RemoveDestructions(RigidBody);
            e.GetNewBodies(m_newBodies);
            if (m_newBodies.Count == 0)// || e.OldBody != DestructionBody) 
            {
                ProfilerShort.End();
                return;
            }
            bool createdEffect = false;
            m_tmpBlocksToDelete.Clear();
            m_tmpBlocksUpdateDamage.Clear();
            MySlimBlock destructionSoundBlock = null;
            ProfilerShort.Begin("ProcessBodies");
            foreach (var b in m_newBodies)
            {
                if (!b.IsFracture() || (MyFakes.ENABLE_FRACTURE_COMPONENT && m_grid.BlocksCount == 1 && m_grid.IsStatic && MyDestructionHelper.IsFixed(b)))
                {
                    m_newBreakableBodies.Add(MyFracturedPiecesManager.Static.GetBreakableBody(b));
                    ProfilerShort.Begin("FindFracturedBlocks");
                    FindFracturedBlocks(b);
                    ProfilerShort.BeginNextBlock("RemoveBBfromWorld");
                    HavokWorld.DestructionWorld.RemoveBreakableBody(b);
                    ProfilerShort.End();
                }
                else
                {
                    ProfilerShort.Begin("CreateFracture");
                    var bBody = MyFracturedPiecesManager.Static.GetBreakableBody(b);
                    var bodyMatrix = bBody.GetRigidBody().GetRigidBodyMatrix();
                    var pos = ClusterToWorld(bodyMatrix.Translation);

                    MySlimBlock cb;
                    var shape = bBody.BreakableShape;
                    ProfilerShort.Begin("Properties");
                    HkVec3IProperty prop = shape.GetProperty(HkdBreakableShape.PROPERTY_GRID_POSITION);
                    if (!prop.IsValid() && shape.IsCompound())  //TODO: this is last block in grid and is fractured
                    {                                           //its compound of childs of our block shape that has position prop, 
                        prop = shape.GetChild(0).Shape.GetProperty(HkdBreakableShape.PROPERTY_GRID_POSITION);
                    }

                    ProfilerShort.End();
                    Debug.Assert(prop.IsValid());
                    bool removePiece = false;
                    cb = m_grid.GetCubeBlock(prop.Value);
                    MyCompoundCubeBlock compoundBlock = cb != null ? cb.FatBlock as MyCompoundCubeBlock : null;

                    if (cb != null)
                    {
                        if (destructionSoundBlock == null)
                            destructionSoundBlock = cb;

                        if (!createdEffect)
                        {
                            ProfilerShort.Begin("CreateParticle");
                            AddDestructionEffect(m_grid.GridIntegerToWorld(cb.Position), Vector3.Down);
                            createdEffect = true;
                            ProfilerShort.End();
                        }

                        MatrixD m = bodyMatrix;
                        m.Translation = pos;
                        MyFracturedPiece fp = null;

                        if (MyFakes.ENABLE_FRACTURE_COMPONENT) 
                        {
                            // Get compound ids
                            Debug.Assert(m_tmpCompoundIds.Count == 0);
                            HkSimpleValueProperty compoundIdProperty = shape.GetProperty(HkdBreakableShape.PROPERTY_BLOCK_COMPOUND_ID);
                            if (compoundIdProperty.IsValid())
                            {
                                m_tmpCompoundIds.Add((ushort)compoundIdProperty.ValueUInt);
                            }
                            else if (!compoundIdProperty.IsValid() && shape.IsCompound())
                            {
                                m_tmpChildren_CompoundIds.Clear();
                                shape.GetChildren(m_tmpChildren_CompoundIds);
                                foreach (var child in m_tmpChildren_CompoundIds)
                                {
                                    HkSimpleValueProperty compoundIdChildProperty = child.Shape.GetProperty(HkdBreakableShape.PROPERTY_BLOCK_COMPOUND_ID);
                                    if (compoundIdChildProperty.IsValid())
                                        m_tmpCompoundIds.Add((ushort)compoundIdChildProperty.ValueUInt);
                                }
                            }

                            // Remove shapes
                            bool fracturePieceValid = true;
                            if (m_tmpCompoundIds.Count > 0) 
                            {
                                Debug.Assert(m_tmpDefinitions.Count == 0);
                                Debug.Assert(compoundBlock != null);
                                foreach (var compoundId in m_tmpCompoundIds)
                                {
                                    var blockInCompound = compoundBlock.GetBlock(compoundId);
                                    if (blockInCompound == null) 
                                    {
                                        fracturePieceValid = false;
                                        continue;
                                    }

                                    m_tmpDefinitions.Add(blockInCompound.BlockDefinition.Id);
                                    fracturePieceValid &= RemoveShapesFromFracturedBlocks(bBody, blockInCompound, compoundId, m_tmpBlocksToDelete, m_tmpBlocksUpdateDamage);
                                }
                            }
                            else 
                            {
                                Debug.Assert(compoundBlock == null);
                                m_tmpDefinitions.Add(cb.BlockDefinition.Id);
                                fracturePieceValid = RemoveShapesFromFracturedBlocks(bBody, cb, null, m_tmpBlocksToDelete, m_tmpBlocksUpdateDamage);
                            }

                            // Test invalid shapes (from block which has been removed from grid).
                            Debug.Assert(fracturePieceValid);
                            if (fracturePieceValid)
                            {
                                fp = MyDestructionHelper.CreateFracturePiece(bBody, ref m, m_tmpDefinitions, compoundBlock != null ? compoundBlock : cb.FatBlock);
                                if (fp == null)
                                    removePiece = true;
                            }
                            else
                            {
                                removePiece = true;
                            }

                            m_tmpChildren_CompoundIds.Clear();
                            m_tmpCompoundIds.Clear();
                            m_tmpDefinitions.Clear();
                        }
                        else
                        {
                            fp = MyDestructionHelper.CreateFracturePiece(bBody, ref m, null, compoundBlock != null ? compoundBlock : cb.FatBlock);
                            if (fp == null)
                                removePiece = true;
                        }
                    }
                    else
                    {
                        //Debug.Fail("Fracture piece missing block!");//safe to ignore
                        removePiece = true;
                    }

                    if (removePiece)
                    {
                        HavokWorld.DestructionWorld.RemoveBreakableBody(b);
                        MyFracturedPiecesManager.Static.ReturnToPool(bBody);
                    }
                    ProfilerShort.End();
                }
            }
            m_newBodies.Clear();
            bool oldGeneratorsEnabled = m_grid.EnableGenerators(false);

            if (destructionSoundBlock != null)
                MyAudioComponent.PlayDestructionSound(destructionSoundBlock);

            if (MyFakes.ENABLE_FRACTURE_COMPONENT)
            {
                // Cache blocks with fracture components
                FindFractureComponentBlocks();

                // Remove blocks from blocksToDelete which are marked for creating fracture component.
                foreach (var info in m_fractureBlockComponentsCache)
                    m_tmpBlocksToDelete.Remove(((MyCubeBlock)info.Entity).SlimBlock);

                // Remove blocks from update collection when the block is also in delete colection.
                foreach (var blockToDelete in m_tmpBlocksToDelete)
                    m_tmpBlocksUpdateDamage.Remove(blockToDelete);

                // Delete blocks
                foreach (var cb in m_tmpBlocksToDelete)
                {
                    // Update deleted blocks destruction damage for multiblocks
                    if (cb.IsMultiBlockPart)
                    {
                        var multiBlockInfo = cb.CubeGrid.GetMultiBlockInfo(cb.MultiBlockId);
                        // Only apply damage if there is some other block in multiblock.
                        if (multiBlockInfo != null && multiBlockInfo.Blocks.Count > 1)
                        {
                            var fractureComponent = cb.GetFractureComponent();
                            if (fractureComponent != null)
                                cb.ApplyDestructionDamage(0f);
                        }
                    }

                    if (cb.FatBlock != null)
                        cb.FatBlock.OnDestroy();

                    m_grid.RemoveBlockWithId(cb, true);
                }

                // Update blocks destruction damage
                foreach (var cb in m_tmpBlocksUpdateDamage)
                {
                    var fractureComponent = cb.GetFractureComponent();
                    if (fractureComponent != null)
                        cb.ApplyDestructionDamage(fractureComponent.GetIntegrityRatioFromFracturedPieceCounts());
                }
            }
            else
            {
                foreach (var cb in m_tmpBlocksToDelete)
                {
                    var b = m_grid.GetCubeBlock(cb.Position);
                    if (b != null)
                    {
                        if (b.FatBlock != null)
                            b.FatBlock.OnDestroy();
                        m_grid.RemoveBlock(b, true);
                    }
                }
            }

            m_grid.EnableGenerators(oldGeneratorsEnabled);

            m_tmpBlocksToDelete.Clear();
            m_tmpBlocksUpdateDamage.Clear();

            ProfilerShort.End();
            //SplitGrid(e);
            m_recreateBody = true;
            ProfilerShort.End();
        }
        void DestructionBody_AfterReplaceBody(ref HkdReplaceBodyEvent e)
        {
            e.GetNewBodies(m_tmpBodyInfos);
            foreach (var b in m_tmpBodyInfos)
            {
                var m = b.Body.GetRigidBody().GetRigidBodyMatrix();
                var t = m.Translation;
                var o = Quaternion.CreateFromRotationMatrix(m.GetOrientation());
                Physics.HavokWorld.GetPenetrationsShape(b.Body.BreakableShape.GetShape(), ref t, ref o, m_tmpResults, MyPhysics.DefaultCollisionLayer);
                foreach (var res in m_tmpResults)
                {
                    if (res.GetCollisionEntity() is MyVoxelMap)
                    {
                        b.Body.GetRigidBody().Quality = HkCollidableQualityType.Fixed;
                        break;
                    }
                }

                m_tmpResults.Clear();
                b.Body.GetRigidBody();
                b.Body.Dispose();
            }
        }
        public override void FracturedBody_AfterReplaceBody(ref HkdReplaceBodyEvent e)
        {
            if (!MyFakes.ENABLE_AFTER_REPLACE_BODY)
                return;

            System.Diagnostics.Debug.Assert(Sync.IsServer, "Client must not simulate destructions");

            if (!Sync.IsServer)
                return;
            Debug.Assert(!m_recreateBody, "Only one destruction per entity per frame");
            if (m_recreateBody)
                return;
            ProfilerShort.Begin("DestructionFracture.AfterReplaceBody");
            HavokWorld.DestructionWorld.RemoveBreakableBody(e.OldBody); // To remove from HkpWorld rigidBodies list
            m_oldLinVel = RigidBody.LinearVelocity;
            m_oldAngVel = RigidBody.AngularVelocity;
            MyPhysics.RemoveDestructions(RigidBody);
            e.GetNewBodies(m_newBodies);
            if (m_newBodies.Count == 0)// || e.OldBody != DestructionBody)
                return;
            bool createdEffect = false;
            var lst = new List<MySlimBlock>();
            ProfilerShort.Begin("ProcessBodies");
            foreach (var b in m_newBodies)
            {
                if (!b.IsFracture())// && m_grid.BlocksCount > 1)// || !IsFracture(b.Body.BreakableShape))
                {
                    m_newBreakableBodies.Add(MyFracturedPiecesManager.Static.GetBreakableBody(b));
                    ProfilerShort.Begin("FindFracturedBlocks");
                    FindFracturedBlocks(b);
                    ProfilerShort.BeginNextBlock("RemoveBBfromWorld");
                    HavokWorld.DestructionWorld.RemoveBreakableBody(b);
                    ProfilerShort.End();
                }
                else
                {
                    ProfilerShort.Begin("CreateFracture");
                    var bBody = MyFracturedPiecesManager.Static.GetBreakableBody(b);
                    var bodyMatrix = bBody.GetRigidBody().GetRigidBodyMatrix();
                    var pos = ClusterToWorld(bodyMatrix.Translation);
                     
                    MySlimBlock cb;
                    var shape = bBody.BreakableShape;
                    ProfilerShort.Begin("GetPositionProp");
                    HkVec3IProperty prop = shape.GetProperty(HkdBreakableShape.PROPERTY_GRID_POSITION);
                    if (!prop.IsValid() && shape.IsCompound())  //TODO: this is last block in grid and is fractured
                    {                                           //its compound of childs of our block shape that has position prop, 
                        prop = shape.GetChild(0).Shape.GetProperty(HkdBreakableShape.PROPERTY_GRID_POSITION);
                    }
                    ProfilerShort.End();
                    Debug.Assert(prop.IsValid());
                    bool removePiece = false;
                    cb = m_grid.GetCubeBlock(prop.Value);
                    if (cb != null)
                    {
                        if (!createdEffect)
                        {
                            ProfilerShort.Begin("CreateParticle");
                            AddDestructionEffect(m_grid.GridIntegerToWorld(cb.Position), Vector3.Down);
                            createdEffect = true;
                            ProfilerShort.End();
                        }
                        if (!lst.Contains(cb))
                        {
                            lst.Add(cb);
                        }
                        MatrixD m = bodyMatrix;
                        m.Translation = pos;
                        MyFracturedPiece fp = null;
                        fp = MyDestructionHelper.CreateFracturePiece(bBody, ref m, null, cb.FatBlock);
                        if (fp == null)
                        {
                            removePiece = true;
                        }
                    }
                    else
                    {
                        //Debug.Fail("Fracture piece missing block!");//safe to ignore
                        removePiece = true;
                    }
                    if (removePiece)
                    {
                        HavokWorld.DestructionWorld.RemoveBreakableBody(b);
                        MyFracturedPiecesManager.Static.ReturnToPool(bBody);
                    }
                    ProfilerShort.End();
                }
            }
            m_newBodies.Clear();
            m_grid.EnableGenerators(false);
            bool first = true;
            foreach (var cb in lst)
            {
                var b = m_grid.GetCubeBlock(cb.Position);
                if ( b!= null)
                {
                    if(b.FatBlock != null)
                        b.FatBlock.OnDestroy();
                    m_grid.RemoveBlock(b, true);
                    if(first)
                    {
                        PlayDestructionSound(b);
                        first = false;
                    }
                }
            }
            m_grid.EnableGenerators(true);
            ProfilerShort.End();
            //SplitGrid(e);
            m_recreateBody = true;
            ProfilerShort.End();
        }
        public override void FracturedBody_AfterReplaceBody(ref HkdReplaceBodyEvent e)
        {
            if (!MyFakes.ENABLE_AFTER_REPLACE_BODY)
                return;

            System.Diagnostics.Debug.Assert(Sync.IsServer, "Client must not simulate destructions");

            if (!Sync.IsServer)
                return;
            Debug.Assert(!m_recreateBody, "Only one destruction per entity per frame");
            if (m_recreateBody)
                return;
            ProfilerShort.Begin("DestructionFracture.AfterReplaceBody");
            HavokWorld.DestructionWorld.RemoveBreakableBody(e.OldBody); // To remove from HkpWorld rigidBodies list
            m_oldLinVel = RigidBody.LinearVelocity;
            m_oldAngVel = RigidBody.AngularVelocity;
            MyPhysics.RemoveDestructions(RigidBody);
            e.GetNewBodies(m_newBodies);
            if (m_newBodies.Count == 0)// || e.OldBody != DestructionBody)
                return;
            bool createdEffect = false;
            var blocksToDelete = new HashSet<MySlimBlock>();
            MySlimBlock destructionSoundBlock = null;
            ProfilerShort.Begin("ProcessBodies");
            foreach (var b in m_newBodies)
            {
                if (!b.IsFracture())// && m_grid.BlocksCount > 1)// || !IsFracture(b.Body.BreakableShape))
                {
                    m_newBreakableBodies.Add(MyFracturedPiecesManager.Static.GetBreakableBody(b));
                    ProfilerShort.Begin("FindFracturedBlocks");
                    FindFracturedBlocks(b);
                    ProfilerShort.BeginNextBlock("RemoveBBfromWorld");
                    HavokWorld.DestructionWorld.RemoveBreakableBody(b);
                    ProfilerShort.End();
                }
                else
                {
                    ProfilerShort.Begin("CreateFracture");
                    var bBody = MyFracturedPiecesManager.Static.GetBreakableBody(b);
                    var bodyMatrix = bBody.GetRigidBody().GetRigidBodyMatrix();
                    var pos = ClusterToWorld(bodyMatrix.Translation);

                    MySlimBlock cb;
                    var shape = bBody.BreakableShape;
                    ProfilerShort.Begin("Properties");
                    HkVec3IProperty prop = shape.GetProperty(HkdBreakableShape.PROPERTY_GRID_POSITION);
                    if (!prop.IsValid() && shape.IsCompound())  //TODO: this is last block in grid and is fractured
                    {                                           //its compound of childs of our block shape that has position prop, 
                        prop = shape.GetChild(0).Shape.GetProperty(HkdBreakableShape.PROPERTY_GRID_POSITION);
                    }

                    // Block id in compound.
                    ushort? compoundId = null;
                    if (MyFakes.ENABLE_FRACTURE_COMPONENT)
                    {
                        HkSimpleValueProperty compoundIdProperty = shape.GetProperty(HkdBreakableShape.PROPERTY_BLOCK_COMPOUND_ID);
                        if (!compoundIdProperty.IsValid() && shape.IsCompound())
                            compoundIdProperty = shape.GetChild(0).Shape.GetProperty(HkdBreakableShape.PROPERTY_BLOCK_COMPOUND_ID);

                        if (compoundIdProperty.IsValid())
                            compoundId = (ushort)compoundIdProperty.ValueUInt;
                    }

                    ProfilerShort.End();
                    Debug.Assert(prop.IsValid());
                    bool removePiece = false;
                    cb = m_grid.GetCubeBlock(prop.Value);

                    if (MyFakes.ENABLE_FRACTURE_COMPONENT && cb != null)
                    {
                        // Prepare block from compound
                        MyCompoundCubeBlock compoundBlock = cb.FatBlock as MyCompoundCubeBlock;
                        if (compoundBlock != null)
                        {
                            if (compoundId != null)
                            {
                                var blockInCompound = compoundBlock.GetBlock(compoundId.Value);
                                if (blockInCompound != null)
                                {
                                    cb = blockInCompound;
                                }
                                else
                                {
                                    Debug.Fail("Block with the BlockId not found in compound");
                                    cb = null;
                                }
                            }
                            else
                            {
                                Debug.Fail("CompoundId not set to internal block in compound");
                                cb = null;
                            }
                        }
                        else
                        {
                            Debug.Assert(compoundId == null, "CompoundId set to block which is not in compound");
                        }
                    }

                    if (cb != null)
                    {
                        if (destructionSoundBlock == null)
                            destructionSoundBlock = cb;

                        if (!createdEffect)
                        {
                            ProfilerShort.Begin("CreateParticle");
                            AddDestructionEffect(m_grid.GridIntegerToWorld(cb.Position), Vector3.Down);
                            createdEffect = true;
                            ProfilerShort.End();
                        }

                        MatrixD m = bodyMatrix;
                        m.Translation = pos;
                        MyFracturedPiece fp = null;
                        fp = MyDestructionHelper.CreateFracturePiece(bBody, ref m, null, cb.FatBlock);
                        if (fp == null)
                        {
                            removePiece = true;
                        }

                        if (MyFakes.ENABLE_FRACTURE_COMPONENT && cb.FatBlock.Components.Has<MyFractureComponentBase>())
                        {
                            // Block can be removed when the removed shape is the last one!
                            MyFractureComponentCubeBlock fractureComponent = cb.GetFractureComponent();
                            if (fractureComponent != null)
                            {
                                var bShape = bBody.BreakableShape;
                                if (IsBreakableShapeCompound(bShape))
                                {
                                    m_tmpShapeNames.Clear();
                                    m_tmpChildren_RemoveShapes.Clear();

                                    bShape.GetChildren(m_tmpChildren_RemoveShapes);
                                    m_tmpChildren_RemoveShapes.ForEach(c => m_tmpShapeNames.Add(c.ShapeName));

                                    // Remove on server.
                                    fractureComponent.RemoveChildShapes(m_tmpShapeNames);

                                    MySyncDestructions.RemoveShapesFromFractureComponent(cb.CubeGrid.EntityId, cb.Position, compoundId ?? 0xFFFF, m_tmpShapeNames);

                                    m_tmpChildren_RemoveShapes.Clear();
                                    m_tmpShapeNames.Clear();
                                }
                                else
                                {
                                    var name = bBody.BreakableShape.Name;

                                    // Remove on server.
                                    fractureComponent.RemoveChildShapes(new string[] { name });

                                    MySyncDestructions.RemoveShapeFromFractureComponent(cb.CubeGrid.EntityId, cb.Position, compoundId ?? 0xFFFF, name);
                                }
                            }
                        }
                        else
                        {
                            blocksToDelete.Add(cb);
                        }
                    }
                    else
                    {
                        //Debug.Fail("Fracture piece missing block!");//safe to ignore
                        removePiece = true;
                    }

                    if (removePiece)
                    {
                        HavokWorld.DestructionWorld.RemoveBreakableBody(b);
                        MyFracturedPiecesManager.Static.ReturnToPool(bBody);
                    }
                    ProfilerShort.End();
                }
            }
            m_newBodies.Clear();
            bool oldGeneratorsEnabled = m_grid.EnableGenerators(false);

            if (destructionSoundBlock != null)
                MyAudioComponent.PlayDestructionSound(destructionSoundBlock);

            if (MyFakes.ENABLE_FRACTURE_COMPONENT)
            {
                // Remove blocks from blocksToDelete which are marked for creating fracture component.
                m_fractureBlockComponentsCache.ForEach(info => blocksToDelete.Remove(((MyCubeBlock)info.Entity).SlimBlock));

                foreach (var cb in blocksToDelete)
                {
                    if (cb.FatBlock != null)
                        cb.FatBlock.OnDestroy();

                    m_grid.RemoveBlockWithId(cb, true);
                }
            }
            else
            {
                foreach (var cb in blocksToDelete)
                {
                    var b = m_grid.GetCubeBlock(cb.Position);
                    if (b != null)
                    {
                        if (b.FatBlock != null)
                            b.FatBlock.OnDestroy();
                        m_grid.RemoveBlock(b, true);
                    }
                }
            }

            m_grid.EnableGenerators(oldGeneratorsEnabled);
            ProfilerShort.End();
            //SplitGrid(e);
            m_recreateBody = true;
            ProfilerShort.End();
        }