Beispiel #1
0
            public override void CreatePhysicsShape(out HkShape shape, out HkMassProperties massProperties, float mass)
            {
                HkSphereShape shape2 = new HkSphereShape((0.5f * ((MyEntity)base.Entity).Render.GetModel().BoundingSphere.Radius) * base.Entity.PositionComp.Scale.Value);

                shape          = (HkShape)shape2;
                massProperties = HkInertiaTensorComputer.ComputeSphereVolumeMassProperties(shape2.Radius * 0.5f, mass);
            }
Beispiel #2
0
        static MyEntityPhysicsStateGroup SphereCast(MyEntity entity, float radius, float distance)
        {
            if (DEBUG_DRAW)
            {
                VRageRender.MyRenderProxy.DebugDrawCapsule(entity.WorldMatrix.Translation, entity.PositionComp.GetPosition() + entity.WorldMatrix.Down * distance, radius, Color.Red, false, false);
            }

            // Sphere cast under character
            Vector3D      target    = entity.PositionComp.GetPosition() + entity.WorldMatrix.Down * distance;
            HkSphereShape shape     = new HkSphereShape(radius);
            MatrixD       transform = entity.WorldMatrix;
            var           dist      = MyPhysics.CastShapeReturnContactBodyData(target, shape, ref transform, MyPhysics.CollisionLayers.CollisionLayerWithoutCharacter, 0);

            if (dist.HasValue)
            {
                var hitEntity = dist.Value.HkHitInfo.GetHitEntity();
                if (!IsValid(hitEntity, false))
                {
                    return(null);
                }

                return(FindPhysics(hitEntity));
            }
            return(null);
        }
Beispiel #3
0
 public override void CreatePhysicsShape(out HkShape shape, ref HkMassProperties massProperties)
 {
     var sphereShape = new HkSphereShape(((MyEntity)Entity).Render.GetModel().BoundingSphere.Radius * Entity.PositionComp.Scale.Value);
     shape = sphereShape;
     var mass = SphereMass(sphereShape.Radius, VoxelDensity);
     massProperties = HkInertiaTensorComputer.ComputeSphereVolumeMassProperties(sphereShape.Radius, mass);
 }
        public void GetFracturesInSphere(ref BoundingSphereD searchSphere, ref List <MyFracturedPiece> output)
        {
            var activeFractures = m_piecesTimesOfDeath.Keys;

            HkShape shape = new HkSphereShape((float)searchSphere.Radius);

            try
            {
                MyPhysics.GetPenetrationsShape(shape, ref searchSphere.Center, ref Quaternion.Identity, m_rigidList, MyPhysics.CollisionLayers.NotCollideWithStaticLayer);

                foreach (var rigidBody in m_rigidList)
                {
                    var fracture = rigidBody.GetCollisionEntity() as MyFracturedPiece;
                    if (fracture != null)
                    {
                        output.Add(fracture);
                    }
                }
            }
            finally
            {
                m_rigidList.Clear();
                shape.RemoveReference();
            }
        }
Beispiel #5
0
        public static HkShape CreateCharacterShape(float height, float width, float headHeight, float headSize, float headForwardOffset, float downOffset = 0, bool capsuleForHead = false)
        {
            HkCapsuleShape capsule = new HkCapsuleShape(Vector3.Up * (height - downOffset) / 2.0f, Vector3.Down * (height) / 2.0f, width / 2.0f);

            if (headSize > 0)
            {
                HkConvexShape headShape;

                if (capsuleForHead)
                {
                    headShape = new HkCapsuleShape(new Vector3(0, 0, -0.3f), new Vector3(0, 0, 0.3f), headSize);
                }
                else
                {
                    headShape = new HkSphereShape(headSize);
                }
                //headShape = new HkCapsuleShape(new Vector3(0, 0, -0.05f), new Vector3(0, 0, 0.05f), headSize);

                HkShape[] shapes = new HkShape[]
                {
                    capsule,
                    new HkConvexTranslateShape(headShape, Vector3.Up * (headHeight - downOffset) / 2.0f + Vector3.Forward * headForwardOffset, HkReferencePolicy.TakeOwnership),
                };

                return(new HkListShape(shapes, shapes.Length, HkReferencePolicy.TakeOwnership));
            }
            else
            {
                return(capsule);
            }
        }
        private void RefreshPhysicsBody()
        {
            if (CubeGrid.CreatePhysics)
            {
                if (Physics != null)
                {
                    Physics.Close();
                }

                var detectorShape  = new HkSphereShape(CubeGrid.GridSize * 0.5f);
                var massProperties = HkInertiaTensorComputer.ComputeSphereVolumeMassProperties(detectorShape.Radius, VirtualMass != 0 ? VirtualMass : 0.01f);
                Physics           = new Engine.Physics.MyPhysicsBody(this, RigidBodyFlag.RBF_KEYFRAMED_REPORTING);
                Physics.IsPhantom = false;
                Physics.CreateFromCollisionObject(detectorShape, Vector3.Zero, WorldMatrix, massProperties, MyPhysics.CollisionLayers.VirtualMassLayer);
                UpdateIsWorking();
                Physics.Enabled = IsWorking && CubeGrid.Physics != null && CubeGrid.Physics.Enabled;

                Physics.RigidBody.Activate();
                detectorShape.Base.RemoveReference();

                if (CubeGrid != null && CubeGrid.Physics != null && !CubeGrid.IsStatic)
                {
                    CubeGrid.Physics.UpdateMass();
                }
            }
        }
Beispiel #7
0
            public override void CreatePhysicsShape(out HkShape shape, ref HkMassProperties massProperties)
            {
                var sphereShape = new HkSphereShape(((MyEntity)Entity).Render.GetModel().BoundingSphere.Radius *Entity.PositionComp.Scale.Value);

                shape          = sphereShape;
                massProperties = HkInertiaTensorComputer.ComputeSphereVolumeMassProperties(sphereShape.Radius, 1);
            }
Beispiel #8
0
        protected override bool CanPlaceRotor(MyMotorRotor rotorBlock, long builtBy)
        {
            BoundingSphereD sphere = rotorBlock.Model.BoundingSphere;

            sphere.Center = Vector3D.Transform(sphere.Center, rotorBlock.WorldMatrix);
            CubeGrid.GetBlocksInsideSphere(ref sphere, m_tmpSet);
            HkSphereShape spShape  = new HkSphereShape((float)sphere.Radius);
            Quaternion    q        = Quaternion.Identity;//Quaternion.CreateFromForwardUp(rotorBlock.WorldMatrix.Forward, rotorBlock.WorldMatrix.Up);
            var           position = rotorBlock.WorldMatrix.Translation;

            MyPhysics.GetPenetrationsShape(spShape, ref position, ref q, m_tmpList, MyPhysics.CharacterNetworkCollisionLayer);
            if (m_tmpSet.Count > 1 || m_tmpList.Count > 0)
            {
                m_tmpList.Clear();
                m_tmpSet.Clear();
                if (builtBy == MySession.LocalPlayerId)
                {
                    MyHud.Notifications.Add(MyNotificationSingletons.WheelNotPlaced);
                }
                return(false);
            }
            m_tmpList.Clear();
            m_tmpSet.Clear();

            return(true);
        }
        private void LoadDummies()
        {
            var finalModel = Engine.Models.MyModels.GetModelOnlyDummies(BlockDefinition.Model);

            foreach (var dummy in finalModel.Dummies)
            {
                if (dummy.Key.ToLower().Contains("detector_shiptool"))
                {
                    var   matrix = dummy.Value.Matrix;
                    float radius = matrix.Scale.AbsMin();

                    Matrix  blockMatrix          = this.PositionComp.LocalMatrix;
                    Vector3 gridDetectorPosition = Vector3.Transform(matrix.Translation, blockMatrix);

                    m_detectorSphere = new BoundingSphere(gridDetectorPosition, radius);

                    var phantom       = new HkPhantomCallbackShape(phantom_Enter, phantom_Leave);
                    var sphereShape   = new HkSphereShape(radius);
                    var detectorShape = new HkBvShape(sphereShape, phantom, HkReferencePolicy.TakeOwnership);

                    Physics           = new Engine.Physics.MyPhysicsBody(this, RigidBodyFlag.RBF_DEFAULT);
                    Physics.IsPhantom = true;
                    Physics.CreateFromCollisionObject(detectorShape, matrix.Translation, WorldMatrix, null, MyPhysics.ObjectDetectionCollisionLayer);
                    detectorShape.Base.RemoveReference();
                    break;
                }
            }
        }
        public static HkShape CreateCharacterShape(float height, float width, float headHeight, float headSize, float headForwardOffset, float downOffset = 0, bool capsuleForHead = false)
        {
            HkCapsuleShape capsule = new HkCapsuleShape(Vector3.Up * (height - downOffset) / 2.0f, Vector3.Down * (height) / 2.0f, width / 2.0f);

            if (headSize > 0)
            {
                HkConvexShape headShape;

                if (capsuleForHead)
                {
                    headShape = new HkCapsuleShape(new Vector3(0, 0, -0.3f), new Vector3(0, 0, 0.3f), headSize);
                }
                else
                {
                    headShape = new HkSphereShape(headSize);
                }
                //headShape = new HkCapsuleShape(new Vector3(0, 0, -0.05f), new Vector3(0, 0, 0.05f), headSize);

                HkShape[] shapes = new HkShape[]
                {
                    capsule,
                    new HkConvexTranslateShape(headShape, Vector3.Up * (headHeight - downOffset) / 2.0f + Vector3.Forward * headForwardOffset, HkReferencePolicy.TakeOwnership),
                };
                
                return new HkListShape(shapes, shapes.Length, HkReferencePolicy.TakeOwnership);
            }
            else
            {
                return capsule;
            }
        }
        protected virtual bool CanPlaceTop(MyAttachableTopBlockBase topBlock, long builtBy)
        {
            // Compute the rough actual position for the head, this improves the detection if it can be placed
            float    topDistance = (Subpart3.Model.BoundingBoxSize.Y);
            Vector3D topPosition = this.Subpart3.WorldMatrix.Translation + this.WorldMatrix.Up * topDistance;
            float    topRadius   = topBlock.ModelCollision.HavokCollisionShapes[0].ConvexRadius * 0.9f;

            // First test if we intersect any blocks of our own grid
            BoundingSphereD sphere = topBlock.Model.BoundingSphere;

            sphere.Center = topPosition;
            sphere.Radius = topRadius;
            CubeGrid.GetBlocksInsideSphere(ref sphere, m_tmpSet);

            // If we intersect more than 1 block (because top sometimes intersects piston), don't add top
            if (m_tmpSet.Count > 1)
            {
                m_tmpSet.Clear();
                if (builtBy == MySession.Static.LocalPlayerId)
                {
                    MyHud.Notifications.Add(MyNotificationSingletons.HeadNotPlaced);
                }
                return(false);
            }

            m_tmpSet.Clear();

            // Next test if we intersect any physics objects
            HkSphereShape spShape = new HkSphereShape(topRadius);
            Quaternion    q       = Quaternion.Identity;

            MyPhysics.GetPenetrationsShape(topBlock.ModelCollision.HavokCollisionShapes[0], ref topPosition, ref q, m_penetrations, MyPhysics.CollisionLayers.DefaultCollisionLayer);

            // If we have any collisions with anything other than our own grid, don't add the head
            // We already checked for inner-grid collisions in the previous case
            for (int i = 0; i < m_penetrations.Count; i++)
            {
                MyCubeGrid grid = m_penetrations[i].GetCollisionEntity().GetTopMostParent() as MyCubeGrid;
                if (grid == null || grid != CubeGrid)
                {
                    m_penetrations.Clear();
                    if (builtBy == MySession.Static.LocalPlayerId)
                    {
                        MyHud.Notifications.Add(MyNotificationSingletons.HeadNotPlaced);
                    }
                    return(false);
                }
            }

            m_penetrations.Clear();

            return(true);
        }
Beispiel #12
0
        protected override bool CanPlaceRotor(MyAttachableTopBlockBase rotorBlock, long builtBy)
        {
            // Compute the rough actual position for the wheel, this improves the detection if it can be placed
            float    wheelDistance = BlockDefinition.Size.Y * CubeGrid.GridSize - 0.2f * CubeGrid.GridSize;
            Vector3D wheelPosition = this.WorldMatrix.Translation + this.WorldMatrix.Up * wheelDistance;
            float    wheelRadius   = rotorBlock.ModelCollision.HavokCollisionShapes[0].ConvexRadius * 0.9f;

            // First test if we intersect any blocks of our own grid
            BoundingSphereD sphere = rotorBlock.Model.BoundingSphere;

            sphere.Center = wheelPosition;
            sphere.Radius = wheelRadius;
            CubeGrid.GetBlocksInsideSphere(ref sphere, m_tmpSet);

            // If we intersect more than 1 block (because wheel sometimes intersects suspension), don't add wheel
            if (m_tmpSet.Count > 1)
            {
                m_tmpSet.Clear();
                if (builtBy == MySession.Static.LocalPlayerId)
                {
                    MyHud.Notifications.Add(MyNotificationSingletons.WheelNotPlaced);
                }
                return(false);
            }

            m_tmpSet.Clear();

            // Next test if we intersect any physics objects
            HkSphereShape spShape = new HkSphereShape(wheelRadius);
            Quaternion    q       = Quaternion.Identity;

            MyPhysics.GetPenetrationsShape(rotorBlock.ModelCollision.HavokCollisionShapes[0], ref wheelPosition, ref q, m_tmpList, MyPhysics.CollisionLayers.DefaultCollisionLayer);

            // If we have any collisions with anything other than our own grid, don't add the wheel
            // We already checked for inner-grid collisions in the previous case
            for (int i = 0; i < m_tmpList.Count; i++)
            {
                MyCubeGrid grid = m_tmpList[i].GetCollisionEntity() as MyCubeGrid;
                if (grid == null || grid != CubeGrid)
                {
                    m_tmpList.Clear();
                    if (builtBy == MySession.Static.LocalPlayerId)
                    {
                        MyHud.Notifications.Add(MyNotificationSingletons.WheelNotPlaced);
                    }
                    return(false);
                }
            }

            m_tmpList.Clear();

            return(true);
        }
Beispiel #13
0
            public override void ScalePhysicsShape(ref HkMassProperties massProperties)
            {
                HkSphereShape shape = (HkSphereShape)this.RigidBody.GetShape();

                shape.Radius = ((MyEntity)base.Entity).Render.GetModel().BoundingSphere.Radius *base.Entity.PositionComp.Scale.Value;
                float mass = this.SphereMass(shape.Radius, 260f);

                massProperties = HkInertiaTensorComputer.ComputeSphereVolumeMassProperties(shape.Radius, mass);
                this.RigidBody.SetShape((HkShape)shape);
                this.RigidBody.SetMassProperties(ref massProperties);
                this.RigidBody.UpdateShape();
            }
        public static Vector3D?FindFreePlace(Vector3D basePos, float radius, int maxTestCount = 40, int testsPerDistance = 6, float stepSize = 1f, float radiusIncrement = 10f, MyEntity ignoreEnt = null)
        {
            Vector3D   position = basePos;
            Quaternion rotation = Quaternion.Identity;
            HkShape    shape    = new HkSphereShape(radius);

            try
            {
                if (MyEntities.IsInsideWorld(position) && !MyEntities.IsShapePenetrating(shape, ref position, ref rotation, 15, ignoreEnt))
                {
                    BoundingSphereD sphere = new BoundingSphereD(position, radius);
                    MyVoxelBase     overlappingWithSphere = MySession.Static.VoxelMaps.GetOverlappingWithSphere(ref sphere);
                    if (overlappingWithSphere == null)
                    {
                        return(position);
                    }
                    if (overlappingWithSphere is MyPlanet)
                    {
                        (overlappingWithSphere as MyPlanet).CorrectSpawnLocation(ref basePos, radius);
                    }
                    return(basePos);
                }
                int   num  = (int)Math.Ceiling((float)maxTestCount / (float)testsPerDistance);
                float num2 = 0f;
                for (int i = 0; i < num; i++)
                {
                    num2 += radius * stepSize + radiusIncrement;
                    for (int j = 0; j < testsPerDistance; j++)
                    {
                        position = basePos + MyUtils.GetRandomVector3Normalized() * num2;
                        if (MyEntities.IsInsideWorld(position) && !MyEntities.IsShapePenetrating(shape, ref position, ref rotation, 15, ignoreEnt))
                        {
                            BoundingSphereD sphere2 = new BoundingSphereD(position, radius);
                            MyVoxelBase     overlappingWithSphere2 = MySession.Static.VoxelMaps.GetOverlappingWithSphere(ref sphere2);
                            if (overlappingWithSphere2 == null)
                            {
                                return(position);
                            }
                            if (overlappingWithSphere2 is MyPlanet)
                            {
                                (overlappingWithSphere2 as MyPlanet).CorrectSpawnLocation(ref basePos, radius);
                            }
                        }
                    }
                }
                return(null);
            }
            finally
            {
                shape.RemoveReference();
            }
        }
Beispiel #15
0
        private void DamageGrid(FlameInfo flameInfo, LineD l, MyCubeGrid grid)
        {
            HkSphereShape sph       = new HkSphereShape(flameInfo.Radius * BlockDefinition.FlameDamageLengthScale);
            var           transform = MatrixD.CreateWorld(l.From, Vector3.Forward, Vector3.Up);
            var           hit       = MyPhysics.CastShapeReturnPoint(l.To, sph, ref transform, (int)MyPhysics.CollisionLayers.DefaultCollisionLayer, 0.05f);

            sph.Base.RemoveReference();

            if (hit.HasValue)
            {
                //MyRenderProxy.DebugDrawSphere(hit.Value, 0.1f, Color.Green.ToVector3(), 1, true);
                MyPhysics.CastRay(hit.Value - l.Direction * 0.1f, hit.Value + l.Direction * 0.1f, m_gridRayCastLst, MyPhysics.CollisionLayers.ObjectDetectionCollisionLayer);
                if (m_gridRayCastLst.Count == 0 || m_gridRayCastLst[0].HkHitInfo.GetHitEntity() != grid)    //If you found something other than the targeted grid do nothing
                {
                    m_gridRayCastLst.Clear();
                    return;
                }

                Vector3D offsetHit = hit.Value + l.Direction * 0.1;
                m_gridRayCastLst.Clear();
                var block = grid.GetCubeBlock(grid.WorldToGridInteger(offsetHit));
                //if (block != this.SlimBlock)
                {
                    //MyRenderProxy.DebugDrawSphere(hit.Value, 0.1f, Color.Green.ToVector3(), 1, true);
                    var invWorld = grid.PositionComp.WorldMatrixNormalizedInv;
                    var gridPos  = Vector3D.Transform(offsetHit, invWorld);
                    var gridDir  = Vector3D.TransformNormal(l.Direction, invWorld);
                    if (block != null)
                    {
                        //We dont want to damage thruster itself
                        //We dont want smallship thruster to damage heavy armors because of landing
                        if (block.FatBlock != this && (CubeGrid.GridSizeEnum == MyCubeSize.Large || block.BlockDefinition.DeformationRatio > 0.25))
                        {
                            block.DoDamage(30 * BlockDefinition.FlameDamage, MyDamageType.Environment, attackerId: EntityId);
                        }
                    }

                    if (block == null || block.FatBlock != this)
                    {
                        var areaPlanar   = 0.5f * flameInfo.Radius * CubeGrid.GridSize;
                        var areaVertical = 0.5f * CubeGrid.GridSize;

                        grid.Physics.ApplyDeformation(BlockDefinition.FlameDamage, areaPlanar, areaVertical, gridPos, gridDir, MyDamageType.Environment, CubeGrid.GridSizeEnum == MyCubeSize.Small ? 0.1f : 0, attackerId: EntityId);
                    }
                }
            }
        }
Beispiel #16
0
        public static void InitSpherePhysics(this IMyEntity entity, MyStringHash materialType, Vector3 sphereCenter, float sphereRadius, float mass, float linearDamping, float angularDamping, ushort collisionLayer, RigidBodyFlag rbFlag)
        {
            float single1 = mass;

            mass = ((rbFlag & RigidBodyFlag.RBF_STATIC) != RigidBodyFlag.RBF_DEFAULT) ? 0f : single1;
            MyPhysicsBody body1 = new MyPhysicsBody(entity, rbFlag);

            body1.MaterialType   = materialType;
            body1.AngularDamping = angularDamping;
            body1.LinearDamping  = linearDamping;
            MyPhysicsBody    body       = body1;
            HkMassProperties properties = HkInertiaTensorComputer.ComputeSphereVolumeMassProperties(sphereRadius, mass);
            HkSphereShape    shape      = new HkSphereShape(sphereRadius);

            body.CreateFromCollisionObject((HkShape)shape, sphereCenter, entity.PositionComp.WorldMatrix, new HkMassProperties?(properties), 15);
            shape.Base.RemoveReference();
            entity.Physics = body;
        }
        public static void InitSpherePhysics(this IMyEntity entity, MyStringHash materialType, Vector3 sphereCenter, float sphereRadius, float mass, float linearDamping, float angularDamping, ushort collisionLayer, RigidBodyFlag rbFlag)
        {
            mass = (rbFlag & RigidBodyFlag.RBF_STATIC) != 0 ? 0 : mass;

            var physics = new Sandbox.Engine.Physics.MyPhysicsBody(entity, rbFlag)
            {
                MaterialType = materialType,
                AngularDamping = angularDamping,
                LinearDamping = linearDamping
            };

            var massProperties = HkInertiaTensorComputer.ComputeSphereVolumeMassProperties(sphereRadius, mass);

            HkSphereShape shape = new HkSphereShape(sphereRadius);
            physics.CreateFromCollisionObject((HkShape)shape, sphereCenter, entity.PositionComp.WorldMatrix, massProperties);

            shape.Base.RemoveReference();
            entity.Physics = physics;
        }
Beispiel #18
0
        public static void InitSpherePhysics(this IMyEntity entity, MyStringHash materialType, Vector3 sphereCenter, float sphereRadius, float mass, float linearDamping, float angularDamping, ushort collisionLayer, RigidBodyFlag rbFlag)
        {
            mass = (rbFlag & RigidBodyFlag.RBF_STATIC) != 0 ? 0 : mass;

            var physics = new Sandbox.Engine.Physics.MyPhysicsBody(entity, rbFlag)
            {
                MaterialType   = materialType,
                AngularDamping = angularDamping,
                LinearDamping  = linearDamping
            };

            var massProperties = HkInertiaTensorComputer.ComputeSphereVolumeMassProperties(sphereRadius, mass);

            HkSphereShape shape = new HkSphereShape(sphereRadius);

            physics.CreateFromCollisionObject((HkShape)shape, sphereCenter, entity.PositionComp.WorldMatrix, massProperties);

            shape.Base.RemoveReference();
            entity.Physics = physics;
        }
Beispiel #19
0
        private void DamageGrid(FlameInfo flameInfo, LineD l, MyCubeGrid grid)
        {
            HkSphereShape sph       = new HkSphereShape(flameInfo.Radius * m_thrustDefinition.FlameDamageLengthScale);
            var           transform = MatrixD.CreateWorld(l.From, Vector3.Forward, Vector3.Up);
            var           hit       = MyPhysics.CastShapeReturnPoint(l.To, sph, ref transform, (int)MyPhysics.DefaultCollisionLayer, 0.05f);

            sph.Base.RemoveReference();

            if (hit.HasValue)
            {
                //MyRenderProxy.DebugDrawSphere(hit.Value, 0.1f, Color.Green.ToVector3(), 1, true);
                MyPhysics.CastRay(hit.Value - l.Direction * 0.1f, hit.Value + l.Direction * 0.1f, m_gridRayCastLst, MyPhysics.ObjectDetectionCollisionLayer);
                if ((m_gridRayCastLst.Count == 0 || m_gridRayCastLst[0].HkHitInfo.Body.GetEntity() != grid) && grid == CubeGrid)
                {
                    m_gridRayCastLst.Clear();
                    return;
                }
                m_gridRayCastLst.Clear();
                var block = grid.GetCubeBlock(grid.WorldToGridInteger(hit.Value));
                //if (block != this.SlimBlock)
                {
                    //MyRenderProxy.DebugDrawSphere(hit.Value, 0.1f, Color.Green.ToVector3(), 1, true);
                    var invWorld = grid.PositionComp.GetWorldMatrixNormalizedInv();
                    var gridPos  = Vector3D.Transform(hit.Value, invWorld);
                    var gridDir  = Vector3D.TransformNormal(l.Direction, invWorld);
                    if (block != null)
                    {
                        if (block.FatBlock != this && (CubeGrid.GridSizeEnum == MyCubeSize.Large || block.BlockDefinition.DeformationRatio > 0.25))
                        {
                            block.DoDamage(30 * m_thrustDefinition.FlameDamage, MyDamageType.Environment, attackerId: EntityId);
                        }
                    }
                    var areaPlanar   = 0.5f * flameInfo.Radius * CubeGrid.GridSize;
                    var areaVertical = 0.5f * CubeGrid.GridSize;

                    grid.Physics.ApplyDeformation(m_thrustDefinition.FlameDamage, areaPlanar, areaVertical, gridPos, gridDir, MyDamageType.Environment, CubeGrid.GridSizeEnum == MyCubeSize.Small ? 0.1f : 0, attackerId: EntityId);
                }
            }
        }
        static MyEntityPhysicsStateGroup SphereCast(MyEntity entity, float radius, float distance)
        {
            if (DEBUG_DRAW)
            {
                VRageRender.MyRenderProxy.DebugDrawCapsule(entity.WorldMatrix.Translation, entity.PositionComp.GetPosition() + entity.WorldMatrix.Down * distance, radius, Color.Red, false, false);
            }

            // Sphere cast under character
            Vector3D target = entity.PositionComp.GetPosition() + entity.WorldMatrix.Down * distance;
            HkSphereShape shape = new HkSphereShape(radius);
            MatrixD transform = entity.WorldMatrix;
            var dist = MyPhysics.CastShapeReturnContactBodyData(target, shape, ref transform, MyPhysics.CollisionLayers.CollisionLayerWithoutCharacter, 0);
            if (dist.HasValue)
            {
                var hitEntity = dist.Value.HkHitInfo.GetHitEntity();
                if (!IsValid(hitEntity, false))
                    return null;

                return FindPhysics(hitEntity);
            }
            return null;
        }
Beispiel #21
0
        private bool CreateOwnerVirtualPhysics()
        {
            if (Owner == null)
            {
                return(false);
            }

            OwnerVirtualPhysics = new MyCharacterVirtualPhysicsBody(Owner, RigidBodyFlag.RBF_KINEMATIC);
            var     massProperties = HkInertiaTensorComputer.ComputeSphereVolumeMassProperties(0.1f, MyPerGameSettings.Destruction ? MyDestructionHelper.MassToHavok(Owner.Definition.Mass) : Owner.Definition.Mass);
            HkShape sh             = new HkSphereShape(0.1f);

            OwnerVirtualPhysics.InitialSolverDeactivation = HkSolverDeactivation.Off;
            MatrixD headWorldMatrix = Owner.GetHeadMatrix(false, forceHeadBone: true);

            OwnerVirtualPhysics.CreateFromCollisionObject(sh, Vector3.Zero, headWorldMatrix, massProperties, Sandbox.Engine.Physics.MyPhysics.NoCollisionLayer);
            OwnerVirtualPhysics.RigidBody.EnableDeactivation = false;
            // Character ray casts includes also NoCollision layer shapes so setup property for ignoring the body
            OwnerVirtualPhysics.RigidBody.SetProperty(HkCharacterRigidBody.MANIPULATED_OBJECT, 0);
            sh.RemoveReference();

            OwnerVirtualPhysics.Enabled = true;

            return(true);
        }
        /// <summary>
        /// Handles camera collisions with environment
        /// </summary>
        /// <param name="controlledEntity"></param>
        /// <param name="shakeActive"></param>
        /// <param name="headPosition"></param>
        /// <param name="headDirection"></param>
        /// <returns>False if no correct position was found</returns>
        private bool HandleIntersection(MyEntity controlledEntity, MyOrientedBoundingBoxD safeOBB, bool requireRaycast, bool shakeActive, Vector3D headPosition, Vector3 headDirection)
        {
            var line = new LineD(m_target, m_position);

            var safeOBBLine = new LineD(line.From, line.From + line.Direction * 2 * safeOBB.HalfExtent.Length());
            Vector3D castStartSafe;
            {
                MyOrientedBoundingBoxD safeObbWithCollisionExtents = new MyOrientedBoundingBoxD(safeOBB.Center, safeOBB.HalfExtent + 2 * CAMERA_RADIUS, safeOBB.Orientation);
                double? safeIntersection = safeObbWithCollisionExtents.Intersects(ref safeOBBLine);
                if (!safeIntersection.HasValue)
                    safeIntersection = safeOBB.HalfExtent.Length();
                double safeDistance = safeIntersection.Value;
                castStartSafe = line.From + line.Direction * safeDistance;
            }

            {
                double? unsafeIntersection = safeOBB.Intersects(ref safeOBBLine);
                if (!requireRaycast && unsafeIntersection.HasValue)
                {
                    var castStartUnsafe = line.From + line.Direction * unsafeIntersection.Value;
                    var castEndUnsafe = castStartSafe + line.Direction;
                    // short raycast, not causing problems with asteroids generating geometry
                    Physics.MyPhysics.CastRay(castStartUnsafe, castEndUnsafe, m_raycastList, MyPhysics.DefaultCollisionLayer);
                    if (!IsRaycastOK(m_raycastList))
                    {
                        return false;
                    }
                }
            }

            if (requireRaycast)
            {
                // short raycast, not causing problems with asteroids generating geometry
                Physics.MyPhysics.CastRay(line.From, castStartSafe + line.Direction, m_raycastList, MyPhysics.DefaultCollisionLayer);
                if (!IsRaycastOK(m_raycastList))
                {
                    return false;
                }
            }

            HkShape shape = new HkSphereShape(CAMERA_RADIUS);
            try
            {
                // small shape, not causing problems with asteroids generating geometry
                Physics.MyPhysics.GetPenetrationsShape(shape, ref castStartSafe, ref Quaternion.Identity, m_rigidList, 15);
                if (m_rigidList.Count > 0)
                {
                    bool sameGrid = false;
                    if (MySession.ControlledEntity != null && m_rigidList[0].Body != null)
                    {
                        sameGrid = m_rigidList[0].GetCollisionEntity() == MySession.ControlledEntity;
                    }

                    if (sameGrid)
                        castStartSafe += line.Direction;
                }

                var shapeCastLine = new LineD(castStartSafe, m_position);
                uint steps = 1;
                uint stepIdx = 0;
                if (shapeCastLine.Length > SHAPE_CAST_STEP)
                {
                    steps = (uint)Math.Ceiling(shapeCastLine.Length / SHAPE_CAST_STEP);
                    if (steps >= SHAPE_CAST_MAX_STEP_COUNT)
                        steps = SHAPE_CAST_MAX_STEP_COUNT - 1;
                    stepIdx = m_updateCount % steps;
                    m_lastShapeCastDistance[stepIdx] = float.PositiveInfinity;

                    Vector3D step = shapeCastLine.Direction * (shapeCastLine.Length / steps);
                    shapeCastLine = new LineD(castStartSafe + stepIdx * step, castStartSafe + (stepIdx + 1) * step);
                }

                if (false)
                {
                    BoundingBoxD bbox = BoundingBoxD.CreateInvalid();
                    bbox.Include(new BoundingSphereD(shapeCastLine.From, CAMERA_RADIUS));
                    bbox.Include(new BoundingSphereD(shapeCastLine.To, CAMERA_RADIUS));
                    VRageRender.MyRenderProxy.DebugDrawAABB(bbox, Color.Crimson, 1f, 1f, true);
                }

                var matrix = MatrixD.CreateTranslation(shapeCastLine.From);
                HkContactPointData? cpd;
                if (controlledEntity.Physics != null && controlledEntity.Physics.CharacterProxy != null)
                    cpd = MyPhysics.CastShapeReturnContactData(shapeCastLine.To, shape, ref matrix, controlledEntity.Physics.CharacterCollisionFilter, 0.0f); 
                else
                    cpd = MyPhysics.CastShapeReturnContactData(shapeCastLine.To, shape, ref matrix, HkGroupFilter.CalcFilterInfo(MyPhysics.DefaultCollisionLayer,0), 0.0f);
                if (cpd.HasValue)
                {
                    var point = shapeCastLine.From + shapeCastLine.Direction * shapeCastLine.Length * cpd.Value.DistanceFraction;
                    m_lastShapeCastDistance[stepIdx] = (float)(castStartSafe - point).Length();
                }
                else
                {
                    m_lastShapeCastDistance[stepIdx] = float.PositiveInfinity;
                }


                float? dist = null;
                for (int i = 0; i < steps; ++i)
                {
                    if (m_lastShapeCastDistance[i] != float.PositiveInfinity)
                        dist = Math.Min(m_lastShapeCastDistance[i], dist ?? float.PositiveInfinity);
                }

                if (dist.HasValue)
                {
                    if (dist == 0.0f)
                    {
                        return false;
                    }
                    else
                    {
                        m_positionSafe = castStartSafe + shapeCastLine.Direction * dist.Value;
                    }
                }
                else
                {
                    m_positionSafe = m_position;
                }
                return true;
            }
            finally
            {
                shape.RemoveReference();
            }
        }
Beispiel #23
0
        /// <summary>
        /// Spawns bag around position given by "baseTransform", checks all 4 directions around - forwards (forward, right, backward, left) and on each such direction moves test sphere
        /// in 3 directions forward (frontChecks), sides (perpendicular to forward direction - rights) and up. If spawn position is not found then position above "worldAabbTopPosition"
        /// is selected.
        /// </summary>
        private static MyEntity SpawnBagAround(MyEntity itemOwner, MyContainerDefinition bagDefinition,
                                               int sideCheckCount = 3, int frontCheckCount = 2, int upCheckCount = 5, float stepSize = 1f)
        {
            Debug.Assert(Sandbox.Game.Multiplayer.Sync.IsServer);

            Vector3D?finalPos = null;

            // Model sphere
            MyModel bagModel = null;

            foreach (var componentDef in bagDefinition.DefaultComponents)
            {
                if (typeof(MyObjectBuilder_ModelComponent).IsAssignableFrom(componentDef.BuilderType))
                {
                    MyComponentDefinitionBase componentDefinition = null;
                    var componentSubtype = bagDefinition.Id.SubtypeId;
                    if (componentDef.SubtypeId.HasValue)
                    {
                        componentSubtype = componentDef.SubtypeId.Value;
                    }

                    if (MyComponentContainerExtension.TryGetComponentDefinition(componentDef.BuilderType, componentSubtype, out componentDefinition))
                    {
                        var modelComponentDef = componentDefinition as MyModelComponentDefinition;
                        Debug.Assert(modelComponentDef != null);
                        if (modelComponentDef != null)
                        {
                            bagModel = MyModels.GetModelOnlyData(modelComponentDef.Model);
                        }
                    }

                    break;
                }
            }

            Debug.Assert(bagModel != null);
            if (bagModel == null)
            {
                return(null);
            }

            float   bagBoxRadius = bagModel.BoundingBox.HalfExtents.Max();
            HkShape sphere       = new HkSphereShape(bagBoxRadius);

            try
            {
                Vector3D basePos = itemOwner.PositionComp.WorldMatrix.Translation;
                float    step    = bagBoxRadius * stepSize;

                // Calculate right, up and forward vectors from gravity
                Vector3 upDir = -MyGravityProviderSystem.CalculateNaturalGravityInPoint(itemOwner.PositionComp.WorldMatrix.Translation);
                if (upDir == Vector3.Zero)
                {
                    upDir = Vector3.Up;
                }
                else
                {
                    upDir.Normalize();
                }

                Vector3 forwardDir;
                upDir.CalculatePerpendicularVector(out forwardDir);

                Vector3 rightDir = Vector3.Cross(forwardDir, upDir);
                rightDir.Normalize();

                Vector3D   currentPos;
                Quaternion rot = Quaternion.Identity;

                Vector3[] forwards = new Vector3[]
                {
                    forwardDir,
                    rightDir,
                    -forwardDir,
                    -rightDir
                };

                Vector3[] rights = new Vector3[]
                {
                    rightDir,
                    -forwardDir,
                    -rightDir,
                    forwardDir
                };

                // All sides
                for (int i = 0; i < forwards.Length && finalPos == null; ++i)
                {
                    var forward = forwards[i];
                    var right   = rights[i];

                    // Move forward
                    for (int frontMove = 0; frontMove < frontCheckCount && finalPos == null; ++frontMove)
                    {
                        Vector3D sidePosBase = basePos + 0.25f * forward + bagBoxRadius * forward + frontMove * step * forward - 0.5f * (sideCheckCount - 1) * step * right;

                        // Move perp to forward
                        for (int sideMove = 0; sideMove < sideCheckCount && finalPos == null; ++sideMove)
                        {
                            // Move up
                            for (int upMove = 0; upMove < upCheckCount && finalPos == null; ++upMove)
                            {
                                currentPos = sidePosBase + sideMove * step * right + upMove * step * upDir;

                                if (MyEntities.IsInsideWorld(currentPos) && !MyEntities.IsShapePenetrating(sphere, ref currentPos, ref rot))
                                {
                                    BoundingSphereD boundingSphere     = new BoundingSphereD(currentPos, bagBoxRadius);
                                    MyVoxelBase     overlappedVoxelmap = MySession.Static.VoxelMaps.GetOverlappingWithSphere(ref boundingSphere);

                                    if (overlappedVoxelmap == null)
                                    {
                                        finalPos = currentPos;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }

                // If not found position then select position above aabb's top.
                if (finalPos == null)
                {
                    MyOrientedBoundingBoxD obb     = new MyOrientedBoundingBoxD((BoundingBoxD)itemOwner.PositionComp.LocalAABB, itemOwner.PositionComp.WorldMatrix);
                    Vector3D[]             corners = new Vector3D[8];
                    obb.GetCorners(corners, 0);
                    float dotUp = float.MinValue;
                    foreach (var corner in corners)
                    {
                        var localDot = Vector3.Dot(corner - obb.Center, upDir);
                        dotUp = Math.Max(dotUp, localDot);
                    }

                    finalPos = itemOwner.PositionComp.WorldMatrix.Translation;
                    Debug.Assert(dotUp > 0);
                    if (dotUp > 0)
                    {
                        finalPos = obb.Center + dotUp * upDir;
                    }
                }
            }
            finally
            {
                sphere.RemoveReference();
            }

            Debug.Assert(finalPos != null);

            MatrixD transform = itemOwner.PositionComp.WorldMatrix;

            transform.Translation = finalPos.Value;

            MyEntity bagEntity = MyEntities.CreateFromComponentContainerDefinitionAndAdd(bagDefinition.Id);

            if (bagEntity == null)
            {
                return(null);
            }

            bagEntity.PositionComp.SetWorldMatrix(transform);

            bagEntity.Physics.LinearVelocity  = Vector3.Zero;
            bagEntity.Physics.AngularVelocity = Vector3.Zero;

            return(bagEntity);
        }
        private void RefreshPhysicsBody()
        {
            if (CubeGrid.CreatePhysics)
            {
                if (Physics != null)
                {
                    Physics.Close();
                }

                var detectorShape = new HkSphereShape(CubeGrid.GridSize * 0.5f);
                var massProperties = HkInertiaTensorComputer.ComputeSphereVolumeMassProperties(detectorShape.Radius, VirtualMass != 0 ? VirtualMass : 0.01f);
                Physics = new Engine.Physics.MyPhysicsBody(this, RigidBodyFlag.RBF_KEYFRAMED_REPORTING);
                Physics.IsPhantom = false;
                Physics.CreateFromCollisionObject(detectorShape, Vector3.Zero, WorldMatrix, massProperties, MyPhysics.CollisionLayers.VirtualMassLayer);
                UpdateIsWorking();
                Physics.Enabled = IsWorking && CubeGrid.Physics != null && CubeGrid.Physics.Enabled;

                Physics.RigidBody.Activate();
                detectorShape.Base.RemoveReference();

                if (CubeGrid != null && CubeGrid.Physics != null && !CubeGrid.IsStatic)
                    CubeGrid.Physics.UpdateMass();
            }
        }
        /// <summary>
        /// Handles camera collisions with environment
        /// </summary>
        /// <returns>False if no correct position was found</returns>
        private void HandleIntersection(MyEntity controlledEntity)
        {
            Debug.Assert(controlledEntity != null);
            MyEntity parentEntity = controlledEntity.GetTopMostParent() ?? controlledEntity;

            // line from target to eye
            LineD line = new LineD(m_target, m_position);
            // oriented bb of the entity
            MyOrientedBoundingBoxD safeObb = GetEntitySafeOBB(parentEntity);
            // oriented bb of the entity + camera radius
            MyOrientedBoundingBoxD safeObbWithCollisionExtents =
                new MyOrientedBoundingBoxD(safeObb.Center, safeObb.HalfExtent + (controlledEntity.Parent == null ? 0.5 : 2.0) * CAMERA_RADIUS, safeObb.Orientation);

            // start = target, end = eye
            // find safe start...
            LineD    safeOBBLine      = new LineD(line.From + line.Direction * 2 * safeObb.HalfExtent.Length(), line.From);
            double?  safeIntersection = safeObbWithCollisionExtents.Intersects(ref safeOBBLine);
            Vector3D castStartSafe    = safeIntersection != null ? (safeOBBLine.From + safeOBBLine.Direction * safeIntersection.Value) : m_target;

            if (controlledEntity.Parent != null && safeIntersection != null)
            {
                HkShape hkSphere = new HkSphereShape(CAMERA_RADIUS * 2);
                //var hitInfo = MyPhysics.CastRay(castStartSafe, m_target);

                MatrixD shapeCastStart = MatrixD.CreateTranslation(castStartSafe);
                var     hitInfo        = MyPhysics.CastShapeReturnContactBodyData(m_target, hkSphere, ref shapeCastStart, 0, 0);

                MyEntity hitEntity = hitInfo.HasValue ? hitInfo.Value.HkHitInfo.GetHitEntity() as MyEntity : null;
                MyEntity entity    = controlledEntity;

                var hitEntityWeldingGroup = hitEntity != null?MyWeldingGroups.Static.GetGroup(hitEntity) : null;

                bool weldingGroupEquals = false;

                while (entity != null && !weldingGroupEquals)
                {
                    if (hitEntityWeldingGroup == MyWeldingGroups.Static.GetGroup(entity))
                    {
                        weldingGroupEquals = true;
                    }

                    entity = entity.Parent;
                }

                if (hitInfo.HasValue && hitEntityWeldingGroup != null && weldingGroupEquals)
                {
                    castStartSafe = hitInfo.Value.Position + line.Direction;
                }
                else
                {
                    safeObb = GetEntitySafeOBB(controlledEntity);
                    safeObbWithCollisionExtents = new MyOrientedBoundingBoxD(safeObb.Center, safeObb.HalfExtent + 0.5f * CAMERA_RADIUS, safeObb.Orientation);
                    safeIntersection            = safeObbWithCollisionExtents.Intersects(ref safeOBBLine);
                    castStartSafe = safeIntersection != null ? (safeOBBLine.From + safeOBBLine.Direction * safeIntersection.Value) : m_target;
                }
                hkSphere.RemoveReference();
            }

            // raycast against occluders
            Vector3D safePositionCandidate;

            //double lastSafeMinimumDistance = m_safeMinimumDistance;
            m_safeMinimumDistance = controlledEntity is MyCharacter ? 0 : (castStartSafe - m_target).Length(); // store current safe minimum dist
            m_safeMinimumDistance = Math.Max(m_safeMinimumDistance, MIN_VIEWER_DISTANCE);
            //if (lastSafeMinimumDistance + 30.0f < m_safeMinimumDistance)
            //{
            //    castStartSafe = m_target + (castStartSafe - m_target) / m_safeMinimumDistance * lastSafeMinimumDistance;
            //    m_safeMinimumDistance = lastSafeMinimumDistance;
            //}
            Vector3D raycastOrigin = (controlledEntity is MyCharacter) ? m_target : castStartSafe;
            MyCameraRaycastResult raycastResult = RaycastOccludingObjects(controlledEntity, ref raycastOrigin, ref m_position,
                                                                          ref castStartSafe, out safePositionCandidate);

            // visual debugging :)
            if (m_debugDraw)
            {
                VRageRender.MyRenderProxy.DebugDrawOBB(safeObb, Color.Red, 0.1f, false, true);
                VRageRender.MyRenderProxy.DebugDrawOBB(safeObbWithCollisionExtents, Color.Yellow, 0.0f, false, true);
                VRageRender.MyRenderProxy.DebugDrawArrow3D(safeOBBLine.From, safeOBBLine.To, Color.White, Color.Purple,
                                                           false);
                VRageRender.MyRenderProxy.DebugDrawArrow3D(safeOBBLine.From, castStartSafe, Color.White, Color.Red,
                                                           false);
                VRageRender.MyRenderProxy.DebugDrawArrow3D(castStartSafe, m_position, Color.White, Color.Orange, false);

                VRageRender.MyRenderProxy.DebugDrawSphere(castStartSafe, 0.2f, Color.Green, 1.0f, false, true);
            }

            switch (raycastResult)
            {
            case MyCameraRaycastResult.Ok:
            case MyCameraRaycastResult.FoundOccluder:
                m_positionCurrentIsSafe = true;
                {
                    double distFromCandidateToTarget = (safePositionCandidate - m_target).Length();
                    if ((distFromCandidateToTarget > m_lastRaycastDist + CAMERA_RADIUS && distFromCandidateToTarget > m_safeMinimumDistance) ||
                        raycastResult == MyCameraRaycastResult.Ok)
                    {
                        // now we need it from the other side
                        double newDist = (safePositionCandidate - m_position).Length();
                        // new safe position is further from target => change over time (zoom out)
                        if (m_positionSafeZoomingOutTimeout <= 0)
                        {
                            float distDiffZoomSpeed = 1 -
                                                      MathHelper.Clamp((float)Math.Abs(m_lastRaycastDist - newDist), 0.0f,
                                                                       1.0f - MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS);
                            m_positionSafeZoomingOutSpeed += distDiffZoomSpeed;
                            m_positionSafeZoomingOutSpeed  = MathHelper.Clamp(m_positionSafeZoomingOutSpeed, 0.0f,
                                                                              1.0f);

                            Vector3D targetToPosSafe     = m_positionSafe - m_target;
                            double   lenTargetToPosSafe  = targetToPosSafe.Length();
                            Vector3D rotatedPositionSafe = m_target +
                                                           Vector3D.Normalize(safePositionCandidate - m_target) *
                                                           lenTargetToPosSafe;
                            m_positionSafe = Vector3D.Lerp(rotatedPositionSafe, safePositionCandidate,
                                                           m_positionSafeZoomingOutSpeed);
                        }
                        else
                        {
                            m_positionSafeZoomingOutTimeout -= MyEngineConstants.UPDATE_STEP_SIZE_IN_MILLISECONDS;

                            Vector3D targetToPosSafe    = m_positionSafe - m_target;
                            double   lenTargetToPosSafe = targetToPosSafe.Length();
                            m_positionSafe = m_target + Vector3D.Normalize(safePositionCandidate - m_target) * lenTargetToPosSafe;
                        }
                    }
                    else
                    {
                        // new safe position is closer or closer than safe distance => instant change
                        m_positionSafeZoomingOutSpeed = 0.0f;   // set zooming out speed to zero for next time
                        m_positionSafe = safePositionCandidate;
                        m_positionSafeZoomingOutTimeout = 0;    // controlledEntity.Parent != null ? m_positionSafeZoomingOutDefaultTimeoutMs : 0;
                        m_disableSpringThisFrame        = true;
                    }
                }
                break;

            //case MyCameraRaycastResult.FoundOccluderNoSpace:
            default:
                m_positionSafeZoomingOutSpeed = 1.0f;     // we're in first person, change instantly to third if possible
                m_positionCurrentIsSafe       = false;
                break;
            }

            m_lastRaycastDist = (float)(m_positionSafe - m_position).Length();

            if (m_debugDraw)
            {
                VRageRender.MyRenderProxy.DebugDrawSphere(m_positionSafe, 0.225f, Color.Purple, 1, false);
                VRageRender.MyRenderProxy.DebugDrawSphere(safePositionCandidate, 0.2f, Color.Azure, 1, false);
            }
        }
        /// <summary>
        /// Handles camera collisions with environment
        /// </summary>
        /// <returns>False if no correct position was found</returns>
        private void HandleIntersection(MyEntity controlledEntity)
        {
            Debug.Assert(controlledEntity != null);
            MyEntity parentEntity = controlledEntity.GetTopMostParent() ?? controlledEntity;
            var parentEntityAsCubeGrid = parentEntity as MyCubeGrid;
            if (parentEntityAsCubeGrid != null && parentEntityAsCubeGrid.IsStatic)
                parentEntity = controlledEntity;  // cancel previous assignment, topmost parent is a station, we need smaller bounding box

            // line from target to eye
            LineD line = new LineD(m_target, m_position);
            // oriented bb of the entity
            MyOrientedBoundingBoxD safeObb = GetEntitySafeOBB(parentEntity);
            // oriented bb of the entity + camera radius
            MyOrientedBoundingBoxD safeObbWithCollisionExtents = 
                new MyOrientedBoundingBoxD(safeObb.Center, safeObb.HalfExtent + (controlledEntity.Parent == null ? 0.5 : 2.0) * CAMERA_RADIUS, safeObb.Orientation);

            // start = target, end = eye
            // find safe start...
            LineD safeOBBLine = new LineD(line.From + line.Direction * 2 * safeObb.HalfExtent.Length(), line.From);
            double? safeIntersection = safeObbWithCollisionExtents.Intersects(ref safeOBBLine);
            Vector3D castStartSafe = safeIntersection != null ? (safeOBBLine.From + safeOBBLine.Direction * safeIntersection.Value) : m_target;

            if (controlledEntity.Parent != null && safeIntersection != null)
            {
                MatrixD shapeCastStart = MatrixD.CreateTranslation(castStartSafe);
                HkShape hkSphere = new HkSphereShape(CAMERA_RADIUS * 2);
                var hitInfo = MyPhysics.CastShapeReturnContactBodyData(m_target, hkSphere, ref shapeCastStart, 0, 0);

                //VRageRender.MyRenderProxy.DebugDrawCapsule(castStartSafe, m_target, CAMERA_RADIUS * 2, Color.Orange, false);
                
                MyEntity hitEntity = hitInfo.HasValue ? hitInfo.Value.HkHitInfo.GetHitEntity() as MyEntity : null;
                MyEntity entity = controlledEntity;

                var hitEntityWeldingGroup = hitEntity != null ? MyWeldingGroups.Static.GetGroup(hitEntity) : null;
                bool weldingGroupEquals = false;

                while (entity != null && !weldingGroupEquals)
                {
                    if (hitEntityWeldingGroup == MyWeldingGroups.Static.GetGroup(entity))
                        weldingGroupEquals = true;

                    entity = entity.Parent;
                }

                if (hitInfo.HasValue && hitEntityWeldingGroup != null && weldingGroupEquals)
                {
                    castStartSafe = castStartSafe + hitInfo.Value.HkHitInfo.HitFraction * (m_target - castStartSafe);
                }
                else
                {
                    safeObb = GetEntitySafeOBB(controlledEntity);
                    safeObbWithCollisionExtents = new MyOrientedBoundingBoxD(safeObb.Center, safeObb.HalfExtent + 0.5f * CAMERA_RADIUS, safeObb.Orientation);
                    safeIntersection = safeObbWithCollisionExtents.Intersects(ref safeOBBLine);
                    castStartSafe = safeIntersection != null ? (safeOBBLine.From + safeOBBLine.Direction * safeIntersection.Value) : m_target;
                }
                hkSphere.RemoveReference();
            }

            // raycast against occluders
            Vector3D safePositionCandidate;
            //double lastSafeMinimumDistance = m_safeMinimumDistance;
            m_safeMinimumDistance = controlledEntity is MyCharacter ? 0 : (castStartSafe - m_target).Length(); // store current safe minimum dist
            m_safeMinimumDistance = Math.Max(m_safeMinimumDistance, MIN_VIEWER_DISTANCE);
            //if (lastSafeMinimumDistance + 30.0f < m_safeMinimumDistance)
            //{
            //    castStartSafe = m_target + (castStartSafe - m_target) / m_safeMinimumDistance * lastSafeMinimumDistance;
            //    m_safeMinimumDistance = lastSafeMinimumDistance;
            //}
            Vector3D raycastOrigin = (controlledEntity is MyCharacter) ? m_target : castStartSafe;
            MyCameraRaycastResult raycastResult = RaycastOccludingObjects(controlledEntity, ref raycastOrigin, ref m_position,
                ref castStartSafe, out safePositionCandidate);

            // visual debugging :)
            if (m_debugDraw)
            {
                VRageRender.MyRenderProxy.DebugDrawOBB(safeObb, Color.Red, 0.1f, false, true);
                VRageRender.MyRenderProxy.DebugDrawOBB(safeObbWithCollisionExtents, Color.Yellow, 0.0f, false, true);
                VRageRender.MyRenderProxy.DebugDrawArrow3D(safeOBBLine.From, safeOBBLine.To, Color.White, Color.Purple,
                    false);
                VRageRender.MyRenderProxy.DebugDrawArrow3D(safeOBBLine.From, castStartSafe, Color.White, Color.Red,
                    false);
                VRageRender.MyRenderProxy.DebugDrawArrow3D(castStartSafe, m_position, Color.White, Color.Orange, false);

                VRageRender.MyRenderProxy.DebugDrawSphere(castStartSafe, 0.2f, Color.Green, 1.0f, false, true);
                VRageRender.MyRenderProxy.DebugDrawSphere(safePositionCandidate, 1.0f, Color.LightPink, 1, false);
            }

            switch (raycastResult)
            {
                case MyCameraRaycastResult.Ok:
                case MyCameraRaycastResult.FoundOccluder:
                    m_positionCurrentIsSafe = true;
                    {
                        double distFromCandidateToTarget = (safePositionCandidate - m_target).Length();
                        if (m_disableSpringThisFrame)
                        {
                            m_lastRaycastDist = (float) distFromCandidateToTarget;
                        }

                        if (!m_disableSpringThisFrame && 
                            ((distFromCandidateToTarget > m_lastRaycastDist + CAMERA_RADIUS && distFromCandidateToTarget > m_safeMinimumDistance)
                            || raycastResult == MyCameraRaycastResult.Ok))
                        {
                            // now we need it from the other side
                            double newDist = (safePositionCandidate - m_position).Length();
                            // new safe position is further from target => change over time (zoom out)
                            if (m_positionSafeZoomingOutTimeout <= 0)
                            {
                                float distDiffZoomSpeed = 1 -
                                                          MathHelper.Clamp((float) Math.Abs(m_lastRaycastDist - newDist), 0.0f,
                                                              1.0f - MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS);
                                m_positionSafeZoomingOutSpeed += distDiffZoomSpeed;
                                m_positionSafeZoomingOutSpeed = MathHelper.Clamp(m_positionSafeZoomingOutSpeed, 0.0f,
                                    1.0f);

                                Vector3D targetToPosSafe = m_positionSafe - m_target;
                                double lenTargetToPosSafe = targetToPosSafe.Length();
                                Vector3D rotatedPositionSafe = m_target +
                                                               Vector3D.Normalize(safePositionCandidate - m_target) *
                                                               lenTargetToPosSafe;
                                m_positionSafe = Vector3D.Lerp(rotatedPositionSafe, safePositionCandidate,
                                    m_positionSafeZoomingOutSpeed);
                            }
                            else
                            {
                                m_positionSafeZoomingOutTimeout -= MyEngineConstants.UPDATE_STEP_SIZE_IN_MILLISECONDS;

                                Vector3D targetToPosSafe = m_positionSafe - m_target;
                                double lenTargetToPosSafe = targetToPosSafe.Length();
                                m_positionSafe = m_target + Vector3D.Normalize(safePositionCandidate - m_target) * lenTargetToPosSafe;
                            }
                        }
                        else
                        {
                            // new safe position is closer or closer than safe distance => instant change
                            m_positionSafeZoomingOutSpeed = 0.0f;    // set zooming out speed to zero for next time
                            m_positionSafeZoomingOutTimeout = 0;// controlledEntity.Parent != null ? m_positionSafeZoomingOutDefaultTimeoutMs : 0;
                            m_positionSafe = safePositionCandidate;
                            m_disableSpringThisFrame = true;
                            m_positionCurrentIsSafe = distFromCandidateToTarget >= m_safeMinimumDistance;
                        }
                    }
                    break;
                //case MyCameraRaycastResult.FoundOccluderNoSpace:
                default:
                    m_positionSafeZoomingOutSpeed = 1.0f; // we're in first person, change instantly to third if possible
                    m_positionCurrentIsSafe = false;
                    break;    
            }

            m_lastRaycastDist = (float)(m_positionSafe - m_position).Length();

            if (m_debugDraw)
            {
                VRageRender.MyRenderProxy.DebugDrawSphere(m_positionSafe, 0.225f, Color.Purple, 1, false);
                VRageRender.MyRenderProxy.DebugDrawSphere(safePositionCandidate, 0.2f, Color.Azure, 1, false);
            }
        }
 private HkBvShape CreateDetectorShape(Vector3 extents, Mode mode)
 {
     if (mode == Mode.Ejector)
     {
         var phantom = new HkPhantomCallbackShape(phantom_EnterEjector, phantom_LeaveEjector);
         var detectorShape = new HkBoxShape(extents);
         return new HkBvShape(detectorShape, phantom, HkReferencePolicy.TakeOwnership);
     }
     else
     {
         var phantom = new HkPhantomCallbackShape(phantom_EnterConnector, phantom_LeaveConnector);
         var detectorShape = new HkSphereShape(extents.AbsMax());
         return new HkBvShape(detectorShape, phantom, HkReferencePolicy.TakeOwnership);
     }
 }
        protected override void DoDetection(bool useHead)
        {
            if (Character == MySession.ControlledEntity)
                MyHud.SelectedObjectHighlight.Visible = false;

            var head = Character.GetHeadMatrix(false);
            var headPos = head.Translation - (Vector3D)head.Forward * 0.3; // Move to center of head, we don't want eyes (in front of head)

            Vector3D from;
            Vector3D dir;

            if (!useHead)
            {
                //Ondrej version
                var cameraMatrix = MySector.MainCamera.WorldMatrix;
                dir = cameraMatrix.Forward;
                from = MyUtils.LinePlaneIntersection(headPos, (Vector3)dir, cameraMatrix.Translation, (Vector3)dir);
            }
            else
            {
                //Petr version
                dir = head.Forward;
                from = headPos;
            }

            Vector3D to = from + dir * MyConstants.DEFAULT_INTERACTIVE_DISTANCE;

            MatrixD matrix = MatrixD.CreateTranslation(from);
            HkShape shape = new HkSphereShape(SHAPE_RADIUS);
            IMyEntity hitEntity = null;
            int shapeKey = -1;
            Vector3D hitPosition = Vector3D.Zero;
            m_hits.Clear();

            try
            {
                MyPhysics.CastShapeReturnContactBodyDatas(to, shape, ref matrix, 0, 0f, m_hits);

                int index = 0;
                while (index < m_hits.Count && (m_hits[index].Body == null || m_hits[index].Body.UserObject == Character.Physics
                    || (Character.VirtualPhysics != null && m_hits[index].Body.UserObject == Character.VirtualPhysics) || m_hits[index].Body.HasProperty(HkCharacterRigidBody.MANIPULATED_OBJECT))) // Skip invalid hits and self character
                {
                    index++;
                }

                if (index < m_hits.Count)
                {
                    hitEntity = m_hits[index].Body.GetEntity();
                    shapeKey = m_hits[index].ShapeKey;
                    hitPosition = m_hits[index].HitPosition;
                }
            }
            finally
            {
                shape.RemoveReference();
            }

            bool hasInteractive = false;

            var interactive = hitEntity as IMyUseObject;
            DetectedEntity = hitEntity;

            if (hitEntity != null)
            {
                MyUseObjectsComponentBase useObject = null;
                hitEntity.Components.TryGet<MyUseObjectsComponentBase>(out useObject);
                if (useObject != null)
                {
                    interactive = useObject.GetInteractiveObject(shapeKey);
                }
            }

            if (UseObject != null && interactive != null && UseObject != interactive)
            {
                UseObject.OnSelectionLost();
            }

            if (interactive != null && interactive.SupportedActions != UseActionEnum.None && (Vector3D.Distance(from, hitPosition)) < interactive.InteractiveDistance && Character == MySession.ControlledEntity)
            {
                MyHud.SelectedObjectHighlight.Visible = true;
                MyHud.SelectedObjectHighlight.InteractiveObject = interactive;

                UseObject = interactive;
                hasInteractive = true;
            }

            if (!hasInteractive)
            {
                if (UseObject != null)
                    UseObject.OnSelectionLost();

                UseObject = null;
            }
        }
Beispiel #29
0
        private unsafe void AddPhysicalShape(HkShape shape, Matrix rdWorldMatrix)
        {
            switch (shape.ShapeType)
            {
            case HkShapeType.Sphere:
            {
                HkSphereShape shape7 = (HkSphereShape)shape;
                m_icosphereMesh.AddTrianglesToWorldVertices(rdWorldMatrix.Translation, shape7.Radius);
                return;
            }

            case HkShapeType.Cylinder:
            case HkShapeType.Triangle:
            case HkShapeType.TriSampledHeightFieldCollection:
            case HkShapeType.TriSampledHeightFieldBvTree:
                break;

            case HkShapeType.Box:
            {
                HkBoxShape   shape2 = (HkBoxShape)shape;
                Vector3D     min    = new Vector3D((double)-shape2.HalfExtents.X, (double)-shape2.HalfExtents.Y, (double)-shape2.HalfExtents.Z);
                Vector3D     max    = new Vector3D((double)shape2.HalfExtents.X, (double)shape2.HalfExtents.Y, (double)shape2.HalfExtents.Z);
                BoundingBoxD bbox   = new BoundingBoxD(min, max);
                this.BoundingBoxToTranslatedTriangles(bbox, rdWorldMatrix);
                return;
            }

            case HkShapeType.Capsule:
                return;

            case HkShapeType.ConvexVertices:
            {
                Vector3 vector;
                HkConvexVerticesShape shape9   = (HkConvexVerticesShape)shape;
                HkGeometry            geometry = new HkGeometry();
                shape9.GetGeometry(geometry, out vector);
                int triangleIndex = 0;
                while (true)
                {
                    int num2;
                    int num3;
                    int num4;
                    int num5;
                    if (triangleIndex >= geometry.TriangleCount)
                    {
                        int vertexIndex = 0;
                        while (true)
                        {
                            if (vertexIndex >= geometry.VertexCount)
                            {
                                WorldVerticesInfo worldVertices = m_worldVertices;
                                worldVertices.VerticesMaxValue += geometry.VertexCount;
                                break;
                            }
                            Vector3  vertex     = geometry.GetVertex(vertexIndex);
                            Vector3 *vectorPtr1 = (Vector3 *)ref vertex;
                            Vector3.Transform(ref (Vector3) ref vectorPtr1, ref rdWorldMatrix, out vertex);
                            m_worldVertices.Vertices.Add(vertex);
                            vertexIndex++;
                        }
                        break;
                    }
                    geometry.GetTriangle(triangleIndex, out num2, out num3, out num4, out num5);
                    m_worldVertices.Triangles.Add(m_worldVertices.VerticesMaxValue + num2);
                    m_worldVertices.Triangles.Add(m_worldVertices.VerticesMaxValue + num3);
                    m_worldVertices.Triangles.Add(m_worldVertices.VerticesMaxValue + num4);
                    triangleIndex++;
                }
                break;
            }

            case HkShapeType.List:
            {
                HkShapeContainerIterator iterator = ((HkListShape)shape).GetIterator();
                while (iterator.IsValid)
                {
                    this.AddPhysicalShape(iterator.CurrentValue, rdWorldMatrix);
                    iterator.Next();
                }
                return;
            }

            case HkShapeType.Mopp:
            {
                HkMoppBvTreeShape shape4 = (HkMoppBvTreeShape)shape;
                this.AddPhysicalShape((HkShape)shape4.ShapeCollection, rdWorldMatrix);
                return;
            }

            case HkShapeType.ConvexTranslate:
            {
                HkConvexTranslateShape shape6 = (HkConvexTranslateShape)shape;
                Matrix matrix = Matrix.CreateTranslation(shape6.Translation);
                this.AddPhysicalShape((HkShape)shape6.ChildShape, matrix * rdWorldMatrix);
                return;
            }

            case HkShapeType.ConvexTransform:
            {
                HkConvexTransformShape shape5 = (HkConvexTransformShape)shape;
                this.AddPhysicalShape((HkShape)shape5.ChildShape, shape5.Transform * rdWorldMatrix);
                return;
            }

            default:
                return;
            }
        }
        /// <summary>
        /// Spawns bag around position given by "baseTransform", checks all 4 directions around - forwards (forward, right, backward, left) and on each such direction moves test sphere 
        /// in 3 directions forward (frontChecks), sides (perpendicular to forward direction - rights) and up. If spawn position is not found then position above "worldAabbTopPosition"
        /// is selected.
        /// </summary>
        private static MyEntity SpawnBagAround(MyEntity itemOwner, MyContainerDefinition bagDefinition,
            int sideCheckCount = 3, int frontCheckCount = 2, int upCheckCount = 5, float stepSize = 1f)
        {
            Debug.Assert(Sandbox.Game.Multiplayer.Sync.IsServer);

            Vector3D? finalPos = null;

            // Model sphere
            MyModel bagModel = null;
            foreach (var componentDef in bagDefinition.DefaultComponents)
            {
                if (typeof(MyObjectBuilder_ModelComponent).IsAssignableFrom(componentDef.BuilderType))
                {
                    MyComponentDefinitionBase componentDefinition = null;
                    var componentSubtype = bagDefinition.Id.SubtypeId;
                    if (componentDef.SubtypeId.HasValue)
                        componentSubtype = componentDef.SubtypeId.Value;

                    if (MyComponentContainerExtension.TryGetComponentDefinition(componentDef.BuilderType, componentSubtype, out componentDefinition))
                    {
                        var modelComponentDef = componentDefinition as MyModelComponentDefinition;
                        Debug.Assert(modelComponentDef != null);
                        if (modelComponentDef != null)
                            bagModel = MyModels.GetModelOnlyData(modelComponentDef.Model);
                    }

                    break;
                }
            }

            Debug.Assert(bagModel != null);
            if (bagModel == null)
                return null;

            float bagBoxRadius = bagModel.BoundingBox.HalfExtents.Max();
            HkShape sphere = new HkSphereShape(bagBoxRadius);

            try
            {
                Vector3D basePos = itemOwner.PositionComp.WorldMatrix.Translation;
                float step = bagBoxRadius * stepSize;

                // Calculate right, up and forward vectors from gravity
                Vector3 upDir = -MyGravityProviderSystem.CalculateNaturalGravityInPoint(itemOwner.PositionComp.WorldMatrix.Translation);
                if (upDir == Vector3.Zero)
                    upDir = Vector3.Up;
                else
                    upDir.Normalize();

                Vector3 forwardDir;
                upDir.CalculatePerpendicularVector(out forwardDir);

                Vector3 rightDir = Vector3.Cross(forwardDir, upDir);
                rightDir.Normalize();

                Vector3D currentPos;
                Quaternion rot = Quaternion.Identity;

                Vector3[] forwards = new Vector3[] 
                {
                    forwardDir,
                    rightDir,
                    -forwardDir,
                    -rightDir
                };

                Vector3[] rights = new Vector3[] 
                {
                    rightDir,
                    -forwardDir,
                    -rightDir,
                    forwardDir
                };

                // All sides
                for (int i = 0; i < forwards.Length && finalPos == null; ++i)
                {
                    var forward = forwards[i];
                    var right = rights[i];

                    // Move forward
                    for (int frontMove = 0; frontMove < frontCheckCount && finalPos == null; ++frontMove)
                    {
                        Vector3D sidePosBase = basePos + 0.25f * forward + bagBoxRadius * forward + frontMove * step * forward - 0.5f * (sideCheckCount - 1) * step * right;

                        // Move perp to forward
                        for (int sideMove = 0; sideMove < sideCheckCount && finalPos == null; ++sideMove)
                        {
                            // Move up
                            for (int upMove = 0; upMove < upCheckCount && finalPos == null; ++upMove)
                            {
                                currentPos = sidePosBase + sideMove * step * right + upMove * step * upDir;

                                if (MyEntities.IsInsideWorld(currentPos) && !MyEntities.IsShapePenetrating(sphere, ref currentPos, ref rot))
                                {
                                    BoundingSphereD boundingSphere = new BoundingSphereD(currentPos, bagBoxRadius);
                                    MyVoxelBase overlappedVoxelmap = MySession.Static.VoxelMaps.GetOverlappingWithSphere(ref boundingSphere);

                                    if (overlappedVoxelmap == null)
                                    {
                                        finalPos = currentPos;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }

                // If not found position then select position above aabb's top.
                if (finalPos == null)
                {
                    MyOrientedBoundingBoxD obb = new MyOrientedBoundingBoxD((BoundingBoxD)itemOwner.PositionComp.LocalAABB, itemOwner.PositionComp.WorldMatrix);
                    Vector3D[] corners = new Vector3D[8];
                    obb.GetCorners(corners, 0);
                    float dotUp = float.MinValue;
                    foreach (var corner in corners)
                    {
                        var localDot = Vector3.Dot(corner - obb.Center, upDir);
                        dotUp = Math.Max(dotUp, localDot);
                    }

                    finalPos = itemOwner.PositionComp.WorldMatrix.Translation;
                    Debug.Assert(dotUp > 0);
                    if (dotUp > 0)
                        finalPos = obb.Center + dotUp * upDir;
                }
            }
            finally
            {
                sphere.RemoveReference();
            }

            Debug.Assert(finalPos != null);

            MatrixD transform = itemOwner.PositionComp.WorldMatrix;
            transform.Translation = finalPos.Value;

            MyEntity bagEntity = MyEntities.CreateFromComponentContainerDefinitionAndAdd(bagDefinition.Id);
            if (bagEntity == null)
                return null;

            bagEntity.PositionComp.SetWorldMatrix(transform);

            bagEntity.Physics.LinearVelocity = Vector3.Zero;
            bagEntity.Physics.AngularVelocity = Vector3.Zero;

            return bagEntity;
        }
Beispiel #31
0
        private void DoDetection(bool useHead, bool doModelIntersection)
        {
            if (Character == MySession.Static.ControlledEntity)
            {
                MyHud.SelectedObjectHighlight.RemoveHighlight();
            }

            var head    = Character.GetHeadMatrix(false);
            var headPos = head.Translation - (Vector3D)head.Forward * 0.3; // Move to center of head, we don't want eyes (in front of head)

            Vector3D from;
            Vector3D dir;

            if (!useHead)
            {
                //Ondrej version
                //var cameraMatrix = MySector.MainCamera.WorldMatrix;
                var cameraMatrix = Character.Get3rdBoneMatrix(true, true);
                dir  = cameraMatrix.Forward;
                from = MyUtils.LinePlaneIntersection(headPos, (Vector3)dir, cameraMatrix.Translation, (Vector3)dir);
            }
            else
            {
                //Petr version
                dir  = head.Forward;
                from = headPos;
            }

            Vector3D to = from + dir * 2.5;//MyConstants.DEFAULT_INTERACTIVE_DISTANCE;

            StartPosition = from;

            MatrixD   matrix    = MatrixD.CreateTranslation(from);
            HkShape   shape     = new HkSphereShape(ShapeRadius);
            IMyEntity hitEntity = null;

            ShapeKey    = uint.MaxValue;
            HitPosition = Vector3D.Zero;
            HitNormal   = Vector3.Zero;
            HitMaterial = MyStringHash.NullOrEmpty;
            HitTag      = null;
            m_hits.Clear();

            Vector3 interactivePosition = Vector3D.Zero;

            try
            {
                EnableDetectorsInArea(from);

                MyPhysics.CastShapeReturnContactBodyDatas(to, shape, ref matrix, 0, 0f, m_hits);

                m_hits.Sort(delegate(MyPhysics.HitInfo info1, MyPhysics.HitInfo info2)
                {
                    float dot1 = Vector3.Dot(head.Forward, Vector3.Normalize(info1.Position - StartPosition));
                    float dot2 = Vector3.Dot(head.Forward, Vector3.Normalize(info2.Position - StartPosition));
                    return(dot1.CompareTo(dot2));
                });

                if (m_hits.Count > 0)
                {
                    int index = 0;

                    bool isValidBlock    = false;
                    bool isPhysicalBlock = false;

                    do
                    {
                        HkRigidBody body   = m_hits[index].HkHitInfo.Body;
                        IMyEntity   entity = m_hits[index].HkHitInfo.GetHitEntity();

                        if (entity is VRage.Game.Entity.MyEntitySubpart)
                        {
                            entity = entity.Parent;
                        }

                        isValidBlock = body != null && entity != null && entity != Character && !body.HasProperty(HkCharacterRigidBody.MANIPULATED_OBJECT);

                        isPhysicalBlock = entity != null && entity.Physics != null;

                        if (hitEntity == null && isValidBlock)
                        {
                            hitEntity = entity;
                            ShapeKey  = m_hits[index].HkHitInfo.GetShapeKey(0);
                        }

                        // Set hit material etc. only for object's that have physical representation in the world, this exclude detectors
                        if (HitMaterial.Equals(MyStringHash.NullOrEmpty) && isValidBlock && isPhysicalBlock)
                        {
                            HitBody     = body;
                            HitNormal   = m_hits[index].HkHitInfo.Normal;
                            HitPosition = m_hits[index].GetFixedPosition();
                            HitMaterial = body.GetBody().GetMaterialAt(HitPosition);

                            interactivePosition = HitPosition;
                        }
                        else if (body != null)
                        {
                            interactivePosition = m_hits[index].GetFixedPosition();
                        }

                        index++;
                    } while (index < m_hits.Count && (!isValidBlock || !isPhysicalBlock));
                }
            }
            finally
            {
                shape.RemoveReference();
            }

            bool hasInteractive = false;

            var interactive = hitEntity as IMyUseObject;

            DetectedEntity = hitEntity;

            if (hitEntity != null)
            {
                MyUseObjectsComponentBase useObject = null;
                hitEntity.Components.TryGet <MyUseObjectsComponentBase>(out useObject);
                if (useObject != null)
                {
                    interactive = useObject.GetInteractiveObject(ShapeKey);
                }

                // Do accurate collision checking on model
                if (doModelIntersection)
                {
                    LineD line      = new LineD(from, to);
                    var   character = hitEntity as MyCharacter;
                    if (character == null)
                    {
                        MyIntersectionResultLineTriangleEx?result;
                        bool success = hitEntity.GetIntersectionWithLine(ref line, out result, IntersectionFlags.ALL_TRIANGLES);
                        if (success)
                        {
                            HitPosition = result.Value.IntersectionPointInWorldSpace;
                            HitNormal   = result.Value.NormalInWorldSpace;
                        }
                    }
                    else
                    {
                        bool success = character.GetIntersectionWithLine(ref line, ref CharHitInfo);
                        if (success)
                        {
                            HitPosition = CharHitInfo.Triangle.IntersectionPointInWorldSpace;
                            HitNormal   = CharHitInfo.Triangle.NormalInWorldSpace;
                            HitTag      = CharHitInfo;
                        }
                    }
                }
            }

            if (UseObject != null && interactive != null && UseObject != interactive)
            {
                UseObject.OnSelectionLost();
            }

            if (interactive != null && interactive.SupportedActions != UseActionEnum.None && (Vector3D.Distance(from, interactivePosition)) < interactive.InteractiveDistance && Character == MySession.Static.ControlledEntity)
            {
                HandleInteractiveObject(interactive);

                UseObject      = interactive;
                hasInteractive = true;
            }

            if (!hasInteractive)
            {
                if (UseObject != null)
                {
                    UseObject.OnSelectionLost();
                }

                UseObject = null;
            }

            DisableDetectors();
        }
        protected override bool CanPlaceRotor(MyMotorRotor rotorBlock, long builtBy)
        {
            BoundingSphereD sphere = rotorBlock.Model.BoundingSphere;
            sphere.Center = Vector3D.Transform(sphere.Center, rotorBlock.WorldMatrix);
            CubeGrid.GetBlocksInsideSphere(ref sphere, m_tmpSet);
            HkSphereShape spShape = new HkSphereShape((float)sphere.Radius);
            Quaternion q = Quaternion.Identity;//Quaternion.CreateFromForwardUp(rotorBlock.WorldMatrix.Forward, rotorBlock.WorldMatrix.Up);
            var position = rotorBlock.WorldMatrix.Translation;
            MyPhysics.GetPenetrationsShape(spShape, ref position, ref q, m_tmpList, MyPhysics.CharacterNetworkCollisionLayer);
            if (m_tmpSet.Count > 1 || m_tmpList.Count > 0)
            {
                m_tmpList.Clear();
				m_tmpSet.Clear();
                if (builtBy == MySession.LocalPlayerId)
                    MyHud.Notifications.Add(MyNotificationSingletons.WheelNotPlaced);
                return false;
            }
            m_tmpList.Clear();
			m_tmpSet.Clear();

            return true;
        }
		public void GetFracturesInSphere(ref BoundingSphereD searchSphere, ref List<MyFracturedPiece> output)
		{
			var activeFractures = m_piecesTimesOfDeath.Keys;
			
			HkShape shape = new HkSphereShape((float)searchSphere.Radius);
			try
			{
				MyPhysics.GetPenetrationsShape(shape, ref searchSphere.Center, ref Quaternion.Identity, m_rigidList, MyPhysics.NotCollideWithStaticLayer);
			
				foreach(var rigidBody in m_rigidList)
				{
					var fracture = rigidBody.GetCollisionEntity() as MyFracturedPiece;
					if (fracture != null)
						output.Add(fracture);
				}
			}
			finally
			{
				m_rigidList.Clear();
				shape.RemoveReference();
			}
		}
Beispiel #34
0
        private void ThrustDamage()
        {
            if (m_flames.Count > 0 && MySession.Static.ThrusterDamage && Sync.IsServer && IsWorking && CubeGrid.InScene && CubeGrid.Physics != null && CubeGrid.Physics.Enabled)
            {
                if (CurrentStrength == 0 && !MyFakes.INACTIVE_THRUSTER_DMG)
                    return;

                UpdateThrustFlame();

                foreach (var flameInfo in m_flames)
                {
                    var l = GetDamageCapsuleLine(flameInfo);
                    HkShape shape;
                    if (l.Length != 0)
                        shape = new HkCapsuleShape(Vector3.Zero, l.To - l.From, flameInfo.Radius * BlockDefinition.FlameDamageLengthScale);
                    else
                        shape = new HkSphereShape(flameInfo.Radius * BlockDefinition.FlameDamageLengthScale);
                    MyPhysics.GetPenetrationsShape(shape, ref l.From, ref Quaternion.Identity, m_flameCollisionsList, 0);
                    shape.RemoveReference();

                    foreach (var obj in m_flameCollisionsList)
                    {
                        var ent = obj.GetCollisionEntity();
                        if (ent == null || ent.Equals(this))
                            continue;

                        if (!(ent is MyCharacter))
                            ent = ent.GetTopMostParent();
                        if (m_damagedEntities.Contains(ent))
                            continue;
                        else
                            m_damagedEntities.Add(ent);

                        if (ent is IMyDestroyableObject)
                            (ent as IMyDestroyableObject).DoDamage(flameInfo.Radius * BlockDefinition.FlameDamage * 10, MyDamageType.Environment, true, attackerId: EntityId);
                        else if (ent is MyCubeGrid)
                        {
                            var grid = ent as MyCubeGrid;
                            if (grid.BlocksDestructionEnabled)
                            {
                                DamageGrid(flameInfo, l, grid);
                            }
                        }
                    }
                    m_damagedEntities.Clear();
                    m_flameCollisionsList.Clear();
                }
            }
        }
Beispiel #35
0
        protected override void DoDetection(bool useHead)
        {
            if (Character == MySession.Static.ControlledEntity)
            {
                MyHud.SelectedObjectHighlight.RemoveHighlight();
            }

            var head    = Character.GetHeadMatrix(false);
            var headPos = head.Translation - (Vector3D)head.Forward * 0.3; // Move to center of head, we don't want eyes (in front of head)

            Vector3D from;
            Vector3D dir;

            if (!useHead)
            {
                //Ondrej version
                var cameraMatrix = MySector.MainCamera.WorldMatrix;
                //var cameraMatrix = Character.Get3rdBoneMatrix(true, true);
                dir  = cameraMatrix.Forward;
                from = MyUtils.LinePlaneIntersection(headPos, (Vector3)dir, cameraMatrix.Translation, (Vector3)dir);
            }
            else
            {
                //Petr version
                dir  = head.Forward;
                from = headPos;
            }

            Vector3D to = from + dir * MyConstants.DEFAULT_INTERACTIVE_DISTANCE;

            StartPosition = from;

            MatrixD   matrix    = MatrixD.CreateTranslation(from);
            HkShape   shape     = new HkSphereShape(ShapeRadius);
            IMyEntity hitEntity = null;

            ShapeKey    = uint.MaxValue;
            HitPosition = Vector3D.Zero;
            HitNormal   = Vector3.Zero;
            HitMaterial = MyStringHash.NullOrEmpty;
            m_hits.Clear();

            try
            {
                EnableDetectorsInArea(from);

                MyPhysics.CastShapeReturnContactBodyDatas(to, shape, ref matrix, 0, 0f, m_hits);

                if (m_hits.Count > 0)
                {
                    int index = 0;

                    bool isValidBlock    = false;
                    bool isPhysicalBlock = false;

                    do
                    {
                        isValidBlock = m_hits[index].HkHitInfo.Body != null && m_hits[index].HkHitInfo.GetHitEntity() != Character && m_hits[index].HkHitInfo.GetHitEntity() != null && !m_hits[index].HkHitInfo.Body.HasProperty(HkCharacterRigidBody.MANIPULATED_OBJECT);

                        isPhysicalBlock = m_hits[index].HkHitInfo.GetHitEntity() != null && m_hits[index].HkHitInfo.GetHitEntity().Physics != null;

                        if (hitEntity == null && isValidBlock)
                        {
                            hitEntity = m_hits[index].HkHitInfo.GetHitEntity();
                            ShapeKey  = m_hits[index].HkHitInfo.GetShapeKey(0);
                        }

                        // Set hit material etc. only for object's that have physical representation in the world, this exclude detectors
                        if (HitMaterial.Equals(MyStringHash.NullOrEmpty) && isValidBlock && isPhysicalBlock)
                        {
                            HitBody     = m_hits[index].HkHitInfo.Body;
                            HitPosition = m_hits[index].Position;
                            HitNormal   = m_hits[index].HkHitInfo.Normal;
                            HitMaterial = m_hits[index].HkHitInfo.Body.GetBody().GetMaterialAt(HitPosition + HitNormal * 0.1f);
                        }

                        index++;
                    } while (index < m_hits.Count && (!isValidBlock || !isPhysicalBlock));
                }
            }
            finally
            {
                shape.RemoveReference();
            }

            bool hasInteractive = false;

            var interactive = hitEntity as IMyUseObject;

            DetectedEntity = hitEntity;

            if (hitEntity != null)
            {
                MyUseObjectsComponentBase useObject = null;
                hitEntity.Components.TryGet <MyUseObjectsComponentBase>(out useObject);
                if (useObject != null)
                {
                    interactive = useObject.GetInteractiveObject(ShapeKey);
                }
            }

            if (UseObject != null && interactive != null && UseObject != interactive)
            {
                UseObject.OnSelectionLost();
            }

            if (interactive != null && interactive.SupportedActions != UseActionEnum.None && (Vector3D.Distance(from, HitPosition)) < interactive.InteractiveDistance && Character == MySession.Static.ControlledEntity)
            {
                HandleInteractiveObject(interactive);

                UseObject      = interactive;
                hasInteractive = true;
            }

            if (!hasInteractive)
            {
                if (UseObject != null)
                {
                    UseObject.OnSelectionLost();
                }

                UseObject = null;
            }

            DisableDetectors();
        }
        protected override void DoDetection(bool useHead)
        {
            if (Character == MySession.ControlledEntity)
            {
                MyHud.SelectedObjectHighlight.Visible = false;
            }

            var head    = Character.GetHeadMatrix(false);
            var headPos = head.Translation - (Vector3D)head.Forward * 0.3; // Move to center of head, we don't want eyes (in front of head)

            Vector3D from;
            Vector3D dir;

            if (!useHead)
            {
                //Ondrej version
                var cameraMatrix = MySector.MainCamera.WorldMatrix;
                dir  = cameraMatrix.Forward;
                from = MyUtils.LinePlaneIntersection(headPos, (Vector3)dir, cameraMatrix.Translation, (Vector3)dir);
            }
            else
            {
                //Petr version
                dir  = head.Forward;
                from = headPos;
            }

            Vector3D to = from + dir * MyConstants.DEFAULT_INTERACTIVE_DISTANCE;

            MatrixD   matrix      = MatrixD.CreateTranslation(from);
            HkShape   shape       = new HkSphereShape(SHAPE_RADIUS);
            IMyEntity hitEntity   = null;
            int       shapeKey    = -1;
            Vector3D  hitPosition = Vector3D.Zero;

            m_hits.Clear();

            try
            {
                MyPhysics.CastShapeReturnContactBodyDatas(to, shape, ref matrix, 0, 0f, m_hits);

                int index = 0;
                while (index < m_hits.Count && (m_hits[index].Body == null || m_hits[index].Body.UserObject == Character.Physics ||
                                                (Character.VirtualPhysics != null && m_hits[index].Body.UserObject == Character.VirtualPhysics) || m_hits[index].Body.HasProperty(HkCharacterRigidBody.MANIPULATED_OBJECT))) // Skip invalid hits and self character
                {
                    index++;
                }

                if (index < m_hits.Count)
                {
                    hitEntity   = m_hits[index].Body.GetEntity();
                    shapeKey    = m_hits[index].ShapeKey;
                    hitPosition = m_hits[index].HitPosition;
                }
            }
            finally
            {
                shape.RemoveReference();
            }

            bool hasInteractive = false;

            var interactive = hitEntity as IMyUseObject;

            if (hitEntity != null)
            {
                MyUseObjectsComponentBase useObject = null;
                hitEntity.Components.TryGet <MyUseObjectsComponentBase>(out useObject);
                if (useObject != null)
                {
                    interactive = useObject.GetInteractiveObject(shapeKey);
                }
            }

            if (UseObject != null && interactive != null && UseObject != interactive)
            {
                UseObject.OnSelectionLost();
            }

            if (interactive != null && interactive.SupportedActions != UseActionEnum.None && (Vector3D.Distance(from, hitPosition)) < interactive.InteractiveDistance && Character == MySession.ControlledEntity)
            {
                MyHud.SelectedObjectHighlight.Visible           = true;
                MyHud.SelectedObjectHighlight.InteractiveObject = interactive;

                UseObject      = interactive;
                hasInteractive = true;
            }

            if (!hasInteractive)
            {
                if (UseObject != null)
                {
                    UseObject.OnSelectionLost();
                }

                UseObject = null;
            }
        }
Beispiel #37
0
            private void InitInternal()
            {
                // TODO: This will be fixed and made much more simple once ore models are done
                // https://app.asana.com/0/6594565324126/10473934569658
                var physicalItem = MyDefinitionManager.Static.GetPhysicalItemDefinition(Item.Content);

                var ore = Item.Content as MyObjectBuilder_Ore;

                string model = physicalItem.Model;
                float  scale = 1.0f;

                VoxelMaterial = null;
                if (ore != null)
                {
                    foreach (var mat in MyDefinitionManager.Static.GetVoxelMaterialDefinitions())
                    {
                        if (mat.MinedOre == ore.SubtypeName)
                        {
                            VoxelMaterial = mat;
                            model         = MyDebris.GetRandomDebrisVoxel();
                            scale         = (float)Math.Pow((float)Item.Amount * physicalItem.Volume / MyDebris.VoxelDebrisModelVolume, 0.333f);
                            break;
                        }
                    }
                }

                if (scale < 0.15f)
                {
                    scale = 0.15f;
                }

                var voxelRender = (Entity.Render as MyRenderComponentDebrisVoxel);

                voxelRender.VoxelMaterialIndex = VoxelMaterial.Index;
                voxelRender.TexCoordOffset     = 5;
                voxelRender.TexCoordScale      = 8;
                Entity.Init(new StringBuilder("Meteor"), model, null, null, null);

                Entity.PositionComp.Scale = scale; // Must be set after init

                var           massProperties = HkInertiaTensorComputer.ComputeSphereVolumeMassProperties(Entity.PositionComp.LocalVolume.Radius, (float)(4 / 3f * Math.PI * Math.Pow(Entity.PositionComp.LocalVolume.Radius, 3)) * 3.7f);
                HkSphereShape transform      = new HkSphereShape(Entity.PositionComp.LocalVolume.Radius);

                if (Entity.Physics != null)
                {
                    Entity.Physics.Close();
                }

                Entity.Physics = new MyPhysicsBody(Entity, RigidBodyFlag.RBF_BULLET);
                Entity.Physics.ReportAllContacts = true;
                Entity.GetPhysicsBody().CreateFromCollisionObject(transform, Vector3.Zero, MatrixD.Identity, massProperties, MyPhysics.CollisionLayers.DefaultCollisionLayer);
                Entity.Physics.Enabled = true;
                Entity.Physics.RigidBody.ContactPointCallbackEnabled = true;
                Entity.GetPhysicsBody().ContactPointCallback += RigidBody_ContactPointCallback;
                transform.Base.RemoveReference();
                Entity.Physics.PlayCollisionCueEnabled = true;

                m_timeCreated = MySandboxGame.TotalGamePlayTimeInMilliseconds;

                NeedsUpdate = MyEntityUpdateEnum.EACH_FRAME | MyEntityUpdateEnum.EACH_100TH_FRAME;

                StartLoopSound();
            }
        private void DoDetection(bool useHead, bool doModelIntersection)
        {
            if (Character == MySession.Static.ControlledEntity)
                MyHud.SelectedObjectHighlight.RemoveHighlight();

            var head = Character.GetHeadMatrix(false);
            Vector3D from = head.Translation;
            Vector3D dir = head.Forward;

            if (!useHead)
            {
                var headPos = head.Translation - (Vector3D)head.Forward * 0.3; // Move to center of head, we don't want eyes (in front of head)

                if (Character == MySession.Static.LocalCharacter)
                {
                    from = MySector.MainCamera.WorldMatrix.Translation;
                    dir = MySector.MainCamera.WorldMatrix.Forward;

                    from = MyUtils.LinePlaneIntersection(headPos, (Vector3)dir, from, (Vector3)dir);
                }
                else
                {
                    from = headPos;
                    dir = head.Forward;
                }
            }

            Vector3D to = from + dir * 2.5;//MyConstants.DEFAULT_INTERACTIVE_DISTANCE;

            StartPosition = from;

            MatrixD matrix = MatrixD.CreateTranslation(from);
            HkShape shape = new HkSphereShape(ShapeRadius);
            IMyEntity hitEntity = null;
            ShapeKey = uint.MaxValue;
            HitPosition = Vector3D.Zero;
            HitNormal = Vector3.Zero;
            HitMaterial = MyStringHash.NullOrEmpty;
            HitTag = null;
            m_hits.Clear();

            Vector3 interactivePosition = Vector3D.Zero;

            try
            {
                EnableDetectorsInArea(from);

                MyPhysics.CastShapeReturnContactBodyDatas(to, shape, ref matrix, 0, 0f, m_hits);

                m_rayOrigin = from;
                m_rayDirection = dir;
                m_hits.Sort(CompareHits);
                
                if (m_hits.Count > 0)
                {
                    bool isValidBlock = false;
                    bool isPhysicalBlock = false;

                    for (int index = 0; index < m_hits.Count; index++)
                    {
                        HkRigidBody body = m_hits[index].HkHitInfo.Body;
                        IMyEntity entity = m_hits[index].HkHitInfo.GetHitEntity();

                        // Ignore self-interaction
                        if (entity == Character) continue;

                        if (entity is VRage.Game.Entity.MyEntitySubpart)
                        {
                            entity = entity.Parent;
                        }

                        isValidBlock = body != null && entity != null && entity != Character && !body.HasProperty(HkCharacterRigidBody.MANIPULATED_OBJECT);
                        isPhysicalBlock = entity != null && entity.Physics != null;

                        if (hitEntity == null && isValidBlock)
                        {
                            hitEntity = entity;
                            ShapeKey = m_hits[index].HkHitInfo.GetShapeKey(0);
                        }

                        // If hit-entity is a grid, raycast it to see which block we hit first
                        if (entity is MyCubeGrid)
                        {
                            MyCubeGrid grid = entity as MyCubeGrid;
                            List<MyCube> cubeList = grid.RayCastBlocksAllOrdered(from, to);
                            if (cubeList != null && cubeList.Count > 0)
                            {
                                var slimblock = cubeList[0].CubeBlock;
                                if (slimblock.FatBlock != null)
                                {
                                    entity = slimblock.FatBlock;
                                    isPhysicalBlock = true;
                                    hitEntity = entity;
                                    ShapeKey = 0;
                                }
                            }
                        }

                        // Set hit material etc. only for object's that have physical representation in the world, this exclude detectors
                        if (HitMaterial.Equals(MyStringHash.NullOrEmpty) && isValidBlock && isPhysicalBlock)
                        {
                            HitBody = body;
                            HitNormal = m_hits[index].HkHitInfo.Normal;
                            HitPosition = m_hits[index].GetFixedPosition();
                            HitMaterial = body.GetBody().GetMaterialAt(HitPosition);

                            interactivePosition = HitPosition;
                            break;
                        }
                        else if (body != null)
                        {
                            interactivePosition = m_hits[index].GetFixedPosition();
                            break;
                        }

                        index++;
                    }
                }
            }
            finally
            {
                shape.RemoveReference();
            }

            bool hasInteractive = false;

            var interactive = hitEntity as IMyUseObject;
            DetectedEntity = hitEntity;

            if (hitEntity != null)
            {
                MyUseObjectsComponentBase useObject = null;
                hitEntity.Components.TryGet<MyUseObjectsComponentBase>(out useObject);
                if (useObject != null)
                {
                    interactive = useObject.GetInteractiveObject(ShapeKey);
                }

                // Do accurate collision checking on model
                if (doModelIntersection)
                {
                    LineD line = new LineD(from, to);
                    var character = hitEntity as MyCharacter;
                    if (character == null)
                    {
                        MyIntersectionResultLineTriangleEx? result;
                        bool success = hitEntity.GetIntersectionWithLine(ref line, out result, IntersectionFlags.ALL_TRIANGLES);
                        if (success)
                        {
                            HitPosition = result.Value.IntersectionPointInWorldSpace;
                            HitNormal = result.Value.NormalInWorldSpace;
                        }
                    }
                    else
                    {
                        bool success = character.GetIntersectionWithLine(ref line, ref CharHitInfo);
                        if (success)
                        {
                            HitPosition = CharHitInfo.Triangle.IntersectionPointInWorldSpace;
                            HitNormal = CharHitInfo.Triangle.NormalInWorldSpace;
                            HitTag = CharHitInfo;
                        }
                    }
                }
            }

            if (UseObject != null && interactive != null && UseObject != interactive)
            {
                UseObject.OnSelectionLost();
            }

            if (interactive != null && interactive.SupportedActions != UseActionEnum.None && (Vector3D.Distance(from, interactivePosition)) < interactive.InteractiveDistance && Character == MySession.Static.ControlledEntity)
            {
                HandleInteractiveObject(interactive);

                UseObject = interactive;
                hasInteractive = true;
            }

            if (!hasInteractive)
            {
                if (UseObject != null)
                    UseObject.OnSelectionLost();

                UseObject = null;
            }

            DisableDetectors();
        }
        protected virtual bool CanPlaceTop(MyAttachableTopBlockBase topBlock, long builtBy)
        {
            // Compute the rough actual position for the head, this improves the detection if it can be placed
            float topDistance = (Subpart3.Model.BoundingBoxSize.Y);
            Vector3D topPosition = this.Subpart3.WorldMatrix.Translation + this.WorldMatrix.Up * topDistance;
            float topRadius = topBlock.ModelCollision.HavokCollisionShapes[0].ConvexRadius * 0.9f;

            // First test if we intersect any blocks of our own grid
            BoundingSphereD sphere = topBlock.Model.BoundingSphere;
            sphere.Center = topPosition;
            sphere.Radius = topRadius;
            CubeGrid.GetBlocksInsideSphere(ref sphere, m_tmpSet);

            // If we intersect more than 1 block (because top sometimes intersects piston), don't add top
            if (m_tmpSet.Count > 1)
            {
                m_tmpSet.Clear();
                if (builtBy == MySession.Static.LocalPlayerId)
                    MyHud.Notifications.Add(MyNotificationSingletons.HeadNotPlaced);
                return false;
            }

            m_tmpSet.Clear();

            // Next test if we intersect any physics objects
            HkSphereShape spShape = new HkSphereShape(topRadius);
            Quaternion q = Quaternion.Identity;
            MyPhysics.GetPenetrationsShape(topBlock.ModelCollision.HavokCollisionShapes[0], ref topPosition, ref q, m_penetrations, MyPhysics.CollisionLayers.DefaultCollisionLayer);

            // If we have any collisions with anything other than our own grid, don't add the head
            // We already checked for inner-grid collisions in the previous case
            for (int i = 0; i < m_penetrations.Count; i++)
            {
                MyCubeGrid grid = m_penetrations[i].GetCollisionEntity().GetTopMostParent() as MyCubeGrid;
                if (grid == null || grid != CubeGrid)
                {
                    m_penetrations.Clear();
                    if (builtBy == MySession.Static.LocalPlayerId)
                        MyHud.Notifications.Add(MyNotificationSingletons.HeadNotPlaced);
                    return false;
                }
            }

            m_penetrations.Clear();

            return true;
        }
        protected override void DoDetection(bool useHead)
        {
            if (Character == MySession.ControlledEntity)
                MyHud.SelectedObjectHighlight.Visible = false;

            var head = Character.GetHeadMatrix(false);
            var headPos = head.Translation - (Vector3D)head.Forward * 0.3; // Move to center of head, we don't want eyes (in front of head)

            Vector3D from;
            Vector3D dir;

            if (!useHead)
            {
                //Ondrej version
                //var cameraMatrix = MySector.MainCamera.WorldMatrix;
                var cameraMatrix = Character.Get3rdBoneMatrix(true, true);
                dir = cameraMatrix.Forward;
                from = MyUtils.LinePlaneIntersection(headPos, (Vector3)dir, cameraMatrix.Translation, (Vector3)dir);
            }
            else
            {
                //Petr version
                dir = head.Forward;
                from = headPos;
            }

            Vector3D to = from + dir * 2.5f;

            StartPosition = from;

            MatrixD matrix = MatrixD.CreateTranslation(from);
            HkShape shape = new HkSphereShape(ShapeRadius);
            IMyEntity hitEntity = null;
            ShapeKey = uint.MaxValue;
            HitPosition = Vector3D.Zero;
            HitNormal = Vector3.Zero;
            m_hits.Clear();

            try
            {
                MyPhysics.CastShapeReturnContactBodyDatas(to, shape, ref matrix, 0, 0f, m_hits);

                int index = 0;
                while (index < m_hits.Count && (m_hits[index].HkHitInfo.Body == null || m_hits[index].HkHitInfo.GetHitEntity() == Character
                    || m_hits[index].HkHitInfo.Body.HasProperty(HkCharacterRigidBody.MANIPULATED_OBJECT))) // Skip invalid hits and self character
                {
                    index++;
                }

                if (index < m_hits.Count)
                {
                    hitEntity = m_hits[index].HkHitInfo.GetHitEntity();
                    ShapeKey = m_hits[index].HkHitInfo.GetShapeKey(0);
                    HitPosition = m_hits[index].Position;
                    HitNormal = m_hits[index].HkHitInfo.Normal;
                    HitMaterial = m_hits[index].HkHitInfo.Body.GetBody().GetMaterialAt(HitPosition + HitNormal * 0.1f);
                    HitBody = m_hits[index].HkHitInfo.Body;
                }
            }
            finally
            {
                shape.RemoveReference();
            }

            bool hasInteractive = false;

            var interactive = hitEntity as IMyUseObject;
            DetectedEntity = hitEntity;

            if (hitEntity != null)
            {
                MyUseObjectsComponentBase useObject = null;
                hitEntity.Components.TryGet<MyUseObjectsComponentBase>(out useObject);
                if (useObject != null)
                {
                    interactive = useObject.GetInteractiveObject(ShapeKey);
                }
            }

            if (UseObject != null && interactive != null && UseObject != interactive)
            {
                UseObject.OnSelectionLost();
            }

            if (interactive != null && interactive.SupportedActions != UseActionEnum.None && (Vector3D.Distance(from, HitPosition)) < interactive.InteractiveDistance && Character == MySession.ControlledEntity)
            {
                MyHud.SelectedObjectHighlight.Visible = true;
                MyHud.SelectedObjectHighlight.InteractiveObject = interactive;

                UseObject = interactive;
                hasInteractive = true;
            }

            if (!hasInteractive)
            {
                if (UseObject != null)
                    UseObject.OnSelectionLost();

                UseObject = null;
            }
        }
        private void DoDetection(bool useHead, bool doModelIntersection)
        {
            if (Character == MySession.Static.ControlledEntity)
                MyHud.SelectedObjectHighlight.RemoveHighlight();

            var head = Character.GetHeadMatrix(false);
            var headPos = head.Translation - (Vector3D)head.Forward * 0.3; // Move to center of head, we don't want eyes (in front of head)

            Vector3D from;
            Vector3D dir;

            if (!useHead)
            {
                //Ondrej version
                //var cameraMatrix = MySector.MainCamera.WorldMatrix;
                var cameraMatrix = Character.Get3rdBoneMatrix(true, true);
                dir = cameraMatrix.Forward;
                from = MyUtils.LinePlaneIntersection(headPos, (Vector3)dir, cameraMatrix.Translation, (Vector3)dir);
            }
            else
            {
                //Petr version
                dir = head.Forward;
                from = headPos;
            }

            Vector3D to = from + dir * 2.5;//MyConstants.DEFAULT_INTERACTIVE_DISTANCE;

            StartPosition = from;

            MatrixD matrix = MatrixD.CreateTranslation(from);
            HkShape shape = new HkSphereShape(ShapeRadius);
            IMyEntity hitEntity = null;
            ShapeKey = uint.MaxValue;
            HitPosition = Vector3D.Zero;
            HitNormal = Vector3.Zero;
            HitMaterial = MyStringHash.NullOrEmpty;
            HitTag = null;
            m_hits.Clear();

            Vector3 interactivePosition = Vector3D.Zero;

            try
            {
                EnableDetectorsInArea(from);

                MyPhysics.CastShapeReturnContactBodyDatas(to, shape, ref matrix, 0, 0f, m_hits);

                m_hits.Sort(delegate(MyPhysics.HitInfo info1, MyPhysics.HitInfo info2)
                {
                    float dot1 = Vector3.Dot(head.Forward, Vector3.Normalize(info1.Position - StartPosition));
                    float dot2 = Vector3.Dot(head.Forward, Vector3.Normalize(info2.Position - StartPosition));
                    return dot1.CompareTo(dot2);
                });
                
                if (m_hits.Count > 0)
                {

                    int index = 0;

                    bool isValidBlock = false;
                    bool isPhysicalBlock = false;

                    do
                    {
                        HkRigidBody body = m_hits[index].HkHitInfo.Body;
                        IMyEntity entity = m_hits[index].HkHitInfo.GetHitEntity();

                        if (entity is VRage.Game.Entity.MyEntitySubpart)
                        {
                            entity = entity.Parent;
                        }

                        isValidBlock = body != null && entity != null && entity != Character && !body.HasProperty(HkCharacterRigidBody.MANIPULATED_OBJECT);

                        isPhysicalBlock = entity != null && entity.Physics != null;

                        if (hitEntity == null && isValidBlock)
                        {
                            hitEntity = entity;
                            ShapeKey = m_hits[index].HkHitInfo.GetShapeKey(0);
                        }

                        // Set hit material etc. only for object's that have physical representation in the world, this exclude detectors
                        if (HitMaterial.Equals(MyStringHash.NullOrEmpty) && isValidBlock && isPhysicalBlock)
                        {
                            HitBody = body;
                            HitNormal = m_hits[index].HkHitInfo.Normal;
                            HitPosition = m_hits[index].GetFixedPosition();
                            HitMaterial = body.GetBody().GetMaterialAt(HitPosition);

                            interactivePosition = HitPosition;
                        }
                        else if (body != null)
                        {
                            interactivePosition = m_hits[index].GetFixedPosition();
                        }

                        index++;

                    } while (index < m_hits.Count && (!isValidBlock || !isPhysicalBlock));
                }
            }
            finally
            {
                shape.RemoveReference();
            }

            bool hasInteractive = false;

            var interactive = hitEntity as IMyUseObject;
            DetectedEntity = hitEntity;

            if (hitEntity != null)
            {
                MyUseObjectsComponentBase useObject = null;
                hitEntity.Components.TryGet<MyUseObjectsComponentBase>(out useObject);
                if (useObject != null)
                {
                    interactive = useObject.GetInteractiveObject(ShapeKey);
                }

                // Do accurate collision checking on model
                if (doModelIntersection)
                {
                    LineD line = new LineD(from, to);
                    var character = hitEntity as MyCharacter;
                    if (character == null)
                    {
                        MyIntersectionResultLineTriangleEx? result;
                        bool success = hitEntity.GetIntersectionWithLine(ref line, out result, IntersectionFlags.ALL_TRIANGLES);
                        if (success)
                        {
                            HitPosition = result.Value.IntersectionPointInWorldSpace;
                            HitNormal = result.Value.NormalInWorldSpace;
                        }
                    }
                    else
                    {
                        bool success = character.GetIntersectionWithLine(ref line, ref CharHitInfo);
                        if (success)
                        {
                            HitPosition = CharHitInfo.Triangle.IntersectionPointInWorldSpace;
                            HitNormal = CharHitInfo.Triangle.NormalInWorldSpace;
                            HitTag = CharHitInfo;
                        }
                    }
                }
            }

            if (UseObject != null && interactive != null && UseObject != interactive)
            {
                UseObject.OnSelectionLost();
            }

            if (interactive != null && interactive.SupportedActions != UseActionEnum.None && (Vector3D.Distance(from, interactivePosition)) < interactive.InteractiveDistance && Character == MySession.Static.ControlledEntity)
            {
                HandleInteractiveObject(interactive);

                UseObject = interactive;
                hasInteractive = true;
            }

            if (!hasInteractive)
            {
                if (UseObject != null)
                    UseObject.OnSelectionLost();

                UseObject = null;
            }

            DisableDetectors();
        }
        /// <summary>
        /// Processes previously acquired raycast results.
        /// Returns safe camera eye position (As far from target as possible, but not colliding, best case = desired eye pos).
        /// </summary>
        private MyCameraRaycastResult RaycastOccludingObjects(MyEntity controlledEntity, ref Vector3D raycastOrigin, ref Vector3D raycastEnd, ref Vector3D raycastSafeCameraStart, out Vector3D outSafePosition)
        {
            Vector3D rayDirection = raycastEnd - raycastOrigin;

            rayDirection.Normalize();

            outSafePosition = m_position;
            double closestDistanceSquared = double.PositiveInfinity;
            bool   positionChanged        = false;

            // ray cast - very close objects
            MyPhysics.CastRay(raycastOrigin, raycastOrigin + CAMERA_RADIUS * rayDirection, m_raycastList);
            foreach (MyPhysics.HitInfo rb in m_raycastList)
            {
                if (rb.HkHitInfo.Body == null ||
                    rb.HkHitInfo.Body.UserObject == null ||
                    !(rb.HkHitInfo.Body.UserObject is MyPhysicsBody) ||
                    rb.HkHitInfo.GetHitEntity() == controlledEntity)
                {
                    continue;
                }
                if (rb.HkHitInfo.GetHitEntity() is IMyHandheldGunObject <Game.Weapons.MyDeviceBase> ) // ignore player weapons
                {
                    continue;
                }

                double distSq = Vector3D.DistanceSquared(rb.Position, raycastOrigin);
                if (distSq < closestDistanceSquared)
                {
                    closestDistanceSquared = distSq;
                    float dist = (float)Math.Sqrt(distSq) - CAMERA_RADIUS;
                    outSafePosition = raycastOrigin + rayDirection * dist;
                    positionChanged = true;
                }
            }

            if (m_debugDraw)
            {
                foreach (var raycastResult in m_raycastList)
                {
                    VRageRender.MyRenderProxy.DebugDrawPoint(raycastResult.Position, Color.Red, false);
                }
            }

            // shape cast - further objects
            if ((raycastEnd - raycastOrigin).LengthSquared() > CAMERA_RADIUS * CAMERA_RADIUS)
            {
                HkShape shapeSphere            = new HkSphereShape(CAMERA_RADIUS);
                MatrixD raycastOriginTransform = MatrixD.Identity;
                raycastOriginTransform.Translation = raycastOrigin + CAMERA_RADIUS * rayDirection;
                MyPhysics.CastShapeReturnContactBodyDatas(raycastEnd, shapeSphere, ref raycastOriginTransform, 0,
                                                          0, m_raycastList);
                //MyPhysics.CastRay(raycastOrigin + CAMERA_RADIUS * rayDirection, raycastEnd, m_raycastList, 0);
                foreach (MyPhysics.HitInfo rb in m_raycastList)
                {
                    IMyEntity hitEntity = rb.HkHitInfo.GetHitEntity();
                    if (rb.HkHitInfo.Body == null ||
                        rb.HkHitInfo.Body.UserObject == null ||
                        hitEntity == controlledEntity ||
                        !(rb.HkHitInfo.Body.UserObject is MyPhysicsBody))
                    {
                        continue;
                    }
                    if (hitEntity is IMyHandheldGunObject <Game.Weapons.MyDeviceBase> )
                    {
                        // ignore player weapons
                        continue;
                    }

                    double distSq = Vector3D.DistanceSquared(rb.Position, raycastOrigin);
                    if (distSq < closestDistanceSquared)
                    {
                        closestDistanceSquared = distSq;
                        float dist = (float)Math.Sqrt(distSq);
                        outSafePosition = raycastOrigin + rayDirection * dist;
                        positionChanged = true;
                    }
                }
                shapeSphere.RemoveReference();
            }

            if (m_debugDraw)
            {
                foreach (var raycastResult in m_raycastList)
                {
                    VRageRender.MyRenderProxy.DebugDrawSphere(raycastResult.Position, CAMERA_RADIUS, Color.Red, 1, false);
                }
            }


            if (closestDistanceSquared < (raycastSafeCameraStart - raycastOrigin).LengthSquared() + CAMERA_RADIUS)
            {
                return(MyCameraRaycastResult.FoundOccluderNoSpace); // obstacle too close, switch to first person
            }

            // last check - isn't there voxel between safe pos and entity pos
            if (!positionChanged)
            {
                //Vector3D entityPos = controlledEntity.PositionComp.GetPosition();
                MyPhysics.CastRay(m_target, raycastSafeCameraStart, m_raycastList);

                if (m_debugDraw)
                {
                    BoundingBoxD bb = new BoundingBoxD(m_target, raycastSafeCameraStart);
                    VRageRender.MyRenderProxy.DebugDrawAABB(bb, Color.Magenta);
                }

                foreach (var collision in m_raycastList)
                {
                    if (collision.HkHitInfo.GetHitEntity() is MyVoxelBase)
                    {
                        return(MyCameraRaycastResult.FoundOccluderNoSpace);
                    }
                }
            }

            return(positionChanged ? MyCameraRaycastResult.FoundOccluder : MyCameraRaycastResult.Ok);
        }
        protected override bool CanPlaceRotor(MyAttachableTopBlockBase rotorBlock, long builtBy)
        {
            // Compute the rough actual position for the wheel, this improves the detection if it can be placed
            float wheelDistance = BlockDefinition.Size.Y * CubeGrid.GridSize - 0.2f * CubeGrid.GridSize;
            Vector3D wheelPosition = this.WorldMatrix.Translation + this.WorldMatrix.Up * wheelDistance;
            float wheelRadius = rotorBlock.ModelCollision.HavokCollisionShapes[0].ConvexRadius * 0.9f;

            // First test if we intersect any blocks of our own grid
            BoundingSphereD sphere = rotorBlock.Model.BoundingSphere;
            sphere.Center = wheelPosition;
            sphere.Radius = wheelRadius;
            CubeGrid.GetBlocksInsideSphere(ref sphere, m_tmpSet);

            // If we intersect more than 1 block (because wheel sometimes intersects suspension), don't add wheel
            if (m_tmpSet.Count > 1)
            {
                m_tmpSet.Clear();
                if (builtBy == MySession.Static.LocalPlayerId)
                    MyHud.Notifications.Add(MyNotificationSingletons.WheelNotPlaced);
                return false;
            }

            m_tmpSet.Clear();

            // Next test if we intersect any physics objects
            HkSphereShape spShape = new HkSphereShape(wheelRadius);
            Quaternion q = Quaternion.Identity;
            MyPhysics.GetPenetrationsShape(rotorBlock.ModelCollision.HavokCollisionShapes[0], ref wheelPosition, ref q, m_tmpList, MyPhysics.CollisionLayers.DefaultCollisionLayer);

            // If we have any collisions with anything other than our own grid, don't add the wheel
            // We already checked for inner-grid collisions in the previous case
            for (int i = 0; i < m_tmpList.Count; i++)
            {
                MyCubeGrid grid = m_tmpList[i].GetCollisionEntity() as MyCubeGrid;
                if (grid == null || grid != CubeGrid)
                {
                    m_tmpList.Clear();
                    if (builtBy == MySession.Static.LocalPlayerId)
                        MyHud.Notifications.Add(MyNotificationSingletons.WheelNotPlaced);
                    return false;
                }
            }

            m_tmpList.Clear();

            return true;
        }
        private void DoDetection(bool useHead, bool doModelIntersection)
        {
            if (Character == MySession.Static.ControlledEntity)
            {
                MyHud.SelectedObjectHighlight.RemoveHighlight();
            }

            var      head = Character.GetHeadMatrix(false);
            Vector3D from = head.Translation;
            Vector3D dir  = head.Forward;

            if (!useHead)
            {
                var headPos = head.Translation - (Vector3D)head.Forward * 0.3; // Move to center of head, we don't want eyes (in front of head)

                if (Character == MySession.Static.LocalCharacter)
                {
                    from = MySector.MainCamera.WorldMatrix.Translation;
                    dir  = MySector.MainCamera.WorldMatrix.Forward;

                    from = MyUtils.LinePlaneIntersection(headPos, (Vector3)dir, from, (Vector3)dir);
                }
                else
                {
                    from = headPos;
                    dir  = head.Forward;
                }
            }

            Vector3D to = from + dir * 2.5;//MyConstants.DEFAULT_INTERACTIVE_DISTANCE;

            StartPosition = from;

            MatrixD   matrix    = MatrixD.CreateTranslation(from);
            HkShape   shape     = new HkSphereShape(ShapeRadius);
            IMyEntity hitEntity = null;

            ShapeKey    = uint.MaxValue;
            HitPosition = Vector3D.Zero;
            HitNormal   = Vector3.Zero;
            HitMaterial = MyStringHash.NullOrEmpty;
            HitTag      = null;
            m_hits.Clear();

            Vector3 interactivePosition = Vector3D.Zero;

            try
            {
                EnableDetectorsInArea(from);

                MyPhysics.CastShapeReturnContactBodyDatas(to, shape, ref matrix, 0, 0f, m_hits);

                m_rayOrigin    = from;
                m_rayDirection = dir;
                m_hits.Sort(CompareHits);

                if (m_hits.Count > 0)
                {
                    bool isValidBlock    = false;
                    bool isPhysicalBlock = false;

                    for (int index = 0; index < m_hits.Count; index++)
                    {
                        HkRigidBody body   = m_hits[index].HkHitInfo.Body;
                        IMyEntity   entity = m_hits[index].HkHitInfo.GetHitEntity();

                        // Ignore self-interaction
                        if (entity == Character)
                        {
                            continue;
                        }

                        if (entity is VRage.Game.Entity.MyEntitySubpart)
                        {
                            entity = entity.Parent;
                        }

                        isValidBlock    = body != null && entity != null && entity != Character && !body.HasProperty(HkCharacterRigidBody.MANIPULATED_OBJECT);
                        isPhysicalBlock = entity != null && entity.Physics != null;

                        if (hitEntity == null && isValidBlock)
                        {
                            hitEntity = entity;
                            ShapeKey  = m_hits[index].HkHitInfo.GetShapeKey(0);
                        }

                        // If hit-entity is a grid, raycast it to see which block we hit first
                        if (entity is MyCubeGrid)
                        {
                            MyCubeGrid    grid     = entity as MyCubeGrid;
                            List <MyCube> cubeList = grid.RayCastBlocksAllOrdered(from, to);
                            if (cubeList != null && cubeList.Count > 0)
                            {
                                var slimblock = cubeList[0].CubeBlock;
                                if (slimblock.FatBlock != null)
                                {
                                    entity          = slimblock.FatBlock;
                                    isPhysicalBlock = true;
                                    hitEntity       = entity;
                                    ShapeKey        = 0;
                                }
                            }
                        }

                        // Set hit material etc. only for object's that have physical representation in the world, this exclude detectors
                        if (HitMaterial.Equals(MyStringHash.NullOrEmpty) && isValidBlock && isPhysicalBlock)
                        {
                            HitBody     = body;
                            HitNormal   = m_hits[index].HkHitInfo.Normal;
                            HitPosition = m_hits[index].GetFixedPosition();
                            HitMaterial = body.GetBody().GetMaterialAt(HitPosition);

                            interactivePosition = HitPosition;
                            break;
                        }
                        else if (body != null)
                        {
                            interactivePosition = m_hits[index].GetFixedPosition();
                            break;
                        }

                        index++;
                    }
                }
            }
            finally
            {
                shape.RemoveReference();
            }

            bool hasInteractive = false;

            var interactive = hitEntity as IMyUseObject;

            DetectedEntity = hitEntity;

            if (hitEntity != null)
            {
                MyUseObjectsComponentBase useObject = null;
                hitEntity.Components.TryGet <MyUseObjectsComponentBase>(out useObject);
                if (useObject != null)
                {
                    interactive = useObject.GetInteractiveObject(ShapeKey);
                }

                // Do accurate collision checking on model
                if (doModelIntersection)
                {
                    LineD line      = new LineD(from, to);
                    var   character = hitEntity as MyCharacter;
                    if (character == null)
                    {
                        MyIntersectionResultLineTriangleEx?result;
                        bool success = hitEntity.GetIntersectionWithLine(ref line, out result, IntersectionFlags.ALL_TRIANGLES);
                        if (success)
                        {
                            HitPosition = result.Value.IntersectionPointInWorldSpace;
                            HitNormal   = result.Value.NormalInWorldSpace;
                        }
                    }
                    else
                    {
                        bool success = character.GetIntersectionWithLine(ref line, ref CharHitInfo);
                        if (success)
                        {
                            HitPosition = CharHitInfo.Triangle.IntersectionPointInWorldSpace;
                            HitNormal   = CharHitInfo.Triangle.NormalInWorldSpace;
                            HitTag      = CharHitInfo;
                        }
                    }
                }
            }

            if (UseObject != null && interactive != null && UseObject != interactive)
            {
                UseObject.OnSelectionLost();
            }

            if (interactive != null && interactive.SupportedActions != UseActionEnum.None && (Vector3D.Distance(from, interactivePosition)) < interactive.InteractiveDistance && Character == MySession.Static.ControlledEntity)
            {
                HandleInteractiveObject(interactive);

                UseObject      = interactive;
                hasInteractive = true;
            }

            if (!hasInteractive)
            {
                if (UseObject != null)
                {
                    UseObject.OnSelectionLost();
                }

                UseObject = null;
            }

            DisableDetectors();
        }
        /// <summary>
        /// Processes previously acquired raycast results.
        /// Returns safe camera eye position (As far from target as possible, but not colliding, best case = desired eye pos).
        /// </summary>
        private MyCameraRaycastResult RaycastOccludingObjects(MyEntity controlledEntity, ref Vector3D raycastOrigin, ref Vector3D raycastEnd, ref Vector3D raycastSafeCameraStart, out Vector3D outSafePosition)
        {
            Vector3D rayDirection = raycastEnd - raycastOrigin;
            rayDirection.Normalize();

            outSafePosition = m_position;
            double closestDistanceSquared = double.PositiveInfinity;
            bool positionChanged = false;
            
            // ray cast - very close objects
            MyPhysics.CastRay(raycastOrigin, raycastOrigin + CAMERA_RADIUS * rayDirection, m_raycastList);
            foreach (MyPhysics.HitInfo rb in m_raycastList)
            {
                if (rb.HkHitInfo.Body == null
                    || rb.HkHitInfo.Body.UserObject == null
                    || !(rb.HkHitInfo.Body.UserObject is MyPhysicsBody)
                    || rb.HkHitInfo.GetHitEntity() == controlledEntity)
                    continue;
                if (rb.HkHitInfo.GetHitEntity() is IMyHandheldGunObject<Game.Weapons.MyDeviceBase>) // ignore player weapons
                    continue;

                double distSq = Vector3D.DistanceSquared(rb.Position, raycastOrigin);
                if (distSq < closestDistanceSquared)
                {
                    closestDistanceSquared = distSq;
                    double dist = Math.Sqrt(distSq) - CAMERA_RADIUS;
                    outSafePosition = raycastOrigin + rayDirection * dist;
                    positionChanged = true;
                }
            }

            if (m_debugDraw)
                foreach (var raycastResult in m_raycastList)
                {
                    VRageRender.MyRenderProxy.DebugDrawPoint(raycastResult.Position, Color.Red, false);
                }

            // shape cast - further objects
            if ((raycastEnd - raycastOrigin).LengthSquared() > CAMERA_RADIUS * CAMERA_RADIUS)
            {
                HkShape shapeSphere = new HkSphereShape(CAMERA_RADIUS);
                MatrixD raycastOriginTransform = MatrixD.Identity;
                raycastOriginTransform.Translation = raycastOrigin + CAMERA_RADIUS * rayDirection;
                MyPhysics.CastShapeReturnContactBodyDatas(raycastEnd, shapeSphere, ref raycastOriginTransform, 0,
                    0, m_raycastList);
                //MyPhysics.CastRay(raycastOrigin + CAMERA_RADIUS * rayDirection, raycastEnd, m_raycastList, 0);
                float closestFraction = 1;
                foreach (MyPhysics.HitInfo rb in m_raycastList)
                {
                    IMyEntity hitEntity = rb.HkHitInfo.GetHitEntity();
                    if (rb.HkHitInfo.Body == null
                        || rb.HkHitInfo.Body.UserObject == null
                        || hitEntity == controlledEntity
                        || !(rb.HkHitInfo.Body.UserObject is MyPhysicsBody))
                        continue;
                    if (hitEntity is IMyHandheldGunObject<Game.Weapons.MyDeviceBase>)
                        // ignore player weapons
                        continue;

                    Vector3D safePos = Vector3D.Lerp(raycastOrigin, raycastEnd - CAMERA_RADIUS * rayDirection,
                        Math.Max(rb.HkHitInfo.HitFraction, 0.0001));
                    double distSq = Vector3D.DistanceSquared(raycastOrigin, outSafePosition);
                    if (rb.HkHitInfo.HitFraction < closestFraction && distSq < closestDistanceSquared)
                    {
                        outSafePosition = safePos;
                        closestDistanceSquared = distSq;
                        positionChanged = true;
                        closestFraction = rb.HkHitInfo.HitFraction;
                    }
                }
                shapeSphere.RemoveReference();
            }

            if (m_debugDraw)
                foreach (var raycastResult in m_raycastList)
                {
                    VRageRender.MyRenderProxy.DebugDrawSphere(raycastResult.Position, CAMERA_RADIUS, Color.Red, 1, false);
                }

            
            if (closestDistanceSquared < (raycastSafeCameraStart - raycastOrigin).LengthSquared() + CAMERA_RADIUS)
            {
                return MyCameraRaycastResult.FoundOccluderNoSpace; // obstacle too close, switch to first person
            }

            // last check - isn't there voxel between safe pos and entity pos
            if (!positionChanged)
            {
                //Vector3D entityPos = controlledEntity.PositionComp.GetPosition();
                MyPhysics.CastRay(m_target, raycastSafeCameraStart, m_raycastList);

                if (m_debugDraw)
                {
                    BoundingBoxD bb = new BoundingBoxD(m_target, raycastSafeCameraStart);
                    VRageRender.MyRenderProxy.DebugDrawAABB(bb, Color.Magenta);
                }

                foreach (var collision in m_raycastList)
                {
                    if (collision.HkHitInfo.GetHitEntity() is MyVoxelBase)
                    {
                        return MyCameraRaycastResult.FoundOccluderNoSpace;
                    }
                }
            }

            return positionChanged ? MyCameraRaycastResult.FoundOccluder : MyCameraRaycastResult.Ok;
        }
Beispiel #46
0
        private void ThrustDamage()
        {
            if (m_flames.Count > 0 && MySession.Static.ThrusterDamage && Sync.IsServer && IsWorking && CubeGrid.InScene && CubeGrid.Physics != null && CubeGrid.Physics.Enabled)
            {
                if (CurrentStrength == 0 && !MyFakes.INACTIVE_THRUSTER_DMG)
                {
                    return;
                }

                UpdateThrustFlame();

                foreach (var flameInfo in m_flames)
                {
                    var     l = GetDamageCapsuleLine(flameInfo);
                    HkShape shape;
                    if (l.Length != 0)
                    {
                        shape = new HkCapsuleShape(Vector3.Zero, l.To - l.From, flameInfo.Radius * m_thrustDefinition.FlameDamageLengthScale);
                    }
                    else
                    {
                        shape = new HkSphereShape(flameInfo.Radius * m_thrustDefinition.FlameDamageLengthScale);
                    }
                    MyPhysics.GetPenetrationsShape(shape, ref l.From, ref Quaternion.Identity, m_flameCollisionsList, 0);
                    shape.RemoveReference();

                    foreach (var obj in m_flameCollisionsList)
                    {
                        var entity = obj.GetEntity();
                        if (entity == null)
                        {
                            continue;
                        }
                        if (entity.Equals(this))
                        {
                            continue;
                        }
                        if (!(entity is MyCharacter))
                        {
                            entity = entity.GetTopMostParent();
                        }
                        if (m_damagedEntities.Contains(entity))
                        {
                            continue;
                        }
                        else
                        {
                            m_damagedEntities.Add(entity);
                        }

                        if (entity is IMyDestroyableObject)
                        {
                            (entity as IMyDestroyableObject).DoDamage(flameInfo.Radius * m_thrustDefinition.FlameDamage * 10, MyDamageType.Environment, true);
                        }
                        else if (entity is MyCubeGrid && MySession.Static.DestructibleBlocks)
                        {
                            DamageGrid(flameInfo, l, entity as MyCubeGrid);
                        }
                    }
                    m_damagedEntities.Clear();
                    m_flameCollisionsList.Clear();
                }
            }
        }
        public override void AccumulateCorrection(ref VRageMath.Vector3 correction, ref float weight)
        {
            // Don't do any correction if we're not moving
            if (Parent.Speed < 0.01)
            {
                return;
            }

            Vector3D position = Parent.PositionAndOrientation.Translation;

            // Find trees
            Quaternion rotation    = Quaternion.Identity;
            HkShape    sphereShape = new HkSphereShape(6);

            MyPhysics.GetPenetrationsShape(sphereShape, ref position, ref rotation, m_trees, MyPhysics.CollisionLayers.NoVoxelCollisionLayer);

            foreach (var tree in m_trees)
            {
                // Make sure the tree is actually a tree
                if (tree.Body == null)
                {
                    continue;
                }
                MyPhysicsBody physicsBody = tree.Body.UserObject as MyPhysicsBody;
                if (physicsBody == null)
                {
                    continue;
                }

                HkShape bodyShape = tree.Body.GetShape();
                if (bodyShape.ShapeType != HkShapeType.StaticCompound)
                {
                    continue;
                }

                // Get the static compound shape
                HkStaticCompoundShape staticCompoundShape = (HkStaticCompoundShape)bodyShape;

                int  instanceId;
                uint childKey;
                staticCompoundShape.DecomposeShapeKey(tree.ShapeKey, out instanceId, out childKey);

                // Get the local shape position, and add entity world position
                Vector3D item = staticCompoundShape.GetInstanceTransform(instanceId).Translation;
                item += physicsBody.GetWorldMatrix().Translation;

                // Avoid tree
                Vector3D dir  = item - position;
                var      dist = dir.Normalize();
                dir = Vector3D.Reject(Parent.ForwardVector, dir);

                dir.Y = 0.0f;
                if (dir.Z * dir.Z + dir.X * dir.X < 0.1)
                {
                    Vector3D dirLocal = Vector3D.TransformNormal(dir, Parent.PositionAndOrientationInverted);
                    dir = position - item;
                    dir = Vector3D.Cross(Vector3D.Up, dir);
                    if (dirLocal.X < 0)
                    {
                        dir = -dir;
                    }
                }

                dir.Normalize();

                correction += (6f - dist) * Weight * dir;
                if (!correction.IsValid())
                {
                    System.Diagnostics.Debugger.Break();
                }
            }

            m_trees.Clear();

            weight += Weight;
        }
Beispiel #48
0
            private void InitInternal()
            {
                // TODO: This will be fixed and made much more simple once ore models are done
                // https://app.asana.com/0/6594565324126/10473934569658
                var physicalItem = MyDefinitionManager.Static.GetPhysicalItemDefinition(Item.Content);

                var ore = Item.Content as MyObjectBuilder_Ore;

                string model = physicalItem.Model;
                float scale = 1.0f;
                VoxelMaterial = null;
                if (ore != null)
                {
                    foreach (var mat in MyDefinitionManager.Static.GetVoxelMaterialDefinitions())
                    {
                        if (mat.MinedOre == ore.SubtypeName)
                        {
                            VoxelMaterial = mat;
                            model = MyDebris.GetRandomDebrisVoxel();
                            scale = (float)Math.Pow((float)Item.Amount * physicalItem.Volume  / MyDebris.VoxelDebrisModelVolume, 0.333f);
                            break;
                        }
                    }
                }

                if (scale < 0.15f)
                    scale = 0.15f;

                var voxelRender = (Entity.Render as MyRenderComponentDebrisVoxel);
                voxelRender.VoxelMaterialIndex = VoxelMaterial.Index;
                voxelRender.TexCoordOffset = 5;
                voxelRender.TexCoordScale = 8;
                Entity.Init(new StringBuilder("Meteor"), model, null, null, null);

                Entity.PositionComp.Scale = scale; // Must be set after init

                var massProperties = HkInertiaTensorComputer.ComputeSphereVolumeMassProperties(Entity.PositionComp.LocalVolume.Radius, (float)(4 / 3f * Math.PI * Math.Pow(Entity.PositionComp.LocalVolume.Radius, 3)) * 3.7f);
                HkSphereShape transform = new HkSphereShape(Entity.PositionComp.LocalVolume.Radius);

                if (Entity.Physics != null)
                    Entity.Physics.Close();

                Entity.Physics = new MyPhysicsBody(Entity, RigidBodyFlag.RBF_BULLET);
                Entity.Physics.ReportAllContacts = true;
                Entity.GetPhysicsBody().CreateFromCollisionObject(transform, Vector3.Zero, MatrixD.Identity, massProperties, MyPhysics.CollisionLayers.DefaultCollisionLayer);
                Entity.Physics.Enabled = true;
                Entity.Physics.RigidBody.ContactPointCallbackEnabled = true;
                Entity.GetPhysicsBody().ContactPointCallback += RigidBody_ContactPointCallback;
                transform.Base.RemoveReference();
                Entity.Physics.PlayCollisionCueEnabled = true;

                m_timeCreated = MySandboxGame.TotalGamePlayTimeInMilliseconds;

                NeedsUpdate = MyEntityUpdateEnum.EACH_FRAME | MyEntityUpdateEnum.EACH_100TH_FRAME;

                StartLoopSound();
            }
        protected override void DoDetection(bool useHead)
        {
            if (Character == MySession.Static.ControlledEntity)
                MyHud.SelectedObjectHighlight.RemoveHighlight();

            var head = Character.GetHeadMatrix(false);
            var headPos = head.Translation - (Vector3D)head.Forward * 0.3; // Move to center of head, we don't want eyes (in front of head)

            Vector3D from;
            Vector3D dir;

            if (!useHead)
            {
                //Ondrej version
                var cameraMatrix = MySector.MainCamera.WorldMatrix;
                //var cameraMatrix = Character.Get3rdBoneMatrix(true, true);
                dir = cameraMatrix.Forward;
                from = MyUtils.LinePlaneIntersection(headPos, (Vector3)dir, cameraMatrix.Translation, (Vector3)dir);
            }
            else
            {
                //Petr version
                dir = head.Forward;
                from = headPos;
            }

            Vector3D to = from + dir * MyConstants.DEFAULT_INTERACTIVE_DISTANCE;

            StartPosition = from;

            MatrixD matrix = MatrixD.CreateTranslation(from);
            HkShape shape = new HkSphereShape(ShapeRadius);
            IMyEntity hitEntity = null;
            ShapeKey = uint.MaxValue;
            HitPosition = Vector3D.Zero;
            HitNormal = Vector3.Zero;
            HitMaterial = MyStringHash.NullOrEmpty;
            m_hits.Clear();

            try
            {
                EnableDetectorsInArea(from);

                MyPhysics.CastShapeReturnContactBodyDatas(to, shape, ref matrix, 0, 0f, m_hits);

                if (m_hits.Count > 0)
                {

                    int index = 0;

                    bool isValidBlock = false;
                    bool isPhysicalBlock = false;

                    do
                    {
                        isValidBlock = m_hits[index].HkHitInfo.Body != null && m_hits[index].HkHitInfo.GetHitEntity() != Character && m_hits[index].HkHitInfo.GetHitEntity() != null && !m_hits[index].HkHitInfo.Body.HasProperty(HkCharacterRigidBody.MANIPULATED_OBJECT);

                        isPhysicalBlock = m_hits[index].HkHitInfo.GetHitEntity() != null && m_hits[index].HkHitInfo.GetHitEntity().Physics != null;

                        if (hitEntity == null && isValidBlock)
                        {
                            hitEntity = m_hits[index].HkHitInfo.GetHitEntity();
                            ShapeKey = m_hits[index].HkHitInfo.GetShapeKey(0);
                        }

                        // Set hit material etc. only for object's that have physical representation in the world, this exclude detectors
                        if (HitMaterial.Equals(MyStringHash.NullOrEmpty) && isValidBlock && isPhysicalBlock)
                        {
                            HitBody = m_hits[index].HkHitInfo.Body;
                            HitPosition = m_hits[index].Position;
                            HitNormal = m_hits[index].HkHitInfo.Normal;
                            HitMaterial = m_hits[index].HkHitInfo.Body.GetBody().GetMaterialAt(HitPosition + HitNormal * 0.1f);
                        }

                        index++;

                    } while (index < m_hits.Count && (!isValidBlock || !isPhysicalBlock));
                }
            }
            finally
            {
                shape.RemoveReference();
            }

            bool hasInteractive = false;

            var interactive = hitEntity as IMyUseObject;
            DetectedEntity = hitEntity;

            if (hitEntity != null)
            {
                MyUseObjectsComponentBase useObject = null;
                hitEntity.Components.TryGet<MyUseObjectsComponentBase>(out useObject);
                if (useObject != null)
                {
                    interactive = useObject.GetInteractiveObject(ShapeKey);
                }
            }

            if (UseObject != null && interactive != null && UseObject != interactive)
            {
                UseObject.OnSelectionLost();
            }

            if (interactive != null && interactive.SupportedActions != UseActionEnum.None && (Vector3D.Distance(from, HitPosition)) < interactive.InteractiveDistance && Character == MySession.Static.ControlledEntity)
            {
                HandleInteractiveObject(interactive);

                UseObject = interactive;
                hasInteractive = true;
            }

            if (!hasInteractive)
            {
                if (UseObject != null)
                    UseObject.OnSelectionLost();

                UseObject = null;
            }

            DisableDetectors();
        }
Beispiel #50
0
        private void DamageGrid(FlameInfo flameInfo, LineD l, MyCubeGrid grid)
        {
            HkSphereShape sph = new HkSphereShape(flameInfo.Radius * BlockDefinition.FlameDamageLengthScale);
            var transform = MatrixD.CreateWorld(l.From, Vector3.Forward, Vector3.Up);
            var hit = MyPhysics.CastShapeReturnPoint(l.To, sph, ref transform, (int)MyPhysics.DefaultCollisionLayer, 0.05f);

            sph.Base.RemoveReference();

            if (hit.HasValue)
            {
                //MyRenderProxy.DebugDrawSphere(hit.Value, 0.1f, Color.Green.ToVector3(), 1, true);
                MyPhysics.CastRay(hit.Value - l.Direction * 0.1f, hit.Value + l.Direction * 0.1f, m_gridRayCastLst, MyPhysics.ObjectDetectionCollisionLayer);
                if ((m_gridRayCastLst.Count == 0 || m_gridRayCastLst[0].HkHitInfo.GetHitEntity() != grid) && grid == CubeGrid)
                {
                    m_gridRayCastLst.Clear();
                    return;
                }
                m_gridRayCastLst.Clear();
                var block = grid.GetCubeBlock(grid.WorldToGridInteger(hit.Value));
                //if (block != this.SlimBlock)
                {
                    //MyRenderProxy.DebugDrawSphere(hit.Value, 0.1f, Color.Green.ToVector3(), 1, true);
                    var invWorld = grid.PositionComp.GetWorldMatrixNormalizedInv();
                    var gridPos = Vector3D.Transform(hit.Value, invWorld);
                    var gridDir = Vector3D.TransformNormal(l.Direction, invWorld);
                    if (block != null)
                        if (block.FatBlock != this && (CubeGrid.GridSizeEnum == MyCubeSize.Large || block.BlockDefinition.DeformationRatio > 0.25))
                        {
                            block.DoDamage(30 * BlockDefinition.FlameDamage, MyDamageType.Environment, attackerId: EntityId);
                        }
                    var areaPlanar = 0.5f * flameInfo.Radius * CubeGrid.GridSize;
                    var areaVertical = 0.5f * CubeGrid.GridSize;

                    grid.Physics.ApplyDeformation(BlockDefinition.FlameDamage, areaPlanar, areaVertical, gridPos, gridDir, MyDamageType.Environment, CubeGrid.GridSizeEnum == MyCubeSize.Small ? 0.1f : 0, attackerId: EntityId);
                }
            }
        }
        protected override void DoDetection(bool useHead)
        {
            if (Character == MySession.ControlledEntity)
            {
                MyHud.SelectedObjectHighlight.Visible = false;
            }

            var head    = Character.GetHeadMatrix(false);
            var headPos = head.Translation - (Vector3D)head.Forward * 0.3; // Move to center of head, we don't want eyes (in front of head)

            Vector3D from;
            Vector3D dir;

            if (!useHead)
            {
                //Ondrej version
                //var cameraMatrix = MySector.MainCamera.WorldMatrix;
                var cameraMatrix = Character.Get3rdBoneMatrix(true, true);
                dir  = cameraMatrix.Forward;
                from = MyUtils.LinePlaneIntersection(headPos, (Vector3)dir, cameraMatrix.Translation, (Vector3)dir);
            }
            else
            {
                //Petr version
                dir  = head.Forward;
                from = headPos;
            }

            Vector3D to = from + dir * 2.5f;

            StartPosition = from;

            MatrixD   matrix    = MatrixD.CreateTranslation(from);
            HkShape   shape     = new HkSphereShape(ShapeRadius);
            IMyEntity hitEntity = null;

            ShapeKey    = uint.MaxValue;
            HitPosition = Vector3D.Zero;
            HitNormal   = Vector3.Zero;
            m_hits.Clear();

            try
            {
                EnableDetectorsInArea(from);

                MyPhysics.CastShapeReturnContactBodyDatas(to, shape, ref matrix, 0, 0f, m_hits);

                int index = 0;
                while (index < m_hits.Count && (m_hits[index].HkHitInfo.Body == null || m_hits[index].HkHitInfo.GetHitEntity() == Character ||
                                                m_hits[index].HkHitInfo.Body.HasProperty(HkCharacterRigidBody.MANIPULATED_OBJECT))) // Skip invalid hits and self character
                {
                    index++;
                }

                if (index < m_hits.Count)
                {
                    hitEntity   = m_hits[index].HkHitInfo.GetHitEntity();
                    ShapeKey    = m_hits[index].HkHitInfo.GetShapeKey(0);
                    HitPosition = m_hits[index].Position;
                    HitNormal   = m_hits[index].HkHitInfo.Normal;
                    HitMaterial = m_hits[index].HkHitInfo.Body.GetBody().GetMaterialAt(HitPosition + HitNormal * 0.1f);
                    HitBody     = m_hits[index].HkHitInfo.Body;
                }
            }
            finally
            {
                shape.RemoveReference();
            }

            bool hasInteractive = false;

            var interactive = hitEntity as IMyUseObject;

            DetectedEntity = hitEntity;

            if (hitEntity != null)
            {
                MyUseObjectsComponentBase useObject = null;
                hitEntity.Components.TryGet <MyUseObjectsComponentBase>(out useObject);
                if (useObject != null)
                {
                    interactive = useObject.GetInteractiveObject(ShapeKey);
                }
            }

            if (UseObject != null && interactive != null && UseObject != interactive)
            {
                UseObject.OnSelectionLost();
            }

            if (interactive != null && interactive.SupportedActions != UseActionEnum.None && (Vector3D.Distance(from, HitPosition)) < interactive.InteractiveDistance && Character == MySession.ControlledEntity)
            {
                MyHud.SelectedObjectHighlight.Visible           = true;
                MyHud.SelectedObjectHighlight.InteractiveObject = interactive;

                UseObject      = interactive;
                hasInteractive = true;
            }

            if (!hasInteractive)
            {
                if (UseObject != null)
                {
                    UseObject.OnSelectionLost();
                }

                UseObject = null;
            }

            DisableDetectors();
        }
Beispiel #52
0
        /// <summary>
        /// Handles camera collisions with environment
        /// </summary>
        /// <param name="controlledEntity"></param>
        /// <param name="shakeActive"></param>
        /// <param name="headPosition"></param>
        /// <param name="headDirection"></param>
        /// <returns>False if no correct position was found</returns>
        private bool HandleIntersection(MyEntity controlledEntity, MyOrientedBoundingBoxD safeOBB, bool requireRaycast, bool shakeActive, Vector3D headPosition, Vector3 headDirection)
        {
            var line = new LineD(m_target, m_position);

            var      safeOBBLine = new LineD(line.From, line.From + line.Direction * 2 * safeOBB.HalfExtent.Length());
            Vector3D castStartSafe;

            {
                MyOrientedBoundingBoxD safeObbWithCollisionExtents = new MyOrientedBoundingBoxD(safeOBB.Center, safeOBB.HalfExtent + 2 * CAMERA_RADIUS, safeOBB.Orientation);
                double?safeIntersection = safeObbWithCollisionExtents.Intersects(ref safeOBBLine);
                if (!safeIntersection.HasValue)
                {
                    safeIntersection = safeOBB.HalfExtent.Length();
                }
                double safeDistance = safeIntersection.Value;
                castStartSafe = line.From + line.Direction * safeDistance;
            }

            {
                double?unsafeIntersection = safeOBB.Intersects(ref safeOBBLine);
                if (!requireRaycast && unsafeIntersection.HasValue)
                {
                    var castStartUnsafe = line.From + line.Direction * unsafeIntersection.Value;
                    var castEndUnsafe   = castStartSafe + line.Direction;
                    // short raycast, not causing problems with asteroids generating geometry
                    Physics.MyPhysics.CastRay(castStartUnsafe, castEndUnsafe, m_raycastList, MyPhysics.CollisionLayers.CharacterCollisionLayer);
                    if (!IsRaycastOK(m_raycastList))
                    {
                        return(false);
                    }
                }
            }

            if (requireRaycast)
            {
                // short raycast, not causing problems with asteroids generating geometry
                Physics.MyPhysics.CastRay(line.From, castStartSafe + line.Direction, m_raycastList, MyPhysics.CollisionLayers.CharacterCollisionLayer);
                if (!IsRaycastOK(m_raycastList))
                {
                    return(false);
                }
            }

            HkShape shape = new HkSphereShape(CAMERA_RADIUS);

            try
            {
                // small shape, not causing problems with asteroids generating geometry
                Physics.MyPhysics.GetPenetrationsShape(shape, ref castStartSafe, ref Quaternion.Identity, m_rigidList, MyPhysics.CollisionLayers.CharacterCollisionLayer);
                if (m_rigidList.Count > 0)
                {
                    bool sameGrid = false;
                    if (MySession.Static.ControlledEntity != null && m_rigidList[0].Body != null)
                    {
                        sameGrid = m_rigidList[0].GetCollisionEntity() == MySession.Static.ControlledEntity;
                    }

                    if (sameGrid)
                    {
                        castStartSafe += line.Direction;
                    }
                }

                var  shapeCastLine = new LineD(castStartSafe, m_position);
                uint steps         = 1;
                uint stepIdx       = 0;
                if (shapeCastLine.Length > SHAPE_CAST_STEP)
                {
                    steps = (uint)Math.Ceiling(shapeCastLine.Length / SHAPE_CAST_STEP);
                    if (steps >= SHAPE_CAST_MAX_STEP_COUNT)
                    {
                        steps = SHAPE_CAST_MAX_STEP_COUNT - 1;
                    }
                    stepIdx = m_updateCount % steps;
                    m_lastShapeCastDistance[stepIdx] = float.PositiveInfinity;

                    Vector3D step = shapeCastLine.Direction * (shapeCastLine.Length / steps);
                    shapeCastLine = new LineD(castStartSafe + stepIdx * step, castStartSafe + (stepIdx + 1) * step);
                }

                if (false)
                {
                    BoundingBoxD bbox = BoundingBoxD.CreateInvalid();
                    bbox.Include(new BoundingSphereD(shapeCastLine.From, CAMERA_RADIUS));
                    bbox.Include(new BoundingSphereD(shapeCastLine.To, CAMERA_RADIUS));
                    VRageRender.MyRenderProxy.DebugDrawAABB(bbox, Color.Crimson, 1f, 1f, true);
                }

                var matrix = MatrixD.CreateTranslation(shapeCastLine.From);
                HkContactPointData?cpd;
                if (controlledEntity.Physics != null && controlledEntity.GetPhysicsBody().CharacterProxy != null)
                {
                    cpd = MyPhysics.CastShapeReturnContactData(shapeCastLine.To, shape, ref matrix, MyPhysics.CollisionLayers.CharacterCollisionLayer, 0.0f);
                }
                else
                {
                    cpd = MyPhysics.CastShapeReturnContactData(shapeCastLine.To, shape, ref matrix, MyPhysics.CollisionLayers.DefaultCollisionLayer, 0.0f);
                }
                if (cpd.HasValue)
                {
                    var point = shapeCastLine.From + shapeCastLine.Direction * shapeCastLine.Length * cpd.Value.DistanceFraction;
                    m_lastShapeCastDistance[stepIdx] = (float)(castStartSafe - point).Length();
                }
                else
                {
                    m_lastShapeCastDistance[stepIdx] = float.PositiveInfinity;
                }


                float?dist = null;
                for (int i = 0; i < steps; ++i)
                {
                    if (m_lastShapeCastDistance[i] != float.PositiveInfinity)
                    {
                        dist = Math.Min(m_lastShapeCastDistance[i], dist ?? float.PositiveInfinity);
                    }
                }

                if (dist.HasValue)
                {
                    if (dist == 0.0f)
                    {
                        return(false);
                    }
                    else
                    {
                        m_positionSafe = castStartSafe + shapeCastLine.Direction * dist.Value;
                    }
                }
                else
                {
                    m_positionSafe = m_position;
                }
                return(true);
            }
            finally
            {
                shape.RemoveReference();
            }
        }
        public override void AccumulateCorrection(ref VRageMath.Vector3 correction, ref float weight)
        {
            // Don't do any correction if we're not moving
            if (Parent.Speed < 0.01)
                return;

            Vector3D position = Parent.PositionAndOrientation.Translation;

            // Find trees
            Quaternion rotation = Quaternion.Identity;
            HkShape sphereShape = new HkSphereShape(6);
            MyPhysics.GetPenetrationsShape(sphereShape, ref position, ref rotation, m_trees, MyPhysics.CollisionLayers.NoVoxelCollisionLayer);

            foreach (var tree in m_trees)
            {
                // Make sure the tree is actually a tree
                if (tree.Body == null) continue;
                MyPhysicsBody physicsBody = tree.Body.UserObject as MyPhysicsBody;
                if (physicsBody == null) continue;

                HkShape bodyShape = tree.Body.GetShape();
                if (bodyShape.ShapeType != HkShapeType.StaticCompound)
                    continue;

                // Get the static compound shape
                HkStaticCompoundShape staticCompoundShape = (HkStaticCompoundShape)bodyShape;

                int instanceId;
                uint childKey;
                staticCompoundShape.DecomposeShapeKey(tree.ShapeKey, out instanceId, out childKey);

                // Get the local shape position, and add entity world position
                Vector3D item = staticCompoundShape.GetInstanceTransform(instanceId).Translation;
                item += physicsBody.GetWorldMatrix().Translation;

                // Avoid tree
                Vector3D dir = item - position;
                var dist = dir.Normalize();
                dir = Vector3D.Reject(Parent.ForwardVector, dir);

                dir.Y = 0.0f;
                if (dir.Z * dir.Z + dir.X * dir.X < 0.1)
                {
                    Vector3D dirLocal = Vector3D.TransformNormal(dir, Parent.PositionAndOrientationInverted);
                    dir = position - item;
                    dir = Vector3D.Cross(Vector3D.Up, dir);
                    if (dirLocal.X < 0)
                        dir = -dir;
                }

                dir.Normalize();

                correction += (6f - dist) * Weight * dir;
                if (!correction.IsValid())
                {
                    System.Diagnostics.Debugger.Break();
                }
            }

            m_trees.Clear();

            weight += Weight;
        }