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 internal sealed class Configuration : IPluginConfiguration
{ {
public const int PluginSetupVersion = 1;
public int Version { get; set; } = 1; public int Version { get; set; } = 1;
public int PluginSetupCompleteVersion { get; set; }
public GeneralConfiguration General { get; } = new(); public GeneralConfiguration General { get; } = new();
public AdvancedConfiguration Advanced { get; } = new(); public AdvancedConfiguration Advanced { get; } = new();
public WindowConfig DebugWindowConfig { get; } = new(); public WindowConfig DebugWindowConfig { get; } = new();
public WindowConfig ConfigWindowConfig { get; } = new(); public WindowConfig ConfigWindowConfig { get; } = new();
internal bool IsPluginSetupComplete() => PluginSetupCompleteVersion == PluginSetupVersion;
internal void MarkPluginSetupComplete() => PluginSetupCompleteVersion = PluginSetupVersion;
internal sealed class GeneralConfiguration internal sealed class GeneralConfiguration
{ {
public uint MountId { get; set; } = 71; public uint MountId { get; set; } = 71;

View File

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

View File

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

View File

@ -6,6 +6,7 @@ using Dalamud.Game.ClientState.Objects;
using Dalamud.Interface.Windowing; using Dalamud.Interface.Windowing;
using Dalamud.Plugin; using Dalamud.Plugin;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using LLib;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Questionable.Controller; using Questionable.Controller;
@ -110,6 +111,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin
serviceCollection.AddSingleton<GameFunctions>(); serviceCollection.AddSingleton<GameFunctions>();
serviceCollection.AddSingleton<ChatFunctions>(); serviceCollection.AddSingleton<ChatFunctions>();
serviceCollection.AddSingleton<QuestFunctions>(); serviceCollection.AddSingleton<QuestFunctions>();
serviceCollection.AddSingleton<DalamudReflector>();
serviceCollection.AddSingleton<AutoSnipeHandler>(); serviceCollection.AddSingleton<AutoSnipeHandler>();
serviceCollection.AddSingleton<AetherCurrentData>(); serviceCollection.AddSingleton<AetherCurrentData>();
@ -255,6 +257,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin
serviceCollection.AddSingleton<QuestJournalComponent>(); serviceCollection.AddSingleton<QuestJournalComponent>();
serviceCollection.AddSingleton<GatheringJournalComponent>(); serviceCollection.AddSingleton<GatheringJournalComponent>();
serviceCollection.AddSingleton<OneTimeSetupWindow>();
serviceCollection.AddSingleton<QuestWindow>(); serviceCollection.AddSingleton<QuestWindow>();
serviceCollection.AddSingleton<ConfigWindow>(); serviceCollection.AddSingleton<ConfigWindow>();
serviceCollection.AddSingleton<DebugOverlay>(); 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() public override bool DrawConditions()
{ {
if (!_configuration.IsPluginSetupComplete())
return false;
if (!_clientState.IsLoggedIn || _clientState.LocalPlayer == null || _clientState.IsPvPExcludingDen) if (!_clientState.IsLoggedIn || _clientState.LocalPlayer == null || _clientState.IsPvPExcludingDen)
return false; return false;