Add virtual chat API methods in Shared (#40895)

* move chat stuff to shared

* refactor: using cleanup +whitespaces + xml-doc

* review

---------

Co-authored-by: pa.pecherskij <pa.pecherskij@interfax.ru>
This commit is contained in:
slarticodefast
2025-10-19 21:08:27 +02:00
committed by GitHub
parent 1541c107e5
commit 1469b9484d
26 changed files with 248 additions and 153 deletions

View File

@@ -7,6 +7,7 @@ using static Content.Shared.Access.Components.IdCardConsoleComponent;
using Content.Shared.Access.Systems;
using Content.Shared.Access;
using Content.Shared.Administration.Logs;
using Content.Shared.Chat;
using Content.Shared.Construction;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Damage;

View File

@@ -1,5 +1,6 @@
using Content.Server.Chat.Systems;
using Content.Shared.Administration;
using Content.Shared.Chat;
using Robust.Shared.Console;
namespace Content.Server.Administration.Commands;

View File

@@ -2,6 +2,7 @@ using System.Linq;
using Content.Server.Administration.Logs;
using Content.Server.Chat.Systems;
using Content.Shared.Administration;
using Content.Shared.Chat;
using Content.Shared.Database;
using Robust.Shared.Console;

View File

@@ -1,6 +1,7 @@
using Content.Server.Chat.Systems;
using Content.Shared.Advertise.Components;
using Content.Shared.Advertise.Systems;
using Content.Shared.Chat;
using Content.Shared.UserInterface;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;

View File

@@ -1,5 +1,6 @@
using Content.Server.Chat.Systems;
using Content.Shared.Administration;
using Content.Shared.Chat;
using Robust.Shared.Console;
using Robust.Shared.Enums;

View File

@@ -120,42 +120,24 @@ public sealed partial class ChatSystem : SharedChatSystem
}
}
/// <summary>
/// Sends an in-character chat message to relevant clients.
/// </summary>
/// <param name="source">The entity that is speaking</param>
/// <param name="message">The message being spoken or emoted</param>
/// <param name="desiredType">The chat type</param>
/// <param name="hideChat">Whether or not this message should appear in the chat window</param>
/// <param name="hideLog">Whether or not this message should appear in the adminlog window</param>
/// <param name="shell"></param>
/// <param name="player">The player doing the speaking</param>
/// <param name="nameOverride">The name to use for the speaking entity. Usually this should just be modified via <see cref="TransformSpeakerNameEvent"/>. If this is set, the event will not get raised.</param>
public void TrySendInGameICMessage(
/// <inheritdoc />
public override void TrySendInGameICMessage(
EntityUid source,
string message,
InGameICChatType desiredType,
bool hideChat, bool hideLog = false,
bool hideChat,
bool hideLog = false,
IConsoleShell? shell = null,
ICommonSession? player = null, string? nameOverride = null,
ICommonSession? player = null,
string? nameOverride = null,
bool checkRadioPrefix = true,
bool ignoreActionBlocker = false)
{
TrySendInGameICMessage(source, message, desiredType, hideChat ? ChatTransmitRange.HideChat : ChatTransmitRange.Normal, hideLog, shell, player, nameOverride, checkRadioPrefix, ignoreActionBlocker);
}
/// <summary>
/// Sends an in-character chat message to relevant clients.
/// </summary>
/// <param name="source">The entity that is speaking</param>
/// <param name="message">The message being spoken or emoted</param>
/// <param name="desiredType">The chat type</param>
/// <param name="range">Conceptual range of transmission, if it shows in the chat window, if it shows to far-away ghosts or ghosts at all...</param>
/// <param name="shell"></param>
/// <param name="player">The player doing the speaking</param>
/// <param name="nameOverride">The name to use for the speaking entity. Usually this should just be modified via <see cref="TransformSpeakerNameEvent"/>. If this is set, the event will not get raised.</param>
/// <param name="ignoreActionBlocker">If set to true, action blocker will not be considered for whether an entity can send this message.</param>
public void TrySendInGameICMessage(
/// <inheritdoc />
public override void TrySendInGameICMessage(
EntityUid source,
string message,
InGameICChatType desiredType,
@@ -252,7 +234,8 @@ public sealed partial class ChatSystem : SharedChatSystem
}
}
public void TrySendInGameOOCMessage(
/// <inheritdoc />
public override void TrySendInGameOOCMessage(
EntityUid source,
string message,
InGameOOCChatType type,
@@ -301,14 +284,8 @@ public sealed partial class ChatSystem : SharedChatSystem
#region Announcements
/// <summary>
/// Dispatches an announcement to all.
/// </summary>
/// <param name="message">The contents of the message</param>
/// <param name="sender">The sender (Communications Console in Communications Console Announcement)</param>
/// <param name="playSound">Play the announcement sound</param>
/// <param name="colorOverride">Optional color for the announcement message</param>
public void DispatchGlobalAnnouncement(
/// <inheritdoc />
public override void DispatchGlobalAnnouncement(
string message,
string? sender = null,
bool playSound = true,
@@ -327,17 +304,8 @@ public sealed partial class ChatSystem : SharedChatSystem
_adminLogger.Add(LogType.Chat, LogImpact.Low, $"Global station announcement from {sender}: {message}");
}
/// <summary>
/// Dispatches an announcement to players selected by filter.
/// </summary>
/// <param name="filter">Filter to select players who will recieve the announcement</param>
/// <param name="message">The contents of the message</param>
/// <param name="source">The entity making the announcement (used to determine the station)</param>
/// <param name="sender">The sender (Communications Console in Communications Console Announcement)</param>
/// <param name="playDefaultSound">Play the announcement sound</param>
/// <param name="announcementSound">Sound to play</param>
/// <param name="colorOverride">Optional color for the announcement message</param>
public void DispatchFilteredAnnouncement(
/// <inheritdoc />
public override void DispatchFilteredAnnouncement(
Filter filter,
string message,
EntityUid? source = null,
@@ -357,15 +325,8 @@ public sealed partial class ChatSystem : SharedChatSystem
_adminLogger.Add(LogType.Chat, LogImpact.Low, $"Station Announcement from {sender}: {message}");
}
/// <summary>
/// Dispatches an announcement on a specific station
/// </summary>
/// <param name="source">The entity making the announcement (used to determine the station)</param>
/// <param name="message">The contents of the message</param>
/// <param name="sender">The sender (Communications Console in Communications Console Announcement)</param>
/// <param name="playDefaultSound">Play the announcement sound</param>
/// <param name="colorOverride">Optional color for the announcement message</param>
public void DispatchStationAnnouncement(
/// <inheritdoc />
public override void DispatchStationAnnouncement(
EntityUid source,
string message,
string? sender = null,
@@ -904,74 +865,3 @@ public sealed partial class ChatSystem : SharedChatSystem
public record ExpandICChatRecipientsEvent(EntityUid Source, float VoiceRange, Dictionary<ICommonSession, ChatSystem.ICChatRecipientData> Recipients)
{
}
/// <summary>
/// Raised broadcast in order to transform speech.transmit
/// </summary>
public sealed class TransformSpeechEvent : EntityEventArgs
{
public EntityUid Sender;
public string Message;
public TransformSpeechEvent(EntityUid sender, string message)
{
Sender = sender;
Message = message;
}
}
public sealed class CheckIgnoreSpeechBlockerEvent : EntityEventArgs
{
public EntityUid Sender;
public bool IgnoreBlocker;
public CheckIgnoreSpeechBlockerEvent(EntityUid sender, bool ignoreBlocker)
{
Sender = sender;
IgnoreBlocker = ignoreBlocker;
}
}
/// <summary>
/// Raised on an entity when it speaks, either through 'say' or 'whisper'.
/// </summary>
public sealed class EntitySpokeEvent : EntityEventArgs
{
public readonly EntityUid Source;
public readonly string Message;
public readonly string? ObfuscatedMessage; // not null if this was a whisper
/// <summary>
/// If the entity was trying to speak into a radio, this was the channel they were trying to access. If a radio
/// message gets sent on this channel, this should be set to null to prevent duplicate messages.
/// </summary>
public RadioChannelPrototype? Channel;
public EntitySpokeEvent(EntityUid source, string message, RadioChannelPrototype? channel, string? obfuscatedMessage)
{
Source = source;
Message = message;
Channel = channel;
ObfuscatedMessage = obfuscatedMessage;
}
}
/// <summary>
/// InGame IC chat is for chat that is specifically ingame (not lobby) but is also in character, i.e. speaking.
/// </summary>
// ReSharper disable once InconsistentNaming
public enum InGameICChatType : byte
{
Speak,
Emote,
Whisper
}
/// <summary>
/// InGame OOC chat is for chat that is specifically ingame (not lobby) but is OOC, like deadchat or LOOC.
/// </summary>
public enum InGameOOCChatType : byte
{
Looc,
Dead
}

View File

@@ -11,6 +11,7 @@ using Content.Shared.Atmos;
using Content.Shared.CCVar;
using Content.Shared.Chemistry.Components;
using Content.Shared.Cloning;
using Content.Shared.Chat;
using Content.Shared.Damage;
using Content.Shared.DeviceLinking.Events;
using Content.Shared.Emag.Components;

View File

@@ -4,6 +4,7 @@ using Content.Server.Station.Systems;
using Content.Server.StationRecords.Systems;
using Content.Shared.Cargo.Components;
using Content.Shared.Cargo.Prototypes;
using Content.Shared.Chat;
using Content.Shared.Delivery;
using Content.Shared.FingerprintReader;
using Content.Shared.Labels.EntitySystems;

View File

@@ -1,5 +1,6 @@
using Content.Server.Chat.Systems;
using Content.Server.Ghost.Components;
using Content.Shared.Chat;
using Content.Shared.Random.Helpers;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;

View File

@@ -7,20 +7,17 @@ using Content.Server.Ghost;
using Content.Server.Popups;
using Content.Server.PowerCell;
using Content.Shared.Traits.Assorted;
using Content.Shared.Chat;
using Content.Shared.Damage;
using Content.Shared.DoAfter;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Components;
using Content.Shared.Interaction.Events;
using Content.Shared.Item.ItemToggle;
using Content.Shared.Medical;
using Content.Shared.Mind;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Components;
using Content.Shared.Mobs.Systems;
using Content.Shared.PowerCell;
using Content.Shared.Timing;
using Content.Shared.Toggleable;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Player;

View File

@@ -1,4 +1,5 @@
using Content.Server.Chat.Systems;
using Content.Shared.Chat;
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators;

View File

@@ -1,4 +1,5 @@
using Content.Server.Chat.Systems;
using Content.Shared.Chat;
using Content.Shared.Dataset;
using Content.Shared.Random.Helpers;
using JetBrains.Annotations;

View File

@@ -1,10 +1,7 @@
using Content.Server.Chat.Systems;
using Content.Shared.NPC.Components;
using Content.Shared.Chat;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Damage;
using Content.Shared.Emag.Components;
using Content.Shared.Interaction;
using Content.Shared.Mobs.Components;
using Content.Shared.Popups;
using Content.Shared.Silicons.Bots;
using Robust.Shared.Audio.Systems;

View File

@@ -1,4 +1,4 @@
using Content.Server.Chat.Systems;
using Content.Server.Chat.Systems;
using Content.Server.Explosion.EntitySystems;
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;

View File

@@ -1,4 +1,4 @@
using Content.Server.Chat.Systems;
using Content.Shared.Chat;
using Content.Shared.Inventory.Events;
using Content.Shared.Radio;
using Content.Shared.Radio.Components;

View File

@@ -3,16 +3,16 @@ using Content.Server.Chat.Systems;
using Content.Server.Interaction;
using Content.Server.Popups;
using Content.Server.Power.EntitySystems;
using Content.Shared.Radio.Components;
using Content.Shared.Chat;
using Content.Shared.Examine;
using Content.Shared.Interaction;
using Content.Shared.Power;
using Content.Shared.Radio;
using Content.Shared.Radio.Components;
using Content.Shared.Radio.EntitySystems;
using Content.Shared.Speech;
using Content.Shared.Speech.Components;
using Content.Shared.Chat;
using Robust.Shared.Prototypes;
using Content.Shared.Radio.EntitySystems;
namespace Content.Server.Radio.EntitySystems;

View File

@@ -6,6 +6,7 @@ using Content.Server.NPC.HTN;
using Content.Server.NPC.Systems;
using Content.Server.Popups;
using Content.Shared.Atmos;
using Content.Shared.Chat;
using Content.Shared.Dataset;
using Content.Shared.Nutrition.Components;
using Content.Shared.Nutrition.EntitySystems;
@@ -13,7 +14,6 @@ using Content.Shared.Pointing;
using Content.Shared.Random.Helpers;
using Content.Shared.RatKing;
using Robust.Shared.Map;
using Robust.Shared.Random;
namespace Content.Server.RatKing
{

View File

@@ -1,5 +1,5 @@
using System.Text.RegularExpressions;
using Content.Server.Chat.Systems;
using Content.Shared.Chat;
using Content.Shared.Speech;
namespace Content.Server.Speech;

View File

@@ -1,4 +1,5 @@
using Content.Server.Chat.Systems;
using Content.Shared.Chat;
using Content.Shared.Speech;
using Content.Shared.Speech.Components;

View File

@@ -1,10 +1,10 @@
using Content.Server.Chat.Systems;
using Content.Shared.Speech.Components;
using Content.Shared.Actions.Events;
using Content.Shared.Chat;
using Content.Shared.Speech;
using Content.Shared.Speech.Components;
using Content.Shared.Speech.EntitySystems;
using Content.Shared.Speech.Muting;
using Content.Shared.Actions.Events;
namespace Content.Server.Speech.EntitySystems;

View File

@@ -1,5 +1,5 @@
using Content.Server.Chat.Systems;
using Content.Server.Speech.Components;
using Content.Shared.Chat;
namespace Content.Server.Speech.EntitySystems
{

View File

@@ -1,12 +1,10 @@
using Robust.Shared.Audio;
using Content.Server.Chat;
using Content.Server.Chat.Systems;
using Content.Shared.Chat;
using Content.Shared.Speech;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Robust.Shared.Random;
using Robust.Shared.Timing;
namespace Content.Server.Speech
{

View File

@@ -1,4 +1,5 @@
using Content.Server.Chat.Systems;
using Content.Shared.Chat;
using Content.Shared.Trigger;
using Content.Shared.Trigger.Components.Effects;
using Robust.Shared.Prototypes;

View File

@@ -1,5 +1,6 @@
using Content.Server.Chat.Systems;
using Content.Server.Movement.Systems;
using Content.Shared.Chat;
using Content.Shared.Effects;
using Content.Shared.Speech.Components;
using Content.Shared.Weapons.Melee;

View File

@@ -1,6 +1,7 @@
using Content.Shared.Inventory;
using Content.Shared.Radio;
using Content.Shared.Speech;
using Robust.Shared.Prototypes;
using Content.Shared.Inventory;
namespace Content.Shared.Chat;
@@ -22,3 +23,54 @@ public sealed class TransformSpeakerNameEvent : EntityEventArgs, IInventoryRelay
SpeechVerb = null;
}
}
/// <summary>
/// Raised broadcast in order to transform speech.transmit
/// </summary>
public sealed class TransformSpeechEvent : EntityEventArgs
{
public EntityUid Sender;
public string Message;
public TransformSpeechEvent(EntityUid sender, string message)
{
Sender = sender;
Message = message;
}
}
public sealed class CheckIgnoreSpeechBlockerEvent : EntityEventArgs
{
public EntityUid Sender;
public bool IgnoreBlocker;
public CheckIgnoreSpeechBlockerEvent(EntityUid sender, bool ignoreBlocker)
{
Sender = sender;
IgnoreBlocker = ignoreBlocker;
}
}
/// <summary>
/// Raised on an entity when it speaks, either through 'say' or 'whisper'.
/// </summary>
public sealed class EntitySpokeEvent : EntityEventArgs
{
public readonly EntityUid Source;
public readonly string Message;
public readonly string? ObfuscatedMessage; // not null if this was a whisper
/// <summary>
/// If the entity was trying to speak into a radio, this was the channel they were trying to access. If a radio
/// message gets sent on this channel, this should be set to null to prevent duplicate messages.
/// </summary>
public RadioChannelPrototype? Channel;
public EntitySpokeEvent(EntityUid source, string message, RadioChannelPrototype? channel, string? obfuscatedMessage)
{
Source = source;
Message = message;
Channel = channel;
ObfuscatedMessage = obfuscatedMessage;
}
}

View File

@@ -8,7 +8,9 @@ using Content.Shared.Speech;
using Content.Shared.Whitelist;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Console;
using Robust.Shared.Network;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Utility;
@@ -322,6 +324,132 @@ public abstract partial class SharedChatSystem : EntitySystem
NetUserId? author = null
)
{ }
/// <summary>
/// Sends an in-character chat message to relevant clients.
/// </summary>
/// <param name="source">The entity that is speaking.</param>
/// <param name="message">The message being spoken or emoted.</param>
/// <param name="desiredType">The chat type.</param>
/// <param name="hideChat">Whether or not this message should appear in the chat window.</param>
/// <param name="hideLog">Whether or not this message should appear in the adminlog window.</param>
/// <param name="shell"></param>
/// <param name="player">The player doing the speaking.</param>
/// <param name="nameOverride">The name to use for the speaking entity. Usually this should just be modified via <see cref="TransformSpeakerNameEvent"/>. If this is set, the event will not get raised.</param>
/// <param name="checkRadioPrefix">Whether or not <paramref name="message"/> should be parsed with consideration of radio channel prefix text at start the start.</param>
/// <param name="ignoreActionBlocker">If set to true, action blocker will not be considered for whether an entity can send this message.</param>
public virtual void TrySendInGameICMessage(
EntityUid source,
string message,
InGameICChatType desiredType,
bool hideChat,
bool hideLog = false,
IConsoleShell? shell = null,
ICommonSession? player = null,
string? nameOverride = null,
bool checkRadioPrefix = true,
bool ignoreActionBlocker = false)
{ }
/// <summary>
/// Sends an in-character chat message to relevant clients.
/// </summary>
/// <param name="source">The entity that is speaking.</param>
/// <param name="message">The message being spoken or emoted.</param>
/// <param name="desiredType">The chat type.</param>
/// <param name="range">Conceptual range of transmission, if it shows in the chat window, if it shows to far-away ghosts or ghosts at all...</param>
/// <param name="hideLog">Disables the admin log for this message if true. Used for entities that are not players, like vendors, cloning, etc.</param>
/// <param name="shell"></param>
/// <param name="player">The player doing the speaking.</param>
/// <param name="nameOverride">The name to use for the speaking entity. Usually this should just be modified via <see cref="TransformSpeakerNameEvent"/>. If this is set, the event will not get raised.</param>
/// <param name="ignoreActionBlocker">If set to true, action blocker will not be considered for whether an entity can send this message.</param>
public virtual void TrySendInGameICMessage(
EntityUid source,
string message,
InGameICChatType desiredType,
ChatTransmitRange range,
bool hideLog = false,
IConsoleShell? shell = null,
ICommonSession? player = null,
string? nameOverride = null,
bool checkRadioPrefix = true,
bool ignoreActionBlocker = false
)
{ }
/// <summary>
/// Sends an out-of-character chat message to relevant clients.
/// </summary>
/// <param name="source">The entity that is speaking.</param>
/// <param name="message">The message being spoken or emoted.</param>
/// <param name="type">The chat type.</param>
/// <param name="hideChat">Whether or not to show the message in the chat window.</param>
/// <param name="shell"></param>
/// <param name="player">The player doing the speaking.</param>
public virtual void TrySendInGameOOCMessage(
EntityUid source,
string message,
InGameOOCChatType type,
bool hideChat,
IConsoleShell? shell = null,
ICommonSession? player = null
)
{ }
/// <summary>
/// Dispatches an announcement to all.
/// </summary>
/// <param name="message">The contents of the message.</param>
/// <param name="sender">The sender (Communications Console in Communications Console Announcement).</param>
/// <param name="playSound">Play the announcement sound.</param>
/// <param name="announcementSound">Sound to play.</param>
/// <param name="colorOverride">Optional color for the announcement message.</param>
public virtual void DispatchGlobalAnnouncement(
string message,
string? sender = null,
bool playSound = true,
SoundSpecifier? announcementSound = null,
Color? colorOverride = null
)
{ }
/// <summary>
/// Dispatches an announcement to players selected by filter.
/// </summary>
/// <param name="filter">Filter to select players who will recieve the announcement.</param>
/// <param name="message">The contents of the message.</param>
/// <param name="source">The entity making the announcement (used to determine the station).</param>
/// <param name="sender">The sender (Communications Console in Communications Console Announcement).</param>
/// <param name="playSound">Play the announcement sound.</param>
/// <param name="announcementSound">Sound to play.</param>
/// <param name="colorOverride">Optional color for the announcement message.</param>
public virtual void DispatchFilteredAnnouncement(
Filter filter,
string message,
EntityUid? source = null,
string? sender = null,
bool playSound = true,
SoundSpecifier? announcementSound = null,
Color? colorOverride = null)
{ }
/// <summary>
/// Dispatches an announcement on a specific station.
/// </summary>
/// <param name="source">The entity making the announcement (used to determine the station).</param>
/// <param name="message">The contents of the message.</param>
/// <param name="sender">The sender (Communications Console in Communications Console Announcement).</param>
/// <param name="playDefaultSound">Play the announcement sound.</param>
/// <param name="announcementSound">Sound to play.</param>
/// <param name="colorOverride">Optional color for the announcement message.</param>
public virtual void DispatchStationAnnouncement(
EntityUid source,
string message,
string? sender = null,
bool playDefaultSound = true,
SoundSpecifier? announcementSound = null,
Color? colorOverride = null)
{ }
}
/// <summary>
@@ -338,3 +466,23 @@ public enum ChatTransmitRange : byte
/// Ghosts can't hear or see it at all. Regular players can if in-range.
NoGhosts
}
/// <summary>
/// InGame IC chat is for chat that is specifically ingame (not lobby) but is also in character, i.e. speaking.
/// </summary>
// ReSharper disable once InconsistentNaming
public enum InGameICChatType : byte
{
Speak,
Emote,
Whisper
}
/// <summary>
/// InGame OOC chat is for chat that is specifically ingame (not lobby) but is OOC, like deadchat or LOOC.
/// </summary>
public enum InGameOOCChatType : byte
{
Looc,
Dead
}