Add debug command
authorLiza Carvelli <liza@carvel.li>
Sat, 1 Mar 2025 17:13:41 +0000 (18:13 +0100)
committerLiza Carvelli <liza@carvel.li>
Sat, 1 Mar 2025 17:14:39 +0000 (18:14 +0100)
Questionable/Controller/CommandHandler.cs
Questionable/Functions/GameFunctions.cs

index 1c2bed2..6a4e36e 100644 (file)
@@ -4,7 +4,6 @@ using Dalamud.Game.ClientState.Objects;
 using Dalamud.Game.Command;
 using Dalamud.Plugin.Services;
 using Lumina.Excel.Sheets;
-using Microsoft.Extensions.Logging;
 using Questionable.Functions;
 using Questionable.Model.Questing;
 using Questionable.Windows;
@@ -77,18 +76,18 @@ internal sealed class CommandHandler : IDisposable
                 "/qst which - shows all quests starting with your selected target",
                 "/qst zone - shows all quests starting in the current zone (only includes quests with a known quest path, and currently visible unaccepted quests)")
         });
+#if DEBUG
+        _commandManager.AddHandler("/qst@", new CommandInfo(ProcessDebugCommand)
+        {
+            ShowInHelp = false,
+        });
+#endif
     }
 
     private void ProcessCommand(string command, string arguments)
     {
-        if (!_configuration.IsPluginSetupComplete())
-        {
-            if (string.IsNullOrEmpty(arguments))
-                _oneTimeSetupWindow.IsOpen = true;
-            else
-                _chatGui.PrintError("Please complete the one-time setup first.", MessageTag, TagColor);
+        if (OpenSetupIfNeeded(arguments))
             return;
-        }
 
         string[] parts = arguments.Split(' ');
         switch (parts[0])
@@ -151,6 +150,34 @@ internal sealed class CommandHandler : IDisposable
         }
     }
 
+    private void ProcessDebugCommand(string command, string arguments)
+    {
+        if (OpenSetupIfNeeded(arguments))
+            return;
+
+        string[] parts = arguments.Split(' ');
+        switch (parts[0])
+        {
+            case "abandon-duty":
+                _gameFunctions.AbandonDuty();
+                break;
+        }
+    }
+
+    private bool OpenSetupIfNeeded(string arguments)
+    {
+        if (!_configuration.IsPluginSetupComplete())
+        {
+            if (string.IsNullOrEmpty(arguments))
+                _oneTimeSetupWindow.IsOpen = true;
+            else
+                _chatGui.PrintError("Please complete the one-time setup first.", MessageTag, TagColor);
+            return true;
+        }
+
+        return false;
+    }
+
     private void ConfigureDebugOverlay(string[] arguments)
     {
         if (!_debugOverlay.DrawConditions())
@@ -251,6 +278,9 @@ internal sealed class CommandHandler : IDisposable
 
     public void Dispose()
     {
+#if DEBUG
+        _commandManager.RemoveHandler("/qst@");
+#endif
         _commandManager.RemoveHandler("/qst");
     }
 }
index 27c5fc8..50c0c44 100644 (file)
@@ -3,6 +3,8 @@ using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Linq;
 using System.Numerics;
+using System.Runtime.InteropServices;
+using Dalamud.Game;
 using Dalamud.Game.ClientState.Conditions;
 using Dalamud.Game.ClientState.Objects;
 using Dalamud.Game.ClientState.Objects.Types;
@@ -29,8 +31,7 @@ namespace Questionable.Functions;
 
 internal sealed unsafe class GameFunctions
 {
-    private readonly ReadOnlyDictionary<ushort, byte> _territoryToAetherCurrentCompFlgSet;
-    private readonly ReadOnlyDictionary<uint, uint> _contentFinderConditionToContentId;
+    private delegate void AbandonDutyDelegate(bool a1);
 
     private readonly QuestFunctions _questFunctions;
     private readonly IDataManager _dataManager;
@@ -41,6 +42,10 @@ internal sealed unsafe class GameFunctions
     private readonly IGameGui _gameGui;
     private readonly Configuration _configuration;
     private readonly ILogger<GameFunctions> _logger;
+    private readonly AbandonDutyDelegate _abandonDuty;
+
+    private readonly ReadOnlyDictionary<ushort, byte> _territoryToAetherCurrentCompFlgSet;
+    private readonly ReadOnlyDictionary<uint, uint> _contentFinderConditionToContentId;
 
     public GameFunctions(
         QuestFunctions questFunctions,
@@ -51,6 +56,7 @@ internal sealed unsafe class GameFunctions
         IClientState clientState,
         IGameGui gameGui,
         Configuration configuration,
+        ISigScanner sigScanner,
         ILogger<GameFunctions> logger)
     {
         _questFunctions = questFunctions;
@@ -62,6 +68,8 @@ internal sealed unsafe class GameFunctions
         _gameGui = gameGui;
         _configuration = configuration;
         _logger = logger;
+        _abandonDuty =
+            Marshal.GetDelegateForFunctionPointer<AbandonDutyDelegate>(sigScanner.ScanText(Signatures.AbandonDuty));
 
         _territoryToAetherCurrentCompFlgSet = dataManager.GetExcelSheet<TerritoryType>()
             .Where(x => x.RowId > 0)
@@ -502,6 +510,12 @@ internal sealed unsafe class GameFunctions
         return slots;
     }
 
+    /// <summary>
+    /// Abandons <em>some</em> quest battles/duties; but not all? Useful for debugging some quest battle/vbm related
+    /// issues.
+    /// </summary>
+    public void AbandonDuty() => _abandonDuty(false);
+
 #if false
     private byte ExecuteCommand(int id, int a, int b, int c, int d)
     {
@@ -513,4 +527,9 @@ internal sealed unsafe class GameFunctions
         return 0;
     }
 #endif
+
+    private static class Signatures
+    {
+        internal const string AbandonDuty = "E8 ?? ?? ?? ?? 41 B2 01 EB 39";
+    }
 }