internal int GetEntityCompareDist(HitEntity x, HitEntity y, List <Vector3I> slims, ProInfo info) { var xDist = double.MaxValue; var yDist = double.MaxValue; var beam = x.Intersection; var count = y != null ? 2 : 1; var eWarPulse = info.AmmoDef.Const.Ewar && info.AmmoDef.Const.Pulse; var triggerEvent = eWarPulse && !info.TriggeredPulse && info.AmmoDef.Const.EwarTriggerRange > 0; for (int i = 0; i < count; i++) { var isX = i == 0; MyEntity ent; HitEntity hitEnt; if (isX) { hitEnt = x; ent = hitEnt.Entity; } else { hitEnt = y; ent = hitEnt.Entity; } var dist = double.MaxValue; var shield = ent as IMyTerminalBlock; var grid = ent as MyCubeGrid; var voxel = ent as MyVoxelBase; if (triggerEvent && (info.Ai.Targets.ContainsKey(ent) || shield != null)) { hitEnt.PulseTrigger = true; } else if (hitEnt.Projectile != null) { dist = hitEnt.HitDist.Value; } else if (shield != null) { hitEnt.Hit = true; dist = hitEnt.HitDist.Value; } else if (grid != null) { if (hitEnt.Hit) { dist = Vector3D.Distance(hitEnt.Intersection.From, hitEnt.HitPos.Value); hitEnt.HitDist = dist; } else { if (hitEnt.SphereCheck || info.EwarActive) { var ewarActive = hitEnt.EventType == Field || hitEnt.EventType == Effect; var hitPos = !ewarActive ? hitEnt.PruneSphere.Center + (hitEnt.Intersection.Direction * hitEnt.PruneSphere.Radius) : hitEnt.PruneSphere.Center; if (grid.IsSameConstructAs(hitEnt.Info.Ai.MyGrid) && Vector3D.DistanceSquared(hitPos, hitEnt.Info.Origin) <= grid.GridSize * grid.GridSize) { continue; } if (!ewarActive) { GetAndSortBlocksInSphere(hitEnt.Info.AmmoDef, hitEnt.Info.Ai, grid, hitEnt.PruneSphere, false, hitEnt.Blocks); } if (hitEnt.Blocks.Count > 0 || ewarActive) { dist = 0; hitEnt.HitDist = dist; hitEnt.Hit = true; hitEnt.HitPos = hitPos; } } else { grid.RayCastCells(beam.From, beam.To, slims, null, true, true); var closestBlockFound = false; var rotMatrix = Quaternion.CreateFromRotationMatrix(grid.PositionComp.WorldMatrixRef); var hitSelf = grid.IsSameConstructAs(hitEnt.Info.Target.FiringCube.CubeGrid); for (int j = 0; j < slims.Count; j++) { var firstBlock = grid.GetCubeBlock(slims[j]) as IMySlimBlock; if (firstBlock != null && !firstBlock.IsDestroyed && firstBlock != hitEnt.Info.Target.FiringCube.SlimBlock) { hitEnt.Blocks.Add(firstBlock); if (closestBlockFound) { continue; } MyOrientedBoundingBoxD obb; var fat = firstBlock.FatBlock; if (fat != null) { obb = new MyOrientedBoundingBoxD(fat.Model.BoundingBox, fat.PositionComp.WorldMatrixRef); } else { Vector3D center; firstBlock.ComputeWorldCenter(out center); Vector3 halfExt; firstBlock.ComputeScaledHalfExtents(out halfExt); var blockBox = new BoundingBoxD(-halfExt, halfExt); obb = new MyOrientedBoundingBoxD(center, blockBox.HalfExtents, rotMatrix); } var hitDist = obb.Intersects(ref beam) ?? Vector3D.Distance(beam.From, obb.Center); var hitPos = beam.From + (beam.Direction * hitDist); if (hitSelf) { if (Vector3D.DistanceSquared(hitPos, hitEnt.Info.Origin) <= grid.GridSize * 3) { hitEnt.Blocks.Clear(); } else { dist = hitDist; hitEnt.HitDist = dist; hitEnt.Hit = true; hitEnt.HitPos = hitPos; } break; } dist = hitDist; hitEnt.HitDist = dist; hitEnt.Hit = true; hitEnt.HitPos = hitPos; closestBlockFound = true; } } } } } else if (voxel != null) { hitEnt.Hit = true; dist = hitEnt.HitDist.Value; hitEnt.HitDist = dist; } else if (ent is IMyDestroyableObject) { if (hitEnt.Hit) { dist = Vector3D.Distance(hitEnt.Intersection.From, hitEnt.HitPos.Value); } else { if (hitEnt.SphereCheck || info.EwarActive) { var ewarActive = hitEnt.EventType == Field || hitEnt.EventType == Effect; dist = 0; hitEnt.HitDist = dist; hitEnt.Hit = true; var hitPos = !ewarActive ? hitEnt.PruneSphere.Center + (hitEnt.Intersection.Direction * hitEnt.PruneSphere.Radius) : hitEnt.PruneSphere.Center; hitEnt.HitPos = hitPos; } else { var rotMatrix = Quaternion.CreateFromRotationMatrix(ent.PositionComp.WorldMatrixRef); var obb = new MyOrientedBoundingBoxD(ent.PositionComp.WorldAABB.Center, ent.PositionComp.LocalAABB.HalfExtents, rotMatrix); dist = obb.Intersects(ref beam) ?? double.MaxValue; if (dist < double.MaxValue) { hitEnt.Hit = true; hitEnt.HitPos = beam.From + (beam.Direction * dist); hitEnt.HitDist = dist; } } } } if (isX) { xDist = dist; } else { yDist = dist; } } V3Pool.Return(slims); return(xDist.CompareTo(yDist)); }
internal bool GenerateHitInfo(Projectile p) { var count = p.Info.HitList.Count; if (count > 1) { p.Info.HitList.Sort((x, y) => GetEntityCompareDist(x, y, V3Pool.Get(), p.Info)); } else { GetEntityCompareDist(p.Info.HitList[0], null, V3Pool.Get(), p.Info); } var pulseTrigger = false; for (int i = p.Info.HitList.Count - 1; i >= 0; i--) { var ent = p.Info.HitList[i]; if (!ent.Hit) { if (ent.PulseTrigger) { pulseTrigger = true; } p.Info.HitList.RemoveAtFast(i); HitEntityPool.Return(ent); } else { break; } } if (pulseTrigger) { p.Info.TriggeredPulse = true; p.DistanceToTravelSqr = p.Info.DistanceTraveled * p.Info.DistanceTraveled; p.Velocity = Vector3D.Zero; p.Hit.HitPos = p.Position + p.Info.Direction * p.Info.AmmoDef.Const.EwarTriggerRange; p.Info.HitList.Clear(); return(false); } var finalCount = p.Info.HitList.Count; if (finalCount > 0) { var hitEntity = p.Info.HitList[0]; p.LastHitPos = hitEntity.HitPos; p.LastHitEntVel = hitEntity.Projectile?.Velocity ?? hitEntity.Entity?.Physics?.LinearVelocity ?? Vector3D.Zero; p.Info.LastHitShield = hitEntity.EventType == Shield; IMySlimBlock hitBlock = null; if (p.Info.AmmoDef.Const.VirtualBeams && hitEntity.Entity is MyCubeGrid) { hitBlock = hitEntity.Blocks[0]; } p.Hit = new Hit { Block = hitBlock, Entity = hitEntity.Entity, Projectile = null, HitPos = p.LastHitPos ?? Vector3D.Zero, HitVelocity = p.LastHitEntVel ?? Vector3D.Zero }; if (p.EnableAv) { p.Info.AvShot.Hit = p.Hit; } return(true); } return(false); }