From fbbbeebade745948d7d283c9597c4f74a0b6a843 Mon Sep 17 00:00:00 2001 From: Jon Kazama Date: Fri, 15 May 2026 20:18:41 +0200 Subject: [PATCH] refactor(commands): cache slash-command wrappers in private fields TearDownCommands attached the same instance via re-Register with identical args, which was functionally a no-op but masked a latent bug if Description or ShowInHelp ever diverged between Setup and Teardown. Hold the wrapper instances as nullable fields so Teardown can detach the live registration directly. Mirrors the cached-wrapper pattern in ChatLogWindow. --- HellionChat/Plugin.cs | 76 ++++++++++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 26 deletions(-) diff --git a/HellionChat/Plugin.cs b/HellionChat/Plugin.cs index 6c9301e..d3aeb88 100755 --- a/HellionChat/Plugin.cs +++ b/HellionChat/Plugin.cs @@ -123,6 +123,15 @@ public sealed class Plugin : IAsyncDalamudPlugin // isolation. Wired immediately after Dalamud injects Log. internal static IPluginLogProxy LogProxy { get; private set; } = null!; + // Wrapper cached so TearDown can detach the live instance instead of + // re-registering with identical args (v1.4.9 ISSUE-1 cleanup). + private CommandWrapper? _hellionSettingsCmd; + private CommandWrapper? _hellionViewCmd; + private CommandWrapper? _hellionDebuggerCmd; +#if DEBUG + private CommandWrapper? _hellionSeStringCmd; +#endif + // Idempotency guard — Dalamud may fire DisposeAsync twice in a reload race. private int _disposeStarted; @@ -699,21 +708,25 @@ public sealed class Plugin : IAsyncDalamudPlugin { // 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; + _hellionSettingsCmd = Commands.Register( + "/hellion", + "Perform various actions with Hellion Chat." + ); + _hellionSettingsCmd.Execute += OnHellionSettingsCommand; + + _hellionViewCmd = Commands.Register( + "/hellionView", + "Get access to your message history, with simple filter options.", + true + ); + _hellionViewCmd.Execute += OnHellionViewCommand; + + _hellionDebuggerCmd = Commands.Register("/hellionDebugger", showInHelp: false); + _hellionDebuggerCmd.Execute += OnHellionDebuggerCommand; #if DEBUG // SeStringDebugger.cs lives under #if DEBUG too; keep this out of release builds. - Commands.Register("/hellionSeString", showInHelp: false).Execute += - OnHellionSeStringCommand; + _hellionSeStringCmd = Commands.Register("/hellionSeString", showInHelp: false); + _hellionSeStringCmd.Execute += OnHellionSeStringCommand; #endif // Plugin-Manager "Settings" button. Was in Settings.cs:67 pre-v1.4.9. @@ -729,20 +742,31 @@ public sealed class Plugin : IAsyncDalamudPlugin 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; + // Null-tolerant detaches: TearDownCommands can run from the LoadAsync + // failure path (Plugin.cs CaptureFailure) before SetupCommands finished. + if (_hellionSettingsCmd is not null) + { + _hellionSettingsCmd.Execute -= OnHellionSettingsCommand; + _hellionSettingsCmd = null; + } + + if (_hellionViewCmd is not null) + { + _hellionViewCmd.Execute -= OnHellionViewCommand; + _hellionViewCmd = null; + } + + if (_hellionDebuggerCmd is not null) + { + _hellionDebuggerCmd.Execute -= OnHellionDebuggerCommand; + _hellionDebuggerCmd = null; + } #if DEBUG - Commands.Register("/hellionSeString", showInHelp: false).Execute -= - OnHellionSeStringCommand; + if (_hellionSeStringCmd is not null) + { + _hellionSeStringCmd.Execute -= OnHellionSeStringCommand; + _hellionSeStringCmd = null; + } #endif }