using Content.Server.DeviceNetwork; using Content.Server.DeviceNetwork.Components; using Content.Server.DeviceNetwork.Systems; using Content.Server.Medical.SuitSensors; using Content.Shared.DeviceNetwork; using Content.Shared.Medical.SuitSensor; using Robust.Shared.Timing; namespace Content.Server.Medical.CrewMonitoring; public sealed class CrewMonitoringServerSystem : EntitySystem { [Dependency] private readonly SuitSensorSystem _sensors = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default!; [Dependency] private readonly SingletonDeviceNetServerSystem _singletonServerSystem = default!; private const float UpdateRate = 3f; private float _updateDiff; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnRemove); SubscribeLocalEvent(OnPacketReceived); SubscribeLocalEvent(OnDisconnected); } public override void Update(float frameTime) { base.Update(frameTime); // check update rate _updateDiff += frameTime; if (_updateDiff < UpdateRate) return; _updateDiff -= UpdateRate; var servers = EntityQueryEnumerator(); while (servers.MoveNext(out var id, out var server)) { if (!_singletonServerSystem.IsActiveServer(id)) continue; UpdateTimeout(id); BroadcastSensorStatus(id, server); } } /// /// Adds or updates a sensor status entry if the received package is a sensor status update /// private void OnPacketReceived(EntityUid uid, CrewMonitoringServerComponent component, DeviceNetworkPacketEvent args) { var sensorStatus = _sensors.PacketToSuitSensor(args.Data); if (sensorStatus == null) return; sensorStatus.Timestamp = _gameTiming.CurTime; component.SensorStatus[args.SenderAddress] = sensorStatus; } /// /// Clears the servers sensor status list /// private void OnRemove(EntityUid uid, CrewMonitoringServerComponent component, ComponentRemove args) { component.SensorStatus.Clear(); } /// /// Drop the sensor status if it hasn't been updated for to long /// private void UpdateTimeout(EntityUid uid, CrewMonitoringServerComponent? component = null) { if (!Resolve(uid, ref component)) return; foreach (var (address, sensor) in component.SensorStatus) { var dif = _gameTiming.CurTime - sensor.Timestamp; if (dif.Seconds > component.SensorTimeout) component.SensorStatus.Remove(address); } } /// /// Broadcasts the status of all connected sensors /// private void BroadcastSensorStatus(EntityUid uid, CrewMonitoringServerComponent? serverComponent = null, DeviceNetworkComponent? device = null) { if (!Resolve(uid, ref serverComponent, ref device)) return; var payload = new NetworkPayload() { [DeviceNetworkConstants.Command] = DeviceNetworkConstants.CmdUpdatedState, [SuitSensorConstants.NET_STATUS_COLLECTION] = serverComponent.SensorStatus }; _deviceNetworkSystem.QueuePacket(uid, null, payload, device: device); } /// /// Clears sensor data on disconnect /// private void OnDisconnected(EntityUid uid, CrewMonitoringServerComponent component, ref DeviceNetServerDisconnectedEvent _) { component.SensorStatus.Clear(); } }