ScreenSystem.cs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. using Content.Shared.TextScreen;
  2. using Content.Server.Screens.Components;
  3. using Content.Server.DeviceNetwork.Components;
  4. using Content.Server.DeviceNetwork.Systems;
  5. using Robust.Shared.Timing;
  6. namespace Content.Server.Screens.Systems;
  7. /// <summary>
  8. /// Controls the wallmounted screens on stations and shuttles displaying e.g. FTL duration, ETA
  9. /// </summary>
  10. public sealed class ScreenSystem : EntitySystem
  11. {
  12. [Dependency] private readonly IGameTiming _gameTiming = default!;
  13. [Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
  14. public override void Initialize()
  15. {
  16. base.Initialize();
  17. SubscribeLocalEvent<ScreenComponent, DeviceNetworkPacketEvent>(OnPacketReceived);
  18. }
  19. /// <summary>
  20. /// Calls either a normal screen text update or shuttle timer update based on the presence of
  21. /// <see cref="ShuttleTimerMasks.ShuttleMap"/> in <see cref="args.Data"/>
  22. /// </summary>
  23. private void OnPacketReceived(EntityUid uid, ScreenComponent component, DeviceNetworkPacketEvent args)
  24. {
  25. if (args.Data.TryGetValue(ShuttleTimerMasks.ShuttleMap, out _))
  26. ShuttleTimer(uid, component, args);
  27. else
  28. ScreenText(uid, component, args);
  29. }
  30. /// <summary>
  31. /// Send a text update to every screen on the same MapUid as the originating comms console.
  32. /// </summary>
  33. private void ScreenText(EntityUid uid, ScreenComponent component, DeviceNetworkPacketEvent args)
  34. {
  35. // don't allow text updates if there's an active timer
  36. // (and just check here so the server doesn't have to track them)
  37. if (_appearanceSystem.TryGetData(uid, TextScreenVisuals.TargetTime, out TimeSpan target)
  38. && target > _gameTiming.CurTime)
  39. return;
  40. var screenMap = Transform(uid).MapUid;
  41. var argsMap = Transform(args.Sender).MapUid;
  42. if (screenMap != null
  43. && argsMap != null
  44. && screenMap == argsMap
  45. && args.Data.TryGetValue(ScreenMasks.Text, out string? text)
  46. && text != null
  47. )
  48. {
  49. _appearanceSystem.SetData(uid, TextScreenVisuals.DefaultText, text);
  50. _appearanceSystem.SetData(uid, TextScreenVisuals.ScreenText, text);
  51. }
  52. }
  53. /// <summary>
  54. /// Determines if/how a timer packet affects this screen.
  55. /// Currently there are 2 broadcast domains: Arrivals, and every other screen.
  56. /// Domain is determined by the <see cref="DeviceNetworkComponent.TransmitFrequencyId"/> on each timer.
  57. /// Each broadcast domain is divided into subnets. Screen MapUid determines subnet.
  58. /// Subnets are the shuttle, source, and dest. Source/dest change each jump.
  59. /// This is required to send different timers to the shuttle/terminal/station.
  60. /// </summary>
  61. private void ShuttleTimer(EntityUid uid, ScreenComponent component, DeviceNetworkPacketEvent args)
  62. {
  63. var timerXform = Transform(uid);
  64. // no false positives.
  65. if (timerXform.MapUid == null)
  66. return;
  67. string key;
  68. args.Data.TryGetValue(ShuttleTimerMasks.ShuttleMap, out EntityUid? shuttleMap);
  69. args.Data.TryGetValue(ShuttleTimerMasks.SourceMap, out EntityUid? source);
  70. args.Data.TryGetValue(ShuttleTimerMasks.DestMap, out EntityUid? dest);
  71. args.Data.TryGetValue(ShuttleTimerMasks.Docked, out bool docked);
  72. string text = docked ? ShuttleTimerMasks.ETD : ShuttleTimerMasks.ETA;
  73. switch (timerXform.MapUid)
  74. {
  75. // sometimes the timer transforms on FTL shuttles have a hyperspace mapuid, so matching by grid works as a fallback.
  76. case var local when local == shuttleMap || timerXform.GridUid == shuttleMap:
  77. key = ShuttleTimerMasks.ShuttleTime;
  78. break;
  79. case var origin when origin == source:
  80. key = ShuttleTimerMasks.SourceTime;
  81. break;
  82. case var remote when remote == dest:
  83. key = ShuttleTimerMasks.DestTime;
  84. text = ShuttleTimerMasks.ETA;
  85. break;
  86. default:
  87. return;
  88. }
  89. if (!args.Data.TryGetValue(key, out TimeSpan duration))
  90. return;
  91. if (args.Data.TryGetValue(ScreenMasks.Text, out string? label) && label != null)
  92. text = label;
  93. _appearanceSystem.SetData(uid, TextScreenVisuals.ScreenText, text);
  94. _appearanceSystem.SetData(uid, TextScreenVisuals.TargetTime, _gameTiming.CurTime + duration);
  95. if (args.Data.TryGetValue(ScreenMasks.Color, out Color color))
  96. _appearanceSystem.SetData(uid, TextScreenVisuals.Color, color);
  97. }
  98. }