qstbak/Questionable/Questionable.Controller.Steps.Movement/MoveExecutor.cs
2025-10-09 07:47:19 +10:00

291 lines
10 KiB
C#

using System;
using System.Collections.Generic;
using System.Numerics;
using System.Runtime.InteropServices;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Plugin.Services;
using LLib;
using Lumina.Excel.Sheets;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Questionable.Controller.Steps.Common;
using Questionable.Functions;
using Questionable.Model;
using Questionable.Model.Questing;
namespace Questionable.Controller.Steps.Movement;
internal sealed class MoveExecutor : TaskExecutor<MoveTask>, IToastAware, ITaskExecutor
{
private readonly string _cannotExecuteAtThisTime;
private readonly MovementController _movementController;
private readonly GameFunctions _gameFunctions;
private readonly ILogger<MoveExecutor> _logger;
private readonly IClientState _clientState;
private readonly ICondition _condition;
private readonly Questionable.Controller.Steps.Common.Mount.MountEvaluator _mountEvaluator;
private readonly IServiceProvider _serviceProvider;
private System.Action? _startAction;
private Vector3 _destination;
private bool _canRestart;
private (Questionable.Controller.Steps.Common.Mount.MountExecutor Executor, Questionable.Controller.Steps.Common.Mount.MountTask Task)? _mountBeforeMovement;
private (Questionable.Controller.Steps.Common.Mount.UnmountExecutor Executor, Questionable.Controller.Steps.Common.Mount.UnmountTask Task)? _unmountBeforeMovement;
private (Questionable.Controller.Steps.Common.Mount.MountExecutor Executor, Questionable.Controller.Steps.Common.Mount.MountTask Task)? _mountDuringMovement;
public MoveExecutor(MovementController movementController, GameFunctions gameFunctions, ILogger<MoveExecutor> logger, IClientState clientState, ICondition condition, IDataManager dataManager, Questionable.Controller.Steps.Common.Mount.MountEvaluator mountEvaluator, IServiceProvider serviceProvider)
{
_movementController = movementController;
_gameFunctions = gameFunctions;
_logger = logger;
_clientState = clientState;
_condition = condition;
_serviceProvider = serviceProvider;
_mountEvaluator = mountEvaluator;
_cannotExecuteAtThisTime = dataManager.GetString(579u, (LogMessage x) => x.Text);
}
private void PrepareMovementIfNeeded()
{
if (!_gameFunctions.IsFlyingUnlocked(base.Task.TerritoryId))
{
base.Task = base.Task with
{
Fly = false,
Land = false
};
}
if (!base.Task.DisableNavmesh)
{
_startAction = delegate
{
_movementController.NavigateTo(EMovementType.Quest, base.Task.DataId, _destination, base.Task.Fly, base.Task.Sprint ?? (!_mountDuringMovement.HasValue), base.Task.StopDistance, base.Task.IgnoreDistanceToObject ? new float?(float.MaxValue) : ((float?)null), base.Task.Land);
};
return;
}
_startAction = delegate
{
MovementController movementController = _movementController;
uint? dataId = base.Task.DataId;
int num = 1;
List<Vector3> list = new List<Vector3>(num);
CollectionsMarshal.SetCount(list, num);
Span<Vector3> span = CollectionsMarshal.AsSpan(list);
int index = 0;
span[index] = _destination;
movementController.NavigateTo(EMovementType.Quest, dataId, list, base.Task.Fly, base.Task.Sprint ?? (!_mountDuringMovement.HasValue), base.Task.StopDistance, base.Task.IgnoreDistanceToObject ? new float?(float.MaxValue) : ((float?)null), base.Task.Land);
};
}
protected override bool Start()
{
_canRestart = base.Task.RestartNavigation;
_destination = base.Task.Destination;
float num = base.Task.StopDistance ?? 3f;
Vector3? vector = _clientState.LocalPlayer?.Position;
float num2 = ((!vector.HasValue) ? float.MaxValue : Vector3.Distance(vector.Value, _destination));
if (num2 > num)
{
PrepareMovementIfNeeded();
}
if (base.Task.Mount == true)
{
Questionable.Controller.Steps.Common.Mount.MountTask mountTask = new Questionable.Controller.Steps.Common.Mount.MountTask(base.Task.TerritoryId, Questionable.Controller.Steps.Common.Mount.EMountIf.Always);
_mountBeforeMovement = (_serviceProvider.GetRequiredService<Questionable.Controller.Steps.Common.Mount.MountExecutor>(), mountTask);
if (!_mountBeforeMovement.Value.Executor.Start(mountTask))
{
_mountBeforeMovement = null;
}
}
else if (base.Task.Mount == false)
{
Questionable.Controller.Steps.Common.Mount.UnmountTask unmountTask = new Questionable.Controller.Steps.Common.Mount.UnmountTask();
_unmountBeforeMovement = (_serviceProvider.GetRequiredService<Questionable.Controller.Steps.Common.Mount.UnmountExecutor>(), unmountTask);
if (!_unmountBeforeMovement.Value.Executor.Start(unmountTask))
{
_unmountBeforeMovement = null;
}
}
else if (!base.Task.DisableNavmesh)
{
Questionable.Controller.Steps.Common.Mount.EMountIf mountIf = ((!(num2 > num) || !base.Task.Fly || !_gameFunctions.IsFlyingUnlocked(base.Task.TerritoryId)) ? Questionable.Controller.Steps.Common.Mount.EMountIf.AwayFromPosition : Questionable.Controller.Steps.Common.Mount.EMountIf.Always);
Questionable.Controller.Steps.Common.Mount.MountTask mountTask2 = new Questionable.Controller.Steps.Common.Mount.MountTask(base.Task.TerritoryId, mountIf, _destination);
DateTime retryAt = DateTime.Now;
(Questionable.Controller.Steps.Common.Mount.MountExecutor, Questionable.Controller.Steps.Common.Mount.MountTask)? tuple;
if (_mountEvaluator.EvaluateMountState(mountTask2, dryRun: true, ref retryAt) != Questionable.Controller.Steps.Common.Mount.MountResult.DontMount)
{
tuple = (_serviceProvider.GetRequiredService<Questionable.Controller.Steps.Common.Mount.MountExecutor>(), mountTask2);
tuple.Value.Item1.Start(mountTask2);
}
else
{
tuple = null;
}
if (base.Task.Fly)
{
_mountBeforeMovement = tuple;
}
else
{
_mountDuringMovement = tuple;
}
}
if (!_mountBeforeMovement.HasValue && !_unmountBeforeMovement.HasValue && _startAction != null)
{
_startAction();
}
return true;
}
public override ETaskResult Update()
{
ETaskResult? eTaskResult = UpdateMountState();
if (eTaskResult.HasValue)
{
return eTaskResult.GetValueOrDefault();
}
if (_startAction == null)
{
return ETaskResult.TaskComplete;
}
if (_movementController.IsPathfinding || _movementController.IsPathRunning)
{
return ETaskResult.StillRunning;
}
DateTime movementStartedAt = _movementController.MovementStartedAt;
if (movementStartedAt == DateTime.MaxValue || movementStartedAt.AddSeconds(2.0) >= DateTime.Now)
{
return ETaskResult.StillRunning;
}
if (_canRestart && Vector3.Distance(_clientState.LocalPlayer.Position, _destination) > (base.Task.StopDistance ?? 3f) + 5f)
{
_canRestart = false;
if (_clientState.TerritoryType == base.Task.TerritoryId)
{
_logger.LogInformation("Looks like movement was interrupted, re-attempting to move");
_startAction();
return ETaskResult.StillRunning;
}
_logger.LogInformation("Looks like movement was interrupted, do nothing since we're in a different territory now");
}
return ETaskResult.TaskComplete;
}
private ETaskResult? UpdateMountState()
{
(Questionable.Controller.Steps.Common.Mount.MountExecutor, Questionable.Controller.Steps.Common.Mount.MountTask)? mountBeforeMovement = _mountBeforeMovement;
if (mountBeforeMovement.HasValue)
{
Questionable.Controller.Steps.Common.Mount.MountExecutor item = mountBeforeMovement.GetValueOrDefault().Item1;
if (item != null)
{
if (item.Update() == ETaskResult.TaskComplete)
{
_logger.LogInformation("MountBeforeMovement complete");
_mountBeforeMovement = null;
_startAction?.Invoke();
return null;
}
return ETaskResult.StillRunning;
}
}
(Questionable.Controller.Steps.Common.Mount.UnmountExecutor, Questionable.Controller.Steps.Common.Mount.UnmountTask)? unmountBeforeMovement = _unmountBeforeMovement;
if (unmountBeforeMovement.HasValue)
{
Questionable.Controller.Steps.Common.Mount.UnmountExecutor item2 = unmountBeforeMovement.GetValueOrDefault().Item1;
if (item2 != null)
{
if (item2.Update() == ETaskResult.TaskComplete)
{
_logger.LogInformation("UnmountBeforeMovement complete");
_unmountBeforeMovement = null;
_startAction?.Invoke();
return null;
}
return ETaskResult.StillRunning;
}
}
mountBeforeMovement = _mountDuringMovement;
if (mountBeforeMovement.HasValue)
{
(Questionable.Controller.Steps.Common.Mount.MountExecutor, Questionable.Controller.Steps.Common.Mount.MountTask) valueOrDefault = mountBeforeMovement.GetValueOrDefault();
var (mountExecutor, _) = valueOrDefault;
if (mountExecutor != null)
{
Questionable.Controller.Steps.Common.Mount.MountTask item3 = valueOrDefault.Item2;
if ((object)item3 != null)
{
if (mountExecutor.Update() == ETaskResult.TaskComplete)
{
_logger.LogInformation("MountDuringMovement complete (mounted)");
_mountDuringMovement = null;
return null;
}
DateTime retryAt = DateTime.Now;
if (_mountEvaluator.EvaluateMountState(item3, dryRun: true, ref retryAt) == Questionable.Controller.Steps.Common.Mount.MountResult.DontMount)
{
_logger.LogInformation("MountDuringMovement implicitly complete (shouldn't mount anymore)");
_mountDuringMovement = null;
return null;
}
return null;
}
}
}
return null;
}
public override bool WasInterrupted()
{
DateTime retryAt = DateTime.Now;
if (base.Task.Fly && _condition[ConditionFlag.InCombat] && !_condition[ConditionFlag.Mounted])
{
(Questionable.Controller.Steps.Common.Mount.MountExecutor, Questionable.Controller.Steps.Common.Mount.MountTask)? mountBeforeMovement = _mountBeforeMovement;
if (mountBeforeMovement.HasValue)
{
Questionable.Controller.Steps.Common.Mount.MountTask item = mountBeforeMovement.GetValueOrDefault().Item2;
if ((object)item != null && _mountEvaluator.EvaluateMountState(item, dryRun: true, ref retryAt) == Questionable.Controller.Steps.Common.Mount.MountResult.WhenOutOfCombat)
{
return true;
}
}
}
return base.WasInterrupted();
}
public override bool ShouldInterruptOnDamage()
{
if (!_mountBeforeMovement.HasValue)
{
return ShouldResolveCombatBeforeNextInteraction();
}
return true;
}
private bool ShouldResolveCombatBeforeNextInteraction()
{
return base.Task.InteractionType == EInteractionType.Jump;
}
public bool OnErrorToast(SeString message)
{
if (GameFunctions.GameStringEquals(_cannotExecuteAtThisTime, message.TextValue))
{
return true;
}
return false;
}
}