SingletonDeviceNetServerSystem.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. using System.Diagnostics.CodeAnalysis;
  2. using Content.Server.DeviceNetwork.Components;
  3. using Content.Server.Medical.CrewMonitoring;
  4. using Content.Server.Power.Components;
  5. using Content.Server.Station.Systems;
  6. using Content.Shared.Power;
  7. namespace Content.Server.DeviceNetwork.Systems;
  8. /// <summary>
  9. /// Keeps one active server entity per station. Activates another available one if the currently active server becomes unavailable
  10. /// Server in this context means an entity that manages the devicenet packets like the <see cref="Content.Server.Medical.CrewMonitoring.CrewMonitoringServerSystem"/>
  11. /// </summary>
  12. public sealed class SingletonDeviceNetServerSystem : EntitySystem
  13. {
  14. [Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default!;
  15. [Dependency] private readonly StationSystem _stationSystem = default!;
  16. public override void Initialize()
  17. {
  18. base.Initialize();
  19. SubscribeLocalEvent<SingletonDeviceNetServerComponent, PowerChangedEvent>(OnPowerChanged);
  20. }
  21. /// <summary>
  22. /// Returns whether the given entity is an active server or not
  23. /// </summary>
  24. public bool IsActiveServer(EntityUid serverId, SingletonDeviceNetServerComponent? serverComponent = default)
  25. {
  26. return Resolve(serverId, ref serverComponent) && serverComponent.Active;
  27. }
  28. /// <summary>
  29. /// Returns the address of the currently active server for the given station id if there is one.<br/>
  30. /// What kind of server you're trying to get the active instance of is determined by the component type parameter TComp.<br/>
  31. /// <br/>
  32. /// Setting TComp to <see cref="CrewMonitoringServerComponent"/>, for example, gives you the address of an entity containing the crew monitoring server component.<br/>
  33. /// </summary>
  34. /// <param name="stationId">The entityUid of the station</param>
  35. /// <param name="address">The address of the active server if it exists</param>
  36. /// <typeparam name="TComp">The component type that determines what type of server you're getting the address of</typeparam>
  37. /// <returns>True if there is an active serve. False otherwise</returns>
  38. public bool TryGetActiveServerAddress<TComp>(EntityUid stationId, [NotNullWhen(true)] out string? address) where TComp : IComponent
  39. {
  40. var servers = EntityQueryEnumerator<
  41. SingletonDeviceNetServerComponent,
  42. DeviceNetworkComponent,
  43. TComp
  44. >();
  45. (EntityUid id, SingletonDeviceNetServerComponent server, DeviceNetworkComponent device)? last = default;
  46. while (servers.MoveNext(out var uid, out var server, out var device, out _))
  47. {
  48. if (!_stationSystem.GetOwningStation(uid)?.Equals(stationId) ?? true)
  49. continue;
  50. if (!server.Available)
  51. {
  52. DisconnectServer(uid,server, device);
  53. continue;
  54. }
  55. last = (uid, server, device);
  56. if (!server.Active || string.IsNullOrEmpty(device.Address))
  57. continue;
  58. address = device.Address;
  59. return true;
  60. }
  61. //If there was no active server for the station make the last available inactive one active
  62. if (last.HasValue)
  63. {
  64. ConnectServer(last.Value.id, last.Value.server, last.Value.device);
  65. address = last.Value.device.Address;
  66. return true;
  67. }
  68. address = null;
  69. return address != null;
  70. }
  71. /// <summary>
  72. /// Disconnects the server losing power
  73. /// </summary>
  74. private void OnPowerChanged(EntityUid uid, SingletonDeviceNetServerComponent component, ref PowerChangedEvent args)
  75. {
  76. component.Available = args.Powered;
  77. if (!args.Powered && component.Active)
  78. DisconnectServer(uid, component);
  79. }
  80. private void ConnectServer(EntityUid uid, SingletonDeviceNetServerComponent? server = null, DeviceNetworkComponent? device = null)
  81. {
  82. if (!Resolve(uid, ref server, ref device))
  83. return;
  84. server.Active = true;
  85. var connectedEvent = new DeviceNetServerConnectedEvent();
  86. RaiseLocalEvent(uid, ref connectedEvent);
  87. if (_deviceNetworkSystem.IsDeviceConnected(uid, device))
  88. return;
  89. _deviceNetworkSystem.ConnectDevice(uid, device);
  90. }
  91. /// <summary>
  92. /// Disconnects a server from the device network and clears the currently active server
  93. /// </summary>
  94. private void DisconnectServer(EntityUid uid, SingletonDeviceNetServerComponent? server = null, DeviceNetworkComponent? device = null)
  95. {
  96. if (!Resolve(uid, ref server, ref device))
  97. return;
  98. server.Active = false;
  99. var disconnectedEvent = new DeviceNetServerDisconnectedEvent();
  100. RaiseLocalEvent(uid, ref disconnectedEvent);
  101. _deviceNetworkSystem.DisconnectDevice(uid, device, false);
  102. }
  103. }
  104. /// <summary>
  105. /// Raised when a server gets activated and connected to the device net
  106. /// </summary>
  107. [ByRefEvent]
  108. public record struct DeviceNetServerConnectedEvent;
  109. /// <summary>
  110. /// Raised when a server gets disconnected
  111. /// </summary>
  112. [ByRefEvent]
  113. public record struct DeviceNetServerDisconnectedEvent;