qstbak/Questionable/Questionable.Controller/SeasonalDutyController.cs
2026-03-26 14:56:12 +10:00

151 lines
4.9 KiB
C#

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.InteropServices;
using Dalamud.Plugin.Services;
using Microsoft.Extensions.Logging;
using Questionable.Controller.Steps;
using Questionable.Controller.Steps.Common;
using Questionable.Controller.Steps.Interactions;
using Questionable.Controller.Steps.Movement;
using Questionable.Controller.Steps.Shared;
using Questionable.Model.Questing;
namespace Questionable.Controller;
internal sealed class SeasonalDutyController : MiniTaskController<SeasonalDutyController>
{
private readonly MovementController _movementController;
private readonly IClientState _clientState;
private readonly ILogger<SeasonalDutyController> _logger;
private SeasonalDutyDefinition? _currentDuty;
private int _completedCycles;
private int? _cycleLimit;
private DateTime _startTime;
public bool IsRunning => _currentDuty != null;
public SeasonalDutyDefinition? CurrentDuty => _currentDuty;
public int CompletedCycles => _completedCycles;
public int? CycleLimit => _cycleLimit;
public TimeSpan ElapsedTime
{
get
{
if (!IsRunning)
{
return TimeSpan.Zero;
}
return DateTime.UtcNow - _startTime;
}
}
public SeasonalDutyController(IChatGui chatGui, ICondition condition, IServiceProvider serviceProvider, InterruptHandler interruptHandler, IDataManager dataManager, ILogger<SeasonalDutyController> logger, MovementController movementController, IClientState clientState)
: base(chatGui, condition, serviceProvider, interruptHandler, dataManager, logger)
{
_movementController = movementController;
_clientState = clientState;
_logger = logger;
}
public void Start(SeasonalDutyDefinition duty, int? cycleLimit = null)
{
_currentDuty = duty;
_completedCycles = 0;
_cycleLimit = cycleLimit;
_startTime = DateTime.UtcNow;
_logger.LogInformation("Starting seasonal duty farming: {DutyName} (limit: {Limit})", duty.Name, cycleLimit?.ToString(CultureInfo.InvariantCulture) ?? "unlimited");
EnqueueDutyCycle();
}
public void Update()
{
if (_currentDuty == null || _movementController.IsPathfinding || _movementController.IsPathRunning)
{
return;
}
if (_taskQueue.AllTasksComplete)
{
_completedCycles++;
if (_cycleLimit.HasValue && _completedCycles >= _cycleLimit.Value)
{
_logger.LogInformation("Seasonal duty cycle limit reached ({Cycles}/{Limit})", _completedCycles, _cycleLimit.Value);
Stop("Cycle limit reached");
return;
}
EnqueueDutyCycle();
}
UpdateCurrentTask();
}
private void EnqueueDutyCycle()
{
if (_currentDuty != null)
{
SeasonalDutyDefinition currentDuty = _currentDuty;
_logger.LogInformation("Enqueuing seasonal duty cycle for {DutyName}", currentDuty.Name);
if (_clientState.TerritoryType != currentDuty.TerritoryId && _clientState.TerritoryType != currentDuty.DutyTerritoryId)
{
_taskQueue.Enqueue(new AetheryteShortcut.Task(null, null, currentDuty.Aetheryte, currentDuty.TerritoryId));
}
if (currentDuty.AethernetShortcut != null)
{
_taskQueue.Enqueue(new AethernetShortcut.Task(currentDuty.AethernetShortcut.From, currentDuty.AethernetShortcut.To));
}
_taskQueue.Enqueue(new MoveTask(currentDuty.TerritoryId, currentDuty.NpcPosition, null, 3f));
_taskQueue.Enqueue(new Mount.UnmountTask());
_taskQueue.Enqueue(new Interact.Task(currentDuty.NpcDataId, null, EInteractionType.Interact, SkipMarkerCheck: true));
_taskQueue.Enqueue(new WaitCondition.Task(() => _clientState.TerritoryType == _currentDuty.DutyTerritoryId, $"Wait(territory: {currentDuty.DutyTerritoryId})"));
_taskQueue.Enqueue(new ClearObjectsWithAction.ClearTask(currentDuty.DataIds, currentDuty.Action, currentDuty.DutyTerritoryId, currentDuty.StopDistance, currentDuty.WaypointPositions));
_taskQueue.Enqueue(new WaitCondition.Task(() => _clientState.TerritoryType != _currentDuty.DutyTerritoryId, "Wait(duty end)"));
_taskQueue.Enqueue(new WaitAtEnd.WaitDelay(TimeSpan.FromSeconds(3L)));
}
}
public override void Stop(string label)
{
if (_currentDuty != null)
{
_logger.LogInformation("Stopping seasonal duty farming: {Label} (completed {Cycles} cycles)", label, _completedCycles);
_currentDuty = null;
_completedCycles = 0;
_cycleLimit = null;
_taskQueue.Reset();
}
}
public override IList<string> GetRemainingTaskNames()
{
ITask task = _taskQueue.CurrentTaskExecutor?.CurrentTask;
if (task != null)
{
string text = task.ToString() ?? "?";
IList<string> remainingTaskNames = base.GetRemainingTaskNames();
int num = 1 + remainingTaskNames.Count;
List<string> list = new List<string>(num);
CollectionsMarshal.SetCount(list, num);
Span<string> span = CollectionsMarshal.AsSpan(list);
int num2 = 0;
span[num2] = text;
num2++;
{
foreach (string item in remainingTaskNames)
{
span[num2] = item;
num2++;
}
return list;
}
}
return base.GetRemainingTaskNames();
}
}