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 }