"WakingSandsSolar",
"RisingStonesSolar",
"RoguesGuild",
+ "NotRoguesGuild",
"DockStorehouse"
]
}
{ EExtraSkipCondition.WakingSandsSolar, "WakingSandsSolar" },
{ EExtraSkipCondition.RisingStonesSolar, "RisingStonesSolar"},
{ EExtraSkipCondition.RoguesGuild, "RoguesGuild"},
+ { EExtraSkipCondition.NotRoguesGuild, "NotRoguesGuild"},
{ EExtraSkipCondition.DockStorehouse, "DockStorehouse"},
};
}
/// Location for ROG quests in Limsa Lominsa; located far underneath the actual lower decks.
/// </summary>
RoguesGuild,
+ NotRoguesGuild,
/// <summary>
/// Location for NIN quests in Eastern La Noscea; located far underneath the actual zone.
<s:Boolean x:Key="/Default/UserDictionary/Words/=tertium/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=tural/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=urqopacha/@EntryIndexedValue">True</s:Boolean>
+ <s:Boolean x:Key="/Default/UserDictionary/Words/=vnavmesh/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=wachumeqimeqi/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=wachunpelo/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=wolekdorf/@EntryIndexedValue">True</s:Boolean>
public bool IsPathfinding => _pathfindTask is { IsCompleted: false };
public DestinationData? Destination { get; set; }
public DateTime MovementStartedAt { get; private set; } = DateTime.Now;
+ public int BuiltNavmeshPercent => _navmeshIpc.GetBuildProgress();
public void Update()
{
public bool IsRunning => !_taskQueue.AllTasksComplete;
public TaskQueue TaskQueue => _taskQueue;
+ public string? CurrentTaskState
+ {
+ get
+ {
+ if (_taskQueue.CurrentTaskExecutor is IDebugStateProvider debugStateProvider)
+ return debugStateProvider.GetDebugState();
+ else
+ return null;
+ }
+ }
+
public sealed class QuestProgress
{
public Quest Quest { get; }
--- /dev/null
+namespace Questionable.Controller.Steps.Common;
+
+internal sealed class WaitNavmesh
+{
+ internal sealed record Task : ITask
+ {
+ public override string ToString() => "Wait(navmesh)";
+ }
+
+ internal sealed class Executor(MovementController movementController) : TaskExecutor<Task>, IDebugStateProvider
+ {
+ protected override bool Start() => true;
+
+ public override ETaskResult Update() =>
+ movementController.IsNavmeshReady ? ETaskResult.TaskComplete : ETaskResult.StillRunning;
+
+ public override bool ShouldInterruptOnDamage() => false;
+
+ public string? GetDebugState()
+ {
+ if (!movementController.IsNavmeshReady)
+ return $"Navmesh: {movementController.BuiltNavmeshPercent}%";
+ else
+ return null;
+ }
+ }
+}
}
internal sealed class WaitSinglePlayerDutyExecutor(
- BossModIpc bossModIpc) : TaskExecutor<WaitSinglePlayerDuty>, IStoppableTaskExecutor
+ BossModIpc bossModIpc,
+ MovementController movementController)
+ : TaskExecutor<WaitSinglePlayerDuty>, IStoppableTaskExecutor, IDebugStateProvider
{
protected override bool Start() => true;
public void StopNow() => bossModIpc.DisableAi();
public override bool ShouldInterruptOnDamage() => false;
+
+ public string? GetDebugState()
+ {
+ if (!movementController.IsNavmeshReady)
+ return $"Navmesh: {movementController.BuiltNavmeshPercent}%";
+ else
+ return null;
+ }
}
internal sealed record DisableAi : ITask
internal static class AethernetShortcut
{
internal sealed class Factory(
- MovementController movementController,
AetheryteData aetheryteData,
TerritoryData territoryData,
IClientState clientState)
if (step.AethernetShortcut == null)
yield break;
- yield return new WaitCondition.Task(() => movementController.IsNavmeshReady,
- "Wait(navmesh ready)");
+ yield return new WaitNavmesh.Task();
yield return new Task(step.AethernetShortcut.From, step.AethernetShortcut.To,
step.SkipConditions?.AethernetShortcutIf ?? new());
}
internal sealed class DelayedGatheringExecutor(
- MovementController movementController,
GatheringData gatheringData,
GatheringPointRegistry gatheringPointRegistry,
TerritoryData territoryData,
yield return new WaitCondition.Task(() => clientState.TerritoryType == territoryId,
$"Wait(territory: {territoryData.GetNameAndId(territoryId)})");
- yield return new WaitCondition.Task(() => movementController.IsNavmeshReady,
- "Wait(navmesh ready)");
+ yield return new WaitNavmesh.Task();
yield return new GatheringTask(gatheringPointId, Task.GatheredItem);
yield return new WaitAtEnd.WaitDelay();
internal static class MoveTo
{
internal sealed class Factory(
- MovementController movementController,
IClientState clientState,
AetheryteData aetheryteData,
TerritoryData territoryData,
$"Wait(territory: {territoryData.GetNameAndId(step.TerritoryId)})");
if (!step.DisableNavmesh)
- {
- yield return new WaitCondition.Task(() => movementController.IsNavmeshReady,
- "Wait(navmesh ready)");
- }
+ yield return new WaitNavmesh.Task();
yield return new MoveTask(step, destination);
EExtraSkipCondition.WakingSandsSolar => territoryType == 212 && position.X >= 24,
EExtraSkipCondition.RisingStonesSolar => territoryType == 351 && position.Z <= -28,
EExtraSkipCondition.RoguesGuild => territoryType == 129 && position.Y <= -115,
+ EExtraSkipCondition.NotRoguesGuild => territoryType == 129 && position.Y > -115,
EExtraSkipCondition.DockStorehouse => territoryType == 137 && position.Y <= -20,
_ => throw new ArgumentOutOfRangeException(nameof(condition), condition, null)
};
void StopNow();
}
+internal interface IDebugStateProvider : ITaskExecutor
+{
+ string? GetDebugState();
+}
+
internal abstract class TaskExecutor<T> : ITaskExecutor
where T : class, ITask
{
private readonly ICallGateSubscriber<List<Vector3>> _pathListWaypoints;
private readonly ICallGateSubscriber<float, object> _pathSetTolerance;
private readonly ICallGateSubscriber<Vector3, bool, float, Vector3?> _queryPointOnFloor;
+ private readonly ICallGateSubscriber<float> _buildProgress;
public NavmeshIpc(IDalamudPluginInterface pluginInterface, ILogger<NavmeshIpc> logger)
{
_pathSetTolerance = pluginInterface.GetIpcSubscriber<float, object>("vnavmesh.Path.SetTolerance");
_queryPointOnFloor =
pluginInterface.GetIpcSubscriber<Vector3, bool, float, Vector3?>("vnavmesh.Query.Mesh.PointOnFloor");
+ _buildProgress = pluginInterface.GetIpcSubscriber<float>("vnavmesh.Nav.BuildProgress");
}
public bool IsReady
else
return [];
}
+
+ public int GetBuildProgress()
+ {
+ try
+ {
+ float progress = _buildProgress.InvokeFunc();
+ if (progress < 0)
+ return 100;
+ return (int)(progress * 100);
+ }
+ catch (IpcError)
+ {
+ return 0;
+ }
+ }
}
serviceCollection.AddTaskExecutor<SinglePlayerDuty.SetTarget, SinglePlayerDuty.SetTargetExecutor>();
serviceCollection.AddTaskExecutor<WaitCondition.Task, WaitCondition.WaitConditionExecutor>();
+ serviceCollection.AddTaskExecutor<WaitNavmesh.Task, WaitNavmesh.Executor>();
serviceCollection.AddTaskFactory<WaitAtEnd.Factory>();
serviceCollection.AddTaskExecutor<WaitAtEnd.WaitDelay, WaitAtEnd.WaitDelayExecutor>();
serviceCollection.AddTaskExecutor<WaitAtEnd.WaitNextStepOrSequence, WaitAtEnd.WaitNextStepOrSequenceExecutor>();
if (_combatController.IsRunning)
ImGui.TextColored(ImGuiColors.DalamudOrange, "In Combat");
+ else if (_questController.CurrentTaskState is { } currentTaskState)
+ {
+ using var _ = ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudOrange);
+ ImGui.TextUnformatted(currentTaskState);
+ }
else
{
- ImGui.BeginDisabled();
+ using var _ = ImRaii.Disabled();
ImGui.TextUnformatted(_questController.DebugState ?? string.Empty);
- ImGui.EndDisabled();
}
QuestSequence? currentSequence = currentQuest.Quest.FindSequence(currentQuest.Sequence);
QuestStep? currentStep = currentSequence?.FindStep(currentQuest.Step);
if (!isMinimized)
{
- bool colored = currentStep is
- { InteractionType: EInteractionType.Instruction or EInteractionType.WaitForManualProgress or EInteractionType.Snipe };
- if (colored)
- ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudOrange);
- ImGui.TextUnformatted(currentStep?.Comment ??
- currentSequence?.Comment ?? currentQuest.Quest.Root.Comment ?? string.Empty);
- if (colored)
- ImGui.PopStyleColor();
+ using (var color = new ImRaii.Color())
+ {
+ bool colored = currentStep is
+ {
+ InteractionType: EInteractionType.Instruction or EInteractionType.WaitForManualProgress
+ or EInteractionType.Snipe
+ };
+ if (colored)
+ color.Push(ImGuiCol.Text, ImGuiColors.DalamudOrange);
+
+ ImGui.TextUnformatted(currentStep?.Comment ??
+ currentSequence?.Comment ?? currentQuest.Quest.Root.Comment ?? string.Empty);
+ }
//var nextStep = _questController.GetNextStep();
//ImGui.BeginDisabled(nextStep.Step == null);