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 void InitialHitCheck() { var vhCount = ValidateHits.Count; var minCount = Session.Settings.Enforcement.ServerOptimizations ? 96 : 99999; var stride = vhCount < minCount ? 100000 : 48; MyAPIGateway.Parallel.For(0, ValidateHits.Count, x => { var p = ValidateHits[x]; var shieldByPass = p.Info.ConsumableDef.DamageScales.Shields.Type == ShieldDef.ShieldType.Bypass; var shieldFullBypass = shieldByPass && p.Info.ConsumableDef.Const.ShieldBypassMod >= 1; var genericFields = p.Info.EwarActive && (p.Info.ConsumableDef.Const.AreaEffect == DotField || p.Info.ConsumableDef.Const.AreaEffect == PushField || p.Info.ConsumableDef.Const.AreaEffect == PullField); p.FinalizeIntersection = false; var lineCheck = p.Info.ConsumableDef.Const.CollisionIsLine && !p.Info.EwarAreaPulse; var ewarProjectile = (p.Info.EwarActive || p.Info.ConsumableDef.Const.EwarEffect); bool projetileInShield = false; var tick = p.Info.System.Session.Tick; var useEntityCollection = p.CheckType != Projectile.CheckTypes.Ray; var entityCollection = p.UseEntityCache ? p.Info.Ai.NearByEntityCache : p.MyEntityList; var collectionCount = !useEntityCollection ? p.MySegmentList.Count : entityCollection.Count; var ray = new RayD(ref p.Beam.From, ref p.Beam.Direction); var myGrid = p.Info.Target.FiringCube.CubeGrid; Water water = null; if (Session.WaterApiLoaded && p.Info.MyPlanet != null) { Session.WaterMap.TryGetValue(p.Info.MyPlanet, out water); } for (int i = 0; i < collectionCount; i++) { var ent = !useEntityCollection ? p.MySegmentList[i].Element : entityCollection[i]; var grid = ent as MyCubeGrid; var entIsSelf = grid != null && (grid == myGrid || myGrid.IsSameConstructAs(grid)); if (entIsSelf && p.SmartsOn || ent.MarkedForClose || !ent.InScene || ent == p.Info.MyShield) { continue; } var character = ent as IMyCharacter; if (p.Info.EwarActive && character != null && !genericFields) { continue; } var entSphere = ent.PositionComp.WorldVolume; if (useEntityCollection) { if (p.CheckType == Projectile.CheckTypes.CachedRay) { var dist = ray.Intersects(entSphere); if (!dist.HasValue || dist > p.Beam.Length) { continue; } } else if (p.CheckType == Projectile.CheckTypes.CachedSphere && p.PruneSphere.Contains(entSphere) == ContainmentType.Disjoint) { continue; } } if (grid != null || character != null) { var extBeam = new LineD(p.Beam.From - p.Beam.Direction * (entSphere.Radius * 2), p.Beam.To); var transform = ent.PositionComp.WorldMatrixRef; var box = ent.PositionComp.LocalAABB; var obb = new MyOrientedBoundingBoxD(box, transform); if (lineCheck && obb.Intersects(ref extBeam) == null || !lineCheck && !obb.Intersects(ref p.PruneSphere)) { continue; } } var safeZone = ent as MySafeZone; if (safeZone != null && safeZone.Enabled) { var action = (Session.SafeZoneAction)safeZone.AllowedActions; if ((action & Session.SafeZoneAction.Damage) == 0) { bool intersects; if (safeZone.Shape == MySafeZoneShape.Sphere) { var sphere = new BoundingSphereD(safeZone.PositionComp.WorldVolume.Center, safeZone.Radius); var dist = ray.Intersects(sphere); intersects = dist != null && dist <= p.Beam.Length; } else { intersects = new MyOrientedBoundingBoxD(safeZone.PositionComp.LocalAABB, safeZone.PositionComp.WorldMatrixRef).Intersects(ref p.Beam) != null; } if (intersects) { p.State = Projectile.ProjectileState.Depleted; p.EarlyEnd = true; if (p.EnableAv) { p.Info.AvShot.ForceHitParticle = true; } break; } } } HitEntity hitEntity = null; var checkShield = Session.ShieldApiLoaded && Session.ShieldHash == ent.DefinitionId?.SubtypeId && ent.Render.Visible; MyTuple <IMyTerminalBlock, MyTuple <bool, bool, float, float, float, int>, MyTuple <MatrixD, MatrixD> >?shieldInfo = null; if (checkShield && (!shieldFullBypass && !p.ShieldBypassed || p.Info.EwarActive && (p.Info.ConsumableDef.Const.AreaEffect == DotField || p.Info.ConsumableDef.Const.AreaEffect == EmpField))) { shieldInfo = p.Info.System.Session.SApi.MatchEntToShieldFastExt(ent, true); if (shieldInfo != null && !myGrid.IsSameConstructAs(shieldInfo.Value.Item1.CubeGrid)) { if (p.Info.IsShrapnel || Vector3D.Transform(p.Info.Origin, shieldInfo.Value.Item3.Item1).LengthSquared() > 1) { p.EntitiesNear = true; var dist = MathFuncs.IntersectEllipsoid(shieldInfo.Value.Item3.Item1, shieldInfo.Value.Item3.Item2, new RayD(p.Beam.From, p.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 < p.Beam.Length || p.Info.EwarActive)) { if (shieldByPass) { p.ShieldBypassed = true; } hitEntity = HitEntityPool.Get(); hitEntity.EventType = Shield; hitEntity.HitPos = p.Beam.From + (p.Beam.Direction * dist.Value); hitEntity.HitDist = dist; } else { continue; } } } } var destroyable = ent as IMyDestroyableObject; var voxel = ent as MyVoxelBase; if (voxel != null && voxel == voxel?.RootVoxel) { if (ent == p.Info.MyPlanet && !(p.LinePlanetCheck || p.DynamicGuidance || p.CachedPlanetHit)) { continue; } VoxelIntersectBranch voxelState = VoxelIntersectBranch.None; Vector3D?voxelHit = null; if (tick - p.Info.VoxelCache.HitRefreshed < 60) { var cacheDist = ray.Intersects(p.Info.VoxelCache.HitSphere); if (cacheDist.HasValue && cacheDist.Value <= p.Beam.Length) { voxelHit = p.Beam.From + (p.Beam.Direction * cacheDist.Value); voxelState = VoxelIntersectBranch.PseudoHit1; } else if (cacheDist.HasValue) { p.Info.VoxelCache.MissSphere.Center = p.Beam.To; } } if (voxelState != VoxelIntersectBranch.PseudoHit1) { if (voxel == p.Info.MyPlanet && p.Info.VoxelCache.MissSphere.Contains(p.Beam.To) == ContainmentType.Disjoint) { if (p.LinePlanetCheck) { if (water != null && !p.Info.ConsumableDef.IgnoreWater) { var waterSphere = new BoundingSphereD(p.Info.MyPlanet.PositionComp.WorldAABB.Center, water.radius); var estiamtedSurfaceDistance = ray.Intersects(waterSphere); if (estiamtedSurfaceDistance.HasValue && estiamtedSurfaceDistance.Value <= p.Beam.Length) { var estimatedHit = ray.Position + (ray.Direction * estiamtedSurfaceDistance.Value); voxelHit = estimatedHit; voxelState = VoxelIntersectBranch.PseudoHit2; } } if (voxelState != VoxelIntersectBranch.PseudoHit2) { var surfacePos = p.Info.MyPlanet.GetClosestSurfacePointGlobal(ref p.Position); var planetCenter = p.Info.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 <= (p.Beam.Length * p.Beam.Length) || endPointToCenter > startPointToCenter && prevEndPointToCenter > p.DistanceToTravelSqr || surfaceToCenter > Vector3D.DistanceSquared(planetCenter, p.LastPosition)) { var estiamtedSurfaceDistance = ray.Intersects(p.Info.VoxelCache.PlanetSphere); var fullCheck = p.Info.VoxelCache.PlanetSphere.Contains(p.Info.Origin) != ContainmentType.Disjoint || !estiamtedSurfaceDistance.HasValue; if (!fullCheck && estiamtedSurfaceDistance.HasValue && (estiamtedSurfaceDistance.Value <= p.Beam.Length || p.Info.VoxelCache.PlanetSphere.Radius < 1)) { double distSqr; var estimatedHit = ray.Position + (ray.Direction * estiamtedSurfaceDistance.Value); Vector3D.DistanceSquared(ref p.Info.VoxelCache.FirstPlanetHit, ref estimatedHit, out distSqr); if (distSqr > 625) { fullCheck = true; } else { voxelHit = estimatedHit; voxelState = VoxelIntersectBranch.PseudoHit2; } } if (fullCheck) { voxelState = VoxelIntersectBranch.DeferFullCheck; } if (voxelHit.HasValue && Vector3D.DistanceSquared(voxelHit.Value, p.Info.VoxelCache.PlanetSphere.Center) > p.Info.VoxelCache.PlanetSphere.Radius * p.Info.VoxelCache.PlanetSphere.Radius) { p.Info.VoxelCache.GrowPlanetCache(voxelHit.Value); } } } } } else if (voxelHit == null && p.Info.VoxelCache.MissSphere.Contains(p.Beam.To) == ContainmentType.Disjoint) { voxelState = VoxelIntersectBranch.DeferedMissUpdate; } } if (voxelState == VoxelIntersectBranch.PseudoHit1 || voxelState == VoxelIntersectBranch.PseudoHit2) { if (!voxelHit.HasValue) { if (p.Info.VoxelCache.MissSphere.Contains(p.Beam.To) == ContainmentType.Disjoint) { p.Info.VoxelCache.MissSphere.Center = p.Beam.To; } continue; } hitEntity = HitEntityPool.Get(); 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; } else if (voxelState == VoxelIntersectBranch.DeferedMissUpdate || voxelState == VoxelIntersectBranch.DeferFullCheck) { DeferedVoxels.Add(new DeferedVoxels { Projectile = p, Branch = voxelState, Voxel = voxel }); } } else if (ent.Physics != null && !ent.Physics.IsPhantom && !ent.IsPreview && grid != null) { if (grid != null) { hitEntity = HitEntityPool.Get(); if (entIsSelf) { if (!p.Info.ConsumableDef.Const.IsBeamWeapon && p.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)) { HitEntityPool.Return(hitEntity); continue; } } if (!p.Info.EwarAreaPulse) { var forwardPos = p.Info.Age != 1 ? p.Beam.From : p.Beam.From + (p.Beam.Direction * Math.Min(grid.GridSizeHalf, p.Info.DistanceTraveled - p.Info.PrevDistanceTraveled)); grid.RayCastCells(forwardPos, p.Beam.To, hitEntity.Vector3ICache, null, true, true); if (hitEntity.Vector3ICache.Count > 0) { IHitInfo hitInfo; p.Info.System.Session.Physics.CastRay(forwardPos, p.Beam.To, out hitInfo, CollisionLayers.DefaultCollisionLayer); var hitGrid = hitInfo?.HitEntity?.GetTopMostParent() as MyCubeGrid; if (hitGrid == null || !myGrid.IsSameConstructAs(hitGrid)) { HitEntityPool.Return(hitEntity); continue; } hitEntity.HitPos = hitInfo.Position; hitEntity.Blocks.Add(grid.GetCubeBlock(hitEntity.Vector3ICache[0])); } } } else { grid.RayCastCells(p.Beam.From, p.Beam.To, hitEntity.Vector3ICache, null, true, true); } if (!ewarProjectile) { hitEntity.EventType = Grid; } else if (!p.Info.EwarAreaPulse) { hitEntity.EventType = Effect; } else { hitEntity.EventType = Field; } p.EntitiesNear = true; } } else if (destroyable != null) { hitEntity = HitEntityPool.Get(); hitEntity.EventType = Destroyable; } if (hitEntity != null) { p.FinalizeIntersection = true; hitEntity.Info = p.Info; hitEntity.Entity = hitEntity.EventType != Shield ? ent : (MyEntity)shieldInfo.Value.Item1; hitEntity.Intersection = p.Beam; hitEntity.SphereCheck = !lineCheck; hitEntity.PruneSphere = p.PruneSphere; hitEntity.SelfHit = entIsSelf; hitEntity.DamageOverTime = p.Info.ConsumableDef.Const.AreaEffect == DotField; p.Info.HitList.Add(hitEntity); } } if (p.Info.Target.IsProjectile && !p.Info.ConsumableDef.Const.EwarEffect && !projetileInShield) { var detonate = p.State == Projectile.ProjectileState.Detonate; var hitTolerance = detonate ? p.Info.ConsumableDef.Const.DetonationRadius : p.Info.ConsumableDef.Const.AreaEffectSize > p.Info.ConsumableDef.Const.CollisionSize ? p.Info.ConsumableDef.Const.AreaEffectSize : p.Info.ConsumableDef.Const.CollisionSize; var useLine = p.Info.ConsumableDef.Const.CollisionIsLine && !detonate && p.Info.ConsumableDef.Const.AreaEffectSize <= 0; var sphere = new BoundingSphereD(p.Info.Target.Projectile.Position, p.Info.Target.Projectile.Info.ConsumableDef.Const.CollisionSize); sphere.Include(new BoundingSphereD(p.Info.Target.Projectile.LastPosition, 1)); bool rayCheck = false; if (useLine) { var dist = sphere.Intersects(new RayD(p.LastPosition, p.Info.Direction)); if (dist <= hitTolerance || p.Info.ConsumableDef.Const.IsBeamWeapon && dist <= p.Beam.Length) { rayCheck = true; } } var testSphere = p.PruneSphere; testSphere.Radius = hitTolerance; if (rayCheck || sphere.Intersects(testSphere)) { ProjectileHit(p, p.Info.Target.Projectile, lineCheck, ref p.Beam); } } if (!useEntityCollection) { p.MySegmentList.Clear(); } else if (p.CheckType == Projectile.CheckTypes.Sphere) { entityCollection.Clear(); } if (p.FinalizeIntersection) { FinalHitCheck.Add(p); } }, stride); ValidateHits.ClearImmediate(); }