Add plugin setup window

This commit is contained in:
Liza 2024-11-03 19:25:33 +01:00
parent ad76bb88c0
commit bd38b330ed
Signed by: liza
GPG Key ID: 7199F8D727D55F67
7 changed files with 211 additions and 4 deletions

2
LLib

@ -1 +1 @@
Subproject commit 6dfc18ee6a187138036ee2d51ba2257741c1e568
Subproject commit 912a7b04ce180e337af9beeef2d1393b040c1ba8

View File

@ -6,12 +6,19 @@ namespace Questionable;
internal sealed class Configuration : IPluginConfiguration
{
public const int PluginSetupVersion = 1;
public int Version { get; set; } = 1;
public int PluginSetupCompleteVersion { get; set; }
public GeneralConfiguration General { get; } = new();
public AdvancedConfiguration Advanced { get; } = new();
public WindowConfig DebugWindowConfig { get; } = new();
public WindowConfig ConfigWindowConfig { get; } = new();
internal bool IsPluginSetupComplete() => PluginSetupCompleteVersion == PluginSetupVersion;
internal void MarkPluginSetupComplete() => PluginSetupCompleteVersion = PluginSetupVersion;
internal sealed class GeneralConfiguration
{
public uint MountId { get; set; } = 71;

View File

@ -24,12 +24,14 @@ internal sealed class CommandHandler : IDisposable
private readonly QuestRegistry _questRegistry;
private readonly ConfigWindow _configWindow;
private readonly DebugOverlay _debugOverlay;
private readonly OneTimeSetupWindow _oneTimeSetupWindow;
private readonly QuestWindow _questWindow;
private readonly QuestSelectionWindow _questSelectionWindow;
private readonly ITargetManager _targetManager;
private readonly QuestFunctions _questFunctions;
private readonly GameFunctions _gameFunctions;
private readonly IDataManager _dataManager;
private readonly Configuration _configuration;
public CommandHandler(
ICommandManager commandManager,
@ -39,12 +41,14 @@ internal sealed class CommandHandler : IDisposable
QuestRegistry questRegistry,
ConfigWindow configWindow,
DebugOverlay debugOverlay,
OneTimeSetupWindow oneTimeSetupWindow,
QuestWindow questWindow,
QuestSelectionWindow questSelectionWindow,
ITargetManager targetManager,
QuestFunctions questFunctions,
GameFunctions gameFunctions,
IDataManager dataManager)
IDataManager dataManager,
Configuration configuration)
{
_commandManager = commandManager;
_chatGui = chatGui;
@ -53,12 +57,14 @@ internal sealed class CommandHandler : IDisposable
_questRegistry = questRegistry;
_configWindow = configWindow;
_debugOverlay = debugOverlay;
_oneTimeSetupWindow = oneTimeSetupWindow;
_questWindow = questWindow;
_questSelectionWindow = questSelectionWindow;
_targetManager = targetManager;
_questFunctions = questFunctions;
_gameFunctions = gameFunctions;
_dataManager = dataManager;
_configuration = configuration;
_commandManager.AddHandler("/qst", new CommandInfo(ProcessCommand)
{
@ -75,6 +81,15 @@ internal sealed class CommandHandler : IDisposable
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);
return;
}
string[] parts = arguments.Split(' ');
switch (parts[0])
{

View File

@ -18,9 +18,11 @@ internal sealed class DalamudInitializer : IDisposable
private readonly QuestController _questController;
private readonly MovementController _movementController;
private readonly WindowSystem _windowSystem;
private readonly OneTimeSetupWindow _oneTimeSetupWindow;
private readonly QuestWindow _questWindow;
private readonly ConfigWindow _configWindow;
private readonly IToastGui _toastGui;
private readonly Configuration _configuration;
private readonly ILogger<DalamudInitializer> _logger;
public DalamudInitializer(
@ -30,6 +32,7 @@ internal sealed class DalamudInitializer : IDisposable
MovementController movementController,
InteractionUiController interactionUiController,
WindowSystem windowSystem,
OneTimeSetupWindow oneTimeSetupWindow,
QuestWindow questWindow,
DebugOverlay debugOverlay,
ConfigWindow configWindow,
@ -38,6 +41,7 @@ internal sealed class DalamudInitializer : IDisposable
JournalProgressWindow journalProgressWindow,
PriorityWindow priorityWindow,
IToastGui toastGui,
Configuration configuration,
ILogger<DalamudInitializer> logger)
{
_pluginInterface = pluginInterface;
@ -45,11 +49,14 @@ internal sealed class DalamudInitializer : IDisposable
_questController = questController;
_movementController = movementController;
_windowSystem = windowSystem;
_oneTimeSetupWindow = oneTimeSetupWindow;
_questWindow = questWindow;
_configWindow = configWindow;
_toastGui = toastGui;
_configuration = configuration;
_logger = logger;
_windowSystem.AddWindow(oneTimeSetupWindow);
_windowSystem.AddWindow(questWindow);
_windowSystem.AddWindow(configWindow);
_windowSystem.AddWindow(debugOverlay);
@ -59,7 +66,7 @@ internal sealed class DalamudInitializer : IDisposable
_windowSystem.AddWindow(priorityWindow);
_pluginInterface.UiBuilder.Draw += _windowSystem.Draw;
_pluginInterface.UiBuilder.OpenMainUi += _questWindow.Toggle;
_pluginInterface.UiBuilder.OpenMainUi += ToggleQuestWindow;
_pluginInterface.UiBuilder.OpenConfigUi += _configWindow.Toggle;
_framework.Update += FrameworkUpdate;
_framework.RunOnTick(interactionUiController.HandleCurrentDialogueChoices, TimeSpan.FromMilliseconds(200));
@ -91,6 +98,14 @@ internal sealed class DalamudInitializer : IDisposable
private void OnQuestToast(ref SeString message, ref QuestToastOptions options, ref bool isHandled)
=> _logger.LogTrace("Quest Toast: {Message}", message);
private void ToggleQuestWindow()
{
if (_configuration.IsPluginSetupComplete())
_questWindow.Toggle();
else
_oneTimeSetupWindow.IsOpen = true;
}
public void Dispose()
{
_toastGui.QuestToast -= OnQuestToast;
@ -98,7 +113,7 @@ internal sealed class DalamudInitializer : IDisposable
_toastGui.Toast -= OnToast;
_framework.Update -= FrameworkUpdate;
_pluginInterface.UiBuilder.OpenConfigUi -= _configWindow.Toggle;
_pluginInterface.UiBuilder.OpenMainUi -= _questWindow.Toggle;
_pluginInterface.UiBuilder.OpenMainUi -= ToggleQuestWindow;
_pluginInterface.UiBuilder.Draw -= _windowSystem.Draw;
_windowSystem.RemoveAllWindows();

View File

@ -6,6 +6,7 @@ using Dalamud.Game.ClientState.Objects;
using Dalamud.Interface.Windowing;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
using LLib;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Questionable.Controller;
@ -110,6 +111,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin
serviceCollection.AddSingleton<GameFunctions>();
serviceCollection.AddSingleton<ChatFunctions>();
serviceCollection.AddSingleton<QuestFunctions>();
serviceCollection.AddSingleton<DalamudReflector>();
serviceCollection.AddSingleton<AutoSnipeHandler>();
serviceCollection.AddSingleton<AetherCurrentData>();
@ -255,6 +257,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin
serviceCollection.AddSingleton<QuestJournalComponent>();
serviceCollection.AddSingleton<GatheringJournalComponent>();
serviceCollection.AddSingleton<OneTimeSetupWindow>();
serviceCollection.AddSingleton<QuestWindow>();
serviceCollection.AddSingleton<ConfigWindow>();
serviceCollection.AddSingleton<DebugOverlay>();

View File

@ -0,0 +1,164 @@
using System;
using System.Collections.Generic;
using Dalamud.Interface;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Components;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Plugin;
using Dalamud.Utility;
using ImGuiNET;
using LLib;
using LLib.ImGui;
using Microsoft.Extensions.Logging;
namespace Questionable.Windows;
internal sealed class OneTimeSetupWindow : LWindow, IDisposable
{
private static readonly IReadOnlyList<PluginInfo> RequiredPlugins =
[
new("vnavmesh",
"""
vnavmesh handles the navigation within a zone, moving
your character to the next quest-related objective.
""",
new Uri("https://github.com/awgil/ffxiv_navmesh/")),
new("Lifestream",
"""
Used to travel to aethernet shards in cities.
""",
new Uri("https://github.com/NightmareXIV/Lifestream")),
new("TextAdvance",
"""
Automatically accepts and turns in quests, skips cutscenes
and dialogue.
""",
new Uri("https://github.com/NightmareXIV/TextAdvance")),
];
private static readonly IReadOnlyList<PluginInfo> RecommendedPlugins =
[
new("Rotation Solver Reborn",
"""
Automatically handles most combat interactions you encounter
during quests, including being interrupted by mobs.
""",
new Uri("https://github.com/FFXIV-CombatReborn/RotationSolverReborn")),
];
private readonly Configuration _configuration;
private readonly IDalamudPluginInterface _pluginInterface;
private readonly UiUtils _uiUtils;
private readonly DalamudReflector _dalamudReflector;
private readonly ILogger<OneTimeSetupWindow> _logger;
public OneTimeSetupWindow(Configuration configuration, IDalamudPluginInterface pluginInterface, UiUtils uiUtils,
DalamudReflector dalamudReflector, ILogger<OneTimeSetupWindow> logger)
: base("Questionable Setup###QuestionableOneTimeSetup",
ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoSavedSettings, true)
{
_configuration = configuration;
_pluginInterface = pluginInterface;
_uiUtils = uiUtils;
_dalamudReflector = dalamudReflector;
_logger = logger;
RespectCloseHotkey = false;
ShowCloseButton = false;
AllowPinning = false;
AllowClickthrough = false;
IsOpen = !_configuration.IsPluginSetupComplete();
_logger.LogInformation("One-time setup needed: {IsOpen}", IsOpen);
}
public override void Draw()
{
float checklistPadding;
using (_pluginInterface.UiBuilder.IconFontFixedWidthHandle.Push())
{
checklistPadding = ImGui.CalcTextSize(FontAwesomeIcon.Check.ToIconString()).X +
ImGui.GetStyle().ItemSpacing.X;
}
ImGui.Text("Questionable requires the following plugins to work:");
bool allRequiredInstalled = true;
using (ImRaii.PushIndent())
{
foreach (var plugin in RequiredPlugins)
allRequiredInstalled &= DrawPlugin(plugin, checklistPadding);
}
ImGui.Spacing();
ImGui.Separator();
ImGui.Spacing();
ImGui.Text("The following plugins are recommended, but not required:");
using (ImRaii.PushIndent())
{
foreach (var plugin in RecommendedPlugins)
DrawPlugin(plugin, checklistPadding);
}
ImGui.Spacing();
ImGui.Separator();
ImGui.Spacing();
if (allRequiredInstalled)
{
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.ParsedGreen))
{
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Check, "Finish Setup"))
{
_configuration.MarkPluginSetupComplete();
_pluginInterface.SavePluginConfig(_configuration);
}
}
}
else
{
using (ImRaii.Disabled())
{
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudRed))
ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Check, "Missing required plugins");
}
}
ImGui.SameLine();
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Times, "Close window & don't enable Questionable"))
{
IsOpen = false;
}
}
private bool DrawPlugin(PluginInfo plugin, float checklistPadding)
{
bool isInstalled = IsPluginInstalled(plugin.DisplayName);
using (ImRaii.PushId("plugin_" + plugin.DisplayName))
{
_uiUtils.ChecklistItem(plugin.DisplayName, isInstalled);
using (ImRaii.PushIndent(checklistPadding))
{
ImGui.TextUnformatted(plugin.Details);
if (!isInstalled && ImGui.Button("Open Repository"))
Util.OpenLink(plugin.Uri.ToString());
}
}
return isInstalled;
}
private bool IsPluginInstalled(string internalName)
{
return _dalamudReflector.TryGetDalamudPlugin(internalName, out _, suppressErrors: true, ignoreCache: true);
}
public void Dispose()
{
}
private sealed record PluginInfo(
string DisplayName,
string Details,
Uri Uri);
}

View File

@ -113,6 +113,9 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
public override bool DrawConditions()
{
if (!_configuration.IsPluginSetupComplete())
return false;
if (!_clientState.IsLoggedIn || _clientState.LocalPlayer == null || _clientState.IsPvPExcludingDen)
return false;