forked from liza/Questionable
Attempt to handle Revisit triggering
This commit is contained in:
parent
606b9d52ba
commit
9d8c67155f
@ -16,12 +16,15 @@
|
||||
"Z": 405.1829
|
||||
},
|
||||
"MinimumAngle": 100,
|
||||
"MaximumAngle": 250
|
||||
"MaximumAngle": 250,
|
||||
"MinimumDistance": 1.5,
|
||||
"MaximumDistance": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"DataId": 31345,
|
||||
"Fly": false,
|
||||
"Locations": [
|
||||
{
|
||||
"Position": {
|
||||
@ -29,8 +32,10 @@
|
||||
"Y": 216.5585,
|
||||
"Z": 412.4353
|
||||
},
|
||||
"MinimumAngle": 50,
|
||||
"MaximumAngle": 165
|
||||
"MinimumAngle": 75,
|
||||
"MaximumAngle": 145,
|
||||
"MinimumDistance": 1.5,
|
||||
"MaximumDistance": 3
|
||||
},
|
||||
{
|
||||
"Position": {
|
||||
@ -39,7 +44,9 @@
|
||||
"Z": 421.5481
|
||||
},
|
||||
"MinimumAngle": 0,
|
||||
"MaximumAngle": 145
|
||||
"MaximumAngle": 145,
|
||||
"MinimumDistance": 1.5,
|
||||
"MaximumDistance": 3
|
||||
},
|
||||
{
|
||||
"Position": {
|
||||
@ -48,7 +55,9 @@
|
||||
"Z": 408.2164
|
||||
},
|
||||
"MinimumAngle": 155,
|
||||
"MaximumAngle": 225
|
||||
"MaximumAngle": 225,
|
||||
"MinimumDistance": 1.5,
|
||||
"MaximumDistance": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ namespace Questionable.Model.Gathering;
|
||||
public sealed class GatheringNode
|
||||
{
|
||||
public uint DataId { get; set; }
|
||||
public bool Fly { get; set; }
|
||||
public bool? Fly { get; set; }
|
||||
|
||||
public List<GatheringLocation> Locations { get; set; } = [];
|
||||
}
|
||||
|
@ -16,6 +16,6 @@ public sealed class GatheringRoot
|
||||
public EAetheryteLocation? AetheryteShortcut { get; set; }
|
||||
|
||||
public AethernetShortcut? AethernetShortcut { get; set; }
|
||||
public bool FlyBetweenNodes { get; set; } = true;
|
||||
public bool? FlyBetweenNodes { get; set; }
|
||||
public List<GatheringNodeGroup> Groups { get; set; } = [];
|
||||
}
|
||||
|
@ -1,13 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Text.RegularExpressions;
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Event;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.UI;
|
||||
using LLib;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Questionable.Controller.Steps;
|
||||
@ -32,6 +37,7 @@ internal sealed unsafe class GatheringController : MiniTaskController<GatheringC
|
||||
private readonly IObjectTable _objectTable;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ICondition _condition;
|
||||
private readonly Regex _revisitRegex;
|
||||
|
||||
private CurrentRequest? _currentRequest;
|
||||
|
||||
@ -44,7 +50,9 @@ internal sealed unsafe class GatheringController : MiniTaskController<GatheringC
|
||||
IChatGui chatGui,
|
||||
ILogger<GatheringController> logger,
|
||||
IServiceProvider serviceProvider,
|
||||
ICondition condition)
|
||||
ICondition condition,
|
||||
IDataManager dataManager,
|
||||
IPluginLog pluginLog)
|
||||
: base(chatGui, logger)
|
||||
{
|
||||
_movementController = movementController;
|
||||
@ -54,6 +62,9 @@ internal sealed unsafe class GatheringController : MiniTaskController<GatheringC
|
||||
_objectTable = objectTable;
|
||||
_serviceProvider = serviceProvider;
|
||||
_condition = condition;
|
||||
|
||||
_revisitRegex = dataManager.GetRegex<LogMessage>(5574, x => x.Text, pluginLog)
|
||||
?? throw new InvalidDataException("No regex found for revisit message");
|
||||
}
|
||||
|
||||
public bool Start(GatheringRequest gatheringRequest)
|
||||
@ -88,13 +99,19 @@ internal sealed unsafe class GatheringController : MiniTaskController<GatheringC
|
||||
public EStatus Update()
|
||||
{
|
||||
if (_currentRequest == null)
|
||||
{
|
||||
Stop("No request");
|
||||
return EStatus.Complete;
|
||||
}
|
||||
|
||||
if (_movementController.IsPathfinding || _movementController.IsPathfinding)
|
||||
return EStatus.Moving;
|
||||
|
||||
if (HasRequestedItems() && !_condition[ConditionFlag.Gathering])
|
||||
{
|
||||
Stop("Has all items");
|
||||
return EStatus.Complete;
|
||||
}
|
||||
|
||||
if (_currentTask == null && _taskQueue.Count == 0)
|
||||
GoToNextNode();
|
||||
@ -136,6 +153,9 @@ internal sealed unsafe class GatheringController : MiniTaskController<GatheringC
|
||||
|
||||
_taskQueue.Enqueue(_serviceProvider.GetRequiredService<MountTask>()
|
||||
.With(_currentRequest.Root.TerritoryId, MountTask.EMountIf.Always));
|
||||
|
||||
bool fly = currentNode.Fly.GetValueOrDefault(_currentRequest.Root.FlyBetweenNodes.GetValueOrDefault(true)) &&
|
||||
_gameFunctions.IsFlyingUnlocked(_currentRequest.Root.TerritoryId);
|
||||
if (currentNode.Locations.Count > 1)
|
||||
{
|
||||
Vector3 averagePosition = new Vector3
|
||||
@ -144,8 +164,7 @@ internal sealed unsafe class GatheringController : MiniTaskController<GatheringC
|
||||
Y = currentNode.Locations.Select(x => x.Position.Y).Max() + 5f,
|
||||
Z = currentNode.Locations.Sum(x => x.Position.Z) / currentNode.Locations.Count,
|
||||
};
|
||||
bool fly = (currentNode.Fly || _currentRequest.Root.FlyBetweenNodes)
|
||||
&& _gameFunctions.IsFlyingUnlocked(_currentRequest.Root.TerritoryId);
|
||||
|
||||
Vector3? pointOnFloor = _navmeshIpc.GetPointOnFloor(averagePosition, true);
|
||||
if (pointOnFloor != null)
|
||||
pointOnFloor = pointOnFloor.Value with { Y = pointOnFloor.Value.Y + (fly ? 3f : 0f) };
|
||||
@ -156,17 +175,19 @@ internal sealed unsafe class GatheringController : MiniTaskController<GatheringC
|
||||
}
|
||||
|
||||
_taskQueue.Enqueue(_serviceProvider.GetRequiredService<MoveToLandingLocation>()
|
||||
.With(_currentRequest.Root.TerritoryId,
|
||||
currentNode.Fly || _currentRequest.Root.FlyBetweenNodes,
|
||||
currentNode));
|
||||
.With(_currentRequest.Root.TerritoryId, fly, currentNode));
|
||||
_taskQueue.Enqueue(_serviceProvider.GetRequiredService<Interact.DoInteract>()
|
||||
.With(currentNode.DataId, null, EInteractionType.InternalGather, true));
|
||||
|
||||
foreach (bool revisitRequired in new[] { false, true })
|
||||
{
|
||||
_taskQueue.Enqueue(_serviceProvider.GetRequiredService<DoGather>()
|
||||
.With(_currentRequest.Data, currentNode));
|
||||
.With(_currentRequest.Data, currentNode, revisitRequired));
|
||||
if (_currentRequest.Data.Collectability > 0)
|
||||
{
|
||||
_taskQueue.Enqueue(_serviceProvider.GetRequiredService<DoGatherCollectable>()
|
||||
.With(_currentRequest.Data, currentNode));
|
||||
.With(_currentRequest.Data, currentNode, revisitRequired));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -232,6 +253,21 @@ internal sealed unsafe class GatheringController : MiniTaskController<GatheringC
|
||||
return base.GetRemainingTaskNames();
|
||||
}
|
||||
|
||||
public void OnNormalToast(SeString message)
|
||||
{
|
||||
if (_revisitRegex.IsMatch(message.TextValue))
|
||||
{
|
||||
if (_currentTask is IRevisitAware currentTaskRevisitAware)
|
||||
currentTaskRevisitAware.OnRevisit();
|
||||
|
||||
foreach (ITask task in _taskQueue)
|
||||
{
|
||||
if (task is IRevisitAware taskRevisitAware)
|
||||
taskRevisitAware.OnRevisit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class CurrentRequest
|
||||
{
|
||||
public required GatheringRequest Data { get; init; }
|
||||
|
@ -4,6 +4,7 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Game.ClientState.Keys;
|
||||
using Dalamud.Game.Gui.Toast;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
@ -90,6 +91,7 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
|
||||
_taskFactories = taskFactories.ToList().AsReadOnly();
|
||||
|
||||
_condition.ConditionChange += OnConditionChange;
|
||||
_toastGui.Toast += OnNormalToast;
|
||||
_toastGui.ErrorToast += OnErrorToast;
|
||||
}
|
||||
|
||||
@ -786,6 +788,11 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
|
||||
conditionChangeAware.OnConditionChange(flag, value);
|
||||
}
|
||||
|
||||
private void OnNormalToast(ref SeString message, ref ToastOptions options, ref bool ishandled)
|
||||
{
|
||||
_gatheringController.OnNormalToast(message);
|
||||
}
|
||||
|
||||
private void OnErrorToast(ref SeString message, ref bool ishandled)
|
||||
{
|
||||
if (_currentTask is IToastAware toastAware)
|
||||
@ -795,6 +802,7 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
|
||||
public void Dispose()
|
||||
{
|
||||
_toastGui.ErrorToast -= OnErrorToast;
|
||||
_toastGui.Toast -= OnNormalToast;
|
||||
_condition.ConditionChange -= OnConditionChange;
|
||||
}
|
||||
|
||||
|
@ -22,20 +22,24 @@ internal sealed class DoGather(
|
||||
IGameGui gameGui,
|
||||
IClientState clientState,
|
||||
ICondition condition,
|
||||
ILogger<DoGather> logger) : ITask
|
||||
ILogger<DoGather> logger) : ITask, IRevisitAware
|
||||
{
|
||||
private const uint StatusGatheringRateUp = 218;
|
||||
|
||||
private GatheringController.GatheringRequest _currentRequest = null!;
|
||||
private GatheringNode _currentNode = null!;
|
||||
private bool _revisitRequired;
|
||||
private bool _revisitTriggered;
|
||||
private bool _wasGathering;
|
||||
private SlotInfo? _slotToGather;
|
||||
private Queue<EAction>? _actionQueue;
|
||||
|
||||
public ITask With(GatheringController.GatheringRequest currentRequest, GatheringNode currentNode)
|
||||
public ITask With(GatheringController.GatheringRequest currentRequest, GatheringNode currentNode,
|
||||
bool revisitRequired)
|
||||
{
|
||||
_currentRequest = currentRequest;
|
||||
_currentNode = currentNode;
|
||||
_revisitRequired = revisitRequired;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -43,8 +47,17 @@ internal sealed class DoGather(
|
||||
|
||||
public unsafe ETaskResult Update()
|
||||
{
|
||||
if (gatheringController.HasNodeDisappeared(_currentNode))
|
||||
if (_revisitRequired && !_revisitTriggered)
|
||||
{
|
||||
logger.LogInformation("No revisit");
|
||||
return ETaskResult.TaskComplete;
|
||||
}
|
||||
|
||||
if (gatheringController.HasNodeDisappeared(_currentNode))
|
||||
{
|
||||
logger.LogInformation("Node disappeared");
|
||||
return ETaskResult.TaskComplete;
|
||||
}
|
||||
|
||||
if (gameFunctions.GetFreeInventorySlots() == 0)
|
||||
throw new TaskException("Inventory full");
|
||||
@ -225,7 +238,12 @@ internal sealed class DoGather(
|
||||
return ActionManager.Instance()->GetActionStatus(ActionType.Action, (uint)action) == 0;
|
||||
}
|
||||
|
||||
public override string ToString() => "DoGather";
|
||||
public void OnRevisit()
|
||||
{
|
||||
_revisitTriggered = true;
|
||||
}
|
||||
|
||||
public override string ToString() => $"DoGather{(_revisitRequired ? " if revist" : "")}";
|
||||
|
||||
private sealed record SlotInfo(int Index, uint ItemId, int GatheringChance, int BoonChance, int Quantity);
|
||||
|
||||
|
@ -17,16 +17,19 @@ internal sealed class DoGatherCollectable(
|
||||
GameFunctions gameFunctions,
|
||||
IClientState clientState,
|
||||
IGameGui gameGui,
|
||||
ILogger<DoGatherCollectable> logger) : ITask
|
||||
ILogger<DoGatherCollectable> logger) : ITask, IRevisitAware
|
||||
{
|
||||
private GatheringController.GatheringRequest _currentRequest = null!;
|
||||
private GatheringNode _currentNode = null!;
|
||||
private bool _revisitRequired;
|
||||
private bool _revisitTriggered;
|
||||
private Queue<EAction>? _actionQueue;
|
||||
|
||||
public ITask With(GatheringController.GatheringRequest currentRequest, GatheringNode currentNode)
|
||||
public ITask With(GatheringController.GatheringRequest currentRequest, GatheringNode currentNode, bool revisitRequired)
|
||||
{
|
||||
_currentRequest = currentRequest;
|
||||
_currentNode = currentNode;
|
||||
_revisitRequired = revisitRequired;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -34,8 +37,17 @@ internal sealed class DoGatherCollectable(
|
||||
|
||||
public unsafe ETaskResult Update()
|
||||
{
|
||||
if (gatheringController.HasNodeDisappeared(_currentNode))
|
||||
if (_revisitRequired && !_revisitTriggered)
|
||||
{
|
||||
logger.LogInformation("No revisit");
|
||||
return ETaskResult.TaskComplete;
|
||||
}
|
||||
|
||||
if (gatheringController.HasNodeDisappeared(_currentNode))
|
||||
{
|
||||
logger.LogInformation("Node disappeared");
|
||||
return ETaskResult.TaskComplete;
|
||||
}
|
||||
|
||||
if (gatheringController.HasRequestedItems())
|
||||
{
|
||||
@ -150,8 +162,13 @@ internal sealed class DoGatherCollectable(
|
||||
return botanistAction;
|
||||
}
|
||||
|
||||
public void OnRevisit()
|
||||
{
|
||||
_revisitTriggered = true;
|
||||
}
|
||||
|
||||
public override string ToString() =>
|
||||
$"DoGatherCollectable({SeIconChar.Collectible.ToIconString()} {_currentRequest.Collectability})";
|
||||
$"DoGatherCollectable({SeIconChar.Collectible.ToIconString()} {_currentRequest.Collectability}){(_revisitRequired ? " if revist" : "")}";
|
||||
|
||||
[SuppressMessage("ReSharper", "NotAccessedPositionalProperty.Local")]
|
||||
private sealed record NodeCondition(
|
||||
|
6
Questionable/Controller/Steps/IRevisitAware.cs
Normal file
6
Questionable/Controller/Steps/IRevisitAware.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace Questionable.Controller.Steps;
|
||||
|
||||
public interface IRevisitAware
|
||||
{
|
||||
void OnRevisit();
|
||||
}
|
Loading…
Reference in New Issue
Block a user