Mini-YA III, save window configs
authorLiza Carvelli <liza@carvel.li>
Sat, 8 Jun 2024 09:30:26 +0000 (11:30 +0200)
committerLiza Carvelli <liza@carvel.li>
Sat, 8 Jun 2024 09:30:26 +0000 (11:30 +0200)
Questionable/.editorconfig
Questionable/Configuration.cs [new file with mode: 0644]
Questionable/Controller/GameUiController.cs
Questionable/QuestionablePlugin.cs
Questionable/Windows/DebugWindow.cs

index 6a4af82e8f2d2999ed445032107a873a2b10205c..1e0e3b2f48a87d3185ab616900e0aa08a62580dc 100644 (file)
@@ -990,7 +990,7 @@ csharp_space_around_binary_operators = before_and_after
 csharp_using_directive_placement = outside_namespace:silent
 csharp_prefer_simple_using_statement = true:suggestion
 csharp_prefer_braces = true:silent
-csharp_style_namespace_declarations = block_scoped:silent
+csharp_style_namespace_declarations = file_scoped:warning
 csharp_style_prefer_method_group_conversion = true:silent
 csharp_style_prefer_top_level_statements = true:silent
 csharp_style_prefer_primary_constructors = true:suggestion
diff --git a/Questionable/Configuration.cs b/Questionable/Configuration.cs
new file mode 100644 (file)
index 0000000..6aa01ec
--- /dev/null
@@ -0,0 +1,10 @@
+using Dalamud.Configuration;
+using LLib.ImGui;
+
+namespace Questionable;
+
+internal sealed class Configuration : IPluginConfiguration
+{
+    public int Version { get; set; } = 1;
+    public WindowConfig DebugWindowConfig { get; set; } = new();
+}
index fc15fb0b6d1cdce3eb16c52878e202e3aa571a26..131814db37a44a6713c189905ba5b85b1486ae4e 100644 (file)
@@ -16,7 +16,6 @@ namespace Questionable.Controller;
 
 internal sealed class GameUiController : IDisposable
 {
-    private readonly IClientState _clientState;
     private readonly IAddonLifecycle _addonLifecycle;
     private readonly IDataManager _dataManager;
     private readonly GameFunctions _gameFunctions;
@@ -24,10 +23,9 @@ internal sealed class GameUiController : IDisposable
     private readonly IGameGui _gameGui;
     private readonly IPluginLog _pluginLog;
 
-    public GameUiController(IClientState clientState, IAddonLifecycle addonLifecycle, IDataManager dataManager,
-        GameFunctions gameFunctions, QuestController questController, IGameGui gameGui, IPluginLog pluginLog)
+    public GameUiController(IAddonLifecycle addonLifecycle, IDataManager dataManager, GameFunctions gameFunctions,
+        QuestController questController, IGameGui gameGui, IPluginLog pluginLog)
     {
-        _clientState = clientState;
         _addonLifecycle = addonLifecycle;
         _dataManager = dataManager;
         _gameFunctions = gameFunctions;
@@ -48,36 +46,36 @@ internal sealed class GameUiController : IDisposable
         if (_gameGui.TryGetAddonByName("SelectString", out AddonSelectString* addonSelectString))
         {
             _pluginLog.Information("SelectString window is open");
-            SelectStringPostSetup(addonSelectString);
+            SelectStringPostSetup(addonSelectString, true);
         }
 
         if (_gameGui.TryGetAddonByName("CutSceneSelectString",
                 out AddonCutSceneSelectString* addonCutSceneSelectString))
         {
             _pluginLog.Information("CutSceneSelectString window is open");
-            CutsceneSelectStringPostSetup(addonCutSceneSelectString);
+            CutsceneSelectStringPostSetup(addonCutSceneSelectString, true);
         }
 
         if (_gameGui.TryGetAddonByName("SelectIconString", out AddonSelectIconString* addonSelectIconString))
         {
             _pluginLog.Information("SelectIconString window is open");
-            SelectIconStringPostSetup(addonSelectIconString);
+            SelectIconStringPostSetup(addonSelectIconString, true);
         }
 
         if (_gameGui.TryGetAddonByName("SelectYesno", out AddonSelectYesno* addonSelectYesno))
         {
             _pluginLog.Information("SelectYesno window is open");
-            SelectYesnoPostSetup(addonSelectYesno);
+            SelectYesnoPostSetup(addonSelectYesno, true);
         }
     }
 
     private unsafe void SelectStringPostSetup(AddonEvent type, AddonArgs args)
     {
         AddonSelectString* addonSelectString = (AddonSelectString*)args.Addon;
-        SelectStringPostSetup(addonSelectString);
+        SelectStringPostSetup(addonSelectString, false);
     }
 
-    private unsafe void SelectStringPostSetup(AddonSelectString* addonSelectString)
+    private unsafe void SelectStringPostSetup(AddonSelectString* addonSelectString, bool checkAllSteps)
     {
         string? actualPrompt = addonSelectString->AtkUnitBase.AtkValues[2].ReadAtkString();
         if (actualPrompt == null)
@@ -87,10 +85,11 @@ internal sealed class GameUiController : IDisposable
         for (ushort i = 7; i < addonSelectString->AtkUnitBase.AtkValuesCount; ++i)
             answers.Add(addonSelectString->AtkUnitBase.AtkValues[i].ReadAtkString());
 
-        int? answer = HandleListChoice(actualPrompt, answers);
+        int? answer = HandleListChoice(actualPrompt, answers, checkAllSteps);
         if (answer != null)
         {
-            _questController.IncreaseDialogueChoicesSelected();
+            if (!checkAllSteps)
+                _questController.IncreaseDialogueChoicesSelected();
             addonSelectString->AtkUnitBase.FireCallbackInt(answer.Value);
         }
     }
@@ -98,10 +97,11 @@ internal sealed class GameUiController : IDisposable
     private unsafe void CutsceneSelectStringPostSetup(AddonEvent type, AddonArgs args)
     {
         AddonCutSceneSelectString* addonCutSceneSelectString = (AddonCutSceneSelectString*)args.Addon;
-        CutsceneSelectStringPostSetup(addonCutSceneSelectString);
+        CutsceneSelectStringPostSetup(addonCutSceneSelectString, false);
     }
 
-    private unsafe void CutsceneSelectStringPostSetup(AddonCutSceneSelectString* addonCutSceneSelectString)
+    private unsafe void CutsceneSelectStringPostSetup(AddonCutSceneSelectString* addonCutSceneSelectString,
+        bool checkAllSteps)
     {
         string? actualPrompt = addonCutSceneSelectString->AtkUnitBase.AtkValues[2].ReadAtkString();
         if (actualPrompt == null)
@@ -111,10 +111,11 @@ internal sealed class GameUiController : IDisposable
         for (int i = 5; i < addonCutSceneSelectString->AtkUnitBase.AtkValuesCount; ++i)
             answers.Add(addonCutSceneSelectString->AtkUnitBase.AtkValues[i].ReadAtkString());
 
-        int? answer = HandleListChoice(actualPrompt, answers);
+        int? answer = HandleListChoice(actualPrompt, answers, checkAllSteps);
         if (answer != null)
         {
-            _questController.IncreaseDialogueChoicesSelected();
+            if (!checkAllSteps)
+                _questController.IncreaseDialogueChoicesSelected();
             addonCutSceneSelectString->AtkUnitBase.FireCallbackInt(answer.Value);
         }
     }
@@ -122,10 +123,10 @@ internal sealed class GameUiController : IDisposable
     private unsafe void SelectIconStringPostSetup(AddonEvent type, AddonArgs args)
     {
         AddonSelectIconString* addonSelectIconString = (AddonSelectIconString*)args.Addon;
-        SelectIconStringPostSetup(addonSelectIconString);
+        SelectIconStringPostSetup(addonSelectIconString, false);
     }
 
-    private unsafe void SelectIconStringPostSetup(AddonSelectIconString* addonSelectIconString)
+    private unsafe void SelectIconStringPostSetup(AddonSelectIconString* addonSelectIconString, bool checkAllSteps)
     {
         string? actualPrompt = addonSelectIconString->AtkUnitBase.AtkValues[3].ReadAtkString();
         if (string.IsNullOrEmpty(actualPrompt))
@@ -135,16 +136,17 @@ internal sealed class GameUiController : IDisposable
         for (ushort i = 0; i < addonSelectIconString->AtkUnitBase.AtkValues[5].Int; i++)
             answers.Add(addonSelectIconString->AtkUnitBase.AtkValues[i * 3 + 7].ReadAtkString());
 
-        int? answer = HandleListChoice(actualPrompt, answers);
+        int? answer = HandleListChoice(actualPrompt, answers, checkAllSteps);
         if (answer != null)
         {
-            _questController.IncreaseDialogueChoicesSelected();
+            if (!checkAllSteps)
+                _questController.IncreaseDialogueChoicesSelected();
             addonSelectIconString->AtkUnitBase.FireCallbackInt(answer.Value);
         }
     }
 
 
-    private int? HandleListChoice(string? actualPrompt, List<string?> answers)
+    private int? HandleListChoice(string? actualPrompt, List<string?> answers, bool checkAllSteps)
     {
         var currentQuest = _questController.CurrentQuest;
         if (currentQuest == null)
@@ -154,14 +156,25 @@ internal sealed class GameUiController : IDisposable
         }
 
         var quest = currentQuest.Quest;
-        var step = quest.FindSequence(currentQuest.Sequence)?.FindStep(currentQuest.Step);
-        if (step == null)
+        IList<DialogueChoice> dialogueChoices;
+        if (checkAllSteps)
         {
-            _pluginLog.Information("Ignoring list choice, no active step");
-            return null;
+            var sequence = quest.FindSequence(currentQuest.Sequence);
+            dialogueChoices = sequence?.Steps.SelectMany(x => x.DialogueChoices).ToList() ?? new List<DialogueChoice>();
+        }
+        else
+        {
+            var step = quest.FindSequence(currentQuest.Sequence)?.FindStep(currentQuest.Step);
+            if (step == null)
+            {
+                _pluginLog.Information("Ignoring list choice, no active step");
+                return null;
+            }
+
+            dialogueChoices = step.DialogueChoices;
         }
 
-        foreach (var dialogueChoice in step.DialogueChoices)
+        foreach (var dialogueChoice in dialogueChoices)
         {
             if (dialogueChoice.Answer == null)
             {
@@ -211,6 +224,7 @@ internal sealed class GameUiController : IDisposable
 
             for (int i = 0; i < answers.Count; ++i)
             {
+                _pluginLog.Verbose($"Checking if {answers[i]} == {excelAnswer}");
                 if (GameStringEquals(answers[i], excelAnswer))
                 {
                     _pluginLog.Information($"Returning {i}: '{answers[i]}' for '{actualPrompt}'");
@@ -226,10 +240,10 @@ internal sealed class GameUiController : IDisposable
     private unsafe void SelectYesnoPostSetup(AddonEvent type, AddonArgs args)
     {
         AddonSelectYesno* addonSelectYesno = (AddonSelectYesno*)args.Addon;
-        SelectYesnoPostSetup(addonSelectYesno);
+        SelectYesnoPostSetup(addonSelectYesno, false);
     }
 
-    private unsafe void SelectYesnoPostSetup(AddonSelectYesno* addonSelectYesno)
+    private unsafe void SelectYesnoPostSetup(AddonSelectYesno* addonSelectYesno, bool checkAllSteps)
     {
         string? actualPrompt = addonSelectYesno->AtkUnitBase.AtkValues[0].ReadAtkString();
         if (actualPrompt == null)
@@ -242,53 +256,71 @@ internal sealed class GameUiController : IDisposable
             return;
 
         var quest = currentQuest.Quest;
-        var step = quest.FindSequence(currentQuest.Sequence)?.FindStep(currentQuest.Step);
-        if (step != null && HandleDefaultYesNo(addonSelectYesno, quest, step, actualPrompt))
-            return;
+        if (checkAllSteps)
+        {
+            var sequence = quest.FindSequence(currentQuest.Sequence);
+            if (sequence != null && HandleDefaultYesNo(addonSelectYesno, quest,
+                    sequence.Steps.SelectMany(x => x.DialogueChoices).ToList(), actualPrompt, checkAllSteps))
+                return;
+        }
+        else
+        {
+            var step = quest.FindSequence(currentQuest.Sequence)?.FindStep(currentQuest.Step);
+            if (step != null && HandleDefaultYesNo(addonSelectYesno, quest, step.DialogueChoices, actualPrompt,
+                    checkAllSteps))
+                return;
+        }
 
         HandleTravelYesNo(addonSelectYesno, currentQuest, actualPrompt);
     }
 
-    private unsafe bool HandleDefaultYesNo(AddonSelectYesno* addonSelectYesno, Quest quest, QuestStep step,
-        string actualPrompt)
+    private unsafe bool HandleDefaultYesNo(AddonSelectYesno* addonSelectYesno, Quest quest,
+        IList<DialogueChoice> dialogueChoices, string actualPrompt, bool checkAllSteps)
     {
-        _pluginLog.Verbose($"DefaultYesNo: Choice count: {step.DialogueChoices.Count}");
-        foreach (var dialogueChoice in step.DialogueChoices)
+        _pluginLog.Verbose($"DefaultYesNo: Choice count: {dialogueChoices.Count}");
+        foreach (var dialogueChoice in dialogueChoices)
         {
             string? excelPrompt;
-            switch (dialogueChoice.Type)
+            if (dialogueChoice.Prompt != null)
             {
-                case EDialogChoiceType.ContentTalkYesNo:
-                    excelPrompt =
-                        _gameFunctions.GetContentTalk(uint.Parse(dialogueChoice.Prompt, CultureInfo.InvariantCulture));
-                    break;
-                case EDialogChoiceType.YesNo:
-                    excelPrompt =
-                        _gameFunctions.GetDialogueText(quest, dialogueChoice.ExcelSheet, dialogueChoice.Prompt);
-                    break;
-                default:
-                    continue;
+                switch (dialogueChoice.Type)
+                {
+                    case EDialogChoiceType.ContentTalkYesNo:
+                        excelPrompt =
+                            _gameFunctions.GetContentTalk(uint.Parse(dialogueChoice.Prompt,
+                                CultureInfo.InvariantCulture));
+                        break;
+                    case EDialogChoiceType.YesNo:
+                        excelPrompt =
+                            _gameFunctions.GetDialogueText(quest, dialogueChoice.ExcelSheet, dialogueChoice.Prompt);
+                        break;
+                    default:
+                        continue;
+                }
             }
+            else
+                excelPrompt = null;
 
             if (excelPrompt == null || !GameStringEquals(actualPrompt, excelPrompt))
                 continue;
 
             addonSelectYesno->AtkUnitBase.FireCallbackInt(dialogueChoice.Yes ? 0 : 1);
-            _questController.IncreaseDialogueChoicesSelected();
+            if (!checkAllSteps)
+                _questController.IncreaseDialogueChoicesSelected();
             return true;
         }
 
         return false;
     }
 
-    private unsafe bool HandleTravelYesNo(AddonSelectYesno* addonSelectYesno,
+    private unsafe void HandleTravelYesNo(AddonSelectYesno* addonSelectYesno,
         QuestController.QuestProgress currentQuest, string actualPrompt)
     {
         // this can be triggered either manually (in which case we should increase the step counter), or automatically
         // (in which case it is ~1 frame later, and the step counter has already been increased)
         var sequence = currentQuest.Quest.FindSequence(currentQuest.Sequence);
         if (sequence == null)
-            return false;
+            return;
 
         bool increaseStepCount = true;
         QuestStep? step = sequence.FindStep(currentQuest.Step);
@@ -308,7 +340,7 @@ internal sealed class GameUiController : IDisposable
         if (step == null || step.TargetTerritoryId == null)
         {
             _pluginLog.Verbose("TravelYesNo: Not found");
-            return false;
+            return;
         }
 
         var warps = _dataManager.GetExcelSheet<Warp>()!
@@ -327,10 +359,8 @@ internal sealed class GameUiController : IDisposable
             addonSelectYesno->AtkUnitBase.FireCallbackInt(0);
             if (increaseStepCount)
                 _questController.IncreaseStepCount();
-            return true;
+            return;
         }
-
-        return false;
     }
 
     private unsafe void CreditPostSetup(AddonEvent type, AddonArgs args)
@@ -353,7 +383,7 @@ internal sealed class GameUiController : IDisposable
     /// <summary>
     /// Ensures characters like '-' are handled equally in both strings.
     /// </summary>
-    private bool GameStringEquals(string? a, string? b)
+    private static bool GameStringEquals(string? a, string? b)
     {
         if (a == null)
             return b == null;
index c3f21cc6e2268aa9cec00555c4456deb613b819e..56eeea992e24ee6a7b5d9409e67efcd80872669a 100644 (file)
@@ -29,6 +29,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin
     private readonly QuestController _questController;
     private readonly MovementController _movementController;
     private readonly GameUiController _gameUiController;
+    private readonly Configuration _configuration;
 
     public QuestionablePlugin(DalamudPluginInterface pluginInterface, IClientState clientState,
         ITargetManager targetManager, IFramework framework, IGameGui gameGui, IDataManager dataManager,
@@ -47,6 +48,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin
         _commandManager = commandManager;
         _gameFunctions = new GameFunctions(dataManager, objectTable, sigScanner, targetManager, condition, clientState,
             pluginLog);
+        _configuration = (Configuration?)_pluginInterface.GetPluginConfig() ?? new Configuration();
 
         AetheryteData aetheryteData = new AetheryteData(dataManager);
         NavmeshIpc navmeshIpc = new NavmeshIpc(pluginInterface);
@@ -56,11 +58,10 @@ public sealed class QuestionablePlugin : IDalamudPlugin
         _questController = new QuestController(pluginInterface, dataManager, _clientState, _gameFunctions,
             _movementController, pluginLog, condition, chatGui, framework, gameGui, aetheryteData, lifestreamIpc);
         _gameUiController =
-            new GameUiController(clientState, addonLifecycle, dataManager, _gameFunctions, _questController, gameGui,
-                pluginLog);
+            new GameUiController(addonLifecycle, dataManager, _gameFunctions, _questController, gameGui, pluginLog);
 
-        _windowSystem.AddWindow(new DebugWindow(_movementController, _questController, _gameFunctions, clientState,
-            framework, targetManager, _gameUiController));
+        _windowSystem.AddWindow(new DebugWindow(pluginInterface, _movementController, _questController, _gameFunctions,
+            clientState, framework, targetManager, _gameUiController, _configuration));
 
         _pluginInterface.UiBuilder.Draw += _windowSystem.Draw;
         _framework.Update += FrameworkUpdate;
index 34169e70bc59010ee9c4dc59c889282ab0c6d15a..d1e83b08cb73b8867c6ee0e490f78f777dad70fa 100644 (file)
@@ -5,19 +5,22 @@ using Dalamud.Game.ClientState.Objects;
 using Dalamud.Interface;
 using Dalamud.Interface.Components;
 using Dalamud.Interface.Windowing;
+using Dalamud.Plugin;
 using Dalamud.Plugin.Services;
 using FFXIVClientStructs.FFXIV.Client.Game;
 using FFXIVClientStructs.FFXIV.Client.Game.Control;
 using FFXIVClientStructs.FFXIV.Client.UI.Agent;
 using ImGuiNET;
+using LLib.ImGui;
 using Questionable.Controller;
 using Questionable.Model;
 using Questionable.Model.V1;
 
 namespace Questionable.Windows;
 
-internal sealed class DebugWindow : Window
+internal sealed class DebugWindow : LWindow, IPersistableWindowConfig
 {
+    private readonly DalamudPluginInterface _pluginInterface;
     private readonly MovementController _movementController;
     private readonly QuestController _questController;
     private readonly GameFunctions _gameFunctions;
@@ -25,12 +28,14 @@ internal sealed class DebugWindow : Window
     private readonly IFramework _framework;
     private readonly ITargetManager _targetManager;
     private readonly GameUiController _gameUiController;
+    private readonly Configuration _configuration;
 
-    public DebugWindow(MovementController movementController, QuestController questController,
-        GameFunctions gameFunctions, IClientState clientState, IFramework framework,
-        ITargetManager targetManager, GameUiController gameUiController)
+    public DebugWindow(DalamudPluginInterface pluginInterface, MovementController movementController,
+        QuestController questController, GameFunctions gameFunctions, IClientState clientState, IFramework framework,
+        ITargetManager targetManager, GameUiController gameUiController, Configuration configuration)
         : base("Questionable", ImGuiWindowFlags.AlwaysAutoResize)
     {
+        _pluginInterface = pluginInterface;
         _movementController = movementController;
         _questController = questController;
         _gameFunctions = gameFunctions;
@@ -38,6 +43,7 @@ internal sealed class DebugWindow : Window
         _framework = framework;
         _targetManager = targetManager;
         _gameUiController = gameUiController;
+        _configuration = configuration;
 
         IsOpen = true;
         SizeConstraints = new WindowSizeConstraints
@@ -47,6 +53,10 @@ internal sealed class DebugWindow : Window
         };
     }
 
+    public WindowConfig WindowConfig => _configuration.DebugWindowConfig;
+
+    public void SaveWindowConfig() => _pluginInterface.SavePluginConfig(_configuration);
+
     public override bool DrawConditions()
     {
         if (!_clientState.IsLoggedIn || _clientState.LocalPlayer == null)