diff --git a/DMCompiler/Bytecode/StringFormatEncoder.cs b/DMCompiler/Bytecode/StringFormatEncoder.cs
index 3b096e1c97..2e859617f9 100644
--- a/DMCompiler/Bytecode/StringFormatEncoder.cs
+++ b/DMCompiler/Bytecode/StringFormatEncoder.cs
@@ -90,26 +90,10 @@ public static bool Decode(char c, [NotNullWhen(true)] out FormatSuffix? suffix)
return true;
}
- public static bool Decode(char c) {
- ushort bytes = c;
- return (bytes & FormatPrefix) == FormatPrefix; // Could also check that the lower byte is a valid enum but... ehhhhh
- }
-
/// true if argument is a marker for an interpolated value, one of them [] things. false if not.
public static bool IsInterpolation(FormatSuffix suffix) {
//This logic requires that all the interpolated-value enums keep separated from the others.
//I'd write some type-engine code to catch a discrepancy in that but alas, this language is just not OOPy enough.
return suffix <= FormatSuffix.ReferenceOfValue;
}
-
- /// A new version of the string, with all formatting characters removed.
- public static string RemoveFormatting(string input) {
- StringBuilder ret = new StringBuilder(input.Length); // Trying to keep it to one malloc here
- foreach(char c in input) {
- if(!Decode(c))
- ret.Append(c);
- }
-
- return ret.ToString();
- }
}
diff --git a/OpenDreamClient/Input/ContextMenu/ContextMenuPopup.xaml.cs b/OpenDreamClient/Input/ContextMenu/ContextMenuPopup.xaml.cs
index 3e90159083..2effcc7461 100644
--- a/OpenDreamClient/Input/ContextMenu/ContextMenuPopup.xaml.cs
+++ b/OpenDreamClient/Input/ContextMenu/ContextMenuPopup.xaml.cs
@@ -62,7 +62,7 @@ public void RepopulateEntities(ScalingViewport viewport, Vector2 relativePos, Sc
continue;
var reference = new ClientObjectReference(_entityManager.GetNetEntity(uid));
- var name = _appearanceSystem.GetName(reference);
+ var name = _appearanceSystem.GetNameUnformatted(reference);
ContextMenu.AddChild(new ContextMenuItem(this, reference, name, sprite.Icon));
}
@@ -74,7 +74,7 @@ public void RepopulateEntities(ScalingViewport viewport, Vector2 relativePos, Sc
if (_spriteQuery.TryGetComponent(uid, out var sprite) &&
sprite.Icon.Appearance?.MouseOpacity != MouseOpacity.Transparent) {
var reference = new ClientObjectReference(_entityManager.GetNetEntity(uid));
- var name = _appearanceSystem.GetName(reference);
+ var name = _appearanceSystem.GetNameUnformatted(reference);
ContextMenu.AddChild(new ContextMenuItem(this, reference, name, sprite.Icon));
}
}
@@ -82,7 +82,7 @@ public void RepopulateEntities(ScalingViewport viewport, Vector2 relativePos, Sc
// Append the turf to the end of the context menu
var turfUnderMouse = _mouseInputSystem.GetTurfUnderMouse(mapCoords, out var turfId)?.Atom;
if (turfUnderMouse is not null && turfId is not null) {
- var name = _appearanceSystem.GetName(turfUnderMouse.Value);
+ var name = _appearanceSystem.GetNameUnformatted(turfUnderMouse.Value);
var icon = _appearanceSystem.GetTurfIcon(turfId.Value);
ContextMenu.AddChild(new ContextMenuItem(this, turfUnderMouse.Value, name, icon));
diff --git a/OpenDreamClient/Interface/Controls/ControlMap.cs b/OpenDreamClient/Interface/Controls/ControlMap.cs
index 018a45a194..21b7ae429f 100644
--- a/OpenDreamClient/Interface/Controls/ControlMap.cs
+++ b/OpenDreamClient/Interface/Controls/ControlMap.cs
@@ -140,7 +140,7 @@ public override bool TryGetProperty(string property, [NotNullWhen(true)] out IDM
private void UpdateAtomUnderMouse(ClientObjectReference? atom, Vector2 relativePos, Vector2i iconPos) {
if (!_atomUnderMouse.Equals(atom)) {
_entitySystemManager.Resolve(ref _appearanceSystem);
- var name = (atom != null) ? _appearanceSystem.GetName(atom.Value) : string.Empty;
+ var name = (atom != null) ? _appearanceSystem.GetNameUnformatted(atom.Value) : string.Empty;
Window?.SetStatus(name);
if (_atomUnderMouse != null)
diff --git a/OpenDreamClient/Rendering/ClientAppearanceSystem.cs b/OpenDreamClient/Rendering/ClientAppearanceSystem.cs
index d3913ad484..ee59b5b115 100644
--- a/OpenDreamClient/Rendering/ClientAppearanceSystem.cs
+++ b/OpenDreamClient/Rendering/ClientAppearanceSystem.cs
@@ -350,7 +350,7 @@ public bool TryGetAppearance(ClientObjectReference reference, [NotNullWhen(true)
return false;
}
- public string GetName(ClientObjectReference reference) {
+ public string GetNameUnformatted(ClientObjectReference reference) {
switch (reference.Type) {
case ClientObjectReference.RefType.Client:
return _playerManager.LocalSession?.Name ?? "";
@@ -359,7 +359,7 @@ public string GetName(ClientObjectReference reference) {
if (!TryGetAppearance(reference, out var appearance))
break;
- return appearance.Name;
+ return StringFormatDecoder.RemoveFormatting(appearance.Name);
}
return "";
diff --git a/OpenDreamClient/Rendering/MapTextRenderer.cs b/OpenDreamClient/Rendering/MapTextRenderer.cs
index d1b4aa6fd0..59badd82bb 100644
--- a/OpenDreamClient/Rendering/MapTextRenderer.cs
+++ b/OpenDreamClient/Rendering/MapTextRenderer.cs
@@ -1,6 +1,7 @@
using System.Diagnostics.Contracts;
using System.Text;
using OpenDreamClient.Interface.Html;
+using OpenDreamShared.Dream;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface.RichText;
@@ -26,7 +27,7 @@ public void RenderToTarget(DrawingHandleWorld handle, IRenderTexture texture, st
handle.SetTransform(DreamViewOverlay.CreateRenderTargetFlipMatrix(texture.Size, Vector2.Zero));
var message = new FormattedMessage();
- HtmlParser.Parse(maptext, message);
+ HtmlParser.Parse(StringFormatDecoder.RemoveFormatting(maptext), message);
var (height, lineBreaks) = ProcessWordWrap(message, texture.Size.X);
var lineHeight = _defaultFont.GetLineHeight(Scale);
diff --git a/OpenDreamRuntime/DreamConnection.cs b/OpenDreamRuntime/DreamConnection.cs
index 94ea63c49a..6b1e7c7638 100644
--- a/OpenDreamRuntime/DreamConnection.cs
+++ b/OpenDreamRuntime/DreamConnection.cs
@@ -284,7 +284,7 @@ public void OutputDreamValue(DreamValue value) {
// Prune any remaining formatting
var message = value.Stringify();
- message = StringFormatEncoder.RemoveFormatting(message);
+ message = StringFormatDecoder.RemoveFormatting(message);
OutputControl(message, null);
}
diff --git a/OpenDreamRuntime/Objects/DreamObject.cs b/OpenDreamRuntime/Objects/DreamObject.cs
index 8d339c9cc8..f76e6c6faa 100644
--- a/OpenDreamRuntime/Objects/DreamObject.cs
+++ b/OpenDreamRuntime/Objects/DreamObject.cs
@@ -7,6 +7,7 @@
using OpenDreamRuntime.Objects.Types;
using OpenDreamRuntime.Rendering;
using OpenDreamRuntime.Resources;
+using OpenDreamShared.Dream;
using Robust.Server.GameObjects;
using Robust.Server.GameStates;
using Robust.Shared.Map;
@@ -371,7 +372,7 @@ public virtual string GetDisplayName(StringFormatEncoder.FormatSuffix? suffix =
var name = GetRawName();
bool isProper = StringIsProper(name);
- name = StringFormatEncoder.RemoveFormatting(name); // TODO: Care about other formatting macros for obj names beyond \proper & \improper
+ name = StringFormatDecoder.RemoveFormatting(name); // TODO: Care about other formatting macros for obj names beyond \proper & \improper
if(!isProper) {
return name;
}
@@ -390,7 +391,7 @@ public virtual string GetDisplayName(StringFormatEncoder.FormatSuffix? suffix =
/// Similar to except it just returns the name as plaintext, with formatting removed. No article or anything.
///
public string GetNameUnformatted() {
- return StringFormatEncoder.RemoveFormatting(GetRawName());
+ return StringFormatDecoder.RemoveFormatting(GetRawName());
}
///
diff --git a/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs b/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs
index 825115ed8d..5eaa479384 100644
--- a/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs
+++ b/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs
@@ -444,7 +444,7 @@ public static ProcStatus FormatString(DMProcState state) {
if (interps[nextInterpIndex].TryGetValueAsDreamObject(out var dreamObject)) {
formattedString.Append(dreamObject.GetNameUnformatted());
} else if (interps[nextInterpIndex].TryGetValueAsString(out var interpStr)) {
- formattedString.Append(StringFormatEncoder.RemoveFormatting(interpStr));
+ formattedString.Append(StringFormatDecoder.RemoveFormatting(interpStr));
}
// NOTE probably should put this above the TryGetAsDreamObject function and continue if formatting has occured
diff --git a/OpenDreamRuntime/Procs/Native/DreamProcNativeRoot.cs b/OpenDreamRuntime/Procs/Native/DreamProcNativeRoot.cs
index 7e9e71c385..a1d823f5cb 100644
--- a/OpenDreamRuntime/Procs/Native/DreamProcNativeRoot.cs
+++ b/OpenDreamRuntime/Procs/Native/DreamProcNativeRoot.cs
@@ -1233,7 +1233,7 @@ private static void JsonEncode(Utf8JsonWriter writer, DreamValue value) {
writer.WriteEndObject();
}
} else if (value.TryGetValueAsString(out var text))
- writer.WriteStringValue(text);
+ writer.WriteStringValue(StringFormatDecoder.RemoveFormatting(text));
else if (value.TryGetValueAsType(out var type))
writer.WriteStringValue(type.Path);
else if (value.TryGetValueAsProc(out var proc))
diff --git a/OpenDreamRuntime/Resources/ConsoleOutputResource.cs b/OpenDreamRuntime/Resources/ConsoleOutputResource.cs
index d1b5a2dad6..d41f3eafbf 100644
--- a/OpenDreamRuntime/Resources/ConsoleOutputResource.cs
+++ b/OpenDreamRuntime/Resources/ConsoleOutputResource.cs
@@ -1,5 +1,5 @@
-using DMCompiler.Bytecode;
using OpenDreamRuntime.Procs.DebugAdapter;
+using OpenDreamShared.Dream;
namespace OpenDreamRuntime.Resources;
@@ -22,7 +22,7 @@ public void WriteConsole(LogLevel logLevel, string sawmill, string message) {
public override void Output(DreamValue value) {
// Prune any remaining formatting
var message = value.Stringify();
- message = StringFormatEncoder.RemoveFormatting(message);
+ message = StringFormatDecoder.RemoveFormatting(message);
WriteConsole(LogLevel.Info, "world.log", message);
}
diff --git a/OpenDreamRuntime/Resources/DreamResource.cs b/OpenDreamRuntime/Resources/DreamResource.cs
index 72c3db81c0..654b434555 100644
--- a/OpenDreamRuntime/Resources/DreamResource.cs
+++ b/OpenDreamRuntime/Resources/DreamResource.cs
@@ -1,7 +1,8 @@
using System.IO;
-using DMCompiler.Bytecode;
+// ReSharper disable once RedundantUsingDirective
using System.Runtime.CompilerServices;
using System.Text;
+using OpenDreamShared.Dream;
namespace OpenDreamRuntime.Resources;
@@ -80,7 +81,7 @@ public virtual void Output(DreamValue value) {
}
// Prune any remaining formatting
- text = StringFormatEncoder.RemoveFormatting(text);
+ text = StringFormatDecoder.RemoveFormatting(text);
CreateDirectory();
File.AppendAllText(ResourcePath, text + "\r\n");
diff --git a/OpenDreamShared/Dream/StringFormatDecoder.cs b/OpenDreamShared/Dream/StringFormatDecoder.cs
new file mode 100644
index 0000000000..22e7fbbb09
--- /dev/null
+++ b/OpenDreamShared/Dream/StringFormatDecoder.cs
@@ -0,0 +1,25 @@
+using System.Text;
+
+namespace OpenDreamShared.Dream;
+
+public static class StringFormatDecoder {
+ ///
+ /// Refer to DMCompiler.Bytecode.StringFormatEncoder for documentation (can't cref cross-project)
+ ///
+ private static readonly ushort FormatPrefix = 0xFF00;
+
+ private static readonly StringBuilder UnformattedStringBuilder = new();
+
+ /// A new version of the string, with all formatting characters removed.
+ public static string RemoveFormatting(string input) {
+ UnformattedStringBuilder.Clear();
+ UnformattedStringBuilder.EnsureCapacity(input.Length); // Trying to keep it to one malloc here
+ foreach(char c in input) {
+ ushort bytes = c;
+ if((bytes & FormatPrefix) != FormatPrefix)
+ UnformattedStringBuilder.Append(c);
+ }
+
+ return UnformattedStringBuilder.ToString();
+ }
+}