private static async Task <Vector3> GetFateLandingLocation()
        {
            var oracleFate  = OracleFateManager.GetCurrentOracleFate();
            var currentFate = OracleFateManager.GetCurrentFateData();

            Logger.SendDebugLog("Generating a landing spot.");

            var landingLocation = await GenerateRandomSpot(currentFate.Location, currentFate.Radius *oracleFate.LandingRadius);

            if (await CommonTasks.CanLand(landingLocation) == CanLandResult.No)
            {
                Logger.SendDebugLog("Landing spot generation failed: we can't land at " + landingLocation + ".");
                return(Core.Player.Location);
            }

            // Add a random height to the landing location so we fly above it, then land using the landing task.
            landingLocation.Y = landingLocation.Y + Convert.ToSingle(MathEx.Random(7, 13));

            // Raycast to generated location from current location to check we can move there.
            Vector3 collision;

            if (WorldManager.Raycast(Core.Player.Location, landingLocation, out collision) &&
                WorldManager.Raycast(landingLocation, Core.Player.Location, out collision))
            {
                Logger.SendDebugLog("Landing spot generation failed: there's a collision at " + collision + ".");
                return(Core.Player.Location);
            }

            Logger.SendDebugLog("Landing spot generation succeeded.");
            return(landingLocation);
        }
        internal static async Task <bool> NavigateToCurrentFate(bool ignoreCombat)
        {
            OracleFateManager.ReachedCurrentFate = false;
            var currentFate = OracleFateManager.GetCurrentFateData();

            if (currentFate == null || !currentFate.IsValid || currentFate.Status == FateStatus.COMPLETE || currentFate.Status == FateStatus.NOTACTIVE)
            {
                await ClearExpiredFate();

                return(true);
            }

            if (!currentFate.IsValid || currentFate.Status == FateStatus.COMPLETE || currentFate.Status == FateStatus.NOTACTIVE)
            {
                await ClearExpiredFate();

                return(true);
            }

            var cachedFateLocation = currentFate.Location;
            var currentFateRadius  = currentFate.Radius;

            while (Core.Player.Distance(cachedFateLocation) > currentFateRadius * 0.65f || !currentFate.Within2D(Core.Player.Location))
            {
                if (!currentFate.IsValid || currentFate.Status == FateStatus.COMPLETE || currentFate.Status == FateStatus.NOTACTIVE)
                {
                    await ClearExpiredFate();

                    Navigator.Stop();
                    return(true);
                }

                var distanceToFateBoundary = Core.Player.Location.Distance2D(cachedFateLocation) - currentFateRadius;
                if (ActionManager.CanMount == 0 && !Core.Player.IsMounted && IsMountNeeded(distanceToFateBoundary) && ActionManager.AvailableMounts.Any())
                {
                    Navigator.Stop();
                    if (!ignoreCombat && Core.Player.InCombat)
                    {
                        return(true);
                    }

                    await MountUp();
                }

                if (Core.Player.IsDead)
                {
                    OracleFateManager.ClearPoi("Died while moving.");
                    Navigator.Stop();
                    return(true);
                }

                // Throttle navigator path generation requests.
                if (cachedFateLocation.Distance2D(currentFate.Location) > 15f)
                {
                    cachedFateLocation = currentFate.Location;
                }

                Navigator.MoveToPointWithin(cachedFateLocation, currentFateRadius * 0.3f, currentFate.Name);
                await Coroutine.Yield();
            }

            Navigator.Stop();
            OracleFateManager.ReachedCurrentFate = true;
            return(true);
        }
        internal static async Task <bool> MoveToCurrentFate(bool ignoreCombat)
        {
            var currentFate = OracleFateManager.GetCurrentFateData();

            if (!ignoreCombat && GameObjectManager.Attackers.Any(attacker => attacker.IsValid) && !Core.Player.IsMounted)
            {
                return(false);
            }

            await LoadFlightMeshIfAvailable();

            if (!ignoreCombat && MovementSettings.Instance.TeleportIfQuicker && currentFate.IsValid)
            {
                if (await OracleTeleportManager.FasterToTeleport(currentFate))
                {
                    if (GameObjectManager.Attackers.Any(attacker => attacker.IsValid))
                    {
                        OracleFateManager.ClearPoi("We're under attack and can't teleport.");
                        return(false);
                    }

                    await Coroutine.Wait(TimeSpan.FromSeconds(10), WorldManager.CanTeleport);

                    if (WorldManager.CanTeleport())
                    {
                        Logger.SendLog("Teleporting to the closest aetheryte crystal to the FATE.");
                        await OracleTeleportManager.TeleportToClosestAetheryte(currentFate);

                        if (GameObjectManager.Attackers.Any(attacker => attacker.IsValid))
                        {
                            OracleFateManager.ClearPoi("We're under attack and can't teleport.");
                            return(false);
                        }
                    }
                    else
                    {
                        Logger.SendErrorLog("Timed out trying to teleport, running to FATE instead.");
                    }
                }
            }

            // Refresh current fate data.
            currentFate = OracleFateManager.GetCurrentFateData();

            var distanceToFateBoundary = Core.Player.Location.Distance2D(currentFate.Location) - currentFate.Radius;

            if (ActionManager.CanMount == 0 && !ignoreCombat && IsMountNeeded(distanceToFateBoundary) && !Core.Player.IsMounted && currentFate.IsValid)
            {
                await MountUp();
            }

            if (!ignoreCombat && WorldManager.CanFly && ZoneFlightMesh != null)
            {
                await FlyToCurrentFate();
            }
            else
            {
                await NavigateToCurrentFate(ignoreCombat);
            }

            return(true);
        }
        internal static async Task <bool> FlyToCurrentFate()
        {
            if (ActionManager.CanMount != 0 && !Core.Player.IsMounted)
            {
                return(false);
            }

            OracleFateManager.ReachedCurrentFate = false;
            var currentFate = OracleFateManager.GetCurrentFateData();

            if (currentFate == null || !currentFate.IsValid || currentFate.Status == FateStatus.COMPLETE || currentFate.Status == FateStatus.NOTACTIVE)
            {
                await ClearExpiredFate();

                return(true);
            }

            var originalFateLocation = currentFate.Location;
            var path = await GenerateFlightPathToFate(currentFate);

            if (path == null)
            {
                return(false);
            }

            if (!MovementManager.IsFlying)
            {
                await CommonTasks.TakeOff();
            }

            var enumerablePath = path as IList <Vector3> ?? path.ToList();

            foreach (var step in enumerablePath)
            {
                var processedStep = !enumerablePath.Last().Equals(step) ? ProcessFlightStep(step) : step;
                if (Core.Player.Location.Distance2D(currentFate.Location) < Core.Player.Location.Distance2D(processedStep))
                {
                    Logger.SendDebugLog("FATE centre is closer than next hop. Ending navigation early.");
                    break;
                }

                while (Core.Player.Distance(processedStep) > 2f)
                {
                    if (!currentFate.IsValid || currentFate.Status == FateStatus.COMPLETE || currentFate.Status == FateStatus.NOTACTIVE)
                    {
                        await ClearExpiredFate();

                        Navigator.PlayerMover.MoveStop();
                        return(true);
                    }

                    if (!Core.Player.IsMounted && ActionManager.AvailableMounts.Any())
                    {
                        Navigator.PlayerMover.MoveStop();
                        if (Core.Player.InCombat)
                        {
                            return(true);
                        }

                        await MountUp();
                    }

                    if (!MovementManager.IsFlying)
                    {
                        Navigator.PlayerMover.MoveStop();
                        await CommonTasks.TakeOff();
                    }

                    // Did FATE move?
                    if (currentFate.Location.Distance(originalFateLocation) > 50f)
                    {
                        Logger.SendDebugLog("FATE has moved significantly, recalculating flight path.");
                        await FlyToCurrentFate();

                        return(true);
                    }

                    Logger.SendLog("Flying to hop: " + processedStep);
                    Navigator.PlayerMover.MoveTowards(processedStep);
                    await Coroutine.Yield();
                }
            }

            await LandInFateArea();

            OracleFateManager.ReachedCurrentFate = true;
            return(true);
        }