internal void DeferedVoxelCheck() { DeferedVoxels.ApplyAdditions(); for (int i = 0; i < DeferedVoxels.Count; i++) { var p = DeferedVoxels[i].Projectile; var branch = DeferedVoxels[i].Branch; var voxel = DeferedVoxels[i].Voxel; Vector3D?voxelHit = null; if (branch == VoxelIntersectBranch.DeferFullCheck) { if (p.Beam.Length > 85) { IHitInfo hit; p.Info.System.Session.Physics.CastLongRay(p.Beam.From, p.Beam.To, out hit, false); if (hit?.HitEntity is MyVoxelBase) { voxelHit = hit.Position; } } else { using (voxel.Pin()) { if (!voxel.GetIntersectionWithLine(ref p.Beam, out voxelHit, true, IntersectionFlags.DIRECT_TRIANGLES) && VoxelIntersect.PointInsideVoxel(voxel, p.Info.System.Session.TmpStorage, p.Beam.From)) { voxelHit = p.Beam.From; } } } if (voxelHit.HasValue && p.Info.IsShrapnel && p.Info.Age == 0) { if (!VoxelIntersect.PointInsideVoxel(voxel, p.Info.System.Session.TmpStorage, voxelHit.Value + (p.Beam.Direction * 1.25f))) { voxelHit = null; } } } else if (branch == VoxelIntersectBranch.DeferedMissUpdate) { using (voxel.Pin()) { if (!voxel.GetIntersectionWithLine(ref p.Beam, out voxelHit, true, IntersectionFlags.DIRECT_TRIANGLES) && VoxelIntersect.PointInsideVoxel(voxel, p.Info.System.Session.TmpStorage, p.Beam.From)) { voxelHit = p.Beam.From; } } } if (!voxelHit.HasValue) { if (p.Info.VoxelCache.MissSphere.Contains(p.Beam.To) == ContainmentType.Disjoint) { p.Info.VoxelCache.MissSphere.Center = p.Beam.To; } continue; } p.Info.VoxelCache.Update(voxel, ref voxelHit, p.Info.System.Session.Tick); if (voxelHit == null) { continue; } if (!p.FinalizeIntersection) { p.FinalizeIntersection = true; FinalHitCheck.Add(p); } var hitEntity = HitEntityPool.Get(); var lineCheck = p.Info.ConsumableDef.Const.CollisionIsLine && !p.Info.EwarAreaPulse; hitEntity.Info = p.Info; hitEntity.Entity = voxel; hitEntity.Intersection = p.Beam; hitEntity.SphereCheck = !lineCheck; hitEntity.PruneSphere = p.PruneSphere; hitEntity.DamageOverTime = p.Info.ConsumableDef.Const.AreaEffect == DotField; var hitPos = voxelHit.Value; hitEntity.HitPos = hitPos; double dist; Vector3D.Distance(ref p.Beam.From, ref hitPos, out dist); hitEntity.HitDist = dist; hitEntity.EventType = Voxel; p.Info.HitList.Add(hitEntity); } DeferedVoxels.ClearImmediate(); }
internal bool GetAllEntitiesInLine(Projectile p, LineD beam) { var shieldByPass = p.Info.AmmoDef.DamageScales.Shields.Type == ShieldDef.ShieldType.Bypass; var shieldFullBypass = shieldByPass && p.Info.AmmoDef.Const.ShieldBypassMod >= 1; var genericFields = p.Info.EwarActive && (p.Info.AmmoDef.Const.AreaEffect == DotField || p.Info.AmmoDef.Const.AreaEffect == PushField || p.Info.AmmoDef.Const.AreaEffect == PullField); var ai = p.Info.Ai; var found = false; var lineCheck = p.Info.AmmoDef.Const.CollisionIsLine && !p.Info.EwarActive && !p.Info.TriggeredPulse; var planetBeam = beam; planetBeam.To = p.Info.AmmoDef.Const.IsBeamWeapon && p.Info.MaxTrajectory > 1500 ? beam.From + (beam.Direction * 1500) : beam.To; p.EntitiesNear = false; bool projetileInShield = false; for (int i = 0; i < p.SegmentList.Count; i++) { var ent = p.SegmentList[i].Element; var grid = ent as MyCubeGrid; var destroyable = ent as IMyDestroyableObject; var voxel = ent as MyVoxelBase; var safeZone = ent as MySafeZone; if (ent is IMyCharacter && p.Info.EwarActive && !genericFields) { continue; } if (grid != null && p.SmartsOn && p.Info.Ai.MyGrid.IsSameConstructAs(grid) || ent.MarkedForClose || !ent.InScene || ent == p.Info.Ai.MyShield) { continue; } if (safeZone != null) { var outSideSphere = safeZone.Shape == MySafeZoneShape.Sphere && safeZone.PositionComp.WorldVolume.Contains(p.Info.Origin) == ContainmentType.Disjoint; var outSideBox = safeZone.Shape == MySafeZoneShape.Box && safeZone.PositionComp.WorldAABB.Contains(p.Info.Origin) == ContainmentType.Disjoint; var outside = outSideSphere || outSideBox; if (outside) { p.State = Projectile.ProjectileState.Detonate; p.ForceHitParticle = true; break; } } if (!shieldFullBypass && !p.ShieldBypassed || p.Info.EwarActive && (p.Info.AmmoDef.Const.AreaEffect == DotField || p.Info.AmmoDef.Const.AreaEffect == EmpField)) { var shieldInfo = p.Info.Ai.Session.SApi?.MatchEntToShieldFastExt(ent, true); if (shieldInfo != null && !p.Info.Ai.MyGrid.IsSameConstructAs(shieldInfo.Value.Item1.CubeGrid)) { double?dist = null; if (ent.Physics != null && ent.Physics.IsPhantom) { p.EntitiesNear = true; dist = MathFuncs.IntersectEllipsoid(shieldInfo.Value.Item3.Item1, shieldInfo.Value.Item3.Item2, new RayD(beam.From, beam.Direction)); if (p.Info.Target.IsProjectile && Vector3D.Transform(p.Info.Target.Projectile.Position, shieldInfo.Value.Item3.Item1).LengthSquared() <= 1) { projetileInShield = true; } } if (dist != null && (dist.Value < beam.Length || p.Info.EwarActive) && !p.Info.Ai.MyGrid.IsSameConstructAs(shieldInfo.Value.Item1.CubeGrid)) { var hitEntity = HitEntityPool.Get(); hitEntity.Info = p.Info; found = true; if (shieldByPass) { p.ShieldBypassed = true; } hitEntity.Entity = (MyEntity)shieldInfo.Value.Item1; hitEntity.Intersection = beam; hitEntity.EventType = Shield; hitEntity.SphereCheck = !lineCheck; hitEntity.PruneSphere = p.PruneSphere; hitEntity.HitPos = beam.From + (beam.Direction * dist.Value); hitEntity.HitDist = dist; p.Info.HitList.Add(hitEntity); } else { continue; } } } if ((ent == ai.MyPlanet && (p.LinePlanetCheck || p.DynamicGuidance || p.CachedPlanetHit)) || ent.Physics != null && !ent.Physics.IsPhantom && !ent.IsPreview && (grid != null || voxel != null || destroyable != null)) { var extFrom = beam.From - (beam.Direction * (ent.PositionComp.WorldVolume.Radius * 2)); var extBeam = new LineD(extFrom, beam.To); var rotMatrix = Quaternion.CreateFromRotationMatrix(ent.WorldMatrix); var obb = new MyOrientedBoundingBoxD(ent.PositionComp.WorldAABB.Center, ent.PositionComp.LocalAABB.HalfExtents, rotMatrix); if (lineCheck && obb.Intersects(ref extBeam) == null || !lineCheck && !obb.Intersects(ref p.PruneSphere)) { continue; } Vector3D?voxelHit = null; if (voxel != null) { if (voxel.RootVoxel != voxel) { continue; } if (voxel == ai.MyPlanet) { if (p.CachedPlanetHit) { IHitInfo cachedPlanetResult; if (p.Info.WeaponCache.VoxelHits[p.CachedId].NewResult(out cachedPlanetResult)) { voxelHit = cachedPlanetResult.Position; } else { continue; } } if (p.LinePlanetCheck) { var surfacePos = ai.MyPlanet.GetClosestSurfacePointGlobal(ref p.Position); var planetCenter = ai.MyPlanet.PositionComp.WorldAABB.Center; double surfaceToCenter; Vector3D.DistanceSquared(ref surfacePos, ref planetCenter, out surfaceToCenter); double endPointToCenter; Vector3D.DistanceSquared(ref p.Position, ref planetCenter, out endPointToCenter); double startPointToCenter; Vector3D.DistanceSquared(ref p.Info.Origin, ref planetCenter, out startPointToCenter); var prevEndPointToCenter = p.PrevEndPointToCenterSqr; Vector3D.DistanceSquared(ref surfacePos, ref p.Position, out p.PrevEndPointToCenterSqr); if (surfaceToCenter > endPointToCenter || p.PrevEndPointToCenterSqr <= (planetBeam.Length * planetBeam.Length) || endPointToCenter > startPointToCenter && prevEndPointToCenter > p.DistanceToTravelSqr || surfaceToCenter > Vector3D.DistanceSquared(planetCenter, p.LastPosition)) { using (voxel.Pin()) { if (VoxelIntersect.PosHasVoxel(voxel, planetBeam.From)) { voxelHit = planetBeam.From; } else { voxel.GetIntersectionWithLine(ref planetBeam, out voxelHit); } } } } } else { using (voxel.Pin()) voxel.GetIntersectionWithLine(ref beam, out voxelHit); } if (!voxelHit.HasValue) { continue; } } var hitEntity = HitEntityPool.Get(); hitEntity.Info = p.Info; hitEntity.Entity = ent; hitEntity.Intersection = beam; hitEntity.SphereCheck = !lineCheck; hitEntity.PruneSphere = p.PruneSphere; if (voxelHit != null) { var hitPos = voxelHit.Value; hitEntity.HitPos = hitPos; double dist; Vector3D.Distance(ref beam.From, ref hitPos, out dist); hitEntity.HitDist = dist; } if (grid != null) { var isSameConstruct = grid.IsSameConstructAs(p.Info.Target.FiringCube.CubeGrid); if (isSameConstruct) { if (!p.Info.AmmoDef.Const.IsBeamWeapon && beam.Length <= grid.GridSize * 2) { MyCube cube; if (!(grid.TryGetCube(grid.WorldToGridInteger(p.Position), out cube) && cube.CubeBlock != p.Info.Target.FiringCube.SlimBlock || grid.TryGetCube(grid.WorldToGridInteger(p.LastPosition), out cube) && cube.CubeBlock != p.Info.Target.FiringCube.SlimBlock)) { continue; } } if (!hitEntity.SphereCheck && !p.Info.EwarActive) { grid.RayCastCells(hitEntity.Intersection.From, hitEntity.Intersection.To, hitEntity.Vector3ICache, null, true, true); if (hitEntity.Vector3ICache.Count > 0) { IHitInfo hitInfo; p.Info.Ai.Session.Physics.CastRay(hitEntity.Intersection.From, hitEntity.Intersection.To, out hitInfo, CollisionLayers.DefaultCollisionLayer, false); var hitGrid = hitInfo?.HitEntity?.GetTopMostParent() as MyCubeGrid; if (hitGrid == null || !hitGrid.IsSameConstructAs(p.Info.Target.FiringCube.CubeGrid)) { continue; } hitEntity.HitPos = hitInfo.Position; } } } else { grid.RayCastCells(hitEntity.Intersection.From, hitEntity.Intersection.To, hitEntity.Vector3ICache, null, true, true); } if (!(p.Info.EwarActive && p.Info.AmmoDef.Const.EwarEffect)) { hitEntity.EventType = Grid; } else if (!p.Info.AmmoDef.Const.Pulse) { hitEntity.EventType = Effect; } else { hitEntity.EventType = Field; } if (p.Info.AmmoDef.Const.AreaEffect == DotField) { hitEntity.DamageOverTime = true; } p.EntitiesNear = true; } else if (destroyable != null) { hitEntity.EventType = Destroyable; } else if (voxel != null) { hitEntity.EventType = Voxel; } found = true; p.Info.HitList.Add(hitEntity); } } if (p.Info.Target.IsProjectile && !p.Info.AmmoDef.Const.EwarEffect && !projetileInShield) { var detonate = p.State == Projectile.ProjectileState.Detonate; var hitTolerance = detonate ? p.Info.AmmoDef.AreaEffect.Detonation.DetonationRadius : p.Info.AmmoDef.Const.AreaEffectSize > p.Info.AmmoDef.Const.CollisionSize ? p.Info.AmmoDef.Const.AreaEffectSize : p.Info.AmmoDef.Const.CollisionSize; var useLine = p.Info.AmmoDef.Const.CollisionIsLine && !detonate && p.Info.AmmoDef.Const.AreaEffectSize <= 0; var sphere = new BoundingSphereD(p.Info.Target.Projectile.Position, p.Info.Target.Projectile.Info.AmmoDef.Const.CollisionSize); sphere.Include(new BoundingSphereD(p.Info.Target.Projectile.LastPosition, 1)); var rayCheck = useLine && sphere.Intersects(new RayD(p.LastPosition, p.Info.Direction)) != null; var testSphere = p.PruneSphere; testSphere.Radius = hitTolerance; if (rayCheck || sphere.Intersects(testSphere)) { found = ProjectileHit(p, p.Info.Target.Projectile, lineCheck, ref beam); } } p.SegmentList.Clear(); return(found && GenerateHitInfo(p)); }