From 8ed10a536b785015f861084718810b7af573c34c Mon Sep 17 00:00:00 2001 From: Jon Kazama Date: Fri, 15 May 2026 00:28:18 +0200 Subject: [PATCH] refactor(plugin): centralise slash-command registration for lazy-window readiness (v1.4.9 R1 stage 1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pull the four user-triggered slash-commands (/hellion, /hellionView, /hellionDebugger, /hellionSeString) plus the two Plugin-Manager UiBuilder hooks (OpenConfigUi, OpenMainUi) out of their window constructors and into a central Plugin.SetupCommands method so they work before their target window has been opened the first time. A matching TearDownCommands runs as the first CaptureFailure inside the framework-thread teardown lambda. /hellion and /hellionSeString stay under the same #if DEBUG guard SeStringDebugger had before. The four window classes keep their public Dispose method signatures so the existing Plugin.DisposeAsync method-group binding still resolves — the bodies are now empty pointers to TearDownCommands. The pre-v1.4.9 `OpenMainUi` body that flipped SettingsWindow.IsOpen and the three private Toggle(string, string) method-group wrappers are gone since the central handlers call SettingsWindow.Toggle() / DbViewer.Toggle() etc. directly. The properties stay eager in stage 1 — the lazy-init switch lands in stage 2 with the matching `_lazyWindowLock` guard around AddWindow and RemoveAllWindows. Doing it in two commits keeps the slash-command correctness verifiable on its own. Smoke (release build): /hellion, /hellionView, /hellionDebugger, /clearhellion plus Plugin-Manager Settings and Open buttons all toggle their target window. /hellionSeString remains DEBUG-only as before. --- HellionChat/Plugin.cs | 86 ++++++++++++++++++++++++++++-- HellionChat/Ui/DbViewer.cs | 18 +------ HellionChat/Ui/Debugger.cs | 6 +-- HellionChat/Ui/SeStringDebugger.cs | 10 +--- HellionChat/Ui/Settings.cs | 14 +---- 5 files changed, 86 insertions(+), 48 deletions(-) diff --git a/HellionChat/Plugin.cs b/HellionChat/Plugin.cs index 1006267..8049444 100755 --- a/HellionChat/Plugin.cs +++ b/HellionChat/Plugin.cs @@ -289,6 +289,12 @@ public sealed class Plugin : IAsyncDalamudPlugin cancellationToken.ThrowIfCancellationRequested(); + // Populate the command dictionary + UiBuilder hooks BEFORE + // Commands.Initialise() walks the dictionary and registers each + // entry with Dalamud's CommandManager (Commands.cs:15-28). Adding + // wrappers after Initialise() would leak them — they'd live in + // the dictionary but never reach Dalamud. + SetupCommands(); Commands.Initialise(); // Daily retention sweep — fire-and-forget, skips when disabled @@ -424,7 +430,6 @@ public sealed class Plugin : IAsyncDalamudPlugin Framework.Update += FrameworkUpdate; Interface.UiBuilder.Draw += Draw; Interface.LanguageChanged += LanguageChanged; - Interface.UiBuilder.OpenMainUi += OpenMainUi; } catch { @@ -455,7 +460,6 @@ public sealed class Plugin : IAsyncDalamudPlugin Exception? failure = null; // Unsubscribe hooks first — mirrors the hooks-last subscribe order in LoadAsync. - failure = CaptureFailure(failure, () => Interface.UiBuilder.OpenMainUi -= OpenMainUi); failure = CaptureFailure(failure, () => Interface.LanguageChanged -= LanguageChanged); failure = CaptureFailure(failure, () => Interface.UiBuilder.Draw -= Draw); failure = CaptureFailure(failure, () => Framework.Update -= FrameworkUpdate); @@ -505,6 +509,11 @@ public sealed class Plugin : IAsyncDalamudPlugin await Framework .RunOnFrameworkThread(() => { + // TearDown slash-commands + UiBuilder hooks before windows + // tear down. Slash-commands holding handlers that reach + // the windows would otherwise see a half-torn Plugin. + failure = CaptureFailure(failure, TearDownCommands); + failure = CaptureFailure( failure, () => GameFunctions.GameFunctions.SetChatInteractable(true) @@ -683,11 +692,80 @@ public sealed class Plugin : IAsyncDalamudPlugin } } - private void OpenMainUi() + // Central slash-command + UiBuilder.OpenConfigUi/OpenMainUi subscribe so + // the four lazy windows (Settings, DbViewer, SeStringDebugger, Debugger) + // have working entry points before they're constructed. + private void SetupCommands() { - SettingsWindow.IsOpen = !SettingsWindow.IsOpen; + // ChatLogWindow.cs:128 already registers /hellion (ToggleChat). The + // description-arg here keeps the Dalamud help list populated. + Commands.Register("/hellion", "Perform various actions with Hellion Chat.").Execute += + OnHellionSettingsCommand; + Commands + .Register( + "/hellionView", + "Get access to your message history, with simple filter options.", + true + ) + .Execute += OnHellionViewCommand; + Commands.Register("/hellionDebugger", showInHelp: false).Execute += + OnHellionDebuggerCommand; +#if DEBUG + // SeStringDebugger.cs lives under #if DEBUG too; keep this out of release builds. + Commands.Register("/hellionSeString", showInHelp: false).Execute += + OnHellionSeStringCommand; +#endif + + // Plugin-Manager "Settings" button. Was in Settings.cs:67 pre-v1.4.9. + Interface.UiBuilder.OpenConfigUi += OnOpenConfigUi; + + // Plugin-Manager "Open" button. Was in Plugin.cs LoadAsync pre-v1.4.9 + // (separate OpenMainUi handler that flipped SettingsWindow.IsOpen). + Interface.UiBuilder.OpenMainUi += OnOpenMainUi; } + private void TearDownCommands() + { + Interface.UiBuilder.OpenMainUi -= OnOpenMainUi; + Interface.UiBuilder.OpenConfigUi -= OnOpenConfigUi; + + Commands.Register("/hellion", "Perform various actions with Hellion Chat.").Execute -= + OnHellionSettingsCommand; + Commands + .Register( + "/hellionView", + "Get access to your message history, with simple filter options.", + true + ) + .Execute -= OnHellionViewCommand; + Commands.Register("/hellionDebugger", showInHelp: false).Execute -= + OnHellionDebuggerCommand; +#if DEBUG + Commands.Register("/hellionSeString", showInHelp: false).Execute -= + OnHellionSeStringCommand; +#endif + } + + private void OnHellionSettingsCommand(string command, string arguments) + { + // /hellion with args is intentionally a no-op (matches pre-v1.4.9 + // Settings.cs:76-80 behaviour). + if (string.IsNullOrWhiteSpace(arguments)) + SettingsWindow.Toggle(); + } + + private void OnOpenConfigUi() => SettingsWindow.Toggle(); + + private void OnOpenMainUi() => SettingsWindow.Toggle(); + + private void OnHellionViewCommand(string _, string __) => DbViewer.Toggle(); + + private void OnHellionDebuggerCommand(string _, string __) => DebuggerWindow.Toggle(); + +#if DEBUG + private void OnHellionSeStringCommand(string _, string __) => SeStringDebugger.Toggle(); +#endif + private void RunRetentionSweepIfDue() { if (!Config.RetentionEnabled) diff --git a/HellionChat/Ui/DbViewer.cs b/HellionChat/Ui/DbViewer.cs index c033e9f..09481fa 100644 --- a/HellionChat/Ui/DbViewer.cs +++ b/HellionChat/Ui/DbViewer.cs @@ -93,29 +93,13 @@ public class DbViewer : Window RespectCloseHotkey = false; DisableWindowSounds = true; - - Plugin - .Commands.Register( - "/hellionView", - "Get access to your message history, with simple filter options.", - true - ) - .Execute += Toggle; } public void Dispose() { - Plugin - .Commands.Register( - "/hellionView", - "Get access to your message history, with simple filter options.", - true - ) - .Execute -= Toggle; + // Slash-command tear-down moved to Plugin.TearDownCommands. } - private void Toggle(string _, string __) => Toggle(); - public override void Draw() { var totalPages = (int)Math.Ceiling((double)Count / RowPerPage); diff --git a/HellionChat/Ui/Debugger.cs b/HellionChat/Ui/Debugger.cs index 07b8705..acb1921 100644 --- a/HellionChat/Ui/Debugger.cs +++ b/HellionChat/Ui/Debugger.cs @@ -28,17 +28,13 @@ public class DebuggerWindow : Window, IDisposable RespectCloseHotkey = false; DisableWindowSounds = true; - - Plugin.Commands.Register("/hellionDebugger", showInHelp: false).Execute += Toggle; } public void Dispose() { - Plugin.Commands.Register("/hellionDebugger", showInHelp: false).Execute -= Toggle; + // Slash-command tear-down moved to Plugin.TearDownCommands. } - private void Toggle(string _, string __) => Toggle(); - public override unsafe void Draw() { var agent = (nint)AgentItemDetail.Instance(); diff --git a/HellionChat/Ui/SeStringDebugger.cs b/HellionChat/Ui/SeStringDebugger.cs index 1c40804..74afae2 100644 --- a/HellionChat/Ui/SeStringDebugger.cs +++ b/HellionChat/Ui/SeStringDebugger.cs @@ -29,21 +29,13 @@ public class SeStringDebugger : Window RespectCloseHotkey = false; DisableWindowSounds = true; - -#if DEBUG - Plugin.Commands.Register("/hellionSeString", showInHelp: false).Execute += Toggle; -#endif } public void Dispose() { -#if DEBUG - Plugin.Commands.Register("/hellionSeString", showInHelp: false).Execute -= Toggle; -#endif + // Slash-command tear-down moved to Plugin.TearDownCommands. } - private void Toggle(string _, string __) => Toggle(); - public override void Draw() { if (Plugin.MessageManager.LastMessage.Sender == null) diff --git a/HellionChat/Ui/Settings.cs b/HellionChat/Ui/Settings.cs index 689249c..573cdc2 100755 --- a/HellionChat/Ui/Settings.cs +++ b/HellionChat/Ui/Settings.cs @@ -60,23 +60,11 @@ public sealed class SettingsWindow : Dalamud.Interface.Windowing.Window DisableWindowSounds = true; Initialise(); - - Plugin - .Commands.Register("/hellion", "Perform various actions with Hellion Chat.") - .Execute += Command; - Plugin.Interface.UiBuilder.OpenConfigUi += Toggle; } public void Dispose() { - Plugin.Interface.UiBuilder.OpenConfigUi -= Toggle; - Plugin.Commands.Register("/hellion").Execute -= Command; - } - - private void Command(string command, string args) - { - if (string.IsNullOrWhiteSpace(args)) - Toggle(); + // Slash-command + OpenConfigUi tear-down moved to Plugin.TearDownCommands. } private void Initialise()