Files
HellionChat/HellionChat/Ipc/ExtraChat.cs
T
JonKazama-Hellion c4c85cf4b8 docs: unify documentation and streamline code comments
- Translated project documentation (LEARNING-JOURNEY, CONTRIBUTORS, AI_DISCLOSURE) to English for better accessibility.
- Standardized internal code documentation by converting XML-doc blocks to standard comment format.
- Cleaned up inline comments and removed redundant versioning metadata across the codebase.
- Refactored non-functional text elements to improve readability and maintain a consistent style.
2026-05-11 00:52:15 +02:00

86 lines
3.0 KiB
C#

using Dalamud.Plugin.Ipc;
namespace HellionChat.Ipc;
public sealed class ExtraChat : IDisposable
{
#pragma warning disable CS0649 // Assigned through IPC
[Serializable]
private struct OverrideInfo
{
public string? Channel;
public ushort UiColour;
public uint Rgba;
}
#pragma warning restore CS0649
private ICallGateSubscriber<OverrideInfo, object> OverrideChannelGate { get; }
private ICallGateSubscriber<
Dictionary<string, uint>,
Dictionary<string, uint>
> ChannelCommandColoursGate { get; }
private ICallGateSubscriber<
Dictionary<Guid, string>,
Dictionary<Guid, string>
> ChannelNamesGate { get; }
internal (string, uint)? ChannelOverride { get; set; }
// volatile: IPC callbacks fire on a Dalamud thread while ImGui reads these.
// Reference assignment is atomic on x64, but the barrier ensures visibility
// across threads (especially Mono/Wine). See AUDIT-2026-05-05 [SEC-01].
private volatile Dictionary<string, uint> ChannelCommandColoursInternal = new();
internal IReadOnlyDictionary<string, uint> ChannelCommandColours =>
ChannelCommandColoursInternal;
private volatile Dictionary<Guid, string> ChannelNamesInternal = new();
internal IReadOnlyDictionary<Guid, string> ChannelNames => ChannelNamesInternal;
internal ExtraChat()
{
OverrideChannelGate = Plugin.Interface.GetIpcSubscriber<OverrideInfo, object>(
"ExtraChat.OverrideChannelColour"
);
ChannelCommandColoursGate = Plugin.Interface.GetIpcSubscriber<
Dictionary<string, uint>,
Dictionary<string, uint>
>("ExtraChat.ChannelCommandColours");
ChannelNamesGate = Plugin.Interface.GetIpcSubscriber<
Dictionary<Guid, string>,
Dictionary<Guid, string>
>("ExtraChat.ChannelNames");
OverrideChannelGate.Subscribe(OnOverrideChannel);
ChannelCommandColoursGate.Subscribe(OnChannelCommandColours);
ChannelNamesGate.Subscribe(OnChannelNames);
try
{
ChannelCommandColoursInternal = ChannelCommandColoursGate.InvokeFunc(null!);
ChannelNamesInternal = ChannelNamesGate.InvokeFunc(null!);
}
catch (Exception ex)
{
// ExtraChat is optional; IPC failure is normal when the plugin isn't loaded.
Plugin.Log.Verbose(ex, "ExtraChat IPC initial state query failed (peer not loaded?)");
}
}
public void Dispose()
{
OverrideChannelGate.Unsubscribe(OnOverrideChannel);
ChannelCommandColoursGate.Unsubscribe(OnChannelCommandColours);
ChannelNamesGate.Unsubscribe(OnChannelNames);
}
private void OnOverrideChannel(OverrideInfo info)
{
ChannelOverride = info.Channel == null ? null : (info.Channel, info.Rgba);
}
private void OnChannelCommandColours(Dictionary<string, uint> obj) =>
ChannelCommandColoursInternal = obj;
private void OnChannelNames(Dictionary<Guid, string> obj) => ChannelNamesInternal = obj;
}