--- /dev/null
+using Content.Server.DeviceNetwork.Systems;
+
+namespace Content.Server.DeviceNetwork.Components;
+
+[RegisterComponent]
+[Access(typeof(SingletonDeviceNetServerSystem))]
+public sealed partial class SingletonDeviceNetServerComponent : Component
+{
+ /// <summary>
+ /// Whether the server can become the currently active server. The server being unavailable usually means that it isn't powered
+ /// </summary>
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public bool Available = true;
+
+ /// <summary>
+ /// Whether the server is the currently active server for the station it's on
+ /// </summary>
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public bool Active = true;
+}
--- /dev/null
+using Content.Server.DeviceNetwork.Components;
+using Content.Server.Medical.CrewMonitoring;
+using Content.Server.Power.Components;
+using Content.Server.Station.Systems;
+
+namespace Content.Server.DeviceNetwork.Systems;
+
+/// <summary>
+/// Keeps one active server entity per station. Activates another available one if the currently active server becomes unavailable
+/// Server in this context means an entity that manages the devicenet packets like the <see cref="Content.Server.Medical.CrewMonitoring.CrewMonitoringServerSystem"/>
+/// </summary>
+public sealed class SingletonDeviceNetServerSystem : EntitySystem
+{
+ [Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default!;
+ [Dependency] private readonly StationSystem _stationSystem = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent<SingletonDeviceNetServerComponent, PowerChangedEvent>(OnPowerChanged);
+ }
+
+ /// <summary>
+ /// Returns whether the given entity is an active server or not
+ /// </summary>
+ public bool IsActiveServer(EntityUid serverId, SingletonDeviceNetServerComponent? serverComponent = default)
+ {
+ return Resolve(serverId, ref serverComponent) && serverComponent.Active;
+ }
+
+ /// <summary>
+ /// Returns the address of the currently active server for the given station id if there is one.<br/>
+ /// What kind of server you're trying to get the active instance of is determined by the component type parameter TComp.<br/>
+ /// <br/>
+ /// Setting TComp to <see cref="CrewMonitoringServerComponent"/>, for example, gives you the address of an entity containing the crew monitoring server component.<br/>
+ /// </summary>
+ /// <param name="stationId">The entityUid of the station</param>
+ /// <param name="address">The address of the active server if it exists</param>
+ /// <typeparam name="TComp">The component type that determines what type of server you're getting the address of</typeparam>
+ /// <returns>True if there is an active serve. False otherwise</returns>
+ public bool TryGetActiveServerAddress<TComp>(EntityUid stationId, out string? address) where TComp : IComponent
+ {
+ var servers = EntityQueryEnumerator<
+ SingletonDeviceNetServerComponent,
+ DeviceNetworkComponent,
+ TComp
+ >();
+
+ (EntityUid id, SingletonDeviceNetServerComponent server, DeviceNetworkComponent device)? last = default;
+
+ while (servers.MoveNext(out var uid, out var server, out var device, out _))
+ {
+ if (!_stationSystem.GetOwningStation(uid)?.Equals(stationId) ?? true)
+ continue;
+
+ if (!server.Available)
+ {
+ DisconnectServer(uid,server, device);
+ continue;
+ }
+
+ last = (uid, server, device);
+
+ if (!server.Active)
+ continue;
+
+ address = device.Address;
+ return true;
+ }
+
+ //If there was no active server for the station make the last available inactive one active
+ if (last.HasValue)
+ {
+ ConnectServer(last.Value.id, last.Value.server, last.Value.device);
+ address = last.Value.device.Address;
+ return true;
+ }
+
+ address = null;
+ return address != null;
+ }
+
+ /// <summary>
+ /// Disconnects the server losing power
+ /// </summary>
+ private void OnPowerChanged(EntityUid uid, SingletonDeviceNetServerComponent component, ref PowerChangedEvent args)
+ {
+ component.Available = args.Powered;
+
+ if (!args.Powered && component.Active)
+ DisconnectServer(uid, component);
+ }
+
+ private void ConnectServer(EntityUid uid, SingletonDeviceNetServerComponent? server = null, DeviceNetworkComponent? device = null)
+ {
+ if (!Resolve(uid, ref server, ref device))
+ return;
+
+ server.Active = true;
+
+ var connectedEvent = new DeviceNetServerConnectedEvent();
+ RaiseLocalEvent(uid, ref connectedEvent);
+
+ if (_deviceNetworkSystem.IsDeviceConnected(uid, device))
+ return;
+
+ _deviceNetworkSystem.ConnectDevice(uid, device);
+ }
+
+ /// <summary>
+ /// Disconnects a server from the device network and clears the currently active server
+ /// </summary>
+ private void DisconnectServer(EntityUid uid, SingletonDeviceNetServerComponent? server = null, DeviceNetworkComponent? device = null)
+ {
+ if (!Resolve(uid, ref server, ref device))
+ return;
+
+ server.Active = false;
+
+ var disconnectedEvent = new DeviceNetServerDisconnectedEvent();
+ RaiseLocalEvent(uid, ref disconnectedEvent);
+
+ _deviceNetworkSystem.DisconnectDevice(uid, device, false);
+ }
+}
+
+/// <summary>
+/// Raised when a server gets activated and connected to the device net
+/// </summary>
+[ByRefEvent]
+public record struct DeviceNetServerConnectedEvent;
+
+/// <summary>
+/// Raised when a server gets disconnected
+/// </summary>
+[ByRefEvent]
+public record struct DeviceNetServerDisconnectedEvent;
/// </summary>
[DataField("sensorTimeout"), ViewVariables(VVAccess.ReadWrite)]
public float SensorTimeout = 10f;
-
- /// <summary>
- /// Whether the server can become the currently active server. The server being unavailable usually means that it isn't powered
- /// </summary>
- [ViewVariables(VVAccess.ReadWrite)]
- public bool Available = true;
-
-
- /// <summary>
- /// Whether the server is the currently active server for the station it's on
- /// </summary>
- [ViewVariables(VVAccess.ReadWrite)]
- public bool Active = true;
}
using Content.Server.DeviceNetwork.Components;
using Content.Server.DeviceNetwork.Systems;
using Content.Server.Medical.SuitSensors;
-using Content.Server.Power.Components;
-using Content.Server.Station.Systems;
using Content.Shared.DeviceNetwork;
using Content.Shared.Medical.SuitSensor;
using Robust.Shared.Timing;
[Dependency] private readonly SuitSensorSystem _sensors = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default!;
- [Dependency] private readonly StationSystem _stationSystem = default!;
+ [Dependency] private readonly SingletonDeviceNetServerSystem _singletonServerSystem = default!;
private const float UpdateRate = 3f;
private float _updateDiff;
base.Initialize();
SubscribeLocalEvent<CrewMonitoringServerComponent, ComponentRemove>(OnRemove);
SubscribeLocalEvent<CrewMonitoringServerComponent, DeviceNetworkPacketEvent>(OnPacketReceived);
- SubscribeLocalEvent<CrewMonitoringServerComponent, PowerChangedEvent>(OnPowerChanged);
+ SubscribeLocalEvent<CrewMonitoringServerComponent, DeviceNetServerDisconnectedEvent>(OnDisconnected);
}
public override void Update(float frameTime)
_updateDiff -= UpdateRate;
var servers = EntityQueryEnumerator<CrewMonitoringServerComponent>();
- List<EntityUid> activeServers = new();
while (servers.MoveNext(out var id, out var server))
{
- //Make sure the server is disconnected when it becomes unavailable
- if (!server.Available)
- {
- if (server.Active)
- DisconnectServer(id, server);
-
- continue;
- }
-
- if (!server.Active)
- continue;
-
- activeServers.Add(id);
- }
-
- foreach (var activeServer in activeServers)
- {
- UpdateTimeout(activeServer);
- BroadcastSensorStatus(activeServer);
- }
- }
-
- /// <summary>
- /// Returns the address of the currently active server for the given station id if there is one
- /// </summary>
- public bool TryGetActiveServerAddress(EntityUid stationId, out string? address)
- {
- var servers = EntityQueryEnumerator<CrewMonitoringServerComponent, DeviceNetworkComponent>();
- (EntityUid id, CrewMonitoringServerComponent server, DeviceNetworkComponent device)? last = default;
-
- while (servers.MoveNext(out var uid, out var server, out var device))
- {
- if (!_stationSystem.GetOwningStation(uid)?.Equals(stationId) ?? true)
- continue;
-
- if (!server.Available)
- {
- DisconnectServer(uid,server, device);
+ if (!_singletonServerSystem.IsActiveServer(id))
continue;
- }
-
- last = (uid, server, device);
-
- if (server.Active)
- {
- address = device.Address;
- return true;
- }
- }
- //If there was no active server for the station make the last available inactive one active
- if (last.HasValue)
- {
- ConnectServer(last.Value.id, last.Value.server, last.Value.device);
- address = last.Value.device.Address;
- return true;
+ UpdateTimeout(id);
+ BroadcastSensorStatus(id, server);
}
-
- address = null;
- return address != null;
}
/// <summary>
component.SensorStatus.Clear();
}
- /// <summary>
- /// Disconnects the server losing power
- /// </summary>
- private void OnPowerChanged(EntityUid uid, CrewMonitoringServerComponent component, ref PowerChangedEvent args)
- {
- component.Available = args.Powered;
-
- if (!args.Powered)
- DisconnectServer(uid, component);
- }
-
/// <summary>
/// Drop the sensor status if it hasn't been updated for to long
/// </summary>
_deviceNetworkSystem.QueuePacket(uid, null, payload, device: device);
}
- private void ConnectServer(EntityUid uid, CrewMonitoringServerComponent? server = null, DeviceNetworkComponent? device = null)
- {
- if (!Resolve(uid, ref server, ref device))
- return;
-
- server.Active = true;
-
- if (_deviceNetworkSystem.IsDeviceConnected(uid, device))
- return;
-
- _deviceNetworkSystem.ConnectDevice(uid, device);
- }
-
/// <summary>
- /// Disconnects a server from the device network and clears the currently active server
+ /// Clears sensor data on disconnect
/// </summary>
- private void DisconnectServer(EntityUid uid, CrewMonitoringServerComponent? server = null, DeviceNetworkComponent? device = null)
+ private void OnDisconnected(EntityUid uid, CrewMonitoringServerComponent component, ref DeviceNetServerDisconnectedEvent _)
{
- if (!Resolve(uid, ref server, ref device))
- return;
-
- server.SensorStatus.Clear();
- server.Active = false;
-
- _deviceNetworkSystem.DisconnectDevice(uid, device, false);
+ component.SensorStatus.Clear();
}
}
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly StationSystem _stationSystem = default!;
+ [Dependency] private readonly SingletonDeviceNetServerSystem _singletonServerSystem = default!;
public override void Initialize()
{
//Retrieve active server address if the sensor isn't connected to a server
if (sensor.ConnectedServer == null)
{
- if (!_monitoringServerSystem.TryGetActiveServerAddress(sensor.StationId!.Value, out var address))
+ if (!_singletonServerSystem.TryGetActiveServerAddress<CrewMonitoringServerComponent>(sensor.StationId!.Value, out var address))
continue;
sensor.ConnectedServer = address;
machine_board: !type:Container
machine_parts: !type:Container
- type: CrewMonitoringServer
+ - type: SingletonDeviceNetServer
+ ServerType: CrewMonitoringServer
- type: DeviceNetwork
deviceNetId: Wireless
transmitFrequencyId: CrewMonitor