Пример #1
0
        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));
        }