diff --git a/Patches/Tick.cs b/Patches/Tick.cs index 09b827b..f3c8cba 100644 --- a/Patches/Tick.cs +++ b/Patches/Tick.cs @@ -17,60 +17,21 @@ namespace RemoteControl.Patches // ReSharper disable once InconsistentNaming public class LogicStack_LogicStackTick { - private struct State - { - internal object LockObj; - internal bool Taken; - } + [UsedImplicitly] - private static void Prefix(out State __state) + private static void Prefix() { - __state = new State - { - LockObj = SubscriptionManager.Lock, - Taken = false - }; - // System.Threading.Monitor.Enter(__state.LockObj, ref __state.Taken); try { - RemoteControl.Log("logic stack tick: start prefix"); RemoteControl.Subscribers.SendUpdate(); - RemoteControl.Log("logic stack tick: end prefix"); } catch (Exception e) { RemoteControl.Log($"prefix: Exception {e}:\n {e.StackTrace}"); } } - - [UsedImplicitly] - private static void Postfix(State __state) - { - try - { - if (!GameManager.RunSimulation) return; - RemoteControl.Log("logic stack tick: start prefix"); - SubscriptionManager.RescanNetworks(); - RemoteControl.Log("logic stack tick: start postfix"); - - } - catch (Exception e) - { - RemoteControl.Log("logic stack tick: start postfix"); - RemoteControl.Log($"postfix: Exception {e}: \n{e.StackTrace}"); - RemoteControl.Log("logic stack tick: end postfix"); - } - finally - { - // if (__state.Taken) - // { - // System.Threading.Monitor.Exit(__state.LockObj); - // } - } - - } } diff --git a/RemoteControl.csproj b/RemoteControl.csproj index 3f58104..7e81263 100644 --- a/RemoteControl.csproj +++ b/RemoteControl.csproj @@ -72,7 +72,7 @@ - + diff --git a/Scripts/LogTimer.cs b/Scripts/LogTimer.cs new file mode 100644 index 0000000..926824f --- /dev/null +++ b/Scripts/LogTimer.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Assets.Scripts; +using Assets.Scripts.Networks; +using Assets.Scripts.Objects.Electrical; +using Assets.Scripts.Objects.Motherboards; +using Assets.Scripts.Util; +using JetBrains.Annotations; +using RemoteControl.Message; +using Swan; +using UnityEngine; +using GameDevice = Assets.Scripts.Objects.Pipes.Device; +// ReSharper disable ClassNeverInstantiated.Global +// ReSharper disable MemberCanBePrivate.Global +namespace RemoteControl +{ + + public class LogTimer : IDisposable + { + private readonly DateTime _startTime = DateTime.Now; + private string _action; + + public LogTimer(string action) + { + RemoteControl.Log($"Beginning {action}"); + _action = action; + } + + public void Dispose() + { + var endTime = DateTime.Now; + var elapsed = endTime - _startTime; + Debug.Log($"Time taken for {_action}: " + elapsed); + } + } +} \ No newline at end of file diff --git a/Scripts/Remotecontrol.cs b/Scripts/Remotecontrol.cs index 2383d6b..154e10a 100644 --- a/Scripts/Remotecontrol.cs +++ b/Scripts/Remotecontrol.cs @@ -204,7 +204,18 @@ namespace RemoteControl } [Route(HttpVerbs.Get, "/networks")] - public Task> ListNetworks() => Task.FromResult(SubscriptionManager.GetProbes()); + public Task> ListNetworks() + { + IList probeNames = new List(); + GameDevice.AllDevices.ForEach(dev => + { + if (dev is CableAnalyser analyser) + { + probeNames.Add(analyser.DisplayName); + } + }); + return Task.FromResult(probeNames); + } [Route(HttpVerbs.Get, "/networks/{networkId}")] public Task> ListDevices(string networkId) diff --git a/Scripts/SubscriptionManager.cs b/Scripts/SubscriptionManager.cs deleted file mode 100644 index 47489c4..0000000 --- a/Scripts/SubscriptionManager.cs +++ /dev/null @@ -1,390 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Assets.Scripts; -using Assets.Scripts.Networks; -using Assets.Scripts.Objects.Electrical; -using Assets.Scripts.Objects.Motherboards; -using Assets.Scripts.Util; -using JetBrains.Annotations; -using RemoteControl.Message; -using Swan; -using UnityEngine; -using GameDevice = Assets.Scripts.Objects.Pipes.Device; -// ReSharper disable ClassNeverInstantiated.Global -// ReSharper disable MemberCanBePrivate.Global -namespace RemoteControl -{ - public class DataNetwork - { - public long ReferenceId { get; private set; } - internal readonly List Probes = new (); - internal CableNetwork Network { get; private set; } - - private readonly HashSet _knownIds = new(); - - - internal readonly Dictionary DeviceCache = new(); - - public DataNetwork(CableNetwork network) - { - - ReferenceId = network.ReferenceId; - Network = network; - } - - internal void RescanNetworkComposition() - { - _knownIds.Clear(); - _knownIds.UnionWith(Network.DataDeviceList.Select(device => device.ReferenceId)); - DeviceCache.Keys.Except(_knownIds).ToList().ForEach(device => DeviceCache.Remove(device)); - - _knownIds.Except(DeviceCache.Keys).ToList().ForEach(device => - { - var newDev = new Device(); - var dev = Referencable.Find(device); - if (dev == null) return; - newDev.ReferenceId = device; - newDev.PrefabHash = dev.PrefabHash; - newDev.PrefabName = dev.PrefabName; - DeviceCache.Add(device, newDev); - }); - UpdateAllDevices(); - } - - private void UpdateAllDevices() - { - foreach (var kvp in DeviceCache) - { - var device = kvp.Value; - var gameObj = Referencable.Find(kvp.Key); - if (gameObj == null) continue; - device.LogicValues.Clear(); - foreach (var type in EnumCollections.LogicTypes.Values) - { - if (gameObj.CanLogicRead(type)) - { - device.LogicValues[type] = gameObj.GetLogicValue(type); - } - } - - var slotCount = gameObj.TotalSlots; - while (device.Slots.Count > slotCount) - { - device.Slots.RemoveAt(device.Slots.Count - 1); - } - for (int slotIndex = 0; slotIndex < slotCount; slotIndex++) - { - if (device.Slots.Count <= slotIndex) - { - device.Slots.Add(new Dictionary()); - } - - foreach (var type in EnumCollections.LogicSlotTypes.Values) - { - if (gameObj.CanLogicRead(type, slotIndex)) - { - device.Slots[slotIndex][type] = gameObj.GetLogicValue(type, slotIndex); - } - } - } - } - } - - - public DataNetwork Reset(CableNetwork cnet) - { - ReferenceId = cnet.ReferenceId; - Network = cnet; - Probes.Clear(); - DeviceCache.Clear(); - _knownIds.Clear(); - return this; - } - } - - public readonly struct LogicUpdate : IEquatable - { - public readonly long TargetReferenceId; - public readonly LogicType LogicType; - - public LogicUpdate(long targetReferenceId, LogicType logicType) - { - TargetReferenceId = targetReferenceId; - LogicType = logicType; - } - - public bool Equals(LogicUpdate other) - { - return TargetReferenceId == other.TargetReferenceId && LogicType == other.LogicType; - } - - public override bool Equals(object obj) - { - return obj is LogicUpdate other && Equals(other); - } - - public override int GetHashCode() - { - return CompositeHashCode.Using(TargetReferenceId, LogicType); - } - } - - public readonly struct SlotUpdate : IEquatable - { - public readonly long ReferenceId; - public readonly int Slot; - public readonly LogicSlotType Type; - - public SlotUpdate(long referenceID, int slot, LogicSlotType type) - { - ReferenceId = referenceID; - Slot = slot; - Type = type; - } - - public bool Equals(SlotUpdate other) - { - return ReferenceId == other.ReferenceId && Slot == other.Slot && Type == other.Type; - } - - public override bool Equals(object obj) - { - return obj is SlotUpdate other && Equals(other); - } - - public override int GetHashCode() - { - return CompositeHashCode.Using(ReferenceId, Slot, Type); - } - } - - public static class SubscriptionManager - { - public static readonly object Lock = new(); - - private static readonly Dictionary DataNetworks = new(); - // private Dictionary> _probesByName = new(); - // private Dictionary _probesById = new(); - private static readonly Dictionary PendingUpdates = new(); - private static readonly Dictionary PendingSlotUpdates = new(); - - [CanBeNull] - public static Device FindCachedDevice(string probeName, long referenceID) - { - foreach (var analyzer in GetDataNetwork(probeName)) - { - if (analyzer.DeviceCache.TryGetValue(referenceID, out var device)) - { - return device; - } - } - - return null; - } - - // Can be called from any thread - public static bool SetLogic(string probeName, long referenceID, LogicType type, double value) - { - // lock (Lock) - { - var dev = FindCachedDevice(probeName, referenceID); - if (dev == null) - { - return false; - } - - dev.LogicValues[type] = value; - PendingUpdates[new LogicUpdate(referenceID, type)] = value; - } - - return true; - } - - // Can be called from any thread - public static bool SetSlot(string probeName, long referenceID, int slot, LogicSlotType type, double value) - { - // lock (Lock) - { - - var dev = FindCachedDevice(probeName, referenceID); - if (dev != null && dev.Slots.Count > slot && dev.Slots[slot].ContainsKey(type)) - { - dev.Slots[slot][type] = value; - PendingSlotUpdates[new SlotUpdate(referenceID, slot, type)] = value; - return true; - } - else - { - return false; - } - } - - } - - public static DataNetwork GetDataNetwork(CableNetwork network) - { - if (DataNetworks.TryGetValue(network.ReferenceId, out var dataNetwork)) - { - return dataNetwork; - } - else - { - var ret = new DataNetwork(network); - DataNetworks.Add(network.ReferenceId, ret); - return ret; - } - } - - public static IEnumerable GetDataNetwork(string probeName) - { - // lock (Lock) - { - List networks = new(); - GameDevice.AllDevices.ForEach(dev => - { - if (dev is CableAnalyser analyzer) - { - networks.Add(GetDataNetwork(analyzer.CableNetwork)); - } - }); - return networks; - } - } - - - public static GameDevice GetDevice(long referenceID) - { - var device = Referencable.Find(referenceID); - if (!DataNetworks.Values.Any((item) => item.Network.DataDeviceList.Contains(device))) - return null; - return device; - - } - - public static GameDevice GetDevice(string probeName, long referenceID) - { - var device = Referencable.Find(referenceID); - if (GetDataNetwork(probeName).Any(network => network.DeviceCache.ContainsKey(referenceID))) - { - return device; - } - return null; - } - - /// - /// Called from Unity thread pool before the logic tick - /// - /// - public static void ApplyUpdates() - { - lock (Lock) - { - foreach (var update in PendingUpdates) - { - var device = GetDevice(update.Key.TargetReferenceId); - - if (!device.CanLogicWrite(update.Key.LogicType)) - { - device.SetLogicValue(update.Key.LogicType, update.Value); - } - } - - foreach (var update in PendingSlotUpdates) - { - var device = Referencable.Find(update.Key.ReferenceId); - if (!DataNetworks.Values.Any((item) => item.Network.DataDeviceList.Contains(device))) - continue; - - if (!device.CanLogicWrite(update.Key.Type, update.Key.Slot)) - { - device.SetLogicValue(update.Key.Type, update.Key.Slot, update.Value); - } - } - - PendingUpdates.Clear(); - PendingSlotUpdates.Clear(); - } - } - - public static void RescanNetworks() - { - using (new LogTimer("RescanNetworks")) - { - HashSet scannedAnalyzers = new(); - HashSet scannedNetworks = new(); - - scannedNetworks.Clear(); - GameDevice.AllDevices.ForEach(dev => - { - if (dev is CableAnalyser analyser) - { - scannedAnalyzers.Add(analyser); - scannedNetworks.Add(analyser.CableNetwork); - } - }); - - var removed = - new List(DataNetworks.Values.Where(dataNetwork => - !scannedNetworks.Contains(dataNetwork.Network))); - foreach (var dataNet in removed) - { - DataNetworks.Remove(dataNet.ReferenceId); - } - - foreach (var dataNet in DataNetworks.Values) - { - dataNet.Probes.Clear(); - } - - foreach (var analyzer in scannedAnalyzers) - { - if (DataNetworks.ContainsKey(analyzer.ReferenceId)) continue; - - var dataNet = removed.Pop()?.Reset(analyzer.CableNetwork) ?? new DataNetwork(analyzer.CableNetwork); - dataNet.Probes.Add(analyzer); - } - - - // TODO: when we have our own device for tagging a network, make this triggered by on the DataNetworkChange method - foreach (var dataNet in DataNetworks.Values) - { - dataNet.RescanNetworkComposition(); - } - } - } - - public static IList GetProbes() - { - List probes = new(); - GameDevice.AllDevices.ForEach(dev => - { - if (dev is CableAnalyser) - { - probes.Add(dev.DisplayName); - } - }); - return probes; - } - - } - - public class LogTimer : IDisposable - { - private readonly DateTime _startTime = DateTime.Now; - private string _action; - - public LogTimer(string action) - { - RemoteControl.Log($"Beginning {action}"); - _action = action; - } - - public void Dispose() - { - var endTime = DateTime.Now; - var elapsed = endTime - _startTime; - Debug.Log($"Time taken for {_action}: " + elapsed); - } - } -} \ No newline at end of file