Ejemplo n.º 1
0
        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();
        }
Ejemplo n.º 2
0
        internal bool GenerateHitInfo(Projectile p)
        {
            var count = p.Info.HitList.Count;

            if (count > 1)
            {
                p.Info.HitList.Sort((x, y) => GetEntityCompareDist(x, y, p.Info));
            }
            else
            {
                GetEntityCompareDist(p.Info.HitList[0], null, 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.EwarAreaPulse  = true;
                p.DistanceToTravelSqr = p.Info.DistanceTraveled * p.Info.DistanceTraveled;
                p.Velocity            = Vector3D.Zero;
                p.Info.Hit.SurfaceHit = p.Position + p.Info.Direction * p.Info.ConsumableDef.Const.EwarTriggerRange;
                p.Info.Hit.LastHit    = p.Info.Hit.SurfaceHit;
                p.Info.HitList.Clear();
                return(false);
            }

            var finalCount = p.Info.HitList.Count;

            if (finalCount > 0)
            {
                var hitEntity = p.Info.HitList[0];

                if (hitEntity.EventType == Shield)
                {
                    var cube = hitEntity.Entity as MyCubeBlock;
                    if (cube?.CubeGrid?.Physics != null)
                    {
                        p.LastHitEntVel = cube.CubeGrid.Physics.LinearVelocity;
                    }
                }
                else if (hitEntity.Projectile != null)
                {
                    p.LastHitEntVel = hitEntity.Projectile?.Velocity;
                }
                else if (hitEntity.Entity?.Physics != null)
                {
                    p.LastHitEntVel = hitEntity.Entity?.Physics.LinearVelocity;
                }
                else
                {
                    p.LastHitEntVel = Vector3.Zero;
                }

                var grid = hitEntity.Entity as MyCubeGrid;

                IMySlimBlock hitBlock = null;
                Vector3D?    visualHitPos;
                if (grid != null)
                {
                    if (p.Info.ConsumableDef.Const.VirtualBeams)
                    {
                        hitBlock = hitEntity.Blocks[0];
                    }

                    IHitInfo hitInfo = null;
                    if (p.Info.System.Session.HandlesInput && hitEntity.HitPos.HasValue && Vector3D.DistanceSquared(hitEntity.HitPos.Value, p.Info.System.Session.CameraPos) < 22500 && p.Info.System.Session.CameraFrustrum.Contains(hitEntity.HitPos.Value) != ContainmentType.Disjoint)
                    {
                        var entSphere = hitEntity.Entity.PositionComp.WorldVolume;
                        var from      = hitEntity.Intersection.From + (hitEntity.Intersection.Direction * MyUtils.GetSmallestDistanceToSphereAlwaysPositive(ref hitEntity.Intersection.From, ref entSphere));
                        var to        = hitEntity.HitPos.Value + (hitEntity.Intersection.Direction * 3f);
                        p.Info.System.Session.Physics.CastRay(from, to, out hitInfo, 15);
                    }
                    visualHitPos = hitInfo?.HitEntity != null ? hitInfo.Position : hitEntity.HitPos;
                }
                else
                {
                    visualHitPos = hitEntity.HitPos;
                }

                p.Info.Hit = new Hit {
                    Block = hitBlock, Entity = hitEntity.Entity, LastHit = visualHitPos ?? Vector3D.Zero, SurfaceHit = visualHitPos ?? Vector3D.Zero, HitVelocity = p.LastHitEntVel ?? Vector3D.Zero, HitTick = p.Info.System.Session.Tick
                };
                if (p.EnableAv)
                {
                    p.Info.AvShot.LastHitShield = hitEntity.EventType == Shield;
                    p.Info.AvShot.Hit           = p.Info.Hit;
                }

                return(true);
            }
            return(false);
        }
Ejemplo n.º 3
0
        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);
        }