diff --git a/CHANGELOG.md b/CHANGELOG.md index 858e1d5..448335f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ I try to keep this changelog up to date with the latest changes in the project. +## [1.5.0.0] +- safety and magicite usage if no concealment is available +- fixed some bugs with the new retainers +- improved search logic +- timeout leave + ## [1.4.0.0] - run retainers between runs - speed up some things to save 1-2 seconds per run diff --git a/HoardFarm/HoardFarm.csproj b/HoardFarm/HoardFarm.csproj index 6afbd9f..e671e8c 100644 --- a/HoardFarm/HoardFarm.csproj +++ b/HoardFarm/HoardFarm.csproj @@ -2,7 +2,7 @@ Jukkales - 1.4.0.0 + 1.5.0.0 HoardFarm Dalamud Plugin https://github.com/Jukkales/HoardFarm diff --git a/HoardFarm/Service/HoardFarmService.cs b/HoardFarm/Service/HoardFarmService.cs index dd34602..66d2dce 100644 --- a/HoardFarm/Service/HoardFarmService.cs +++ b/HoardFarm/Service/HoardFarmService.cs @@ -3,10 +3,13 @@ using System.Linq; using System.Numerics; using System.Timers; +using Dalamud.Game.ClientState.Conditions; using Dalamud.Game.Text; using Dalamud.Game.Text.SeStringHandling; using Dalamud.Utility; +using ECommons.DalamudServices; using ECommons.GameHelpers; +using ECommons.Throttlers; using HoardFarm.IPC; using HoardFarm.Model; using HoardFarm.Tasks; @@ -17,6 +20,8 @@ namespace HoardFarm.Service; public class HoardFarmService : IDisposable { + private record MapObject(uint ObjectId, uint DataId, Vector3 Position); + public string HoardModeStatus = ""; public string HoardModeError = ""; private bool hoardModeActive; @@ -31,12 +36,14 @@ public class HoardFarmService : IDisposable private bool intuitionUsed; private bool movingToHoard; private bool searchMode; + private bool safetyUsed; private Vector3 hoardPosition = Vector3.Zero; - private readonly List chestIds = []; - private readonly List visitedChestIds = []; + private readonly List visitedObjectIds = []; private readonly string hoardFoundMessage; private readonly string senseHoardMessage; private readonly string noHoardMessage; + private readonly Dictionary objectPositions = new(); + private DateTime runStarted; public HoardFarmService() { @@ -100,34 +107,37 @@ private void Reset() hoardAvailable = false; searchMode = false; FinishRun = false; + safetyUsed = false; + objectPositions.Clear(); + runStarted = DateTime.Now; } private unsafe bool SearchLogic() { HoardModeStatus = "Searching"; - chestIds.Clear(); - var chests = ObjectTable.Where(e => ChestIDs.Contains(e.DataId)).Select(e => e.ObjectId).Distinct().ToList(); - chests.ForEach(e => - { - if (!visitedChestIds.Contains(e)) - { - chestIds.Add(e); - } - }); - if (!TaskManager.IsBusy) - { - var nextChest = chestIds.MaxBy(id => ObjectTable.First(e => e.ObjectId == id).Position.Distance(Player.GameObject->Position)); - visitedChestIds.Add(nextChest); - - if (!Concealment) + if (!TaskManager.IsBusy) { + if (!objectPositions.Where(e => !visitedObjectIds.Contains(e.Value.ObjectId)) + .Where(e => ChestIDs.Contains(e.Value.DataId)) + .OrderBy(e => e.Value.Position.Distance(Player.GameObject->Position)) + .Select(e => e.Value) + .TryGetFirst(out var next)) { - Enqueue(new UsePomanderTask(Pomander.Concealment), "Use Concealment"); + if (!objectPositions.Where(e => !visitedObjectIds.Contains(e.Value.ObjectId)) + .OrderBy(e => e.Value.Position.Distance(Player.GameObject->Position)) + .Select(e => e.Value) + .TryGetFirst(out next)) + { + // We should never reach here normally .. but "never" is still a chance > 0% ;) + LeaveDuty("Unreachable"); + return true; + } } - Enqueue(new PathfindTask(ObjectTable.First(e => e.ObjectId == nextChest).Position, true), 60 * 1000, "Searching " + nextChest); + visitedObjectIds.Add(next!.ObjectId); + Enqueue(new PathfindTask(next.Position, true), 60 * 1000, "Searching " + next.ObjectId); } - + FindHoardPosition(); if (hoardPosition != Vector3.Zero) { @@ -148,22 +158,21 @@ private void OnTimerUpdate(object? sender, ElapsedEventArgs e) return; } - SessionTime++; - Config.OverallTime++; - if (!NavmeshIPC.NavIsReady()) { HoardModeStatus = "Waiting Navmesh"; return; } + SessionTime++; + Config.OverallTime++; + + UpdateObjectPositions(); + SafetyChecks(); + if (searchMode && hoardPosition == Vector3.Zero) - { if (!SearchLogic()) - { return; - } - } if (!TaskManager.IsBusy && hoardModeActive) { @@ -190,7 +199,7 @@ private void OnTimerUpdate(object? sender, ElapsedEventArgs e) { HoardModeStatus = "Finished"; HoardMode = false; - return; + return; } if (CheckRetainer()) @@ -234,10 +243,10 @@ private void OnTimerUpdate(object? sender, ElapsedEventArgs e) { if (!movingToHoard) { - if (!Concealment) - { - Enqueue(new UsePomanderTask(Pomander.Concealment, false), "Use Concealment"); - } + // if (!Concealment) + // { + // Enqueue(new UsePomanderTask(Pomander.Concealment, false), "Use Concealment"); + // } Enqueue(new PathfindTask(hoardPosition, true, 1.5f), 60 * 1000, "Move to Hoard"); movingToHoard = true; HoardModeStatus = "Move to Hoard"; @@ -272,6 +281,65 @@ private void OnTimerUpdate(object? sender, ElapsedEventArgs e) } } + private void SafetyChecks() + { + if (InHoH && intuitionUsed) + { + if (DateTime.Now.Subtract(runStarted).TotalSeconds > 130 && !Svc.Condition[ConditionFlag.InCombat]) + { + TaskManager.Abort(); + NavmeshIPC.PathStop(); + LeaveDuty("Timeout"); + return; + } + + if (IsMoving()) + { + if (!Concealment) + { + if (CanUsePomander(Pomander.Concealment)) + { + if (EzThrottler.Check("Concealment")) + { + EzThrottler.Throttle("Concealment", 2000); + new UsePomanderTask(Pomander.Concealment, false).Run(); + return; // start next iteration + } + } else if (CanUsePomander(Pomander.Safety) && !safetyUsed && EzThrottler.Check("Concealment")) + { + if (EzThrottler.Check("Safety")) + { + EzThrottler.Throttle("Safety", 2000); + new UsePomanderTask(Pomander.Safety, false).Run(); + safetyUsed = true; + return; // start next iteration + } + } + } + } + + if (Svc.Condition[ConditionFlag.InCombat]) + { + if (CanUseMagicite() && EzThrottler.Check("Magicite")) + { + EzThrottler.Throttle("Magicite", 6000); + new UseMagiciteTask().Run(); + } + } + + if (Svc.Condition[ConditionFlag.Unconscious]) + { + LeaveDuty("Player died"); + } + } + } + + private void UpdateObjectPositions() + { + foreach (var gameObject in ObjectTable) + objectPositions.TryAdd(gameObject.ObjectId, new MapObject(gameObject.ObjectId, gameObject.DataId, gameObject.Position)); + } + private bool CheckRetainer() { if (Config.DoRetainers && RetainerService.CheckRetainersDone(Config.RetainerMode == 1)) diff --git a/HoardFarm/Service/RetainerService.cs b/HoardFarm/Service/RetainerService.cs index 1c7534c..a2fe4fc 100644 --- a/HoardFarm/Service/RetainerService.cs +++ b/HoardFarm/Service/RetainerService.cs @@ -32,6 +32,7 @@ public RetainerService() public void Dispose() { RetainerApi.OnRetainerPostprocessStep -= CheckRetainerPostProcess; + updateTimer.Dispose(); } public void StartProcess() diff --git a/HoardFarm/Utils/TaskManagerUtil.cs b/HoardFarm/Utils/TaskManagerUtil.cs index 5a3166b..0593fa9 100644 --- a/HoardFarm/Utils/TaskManagerUtil.cs +++ b/HoardFarm/Utils/TaskManagerUtil.cs @@ -53,16 +53,16 @@ public static void EnqueueImmediate(BaseTask task, int timeLimitMs = 10000, stri TaskManager.EnqueueImmediate(task.Run, timeLimitMs, name); } - public static void EnqueueImmediate(BaseTask task, string? name = null) => Enqueue(task, 10000, name); - public static void EnqueueImmediate(BaseTask task) => Enqueue(task, 10000); + public static void EnqueueImmediate(BaseTask task, string? name = null) => EnqueueImmediate(task, 10000, name); + public static void EnqueueImmediate(BaseTask task) => EnqueueImmediate(task, 10000); public static void EnqueueImmediate(Func task, int timeLimitMs = 10000, string? name = null) { TaskManager.EnqueueImmediate(task, timeLimitMs, name); } - public static void EnqueueImmediate(Func task, string? name = null) => Enqueue(task, 10000, name); - public static void EnqueueImmediate(Func task) => Enqueue(task, 10000); + public static void EnqueueImmediate(Func task, string? name = null) => EnqueueImmediate(task, 10000, name); + public static void EnqueueImmediate(Func task) => EnqueueImmediate(task, 10000); public static void EnqueueWaitImmediate(int delayMS) {