Пример #1
0
    /// <summary>
    /// Tries to arrive nearby without overlapping with other grids.
    /// </summary>
    public bool TryFTLProximity(ShuttleComponent component, EntityUid targetUid, TransformComponent?xform = null, TransformComponent?targetXform = null)
    {
        if (!Resolve(targetUid, ref targetXform) || targetXform.MapUid == null || !Resolve(component.Owner, ref xform))
        {
            return(false);
        }

        var  xformQuery  = GetEntityQuery <TransformComponent>();
        var  shuttleAABB = Comp <IMapGridComponent>(component.Owner).Grid.LocalAABB;
        Box2?aabb        = null;

        // Spawn nearby.
        // We essentially expand the Box2 of the target area until nothing else is added then we know it's valid.
        // Can't just get an AABB of every grid as we may spawn very far away.
        var targetAABB = _transform.GetWorldMatrix(targetXform, xformQuery)
                         .TransformBox(Comp <IMapGridComponent>(targetUid).Grid.LocalAABB).Enlarged(shuttleAABB.Size.Length);

        var nearbyGrids = new HashSet <EntityUid>(1)
        {
            targetUid
        };
        var iteration = 0;
        var lastCount = 1;
        var mapId     = targetXform.MapID;

        while (iteration < 3)
        {
            foreach (var grid in _mapManager.FindGridsIntersecting(mapId, targetAABB))
            {
                if (!nearbyGrids.Add(grid.GridEntityId))
                {
                    continue;
                }

                targetAABB = targetAABB.Union(_transform.GetWorldMatrix(grid.GridEntityId, xformQuery)
                                              .TransformBox(Comp <IMapGridComponent>(grid.GridEntityId).Grid.LocalAABB));
            }

            // Can do proximity
            if (nearbyGrids.Count == lastCount)
            {
                break;
            }

            targetAABB = targetAABB.Enlarged(shuttleAABB.Size.Length / 2f);
            iteration++;
            lastCount = nearbyGrids.Count;

            // Mishap moment, dense asteroid field or whatever
            if (iteration != 3)
            {
                continue;
            }

            foreach (var grid in _mapManager.GetAllGrids())
            {
                // Don't add anymore as it is irrelevant, but that doesn't mean we need to re-do existing work.
                if (nearbyGrids.Contains(grid.GridEntityId))
                {
                    continue;
                }

                targetAABB = targetAABB.Union(_transform.GetWorldMatrix(grid.GridEntityId, xformQuery)
                                              .TransformBox(Comp <IMapGridComponent>(grid.GridEntityId).Grid.LocalAABB));
            }

            break;
        }

        var minRadius = (MathF.Max(targetAABB.Width, targetAABB.Height) + MathF.Max(shuttleAABB.Width, shuttleAABB.Height)) / 2f;
        var spawnPos  = targetAABB.Center + _random.NextVector2(minRadius, minRadius + 64f);

        if (TryComp <PhysicsComponent>(component.Owner, out var shuttleBody))
        {
            shuttleBody.LinearVelocity  = Vector2.Zero;
            shuttleBody.AngularVelocity = 0f;
        }

        xform.Coordinates   = new EntityCoordinates(targetXform.MapUid.Value, spawnPos);
        xform.WorldRotation = _random.NextAngle();
        return(true);
    }