SurveillanceCameraMicrophoneSystem.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. using Content.Server.Chat.Systems;
  2. using Content.Server.Speech;
  3. using Content.Server.Speech.Components;
  4. using Content.Shared.Whitelist;
  5. using Robust.Shared.Player;
  6. using static Content.Server.Chat.Systems.ChatSystem;
  7. namespace Content.Server.SurveillanceCamera;
  8. public sealed class SurveillanceCameraMicrophoneSystem : EntitySystem
  9. {
  10. [Dependency] private readonly SharedTransformSystem _xforms = default!;
  11. [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
  12. public override void Initialize()
  13. {
  14. base.Initialize();
  15. SubscribeLocalEvent<SurveillanceCameraMicrophoneComponent, ComponentInit>(OnInit);
  16. SubscribeLocalEvent<SurveillanceCameraMicrophoneComponent, ListenEvent>(RelayEntityMessage);
  17. SubscribeLocalEvent<SurveillanceCameraMicrophoneComponent, ListenAttemptEvent>(CanListen);
  18. SubscribeLocalEvent<ExpandICChatRecipientsEvent>(OnExpandRecipients);
  19. }
  20. private void OnExpandRecipients(ExpandICChatRecipientsEvent ev)
  21. {
  22. var xformQuery = GetEntityQuery<TransformComponent>();
  23. var sourceXform = Transform(ev.Source);
  24. var sourcePos = _xforms.GetWorldPosition(sourceXform, xformQuery);
  25. // This function ensures that chat popups appear on camera views that have connected microphones.
  26. foreach (var (_, __, camera, xform) in EntityQuery<SurveillanceCameraMicrophoneComponent, ActiveListenerComponent, SurveillanceCameraComponent, TransformComponent>())
  27. {
  28. if (camera.ActiveViewers.Count == 0)
  29. continue;
  30. // get range to camera. This way wispers will still appear as obfuscated if they are too far from the camera's microphone
  31. var range = (xform.MapID != sourceXform.MapID)
  32. ? -1
  33. : (sourcePos - _xforms.GetWorldPosition(xform, xformQuery)).Length();
  34. if (range < 0 || range > ev.VoiceRange)
  35. continue;
  36. foreach (var viewer in camera.ActiveViewers)
  37. {
  38. // if the player has not already received the chat message, send it to them but don't log it to the chat
  39. // window. This is simply so that it appears in camera.
  40. if (TryComp(viewer, out ActorComponent? actor))
  41. ev.Recipients.TryAdd(actor.PlayerSession, new ICChatRecipientData(range, false, true));
  42. }
  43. }
  44. }
  45. private void OnInit(EntityUid uid, SurveillanceCameraMicrophoneComponent component, ComponentInit args)
  46. {
  47. if (component.Enabled)
  48. EnsureComp<ActiveListenerComponent>(uid).Range = component.Range;
  49. else
  50. RemCompDeferred<ActiveListenerComponent>(uid);
  51. }
  52. public void CanListen(EntityUid uid, SurveillanceCameraMicrophoneComponent microphone, ListenAttemptEvent args)
  53. {
  54. // TODO maybe just make this a part of ActiveListenerComponent?
  55. if (_whitelistSystem.IsBlacklistPass(microphone.Blacklist, args.Source))
  56. args.Cancel();
  57. }
  58. public void RelayEntityMessage(EntityUid uid, SurveillanceCameraMicrophoneComponent component, ListenEvent args)
  59. {
  60. if (!TryComp(uid, out SurveillanceCameraComponent? camera))
  61. return;
  62. var ev = new SurveillanceCameraSpeechSendEvent(args.Source, args.Message);
  63. foreach (var monitor in camera.ActiveMonitors)
  64. {
  65. RaiseLocalEvent(monitor, ev);
  66. }
  67. }
  68. public void SetEnabled(EntityUid uid, bool value, SurveillanceCameraMicrophoneComponent? microphone = null)
  69. {
  70. if (!Resolve(uid, ref microphone))
  71. return;
  72. if (value == microphone.Enabled)
  73. return;
  74. microphone.Enabled = value;
  75. if (value)
  76. EnsureComp<ActiveListenerComponent>(uid).Range = microphone.Range;
  77. else
  78. RemCompDeferred<ActiveListenerComponent>(uid);
  79. }
  80. }
  81. public sealed class SurveillanceCameraSpeechSendEvent : EntityEventArgs
  82. {
  83. public EntityUid Speaker { get; }
  84. public string Message { get; }
  85. public SurveillanceCameraSpeechSendEvent(EntityUid speaker, string message)
  86. {
  87. Speaker = speaker;
  88. Message = message;
  89. }
  90. }