Add experimental navmesh path replay (mostly for finding stuck places)
authorLiza Carvelli <liza@carvel.li>
Wed, 10 Jul 2024 15:58:11 +0000 (17:58 +0200)
committerLiza Carvelli <liza@carvel.li>
Wed, 10 Jul 2024 15:58:11 +0000 (17:58 +0200)
QuestPaths/Dawntrail/MSQ/C-Yak T'el/4907_Mamook Speaks.json
Questionable/Controller/QuestController.cs
Questionable/DalamudInitializer.cs
Questionable/Windows/QuestWindow.cs

index dd7de4f962b6ee7c110361d4e08878385afc993d..9565e80e5897e8c0256bdcf8980b6bce834811d6 100644 (file)
     {
       "Sequence": 5,
       "Steps": [
+        {
+          "Position": {
+            "X": -136.90475,
+            "Y": -215.01514,
+            "Z": 330.17505
+          },
+          "TerritoryId": 1189,
+          "InteractionType": "WalkTo",
+          "Mount": true
+        },
         {
           "DataId": 1047669,
           "Position": {
index 48463285f2a8bbac72a11d85cb7402e365861b46..07f21d728f68b32d4323e7c1081198382206585d 100644 (file)
@@ -53,6 +53,7 @@ internal sealed class QuestController
 
 
     public QuestProgress? CurrentQuest { get; set; }
+    public SimulationProgress? SimulatedQuest { get; set; }
     public string? DebugState { get; private set; }
     public string? Comment { get; private set; }
 
@@ -110,7 +111,16 @@ internal sealed class QuestController
         {
             DebugState = null;
 
-            (ushort currentQuestId, byte currentSequence) = _gameFunctions.GetCurrentQuest();
+            ushort currentQuestId;
+            byte currentSequence;
+            if (SimulatedQuest != null)
+            {
+                currentQuestId = SimulatedQuest.Quest.QuestId;
+                currentSequence = SimulatedQuest.Sequence;
+            }
+            else
+                (currentQuestId, currentSequence) = _gameFunctions.GetCurrentQuest();
+
             if (currentQuestId == 0)
             {
                 if (CurrentQuest != null)
@@ -302,6 +312,14 @@ internal sealed class QuestController
         }
     }
 
+    public void SimulateQuest(Quest? quest)
+    {
+        if (quest != null)
+            SimulatedQuest = new SimulationProgress(quest, 0);
+        else
+            SimulatedQuest = null;
+    }
+
     private void UpdateCurrentTask()
     {
         if (_gameFunctions.IsOccupied())
@@ -464,6 +482,8 @@ internal sealed class QuestController
         }
     }
 
+    public sealed record SimulationProgress(Quest Quest, byte Sequence);
+
     public void Skip(ushort questQuestId, byte currentQuestSequence)
     {
         lock (_lock)
index c45df4173e0cb952cb8be750f0147fd80c8f62a0..caa490f1766246975a705aec173540faf25af4be 100644 (file)
@@ -6,6 +6,7 @@ using Dalamud.Plugin.Services;
 using Microsoft.Extensions.Logging;
 using Questionable.Controller;
 using Questionable.Data;
+using Questionable.Model;
 using Questionable.Windows;
 
 namespace Questionable;
@@ -18,15 +19,18 @@ internal sealed class DalamudInitializer : IDisposable
     private readonly QuestController _questController;
     private readonly MovementController _movementController;
     private readonly NavigationShortcutController _navigationShortcutController;
+    private readonly IChatGui _chatGui;
     private readonly WindowSystem _windowSystem;
     private readonly QuestWindow _questWindow;
-    private readonly ConfigWindow _configWindow;
     private readonly DebugOverlay _debugOverlay;
+    private readonly ConfigWindow _configWindow;
+    private readonly QuestRegistry _questRegistry;
 
     public DalamudInitializer(IDalamudPluginInterface pluginInterface, IFramework framework,
         ICommandManager commandManager, QuestController questController, MovementController movementController,
-        GameUiController gameUiController, NavigationShortcutController navigationShortcutController,
-        WindowSystem windowSystem, QuestWindow questWindow, DebugOverlay debugOverlay, ConfigWindow configWindow)
+        GameUiController gameUiController, NavigationShortcutController navigationShortcutController, IChatGui chatGui,
+        WindowSystem windowSystem, QuestWindow questWindow, DebugOverlay debugOverlay, ConfigWindow configWindow,
+        QuestRegistry questRegistry)
     {
         _pluginInterface = pluginInterface;
         _framework = framework;
@@ -34,10 +38,12 @@ internal sealed class DalamudInitializer : IDisposable
         _questController = questController;
         _movementController = movementController;
         _navigationShortcutController = navigationShortcutController;
+        _chatGui = chatGui;
         _windowSystem = windowSystem;
         _questWindow = questWindow;
-        _configWindow = configWindow;
         _debugOverlay = debugOverlay;
+        _configWindow = configWindow;
+        _questRegistry = questRegistry;
 
         _windowSystem.AddWindow(questWindow);
         _windowSystem.AddWindow(configWindow);
@@ -83,10 +89,46 @@ internal sealed class DalamudInitializer : IDisposable
         }
         else if (arguments.StartsWith("do", StringComparison.Ordinal))
         {
+            if (!_debugOverlay.DrawConditions())
+            {
+                _chatGui.PrintError("[Questionable] You don't have the debug overlay enabled.");
+                return;
+            }
+
             if (arguments.Length >= 4 && ushort.TryParse(arguments.AsSpan(3), out ushort questId))
-                _debugOverlay.HighlightedQuest = questId;
+            {
+                if (_questRegistry.IsKnownQuest(questId))
+                {
+                    _debugOverlay.HighlightedQuest = questId;
+                    _chatGui.Print($"[Questionable] Set highlighted quest to {questId}.");
+                }
+                else
+                    _chatGui.PrintError($"[Questionable] Unknown quest {questId}.");
+            }
             else
+            {
                 _debugOverlay.HighlightedQuest = null;
+                _chatGui.Print("[Questionable] Cleared highlighted quest.");
+            }
+        }
+        else if (arguments.StartsWith("sim", StringComparison.InvariantCulture))
+        {
+            string[] parts = arguments.Split(' ');
+            if (parts.Length == 2 && ushort.TryParse(parts[1], out ushort questId))
+            {
+                if (_questRegistry.TryGetQuest(questId, out Quest? quest))
+                {
+                    _questController.SimulateQuest(quest);
+                    _chatGui.Print($"[Questionable] Simulating quest {questId}.");
+                }
+                else
+                    _chatGui.PrintError($"[Questionable] Unknown quest {questId}.");
+            }
+            else
+            {
+                _questController.SimulateQuest(null);
+                _chatGui.Print("[Questionable] Cleared simulated quest.");
+            }
         }
         else if (string.IsNullOrEmpty(arguments))
             _questWindow.Toggle();
index e7871118ce09e9cf39b07558a8d13b791ccc6078..aef55d0b2645fc1a06c37619bf59abf3eded65e7 100644 (file)
@@ -8,6 +8,7 @@ using Dalamud.Game.Text;
 using Dalamud.Interface;
 using Dalamud.Interface.Colors;
 using Dalamud.Interface.Components;
+using Dalamud.Interface.Utility.Raii;
 using Dalamud.Plugin;
 using Dalamud.Plugin.Services;
 using FFXIVClientStructs.FFXIV.Client.Game;
@@ -202,6 +203,101 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
                 _configuration.General.AutoAcceptNextQuest = autoAcceptNextQuest;
                 _pluginInterface.SavePluginConfig(_configuration);
             }
+
+
+            if (_questController.SimulatedQuest != null)
+            {
+                ImGui.Separator();
+                ImGui.TextColored(ImGuiColors.DalamudRed, "Quest sim active (experimental)");
+                ImGui.Text($"Sequence: {_questController.SimulatedQuest.Sequence}");
+
+                ImGui.BeginDisabled(_questController.SimulatedQuest.Sequence == 0);
+                if (ImGuiComponents.IconButton(FontAwesomeIcon.Minus))
+                {
+                    _movementController.Stop();
+                    _questController.Stop("Sim-");
+
+                    byte oldSequence = _questController.SimulatedQuest.Sequence;
+                    byte newSequence = _questController.SimulatedQuest.Quest.Data.QuestSequence
+                        .Select(x => (byte)x.Sequence)
+                        .LastOrDefault(x => x < oldSequence, byte.MinValue);
+
+                    _questController.SimulatedQuest = _questController.SimulatedQuest with
+                    {
+                        Sequence = newSequence,
+                    };
+                }
+
+                ImGui.EndDisabled();
+
+                ImGui.SameLine();
+                ImGui.BeginDisabled(_questController.SimulatedQuest.Sequence >= 255);
+                if (ImGuiComponents.IconButton(FontAwesomeIcon.Plus))
+                {
+                    _movementController.Stop();
+                    _questController.Stop("Sim+");
+
+                    byte oldSequence = _questController.SimulatedQuest.Sequence;
+                    byte newSequence = _questController.SimulatedQuest.Quest.Data.QuestSequence
+                        .Select(x => (byte)x.Sequence)
+                        .FirstOrDefault(x => x > oldSequence, byte.MaxValue);
+
+                    _questController.SimulatedQuest = _questController.SimulatedQuest with
+                    {
+                        Sequence = newSequence,
+                    };
+                }
+
+                ImGui.EndDisabled();
+
+                var simulatedSequence =
+                    _questController.SimulatedQuest.Quest.FindSequence(_questController.SimulatedQuest.Sequence);
+                if (simulatedSequence != null)
+                {
+                    using var _ = ImRaii.PushId("SimulatedStep");
+
+                    ImGui.Text($"Step: {currentQuest.Step} / {simulatedSequence.Steps.Count - 1}");
+
+                    ImGui.BeginDisabled(currentQuest.Step == 0);
+                    if (ImGuiComponents.IconButton(FontAwesomeIcon.Minus))
+                    {
+                        _movementController.Stop();
+                        _questController.Stop("SimStep-");
+
+                        _questController.CurrentQuest = currentQuest with
+                        {
+                            Step = Math.Min(currentQuest.Step - 1, simulatedSequence.Steps.Count - 1),
+                        };
+                    }
+
+                    ImGui.EndDisabled();
+
+                    ImGui.SameLine();
+                    ImGui.BeginDisabled(currentQuest.Step >= simulatedSequence.Steps.Count);
+                    if (ImGuiComponents.IconButton(FontAwesomeIcon.Plus))
+                    {
+                        _movementController.Stop();
+                        _questController.Stop("SimStep+");
+
+                        _questController.CurrentQuest = currentQuest with
+                        {
+                            Step = currentQuest.Step == simulatedSequence.Steps.Count - 1
+                                ? 255
+                                : (currentQuest.Step + 1),
+                        };
+                    }
+
+                    ImGui.EndDisabled();
+
+                    if (ImGui.Button("Clear sim"))
+                    {
+                        _questController.SimulateQuest(null);
+
+                        _movementController.Stop();
+                        _questController.Stop("ClearSim");
+                    }
+                }
+            }
         }
         else
             ImGui.Text("No active quest");