Files
Stationeers-RemoteControl/Scripts/SubscriptionModule.cs
2026-01-15 00:02:26 +01:00

139 lines
4.8 KiB
C#

using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Assets.Scripts;
using Assets.Scripts.Objects.Electrical;
using Assets.Scripts.Objects.Motherboards;
using EmbedIO.WebSockets;
using RemoteControl.Message;
using Swan;
using Swan.Diagnostics;
using GameDevice = Assets.Scripts.Objects.Pipes.Device;
namespace RemoteControl
{
internal class SubscriptionModule: WebSocketModule
{
private HashSet<IWebSocketContext> _jsonSubscribers = new();
public void SendUpdate(Message.Update update)
{
if (_jsonSubscribers.Count > 0)
{
var encoded = System.Text.Encoding.UTF8.GetBytes(update.ToJson());
foreach (var webSocketContext in _jsonSubscribers)
{
_ = SendAsync(webSocketContext, encoded);
}
}
}
public SubscriptionModule(string urlPath, bool enableConnectionWatchdog = true) : base(urlPath, enableConnectionWatchdog)
{
}
protected override Task OnMessageReceivedAsync(IWebSocketContext context, byte[] buffer, IWebSocketReceiveResult result)
{
return Task.CompletedTask;
}
protected override Task OnClientConnectedAsync(IWebSocketContext context)
{
_jsonSubscribers.Add(context);
return base.OnClientConnectedAsync(context);
}
protected override Task OnClientDisconnectedAsync(IWebSocketContext context)
{
_jsonSubscribers.Remove(context);
return base.OnClientDisconnectedAsync(context);
}
internal static Update GetUpdate()
{
Dictionary<long, Device> cache = new();
Dictionary<long, Message.Network> networks = new();
// lock (SubscriptionManager.Lock)
var timer = new HighResolutionTimer();
timer.Start();
GameDevice.AllDevices.ForEach(dev =>
{
if (dev is CableAnalyser analyser)
{
var network = networks.GetOrAdd(analyser.CableNetwork.ReferenceId, (long _) => new Message.Network
{
ReferenceId = analyser.CableNetwork.ReferenceId,
Devices = analyser.CableNetwork.DeviceList
.Select(subdev => cache.GetOrAdd(subdev.ReferenceId, _ => new Device(subdev)))
.ToList()
});
network.Probes.Add(analyser.DisplayName);
}
});
Update update = new()
{
Networks = networks.Values.ToList(),
CalculationTime = timer.ElapsedMicroseconds,
};
return update;
}
internal void SendUpdate()
{
SendUpdate(GetUpdate());
}
}
namespace Message
{
public class Update
{
public long CalculationTime { get; set; }
public List<Network> Networks { get; set; } = new();
}
public class Network
{
public long ReferenceId { get; set; }
public List<string> Probes { get; set; } = new();
public List<Device> Devices { get; set; } = new();
}
public class Device
{
public Device() {}
public Device(GameDevice device)
{
ReferenceId = device.ReferenceId;
Name = device.DisplayName;
NameHash = device.GetNameHash();
PrefabHash = device.PrefabHash;
PrefabName = device.PrefabName;
LogicValues = EnumCollections.LogicTypes.Values.Where(device.CanLogicRead)
.ToDictionary(ty => ty, device.GetLogicValue);
Slots = Enumerable.Range(0, device.TotalSlots)
.Select(slot => EnumCollections.LogicSlotTypes.Values.Where(sty => device.CanLogicRead(sty, slot))
.ToDictionary(ty => ty, sty => device.GetLogicValue(sty, slot)))
.ToList();
IsCircuitHolder = device is ICircuitHolder;
}
public long ReferenceId { get; set; }
public long NameHash{ get; set; }
public string Name{ get; set; }
public long PrefabHash{ get; set; }
public string PrefabName{ get; set; }
public Dictionary<LogicType, double> LogicValues { get; set; } = new();
public List<Dictionary<LogicSlotType, double>> Slots { get; set; }= new();
public bool IsCircuitHolder { get; set; }
}
}
}