mirror of
https://github.com/DeltaV-Station/Delta-v.git
synced 2026-09-30 16:17:27 +00:00
* Changed up how emoting works This was a long 10 hours just to get the chat to behave slightly different. At least we can now scream over radio! Will most definitely need some more work to get bugs out since this is the first implementation. * Not ok This was unmarked for some reason... I don't remember unmarking this. * DeltaV comments Added comments to explain changes. Moved localization files to the _DV folder. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Moved code Moved code to more suitable files and added some comments. * Rights for robots Now those with intrinsic radios can also emote! * Fixes up some small stuff Changes to fix some small issues with the code to align it more with modern standards. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fix by-ref event Never worked with this event type before so gonna hope this works. * Update Content.Shared/Chat/SharedChatSystem.Emote.cs Signed-off-by: pathetic meowmeow <uhhadd@gmail.com> * Update Content.Shared/Chat/SharedChatSystem.cs Signed-off-by: pathetic meowmeow <uhhadd@gmail.com> * Update Content.Server/Chat/Systems/ChatSystem.cs Signed-off-by: pathetic meowmeow <uhhadd@gmail.com> * fix style nits * remove conflicting chatsan --------- Signed-off-by: pathetic meowmeow <uhhadd@gmail.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: pathetic meowmeow <uhhadd@gmail.com>
206 lines
8.8 KiB
C#
206 lines
8.8 KiB
C#
using Content.Server.Administration.Logs;
|
|
using Content.Server.Chat.Systems;
|
|
using Content.Server.Power.Components;
|
|
using Content.Shared._DV.Chat;
|
|
using Content.Shared.Chat;
|
|
using Content.Shared.Database;
|
|
using Content.Shared.Radio;
|
|
using Content.Shared.Radio.Components;
|
|
using Content.Shared.Speech;
|
|
using Robust.Shared.Map;
|
|
using Robust.Shared.Network;
|
|
using Robust.Shared.Player;
|
|
using Robust.Shared.Prototypes;
|
|
using Robust.Shared.Random;
|
|
using Robust.Shared.Replays;
|
|
using Robust.Shared.Utility;
|
|
|
|
namespace Content.Server.Radio.EntitySystems;
|
|
|
|
/// <summary>
|
|
/// This system handles intrinsic radios and the general process of converting radio messages into chat messages.
|
|
/// </summary>
|
|
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 IPrototypeManager _prototype = default!;
|
|
[Dependency] private readonly IRobustRandom _random = default!;
|
|
[Dependency] private readonly ChatSystem _chat = default!;
|
|
|
|
// set used to prevent radio feedback loops.
|
|
private readonly HashSet<string> _messages = new();
|
|
|
|
private EntityQuery<TelecomExemptComponent> _exemptQuery;
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
SubscribeLocalEvent<IntrinsicRadioReceiverComponent, RadioReceiveEvent>(OnIntrinsicReceive);
|
|
SubscribeLocalEvent<IntrinsicRadioTransmitterComponent, EntitySpokeEvent>(OnIntrinsicSpeak);
|
|
SubscribeLocalEvent<IntrinsicRadioTransmitterComponent, EntityAudiblyEmotedEvent>(OnIntrinsicAudibleEmote); // DeltaV - Robots should be allowed to emote over radio.
|
|
|
|
_exemptQuery = GetEntityQuery<TelecomExemptComponent>();
|
|
}
|
|
|
|
private void OnIntrinsicSpeak(EntityUid uid, IntrinsicRadioTransmitterComponent component, EntitySpokeEvent args)
|
|
{
|
|
if (args.Channel != null && component.Channels.Contains(args.Channel.ID))
|
|
{
|
|
SendRadioMessage(uid, args.Message, args.Channel, uid);
|
|
args.Channel = null; // prevent duplicate messages from other listeners.
|
|
}
|
|
}
|
|
|
|
private void OnIntrinsicReceive(EntityUid uid, IntrinsicRadioReceiverComponent component, ref RadioReceiveEvent args)
|
|
{
|
|
if (TryComp(uid, out ActorComponent? actor))
|
|
_netMan.ServerSendMessage(args.ChatMsg, actor.PlayerSession.Channel);
|
|
}
|
|
|
|
// DeltaV
|
|
private void OnIntrinsicAudibleEmote(EntityUid uid, IntrinsicRadioTransmitterComponent component, EntityAudiblyEmotedEvent args)
|
|
{
|
|
if (args.Channel != null && component.Channels.Contains(args.Channel.ID))
|
|
{
|
|
SendRadioMessage(uid, args.Message, args.Channel, uid, emType: args.Type);
|
|
}
|
|
}
|
|
// DeltaV - End
|
|
|
|
/// <summary>
|
|
/// Send radio message to all active radio listeners
|
|
/// </summary>
|
|
public void SendRadioMessage(EntityUid messageSource, string message, ProtoId<RadioChannelPrototype> channel, EntityUid radioSource, bool escapeMarkup = true, EmoteType? emType = null) // DeltaV - EmoteType? added.
|
|
{
|
|
SendRadioMessage(messageSource, message, _prototype.Index(channel), radioSource, escapeMarkup: escapeMarkup, emType: emType);
|
|
}
|
|
|
|
/// <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, bool escapeMarkup = true, EmoteType? emType = null) // DeltaV - EmoteType? added.
|
|
{
|
|
// TODO if radios ever garble / modify messages, feedback-prevention needs to be handled better than this.
|
|
if (!_messages.Add(message))
|
|
return;
|
|
|
|
var evt = new TransformSpeakerNameEvent(messageSource, MetaData(messageSource).EntityName);
|
|
RaiseLocalEvent(messageSource, evt);
|
|
|
|
var name = evt.VoiceName;
|
|
name = FormattedMessage.EscapeText(name);
|
|
|
|
SpeechVerbPrototype speech;
|
|
if (evt.SpeechVerb != null && _prototype.Resolve(evt.SpeechVerb, out var evntProto))
|
|
speech = evntProto;
|
|
else
|
|
speech = _chat.GetSpeechVerb(messageSource, message);
|
|
|
|
var content = escapeMarkup
|
|
? FormattedMessage.EscapeText(message)
|
|
: message;
|
|
|
|
// DeltaV - This change is to change up how the messages are wrapped up. Basically changing the formatting depending on the emote type.
|
|
string wrappedMessage;
|
|
|
|
if (emType == EmoteType.Audible)
|
|
wrappedMessage = Loc.GetString("chat-radio-message-audible-emote-wrap",
|
|
("color", channel.Color),
|
|
("channel", $"\\[{channel.LocalizedName}\\]"),
|
|
("name", name),
|
|
("message", content));
|
|
else if (emType == EmoteType.AudiblePossessive)
|
|
wrappedMessage = Loc.GetString("chat-radio-message-audible-possessive-emote-wrap",
|
|
("color", channel.Color),
|
|
("channel", $"\\[{channel.LocalizedName}\\]"),
|
|
("name", name),
|
|
("message", content));
|
|
else
|
|
wrappedMessage = Loc.GetString(speech.Bold ? "chat-radio-message-wrap-bold" : "chat-radio-message-wrap",
|
|
("color", channel.Color),
|
|
("fontType", speech.FontId),
|
|
("fontSize", speech.FontSize),
|
|
("verb", Loc.GetString(_random.Pick(speech.SpeechVerbStrings))),
|
|
("channel", $"\\[{channel.LocalizedName}\\]"),
|
|
("name", name),
|
|
("message", content));
|
|
// DeltaV - End
|
|
|
|
// most radios are relayed to chat, so lets parse the chat message beforehand
|
|
var chat = new ChatMessage(
|
|
ChatChannel.Radio,
|
|
message,
|
|
wrappedMessage,
|
|
NetEntity.Invalid,
|
|
null);
|
|
var chatMsg = new MsgChatMessage { Message = chat };
|
|
var ev = new RadioReceiveEvent(message, messageSource, channel, radioSource, chatMsg);
|
|
|
|
var sendAttemptEv = new RadioSendAttemptEvent(channel, radioSource);
|
|
RaiseLocalEvent(ref sendAttemptEv);
|
|
RaiseLocalEvent(radioSource, ref sendAttemptEv);
|
|
var canSend = !sendAttemptEv.Cancelled;
|
|
|
|
var sourceMapId = Transform(radioSource).MapID;
|
|
var hasActiveServer = HasActiveServer(sourceMapId, channel.ID);
|
|
var sourceServerExempt = _exemptQuery.HasComp(radioSource);
|
|
|
|
var radioQuery = EntityQueryEnumerator<ActiveRadioComponent, TransformComponent>();
|
|
while (canSend && radioQuery.MoveNext(out var receiver, out var radio, out var transform))
|
|
{
|
|
if (!radio.ReceiveAllChannels)
|
|
{
|
|
if (!radio.Channels.Contains(channel.ID) || (TryComp<IntercomComponent>(receiver, out var intercom) &&
|
|
!intercom.SupportedChannels.Contains(channel.ID)))
|
|
continue;
|
|
}
|
|
|
|
if (!channel.LongRange && transform.MapID != sourceMapId && !radio.GlobalReceive)
|
|
continue;
|
|
|
|
// don't need telecom server for long range channels or handheld radios and intercoms
|
|
var needServer = !channel.LongRange && !sourceServerExempt;
|
|
if (needServer && !hasActiveServer)
|
|
continue;
|
|
|
|
// check if message can be sent to specific receiver
|
|
var attemptEv = new RadioReceiveAttemptEvent(channel, radioSource, receiver);
|
|
RaiseLocalEvent(ref attemptEv);
|
|
RaiseLocalEvent(receiver, ref attemptEv);
|
|
if (attemptEv.Cancelled)
|
|
continue;
|
|
|
|
// send the message
|
|
RaiseLocalEvent(receiver, ref ev);
|
|
}
|
|
|
|
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(messageSource):user} on {channel.LocalizedName}: {message}");
|
|
|
|
_replay.RecordServerMessage(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;
|
|
}
|
|
}
|