private bool GridInside(MyCubeGrid grid, MyOrientedBoundingBoxD bOriBBoxD)
 {
     if (grid != null && CustomCollision.PointInShield(grid.PositionComp.WorldVolume.Center, DetectMatrixOutsideInv))
     {
         if (CustomCollision.ObbCornersInShield(bOriBBoxD, DetectMatrixOutsideInv, _obbCorners))
         {
             var sMass      = ((MyCubeGrid)Shield.CubeGrid).GetCurrentMass();
             var bPhysics   = ((IMyCubeGrid)grid).Physics;
             var sPhysics   = Shield.CubeGrid.Physics;
             var sLSpeed    = sPhysics.LinearVelocity;
             var sASpeed    = sPhysics.AngularVelocity * 50;
             var sLSpeedLen = sLSpeed.LengthSquared();
             var sASpeedLen = sASpeed.LengthSquared();
             var sSpeedLen  = sLSpeedLen > sASpeedLen ? sLSpeedLen : sASpeedLen;
             var forceData  = new MyAddForceData {
                 MyGrid = grid, Force = -(grid.PositionComp.WorldAABB.Center - sPhysics.CenterOfMassWorld) * -sMass, MaxSpeed = sSpeedLen + 3
             };
             if (!bPhysics.IsStatic)
             {
                 ForceData.Enqueue(forceData);
             }
             return(true);
         }
     }
     return(false);
 }
        private void BlockIntersect(MyCubeGrid breaching, MyOrientedBoundingBoxD bOriBBoxD, EntIntersectInfo entInfo)
        {
            var collisionAvg = Vector3D.Zero;
            var transformInv = DetectMatrixOutsideInv;
            var normalMat    = MatrixD.Transpose(transformInv);
            var damageBlocks = Session.Enforced.DisableBlockDamage == 0;

            var blockDmgNum = 5;

            if (ShieldMode == ShieldType.Station && DsState.State.Enhancer)
            {
                blockDmgNum = 50;
            }
            var intersection = bOriBBoxD.Intersects(ref SOriBBoxD);

            try
            {
                if (intersection)
                {
                    var      cacheBlockList = entInfo.CacheBlockList;
                    var      bPhysics       = ((IMyCubeGrid)breaching).Physics;
                    var      sPhysics       = Shield.CubeGrid.Physics;
                    var      sGrid          = (MyCubeGrid)Shield.CubeGrid;
                    var      bMass          = breaching.GetCurrentMass();
                    var      sMass          = sGrid.GetCurrentMass();
                    var      momentum       = (bMass * bPhysics.LinearVelocity) + (sMass * sPhysics.LinearVelocity);
                    var      resultVelocity = momentum / (bMass + sMass);
                    Vector3D bBlockCenter;
                    var      stale     = false;
                    var      rawDamage = 0f;
                    var      blockSize = breaching.GridSize;
                    var      gc        = breaching.WorldToGridInteger(DetectionCenter);
                    var      rc        = ShieldSize.AbsMax() / blockSize;
                    rc *= rc;
                    rc  = rc + 1;
                    rc  = Math.Ceiling(rc);
                    var hits        = 0;
                    var blockPoints = new Vector3D[9];
                    for (int i = 0; i < cacheBlockList.Count; i++)
                    {
                        var block    = cacheBlockList[i];
                        var blockPos = block.Position;
                        var num1     = gc.X - blockPos.X;
                        var num2     = gc.Y - blockPos.Y;
                        var num3     = gc.Z - blockPos.Z;
                        var result   = (num1 * num1) + (num2 * num2) + (num3 * num3);

                        if (_isServer)
                        {
                            if (result > rc)
                            {
                                continue;
                            }
                            if (damageBlocks && block.IsDestroyed)
                            {
                                DestroyedBlocks.Enqueue(block);
                                continue;
                            }
                            if (block.CubeGrid != breaching)
                            {
                                stale = true;
                                continue;
                            }
                        }
                        else
                        {
                            if (hits > blockDmgNum)
                            {
                                break;
                            }
                            if (result > rc || block.IsDestroyed || block.CubeGrid != breaching)
                            {
                                continue;
                            }
                        }
                        BoundingBoxD blockBox;
                        block.GetWorldBoundingBox(out blockBox);

                        blockBox.GetCorners(blockPoints);
                        blockPoints[8] = blockBox.Center;
                        for (int j = 8; j > -1; j--)
                        {
                            var point = blockPoints[j];
                            if (Vector3.Transform(point, DetectMatrixOutsideInv).LengthSquared() > 1)
                            {
                                continue;
                            }
                            collisionAvg += point;
                            hits++;
                            if (!_isServer)
                            {
                                break;
                            }

                            if (!damageBlocks)
                            {
                                if (hits > blockDmgNum)
                                {
                                    break;
                                }
                            }
                            else if (CollidingBlocks.Count > blockDmgNum)
                            {
                                break;
                            }

                            rawDamage += MathHelper.Clamp(block.Integrity, 0, 350);
                            if (damageBlocks)
                            {
                                CollidingBlocks.Enqueue(block);
                            }
                            break;
                        }
                    }

                    entInfo.MarkForClose = stale;

                    if (collisionAvg != Vector3D.Zero)
                    {
                        collisionAvg /= hits;

                        if (sPhysics.IsStatic && !bPhysics.IsStatic)
                        {
                            var bLSpeed    = bPhysics.LinearVelocity;
                            var bASpeed    = bPhysics.AngularVelocity * 100;
                            var bLSpeedLen = bLSpeed.Length();
                            var bASpeedLen = bASpeed.Length();
                            bASpeedLen = MathHelper.Clamp(bASpeedLen, 0, 50);
                            var bSpeedLen   = bLSpeedLen > bASpeedLen ? bLSpeedLen : bASpeedLen;
                            var surfaceMass = (bMass > sMass) ? sMass : bMass;

                            var surfaceMulti  = (hits > 5) ? 5 : hits;
                            var localNormal   = Vector3D.Transform(collisionAvg, transformInv);
                            var surfaceNormal = Vector3D.Normalize(Vector3D.TransformNormal(localNormal, normalMat));

                            var impulseData1 = new MyImpulseData {
                                MyGrid = breaching, Direction = (resultVelocity - bLSpeed) * bMass, Position = bPhysics.CenterOfMassWorld
                            };
                            var impulseData2 = new MyImpulseData {
                                MyGrid = breaching, Direction = surfaceMulti * (surfaceMass * 0.025) * -Vector3D.Dot(bLSpeed, surfaceNormal) * surfaceNormal, Position = collisionAvg
                            };
                            var forceData = new MyAddForceData {
                                MyGrid = breaching, Force = (bPhysics.CenterOfMassWorld - collisionAvg) * (bMass * bSpeedLen), MaxSpeed = MathHelper.Clamp(bSpeedLen, 1f, bSpeedLen * 0.5f)
                            };
                            ImpulseData.Enqueue(impulseData1);
                            ImpulseData.Enqueue(impulseData2);
                            ForceData.Enqueue(forceData);
                        }
                        else
                        {
                            var bLSpeed    = bPhysics.LinearVelocity;
                            var bASpeed    = bPhysics.AngularVelocity * 100;
                            var bLSpeedLen = bLSpeed.Length();
                            var bASpeedLen = bASpeed.Length();
                            bASpeedLen = MathHelper.Clamp(bASpeedLen, 0, 50);
                            var   bSpeedLen = bLSpeedLen > bASpeedLen ? bLSpeedLen : bASpeedLen;
                            float?speed;


                            if (!bPhysics.IsStatic)
                            {
                                var bImpulseData = new MyImpulseData {
                                    MyGrid = breaching, Direction = (resultVelocity - bLSpeed) * bMass, Position = bPhysics.CenterOfMassWorld
                                };
                                ImpulseData.Enqueue(bImpulseData);
                            }

                            if (!sPhysics.IsStatic)
                            {
                                var sImpulseData = new MyImpulseData {
                                    MyGrid = sGrid, Direction = (resultVelocity - sPhysics.LinearVelocity) * sMass, Position = sPhysics.CenterOfMassWorld
                                };
                                ImpulseData.Enqueue(sImpulseData);
                            }

                            if (!sPhysics.IsStatic)
                            {
                                if (bMass / sMass > 20)
                                {
                                    speed = MathHelper.Clamp(bSpeedLen, 1f, bSpeedLen * 0.5f);
                                }
                                else
                                {
                                    speed = null;
                                }

                                var sForceData = new MyAddForceData {
                                    MyGrid = sGrid, Force = (sPhysics.CenterOfMassWorld - collisionAvg) * bMass, MaxSpeed = speed
                                };
                                ForceData.Enqueue(sForceData);
                            }

                            if (!bPhysics.IsStatic)
                            {
                                if (sMass / bMass > 20)
                                {
                                    speed = MathHelper.Clamp(bSpeedLen, 1f, bSpeedLen * 0.5f);
                                }
                                else
                                {
                                    speed = null;
                                }

                                var bForceData = new MyAddForceData {
                                    MyGrid = breaching, Force = (bPhysics.CenterOfMassWorld - collisionAvg) * sMass, MaxSpeed = speed
                                };
                                ForceData.Enqueue(bForceData);
                            }
                        }
                        WebDamage    = true;
                        bBlockCenter = collisionAvg;
                    }
                    else
                    {
                        return;
                    }
                    if (!_isServer)
                    {
                        return;
                    }

                    var damage = rawDamage * DsState.State.ModulateEnergy;

                    entInfo.Damage = damage;
                    if (_mpActive)
                    {
                        if (_isServer && bBlockCenter != Vector3D.NegativeInfinity)
                        {
                            AddShieldHit(breaching.EntityId, damage, Session.Instance.MPKinetic, null, false, collisionAvg);
                        }
                    }
                    else
                    {
                        if (bBlockCenter != Vector3D.NegativeInfinity)
                        {
                            entInfo.ContactPoint = bBlockCenter;
                            ImpactSize           = entInfo.Damage;

                            entInfo.Damage      = 0;
                            entInfo.EmpSize     = 0;
                            WorldImpactPosition = bBlockCenter;
                        }
                    }
                    Absorb += damage;
                }
            }
            catch (Exception ex) { Log.Line($"Exception in BlockIntersect: {ex}"); }
        }
        private void ShieldIntersect(MyEntity ent)
        {
            var grid = ent as MyCubeGrid;

            if (grid == null)
            {
                return;
            }

            if (GridInside(grid, MyOrientedBoundingBoxD.CreateFromBoundingBox(grid.PositionComp.WorldAABB)))
            {
                return;
            }
            ShieldGridComponent shieldComponent;

            grid.Components.TryGet(out shieldComponent);
            if (shieldComponent?.DefenseShields == null)
            {
                return;
            }

            var ds = shieldComponent.DefenseShields;

            if (!ds.WasOnline)
            {
                EntIntersectInfo entInfo;
                WebEnts.TryRemove(ent, out entInfo);
            }
            var dsVerts     = ds.ShieldComp.PhysicsOutside;
            var dsMatrixInv = ds.DetectMatrixOutsideInv;
            var myGrid      = Shield.CubeGrid;

            var insidePoints = new List <Vector3D>();

            if (_isServer)
            {
                CustomCollision.ShieldX2PointsInside(dsVerts, dsMatrixInv, ShieldComp.PhysicsOutside, DetectMatrixOutsideInv, insidePoints);
            }
            else
            {
                CustomCollision.ClientShieldX2PointsInside(dsVerts, dsMatrixInv, ShieldComp.PhysicsOutsideLow, DetectMatrixOutsideInv, insidePoints);
            }

            var bPhysics = ((IMyCubeGrid)grid).Physics;
            var sPhysics = myGrid.Physics;

            var bMass = grid.GetCurrentMass();
            var sMass = ((MyCubeGrid)myGrid).GetCurrentMass();

            if (bMass <= 0)
            {
                bMass = int.MaxValue;
            }
            if (sMass <= 0)
            {
                sMass = int.MaxValue;
            }

            var bVel           = bPhysics.LinearVelocity;
            var bVelLen        = bVel.Length();
            var momentum       = (bMass * bVel) + (sMass * sPhysics.LinearVelocity);
            var resultVelocity = momentum / (bMass + sMass);

            var collisionAvg      = Vector3D.Zero;
            var numOfPointsInside = insidePoints.Count;

            for (int i = 0; i < numOfPointsInside; i++)
            {
                collisionAvg += insidePoints[i];
            }

            collisionAvg /= numOfPointsInside;

            if (numOfPointsInside > 0 && !bPhysics.IsStatic)
            {
                var ejectorAccel = numOfPointsInside > 10 ? numOfPointsInside : 10;
                var impulseData  = new MyImpulseData {
                    MyGrid = grid, Direction = (resultVelocity - bVel) * bMass, Position = bPhysics.CenterOfMassWorld
                };
                var forceData = new MyAddForceData {
                    MyGrid = grid, Force = (bPhysics.CenterOfMassWorld - collisionAvg) * bMass * ejectorAccel, MaxSpeed = MathHelper.Clamp(bVelLen, 1f, 50f)
                };
                ImpulseData.Enqueue(impulseData);
                ForceData.Enqueue(forceData);
            }
            if (!_isServer || numOfPointsInside <= 0)
            {
                return;
            }

            var shieldMaxChargeRate = ds._shieldMaxChargeRate;
            var damage = ((shieldMaxChargeRate * ConvToHp) * DsState.State.ModulateKinetic) * 0.01666666666f;

            if (_mpActive)
            {
                if (_isServer)
                {
                    AddShieldHit(ds.Shield.EntityId, damage, Session.Instance.MPEnergy, null, false, collisionAvg);
                }
            }
            else
            {
                EnergyHit           = true;
                WorldImpactPosition = collisionAvg;

                ds.EnergyHit           = true;
                ds.WorldImpactPosition = collisionAvg;

                Absorb    += damage;
                ImpactSize = damage;
                WebDamage  = true;
            }
        }