291 lines
10 KiB
C#
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;
|
|
}
|
|
}
|