From c7f4865201fb9dbbf89f6e9c4f0b17f850f81d91 Mon Sep 17 00:00:00 2001 From: Liza Carvelli Date: Sun, 23 Feb 2025 18:31:51 +0100 Subject: [PATCH] Indicate navmesh build % in UI --- QuestPaths/quest-v1.json | 1 + .../Converter/SkipConditionConverter.cs | 1 + .../Questing/EExtraSkipCondition.cs | 1 + Questionable.sln.DotSettings | 1 + Questionable/Controller/MovementController.cs | 1 + Questionable/Controller/QuestController.cs | 11 +++++++ .../Controller/Steps/Common/WaitNavmesh.cs | 27 +++++++++++++++++ .../Steps/Interactions/SinglePlayerDuty.cs | 12 +++++++- .../Steps/Shared/AethernetShortcut.cs | 4 +-- .../Controller/Steps/Shared/Gather.cs | 4 +-- .../Controller/Steps/Shared/MoveTo.cs | 6 +--- .../Controller/Steps/Shared/SkipCondition.cs | 1 + Questionable/Controller/Steps/TaskExecutor.cs | 5 ++++ Questionable/External/NavmeshIpc.cs | 17 +++++++++++ Questionable/QuestionablePlugin.cs | 1 + .../QuestComponents/ActiveQuestComponent.cs | 29 ++++++++++++------- 16 files changed, 100 insertions(+), 22 deletions(-) create mode 100644 Questionable/Controller/Steps/Common/WaitNavmesh.cs diff --git a/QuestPaths/quest-v1.json b/QuestPaths/quest-v1.json index ede8e6c66..595974c1b 100644 --- a/QuestPaths/quest-v1.json +++ b/QuestPaths/quest-v1.json @@ -302,6 +302,7 @@ "WakingSandsSolar", "RisingStonesSolar", "RoguesGuild", + "NotRoguesGuild", "DockStorehouse" ] } diff --git a/Questionable.Model/Questing/Converter/SkipConditionConverter.cs b/Questionable.Model/Questing/Converter/SkipConditionConverter.cs index eb9179501..b49a1cfb4 100644 --- a/Questionable.Model/Questing/Converter/SkipConditionConverter.cs +++ b/Questionable.Model/Questing/Converter/SkipConditionConverter.cs @@ -11,6 +11,7 @@ public sealed class SkipConditionConverter() : EnumConverter RoguesGuild, + NotRoguesGuild, /// /// Location for NIN quests in Eastern La Noscea; located far underneath the actual zone. diff --git a/Questionable.sln.DotSettings b/Questionable.sln.DotSettings index ef6a1abd7..528fc571e 100644 --- a/Questionable.sln.DotSettings +++ b/Questionable.sln.DotSettings @@ -37,6 +37,7 @@ True True True + True True True True diff --git a/Questionable/Controller/MovementController.cs b/Questionable/Controller/MovementController.cs index cc8012cf6..338bea94e 100644 --- a/Questionable/Controller/MovementController.cs +++ b/Questionable/Controller/MovementController.cs @@ -89,6 +89,7 @@ internal sealed class MovementController : IDisposable 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() { diff --git a/Questionable/Controller/QuestController.cs b/Questionable/Controller/QuestController.cs index b509de18a..c10d160c6 100644 --- a/Questionable/Controller/QuestController.cs +++ b/Questionable/Controller/QuestController.cs @@ -687,6 +687,17 @@ internal sealed class QuestController : MiniTaskController 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; } diff --git a/Questionable/Controller/Steps/Common/WaitNavmesh.cs b/Questionable/Controller/Steps/Common/WaitNavmesh.cs new file mode 100644 index 000000000..552c7684d --- /dev/null +++ b/Questionable/Controller/Steps/Common/WaitNavmesh.cs @@ -0,0 +1,27 @@ +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, 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; + } + } +} diff --git a/Questionable/Controller/Steps/Interactions/SinglePlayerDuty.cs b/Questionable/Controller/Steps/Interactions/SinglePlayerDuty.cs index 7bf43b810..ef61cb461 100644 --- a/Questionable/Controller/Steps/Interactions/SinglePlayerDuty.cs +++ b/Questionable/Controller/Steps/Interactions/SinglePlayerDuty.cs @@ -96,7 +96,9 @@ internal static class SinglePlayerDuty } internal sealed class WaitSinglePlayerDutyExecutor( - BossModIpc bossModIpc) : TaskExecutor, IStoppableTaskExecutor + BossModIpc bossModIpc, + MovementController movementController) + : TaskExecutor, IStoppableTaskExecutor, IDebugStateProvider { protected override bool Start() => true; @@ -110,6 +112,14 @@ internal static class SinglePlayerDuty 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 diff --git a/Questionable/Controller/Steps/Shared/AethernetShortcut.cs b/Questionable/Controller/Steps/Shared/AethernetShortcut.cs index 460aa440b..ff1c585a6 100644 --- a/Questionable/Controller/Steps/Shared/AethernetShortcut.cs +++ b/Questionable/Controller/Steps/Shared/AethernetShortcut.cs @@ -20,7 +20,6 @@ namespace Questionable.Controller.Steps.Shared; internal static class AethernetShortcut { internal sealed class Factory( - MovementController movementController, AetheryteData aetheryteData, TerritoryData territoryData, IClientState clientState) @@ -31,8 +30,7 @@ internal static class AethernetShortcut 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()); diff --git a/Questionable/Controller/Steps/Shared/Gather.cs b/Questionable/Controller/Steps/Shared/Gather.cs index f4aad9c94..45c007c42 100644 --- a/Questionable/Controller/Steps/Shared/Gather.cs +++ b/Questionable/Controller/Steps/Shared/Gather.cs @@ -38,7 +38,6 @@ internal static class Gather } internal sealed class DelayedGatheringExecutor( - MovementController movementController, GatheringData gatheringData, GatheringPointRegistry gatheringPointRegistry, TerritoryData territoryData, @@ -85,8 +84,7 @@ internal static class Gather 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(); diff --git a/Questionable/Controller/Steps/Shared/MoveTo.cs b/Questionable/Controller/Steps/Shared/MoveTo.cs index 60d83aedd..741c5433c 100644 --- a/Questionable/Controller/Steps/Shared/MoveTo.cs +++ b/Questionable/Controller/Steps/Shared/MoveTo.cs @@ -25,7 +25,6 @@ namespace Questionable.Controller.Steps.Shared; internal static class MoveTo { internal sealed class Factory( - MovementController movementController, IClientState clientState, AetheryteData aetheryteData, TerritoryData territoryData, @@ -67,10 +66,7 @@ internal static class MoveTo $"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); diff --git a/Questionable/Controller/Steps/Shared/SkipCondition.cs b/Questionable/Controller/Steps/Shared/SkipCondition.cs index bd9535397..b651165fd 100644 --- a/Questionable/Controller/Steps/Shared/SkipCondition.cs +++ b/Questionable/Controller/Steps/Shared/SkipCondition.cs @@ -310,6 +310,7 @@ internal static class SkipCondition 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) }; diff --git a/Questionable/Controller/Steps/TaskExecutor.cs b/Questionable/Controller/Steps/TaskExecutor.cs index d96dce2f9..0d0f2a576 100644 --- a/Questionable/Controller/Steps/TaskExecutor.cs +++ b/Questionable/Controller/Steps/TaskExecutor.cs @@ -30,6 +30,11 @@ internal interface IStoppableTaskExecutor : ITaskExecutor void StopNow(); } +internal interface IDebugStateProvider : ITaskExecutor +{ + string? GetDebugState(); +} + internal abstract class TaskExecutor : ITaskExecutor where T : class, ITask { diff --git a/Questionable/External/NavmeshIpc.cs b/Questionable/External/NavmeshIpc.cs index 0c8ce0a71..ab43a5ea0 100644 --- a/Questionable/External/NavmeshIpc.cs +++ b/Questionable/External/NavmeshIpc.cs @@ -20,6 +20,7 @@ internal sealed class NavmeshIpc private readonly ICallGateSubscriber> _pathListWaypoints; private readonly ICallGateSubscriber _pathSetTolerance; private readonly ICallGateSubscriber _queryPointOnFloor; + private readonly ICallGateSubscriber _buildProgress; public NavmeshIpc(IDalamudPluginInterface pluginInterface, ILogger logger) { @@ -35,6 +36,7 @@ internal sealed class NavmeshIpc _pathSetTolerance = pluginInterface.GetIpcSubscriber("vnavmesh.Path.SetTolerance"); _queryPointOnFloor = pluginInterface.GetIpcSubscriber("vnavmesh.Query.Mesh.PointOnFloor"); + _buildProgress = pluginInterface.GetIpcSubscriber("vnavmesh.Nav.BuildProgress"); } public bool IsReady @@ -136,4 +138,19 @@ internal sealed class NavmeshIpc else return []; } + + public int GetBuildProgress() + { + try + { + float progress = _buildProgress.InvokeFunc(); + if (progress < 0) + return 100; + return (int)(progress * 100); + } + catch (IpcError) + { + return 0; + } + } } diff --git a/Questionable/QuestionablePlugin.cs b/Questionable/QuestionablePlugin.cs index 04d69bcf2..865718cbb 100644 --- a/Questionable/QuestionablePlugin.cs +++ b/Questionable/QuestionablePlugin.cs @@ -235,6 +235,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin serviceCollection.AddTaskExecutor(); serviceCollection.AddTaskExecutor(); + serviceCollection.AddTaskExecutor(); serviceCollection.AddTaskFactory(); serviceCollection.AddTaskExecutor(); serviceCollection.AddTaskExecutor(); diff --git a/Questionable/Windows/QuestComponents/ActiveQuestComponent.cs b/Questionable/Windows/QuestComponents/ActiveQuestComponent.cs index 7ec46f3dd..7452a4d71 100644 --- a/Questionable/Windows/QuestComponents/ActiveQuestComponent.cs +++ b/Questionable/Windows/QuestComponents/ActiveQuestComponent.cs @@ -73,25 +73,34 @@ internal sealed partial class ActiveQuestComponent 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);