diff options
| -rw-r--r-- | DiscordToXIV/Plugin.cs | 179 |
1 files changed, 136 insertions, 43 deletions
diff --git a/DiscordToXIV/Plugin.cs b/DiscordToXIV/Plugin.cs index bd8c977..c73ea58 100644 --- a/DiscordToXIV/Plugin.cs +++ b/DiscordToXIV/Plugin.cs @@ -8,37 +8,55 @@ using System.Collections.Generic; using System.Threading; using System.Text.Json; using System.Text.Json.Serialization; +using Dalamud.Game.Text.SeStringHandling; +using Dalamud.Game.Text.SeStringHandling.Payloads; using Dalamud.Interface.Windowing; using DiscordToXIV.Windows; + + namespace DiscordToXIV; public class Message { + [JsonPropertyName("id")] + public string? Id { get; init; } [JsonPropertyName("author")] - public string Author { get; set; } + public string? Author { get; init; } [JsonPropertyName("author_name")] - public string AuthorName { get; set; } + public string? AuthorName { get; init; } [JsonPropertyName("nickname")] - public string Nickname { get; set; } + public string? Nickname { get; init; } [JsonPropertyName("content")] - public string Content { get; set; } + public string? Content { get; init; } [JsonPropertyName("time")] - public string Time { get; set; } + public string? Time { get; init; } [JsonPropertyName("channel")] - public string Channel { get; set; } -} + public string? Channel { get; init; } + + [JsonPropertyName("sticker_id")] + public string? StickerId { get; init; } + + [JsonPropertyName("sticker_name")] + public string? StickerName { get; init; } + [JsonIgnore] + public string? ChannelName { get; set; } +} public sealed class Plugin : IDalamudPlugin { + private int[] nameColor = + { + 45, 517, 704, 708, 52, 61 + }; [PluginService] internal static IDalamudPluginInterface PluginInterface { get; private set; } = null!; [PluginService] internal static ICommandManager CommandManager { get; private set; } = null!; [PluginService] internal static IChatGui ChatGui { get; private set; } = null!; @@ -47,25 +65,31 @@ public sealed class Plugin : IDalamudPlugin private const string CommandName = "/pdiscordtoxiv"; private const int DefaultPort = 8765; - private WebSocketServer _webSocketServer; - private CancellationTokenSource _cancellationTokenSource; - private List<IWebSocketConnection> _connectedClients; + private WebSocketServer webSocketServer; + private readonly CancellationTokenSource cancellationTokenSource; + private readonly List<IWebSocketConnection> connectedClients; + private readonly HashSet<string> recentMessages = new HashSet<string>(); + private readonly Queue<string> messageQueue = new Queue<string>(); + private const int MaxRecentMessages = 100; + private readonly object messageLock = new object(); public Configuration Configuration { get; init; } private ConfigWindow ConfigWindow { get; init; } - public readonly WindowSystem WindowSystem = new("SamplePlugin"); + public readonly WindowSystem WindowSystem = new("DiscordToXIV"); + public Plugin() { Configuration = PluginInterface.GetPluginConfig() as Configuration ?? new Configuration(); ConfigWindow = new ConfigWindow(this); WindowSystem.AddWindow(ConfigWindow); - _cancellationTokenSource = new CancellationTokenSource(); - _connectedClients = new List<IWebSocketConnection>(); + cancellationTokenSource = new CancellationTokenSource(); + connectedClients = new List<IWebSocketConnection>(); CommandManager.AddHandler(CommandName, new CommandInfo(OnCommand) { HelpMessage = "Start WebSocket server. Usage: /pdiscordtoxiv [port]" }); + PluginInterface.UiBuilder.Draw += DrawUI; PluginInterface.UiBuilder.OpenConfigUi += ToggleConfigUI; ChatGui.Print("Plugin starting..."); } @@ -98,50 +122,112 @@ public sealed class Plugin : IDalamudPlugin ChatGui.Print($"WebSocket server started on port {port}"); } - private void StartWebSocketServer(int port) +private void StartWebSocketServer(int port) +{ + StopWebSocketServer(); + + webSocketServer = new WebSocketServer($"ws://0.0.0.0:{port}"); + + webSocketServer.Start(socket => { - StopWebSocketServer(); + socket.OnOpen = () => + { + PluginLog.Information("WebSocket connection opened."); + connectedClients.Add(socket); + }; - _webSocketServer = new WebSocketServer($"ws://0.0.0.0:{port}"); + socket.OnClose = () => + { + PluginLog.Information("WebSocket connection closed."); + connectedClients.Remove(socket); + }; - _webSocketServer.Start(socket => + socket.OnMessage = message => { - socket.OnOpen = () => - { - PluginLog.Information("WebSocket connection opened."); - _connectedClients.Add(socket); - }; - - socket.OnClose = () => - { - PluginLog.Information("WebSocket connection closed."); - _connectedClients.Remove(socket); - }; - - socket.OnMessage = message => + try { - try + var receivedMessage = JsonSerializer.Deserialize<Message>(message); + + if (receivedMessage == null || string.IsNullOrEmpty(receivedMessage.Id)) + { + PluginLog.Error("Received message without an ID."); + return; + } + + lock (messageLock) { - Message receivedMessage = JsonSerializer.Deserialize<Message>(message); - //PluginLog.Information($"Message from {receivedMessage.Nickname}: {receivedMessage.Content}"); - ChatGui.Print($"[{receivedMessage.AuthorName}] {receivedMessage.Nickname}: {receivedMessage.Content}"); + if (recentMessages.Contains(receivedMessage.Id)) + { + PluginLog.Information("Duplicate message detected by ID, skipping."); + return; + } + + recentMessages.Add(receivedMessage.Id); + messageQueue.Enqueue(receivedMessage.Id); + + if (messageQueue.Count > MaxRecentMessages) + { + string oldMessageId = messageQueue.Dequeue(); + recentMessages.Remove(oldMessageId); + } } - catch (Exception ex) + var seString = new SeString(new List<Payload>()); + var name = receivedMessage.Author; + ushort nameColor = (ushort)GetNameColor(name); + if (receivedMessage.Nickname != null) { - PluginLog.Error($"Failed to deserialize message: {ex.Message}"); + if (!Configuration.HideUsernameWhenNicknameExists) + name = $"{receivedMessage.Nickname} ({receivedMessage.AuthorName})"; + else + name = receivedMessage.Nickname; + } + else if (receivedMessage.AuthorName != null) + { + name = receivedMessage.AuthorName; } - }; - }); - } + receivedMessage.ChannelName = Configuration.ChannelMappings.TryGetValue(receivedMessage.Channel, out var channelName) + ? channelName + : receivedMessage.Channel; + + seString.Append(new UIForegroundPayload(35)); + seString.Append($"[{receivedMessage.ChannelName}] "); + seString.Append(UIForegroundPayload.UIForegroundOff); + seString.Append(new UIForegroundPayload(nameColor)); + seString.Append(name); + seString.Append(UIForegroundPayload.UIForegroundOff); + seString.Append(new UIForegroundPayload(1)); + seString.Append($": {receivedMessage.Content}"); + var stickerData = ""; + if (receivedMessage.StickerId != null) + stickerData = $" [{receivedMessage.StickerName}](https://media.discordapp.net/stickers/{receivedMessage.StickerId}.webp?size=160&quality=lossless)"; + if(stickerData == "" && receivedMessage.Content == null) + return; + if (stickerData != "") + { + seString.Append(new UIForegroundPayload(25)); + seString.Append(stickerData); + } + seString.Append(UIForegroundPayload.UIForegroundOff); + + ChatGui.Print(seString); + } + catch (Exception ex) + { + PluginLog.Error($"Failed to process message: {ex.Message}"); + } + }; + }); +} + private void StopWebSocketServer() { - if (_webSocketServer != null) + if (webSocketServer != null) { PluginLog.Information("Stopping WebSocket server..."); - foreach (var socket in _connectedClients) + foreach (var socket in connectedClients) { if (socket.IsAvailable) { @@ -149,10 +235,17 @@ public sealed class Plugin : IDalamudPlugin } } - _webSocketServer.Dispose(); - _cancellationTokenSource.Cancel(); + webSocketServer.Dispose(); + cancellationTokenSource.Cancel(); PluginLog.Information("WebSocket server stopped."); } } + + private int GetNameColor(string name) + { + var index = Math.Abs(name.GetHashCode()) % nameColor.Length; + return nameColor[index]; + } public void ToggleConfigUI() => ConfigWindow.Toggle(); + private void DrawUI() => WindowSystem.Draw(); } |
