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