From 1e349f4369f2b3914d30c15d92852942d878993e Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Sun, 13 Apr 2025 22:55:44 -0700 Subject: [PATCH] fix: Fixes mutate speech character limit (#2157) ### Summary * Fixes the accidental limitation of dead character speech (OoOo) to 256 characters. * Optimizes it by 1.5x ```cs | Method | Mean | Error | StdDev | Allocated | |------------------------ |----------:|---------:|---------:|----------:| | ManuaLoopMutation | 147.01 ns | 1.298 ns | 1.084 ns | - | | SpanLoopMutation | 92.03 ns | 0.583 ns | 0.487 ns | - | ``` --- Projects/Server/Mobiles/Mobile.cs | 53 +++++++++++++++---------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/Projects/Server/Mobiles/Mobile.cs b/Projects/Server/Mobiles/Mobile.cs index 66064b87b..e82692ab0 100644 --- a/Projects/Server/Mobiles/Mobile.cs +++ b/Projects/Server/Mobiles/Mobile.cs @@ -29,6 +29,7 @@ using Server.Text; using System; using System.Collections.Generic; using System.Runtime.CompilerServices; +using Server.Buffers; using CalcMoves = Server.Movement.Movement; namespace Server; @@ -5371,13 +5372,32 @@ public partial class Mobile : IHued, IComparable, ISpawnable, IObjectPro return false; } - using var sb = new ValueStringBuilder(stackalloc char[Math.Min(text.Length, 256)]); - for (var i = 0; i < text.Length; ++i) + ReadOnlySpan ghostChars = (GhostChars ?? DefaultGhostChars).AsSpan(); + + var length = text.Length; + char[] rentedChars = null; + Span chars = length <= 256 + ? stackalloc char[length] + : rentedChars = STArrayPool.Shared.Rent(length); + + try { - sb.Append(text[i] != ' ' ? (GhostChars ?? DefaultGhostChars).RandomElement() : ' '); + var textSpan = text.AsSpan(); + for (var i = 0; i < textSpan.Length; ++i) + { + chars[i] = textSpan[i] != ' ' ? ghostChars.RandomElement() : ' '; + } + + text = new string(chars[..length]); + } + finally + { + if (rentedChars != null) + { + STArrayPool.Shared.Return(rentedChars); + } } - text = sb.ToString(); context = m_GhostMutateContext; return true; } @@ -5418,7 +5438,7 @@ public partial class Mobile : IHued, IComparable, ISpawnable, IObjectPro public virtual bool CheckHearsMutatedSpeech(Mobile m, object context) => context != m_GhostMutateContext || m.Alive && !m.CanHearGhosts; - private void AddSpeechItemsFrom(List list, Container cont) + private static void AddSpeechItemsFrom(List list, Container cont) { for (var i = 0; i < cont.Items.Count; ++i) { @@ -5470,33 +5490,12 @@ public partial class Mobile : IHued, IComparable, ISpawnable, IObjectPro break; } case MessageType.System: - { - break; - } case MessageType.Label: - { - break; - } case MessageType.Focus: - { - break; - } case MessageType.Spell: - { - break; - } case MessageType.Guild: - { - break; - } case MessageType.Alliance: - { - break; - } case MessageType.Command: - { - break; - } case MessageType.Encoded: { break; @@ -7988,7 +7987,7 @@ public partial class Mobile : IHued, IComparable, ISpawnable, IObjectPro public static TimeSpan GetManaRegenRate(Mobile m) => ManaRegenRateHandler?.Invoke(m) ?? DefaultManaRate; - public static char[] DefaultGhostChars = { 'o', 'O' }; + public static readonly char[] DefaultGhostChars = ['o', 'O']; public Prompt BeginPrompt(PromptCallback callback, PromptCallback cancelCallback) => Prompt = new SimplePrompt(callback, cancelCallback);