RoboticsConsoleSystem.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. using Content.Server.Administration.Logs;
  2. using Content.Server.DeviceNetwork;
  3. using Content.Server.DeviceNetwork.Systems;
  4. using Content.Server.Radio.EntitySystems;
  5. using Content.Shared.Lock;
  6. using Content.Shared.Database;
  7. using Content.Shared.DeviceNetwork;
  8. using Content.Shared.Robotics;
  9. using Content.Shared.Robotics.Components;
  10. using Content.Shared.Robotics.Systems;
  11. using Robust.Server.GameObjects;
  12. using Robust.Shared.Timing;
  13. using System.Diagnostics.CodeAnalysis;
  14. namespace Content.Server.Research.Systems;
  15. /// <summary>
  16. /// Handles UI and state receiving for the robotics control console.
  17. /// <c>BorgTransponderComponent<c/> broadcasts state from the station's borgs to consoles.
  18. /// </summary>
  19. public sealed class RoboticsConsoleSystem : SharedRoboticsConsoleSystem
  20. {
  21. [Dependency] private readonly DeviceNetworkSystem _deviceNetwork = default!;
  22. [Dependency] private readonly IAdminLogManager _adminLogger = default!;
  23. [Dependency] private readonly IGameTiming _timing = default!;
  24. [Dependency] private readonly LockSystem _lock = default!;
  25. [Dependency] private readonly RadioSystem _radio = default!;
  26. [Dependency] private readonly UserInterfaceSystem _ui = default!;
  27. // almost never timing out more than 1 per tick so initialize with that capacity
  28. private List<string> _removing = new(1);
  29. public override void Initialize()
  30. {
  31. base.Initialize();
  32. SubscribeLocalEvent<RoboticsConsoleComponent, DeviceNetworkPacketEvent>(OnPacketReceived);
  33. Subs.BuiEvents<RoboticsConsoleComponent>(RoboticsConsoleUiKey.Key, subs =>
  34. {
  35. subs.Event<BoundUIOpenedEvent>(OnOpened);
  36. subs.Event<RoboticsConsoleDisableMessage>(OnDisable);
  37. subs.Event<RoboticsConsoleDestroyMessage>(OnDestroy);
  38. // TODO: camera stuff
  39. });
  40. }
  41. public override void Update(float frameTime)
  42. {
  43. base.Update(frameTime);
  44. var now = _timing.CurTime;
  45. var query = EntityQueryEnumerator<RoboticsConsoleComponent>();
  46. while (query.MoveNext(out var uid, out var comp))
  47. {
  48. // remove cyborgs that havent pinged in a while
  49. _removing.Clear();
  50. foreach (var (address, data) in comp.Cyborgs)
  51. {
  52. if (now >= data.Timeout)
  53. _removing.Add(address);
  54. }
  55. // needed to prevent modifying while iterating it
  56. foreach (var address in _removing)
  57. {
  58. comp.Cyborgs.Remove(address);
  59. }
  60. if (_removing.Count > 0)
  61. UpdateUserInterface((uid, comp));
  62. }
  63. }
  64. private void OnPacketReceived(Entity<RoboticsConsoleComponent> ent, ref DeviceNetworkPacketEvent args)
  65. {
  66. var payload = args.Data;
  67. if (!payload.TryGetValue(DeviceNetworkConstants.Command, out string? command))
  68. return;
  69. if (command != DeviceNetworkConstants.CmdUpdatedState)
  70. return;
  71. if (!payload.TryGetValue(RoboticsConsoleConstants.NET_CYBORG_DATA, out CyborgControlData? data))
  72. return;
  73. var real = data.Value;
  74. real.Timeout = _timing.CurTime + ent.Comp.Timeout;
  75. ent.Comp.Cyborgs[args.SenderAddress] = real;
  76. UpdateUserInterface(ent);
  77. }
  78. private void OnOpened(Entity<RoboticsConsoleComponent> ent, ref BoundUIOpenedEvent args)
  79. {
  80. UpdateUserInterface(ent);
  81. }
  82. private void OnDisable(Entity<RoboticsConsoleComponent> ent, ref RoboticsConsoleDisableMessage args)
  83. {
  84. if (_lock.IsLocked(ent.Owner))
  85. return;
  86. if (!ent.Comp.Cyborgs.TryGetValue(args.Address, out var data))
  87. return;
  88. var payload = new NetworkPayload()
  89. {
  90. [DeviceNetworkConstants.Command] = RoboticsConsoleConstants.NET_DISABLE_COMMAND
  91. };
  92. _deviceNetwork.QueuePacket(ent, args.Address, payload);
  93. _adminLogger.Add(LogType.Action, LogImpact.High, $"{ToPrettyString(args.Actor):user} disabled borg {data.Name} with address {args.Address}");
  94. }
  95. private void OnDestroy(Entity<RoboticsConsoleComponent> ent, ref RoboticsConsoleDestroyMessage args)
  96. {
  97. if (_lock.IsLocked(ent.Owner))
  98. return;
  99. var now = _timing.CurTime;
  100. if (now < ent.Comp.NextDestroy)
  101. return;
  102. if (!ent.Comp.Cyborgs.Remove(args.Address, out var data))
  103. return;
  104. var payload = new NetworkPayload()
  105. {
  106. [DeviceNetworkConstants.Command] = RoboticsConsoleConstants.NET_DESTROY_COMMAND
  107. };
  108. _deviceNetwork.QueuePacket(ent, args.Address, payload);
  109. var message = Loc.GetString(ent.Comp.DestroyMessage, ("name", data.Name));
  110. _radio.SendRadioMessage(ent, message, ent.Comp.RadioChannel, ent);
  111. _adminLogger.Add(LogType.Action, LogImpact.Extreme, $"{ToPrettyString(args.Actor):user} destroyed borg {data.Name} with address {args.Address}");
  112. ent.Comp.NextDestroy = now + ent.Comp.DestroyCooldown;
  113. Dirty(ent, ent.Comp);
  114. }
  115. private void UpdateUserInterface(Entity<RoboticsConsoleComponent> ent)
  116. {
  117. var state = new RoboticsConsoleState(ent.Comp.Cyborgs);
  118. _ui.SetUiState(ent.Owner, RoboticsConsoleUiKey.Key, state);
  119. }
  120. }