using System; using System.Numerics; using Dalamud.Game.ClientState.Objects.Enums; using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Plugin.Services; using Microsoft.Extensions.Logging; using Questionable.Functions; using Questionable.Model; namespace Questionable.Controller.Steps.Movement; internal sealed class MoveToObjectExecutor(MovementController movementController, GameFunctions gameFunctions, IClientState clientState, IObjectTable objectTable, ILogger logger) : TaskExecutor() { private DateTime _startedLookingAt = DateTime.MaxValue; private Vector3 _destination; private bool _moving; protected override bool Start() { if (!base.Task.Step.DataId.HasValue) { logger.LogWarning("MoveToObject task has no DataId"); return false; } if (clientState.TerritoryType != base.Task.Step.TerritoryId) { logger.LogInformation("Not in correct territory yet, waiting"); return true; } _startedLookingAt = DateTime.Now; return TryStartMovement(); } private IGameObject? FindDistantObjectByDataId(uint dataId) { IGameObject gameObject = objectTable[0]; if (gameObject == null) { return null; } float num = base.Task.Step.CalculateActualStopDistance(); IGameObject result = null; float num2 = float.MaxValue; foreach (IGameObject item in objectTable) { ObjectKind objectKind = item.ObjectKind; bool flag = ((objectKind == ObjectKind.Player || objectKind - 8 <= ObjectKind.BattleNpc || objectKind == ObjectKind.Housing) ? true : false); if (!flag && item.BaseId == dataId) { float num3 = Vector3.Distance(gameObject.Position, item.Position); if (!(num3 <= num) && num3 < num2) { result = item; num2 = num3; } } } return result; } private bool TryStartMovement() { IGameObject gameObject = FindDistantObjectByDataId(base.Task.Step.DataId.Value); if (gameObject == null) { gameObject = gameFunctions.FindObjectByDataId(base.Task.Step.DataId.Value, null, warnIfMissing: false); if (gameObject == null) { logger.LogInformation("Object {DataId} not found yet, waiting", base.Task.Step.DataId); return true; } IGameObject gameObject2 = objectTable[0]; float num = base.Task.Step.CalculateActualStopDistance(); if (gameObject2 != null && Vector3.Distance(gameObject2.Position, gameObject.Position) <= num) { logger.LogInformation("Only nearby objects with DataId {DataId} remain, skipping", base.Task.Step.DataId); return true; } } _destination = gameObject.Position; logger.LogInformation("Moving to object {DataId} at {Position}", base.Task.Step.DataId, _destination); movementController.NavigateTo(EMovementType.Quest, base.Task.Step.DataId, _destination, fly: false, base.Task.Step.Sprint ?? true, base.Task.Step.CalculateActualStopDistance()); _moving = true; return true; } public override ETaskResult Update() { if (clientState.TerritoryType != base.Task.Step.TerritoryId) { return ETaskResult.StillRunning; } if (!_moving) { if (_startedLookingAt != DateTime.MaxValue && DateTime.Now > _startedLookingAt.AddSeconds(3.0)) { logger.LogInformation("Object {DataId} not found after timeout, skipping step", base.Task.Step.DataId); return ETaskResult.TaskComplete; } if (!TryStartMovement()) { return ETaskResult.TaskComplete; } if (!_moving) { return ETaskResult.StillRunning; } } 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; } return ETaskResult.TaskComplete; } public override bool ShouldInterruptOnDamage() { return false; } }