public MyDetectedEntityInfo Raycast(double distance, Vector3D direction) { if (Vector3D.IsZero(direction)) { throw new ArgumentOutOfRangeException("direction", "Direction cannot be 0,0,0"); } //mods can disable raycast on a block by setting the distance limit to 0 (-1 means infinite) if (distance <= 0 || (BlockDefinition.RaycastDistanceLimit > -1 && distance > BlockDefinition.RaycastDistanceLimit)) { return(new MyDetectedEntityInfo()); } if (AvailableScanRange < distance || !this.CheckIsWorking()) { return(new MyDetectedEntityInfo()); } AvailableScanRange -= distance; var startPos = this.WorldMatrix.Translation; var targetPos = startPos + direction * distance; //try a physics raycast first //very accurate, but very slow List <MyPhysics.HitInfo> hits = new List <MyPhysics.HitInfo>(); MyPhysics.CastRay(startPos, targetPos, hits); foreach (var hit in hits) { var entity = (MyEntity)hit.HkHitInfo.GetHitEntity(); if (entity == this) { continue; } m_lastRay = new RaycastInfo() { Distance = distance, Start = startPos, End = targetPos, Hit = hit.Position }; return(MyDetectedEntityInfoHelper.Create(entity, this.OwnerId, hit.Position)); } //long-distance planet scanning //fastest way is to intersect planet bounding boxes then treat the planet as a sphere LineD line = new LineD(startPos, targetPos); var voxels = new List <MyLineSegmentOverlapResult <MyVoxelBase> >(); MyGamePruningStructure.GetVoxelMapsOverlappingRay(ref line, voxels); foreach (var result in voxels) { var planet = result.Element as MyPlanet; if (planet == null) { continue; } double distCenter = Vector3D.DistanceSquared(this.PositionComp.GetPosition(), planet.PositionComp.GetPosition()); var gravComp = planet.Components.Get <MyGravityProviderComponent>(); if (gravComp == null) { continue; } if (!gravComp.IsPositionInRange(startPos) && distCenter > planet.MaximumRadius * planet.MaximumRadius) { var boundingSphere = new BoundingSphereD(planet.PositionComp.GetPosition(), planet.MaximumRadius); var rayd = new RayD(startPos, direction); var intersection = boundingSphere.Intersects(rayd); if (!intersection.HasValue) { continue; } if (distance < intersection.Value) { continue; } var hitPos = startPos + direction * intersection.Value; m_lastRay = new RaycastInfo() { Distance = distance, Start = startPos, End = targetPos, Hit = hitPos }; return(MyDetectedEntityInfoHelper.Create(result.Element, this.OwnerId, hitPos)); } //if the camera is inside gravity, query voxel storage if (planet.RootVoxel.Storage == null) { continue; } var start = Vector3D.Transform(line.From, planet.PositionComp.WorldMatrixInvScaled); start += planet.SizeInMetresHalf; var end = Vector3D.Transform(line.To, planet.PositionComp.WorldMatrixInvScaled); end += planet.SizeInMetresHalf; var voxRay = new LineD(start, end); double startOffset; double endOffset; if (!planet.RootVoxel.Storage.DataProvider.Intersect(ref voxRay, out startOffset, out endOffset)) { continue; } var from = voxRay.From; voxRay.From = from + voxRay.Direction * voxRay.Length * startOffset; voxRay.To = from + voxRay.Direction * voxRay.Length * endOffset; start = voxRay.From - planet.SizeInMetresHalf; start = Vector3D.Transform(start, planet.PositionComp.WorldMatrix); m_lastRay = new RaycastInfo() { Distance = distance, Start = startPos, End = targetPos, Hit = start }; return(MyDetectedEntityInfoHelper.Create(result.Element, this.OwnerId, start)); } m_lastRay = new RaycastInfo() { Distance = distance, Start = startPos, End = targetPos, Hit = null }; return(new MyDetectedEntityInfo()); }