using SilkroadBot.Plugins.SDK.Attributes; using SilkroadBot.Plugins.SDK.Interfaces; using SilkroadBot.Plugins.SDK.Models; namespace SilkroadBot.Plugin.Chat; /// /// Chat plugin - monitors, filters, and responds to chat messages. /// Supports auto-reply, chat logging, and command processing. /// [Plugin("chat", "Chat Manager", "Monitors and manages in-game chat with auto-reply and command support")] public class ChatPlugin : PluginBase { public override string Id => "chat"; public override string Name => "Chat Manager"; public override Version Version => new(1, 0, 0); public override string Author => "SilkroadBot Team"; public override string Description => "Chat monitoring, auto-reply, and command processing"; private readonly List _rules = new(); private readonly List _chatLog = new(); private const int MaxLogEntries = 1000; public override async Task InitializeAsync(IPluginContext context) { await base.InitializeAsync(context); await LoadRulesAsync(); } public override Task StartAsync(CancellationToken ct = default) { // Subscribe to chat events through the event system // In a real implementation, this would hook into PacketReceived // and filter for chat opcodes Log(LogLevel.Information, "Chat monitoring started"); return base.StartAsync(ct); } public override Task StopAsync() { Log(LogLevel.Information, "Chat monitoring stopped"); return base.StopAsync(); } /// /// Process an incoming chat message. /// public async Task ProcessMessage(Domain.Enums.ChatType chatType, string sender, string message) { // Log the message var entry = new ChatLogEntry(DateTime.UtcNow, chatType, sender, message); _chatLog.Add(entry); if (_chatLog.Count > MaxLogEntries) _chatLog.RemoveAt(0); Log(LogLevel.Debug, $"[{chatType}] {sender}: {message}"); // Check rules foreach (var rule in _rules.Where(r => r.IsEnabled)) { if (rule.Matches(chatType, sender, message)) { await ExecuteRuleAction(rule, sender, message); } } } /// /// Add a chat auto-reply rule. /// public void AddRule(ChatRule rule) { _rules.Add(rule); Log(LogLevel.Information, $"Added chat rule: {rule.Name}"); } /// /// Get the chat log. /// public IReadOnlyList GetChatLog() => _chatLog.AsReadOnly(); private async Task ExecuteRuleAction(ChatRule rule, string sender, string message) { switch (rule.Action) { case ChatAction.Reply: if (!string.IsNullOrEmpty(rule.ReplyMessage)) { Log(LogLevel.Information, $"Auto-replying to {sender}: {rule.ReplyMessage}"); // TODO: Send chat packet with reply } break; case ChatAction.Log: Log(LogLevel.Information, $"[LOGGED] {sender}: {message}"); break; case ChatAction.Block: Log(LogLevel.Information, $"Blocked message from {sender}"); break; case ChatAction.Alert: Log(LogLevel.Warning, $"ALERT - {sender}: {message}"); break; } await Task.CompletedTask; } private Task LoadRulesAsync() { // Add default rules _rules.Add(new ChatRule { Name = "PM Logger", ChatType = Domain.Enums.ChatType.PM, Action = ChatAction.Log, IsEnabled = true }); _rules.Add(new ChatRule { Name = "GM Alert", ChatType = Domain.Enums.ChatType.GM, Action = ChatAction.Alert, IsEnabled = true }); return Task.CompletedTask; } } public record ChatLogEntry(DateTime Timestamp, Domain.Enums.ChatType ChatType, string Sender, string Message); public class ChatRule { public string Name { get; set; } = string.Empty; public Domain.Enums.ChatType? ChatType { get; set; } public string? SenderFilter { get; set; } public string? MessageContains { get; set; } public ChatAction Action { get; set; } = ChatAction.Log; public string? ReplyMessage { get; set; } public bool IsEnabled { get; set; } = true; public bool Matches(Domain.Enums.ChatType type, string sender, string message) { if (ChatType.HasValue && ChatType.Value != type) return false; if (!string.IsNullOrEmpty(SenderFilter) && !sender.Contains(SenderFilter, StringComparison.OrdinalIgnoreCase)) return false; if (!string.IsNullOrEmpty(MessageContains) && !message.Contains(MessageContains, StringComparison.OrdinalIgnoreCase)) return false; return true; } } public enum ChatAction { Log, Reply, Block, Alert, Command }