From 6b5bd54f4fc4f1fd4a57cb38fe1749390022ef35 Mon Sep 17 00:00:00 2001 From: TQ Hirsch Date: Thu, 15 Jan 2026 02:02:59 +0100 Subject: [PATCH] All features seem to work. --- Patches/Tick.cs | 1 + Scripts/Remotecontrol.cs | 105 +++++++++++++++++++++++++-------------- 2 files changed, 69 insertions(+), 37 deletions(-) diff --git a/Patches/Tick.cs b/Patches/Tick.cs index f3c8cba..9b6a844 100644 --- a/Patches/Tick.cs +++ b/Patches/Tick.cs @@ -25,6 +25,7 @@ namespace RemoteControl.Patches { try { + RemoteControl.Log("Sending update"); RemoteControl.Subscribers.SendUpdate(); } catch (Exception e) diff --git a/Scripts/Remotecontrol.cs b/Scripts/Remotecontrol.cs index 154e10a..757839c 100644 --- a/Scripts/Remotecontrol.cs +++ b/Scripts/Remotecontrol.cs @@ -3,6 +3,8 @@ using UnityEngine; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Net; +using System.Text; using System.Threading; using System.Threading.Tasks; using Assets.Scripts; @@ -38,7 +40,7 @@ namespace RemoteControl private readonly Harmony _harmony = new Harmony(pluginGuid); public static WebServer WebServer { get; private set; } - internal static SubscriptionModule Subscribers { get; private set; } + internal static SubscriptionModule Subscribers { get; } = new SubscriptionModule("/subscribe"); private CancellationTokenSource _modLifecycle = new(); @@ -46,7 +48,7 @@ namespace RemoteControl public const string pluginGuid = "com.thequux.stationeers.RemoteControl"; public const string pluginName = "RemoteControl"; public const string pluginVersion = "1.0"; - + public static void Log(string line) { Debug.Log("[" + pluginName + "]: " + line); @@ -54,13 +56,6 @@ namespace RemoteControl private void StartRC() { - if (!_modLifecycle.IsCancellationRequested) - { - _modLifecycle.Cancel(); - } - - _modLifecycle = new CancellationTokenSource(); - Port = Config.Bind(new ConfigDefinition("Server", "Port"), 39125, new ConfigDescription("The port to listen on")); ListenOnAllInterfaces = Config.Bind( @@ -69,29 +64,51 @@ namespace RemoteControl new ConfigDescription("If set, listen on all interfaces. Otherwise, listen only on localhost")); - var subscriptionModule = new SubscriptionModule("/subscribe"); - Subscribers = subscriptionModule; - WebServer = new WebServer(o => - o.WithUrlPrefix($"http://{(ListenOnAllInterfaces.Value ? "0.0.0.0" : "localhost")}:{Port.Value}/") - .WithEmbedIOHttpListener() - ) - .WithWebApi("/api/v1", m => m.WithController()) - .WithModule(subscriptionModule); - WebServer.Start(_modLifecycle.Token); + // No need to restart the game after changing settings :-) + Port.SettingChanged += WebserverSettingsChanged; + ListenOnAllInterfaces.SettingChanged += WebserverSettingsChanged; + + // Subscribers = new SubscriptionModule("/subscribe"); + RestartWebserver(); _harmony.PatchAll(); foreach (var patchedMethod in _harmony.GetPatchedMethods()) { Log($"Patched {patchedMethod.FullDescription()}"); } - Log($"Patched {_harmony.GetPatchedMethods().Count()} methods total"); - + Log($"Patched {_harmony.GetPatchedMethods().Count()} methods total"); } - + + private void WebserverSettingsChanged(object _1, EventArgs _2) + { + RestartWebserver(); + } + + private void RestartWebserver() + { + if (!_modLifecycle.IsCancellationRequested) + { + _modLifecycle.Cancel(); + } + + var URL = $"http://{(ListenOnAllInterfaces.Value ? "*" : "localhost")}:{Port.Value}/"; + Log($"Starting webserver on {URL}"); + _modLifecycle = new CancellationTokenSource(); + WebServer = new WebServer(o => + { + o.WithUrlPrefix(URL) + .WithEmbedIOHttpListener(); + }) + .WithWebApi("/api/v1", m => m.WithController()) + .WithModule(Subscribers); + WebServer.Start(_modLifecycle.Token); + } + public void OnLoaded(List prefabs) { - // Start(); + Log("Starting RemoteControl"); + StartRC(); #if DEVELOPMENT_BUILD Debug.Log($"Loaded {prefabs.Count} prefabs"); #endif @@ -99,7 +116,8 @@ namespace RemoteControl public void OnUnloaded(List prefabs) { - // Stop(); + Log("Tearing down RemoteControl"); + StopRC(); } public void StopRC() @@ -110,25 +128,27 @@ namespace RemoteControl public void Awake() { - Log("Starting RemoteControl"); - StartRC(); + // Log("Starting RemoteControl"); + // StartRC(); } private void OnDestroy() { - Log("Tearing down RemoteControl"); - StopRC(); + // Log("Tearing down RemoteControl"); + // StopRC(); } } internal class ApiController : WebApiController { private static readonly Dictionary LtByName = EnumCollections.LogicTypes.AsLookupDict(true); - private static readonly Dictionary StByName = EnumCollections.LogicSlotTypes.AsLookupDict(true); + + private static readonly Dictionary StByName = + EnumCollections.LogicSlotTypes.AsLookupDict(true); private static Device GetDeviceJson(GameDevice device) => new(device); - - + + private static Device? GetDeviceJson(long referenceId) { var dev = Referencable.Find(referenceId); @@ -153,7 +173,7 @@ namespace RemoteControl return dev; } - + private static List GetNetworkDevice(string probeName, string deviceName) { @@ -178,6 +198,9 @@ namespace RemoteControl var result = default(T); bool isFound = false; + // deviceName = WebUtility.UrlDecode(deviceName); + // networkName = WebUtility.UrlDecode(networkName); + GameDevice.AllDevices.ForEach(anaDev => { if (anaDev is not CableAnalyser analyser) return; @@ -202,7 +225,7 @@ namespace RemoteControl return result!; } - + [Route(HttpVerbs.Get, "/networks")] public Task> ListNetworks() { @@ -241,6 +264,7 @@ namespace RemoteControl devices.Add(device.ReferenceId, GetDeviceJson(device)); } } + return Task.FromResult>(devices); } } @@ -284,7 +308,9 @@ namespace RemoteControl else { throw HttpException.MethodNotAllowed(); - }; + } + + ; } [Route(HttpVerbs.Patch, "/networks/{networkId}/device/{deviceId}")] @@ -308,17 +334,22 @@ namespace RemoteControl } [Route(HttpVerbs.Get, "/networks/{networkId}/device/{deviceId}/code")] - public UniTask GetCode(string networkId, string deviceId) + public async Task GetCode(string networkId, string deviceId) { var dev = FindUniqueDeviceForHttp(networkId, deviceId); - return UniTask.FromResult(dev.GetSourceCode()); + var code = dev.GetSourceCode(); + HttpContext.Response.ContentType = "text/plain"; + + var codeBytes = Encoding.UTF8.GetBytes(code); + await HttpContext.Response.OutputStream.WriteAsync(codeBytes, 0, codeBytes.Length); } [Route(HttpVerbs.Post, "/networks/{networkId}/device/{deviceId}/code")] - public UniTask SetCode(string networkId, string deviceId, string code) + public async Task SetCode(string networkId, string deviceId) { + var code = await HttpContext.GetRequestBodyAsByteArrayAsync(); var dev = FindUniqueDeviceForHttp(networkId, deviceId); - return UniTask.FromResult(dev.GetSourceCode()); + dev.SetSourceCode(Encoding.UTF8.GetString(code)); } } } \ No newline at end of file