Merge remote-tracking branch 'upstream/stable' into ed-29-10-2024-upstream

# Conflicts:
#	Content.Server/Chat/Managers/ChatSanitizationManager.cs
#	Content.Server/Temperature/Systems/TemperatureSystem.cs
#	Content.Shared/Localizations/ContentLocalizationManager.cs
This commit is contained in:
Ed
2024-10-29 11:16:56 +03:00
388 changed files with 34535 additions and 18822 deletions

View File

@@ -1,15 +1,18 @@
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text.RegularExpressions;
using Content.Shared.CCVar;
using Robust.Shared.Configuration;
namespace Content.Server.Chat.Managers;
/// <summary>
/// Sanitizes messages!
/// It currently ony removes the shorthands for emotes (like "lol" or "^-^") from a chat message and returns the last
/// emote in their message
/// </summary>
public sealed class ChatSanitizationManager : IChatSanitizationManager
{
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
private static readonly Dictionary<string, string> SmileyToEmote = new()
private static readonly Dictionary<string, string> ShorthandToEmote = new()
{
// CP14-RU-Localization-Start
{ "лол", "chatsan-laughs" },
@@ -60,7 +63,7 @@ public sealed class ChatSanitizationManager : IChatSanitizationManager
{ ":D", "chatsan-smiles-widely" },
{ "D:", "chatsan-frowns-deeply" },
{ ":O", "chatsan-surprised" },
{ ":3", "chatsan-smiles" }, //nope
{ ":3", "chatsan-smiles" },
{ ":S", "chatsan-uncertain" },
{ ":>", "chatsan-grins" },
{ ":<", "chatsan-pouts" },
@@ -102,7 +105,7 @@ public sealed class ChatSanitizationManager : IChatSanitizationManager
{ "kek", "chatsan-laughs" },
{ "rofl", "chatsan-laughs" },
{ "o7", "chatsan-salutes" },
{ ";_;7", "chatsan-tearfully-salutes"},
{ ";_;7", "chatsan-tearfully-salutes" },
{ "idk", "chatsan-shrugs" },
{ ";)", "chatsan-winks" },
{ ";]", "chatsan-winks" },
@@ -115,9 +118,12 @@ public sealed class ChatSanitizationManager : IChatSanitizationManager
{ "(':", "chatsan-tearfully-smiles" },
{ "[':", "chatsan-tearfully-smiles" },
{ "('=", "chatsan-tearfully-smiles" },
{ "['=", "chatsan-tearfully-smiles" },
{ "['=", "chatsan-tearfully-smiles" }
};
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
[Dependency] private readonly ILocalizationManager _loc = default!;
private bool _doSanitize;
public void Initialize()
@@ -125,29 +131,60 @@ public sealed class ChatSanitizationManager : IChatSanitizationManager
_configurationManager.OnValueChanged(CCVars.ChatSanitizerEnabled, x => _doSanitize = x, true);
}
public bool TrySanitizeOutSmilies(string input, EntityUid speaker, out string sanitized, [NotNullWhen(true)] out string? emote)
/// <summary>
/// Remove the shorthands from the message, returning the last one found as the emote
/// </summary>
/// <param name="message">The pre-sanitized message</param>
/// <param name="speaker">The speaker</param>
/// <param name="sanitized">The sanitized message with shorthands removed</param>
/// <param name="emote">The localized emote</param>
/// <returns>True if emote has been sanitized out</returns>
public bool TrySanitizeEmoteShorthands(string message,
EntityUid speaker,
out string sanitized,
[NotNullWhen(true)] out string? emote)
{
if (!_doSanitize)
{
sanitized = input;
emote = null;
return false;
}
input = input.TrimEnd();
foreach (var (smiley, replacement) in SmileyToEmote)
{
if (input.EndsWith(smiley, true, CultureInfo.InvariantCulture))
{
sanitized = input.Remove(input.Length - smiley.Length).TrimEnd();
emote = Loc.GetString(replacement, ("ent", speaker));
return true;
}
}
sanitized = input;
emote = null;
return false;
sanitized = message;
if (!_doSanitize)
return false;
// -1 is just a canary for nothing found yet
var lastEmoteIndex = -1;
foreach (var (shorthand, emoteKey) in ShorthandToEmote)
{
// We have to escape it because shorthands like ":)" or "-_-" would break the regex otherwise.
var escaped = Regex.Escape(shorthand);
// So there are 2 cases:
// - If there is whitespace before it and after it is either punctuation, whitespace, or the end of the line
// Delete the word and the whitespace before
// - If it is at the start of the string and is followed by punctuation, whitespace, or the end of the line
// Delete the word and the punctuation if it exists.
var pattern =
$@"\s{escaped}(?=\p{{P}}|\s|$)|^{escaped}(?:\p{{P}}|(?=\s|$))";
var r = new Regex(pattern, RegexOptions.RightToLeft | RegexOptions.IgnoreCase);
// We're using sanitized as the original message until the end so that we can make sure the indices of
// the emotes are accurate.
var lastMatch = r.Match(sanitized);
if (!lastMatch.Success)
continue;
if (lastMatch.Index > lastEmoteIndex)
{
lastEmoteIndex = lastMatch.Index;
emote = _loc.GetString(emoteKey, ("ent", speaker));
}
message = r.Replace(message, string.Empty);
}
sanitized = message.Trim();
return emote is not null;
}
}

View File

@@ -6,5 +6,8 @@ public interface IChatSanitizationManager
{
public void Initialize();
public bool TrySanitizeOutSmilies(string input, EntityUid speaker, out string sanitized, [NotNullWhen(true)] out string? emote);
public bool TrySanitizeEmoteShorthands(string input,
EntityUid speaker,
out string sanitized,
[NotNullWhen(true)] out string? emote);
}

View File

@@ -746,8 +746,12 @@ public sealed partial class ChatSystem : SharedChatSystem
// ReSharper disable once InconsistentNaming
private string SanitizeInGameICMessage(EntityUid source, string message, out string? emoteStr, bool capitalize = true, bool punctuate = false, bool capitalizeTheWordI = true)
{
var newMessage = message.Trim();
newMessage = SanitizeMessageReplaceWords(newMessage);
var newMessage = SanitizeMessageReplaceWords(message.Trim());
GetRadioKeycodePrefix(source, newMessage, out newMessage, out var prefix);
// Sanitize it first as it might change the word order
_sanitizer.TrySanitizeEmoteShorthands(newMessage, source, out newMessage, out emoteStr);
if (capitalize)
newMessage = SanitizeMessageCapital(newMessage);
@@ -756,9 +760,7 @@ public sealed partial class ChatSystem : SharedChatSystem
if (punctuate)
newMessage = SanitizeMessagePeriod(newMessage);
_sanitizer.TrySanitizeOutSmilies(newMessage, source, out newMessage, out emoteStr);
return newMessage;
return prefix + newMessage;
}
private string SanitizeInGameOOCMessage(string message)