예제 #1
0
        void GetTarget(IMyCharacter character, out IMyCubeGrid targetGrid, out IMySlimBlock targetBlock, out IMyPlayer targetPlayer, out Vector3D aimPoint)
        {
            targetGrid   = null;
            targetBlock  = null;
            targetPlayer = null;

            bool     aiming  = Utils.IsAimingDownSights(character);
            MatrixD  head    = character.GetHeadMatrix(false, true);
            Vector3D rayDir  = head.Forward;
            Vector3D rayFrom = head.Translation;

            if (aiming)
            {
                rayFrom += rayDir * PAINT_AIM_START_OFFSET;
            }

            Vector3D rayTo = head.Translation + rayDir * PAINT_DISTANCE;

            aimPoint = rayTo;

            targetGrid = MyAPIGateway.CubeBuilder.FindClosestGrid();

            if (targetGrid == null || targetGrid.Physics == null || !targetGrid.Physics.Enabled)
            {
                targetGrid = null;
                return;
            }

            // older selection behavior when aiming down sights
            if (aiming)
            {
                Vector3I?blockPos = targetGrid.RayCastBlocks(rayFrom, rayTo);

                if (blockPos.HasValue)
                {
                    targetBlock = targetGrid.GetCubeBlock(blockPos.Value);
                }

                return;
            }

            // HACK copied and converted from MyDrillSensorRayCast.ReadEntitiesInRange() + MyCasterComponent.OnWorldPosChanged()
            // last cloned in SE v201
            #region Welder-like block selection
            hits.Clear();
            detections.Clear();
            rayOverlapResults.Clear();

            MyAPIGateway.Physics.CastRay(rayFrom, rayTo, hits, 24);

            foreach (IHitInfo hit in hits)
            {
                IMyEntity parent = hit.HitEntity?.GetTopMostParent();
                if (parent == null || parent.Physics == null || !parent.Physics.Enabled)
                {
                    continue;
                }

                Vector3D    hitPos = hit.Position;
                IMyCubeGrid grid   = parent as IMyCubeGrid;
                if (grid != null)
                {
                    // just how it's set in game code /shrug
                    hitPos += hit.Normal * -0.005f;
                }

                DetectionInfo detected;
                if (detections.TryGetValue(parent.EntityId, out detected))
                {
                    double dist1 = Vector3D.DistanceSquared(rayFrom, detected.DetectionPoint);
                    double dist2 = Vector3D.DistanceSquared(rayFrom, hitPos);
                    if (dist1 > dist2)
                    {
                        detections[parent.EntityId] = new DetectionInfo(parent, hitPos);
                    }
                }
                else
                {
                    detections[parent.EntityId] = new DetectionInfo(parent, hitPos);
                }
            }

            hits.Clear();

            LineD line = new LineD(rayFrom, rayTo);
            MyGamePruningStructure.GetAllEntitiesInRay(ref line, rayOverlapResults);

            foreach (MyLineSegmentOverlapResult <MyEntity> result in rayOverlapResults)
            {
                if (result.Element == null)
                {
                    continue;
                }

                IMyCubeBlock block = result.Element as IMyCubeBlock;
                if (block == null)
                {
                    continue;
                }

                MyCubeBlockDefinition def = (MyCubeBlockDefinition)block.SlimBlock.BlockDefinition;
                if (def.HasPhysics)
                {
                    continue; // this section is only for things that are not caught by the raycast
                }
                MyEntity parent = result.Element.GetTopMostParent();
                if (parent.Physics == null || !parent.Physics.Enabled)
                {
                    continue;
                }

                MatrixD invMatrix = block.PositionComp.WorldMatrixNormalizedInv;
                Vector3 localFrom = Vector3D.Transform(rayFrom, ref invMatrix);
                Vector3 localTo   = Vector3D.Transform(rayTo, ref invMatrix);

                float?intersectDistance = new Ray(localFrom, Vector3.Normalize(localTo - localFrom)).Intersects(block.PositionComp.LocalAABB) + 0.01f;
                if (intersectDistance.HasValue && intersectDistance <= PAINT_DISTANCE)
                {
                    Vector3D      hitPos = rayFrom + rayDir * intersectDistance.Value;
                    DetectionInfo detected;
                    if (detections.TryGetValue(parent.EntityId, out detected))
                    {
                        double dist1 = Vector3D.DistanceSquared(rayFrom, detected.DetectionPoint);
                        double dist2 = Vector3D.DistanceSquared(rayFrom, hitPos);
                        if (dist1 > dist2)
                        {
                            detections[parent.EntityId] = new DetectionInfo(parent, hitPos);
                        }
                    }
                    else
                    {
                        detections[parent.EntityId] = new DetectionInfo(parent, hitPos);
                    }
                }
            }

            rayOverlapResults.Clear();

            if (detections.Count == 0)
            {
                return;
            }

            double        closetDist = double.MaxValue;
            DetectionInfo closestObj = new DetectionInfo(null, Vector3D.Zero);

            foreach (DetectionInfo detected in detections.Values)
            {
                double dist = Vector3D.DistanceSquared(detected.DetectionPoint, rayFrom);
                if (dist < closetDist)
                {
                    closestObj = detected;
                    closetDist = dist;
                }
            }

            detections.Clear();

            targetGrid = closestObj.Entity as IMyCubeGrid;
            if (targetGrid == null)
            {
                return;
            }

            Vector3D localPos = Vector3D.Transform(closestObj.DetectionPoint, targetGrid.WorldMatrixNormalizedInv);
            Vector3I cube;
            targetGrid.FixTargetCube(out cube, localPos / targetGrid.GridSize);
            targetBlock = targetGrid.GetCubeBlock(cube);
            #endregion Welder-like block selection
        }