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();
            }
        }
        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 #3
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();
            }
        }
        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 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();
        }
        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;
            }
        }
		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();
			}
		}
        /// <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);
            }
        }
        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;
            }
        }
        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();
        }
        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>
        /// 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 #14
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 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 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;
            }
        }
        /// <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);
        }
        /// <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;
        }
        /// <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);
            }
        }
Beispiel #20
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();
        }
Beispiel #21
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();
            }
        }
Beispiel #22
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();
        }