1
0
Fork 0
forked from aly/qstbak

muffin v7.4.18

This commit is contained in:
alydev 2026-03-26 14:56:12 +10:00
parent 53aa9fdee8
commit f82b9ce2a2
50 changed files with 142364 additions and 230361 deletions

View file

@ -0,0 +1,347 @@
using System;
using System.Collections.Generic;
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;
using Questionable.Model.Questing;
namespace Questionable.Controller.Steps.Interactions;
internal static class ClearObjectsWithAction
{
internal sealed class Factory : ITaskFactory
{
public IEnumerable<ITask> CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step)
{
if (step.InteractionType != EInteractionType.Action)
{
return Array.Empty<ITask>();
}
if (step.DataIds.Count == 0)
{
return Array.Empty<ITask>();
}
if (!step.Action.HasValue)
{
return Array.Empty<ITask>();
}
return new global::_003C_003Ez__ReadOnlySingleElementList<ITask>(new ClearTask(step.DataIds, step.Action.Value, step.TerritoryId, step.CalculateActualStopDistance(), step.WaypointPositions));
}
}
internal sealed record ClearTask(List<uint> DataIds, EAction Action, ushort TerritoryId, float StopDistance, List<Vector3> WaypointPositions) : ITask
{
public bool ShouldRedoOnInterrupt()
{
return true;
}
public override string ToString()
{
return $"ClearObjects({Action}, {DataIds.Count} types)";
}
}
internal sealed class ClearTaskExecutor(MovementController movementController, GameFunctions gameFunctions, IClientState clientState, IObjectTable objectTable, ILogger<ClearTaskExecutor> logger) : TaskExecutor<ClearTask>()
{
private enum State
{
FindingObject,
MovingToObject,
UsingAction,
WaitingAfterAction,
MovingToWaypoint,
WaitingForTransition
}
private const float VisitedPositionRadius = 5f;
private State _state;
private DateTime _noObjectFoundSince = DateTime.MaxValue;
private DateTime _waitUntil = DateTime.MinValue;
private DateTime _waypointReachedAt = DateTime.MaxValue;
private Vector3 _lastPlayerPosition;
private readonly List<Vector3> _visitedPositions = new List<Vector3>();
private readonly List<int> _triedWaypointIndices = new List<int>();
protected override bool Start()
{
if (clientState.TerritoryType != base.Task.TerritoryId)
{
return true;
}
return TryFindAndMove();
}
private bool IsVisitedPosition(Vector3 position)
{
foreach (Vector3 visitedPosition in _visitedPositions)
{
if (Vector3.Distance(visitedPosition, position) <= 5f)
{
return true;
}
}
return false;
}
private IGameObject? FindNearestUnvisitedObject()
{
IGameObject gameObject = objectTable[0];
if (gameObject == null)
{
return null;
}
IGameObject result = null;
float num = float.MaxValue;
foreach (IGameObject item in objectTable)
{
ObjectKind objectKind = item.ObjectKind;
if ((objectKind == ObjectKind.Player || objectKind - 8 <= ObjectKind.BattleNpc || objectKind == ObjectKind.Housing) ? true : false)
{
continue;
}
bool flag = false;
foreach (uint dataId in base.Task.DataIds)
{
if (item.BaseId == dataId)
{
flag = true;
break;
}
}
if (flag && !IsVisitedPosition(item.Position))
{
float num2 = Vector3.Distance(gameObject.Position, item.Position);
if (num2 < num)
{
result = item;
num = num2;
}
}
}
return result;
}
private bool AnyMatchingObjectsExist()
{
foreach (IGameObject item in objectTable)
{
ObjectKind objectKind = item.ObjectKind;
if ((objectKind == ObjectKind.Player || objectKind - 8 <= ObjectKind.BattleNpc || objectKind == ObjectKind.Housing) ? true : false)
{
continue;
}
foreach (uint dataId in base.Task.DataIds)
{
if (item.BaseId == dataId)
{
return true;
}
}
}
return false;
}
private bool TryFindAndMove()
{
IGameObject gameObject = FindNearestUnvisitedObject();
if (gameObject == null)
{
_state = State.FindingObject;
if (_noObjectFoundSince == DateTime.MaxValue)
{
_noObjectFoundSince = DateTime.Now;
}
return true;
}
_noObjectFoundSince = DateTime.MaxValue;
Vector3 position = gameObject.Position;
logger.LogInformation("Moving to object {DataId} at {Position}", gameObject.BaseId, position);
movementController.NavigateTo(EMovementType.Quest, gameObject.BaseId, position, fly: false, sprint: true, base.Task.StopDistance);
_state = State.MovingToObject;
return true;
}
private (Vector3 Position, int Index)? FindNextWaypoint()
{
IGameObject gameObject = objectTable[0];
if (gameObject == null || base.Task.WaypointPositions.Count == 0)
{
return null;
}
(Vector3, int)? result = null;
float num = float.MaxValue;
for (int i = 0; i < base.Task.WaypointPositions.Count; i++)
{
if (!_triedWaypointIndices.Contains(i))
{
float num2 = Vector3.Distance(gameObject.Position, base.Task.WaypointPositions[i]);
if (num2 < num)
{
result = (base.Task.WaypointPositions[i], i);
num = num2;
}
}
}
return result;
}
private void NavigateToNextWaypoint()
{
(Vector3, int)? tuple = FindNextWaypoint();
if (!tuple.HasValue)
{
logger.LogInformation("All waypoints tried without transition, resetting");
_triedWaypointIndices.Clear();
tuple = FindNextWaypoint();
if (!tuple.HasValue)
{
logger.LogWarning("No waypoint positions configured, waiting for transition");
_state = State.WaitingForTransition;
_lastPlayerPosition = objectTable[0]?.Position ?? Vector3.Zero;
return;
}
}
_triedWaypointIndices.Add(tuple.Value.Item2);
logger.LogInformation("Moving to waypoint {Index} at {Position}", tuple.Value.Item2, tuple.Value.Item1);
movementController.NavigateTo(EMovementType.Quest, null, tuple.Value.Item1, fly: false, sprint: true, 0f);
_state = State.MovingToWaypoint;
}
public override ETaskResult Update()
{
if (clientState.TerritoryType != base.Task.TerritoryId)
{
return ETaskResult.TaskComplete;
}
switch (_state)
{
case State.FindingObject:
if (_noObjectFoundSince != DateTime.MaxValue && DateTime.Now > _noObjectFoundSince.AddSeconds(3.0))
{
if (AnyMatchingObjectsExist())
{
logger.LogInformation("Matching objects still exist, clearing visited positions and retrying");
_visitedPositions.Clear();
_noObjectFoundSince = DateTime.MaxValue;
}
else
{
logger.LogInformation("No matching objects remain, moving to waypoint");
NavigateToNextWaypoint();
}
return ETaskResult.StillRunning;
}
TryFindAndMove();
return ETaskResult.StillRunning;
case State.MovingToObject:
{
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;
}
IGameObject gameObject2 = FindNearestUnvisitedObject();
IGameObject gameObject3 = objectTable[0];
if (gameObject2 != null && gameObject3 != null && Vector3.Distance(gameObject3.Position, gameObject2.Position) <= 5f)
{
_visitedPositions.Add(gameObject2.Position);
_state = State.UsingAction;
}
else
{
logger.LogInformation("Target no longer valid at destination, finding next");
TryFindAndMove();
}
return ETaskResult.StillRunning;
}
case State.UsingAction:
if (gameFunctions.UseAction(base.Task.Action))
{
logger.LogInformation("Used action {Action}", base.Task.Action);
_waitUntil = DateTime.Now.AddSeconds(1.0);
_state = State.WaitingAfterAction;
}
return ETaskResult.StillRunning;
case State.WaitingAfterAction:
if (DateTime.Now < _waitUntil)
{
return ETaskResult.StillRunning;
}
TryFindAndMove();
return ETaskResult.StillRunning;
case State.MovingToWaypoint:
{
if (movementController.IsPathfinding || movementController.IsPathRunning)
{
return ETaskResult.StillRunning;
}
DateTime movementStartedAt2 = movementController.MovementStartedAt;
if (movementStartedAt2 == DateTime.MaxValue || movementStartedAt2.AddSeconds(2.0) >= DateTime.Now)
{
return ETaskResult.StillRunning;
}
logger.LogInformation("Reached waypoint, waiting for zone transition");
_state = State.WaitingForTransition;
_lastPlayerPosition = objectTable[0]?.Position ?? Vector3.Zero;
_waypointReachedAt = DateTime.Now;
return ETaskResult.StillRunning;
}
case State.WaitingForTransition:
{
IGameObject gameObject = objectTable[0];
if (gameObject != null)
{
float num = Vector3.Distance(_lastPlayerPosition, gameObject.Position);
if (num > 50f)
{
logger.LogInformation("Zone transition detected (moved {Distance}), resuming plant clearing", num);
_visitedPositions.Clear();
_triedWaypointIndices.Clear();
_noObjectFoundSince = DateTime.MaxValue;
_state = State.FindingObject;
return ETaskResult.StillRunning;
}
}
if (FindNearestUnvisitedObject() != null)
{
logger.LogInformation("New objects detected, resuming plant clearing");
_visitedPositions.Clear();
_triedWaypointIndices.Clear();
_noObjectFoundSince = DateTime.MaxValue;
TryFindAndMove();
return ETaskResult.StillRunning;
}
if (_waypointReachedAt != DateTime.MaxValue && DateTime.Now > _waypointReachedAt.AddSeconds(3.0))
{
logger.LogInformation("No transition at this waypoint, trying next");
NavigateToNextWaypoint();
}
return ETaskResult.StillRunning;
}
default:
return ETaskResult.TaskComplete;
}
}
public override bool ShouldInterruptOnDamage()
{
return false;
}
}
}