added http and settings

This commit is contained in:
erikn 2025-04-15 22:45:08 +02:00
parent 3c4bfbe772
commit 0f404019b6
6 changed files with 327 additions and 2 deletions

View file

@ -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();
}
}
}
}

View file

@ -59,8 +59,13 @@
<Reference Include="VirindiViewService">
<HintPath>lib\VirindiViewService.dll</HintPath>
</Reference>
<Reference Include="YamlDotNet, Version=16.0.0.0, Culture=neutral, PublicKeyToken=ec19458f3c15af5e, processorArchitecture=MSIL">
<HintPath>..\packages\YamlDotNet.16.3.0\lib\net47\YamlDotNet.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="PluginSettings.cs" />
<Compile Include="HttpCommandServer.cs" />
<Compile Include="DelayedCommandManager.cs" />
<Compile Include="MainView.cs" />
<Compile Include="PluginCore.cs" />
@ -85,5 +90,9 @@
<ItemGroup>
<EmbeddedResource Include="ViewXML\mainView.xml" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View file

@ -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<string> rareMessageQueue = new Queue<string>();
private static DateTime _lastSent = DateTime.MinValue;
private static readonly Queue<string> _chatQueue = new Queue<string>();
@ -29,11 +32,13 @@ namespace MosswartMassacre
try
{
MyHost = Host;
WriteToChat("Mosswart Massacre has started!");
// Subscribe to chat message event
CoreManager.Current.ChatBoxMessage += new EventHandler<ChatTextInterceptEventArgs>(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} (?<command>.+)\""$";
string tag = Regex.Escape(PluginCore.CharTag);
string patterntag = $@"^\[Allegiance\].*Dunking Rares.*say[s]?, \""!dot {tag} (?<command>.+)\""$";
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":
@ -332,6 +388,58 @@ namespace MosswartMassacre
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 <enable|disable>");
}
}
else
{
WriteToChat("Usage: /mm http <enable|disable>");
}
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 <enable|disable>");
}
break;
default:
WriteToChat($"Unknown /mm command: {subCommand}. Try /mm help");
break;

View file

@ -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<PluginSettings>(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(); }
}
}
}

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Decal.Interop.Core" publicKeyToken="481f17d392f1fb65" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.9.8.3" newVersion="2.9.8.3" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Decal.Adapter" publicKeyToken="bd1c8ce002ce221e" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.9.8.3" newVersion="2.9.8.3" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Decal.Interop.Inject" publicKeyToken="481f17d392f1fb65" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.9.8.3" newVersion="2.9.8.3" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="YamlDotNet" version="16.3.0" targetFramework="net48" />
</packages>