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(); }
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); }
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); }
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); }