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);
        }
        private static async Task ClearExpiredFate()
        {
            OracleFateManager.DoNotWaitBeforeMovingFlag = true;
            await OracleFateManager.ClearCurrentFate("FATE ended before we got there.", false);

            Navigator.Stop();
        }
Example #3
0
        internal static uint GetTrueLevel()
        {
            var baseClass = OracleFateManager.GetBaseClass(Core.Player.CurrentJob);
            var trueLevel = Core.Player.Levels.FirstOrDefault(kvp => kvp.Key == baseClass).Value;

            return(trueLevel != 0 ? trueLevel : Core.Player.ClassLevel);
        }
Example #4
0
        private static async Task <Aetheryte[]> GetNavigableAetherytes(FateData fate)
        {
            Aetheryte[] viableAetherytes;

            var allAetherytes       = AllTuplesToAetherytes(OracleFateManager.GetAetheryteIdsForZone(WorldManager.ZoneId), fate.Location);
            var viableAetheryteList = new List <Aetheryte>();

            if (!WorldManager.CanFly)
            {
                var navRequest = allAetherytes.Select(target => new CanFullyNavigateTarget
                {
                    Id       = target.Id,
                    Position = target.Location
                }).ToList();
                var navTask    = Navigator.NavigationProvider.CanFullyNavigateTo(navRequest, fate.Location, WorldManager.ZoneId);
                var navResults = await Coroutine.ExternalTask(navTask);

                foreach (var navResult in navResults.Where(result => result.CanNavigate != 0))
                {
                    var aetheryte = allAetherytes.FirstOrDefault(result => result.Id == navResult.Id);
                    aetheryte.Distance = navResult.PathLength;
                    viableAetheryteList.Add(aetheryte);
                    await Coroutine.Yield();
                }

                viableAetherytes = viableAetheryteList.ToArray();
            }
            else
            {
                viableAetherytes = allAetherytes;
            }

            return(viableAetherytes);
        }
        private static async Task <IEnumerable <Vector3> > GenerateFlightPathToFate(FateData currentFate)
        {
            Logger.SendLog("Generating new flight path to FATE.");
            var flightPathTimer = Stopwatch.StartNew();

            var aStar        = new AStarNavigator(ZoneFlightMesh.Graph);
            var startingNode = GetClosestNodeToLocation(Core.Player.Location);
            var endingNode   = GetClosestNodeToFate(currentFate);

            if (startingNode == null || endingNode == null)
            {
                Logger.SendErrorLog("Couldn't generate a flight path to the FATE, blacklisting it and selecting another.");
                Blacklist.Add(currentFate.Id, BlacklistFlags.Node, currentFate.TimeLeft, "Could not generate flight path.");
                await OracleFateManager.ClearCurrentFate("Couldn't generate a flight path to the FATE", false);

                return(null);
            }

            var path = aStar.GeneratePath(startingNode.Position, endingNode.Position).ToList();

            if (!path.Any())
            {
                Logger.SendErrorLog("Couldn't generate a flight path to the FATE, blacklisting it and selecting another.");
                Blacklist.Add(currentFate.Id, BlacklistFlags.Node, currentFate.TimeLeft, "Could not generate flight path.");
                await OracleFateManager.ClearCurrentFate("Couldn't generate a flight path to the FATE", false);

                return(null);
            }

            // Skip first node if we can to prevent bot-like mid-air direction change.
            if (path.Count > 1)
            {
                Vector3 collision;
                if (!WorldManager.Raycast(Core.Player.Location, path[1], out collision))
                {
                    Logger.SendDebugLog("Skipping first node, no collision detected.");
                    path.Remove(path.First());
                }
                else
                {
                    Logger.SendDebugLog("Not skipping first node, collision detected at: " + collision);
                }
            }

            flightPathTimer.Stop();
            Logger.SendDebugLog("Flight path generated in " + flightPathTimer.ElapsedMilliseconds + " ms.");

            return(path);
        }
        internal static async Task <bool> NavigateToLocation(Vector3 location, float precision, bool stopOnFateSpawn)
        {
            var movementParams = new MoveToParameters
            {
                Location          = location,
                DistanceTolerance = precision
            };

            while (Core.Player.Location.Distance(location) > precision)
            {
                if (ActionManager.CanMount == 0 && !Core.Player.IsMounted && IsMountNeeded(Core.Player.Location.Distance(location)) &&
                    ActionManager.AvailableMounts.Any())
                {
                    Navigator.Stop();
                    if (Core.Player.InCombat)
                    {
                        return(true);
                    }

                    await MountUp();
                }

                if (stopOnFateSpawn && await OracleFateManager.AnyViableFates())
                {
                    Navigator.Stop();
                    OracleFateManager.ClearPoi("FATE found.");
                    return(true);
                }

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

                Navigator.MoveTo(movementParams);
                await Coroutine.Yield();
            }

            Navigator.Clear();
            return(true);
        }
Example #7
0
        internal static async Task <bool> TeleportToClosestAetheryte(FateData fate)
        {
            var aetheryte = await GetClosestAetheryte(fate);

            if (aetheryte.Id == 0)
            {
                Logger.SendDebugLog("No viable aetheryte crystals in this zone.");
                return(false);
            }

            await TeleportToAetheryte(aetheryte.Id);

            if (Core.Player.InCombat)
            {
                OracleFateManager.ClearPoi("We're in combat and need to teleport.");
            }

            return(true);
        }
        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);
        }
        internal static async Task <bool> FlyToLocation(Vector3 location, float precision, bool land, bool stopOnFateSpawn)
        {
            if (!IsFlightMeshLoaded())
            {
                await NavigateToLocation(location, precision, stopOnFateSpawn);

                return(true);
            }

            if (ActionManager.CanMount != 0 && !Core.Player.IsMounted)
            {
                return(false);
            }

            if (!Core.Player.IsMounted)
            {
                if (Core.Player.InCombat)
                {
                    return(false);
                }

                await MountUp();
            }

            // Ensure precision isn't too strong, else we get flip-flopping.
            if (precision < 2f)
            {
                precision = 2f;
            }

            var path = await GenerateFlightPathToLocation(location);

            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.Distance(location) < Core.Player.Location.Distance(processedStep))
                {
                    Logger.SendDebugLog("Destination is closer than next hop. Ending navigation early.");
                    break;
                }

                while (Core.Player.Location.Distance(processedStep) > 2f)
                {
                    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();
                    }

                    if (stopOnFateSpawn && await OracleFateManager.AnyViableFates())
                    {
                        Navigator.PlayerMover.MoveStop();
                        OracleFateManager.ClearPoi("FATE found.");
                        return(true);
                    }

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

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

            // Move to destination.
            while (Core.Player.Location.Distance(location) > precision)
            {
                Navigator.PlayerMover.MoveTowards(location);
                await Coroutine.Yield();
            }

            Navigator.PlayerMover.MoveStop();

            if (land && MovementManager.IsFlying && await CommonTasks.CanLand(Core.Player.Location) == CanLandResult.Yes)
            {
                await CommonTasks.Land();
            }

            return(true);
        }