]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Add telecomms system (#14486)
authorSlava0135 <40753025+Slava0135@users.noreply.github.com>
Fri, 24 Mar 2023 00:02:41 +0000 (03:02 +0300)
committerGitHub <noreply@github.com>
Fri, 24 Mar 2023 00:02:41 +0000 (20:02 -0400)
Content.Server/Anomaly/AnomalySystem.Generator.cs
Content.Server/Radio/EntitySystems/HeadsetSystem.cs
Content.Server/Radio/EntitySystems/RadioDeviceSystem.cs
Content.Server/Radio/EntitySystems/RadioSystem.cs
Content.Server/Radio/EntitySystems/TelecomSystem.cs [deleted file]
Content.Server/Radio/RadioReceiveEvent.cs
Content.Server/Salvage/SalvageSystem.cs
Content.Server/StationEvents/Events/SolarFlare.cs
Content.Shared/Radio/Components/TelecomServerComponent.cs
Content.Shared/Radio/RadioChannelPrototype.cs
Resources/Prototypes/radio_channels.yml

index ba7c7b981cce49af5cace2baf26df196c3558fa5..924c3a2a429c4c784e14fd71d18ba19a0a1fb052 100644 (file)
@@ -157,7 +157,7 @@ public sealed partial class AnomalySystem
         Audio.PlayPvs(component.GeneratingFinishedSound, uid);
 
         var message = Loc.GetString("anomaly-generator-announcement");
-        _radio.SendRadioMessage(uid, message, _prototype.Index<RadioChannelPrototype>(component.ScienceChannel));
+        _radio.SendRadioMessage(uid, message, _prototype.Index<RadioChannelPrototype>(component.ScienceChannel), uid);
     }
 
     private void UpdateGenerator()
index 87ec6448aec6df9ead0619a090ca76a8775f4f3c..4f7ab752c8d156e6bac788faf328393c046ce8e4 100644 (file)
@@ -93,7 +93,7 @@ public sealed class HeadsetSystem : SharedHeadsetSystem
         }
     }
 
-    private void OnHeadsetReceive(EntityUid uid, HeadsetComponent component, RadioReceiveEvent args)
+    private void OnHeadsetReceive(EntityUid uid, HeadsetComponent component, ref RadioReceiveEvent args)
     {
         if (TryComp(Transform(uid).ParentUid, out ActorComponent? actor))
             _netMan.ServerSendMessage(args.ChatMsg, actor.PlayerSession.ConnectedClient);
index fc2d89ddbb08c9634acc738fa857389cca824464..c8de62502524b56020a199b036701a2eb0379d15 100644 (file)
@@ -206,10 +206,10 @@ public sealed class RadioDeviceSystem : EntitySystem
         }
     }
 
-    private void OnReceiveRadio(EntityUid uid, RadioSpeakerComponent component, RadioReceiveEvent args)
+    private void OnReceiveRadio(EntityUid uid, RadioSpeakerComponent component, ref RadioReceiveEvent args)
     {
-        var nameEv = new TransformSpeakerNameEvent(args.Source, Name(args.Source));
-        RaiseLocalEvent(args.Source, nameEv);
+        var nameEv = new TransformSpeakerNameEvent(args.MessageSource, Name(args.MessageSource));
+        RaiseLocalEvent(args.MessageSource, nameEv);
 
         var name = Loc.GetString("speech-name-relay", ("speaker", Name(uid)),
             ("originalName", nameEv.Name));
index 6580afc17f3fd303cb1bc034f1f0d5672af0d0e2..15e439465e604e96d98d223a990607566bdd0e56 100644 (file)
@@ -11,6 +11,9 @@ using Robust.Shared.Network;
 using Robust.Shared.Replays;
 using Robust.Shared.Utility;
 using Content.Shared.Popups;
+using Robust.Shared.Map;
+using Content.Shared.Radio.Components;
+using Content.Server.Power.Components;
 
 namespace Content.Server.Radio.EntitySystems;
 
@@ -22,7 +25,7 @@ public sealed class RadioSystem : EntitySystem
     [Dependency] private readonly INetManager _netMan = default!;
     [Dependency] private readonly IReplayRecordingManager _replay = default!;
     [Dependency] private readonly IAdminLogManager _adminLogger = default!;
-    [Dependency] private readonly PopupSystem _popupSystem = default!;
+    [Dependency] private readonly PopupSystem _popup = default!;
 
     // set used to prevent radio feedback loops.
     private readonly HashSet<string> _messages = new();
@@ -38,26 +41,31 @@ public sealed class RadioSystem : EntitySystem
     {
         if (args.Channel != null && component.Channels.Contains(args.Channel.ID))
         {
-            SendRadioMessage(uid, args.Message, args.Channel);
+            SendRadioMessage(uid, args.Message, args.Channel, uid);
             args.Channel = null; // prevent duplicate messages from other listeners.
         }
     }
 
-    private void OnIntrinsicReceive(EntityUid uid, IntrinsicRadioReceiverComponent component, RadioReceiveEvent args)
+    private void OnIntrinsicReceive(EntityUid uid, IntrinsicRadioReceiverComponent component, ref RadioReceiveEvent args)
     {
         if (TryComp(uid, out ActorComponent? actor))
             _netMan.ServerSendMessage(args.ChatMsg, actor.PlayerSession.ConnectedClient);
     }
 
-    public void SendRadioMessage(EntityUid source, string message, RadioChannelPrototype channel, EntityUid? radioSource = null)
+    /// <summary>
+    /// Send radio message to all active radio listeners
+    /// </summary>
+    /// <param name="messageSource">Entity that spoke the message</param>
+    /// <param name="radioSource">Entity that picked up the message and will send it, e.g. headset</param>
+    public void SendRadioMessage(EntityUid messageSource, string message, RadioChannelPrototype channel, EntityUid radioSource)
     {
         // TODO if radios ever garble / modify messages, feedback-prevention needs to be handled better than this.
         if (!_messages.Add(message))
             return;
 
-        var name = TryComp(source, out VoiceMaskComponent? mask) && mask.Enabled
+        var name = TryComp(messageSource, out VoiceMaskComponent? mask) && mask.Enabled
             ? mask.VoiceName
-            : MetaData(source).EntityName;
+            : MetaData(messageSource).EntityName;
 
         name = FormattedMessage.EscapeText(name);
 
@@ -68,37 +76,63 @@ public sealed class RadioSystem : EntitySystem
             Loc.GetString("chat-radio-message-wrap", ("color", channel.Color), ("channel", $"\\[{channel.LocalizedName}\\]"), ("name", name), ("message", FormattedMessage.EscapeText(message))),
             EntityUid.Invalid);
         var chatMsg = new MsgChatMessage { Message = chat };
+        var ev = new RadioReceiveEvent(message, messageSource, channel, chatMsg);
 
-        var ev = new RadioReceiveEvent(message, source, channel, chatMsg, radioSource);
-        var attemptEv = new RadioReceiveAttemptEvent(message, source, channel, radioSource);
-        var sentAtLeastOnce = false;
+        var sourceMapId = Transform(radioSource).MapID;
+        var hasActiveServer = HasActiveServer(sourceMapId, channel.ID);
+        var hasMicro = HasComp<RadioMicrophoneComponent>(radioSource);
 
-        foreach (var radio in EntityQuery<ActiveRadioComponent>())
+        var speakerQuery = GetEntityQuery<RadioSpeakerComponent>();
+        var radioQuery = AllEntityQuery<ActiveRadioComponent, TransformComponent>();
+        var sentAtLeastOnce = false;
+        while (radioQuery.MoveNext(out var receiver, out var radio, out var transform))
         {
-            var ent = radio.Owner;
-            // TODO map/station/range checks?
-
             if (!radio.Channels.Contains(channel.ID))
                 continue;
 
-            RaiseLocalEvent(ent, attemptEv);
+            if (!channel.LongRange && transform.MapID != sourceMapId)
+                continue;
+
+            // don't need telecom server for long range channels or handheld radios and intercoms
+            var needServer = !channel.LongRange && (!hasMicro || !speakerQuery.HasComponent(receiver));
+            if (needServer && !hasActiveServer)
+                continue;
+                
+            // check if message can be sent to specific receiver
+            var attemptEv = new RadioReceiveAttemptEvent(channel, radioSource, receiver);
+            RaiseLocalEvent(ref attemptEv);
             if (attemptEv.Cancelled)
-            {
-                attemptEv.Uncancel();
                 continue;
-            }
+
+            // send the message
+            RaiseLocalEvent(receiver, ref ev);
             sentAtLeastOnce = true;
-            RaiseLocalEvent(ent, ev);
         }
         if (!sentAtLeastOnce)
-            _popupSystem.PopupEntity(Loc.GetString("failed-to-send-message"), source, source, PopupType.MediumCaution);
+            _popup.PopupEntity(Loc.GetString("failed-to-send-message"), messageSource, messageSource, PopupType.MediumCaution);
 
-        if (name != Name(source))
-            _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Radio message from {ToPrettyString(source):user} as {name} on {channel.LocalizedName}: {message}");
+        if (name != Name(messageSource))
+            _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Radio message from {ToPrettyString(messageSource):user} as {name} on {channel.LocalizedName}: {message}");
         else
-            _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Radio message from {ToPrettyString(source):user} on {channel.LocalizedName}: {message}");
+            _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Radio message from {ToPrettyString(messageSource):user} on {channel.LocalizedName}: {message}");
 
         _replay.QueueReplayMessage(chat);
         _messages.Remove(message);
     }
+
+    /// <inheritdoc cref="TelecomServerComponent"/>
+    private bool HasActiveServer(MapId mapId, string channelId)
+    {
+        var servers = EntityQuery<TelecomServerComponent, EncryptionKeyHolderComponent, ApcPowerReceiverComponent, TransformComponent>();
+        foreach (var (_, keys, power, transform) in servers)
+        {
+            if (transform.MapID == mapId &&
+                power.Powered &&
+                keys.Channels.Contains(channelId))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
 }
diff --git a/Content.Server/Radio/EntitySystems/TelecomSystem.cs b/Content.Server/Radio/EntitySystems/TelecomSystem.cs
deleted file mode 100644 (file)
index b4d8897..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-namespace Content.Server.Radio.EntitySystems;
-
-public sealed class TelecomSystem : EntitySystem
-{
-}
index f8d8240b8d27f131a7538f4b76ea7f43e5503c93..abcee61025c10e5cb522a6788fea044cceb21e53 100644 (file)
@@ -3,36 +3,39 @@ using Content.Shared.Radio;
 
 namespace Content.Server.Radio;
 
-public sealed class RadioReceiveEvent : EntityEventArgs
+[ByRefEvent]
+public struct RadioReceiveEvent
 {
     public readonly string Message;
-    public readonly EntityUid Source;
+    public readonly EntityUid MessageSource;
     public readonly RadioChannelPrototype Channel;
     public readonly MsgChatMessage ChatMsg;
-    public readonly EntityUid? RadioSource;
 
-    public RadioReceiveEvent(string message, EntityUid source, RadioChannelPrototype channel, MsgChatMessage chatMsg, EntityUid? radioSource)
+    public RadioReceiveEvent(string message, EntityUid messageSource, RadioChannelPrototype channel, MsgChatMessage chatMsg)
     {
         Message = message;
-        Source = source;
+        MessageSource = messageSource;
         Channel = channel;
         ChatMsg = chatMsg;
-        RadioSource = radioSource;
     }
 }
 
-public sealed class RadioReceiveAttemptEvent : CancellableEntityEventArgs
+/// <summary>
+/// Use this event to cancel sending messages by doing various checks (e.g. range)
+/// </summary>
+[ByRefEvent]
+public struct RadioReceiveAttemptEvent
 {
-    public readonly string Message;
-    public readonly EntityUid Source;
     public readonly RadioChannelPrototype Channel;
-    public readonly EntityUid? RadioSource;
+    public readonly EntityUid RadioSource;
+    public readonly EntityUid RadioReceiver;
 
-    public RadioReceiveAttemptEvent(string message, EntityUid source, RadioChannelPrototype channel, EntityUid? radioSource)
+    public bool Cancelled = false;
+
+    public RadioReceiveAttemptEvent(RadioChannelPrototype channel, EntityUid radioSource, EntityUid radioReceiver)
     {
-        Message = message;
-        Source = source;
         Channel = channel;
         RadioSource = radioSource;
+        RadioReceiver = radioReceiver;
     }
 }
index b0ce24ddbaef2e8d44102832648a3a35a524719d..8fe166f3c743f193da1a6e9d30264818791212f6 100644 (file)
@@ -376,7 +376,7 @@ namespace Content.Server.Salvage
 
             var message = args.Length == 0 ? Loc.GetString(messageKey) : Loc.GetString(messageKey, args);
             var channel = _prototypeManager.Index<RadioChannelPrototype>(channelName);
-            _radioSystem.SendRadioMessage(source, message, channel);
+            _radioSystem.SendRadioMessage(source, message, channel, source);
         }
 
         private void Transition(SalvageMagnetComponent magnet, TimeSpan currentTime)
index 9c1b3114dbc77a39c46b29a1911def410855d9cb..cf3a2a403bfaf93cbc72962e4498c783e8b601af 100644 (file)
@@ -23,7 +23,7 @@ public sealed class SolarFlare : StationEventSystem
     public override void Initialize()
     {
         base.Initialize();
-        SubscribeLocalEvent<ActiveRadioComponent, RadioReceiveAttemptEvent>(OnRadioSendAttempt);
+        SubscribeLocalEvent<RadioReceiveAttemptEvent>(OnRadioSendAttempt);
     }
 
     public override void Added()
@@ -69,10 +69,10 @@ public sealed class SolarFlare : StationEventSystem
         }
     }
 
-    private void OnRadioSendAttempt(EntityUid uid, ActiveRadioComponent component, RadioReceiveAttemptEvent args)
+    private void OnRadioSendAttempt(ref RadioReceiveAttemptEvent args)
     {
         if (RuleStarted && _event.AffectedChannels.Contains(args.Channel.ID))
-            if (!_event.OnlyJamHeadsets || (HasComp<HeadsetComponent>(uid) || HasComp<HeadsetComponent>(args.RadioSource)))
-                args.Cancel();
+            if (!_event.OnlyJamHeadsets || (HasComp<HeadsetComponent>(args.RadioReceiver) || HasComp<HeadsetComponent>(args.RadioSource)))
+                args.Cancelled = true;
     }
 }
index 2aa003a1e788560fc0ff1fc7aa296c09d4198b19..d87bc2be1adb2aa234ea71f4cb365a38c58e6734 100644 (file)
@@ -1,6 +1,12 @@
 namespace Content.Shared.Radio.Components;
 
+/// <summary>
+/// Entities with <see cref="TelecomServerComponent"/> are needed to transmit messages using headsets. 
+/// They also need to be powered by <see cref="ApcPowerReceiverComponent"/>
+/// have <see cref="EncryptionKeyHolderComponent"/> and filled with encryption keys
+/// of channels in order for them to work on the same map as server.
+/// </summary>
 [RegisterComponent]
 public sealed class TelecomServerComponent : Component
 {
-}
\ No newline at end of file
+}
index c72cb0c0d9236692b5b0e3a39c1f218ffd9b4c51..b8b862f61f1b56dbf190ef791b166e1c5eec79ba 100644 (file)
@@ -1,28 +1,38 @@
 using Robust.Shared.Prototypes;
 
-namespace Content.Shared.Radio
+namespace Content.Shared.Radio;
+
+[Prototype("radioChannel")]
+public sealed class RadioChannelPrototype : IPrototype
 {
-    [Prototype("radioChannel")]
-    public sealed class RadioChannelPrototype : IPrototype
-    {
-        /// <summary>
-        /// Human-readable name for the channel.
-        /// </summary>
-        [DataField("name")] public string Name { get; private set; } = string.Empty;
+    /// <summary>
+    /// Human-readable name for the channel.
+    /// </summary>
+    [DataField("name")]
+    public string Name { get; private set; } = string.Empty;
+
+    [ViewVariables(VVAccess.ReadOnly)]
+    public string LocalizedName => Loc.GetString(Name);
 
-        [ViewVariables(VVAccess.ReadOnly)] public string LocalizedName => Loc.GetString(Name);
+    /// <summary>
+    /// Single-character prefix to determine what channel a message should be sent to.
+    /// </summary>
+    [DataField("keycode")]
+    public char KeyCode { get; private set; } = '\0';
 
-        /// <summary>
-        /// Single-character prefix to determine what channel a message should be sent to.
-        /// </summary>
-        [DataField("keycode")] public char KeyCode { get; private set; } = '\0';
+    [DataField("frequency")]
+    public int Frequency { get; private set; } = 0;
 
-        [DataField("frequency")] public int Frequency { get; private set; } = 0;
+    [DataField("color")]
+    public Color Color { get; private set; } = Color.Lime;
 
-        [DataField("color")] public Color Color { get; private set; } = Color.Lime;
+    [IdDataField, ViewVariables]
+    public string ID { get; } = default!;
 
-        [ViewVariables]
-        [IdDataField]
-        public string ID { get; } = default!;
-    }
+    /// <summary>
+    /// If channel is long range it doesn't require telecommunication server 
+    /// and messages can be sent across different stations
+    /// </summary>
+    [DataField("longRange"), ViewVariables]
+    public bool LongRange = false;
 }
index 734568fc90007c38be00525253b47f5466bb0de5..c72f250a265f4d3543b99916c3e363313838c273 100644 (file)
@@ -11,6 +11,7 @@
   keycode: 'y'
   frequency: 1337
   color: "#2681a5"
+  longRange: true
 
 - type: radioChannel
   id: Command
@@ -67,3 +68,4 @@
   keycode: 't'
   frequency: 1213
   color: "#8f4a4b"
+  longRange: true