using System; using System.Collections.Generic; using System.Numerics; using System.Runtime.InteropServices; using Dalamud.Game.ClientState.Conditions; using Dalamud.Plugin.Services; using FFXIVClientStructs.FFXIV.Client.Game; using Microsoft.Extensions.Logging; using Questionable.Model; using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Interactions; internal static class Jump { internal sealed class Factory : SimpleTaskFactory { public override ITask? CreateTask(Quest quest, QuestSequence sequence, QuestStep step) { if (step.InteractionType != EInteractionType.Jump) { return null; } ArgumentNullException.ThrowIfNull(step.JumpDestination, "step.JumpDestination"); if (step.JumpDestination.Type == EJumpType.SingleJump) { return new SingleJumpTask(step.DataId, step.JumpDestination, step.Comment); } return new RepeatedJumpTask(step.DataId, step.JumpDestination, step.Comment); } } internal interface IJumpTask : ITask { uint? DataId { get; } JumpDestination JumpDestination { get; } string? Comment { get; } } internal sealed record SingleJumpTask(uint? DataId, JumpDestination JumpDestination, string? Comment) : IJumpTask, ITask { public override string ToString() { return "Jump(" + Comment + ")"; } } internal abstract class JumpBase(MovementController movementController, IClientState clientState, IFramework framework) : TaskExecutor() where T : class, IJumpTask { protected unsafe override bool Start() { float num = base.Task.JumpDestination.CalculateStopDistance(); if ((_003CclientState_003EP.LocalPlayer.Position - base.Task.JumpDestination.Position).Length() <= num) { return false; } MovementController movementController = _003CmovementController_003EP; uint? dataId = base.Task.DataId; int num2 = 1; List list = new List(num2); CollectionsMarshal.SetCount(list, num2); Span span = CollectionsMarshal.AsSpan(list); int index = 0; span[index] = base.Task.JumpDestination.Position; movementController.NavigateTo(EMovementType.Quest, dataId, list, fly: false, sprint: false, base.Task.JumpDestination.StopDistance ?? num); _003Cframework_003EP.RunOnTick(delegate { ActionManager.Instance()->UseAction(ActionType.GeneralAction, 2u, 3758096384uL, 0u, ActionManager.UseActionMode.None, 0u, null); }, TimeSpan.FromSeconds(base.Task.JumpDestination.DelaySeconds ?? 0.5f)); return true; } public override ETaskResult Update() { if (_003CmovementController_003EP.IsPathfinding || _003CmovementController_003EP.IsPathRunning) { return ETaskResult.StillRunning; } DateTime movementStartedAt = _003CmovementController_003EP.MovementStartedAt; if (movementStartedAt == DateTime.MaxValue || movementStartedAt.AddSeconds(1.0) >= DateTime.Now) { return ETaskResult.StillRunning; } return ETaskResult.TaskComplete; } public override bool ShouldInterruptOnDamage() { return true; } } internal sealed class DoSingleJump : JumpBase { public DoSingleJump(MovementController movementController, IClientState clientState, IFramework framework) : base(movementController, clientState, framework) { } } internal sealed record RepeatedJumpTask(uint? DataId, JumpDestination JumpDestination, string? Comment) : IJumpTask, ITask { public override string ToString() { return "RepeatedJump(" + Comment + ")"; } } internal sealed class DoRepeatedJumps : JumpBase { private readonly IClientState _clientState; private DateTime _continueAt; private int _attempts; public DoRepeatedJumps(MovementController movementController, IClientState clientState, IFramework framework, ICondition condition, ILogger logger) { _003Ccondition_003EP = condition; _003Clogger_003EP = logger; _clientState = clientState; _continueAt = DateTime.MinValue; base._002Ector(movementController, clientState, framework); } protected override bool Start() { _continueAt = DateTime.Now + TimeSpan.FromSeconds(2f * (base.Task.JumpDestination.DelaySeconds ?? 0.5f)); return base.Start(); } public unsafe override ETaskResult Update() { if (DateTime.Now < _continueAt || _003Ccondition_003EP[ConditionFlag.Jumping]) { return ETaskResult.StillRunning; } float num = base.Task.JumpDestination.CalculateStopDistance(); if ((_clientState.LocalPlayer.Position - base.Task.JumpDestination.Position).Length() <= num || _clientState.LocalPlayer.Position.Y >= base.Task.JumpDestination.Position.Y - 0.5f) { return ETaskResult.TaskComplete; } _003Clogger_003EP.LogTrace("Y-Heights for jumps: player={A}, target={B}", _clientState.LocalPlayer.Position.Y, base.Task.JumpDestination.Position.Y - 0.5f); if (ActionManager.Instance()->UseAction(ActionType.GeneralAction, 2u, 3758096384uL, 0u, ActionManager.UseActionMode.None, 0u, null)) { _attempts++; } if (_attempts >= 50) { throw new TaskException("Tried to jump too many times, didn't reach the target"); } _continueAt = DateTime.Now + TimeSpan.FromSeconds(base.Task.JumpDestination.DelaySeconds ?? 0.5f); return ETaskResult.StillRunning; } } }