static IEnumerable <ProximityAlert> GetProximityAlerts(OffenderProximityInfo proximity)
        {
            var(defender, offender, distance) = proximity;

            // skip friendly ships
            if (defender.FactionId is long defenderFactionId &&
                offender.FactionId is long offenderFactionId)
            {
                if (defenderFactionId == offenderFactionId)
                {
                    yield break;
                }

                var(relation, _) = MySession.Static.Factions.GetRelationBetweenFactions(defenderFactionId, offenderFactionId);
                if (relation != MyRelationsBetweenFactions.Enemies)
                {
                    yield break;
                }
            }

            foreach (var steamId in defender.SteamIds)
            {
                yield return(new ProximityAlert(steamId, defender.GridId, defender.GridName, offender, distance));
            }
        }
        bool TryGetOffender(IMyEntity entity, DefenderGridInfo defender, out OffenderProximityInfo proximity)
        {
            proximity = default;

            if (!(entity is MyCubeGrid offenderGrid))
            {
                return(false);
            }
            if (offenderGrid.EntityId == defender.GridId)
            {
                return(false);
            }
            if (!offenderGrid.IsTopMostParent())
            {
                return(false);
            }
            if (!IsEnemyGrid(offenderGrid, defender))
            {
                return(false);
            }

            var position = offenderGrid.PositionComp.GetPosition();
            var distance = Vector3D.Distance(defender.Position, position);

            if (distance > _config.MaxProximity)
            {
                return(false);
            }

            var offenderInfo = MakeOffenderGridInfo(offenderGrid);

            proximity = new OffenderProximityInfo(defender, offenderInfo, distance);
            Log.Trace($"offender: {proximity}");

            return(true);
        }