From 0f404019b6b9657a59c120081c87e995de53dcf6 Mon Sep 17 00:00:00 2001 From: erikn Date: Tue, 15 Apr 2025 22:45:08 +0200 Subject: [PATCH] added http and settings --- MosswartMassacre/HttpCommandServer.cs | 105 +++++++++++++++++++++ MosswartMassacre/MosswartMassacre.csproj | 9 ++ MosswartMassacre/PluginCore.cs | 112 ++++++++++++++++++++++- MosswartMassacre/PluginSettings.cs | 80 ++++++++++++++++ MosswartMassacre/app.config | 19 ++++ MosswartMassacre/packages.config | 4 + 6 files changed, 327 insertions(+), 2 deletions(-) create mode 100644 MosswartMassacre/HttpCommandServer.cs create mode 100644 MosswartMassacre/PluginSettings.cs create mode 100644 MosswartMassacre/app.config create mode 100644 MosswartMassacre/packages.config diff --git a/MosswartMassacre/HttpCommandServer.cs b/MosswartMassacre/HttpCommandServer.cs new file mode 100644 index 0000000..35a6d38 --- /dev/null +++ b/MosswartMassacre/HttpCommandServer.cs @@ -0,0 +1,105 @@ +using System; +using System.Net; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Decal.Adapter; + +namespace MosswartMassacre +{ + public static class HttpCommandServer + { + private static HttpListener listener; + private static CancellationTokenSource cts; + private static bool isRunning = false; + + public static bool IsRunning => isRunning; + + public static void Start() + { + if (isRunning) return; + + try + { + listener = new HttpListener(); + listener.Prefixes.Add("http://localhost:8085/"); + listener.Start(); + cts = new CancellationTokenSource(); + Task.Run(() => ListenLoop(cts.Token)); + + isRunning = true; + PluginCore.WriteToChat("[HTTP] Server started on port 8085."); + } + catch (Exception ex) + { + PluginCore.WriteToChat("[HTTP] Error starting server: " + ex.Message); + } + } + + public static void Stop() + { + if (!isRunning) return; + + try + { + cts.Cancel(); + listener.Stop(); + listener.Close(); + listener = null; + isRunning = false; + PluginCore.WriteToChat("[HTTP] Server stopped."); + } + catch (Exception ex) + { + PluginCore.WriteToChat("[HTTP] Error stopping server: " + ex.Message); + } + } + + private static async Task ListenLoop(CancellationToken token) + { + while (!token.IsCancellationRequested) + { + HttpListenerContext context = null; + + try + { + context = await listener.GetContextAsync(); + } + catch (HttpListenerException) + { + break; // Listener was stopped + } + + if (context == null) continue; + + string requestBody = new System.IO.StreamReader(context.Request.InputStream).ReadToEnd(); + + PluginCore.WriteToChat("[HTTP] Received request: " + requestBody); + + // Parse simple format: target=Name&command=/say hello + string target = ""; + string command = ""; + foreach (var pair in requestBody.Split('&')) + { + var parts = pair.Split('='); + if (parts.Length == 2) + { + if (parts[0] == "target") target = WebUtility.UrlDecode(parts[1]); + else if (parts[0] == "command") command = WebUtility.UrlDecode(parts[1]); + } + } + + if (!string.IsNullOrWhiteSpace(target) && !string.IsNullOrWhiteSpace(command)) + { + string tellCmd = $"/a {target} {command}"; + CoreManager.Current.Actions.InvokeChatParser(tellCmd); + } + + byte[] buffer = Encoding.UTF8.GetBytes("Command received."); + context.Response.ContentLength64 = buffer.Length; + context.Response.OutputStream.Write(buffer, 0, buffer.Length); + context.Response.OutputStream.Close(); + } + } + } +} diff --git a/MosswartMassacre/MosswartMassacre.csproj b/MosswartMassacre/MosswartMassacre.csproj index 92b72c9..ab56762 100644 --- a/MosswartMassacre/MosswartMassacre.csproj +++ b/MosswartMassacre/MosswartMassacre.csproj @@ -59,8 +59,13 @@ lib\VirindiViewService.dll + + ..\packages\YamlDotNet.16.3.0\lib\net47\YamlDotNet.dll + + + @@ -85,5 +90,9 @@ + + + + \ No newline at end of file diff --git a/MosswartMassacre/PluginCore.cs b/MosswartMassacre/PluginCore.cs index e2e96cc..36241dc 100644 --- a/MosswartMassacre/PluginCore.cs +++ b/MosswartMassacre/PluginCore.cs @@ -19,7 +19,10 @@ namespace MosswartMassacre internal static double killsPerHour = 0; internal static DateTime statsStartTime = DateTime.Now; internal static Timer updateTimer; - public static bool RareMetaEnabled { get; private set; } = true; + public static bool RareMetaEnabled { get; set; } = true; + public static bool RemoteCommandsEnabled { get; set; } = false; + public static bool HttpServerEnabled { get; set; } = false; + public static string CharTag { get; set; } = ""; private static Queue rareMessageQueue = new Queue(); private static DateTime _lastSent = DateTime.MinValue; private static readonly Queue _chatQueue = new Queue(); @@ -29,11 +32,13 @@ namespace MosswartMassacre try { MyHost = Host; + WriteToChat("Mosswart Massacre has started!"); // Subscribe to chat message event CoreManager.Current.ChatBoxMessage += new EventHandler(OnChatText); CoreManager.Current.CommandLineText += OnChatCommand; + CoreManager.Current.CharacterFilter.LoginComplete += CharacterFilter_LoginComplete; // Initialize the timer updateTimer = new Timer(1000); // Update every second @@ -53,6 +58,7 @@ namespace MosswartMassacre { try { + PluginSettings.Save(); WriteToChat("Mosswart Massacre is shutting down..."); // Unsubscribe from chat message event @@ -76,6 +82,20 @@ namespace MosswartMassacre WriteToChat("Error during shutdown: " + ex.Message); } } + private void CharacterFilter_LoginComplete(object sender, EventArgs e) + { + CoreManager.Current.CharacterFilter.LoginComplete -= CharacterFilter_LoginComplete; + + PluginSettings.Initialize(); // Safe to call now + + // Apply the values + RareMetaEnabled = PluginSettings.Instance.RareMetaEnabled; + RemoteCommandsEnabled = PluginSettings.Instance.RemoteCommandsEnabled; + HttpServerEnabled = PluginSettings.Instance.HttpServerEnabled; + MainView.SetRareMetaToggleState(RareMetaEnabled); + + WriteToChat("Settings loaded."); + } private void OnChatText(object sender, ChatTextInterceptEventArgs e) { @@ -133,6 +153,39 @@ namespace MosswartMassacre WriteToChat($"[Mosswart Massacre] Reporting to allegiance: {reportMessage}"); MyHost.Actions.InvokeChatParser($"/a {reportMessage}"); } + if (RemoteCommandsEnabled && e.Color == 18) + { + string characterName = Regex.Escape(CoreManager.Current.CharacterFilter.Name); + string pattern = $@"^\[Allegiance\].*Dunking Rares.*say[s]?, \""!do {characterName} (?.+)\""$"; + string tag = Regex.Escape(PluginCore.CharTag); + string patterntag = $@"^\[Allegiance\].*Dunking Rares.*say[s]?, \""!dot {tag} (?.+)\""$"; + + + var match = Regex.Match(e.Text, pattern); + var matchtag = Regex.Match(e.Text, patterntag); + + if (match.Success) + { + string command = match.Groups["command"].Value; + DispatchChatToBoxWithPluginIntercept(command); + DelayedCommandManager.AddDelayedCommand($"/a [Remote] Executing: {command}", 2000); + } + else if (matchtag.Success) + { + string command = matchtag.Groups["command"].Value; + DispatchChatToBoxWithPluginIntercept(command); + DelayedCommandManager.AddDelayedCommand($"/a [Remote] Executing: {command}", 2000); + } + + } + + + + + + + + } catch (Exception ex) { @@ -268,7 +321,8 @@ namespace MosswartMassacre } public static void ToggleRareMeta() { - RareMetaEnabled = !RareMetaEnabled; + PluginSettings.Instance.RareMetaEnabled = !PluginSettings.Instance.RareMetaEnabled; + RareMetaEnabled = PluginSettings.Instance.RareMetaEnabled; MainView.SetRareMetaToggleState(RareMetaEnabled); } @@ -314,6 +368,8 @@ namespace MosswartMassacre WriteToChat("/mm report - Show current stats"); WriteToChat("/mm reset - Reset all counters"); WriteToChat("/mm meta - Toggle rare meta state"); + WriteToChat("/mm http - http server enable|disable"); + WriteToChat("/mm remotecommand - Listen to remote commands enable|disable"); break; case "report": @@ -331,6 +387,58 @@ namespace MosswartMassacre WriteToChat($"Rare meta state is now {(RareMetaEnabled ? "ON" : "OFF")}"); MainView.SetRareMetaToggleState(RareMetaEnabled); // <-- sync the UI break; + + case "http": + if (args.Length > 1) + { + if (args[1].Equals("enable", StringComparison.OrdinalIgnoreCase)) + { + PluginSettings.Instance.HttpServerEnabled = true; + HttpServerEnabled = true; + HttpCommandServer.Start(); + } + else if (args[1].Equals("disable", StringComparison.OrdinalIgnoreCase)) + { + PluginSettings.Instance.HttpServerEnabled = false; + HttpServerEnabled = false; + HttpCommandServer.Stop(); + } + else + { + WriteToChat("Usage: /mm http "); + } + } + else + { + WriteToChat("Usage: /mm http "); + } + break; + + case "remotecommands": + if (args.Length > 1) + { + if (args[1].Equals("enable", StringComparison.OrdinalIgnoreCase)) + { + PluginSettings.Instance.RemoteCommandsEnabled = true; + RemoteCommandsEnabled = true; + WriteToChat("Remote command listening is now ENABLED."); + } + else if (args[1].Equals("disable", StringComparison.OrdinalIgnoreCase)) + { + PluginSettings.Instance.RemoteCommandsEnabled = false; + RemoteCommandsEnabled = false; + WriteToChat("Remote command listening is now DISABLED."); + } + else + { + WriteToChat("Invalid remotecommands argument. Use 'enable' or 'disable'."); + } + } + else + { + WriteToChat("Usage: /mm remotecommands "); + } + break; default: WriteToChat($"Unknown /mm command: {subCommand}. Try /mm help"); diff --git a/MosswartMassacre/PluginSettings.cs b/MosswartMassacre/PluginSettings.cs new file mode 100644 index 0000000..c04c824 --- /dev/null +++ b/MosswartMassacre/PluginSettings.cs @@ -0,0 +1,80 @@ +using System; +using System.IO; +using YamlDotNet.Serialization; +using YamlDotNet.Serialization.NamingConventions; +using Decal.Adapter; + +namespace MosswartMassacre +{ + public class PluginSettings + { + private static PluginSettings _instance; + private static string _filePath; + private bool _remoteCommandsEnabled = false; + private bool _rareMetaEnabled = true; + private bool _httpServerEnabled = false; + private string _charTag = "default"; + public static PluginSettings Instance => _instance; + + public static void Initialize() + { + string characterName = CoreManager.Current.CharacterFilter.Name; + string pluginFolder = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); + _filePath = Path.Combine(pluginFolder, $"{characterName}.yaml"); + + if (File.Exists(_filePath)) + { + var deserializer = new DeserializerBuilder() + .WithNamingConvention(UnderscoredNamingConvention.Instance) + .Build(); + + string yaml = File.ReadAllText(_filePath); + _instance = deserializer.Deserialize(yaml); + } + else + { + _instance = new PluginSettings(); + Save(); + } + + // Apply settings to runtime state + PluginCore.RareMetaEnabled = _instance.RareMetaEnabled; + PluginCore.RemoteCommandsEnabled = _instance.RemoteCommandsEnabled; + PluginCore.HttpServerEnabled = _instance.HttpServerEnabled; + PluginCore.CharTag = _instance.CharTag; + } + + public static void Save() + { + var serializer = new SerializerBuilder() + .WithNamingConvention(UnderscoredNamingConvention.Instance) + .Build(); + + string yaml = serializer.Serialize(_instance); + File.WriteAllText(_filePath, yaml); + } + + public bool RemoteCommandsEnabled + { + get => _remoteCommandsEnabled; + set { _remoteCommandsEnabled = value; Save(); } + } + + public bool RareMetaEnabled + { + get => _rareMetaEnabled; + set { _rareMetaEnabled = value; Save(); } + } + + public bool HttpServerEnabled + { + get => _httpServerEnabled; + set { _httpServerEnabled = value; Save(); } + } + public string CharTag + { + get => _charTag; + set { _charTag = value; Save(); } + } + } +} diff --git a/MosswartMassacre/app.config b/MosswartMassacre/app.config new file mode 100644 index 0000000..7237d3b --- /dev/null +++ b/MosswartMassacre/app.config @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MosswartMassacre/packages.config b/MosswartMassacre/packages.config new file mode 100644 index 0000000..4ac85c1 --- /dev/null +++ b/MosswartMassacre/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file