diff --git a/HellionChat/GameFunctions/Chat.cs b/HellionChat/GameFunctions/Chat.cs index aa6502c..0523bda 100755 --- a/HellionChat/GameFunctions/Chat.cs +++ b/HellionChat/GameFunctions/Chat.cs @@ -19,6 +19,7 @@ using HellionChat.Resources; using HellionChat.Util; using InteropGenerator.Runtime; using Lumina.Text.ReadOnly; +using Microsoft.Extensions.Logging; using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.AtkValueType; namespace HellionChat.GameFunctions; @@ -98,9 +99,12 @@ internal sealed unsafe class Chat : IDisposable private long LastPlayerNameDisplayTypeRefresh; private PlayerNameDisplayType CurrentPlayerNameDisplayType = PlayerNameDisplayType.FullName; - public Chat(Plugin plugin) + private readonly ILogger _logger; + + public Chat(Plugin plugin, ILogger logger) { Plugin = plugin; + _logger = logger; Plugin.GameInteropProvider.InitializeFromAttributes(this); ChatLogRefreshHook?.Enable(); @@ -236,7 +240,7 @@ internal sealed unsafe class Chat : IDisposable } catch (Exception ex) { - Plugin.LogProxy.Error(ex, "Error in chat Activated event"); + _logger.LogError(ex, "Error in chat Activated event"); } }); } @@ -266,7 +270,7 @@ internal sealed unsafe class Chat : IDisposable } catch (Exception ex) { - Plugin.LogProxy.Error(ex, "Error in chat Activated event"); + _logger.LogError(ex, "Error in chat Activated event"); } return 1; // Prevent vanilla chat log from gaining focus @@ -299,7 +303,7 @@ internal sealed unsafe class Chat : IDisposable { playerName = SeString.Parse(agent->TellPlayerName).TextValue; worldId = agent->TellWorldId; - Plugin.LogProxy.Debug($"Detected tell target '[redacted]'@{worldId}"); + _logger.LogDebug($"Detected tell target '[redacted]'@{worldId}"); } Plugin.CurrentTab.CurrentChannel = new UsedChannel @@ -358,7 +362,7 @@ internal sealed unsafe class Chat : IDisposable } catch (Exception ex) { - Plugin.LogProxy.Error(ex, "Error in chat Activated event"); + _logger.LogError(ex, "Error in chat Activated event"); } } @@ -408,7 +412,7 @@ internal sealed unsafe class Chat : IDisposable } catch (Exception ex) { - Plugin.LogProxy.Error(ex, "Error in chat Activated event"); + _logger.LogError(ex, "Error in chat Activated event"); } } @@ -624,7 +628,7 @@ internal sealed unsafe class Chat : IDisposable if (contentId == 0) { Plugin.ChatGui.PrintError(Language.Chat_SendTell_Error); - Plugin.LogProxy.Warning( + _logger.LogWarning( "Tried to send a tell with ContentId being 0, sorry this is an internal error." ); return; diff --git a/HellionChat/GameFunctions/GameFunctions.cs b/HellionChat/GameFunctions/GameFunctions.cs index 985fa16..5e48942 100755 --- a/HellionChat/GameFunctions/GameFunctions.cs +++ b/HellionChat/GameFunctions/GameFunctions.cs @@ -14,6 +14,7 @@ using FFXIVClientStructs.FFXIV.Client.UI.Info; using FFXIVClientStructs.FFXIV.Component.GUI; using Lumina.Excel; using Lumina.Excel.Sheets; +using Microsoft.Extensions.Logging; using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.AtkValueType; namespace HellionChat.GameFunctions; @@ -37,14 +38,20 @@ internal unsafe class GameFunctions : IDisposable #endregion private Plugin Plugin { get; } + private readonly ILogger _logger; internal KeybindManager KeybindManager { get; } internal Chat Chat { get; } - internal GameFunctions(Plugin plugin) + internal GameFunctions( + Plugin plugin, + ILogger logger, + ILoggerFactory loggerFactory + ) { Plugin = plugin; - KeybindManager = new KeybindManager(plugin); - Chat = new Chat(Plugin); + _logger = logger; + KeybindManager = new KeybindManager(plugin, loggerFactory.CreateLogger()); + Chat = new Chat(Plugin, loggerFactory.CreateLogger()); Plugin.GameInteropProvider.InitializeFromAttributes(this); ResolveTextCommandPlaceholderHook?.Enable(); @@ -215,6 +222,10 @@ internal unsafe class GameFunctions : IDisposable } catch (Exception e) { + // Static method has no instance _logger to reach. Promoting this to + // an instance method would force PayloadHandler.cs:814 (the only + // caller) onto Plugin.Functions.* indirection. Lighter touch for + // DI-4 Slice B is to keep this one site on Plugin.LogProxy. Plugin.LogProxy.Warning(e, "Unable to open adventurer plate"); return false; } @@ -255,7 +266,7 @@ internal unsafe class GameFunctions : IDisposable var byteCount = System.Text.Encoding.UTF8.GetByteCount(ReplacementName); if (byteCount >= PlaceholderBufferSize) { - Plugin.LogProxy.Warning( + _logger.LogWarning( $"Replacement name too long for placeholder buffer ({byteCount} bytes >= {PlaceholderBufferSize}); falling back to original." ); ReplacementName = null; diff --git a/HellionChat/GameFunctions/KeybindManager.cs b/HellionChat/GameFunctions/KeybindManager.cs index f374f2a..64aa401 100644 --- a/HellionChat/GameFunctions/KeybindManager.cs +++ b/HellionChat/GameFunctions/KeybindManager.cs @@ -8,6 +8,7 @@ using FFXIVClientStructs.FFXIV.Client.UI; using HellionChat.Code; using HellionChat.GameFunctions.Types; using HellionChat.Util; +using Microsoft.Extensions.Logging; using ModifierFlag = HellionChat.GameFunctions.Types.ModifierFlag; namespace HellionChat.GameFunctions; @@ -306,9 +307,12 @@ internal unsafe class KeybindManager : IDisposable // VirtualKey.OEM_CLEAR, }; - internal KeybindManager(Plugin plugin) + private readonly ILogger _logger; + + internal KeybindManager(Plugin plugin, ILogger logger) { Plugin = plugin; + _logger = logger; Plugin.GameInteropProvider.InitializeFromAttributes(this); // Handle keybinds from the game on every tick. @@ -507,7 +511,7 @@ internal unsafe class KeybindManager : IDisposable } catch (Exception ex) { - Plugin.LogProxy.Error(ex, "Error in chat Activated event"); + _logger.LogError(ex, "Error in chat Activated event"); } } diff --git a/HellionChat/Integrations/HonorificService.cs b/HellionChat/Integrations/HonorificService.cs index 73b47d3..6a37588 100644 --- a/HellionChat/Integrations/HonorificService.cs +++ b/HellionChat/Integrations/HonorificService.cs @@ -2,6 +2,7 @@ using System; using Dalamud.Plugin; using Dalamud.Plugin.Ipc; using Dalamud.Plugin.Services; +using Microsoft.Extensions.Logging; using Newtonsoft.Json; namespace HellionChat.Integrations; @@ -23,7 +24,7 @@ internal sealed class HonorificService : IDisposable private readonly ICallGateSubscriber _ready; private readonly ICallGateSubscriber _disposing; - private readonly IPluginLog _log; + private readonly ILogger _logger; private readonly IFramework _framework; private bool _versionWarningLogged; @@ -34,12 +35,12 @@ internal sealed class HonorificService : IDisposable public HonorificService( IDalamudPluginInterface pluginInterface, - IPluginLog log, + ILogger logger, IFramework framework ) { _framework = framework; - _log = log; + _logger = logger; // Gate objects are cached per-name by Dalamud and safe to register // before Honorific loads — they just won't fire until it does. @@ -84,7 +85,7 @@ internal sealed class HonorificService : IDisposable { if (!_versionWarningLogged) { - _log.Warning( + _logger.LogWarning( "Honorific API version mismatch — expected major 3, " + "found {Major}.{Minor}. Disabling Honorific integration.", version.Item1, @@ -104,7 +105,7 @@ internal sealed class HonorificService : IDisposable catch (Exception ex) { // Honorific not installed or not yet initialised — Ready will retry. - _log.Debug(ex, "Honorific not available at HellionChat startup; awaiting Ready."); + _logger.LogDebug(ex, "Honorific not available at HellionChat startup; awaiting Ready."); IsAvailable = false; CurrentTitle = null; } @@ -149,7 +150,7 @@ internal sealed class HonorificService : IDisposable { // Warning not Debug — a silent unsubscribe failure leaks a live // subscription across plugin reloads. - _log.Warning( + _logger.LogWarning( ex, "Honorific unsubscribe failed (likely API break or gate already gone)." ); diff --git a/HellionChat/Ipc/ExtraChat.cs b/HellionChat/Ipc/ExtraChat.cs index f8a668c..f69547c 100644 --- a/HellionChat/Ipc/ExtraChat.cs +++ b/HellionChat/Ipc/ExtraChat.cs @@ -1,9 +1,12 @@ using Dalamud.Plugin.Ipc; +using Microsoft.Extensions.Logging; namespace HellionChat.Ipc; public sealed class ExtraChat : IDisposable { + private readonly ILogger _logger; + #pragma warning disable CS0649 // Assigned through IPC [Serializable] private struct OverrideInfo @@ -36,8 +39,9 @@ public sealed class ExtraChat : IDisposable private volatile Dictionary ChannelNamesInternal = new(); internal IReadOnlyDictionary ChannelNames => ChannelNamesInternal; - internal ExtraChat() + internal ExtraChat(ILogger logger) { + _logger = logger; OverrideChannelGate = Plugin.Interface.GetIpcSubscriber( "ExtraChat.OverrideChannelColour" ); @@ -62,10 +66,7 @@ public sealed class ExtraChat : IDisposable catch (Exception ex) { // ExtraChat is optional; IPC failure is normal when the plugin isn't loaded. - Plugin.LogProxy.Verbose( - ex, - "ExtraChat IPC initial state query failed (peer not loaded?)" - ); + _logger.LogTrace(ex, "ExtraChat IPC initial state query failed (peer not loaded?)"); } } diff --git a/HellionChat/Ipc/TypingIpc.cs b/HellionChat/Ipc/TypingIpc.cs index 33b6fd6..394cc97 100644 --- a/HellionChat/Ipc/TypingIpc.cs +++ b/HellionChat/Ipc/TypingIpc.cs @@ -1,5 +1,6 @@ using Dalamud.Plugin.Ipc; using HellionChat.Code; +using Microsoft.Extensions.Logging; namespace HellionChat.Ipc; @@ -33,9 +34,12 @@ internal sealed class TypingIpc : IDisposable private ChatInputState LastState; private bool HasState; - internal TypingIpc(Plugin plugin) + private readonly ILogger _logger; + + internal TypingIpc(Plugin plugin, ILogger logger) { Plugin = plugin; + _logger = logger; StateQueryGate = Plugin.Interface.GetIpcProvider( "HellionChat.GetChatInputState" diff --git a/HellionChat/IpcManager.cs b/HellionChat/IpcManager.cs index cbade56..c8cfbd6 100755 --- a/HellionChat/IpcManager.cs +++ b/HellionChat/IpcManager.cs @@ -1,11 +1,14 @@ using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling.Payloads; using Dalamud.Plugin.Ipc; +using Microsoft.Extensions.Logging; namespace HellionChat; internal sealed class IpcManager : IDisposable { + private readonly ILogger _logger; + private ICallGateProvider RegisterGate { get; } private ICallGateProvider UnregisterGate { get; } private ICallGateProvider AvailableGate { get; } @@ -41,8 +44,9 @@ internal sealed class IpcManager : IDisposable internal List Registered { get; } = []; - public IpcManager() + public IpcManager(ILogger logger) { + _logger = logger; RegisterGate = Plugin.Interface.GetIpcProvider("HellionChat.Register"); RegisterGate.RegisterFunc(Register); diff --git a/HellionChat/PluginHostFactory.cs b/HellionChat/PluginHostFactory.cs index af59833..0545d8f 100644 --- a/HellionChat/PluginHostFactory.cs +++ b/HellionChat/PluginHostFactory.cs @@ -100,8 +100,8 @@ internal static class PluginHostFactory services.AddSingleton(_ => new Commands()); services.AddSingleton(_ => new FontManager()); services.AddSingleton(_ => new StatusBar()); - services.AddSingleton(_ => new IpcManager()); - services.AddSingleton(_ => new ExtraChat()); + services.AddSingleton(sp => new IpcManager(sp.GetRequiredService>())); + services.AddSingleton(sp => new ExtraChat(sp.GetRequiredService>())); services.AddSingleton(sp => new ThemeRegistry( Path.Combine( @@ -111,13 +111,18 @@ internal static class PluginHostFactory )); services.AddSingleton(sp => new GameFunctions.GameFunctions( - sp.GetRequiredService() + sp.GetRequiredService(), + sp.GetRequiredService>(), + sp.GetRequiredService() + )); + services.AddSingleton(sp => new TypingIpc( + sp.GetRequiredService(), + sp.GetRequiredService>() )); - services.AddSingleton(sp => new TypingIpc(sp.GetRequiredService())); services.AddSingleton(sp => new Integrations.HonorificService( sp.GetRequiredService(), - sp.GetRequiredService(), + sp.GetRequiredService>(), sp.GetRequiredService() ));