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
}