From: Liza Carvelli Date: Tue, 18 Jun 2024 15:51:23 +0000 (+0200) Subject: Add minimal debug overlay X-Git-Tag: v0.18~3 X-Git-Url: https://git.jacobcasper.com/?a=commitdiff_plain;h=2f73fd64fbf2d0f96f6db6dc3515a1530035f24f;p=Questionable.git Add minimal debug overlay --- diff --git a/QuestPaths/Endwalker/MSQ/B-Garlemald/4385_How the Mighty Are Fallen.json b/QuestPaths/Endwalker/MSQ/B-Garlemald/4385_How the Mighty Are Fallen.json index 94d98301..aa95cdb2 100644 --- a/QuestPaths/Endwalker/MSQ/B-Garlemald/4385_How the Mighty Are Fallen.json +++ b/QuestPaths/Endwalker/MSQ/B-Garlemald/4385_How the Mighty Are Fallen.json @@ -285,8 +285,7 @@ }, "TerritoryId": 958, "InteractionType": "Interact", - "Mount": false, - "Comment": "TODO Should cancel Navmesh on fade out" + "Mount": false } ] }, diff --git a/Questionable/Configuration.cs b/Questionable/Configuration.cs index 7dc415b9..eaef4936 100644 --- a/Questionable/Configuration.cs +++ b/Questionable/Configuration.cs @@ -21,6 +21,7 @@ internal sealed class Configuration : IPluginConfiguration internal sealed class AdvancedConfiguration { + public bool DebugOverlay { get; set; } public bool NeverFly { get; set; } } } diff --git a/Questionable/DalamudInitializer.cs b/Questionable/DalamudInitializer.cs index 192a9ba9..e1370964 100644 --- a/Questionable/DalamudInitializer.cs +++ b/Questionable/DalamudInitializer.cs @@ -17,13 +17,13 @@ internal sealed class DalamudInitializer : IDisposable private readonly MovementController _movementController; private readonly NavigationShortcutController _navigationShortcutController; private readonly WindowSystem _windowSystem; - private readonly DebugWindow _debugWindow; + private readonly QuestWindow _questWindow; private readonly ConfigWindow _configWindow; public DalamudInitializer(DalamudPluginInterface pluginInterface, IFramework framework, ICommandManager commandManager, QuestController questController, MovementController movementController, GameUiController gameUiController, NavigationShortcutController navigationShortcutController, - WindowSystem windowSystem, DebugWindow debugWindow, ConfigWindow configWindow) + WindowSystem windowSystem, QuestWindow questWindow, DebugOverlay debugOverlay, ConfigWindow configWindow) { _pluginInterface = pluginInterface; _framework = framework; @@ -32,14 +32,15 @@ internal sealed class DalamudInitializer : IDisposable _movementController = movementController; _navigationShortcutController = navigationShortcutController; _windowSystem = windowSystem; - _debugWindow = debugWindow; + _questWindow = questWindow; _configWindow = configWindow; - _windowSystem.AddWindow(debugWindow); + _windowSystem.AddWindow(questWindow); _windowSystem.AddWindow(configWindow); + _windowSystem.AddWindow(debugOverlay); _pluginInterface.UiBuilder.Draw += _windowSystem.Draw; - _pluginInterface.UiBuilder.OpenMainUi += _debugWindow.Toggle; + _pluginInterface.UiBuilder.OpenMainUi += _questWindow.Toggle; _pluginInterface.UiBuilder.OpenConfigUi += _configWindow.Toggle; _framework.Update += FrameworkUpdate; _commandManager.AddHandler("/qst", new CommandInfo(ProcessCommand) @@ -70,14 +71,14 @@ internal sealed class DalamudInitializer : IDisposable if (arguments is "c" or "config") _configWindow.Toggle(); else - _debugWindow.Toggle(); + _questWindow.Toggle(); } public void Dispose() { _commandManager.RemoveHandler("/qst"); _framework.Update -= FrameworkUpdate; - _pluginInterface.UiBuilder.OpenMainUi -= _debugWindow.Toggle; + _pluginInterface.UiBuilder.OpenMainUi -= _questWindow.Toggle; _pluginInterface.UiBuilder.Draw -= _windowSystem.Draw; _windowSystem.RemoveAllWindows(); diff --git a/Questionable/QuestionablePlugin.cs b/Questionable/QuestionablePlugin.cs index 4046b3bb..a4f2f9b2 100644 --- a/Questionable/QuestionablePlugin.cs +++ b/Questionable/QuestionablePlugin.cs @@ -80,6 +80,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin serviceCollection.AddTaskWithFactory(); serviceCollection.AddTaskWithFactory(); serviceCollection.AddTaskWithFactory(); + serviceCollection.AddTaskWithFactory(); serviceCollection.AddTaskWithFactory(); serviceCollection.AddTransient(); @@ -109,13 +110,14 @@ public sealed class QuestionablePlugin : IDalamudPlugin serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); _serviceProvider = serviceCollection.BuildServiceProvider(); _serviceProvider.GetRequiredService().Reload(); - _serviceProvider.GetRequiredService(); + _serviceProvider.GetRequiredService(); _serviceProvider.GetRequiredService(); } diff --git a/Questionable/Windows/ConfigWindow.cs b/Questionable/Windows/ConfigWindow.cs index 3a3ce083..b820e7e5 100644 --- a/Questionable/Windows/ConfigWindow.cs +++ b/Questionable/Windows/ConfigWindow.cs @@ -79,6 +79,13 @@ internal sealed class ConfigWindow : LWindow, IPersistableWindowConfig ImGui.Separator(); + bool debugOverlay = _configuration.Advanced.DebugOverlay; + if (ImGui.Checkbox("Enable debug overlay", ref debugOverlay)) + { + _configuration.Advanced.DebugOverlay = debugOverlay; + Save(); + } + bool neverFly = _configuration.Advanced.NeverFly; if (ImGui.Checkbox("Disable flying (even if unlocked for the zone)", ref neverFly)) { diff --git a/Questionable/Windows/DebugOverlay.cs b/Questionable/Windows/DebugOverlay.cs new file mode 100644 index 00000000..191a7d5c --- /dev/null +++ b/Questionable/Windows/DebugOverlay.cs @@ -0,0 +1,68 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Numerics; +using Dalamud.Interface.Utility; +using Dalamud.Interface.Windowing; +using Dalamud.Plugin.Services; +using ImGuiNET; +using Questionable.Controller; +using Questionable.Model.V1; + +namespace Questionable.Windows; + +internal sealed class DebugOverlay : Window +{ + private readonly QuestController _questController; + private readonly IGameGui _gameGui; + private readonly Configuration _configuration; + + public DebugOverlay(QuestController questController, IGameGui gameGui, Configuration configuration) + : base("Questionable Debug Overlay###QuestionableDebugOverlay", + ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoBackground | + ImGuiWindowFlags.NoInputs | ImGuiWindowFlags.NoSavedSettings, true) + { + _questController = questController; + _gameGui = gameGui; + _configuration = configuration; + + Position = Vector2.Zero; + PositionCondition = ImGuiCond.Always; + Size = ImGui.GetIO().DisplaySize; + SizeCondition = ImGuiCond.Always; + IsOpen = true; + } + + public override bool DrawConditions() => _configuration.Advanced.DebugOverlay; + + public override void PreDraw() + { + Size = ImGui.GetIO().DisplaySize; + } + + public override void Draw() + { + var currentQuest = _questController.CurrentQuest; + if (currentQuest == null) + return; + + var sequence = currentQuest.Quest.FindSequence(currentQuest.Sequence); + if (sequence == null) + return; + + for (int i = currentQuest.Step; i <= sequence.Steps.Count; ++i) + { + QuestStep? step = sequence.FindStep(i); + if (step == null || step.Position == null) + continue; + + bool visible = _gameGui.WorldToScreen(step.Position.Value, out Vector2 screenPos); + if (!visible) + continue; + + ImGui.GetWindowDrawList().AddCircleFilled(screenPos, 3f, 0xFF0000FF); + ImGui.GetWindowDrawList().AddText(screenPos + new Vector2(10, -8), 0xFF0000FF, + $"{i}: {step.InteractionType}\n{step.Position.Value.ToString("G", CultureInfo.InvariantCulture)}\n{step.Comment}"); + } + } +} diff --git a/Questionable/Windows/DebugWindow.cs b/Questionable/Windows/DebugWindow.cs deleted file mode 100644 index 7cc3f977..00000000 --- a/Questionable/Windows/DebugWindow.cs +++ /dev/null @@ -1,360 +0,0 @@ -using System; -using System.Diagnostics; -using System.Globalization; -using System.Linq; -using System.Numerics; -using Dalamud.Game.ClientState.Objects; -using Dalamud.Interface; -using Dalamud.Interface.Colors; -using Dalamud.Interface.Components; -using Dalamud.Plugin; -using Dalamud.Plugin.Services; -using FFXIVClientStructs.FFXIV.Client.Game; -using FFXIVClientStructs.FFXIV.Client.Game.Control; -using FFXIVClientStructs.FFXIV.Client.Game.Object; -using FFXIVClientStructs.FFXIV.Client.UI.Agent; -using ImGuiNET; -using LLib.ImGui; -using Microsoft.Extensions.Logging; -using Questionable.Controller; -using Questionable.Controller.Steps.BaseFactory; -using Questionable.External; -using Questionable.Model; -using Questionable.Model.V1; - -namespace Questionable.Windows; - -internal sealed class DebugWindow : LWindow, IPersistableWindowConfig -{ - private readonly DalamudPluginInterface _pluginInterface; - private readonly MovementController _movementController; - private readonly QuestController _questController; - private readonly GameFunctions _gameFunctions; - private readonly IClientState _clientState; - private readonly IFramework _framework; - private readonly ITargetManager _targetManager; - private readonly GameUiController _gameUiController; - private readonly Configuration _configuration; - private readonly NavmeshIpc _navmeshIpc; - private readonly ILogger _logger; - - public DebugWindow(DalamudPluginInterface pluginInterface, - MovementController movementController, - QuestController questController, - GameFunctions gameFunctions, - IClientState clientState, - IFramework framework, - ITargetManager targetManager, - GameUiController gameUiController, - Configuration configuration, - NavmeshIpc navmeshIpc, - ILogger logger) - : base("Questionable", ImGuiWindowFlags.AlwaysAutoResize) - { - _pluginInterface = pluginInterface; - _movementController = movementController; - _questController = questController; - _gameFunctions = gameFunctions; - _clientState = clientState; - _framework = framework; - _targetManager = targetManager; - _gameUiController = gameUiController; - _configuration = configuration; - _navmeshIpc = navmeshIpc; - _logger = logger; - -#if DEBUG - IsOpen = true; -#endif - SizeConstraints = new WindowSizeConstraints - { - MinimumSize = new Vector2(200, 30), - MaximumSize = default - }; - RespectCloseHotkey = false; - } - - public WindowConfig WindowConfig => _configuration.DebugWindowConfig; - - public void SaveWindowConfig() => _pluginInterface.SavePluginConfig(_configuration); - - public override bool DrawConditions() - { - if (!_clientState.IsLoggedIn || _clientState.LocalPlayer == null) - return false; - - var currentQuest = _questController.CurrentQuest; - return currentQuest == null || !currentQuest.Quest.Data.TerritoryBlacklist.Contains(_clientState.TerritoryType); - } - - public override void Draw() - { - DrawQuest(); - ImGui.Separator(); - - DrawCreationUtils(); - ImGui.Separator(); - - DrawQuickAccessButtons(); - DrawRemainingTasks(); - } - - private unsafe void DrawQuest() - { - var currentQuest = _questController.CurrentQuest; - if (currentQuest != null) - { - ImGui.TextUnformatted($"Quest: {currentQuest.Quest.Name} / {currentQuest.Sequence} / {currentQuest.Step}"); - - ImGui.BeginDisabled(); - var questWork = _gameFunctions.GetQuestEx(currentQuest.Quest.QuestId); - if (questWork != null) - { - var qw = questWork.Value; - string vars = ""; - for (int i = 0; i < 6; ++i) - { - vars += qw.Variables[i] + " "; - if (i % 2 == 1) - vars += " "; - } - - // For combat quests, a sequence to kill 3 enemies works a bit like this: - // Trigger enemies → 0 - // Kill first enemy → 1 - // Kill second enemy → 2 - // Last enemy → increase sequence, reset variable to 0 - // The order in which enemies are killed doesn't seem to matter. - // If multiple waves spawn, this continues to count up (e.g. 1 enemy from wave 1, 2 enemies from wave 2, 1 from wave 3) would count to 3 then 0 - ImGui.Text($"QW: {vars.Trim()}"); - } - else - ImGui.TextUnformatted("(Not accepted)"); - - ImGui.TextUnformatted(_questController.DebugState ?? "--"); - ImGui.EndDisabled(); - ImGui.TextUnformatted(_questController.Comment ?? "--"); - - //var nextStep = _questController.GetNextStep(); - //ImGui.BeginDisabled(nextStep.Step == null); - ImGui.Text(_questController.ToStatString()); - //ImGui.EndDisabled(); - - ImGui.BeginDisabled(_questController.IsRunning); - if (ImGuiComponents.IconButton(FontAwesomeIcon.Play)) - { - _questController.ExecuteNextStep(true); - } - - ImGui.SameLine(); - - if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.StepForward, "Step")) - { - _questController.ExecuteNextStep(false); - } - - ImGui.EndDisabled(); - ImGui.SameLine(); - - if (ImGuiComponents.IconButton(FontAwesomeIcon.Stop)) - { - _movementController.Stop(); - _questController.Stop("Manual"); - } - - QuestStep? currentStep = currentQuest.Quest - .FindSequence(currentQuest.Sequence) - ?.FindStep(currentQuest.Step); - bool lastStep = currentStep == - currentQuest.Quest.FindSequence(currentQuest.Sequence)?.Steps.LastOrDefault(); - bool colored = currentStep != null - && !lastStep - && currentStep.InteractionType == EInteractionType.Instruction - && _questController.HasCurrentTaskMatching(); - - ImGui.BeginDisabled(lastStep); - if (colored) - ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.HealerGreen); - if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.ArrowCircleRight, "Skip")) - { - _movementController.Stop(); - _questController.Skip(currentQuest.Quest.QuestId, currentQuest.Sequence); - } - - if (colored) - ImGui.PopStyleColor(); - ImGui.EndDisabled(); - - bool autoAcceptNextQuest = _configuration.General.AutoAcceptNextQuest; - if (ImGui.Checkbox("Automatically accept next quest", ref autoAcceptNextQuest)) - { - _configuration.General.AutoAcceptNextQuest = autoAcceptNextQuest; - _pluginInterface.SavePluginConfig(_configuration); - } - } - else - ImGui.Text("No active quest"); - } - - private unsafe void DrawCreationUtils() - { - Debug.Assert(_clientState.LocalPlayer != null, "_clientState.LocalPlayer != null"); - - ImGui.Text( - $"Current TerritoryId: {_clientState.TerritoryType}, Flying: {(_gameFunctions.IsFlyingUnlockedInCurrentZone() ? "Yes" : "No")}"); - - var q = _gameFunctions.GetCurrentQuest(); - ImGui.Text($"Current Quest: {q.CurrentQuest} → {q.Sequence}"); - - var questManager = QuestManager.Instance(); - if (questManager != null) - { - // unsure how these are sorted - for (int i = 0; i < 1 /*questManager->TrackedQuestsSpan.Length*/; ++i) - { - var trackedQuest = questManager->TrackedQuestsSpan[i]; - switch (trackedQuest.QuestType) - { - default: - ImGui.Text($"Tracked quest {i}: {trackedQuest.QuestType}, {trackedQuest.Index}"); - break; - - case 1: - ImGui.Text( - $"Tracked quest: {questManager->NormalQuestsSpan[trackedQuest.Index].QuestId}, {trackedQuest.Index}"); - break; - } - } - } - - - if (_targetManager.Target != null) - { - ImGui.Separator(); - ImGui.Text(string.Create(CultureInfo.InvariantCulture, - $"Target: {_targetManager.Target.Name} ({_targetManager.Target.ObjectKind}; {_targetManager.Target.DataId})")); - - GameObject* gameObject = (GameObject*)_targetManager.Target.Address; - ImGui.Text(string.Create(CultureInfo.InvariantCulture, - $"Distance: {(_targetManager.Target.Position - _clientState.LocalPlayer.Position).Length():F2}, Y: {_targetManager.Target.Position.Y - _clientState.LocalPlayer.Position.Y:F2} | QM: {gameObject->NamePlateIconId}")); - - ImGui.BeginDisabled(!_movementController.IsNavmeshReady); - if (!_movementController.IsPathfinding) - { - if (ImGui.Button("Move to Target")) - { - _movementController.NavigateTo(EMovementType.DebugWindow, _targetManager.Target.DataId, - _targetManager.Target.Position, _gameFunctions.IsFlyingUnlockedInCurrentZone(), - true); - } - } - else - { - if (ImGui.Button("Cancel pathfinding")) - _movementController.ResetPathfinding(); - } - - ImGui.EndDisabled(); - - ImGui.SameLine(); - if (ImGui.Button("Interact")) - { - ulong result = TargetSystem.Instance()->InteractWithObject( - (GameObject*)_targetManager.Target.Address, false); - _logger.LogInformation("XXXXX Interaction Result: {Result}", result); - } - - ImGui.SameLine(); - - ImGui.Button("Copy"); - if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) - { - ImGui.SetClipboardText($$""" - "DataId": {{_targetManager.Target.DataId}}, - "Position": { - "X": {{_targetManager.Target.Position.X.ToString(CultureInfo.InvariantCulture)}}, - "Y": {{_targetManager.Target.Position.Y.ToString(CultureInfo.InvariantCulture)}}, - "Z": {{_targetManager.Target.Position.Z.ToString(CultureInfo.InvariantCulture)}} - }, - "TerritoryId": {{_clientState.TerritoryType}}, - "InteractionType": "Interact" - """); - } - else if (ImGui.IsItemClicked(ImGuiMouseButton.Right)) - { - EAetheryteLocation location = (EAetheryteLocation)_targetManager.Target.DataId; - ImGui.SetClipboardText(string.Create(CultureInfo.InvariantCulture, - $"{{EAetheryteLocation.{location}, new({_targetManager.Target.Position.X}f, {_targetManager.Target.Position.Y}f, {_targetManager.Target.Position.Z}f)}},")); - } - } - else - { - ImGui.Button($"Copy"); - if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) - { - ImGui.SetClipboardText($$""" - "Position": { - "X": {{_clientState.LocalPlayer.Position.X.ToString(CultureInfo.InvariantCulture)}}, - "Y": {{_clientState.LocalPlayer.Position.Y.ToString(CultureInfo.InvariantCulture)}}, - "Z": {{_clientState.LocalPlayer.Position.Z.ToString(CultureInfo.InvariantCulture)}} - }, - "TerritoryId": {{_clientState.TerritoryType}}, - "InteractionType": "" - """); - } - else if (ImGui.IsItemClicked(ImGuiMouseButton.Right)) - { - Vector3 position = _clientState.LocalPlayer!.Position; - ImGui.SetClipboardText(string.Create(CultureInfo.InvariantCulture, - $"new({position.X}f, {position.Y}f, {position.Z}f)")); - } - } - } - - private unsafe void DrawQuickAccessButtons() - { - var map = AgentMap.Instance(); - ImGui.BeginDisabled(map == null || map->IsFlagMarkerSet == 0 || - map->FlagMapMarker.TerritoryId != _clientState.TerritoryType || - !_navmeshIpc.IsReady); - if (ImGui.Button("Move to Flag")) - { - _movementController.Destination = null; - _gameFunctions.ExecuteCommand( - $"/vnav {(_gameFunctions.IsFlyingUnlockedInCurrentZone() ? "flyflag" : "moveflag")}"); - } - - ImGui.EndDisabled(); - - ImGui.SameLine(); - - ImGui.BeginDisabled(!_movementController.IsPathRunning); - if (ImGui.Button("Stop Nav")) - { - _movementController.Stop(); - _questController.Stop("Manual"); - } - - ImGui.EndDisabled(); - - if (ImGui.Button("Reload Data")) - { - _questController.Reload(); - _framework.RunOnTick(() => _gameUiController.HandleCurrentDialogueChoices(), - TimeSpan.FromMilliseconds(200)); - } - } - - private void DrawRemainingTasks() - { - var remainingTasks = _questController.GetRemainingTaskNames(); - if (remainingTasks.Count > 0) - { - ImGui.Separator(); - ImGui.BeginDisabled(); - foreach (var task in remainingTasks) - ImGui.TextUnformatted(task); - ImGui.EndDisabled(); - } - } -} diff --git a/Questionable/Windows/QuestWindow.cs b/Questionable/Windows/QuestWindow.cs new file mode 100644 index 00000000..11672649 --- /dev/null +++ b/Questionable/Windows/QuestWindow.cs @@ -0,0 +1,360 @@ +using System; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Numerics; +using Dalamud.Game.ClientState.Objects; +using Dalamud.Interface; +using Dalamud.Interface.Colors; +using Dalamud.Interface.Components; +using Dalamud.Plugin; +using Dalamud.Plugin.Services; +using FFXIVClientStructs.FFXIV.Client.Game; +using FFXIVClientStructs.FFXIV.Client.Game.Control; +using FFXIVClientStructs.FFXIV.Client.Game.Object; +using FFXIVClientStructs.FFXIV.Client.UI.Agent; +using ImGuiNET; +using LLib.ImGui; +using Microsoft.Extensions.Logging; +using Questionable.Controller; +using Questionable.Controller.Steps.BaseFactory; +using Questionable.External; +using Questionable.Model; +using Questionable.Model.V1; + +namespace Questionable.Windows; + +internal sealed class QuestWindow : LWindow, IPersistableWindowConfig +{ + private readonly DalamudPluginInterface _pluginInterface; + private readonly MovementController _movementController; + private readonly QuestController _questController; + private readonly GameFunctions _gameFunctions; + private readonly IClientState _clientState; + private readonly IFramework _framework; + private readonly ITargetManager _targetManager; + private readonly GameUiController _gameUiController; + private readonly Configuration _configuration; + private readonly NavmeshIpc _navmeshIpc; + private readonly ILogger _logger; + + public QuestWindow(DalamudPluginInterface pluginInterface, + MovementController movementController, + QuestController questController, + GameFunctions gameFunctions, + IClientState clientState, + IFramework framework, + ITargetManager targetManager, + GameUiController gameUiController, + Configuration configuration, + NavmeshIpc navmeshIpc, + ILogger logger) + : base("Questionable###Questionable", ImGuiWindowFlags.AlwaysAutoResize) + { + _pluginInterface = pluginInterface; + _movementController = movementController; + _questController = questController; + _gameFunctions = gameFunctions; + _clientState = clientState; + _framework = framework; + _targetManager = targetManager; + _gameUiController = gameUiController; + _configuration = configuration; + _navmeshIpc = navmeshIpc; + _logger = logger; + +#if DEBUG + IsOpen = true; +#endif + SizeConstraints = new WindowSizeConstraints + { + MinimumSize = new Vector2(200, 30), + MaximumSize = default + }; + RespectCloseHotkey = false; + } + + public WindowConfig WindowConfig => _configuration.DebugWindowConfig; + + public void SaveWindowConfig() => _pluginInterface.SavePluginConfig(_configuration); + + public override bool DrawConditions() + { + if (!_clientState.IsLoggedIn || _clientState.LocalPlayer == null) + return false; + + var currentQuest = _questController.CurrentQuest; + return currentQuest == null || !currentQuest.Quest.Data.TerritoryBlacklist.Contains(_clientState.TerritoryType); + } + + public override void Draw() + { + DrawQuest(); + ImGui.Separator(); + + DrawCreationUtils(); + ImGui.Separator(); + + DrawQuickAccessButtons(); + DrawRemainingTasks(); + } + + private unsafe void DrawQuest() + { + var currentQuest = _questController.CurrentQuest; + if (currentQuest != null) + { + ImGui.TextUnformatted($"Quest: {currentQuest.Quest.Name} / {currentQuest.Sequence} / {currentQuest.Step}"); + + ImGui.BeginDisabled(); + var questWork = _gameFunctions.GetQuestEx(currentQuest.Quest.QuestId); + if (questWork != null) + { + var qw = questWork.Value; + string vars = ""; + for (int i = 0; i < 6; ++i) + { + vars += qw.Variables[i] + " "; + if (i % 2 == 1) + vars += " "; + } + + // For combat quests, a sequence to kill 3 enemies works a bit like this: + // Trigger enemies → 0 + // Kill first enemy → 1 + // Kill second enemy → 2 + // Last enemy → increase sequence, reset variable to 0 + // The order in which enemies are killed doesn't seem to matter. + // If multiple waves spawn, this continues to count up (e.g. 1 enemy from wave 1, 2 enemies from wave 2, 1 from wave 3) would count to 3 then 0 + ImGui.Text($"QW: {vars.Trim()}"); + } + else + ImGui.TextUnformatted("(Not accepted)"); + + ImGui.TextUnformatted(_questController.DebugState ?? "--"); + ImGui.EndDisabled(); + ImGui.TextUnformatted(_questController.Comment ?? "--"); + + //var nextStep = _questController.GetNextStep(); + //ImGui.BeginDisabled(nextStep.Step == null); + ImGui.Text(_questController.ToStatString()); + //ImGui.EndDisabled(); + + ImGui.BeginDisabled(_questController.IsRunning); + if (ImGuiComponents.IconButton(FontAwesomeIcon.Play)) + { + _questController.ExecuteNextStep(true); + } + + ImGui.SameLine(); + + if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.StepForward, "Step")) + { + _questController.ExecuteNextStep(false); + } + + ImGui.EndDisabled(); + ImGui.SameLine(); + + if (ImGuiComponents.IconButton(FontAwesomeIcon.Stop)) + { + _movementController.Stop(); + _questController.Stop("Manual"); + } + + QuestStep? currentStep = currentQuest.Quest + .FindSequence(currentQuest.Sequence) + ?.FindStep(currentQuest.Step); + bool lastStep = currentStep == + currentQuest.Quest.FindSequence(currentQuest.Sequence)?.Steps.LastOrDefault(); + bool colored = currentStep != null + && !lastStep + && currentStep.InteractionType == EInteractionType.Instruction + && _questController.HasCurrentTaskMatching(); + + ImGui.BeginDisabled(lastStep); + if (colored) + ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.HealerGreen); + if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.ArrowCircleRight, "Skip")) + { + _movementController.Stop(); + _questController.Skip(currentQuest.Quest.QuestId, currentQuest.Sequence); + } + + if (colored) + ImGui.PopStyleColor(); + ImGui.EndDisabled(); + + bool autoAcceptNextQuest = _configuration.General.AutoAcceptNextQuest; + if (ImGui.Checkbox("Automatically accept next quest", ref autoAcceptNextQuest)) + { + _configuration.General.AutoAcceptNextQuest = autoAcceptNextQuest; + _pluginInterface.SavePluginConfig(_configuration); + } + } + else + ImGui.Text("No active quest"); + } + + private unsafe void DrawCreationUtils() + { + Debug.Assert(_clientState.LocalPlayer != null, "_clientState.LocalPlayer != null"); + + ImGui.Text( + $"Current TerritoryId: {_clientState.TerritoryType}, Flying: {(_gameFunctions.IsFlyingUnlockedInCurrentZone() ? "Yes" : "No")}"); + + var q = _gameFunctions.GetCurrentQuest(); + ImGui.Text($"Current Quest: {q.CurrentQuest} → {q.Sequence}"); + + var questManager = QuestManager.Instance(); + if (questManager != null) + { + // unsure how these are sorted + for (int i = 0; i < 1 /*questManager->TrackedQuestsSpan.Length*/; ++i) + { + var trackedQuest = questManager->TrackedQuestsSpan[i]; + switch (trackedQuest.QuestType) + { + default: + ImGui.Text($"Tracked quest {i}: {trackedQuest.QuestType}, {trackedQuest.Index}"); + break; + + case 1: + ImGui.Text( + $"Tracked quest: {questManager->NormalQuestsSpan[trackedQuest.Index].QuestId}, {trackedQuest.Index}"); + break; + } + } + } + + + if (_targetManager.Target != null) + { + ImGui.Separator(); + ImGui.Text(string.Create(CultureInfo.InvariantCulture, + $"Target: {_targetManager.Target.Name} ({_targetManager.Target.ObjectKind}; {_targetManager.Target.DataId})")); + + GameObject* gameObject = (GameObject*)_targetManager.Target.Address; + ImGui.Text(string.Create(CultureInfo.InvariantCulture, + $"Distance: {(_targetManager.Target.Position - _clientState.LocalPlayer.Position).Length():F2}, Y: {_targetManager.Target.Position.Y - _clientState.LocalPlayer.Position.Y:F2} | QM: {gameObject->NamePlateIconId}")); + + ImGui.BeginDisabled(!_movementController.IsNavmeshReady); + if (!_movementController.IsPathfinding) + { + if (ImGui.Button("Move to Target")) + { + _movementController.NavigateTo(EMovementType.DebugWindow, _targetManager.Target.DataId, + _targetManager.Target.Position, _gameFunctions.IsFlyingUnlockedInCurrentZone(), + true); + } + } + else + { + if (ImGui.Button("Cancel pathfinding")) + _movementController.ResetPathfinding(); + } + + ImGui.EndDisabled(); + + ImGui.SameLine(); + if (ImGui.Button("Interact")) + { + ulong result = TargetSystem.Instance()->InteractWithObject( + (GameObject*)_targetManager.Target.Address, false); + _logger.LogInformation("XXXXX Interaction Result: {Result}", result); + } + + ImGui.SameLine(); + + ImGui.Button("Copy"); + if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) + { + ImGui.SetClipboardText($$""" + "DataId": {{_targetManager.Target.DataId}}, + "Position": { + "X": {{_targetManager.Target.Position.X.ToString(CultureInfo.InvariantCulture)}}, + "Y": {{_targetManager.Target.Position.Y.ToString(CultureInfo.InvariantCulture)}}, + "Z": {{_targetManager.Target.Position.Z.ToString(CultureInfo.InvariantCulture)}} + }, + "TerritoryId": {{_clientState.TerritoryType}}, + "InteractionType": "Interact" + """); + } + else if (ImGui.IsItemClicked(ImGuiMouseButton.Right)) + { + EAetheryteLocation location = (EAetheryteLocation)_targetManager.Target.DataId; + ImGui.SetClipboardText(string.Create(CultureInfo.InvariantCulture, + $"{{EAetheryteLocation.{location}, new({_targetManager.Target.Position.X}f, {_targetManager.Target.Position.Y}f, {_targetManager.Target.Position.Z}f)}},")); + } + } + else + { + ImGui.Button($"Copy"); + if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) + { + ImGui.SetClipboardText($$""" + "Position": { + "X": {{_clientState.LocalPlayer.Position.X.ToString(CultureInfo.InvariantCulture)}}, + "Y": {{_clientState.LocalPlayer.Position.Y.ToString(CultureInfo.InvariantCulture)}}, + "Z": {{_clientState.LocalPlayer.Position.Z.ToString(CultureInfo.InvariantCulture)}} + }, + "TerritoryId": {{_clientState.TerritoryType}}, + "InteractionType": "" + """); + } + else if (ImGui.IsItemClicked(ImGuiMouseButton.Right)) + { + Vector3 position = _clientState.LocalPlayer!.Position; + ImGui.SetClipboardText(string.Create(CultureInfo.InvariantCulture, + $"new({position.X}f, {position.Y}f, {position.Z}f)")); + } + } + } + + private unsafe void DrawQuickAccessButtons() + { + var map = AgentMap.Instance(); + ImGui.BeginDisabled(map == null || map->IsFlagMarkerSet == 0 || + map->FlagMapMarker.TerritoryId != _clientState.TerritoryType || + !_navmeshIpc.IsReady); + if (ImGui.Button("Move to Flag")) + { + _movementController.Destination = null; + _gameFunctions.ExecuteCommand( + $"/vnav {(_gameFunctions.IsFlyingUnlockedInCurrentZone() ? "flyflag" : "moveflag")}"); + } + + ImGui.EndDisabled(); + + ImGui.SameLine(); + + ImGui.BeginDisabled(!_movementController.IsPathRunning); + if (ImGui.Button("Stop Nav")) + { + _movementController.Stop(); + _questController.Stop("Manual"); + } + + ImGui.EndDisabled(); + + if (ImGui.Button("Reload Data")) + { + _questController.Reload(); + _framework.RunOnTick(() => _gameUiController.HandleCurrentDialogueChoices(), + TimeSpan.FromMilliseconds(200)); + } + } + + private void DrawRemainingTasks() + { + var remainingTasks = _questController.GetRemainingTaskNames(); + if (remainingTasks.Count > 0) + { + ImGui.Separator(); + ImGui.BeginDisabled(); + foreach (var task in remainingTasks) + ImGui.TextUnformatted(task); + ImGui.EndDisabled(); + } + } +}