1
0
Fork 0
forked from aly/qstbak
qstbak/Questionable/Questionable.Controller.Steps.Interactions/Jump.cs
2026-08-17 20:29:32 +10:00

165 lines
5.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Numerics;
using System.Runtime.InteropServices;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.ClientState.Objects.SubKinds;
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<T>(MovementController movementController, IObjectTable objectTable, IFramework framework) : TaskExecutor<T>() where T : class, IJumpTask
{
protected unsafe override bool Start()
{
IPlayerCharacter localPlayer = _003CobjectTable_003EP.LocalPlayer;
if (localPlayer == null)
{
return false;
}
float num = base.Task.JumpDestination.CalculateStopDistance();
if ((localPlayer.Position - base.Task.JumpDestination.Position).Length() <= num)
{
return false;
}
MovementController movementController = _003CmovementController_003EP;
uint? dataId = base.Task.DataId;
int num2 = 1;
List<Vector3> list = new List<Vector3>(num2);
CollectionsMarshal.SetCount(list, num2);
CollectionsMarshal.AsSpan(list)[0] = 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;
}
if (!_003CmovementController_003EP.HasBeenMovingForAtLeast(1000))
{
return ETaskResult.StillRunning;
}
return ETaskResult.TaskComplete;
}
public override bool ShouldInterruptOnDamage()
{
return true;
}
}
internal sealed class DoSingleJump : JumpBase<SingleJumpTask>
{
public DoSingleJump(MovementController movementController, IObjectTable objectTable, IFramework framework)
: base(movementController, objectTable, 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<RepeatedJumpTask>
{
private readonly IObjectTable _objectTable;
private long _continueAt;
private int _attempts;
public DoRepeatedJumps(MovementController movementController, IObjectTable objectTable, IFramework framework, ICondition condition, ILogger<DoRepeatedJumps> logger)
{
_003Ccondition_003EP = condition;
_003Clogger_003EP = logger;
_objectTable = objectTable;
base._002Ector(movementController, objectTable, framework);
}
protected override bool Start()
{
_continueAt = Environment.TickCount64 + (long)(2000f * (base.Task.JumpDestination.DelaySeconds ?? 0.5f));
return base.Start();
}
public unsafe override ETaskResult Update()
{
if (Environment.TickCount64 < _continueAt || _003Ccondition_003EP[ConditionFlag.Jumping])
{
return ETaskResult.StillRunning;
}
IPlayerCharacter localPlayer = _objectTable.LocalPlayer;
if (localPlayer == null)
{
return ETaskResult.TaskComplete;
}
float num = base.Task.JumpDestination.CalculateStopDistance();
if ((localPlayer.Position - base.Task.JumpDestination.Position).Length() <= num || localPlayer.Position.Y >= base.Task.JumpDestination.Position.Y - 0.5f)
{
return ETaskResult.TaskComplete;
}
_003Clogger_003EP.LogTrace("Y-Heights for jumps: player={A}, target={B}", 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 = Environment.TickCount64 + (long)(1000f * (base.Task.JumpDestination.DelaySeconds ?? 0.5f));
return ETaskResult.StillRunning;
}
}
}