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; } private ICallGateProvider< string, PlayerPayload?, ulong, Payload?, SeString?, SeString?, object? > InvokeGate { get; } // v1.4.9 R4: ChatTwo IPC compatibility mirror. Third-party plugins with // a no-fork policy (e.g. Artisan, AllaganTools) only subscribe to the // ChatTwo.*-prefixed context-menu integration gates. Mirroring all four // provider slots under the ChatTwo namespace lets those plugins keep // working without code changes on their side. Conflict detection // prevents ChatTwo and HellionChat from loading in parallel, so no slot // collision risk. private ICallGateProvider ChatTwoRegisterGate { get; } private ICallGateProvider ChatTwoUnregisterGate { get; } private ICallGateProvider ChatTwoAvailableGate { get; } private ICallGateProvider< string, PlayerPayload?, ulong, Payload?, SeString?, SeString?, object? > ChatTwoInvokeGate { get; } internal List Registered { get; } = []; public IpcManager(ILogger logger) { _logger = logger; RegisterGate = Plugin.Interface.GetIpcProvider("HellionChat.Register"); RegisterGate.RegisterFunc(Register); AvailableGate = Plugin.Interface.GetIpcProvider("HellionChat.Available"); UnregisterGate = Plugin.Interface.GetIpcProvider("HellionChat.Unregister"); UnregisterGate.RegisterAction(Unregister); InvokeGate = Plugin.Interface.GetIpcProvider< string, PlayerPayload?, ulong, Payload?, SeString?, SeString?, object? >("HellionChat.Invoke"); // v1.4.9 R4: ChatTwo-prefixed mirrors of the four context-menu slots // above. Share the same Register/Unregister backing methods so a // plugin that subscribes via either namespace lands in the same // Registered list. SendMessage on Invoke fans out to both gates. ChatTwoRegisterGate = Plugin.Interface.GetIpcProvider("ChatTwo.Register"); ChatTwoRegisterGate.RegisterFunc(Register); ChatTwoAvailableGate = Plugin.Interface.GetIpcProvider("ChatTwo.Available"); ChatTwoUnregisterGate = Plugin.Interface.GetIpcProvider( "ChatTwo.Unregister" ); ChatTwoUnregisterGate.RegisterAction(Unregister); ChatTwoInvokeGate = Plugin.Interface.GetIpcProvider< string, PlayerPayload?, ulong, Payload?, SeString?, SeString?, object? >("ChatTwo.Invoke"); AvailableGate.SendMessage(); ChatTwoAvailableGate.SendMessage(); } internal void Invoke( string id, PlayerPayload? sender, ulong contentId, Payload? payload, SeString? senderString, SeString? content ) { InvokeGate.SendMessage(id, sender, contentId, payload, senderString, content); // v1.4.9 R4: fan out the same event to plugins listening on ChatTwo.Invoke. ChatTwoInvokeGate.SendMessage(id, sender, contentId, payload, senderString, content); } private string Register() { var id = Guid.NewGuid().ToString(); Registered.Add(id); return id; } private void Unregister(string id) { Registered.Remove(id); } public void Dispose() { UnregisterGate.UnregisterAction(); RegisterGate.UnregisterFunc(); ChatTwoUnregisterGate.UnregisterAction(); ChatTwoRegisterGate.UnregisterFunc(); Registered.Clear(); } }