diff --git a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/MessagePacketTests.cs b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/MessagePacketTests.cs index cf9e83ca8..b5eb423f1 100644 --- a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/MessagePacketTests.cs +++ b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/MessagePacketTests.cs @@ -46,6 +46,29 @@ public class MessageTests AssertThat.Equal(result, expected); } + [Fact] + public void TestMessageLocalizedInterpolated() + { + var serial = (Serial)0x1024; + var graphic = 0x100; + var messageType = MessageType.Label; + var hue = 1024; + var font = 3; + var number = 150000; + var name = "Stuff"; + var argValue = 42; + + var expected = new MessageLocalized( + serial, graphic, messageType, hue, font, number, name, $"value: {argValue}" + ).Compile(); + + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendMessageLocalized(serial, graphic, messageType, hue, font, number, name, $"value: {argValue}"); + + var result = ns.SendBuffer.GetReadSpan(); + AssertThat.Equal(result, expected); + } + [Fact] public void TestMessageLocalizedAffix() { @@ -91,6 +114,59 @@ public class MessageTests AssertThat.Equal(result, expected); } + [Fact] + public void TestMessageLocalizedAffixInterpolated() + { + var serial = (Serial)0x1024; + var graphic = 0x100; + var messageType = MessageType.Label; + var hue = 1024; + var font = 3; + var number = 150000; + var name = "Stuff"; + var affixType = AffixType.System; + var affix = "Affix"; + var argValue = 42; + + var expected = new MessageLocalizedAffix( + serial, graphic, messageType, hue, font, number, name, affixType, affix, $"value: {argValue}" + ).Compile(); + + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendMessageLocalizedAffix( + serial, graphic, messageType, hue, font, number, name, affixType, affix, + $"value: {argValue}" + ); + + var result = ns.SendBuffer.GetReadSpan(); + AssertThat.Equal(result, expected); + } + + [Fact] + public void TestUnicodeMessageInterpolated() + { + var serial = (Serial)0x1024; + var graphic = 0x100; + var messageType = MessageType.Label; + var hue = 1024; + var font = 3; + var lang = "ENU"; + var name = "Stuff"; + var who = "Alice"; + + var expected = new UnicodeMessage( + serial, graphic, messageType, hue, font, lang, name, $"hello, {who}" + ).Compile(); + + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendMessage( + serial, graphic, messageType, hue, font, false, lang, name, $"hello, {who}" + ); + + var result = ns.SendBuffer.GetReadSpan(); + AssertThat.Equal(result, expected); + } + [Fact] public void TestAsciiMessage() { diff --git a/Projects/Server/Items/Item.Messages.cs b/Projects/Server/Items/Item.Messages.cs new file mode 100644 index 000000000..b8e24aa17 --- /dev/null +++ b/Projects/Server/Items/Item.Messages.cs @@ -0,0 +1,139 @@ +/************************************************************************* + * ModernUO * + * Copyright 2019-2026 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: Item.Messages.cs * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using Server.Buffers; +using Server.Network; + +namespace Server; + +public partial class Item +{ + private readonly struct PublicVisibilityFilter : IBroadcastFilter + { + private readonly Item _source; + private readonly Point3D _worldLoc; + + public PublicVisibilityFilter(Item source, Point3D worldLoc) + { + _source = source; + _worldLoc = worldLoc; + } + + public bool Allow(NetState state) + { + var m = state.Mobile; + return m.CanSee(_source) && m.InRange(_worldLoc, _source.GetUpdateRange(m)); + } + } + + public void PublicOverheadMessage(MessageType type, int hue, bool ascii, ReadOnlySpan text) + { + var worldLoc = GetWorldLocation(); + OutgoingMessagePackets.BroadcastMessage( + m_Map, worldLoc, GetMaxUpdateRange(), + Serial, m_ItemID, type, hue, 3, ascii, "ENU", Name, text, + new PublicVisibilityFilter(this, worldLoc) + ); + } + + public void PublicOverheadMessage(MessageType type, int hue, int number, ReadOnlySpan args = default) + { + var worldLoc = GetWorldLocation(); + OutgoingMessagePackets.BroadcastMessageLocalized( + m_Map, worldLoc, GetMaxUpdateRange(), + Serial, m_ItemID, type, hue, 3, number, Name, args, + new PublicVisibilityFilter(this, worldLoc) + ); + } + + public void SendLocalizedMessageTo(Mobile to, int number, ReadOnlySpan args = default) + { + if (Deleted || !to.CanSee(this)) + { + return; + } + + to?.NetState?.SendMessageLocalized(Serial, ItemID, MessageType.Regular, 0x3B2, 3, number, "", args); + } + + public void SendLocalizedMessageTo(Mobile to, int number, AffixType affixType, ReadOnlySpan affix, ReadOnlySpan args) + { + if (Deleted || !to.CanSee(this)) + { + return; + } + + to?.NetState?.SendMessageLocalizedAffix( + Serial, + ItemID, + MessageType.Regular, + 0x3B2, + 3, + number, + "", + affixType, + affix, + args + ); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SendLocalizedMessageTo(Mobile to, int number, int hue, ReadOnlySpan args = default) + => to?.NetState?.SendMessageLocalized(Serial, ItemID, MessageType.Regular, hue, 3, number, "", args); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SendMessageTo(Mobile to, ReadOnlySpan text, int hue = 0x3B2) + => to?.NetState?.SendMessage(Serial, ItemID, MessageType.Regular, hue, 3, false, "ENU", "", text); + + // ---------- Interpolated handler overloads ---------- + + public void PublicOverheadMessage(MessageType type, int hue, bool ascii, ref RawInterpolatedStringHandler text) + { + PublicOverheadMessage(type, hue, ascii, text.Text); + text.Clear(); + } + + public void PublicOverheadMessage(MessageType type, int hue, int number, ref RawInterpolatedStringHandler args) + { + PublicOverheadMessage(type, hue, number, args.Text); + args.Clear(); + } + + public void SendLocalizedMessageTo(Mobile to, int number, ref RawInterpolatedStringHandler args) + { + SendLocalizedMessageTo(to, number, args.Text); + args.Clear(); + } + + public void SendLocalizedMessageTo(Mobile to, int number, AffixType affixType, ReadOnlySpan affix, ref RawInterpolatedStringHandler args) + { + SendLocalizedMessageTo(to, number, affixType, affix, args.Text); + args.Clear(); + } + + public void SendLocalizedMessageTo(Mobile to, int number, int hue, ref RawInterpolatedStringHandler args) + { + SendLocalizedMessageTo(to, number, hue, args.Text); + args.Clear(); + } + + public void SendMessageTo(Mobile to, int hue, ref RawInterpolatedStringHandler text) + { + SendMessageTo(to, text.Text, hue); + text.Clear(); + } +} diff --git a/Projects/Server/Items/Item.cs b/Projects/Server/Items/Item.cs index fbb79a414..0e75c175b 100644 --- a/Projects/Server/Items/Item.cs +++ b/Projects/Server/Items/Item.cs @@ -3312,68 +3312,6 @@ public partial class Item : IHued, IComparable, ISpawnable, IObjectPropert Delete(); } - public void PublicOverheadMessage(MessageType type, int hue, bool ascii, string text) - { - if (m_Map == null) - { - return; - } - - var worldLoc = GetWorldLocation(); - - var buffer = stackalloc byte[OutgoingMessagePackets.GetMaxMessageLength(text)].InitializePacket(); - - foreach (var state in m_Map.GetClientsInRange(worldLoc, GetMaxUpdateRange())) - { - var m = state.Mobile; - - if (m.CanSee(this) && m.InRange(worldLoc, GetUpdateRange(m))) - { - var length = OutgoingMessagePackets.CreateMessage( - buffer, Serial, m_ItemID, type, hue, 3, ascii, "ENU", Name, text - ); - - if (length != buffer.Length) - { - buffer = buffer[..length]; // Adjust to the actual size - } - - state.Send(buffer); - } - } - } - - public void PublicOverheadMessage(MessageType type, int hue, int number, string args = "") - { - if (m_Map == null) - { - return; - } - - var worldLoc = GetWorldLocation(); - - var buffer = stackalloc byte[OutgoingMessagePackets.GetMaxMessageLocalizedLength(args)].InitializePacket(); - - foreach (var state in m_Map.GetClientsInRange(worldLoc, GetMaxUpdateRange())) - { - var m = state.Mobile; - - if (m.CanSee(this) && m.InRange(worldLoc, GetUpdateRange(m))) - { - var length = OutgoingMessagePackets.CreateMessageLocalized( - buffer, Serial, m_ItemID, type, hue, 3, number, Name, args - ); - - if (length != buffer.Length) - { - buffer = buffer[..length]; // Adjust to the actual size - } - - state.Send(buffer); - } - } - } - public virtual void OnAfterDelete() { } @@ -3898,37 +3836,6 @@ public partial class Item : IHued, IComparable, ISpawnable, IObjectPropert ); } - public void SendLocalizedMessageTo(Mobile to, int number, string args = "") - { - if (Deleted || !to.CanSee(this)) - { - return; - } - - to.NetState.SendMessageLocalized(Serial, ItemID, MessageType.Regular, 0x3B2, 3, number, "", args); - } - - public void SendLocalizedMessageTo(Mobile to, int number, AffixType affixType, string affix, string args) - { - if (Deleted || !to.CanSee(this)) - { - return; - } - - to.NetState.SendMessageLocalizedAffix( - Serial, - ItemID, - MessageType.Regular, - 0x3B2, - 3, - number, - "", - affixType, - affix, - args - ); - } - public virtual void OnSnoop(Mobile from) { } diff --git a/Projects/Server/Mobiles/Mobile.Messages.cs b/Projects/Server/Mobiles/Mobile.Messages.cs new file mode 100644 index 000000000..29331c5c6 --- /dev/null +++ b/Projects/Server/Mobiles/Mobile.Messages.cs @@ -0,0 +1,389 @@ +/************************************************************************* + * ModernUO * + * Copyright 2019-2026 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: Mobile.Messages.cs * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using Server.Buffers; +using Server.Network; + +namespace Server; + +public partial class Mobile +{ + // ---------- Broadcast filter structs ---------- + + private readonly struct PublicVisibilityFilter : IBroadcastFilter + { + private readonly Mobile _source; + private readonly bool _noLineOfSight; + private readonly AccessLevel _accessLevel; + + public PublicVisibilityFilter(Mobile source, bool noLineOfSight, AccessLevel accessLevel) + { + _source = source; + _noLineOfSight = noLineOfSight; + _accessLevel = accessLevel; + } + + public bool Allow(NetState state) => + state.Mobile.AccessLevel >= _accessLevel && + state.Mobile.CanSee(_source) && + (_noLineOfSight || state.Mobile.InLOS(_source)); + } + + private readonly struct LocalizedVisibilityFilter : IBroadcastFilter + { + private readonly Mobile _source; + private readonly bool _noLineOfSight; + + public LocalizedVisibilityFilter(Mobile source, bool noLineOfSight) + { + _source = source; + _noLineOfSight = noLineOfSight; + } + + public bool Allow(NetState state) => state.Mobile.CanSee(_source) && (_noLineOfSight || state.Mobile.InLOS(_source)); + } + + private readonly struct NonlocalVisibilityFilter : IBroadcastFilter + { + private readonly Mobile _source; + private readonly NetState _exclude; + + public NonlocalVisibilityFilter(Mobile source, NetState exclude) + { + _source = source; + _exclude = exclude; + } + + public bool Allow(NetState state) => state != _exclude && state.Mobile.CanSee(_source); + } + + // ---------- Say / Emote / Whisper / Yell ---------- + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Say(bool ascii, ReadOnlySpan text) => + PublicOverheadMessage(MessageType.Regular, SpeechHue, ascii, text); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Say(ReadOnlySpan text) => + PublicOverheadMessage(MessageType.Regular, SpeechHue, false, text); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Say(int number, AffixType type, ReadOnlySpan affix, ReadOnlySpan args) => + PublicOverheadMessage(MessageType.Regular, SpeechHue, number, type, affix, args); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Say(int number, ReadOnlySpan args = default) => + PublicOverheadMessage(MessageType.Regular, SpeechHue, number, args); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Emote(ReadOnlySpan text) => + PublicOverheadMessage(MessageType.Emote, EmoteHue, false, text); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Emote(int number, ReadOnlySpan args = default) => + PublicOverheadMessage(MessageType.Emote, EmoteHue, number, args); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Whisper(ReadOnlySpan text) => + PublicOverheadMessage(MessageType.Whisper, WhisperHue, false, text); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Whisper(int number, ReadOnlySpan args = default) => + PublicOverheadMessage(MessageType.Whisper, WhisperHue, number, args); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Yell(ReadOnlySpan text) => + PublicOverheadMessage(MessageType.Yell, YellHue, false, text); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Yell(int number, ReadOnlySpan args = default) => + PublicOverheadMessage(MessageType.Yell, YellHue, number, args); + + // ---------- PublicOverheadMessage ---------- + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PublicOverheadMessage( + MessageType type, int hue, bool ascii, ReadOnlySpan text, bool noLineOfSight = true, + AccessLevel accessLevel = AccessLevel.Player + ) => OutgoingMessagePackets.BroadcastMessage( + m_Map, m_Location, + Serial, Body, type, hue, 3, ascii, Language, Name, text, + new PublicVisibilityFilter(this, noLineOfSight, accessLevel) + ); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PublicOverheadMessage( + MessageType type, int hue, int number, ReadOnlySpan args = default, bool noLineOfSight = true + ) => OutgoingMessagePackets.BroadcastMessageLocalized( + m_Map, m_Location, + Serial, Body, type, hue, 3, number, Name, args, + new LocalizedVisibilityFilter(this, noLineOfSight)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PublicOverheadMessage( + MessageType type, int hue, int number, AffixType affixType, ReadOnlySpan affix, + ReadOnlySpan args = default, bool noLineOfSight = false, + AccessLevel accessLevel = AccessLevel.Player + ) => OutgoingMessagePackets.BroadcastMessageLocalizedAffix( + m_Map, m_Location, + Serial, Body, type, hue, 3, number, Name, affixType, affix, args, + new PublicVisibilityFilter(this, noLineOfSight, accessLevel) + ); + + // ---------- PrivateOverheadMessage ---------- + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PrivateOverheadMessage(MessageType type, int hue, bool ascii, ReadOnlySpan text, NetState state) => + state.SendMessage(Serial, Body, type, hue, 3, ascii, m_Language, Name, text); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PrivateOverheadMessage(MessageType type, int hue, int number, NetState state) => + PrivateOverheadMessage(type, hue, number, default, state); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PrivateOverheadMessage(MessageType type, int hue, int number, ReadOnlySpan args, NetState state) => + state.SendMessageLocalized(Serial, Body, type, hue, 3, number, Name, args); + + // ---------- LocalOverheadMessage ---------- + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void LocalOverheadMessage(MessageType type, int hue, bool ascii, ReadOnlySpan text) => + m_NetState.SendMessage(Serial, Body, type, hue, 3, ascii, m_Language, Name, text); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void LocalOverheadMessage(MessageType type, int hue, int number, ReadOnlySpan args = default) => + m_NetState.SendMessageLocalized(Serial, Body, type, hue, 3, number, Name, args); + + // ---------- NonlocalOverheadMessage ---------- + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void NonlocalOverheadMessage(MessageType type, int hue, int number, ReadOnlySpan args = default) => + OutgoingMessagePackets.BroadcastMessageLocalized( + m_Map, m_Location, + Serial, Body, type, hue, 3, number, Name, args, + new NonlocalVisibilityFilter(this, m_NetState) + ); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void NonlocalOverheadMessage(MessageType type, int hue, bool ascii, ReadOnlySpan text) => + OutgoingMessagePackets.BroadcastMessage( + m_Map, m_Location, + Serial, Body, type, hue, 3, ascii, Language, Name, text, + new NonlocalVisibilityFilter(this, m_NetState) + ); + + // ---------- SendLocalizedMessage / SendMessage / SendAsciiMessage ---------- + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SendLocalizedMessage(int number, ReadOnlySpan args = default, int hue = 0x3B2) => + m_NetState.SendMessageLocalized(Serial.MinusOne, -1, MessageType.Regular, hue, 3, number, "System", args); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SendLocalizedMessage( + int number, bool append, ReadOnlySpan affix, ReadOnlySpan args = default, int hue = 0x3B2 + ) => m_NetState.SendMessageLocalizedAffix( + Serial.MinusOne, + -1, + MessageType.Regular, + hue, + 3, + number, + "System", + (append ? AffixType.Append : AffixType.Prepend) | AffixType.System, + affix, + args + ); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SendMessage(ReadOnlySpan text) => SendMessage(0x3B2, text); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SendMessage(int hue, ReadOnlySpan text) => + m_NetState.SendMessage(Serial.MinusOne, -1, MessageType.Regular, hue, 3, false, "ENU", "System", text); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SendAsciiMessage(ReadOnlySpan text) => SendAsciiMessage(0x3B2, text); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SendAsciiMessage(int hue, ReadOnlySpan text) => + m_NetState.SendMessage(Serial.MinusOne, -1, MessageType.Regular, hue, 3, true, null, "System", text); + + // ---------- Interpolated handler overloads ---------- + + public void Say(bool ascii, ref RawInterpolatedStringHandler text) + { + PublicOverheadMessage(MessageType.Regular, SpeechHue, ascii, text.Text); + text.Clear(); + } + + public void Say(ref RawInterpolatedStringHandler text) + { + PublicOverheadMessage(MessageType.Regular, SpeechHue, false, text.Text); + text.Clear(); + } + + public void Say(int number, AffixType type, ReadOnlySpan affix, ref RawInterpolatedStringHandler args) + { + PublicOverheadMessage(MessageType.Regular, SpeechHue, number, type, affix, args.Text); + args.Clear(); + } + + public void Say(int number, ref RawInterpolatedStringHandler args) + { + PublicOverheadMessage(MessageType.Regular, SpeechHue, number, args.Text); + args.Clear(); + } + + public void Emote(ref RawInterpolatedStringHandler text) + { + PublicOverheadMessage(MessageType.Emote, EmoteHue, false, text.Text); + text.Clear(); + } + + public void Emote(int number, ref RawInterpolatedStringHandler args) + { + PublicOverheadMessage(MessageType.Emote, EmoteHue, number, args.Text); + args.Clear(); + } + + public void Whisper(ref RawInterpolatedStringHandler text) + { + PublicOverheadMessage(MessageType.Whisper, WhisperHue, false, text.Text); + text.Clear(); + } + + public void Whisper(int number, ref RawInterpolatedStringHandler args) + { + PublicOverheadMessage(MessageType.Whisper, WhisperHue, number, args.Text); + args.Clear(); + } + + public void Yell(ref RawInterpolatedStringHandler text) + { + PublicOverheadMessage(MessageType.Yell, YellHue, false, text.Text); + text.Clear(); + } + + public void Yell(int number, ref RawInterpolatedStringHandler args) + { + PublicOverheadMessage(MessageType.Yell, YellHue, number, args.Text); + args.Clear(); + } + + public void PublicOverheadMessage( + MessageType type, int hue, bool ascii, ref RawInterpolatedStringHandler text, bool noLineOfSight = true, + AccessLevel accessLevel = AccessLevel.Player + ) + { + PublicOverheadMessage(type, hue, ascii, text.Text, noLineOfSight, accessLevel); + text.Clear(); + } + + public void PublicOverheadMessage(MessageType type, int hue, int number, ref RawInterpolatedStringHandler args, bool noLineOfSight = true) + { + PublicOverheadMessage(type, hue, number, args.Text, noLineOfSight); + args.Clear(); + } + + public void PublicOverheadMessage( + MessageType type, int hue, int number, AffixType affixType, ReadOnlySpan affix, + ref RawInterpolatedStringHandler args, bool noLineOfSight = false, + AccessLevel accessLevel = AccessLevel.Player + ) + { + PublicOverheadMessage(type, hue, number, affixType, affix, args.Text, noLineOfSight, accessLevel); + args.Clear(); + } + + public void PrivateOverheadMessage( + MessageType type, int hue, bool ascii, ref RawInterpolatedStringHandler text, NetState state + ) + { + PrivateOverheadMessage(type, hue, ascii, text.Text, state); + text.Clear(); + } + + public void PrivateOverheadMessage( + MessageType type, int hue, int number, ref RawInterpolatedStringHandler args, NetState state + ) + { + PrivateOverheadMessage(type, hue, number, args.Text, state); + args.Clear(); + } + + public void LocalOverheadMessage(MessageType type, int hue, bool ascii, ref RawInterpolatedStringHandler text) + { + LocalOverheadMessage(type, hue, ascii, text.Text); + text.Clear(); + } + + public void LocalOverheadMessage(MessageType type, int hue, int number, ref RawInterpolatedStringHandler args) + { + LocalOverheadMessage(type, hue, number, args.Text); + args.Clear(); + } + + public void NonlocalOverheadMessage(MessageType type, int hue, int number, ref RawInterpolatedStringHandler args) + { + NonlocalOverheadMessage(type, hue, number, args.Text); + args.Clear(); + } + + public void NonlocalOverheadMessage(MessageType type, int hue, bool ascii, ref RawInterpolatedStringHandler text) + { + NonlocalOverheadMessage(type, hue, ascii, text.Text); + text.Clear(); + } + + public void SendLocalizedMessage(int number, ref RawInterpolatedStringHandler args, int hue = 0x3B2) + { + SendLocalizedMessage(number, args.Text, hue); + args.Clear(); + } + + public void SendLocalizedMessage( + int number, bool append, ReadOnlySpan affix, ref RawInterpolatedStringHandler args, int hue = 0x3B2 + ) + { + SendLocalizedMessage(number, append, affix, args.Text, hue); + args.Clear(); + } + + public void SendMessage(ref RawInterpolatedStringHandler text) + { + SendMessage(0x3B2, text.Text); + text.Clear(); + } + + public void SendMessage(int hue, ref RawInterpolatedStringHandler text) + { + SendMessage(hue, text.Text); + text.Clear(); + } + + public void SendAsciiMessage(ref RawInterpolatedStringHandler text) + { + SendAsciiMessage(0x3B2, text.Text); + text.Clear(); + } + + public void SendAsciiMessage(int hue, ref RawInterpolatedStringHandler text) + { + SendAsciiMessage(hue, text.Text); + text.Clear(); + } +} diff --git a/Projects/Server/Mobiles/Mobile.cs b/Projects/Server/Mobiles/Mobile.cs index 385e70ad9..9c138641a 100644 --- a/Projects/Server/Mobiles/Mobile.cs +++ b/Projects/Server/Mobiles/Mobile.cs @@ -5611,9 +5611,9 @@ public partial class Mobile : IHued, IComparable, ISpawnable, IObjectPro ProcessDelta(); - var regBuffer = stackalloc byte[OutgoingMessagePackets.GetMaxMessageLength(text)].InitializePacket(); + var regBuffer = stackalloc byte[OutgoingMessagePackets.GetMaxMessageLength(text.Length)].InitializePacket(); var mutBuffer = - stackalloc byte[OutgoingMessagePackets.GetMaxMessageLength(mutatedText)].InitializePacket(); + stackalloc byte[OutgoingMessagePackets.GetMaxMessageLength(mutatedText.Length)].InitializePacket(); // TODO: Should this be sorted like onSpeech is below? for (var i = 0; i < hears.Count; ++i) @@ -8089,29 +8089,6 @@ public partial class Mobile : IHued, IComparable, ISpawnable, IObjectPro public void SayTo(Mobile to, int number, string args = "") => to.NetState.SendMessageLocalized(Serial, Body, MessageType.Regular, SpeechHue, 3, number, Name, args); - public void Say(bool ascii, string text) => PublicOverheadMessage(MessageType.Regular, SpeechHue, ascii, text); - - public void Say(string text) => PublicOverheadMessage(MessageType.Regular, SpeechHue, false, text); - - public void Say(int number, AffixType type, string affix, string args) => - PublicOverheadMessage(MessageType.Regular, SpeechHue, number, type, affix, args); - - public void Say(int number, string args = "") => PublicOverheadMessage(MessageType.Regular, SpeechHue, number, args); - - public void Emote(string text) => PublicOverheadMessage(MessageType.Emote, EmoteHue, false, text); - - public void Emote(int number, string args = "") => PublicOverheadMessage(MessageType.Emote, EmoteHue, number, args); - - public void Whisper(string text) => PublicOverheadMessage(MessageType.Whisper, WhisperHue, false, text); - - public void Whisper(int number, string args = "") => - PublicOverheadMessage(MessageType.Whisper, WhisperHue, number, args); - - public void Yell(string text) => PublicOverheadMessage(MessageType.Yell, YellHue, false, text); - - public void Yell(int number, string args = "") => - PublicOverheadMessage(MessageType.Yell, YellHue, number, args); - public bool SendHuePicker(HuePicker p) { if (m_NetState != null) @@ -8844,245 +8821,6 @@ public partial class Mobile : IHued, IComparable, ISpawnable, IObjectPro public Direction GetDirectionTo(IPoint2D p, bool run = false) => p == null ? Direction.North | (run ? Direction.Running : 0) : GetDirectionTo(p.X, p.Y, run); - public void PublicOverheadMessage( - MessageType type, int hue, bool ascii, string text, bool noLineOfSight = true, - AccessLevel accessLevel = AccessLevel.Player - ) - { - if (m_Map == null) - { - return; - } - - var buffer = stackalloc byte[OutgoingMessagePackets.GetMaxMessageLength(text)].InitializePacket(); - - foreach (var state in m_Map.GetClientsInRange(m_Location)) - { - if ( - state.Mobile.AccessLevel >= accessLevel && - state.Mobile.CanSee(this) && - (noLineOfSight || state.Mobile.InLOS(this)) - ) - { - var length = OutgoingMessagePackets.CreateMessage( - buffer, - Serial, - Body, - type, - hue, - 3, - ascii, - Language, - Name, - text - ); - - if (length != buffer.Length) - { - buffer = buffer[..length]; // Adjust to the actual size - } - - state.Send(buffer); - } - } - } - - public void PublicOverheadMessage(MessageType type, int hue, int number, string args = "", bool noLineOfSight = true) - { - if (m_Map == null) - { - return; - } - - var buffer = stackalloc byte[OutgoingMessagePackets.GetMaxMessageLocalizedLength(args)].InitializePacket(); - - foreach (var state in m_Map.GetClientsInRange(m_Location)) - { - if (state.Mobile.CanSee(this) && (noLineOfSight || state.Mobile.InLOS(this))) - { - var length = OutgoingMessagePackets.CreateMessageLocalized( - buffer, - Serial, - Body, - type, - hue, - 3, - number, - Name, - args - ); - - if (length != buffer.Length) - { - buffer = buffer[..length]; // Adjust to the actual size - } - - state.Send(buffer); - } - } - } - - public void PublicOverheadMessage( - MessageType type, int hue, int number, AffixType affixType, string affix, - string args = "", bool noLineOfSight = false, - AccessLevel accessLevel = AccessLevel.Player - ) - { - if (m_Map == null) - { - return; - } - - var buffer = stackalloc byte[OutgoingMessagePackets.GetMaxMessageLocalizedAffixLength(affix, args)] - .InitializePacket(); - - foreach (var state in m_Map.GetClientsInRange(m_Location)) - { - if ( - state.Mobile.AccessLevel >= accessLevel && - state.Mobile.CanSee(this) && - (noLineOfSight || state.Mobile.InLOS(this)) - ) - { - var length = OutgoingMessagePackets.CreateMessageLocalizedAffix( - buffer, - Serial, - Body, - type, - hue, - 3, - number, - Name, - affixType, - affix, - args - ); - - if (length != buffer.Length) - { - buffer = buffer[..length]; // Adjust to the actual size - } - - state.Send(buffer); - } - } - } - - public void PrivateOverheadMessage(MessageType type, int hue, bool ascii, string text, NetState state) - { - state.SendMessage(Serial, Body, type, hue, 3, ascii, m_Language, Name, text); - } - - public void PrivateOverheadMessage(MessageType type, int hue, int number, NetState state) => - PrivateOverheadMessage(type, hue, number, "", state); - - public void PrivateOverheadMessage(MessageType type, int hue, int number, string args, NetState state) => - state.SendMessageLocalized(Serial, Body, type, hue, 3, number, Name, args); - - public void LocalOverheadMessage(MessageType type, int hue, bool ascii, string text) => - m_NetState.SendMessage(Serial, Body, type, hue, 3, ascii, m_Language, Name, text); - - public void LocalOverheadMessage(MessageType type, int hue, int number, string args = "") => - m_NetState.SendMessageLocalized(Serial, Body, type, hue, 3, number, Name, args); - - public void NonlocalOverheadMessage(MessageType type, int hue, int number, string args = "") - { - if (m_Map == null) - { - return; - } - - var buffer = stackalloc byte[OutgoingMessagePackets.GetMaxMessageLocalizedLength(args)].InitializePacket(); - - foreach (var state in m_Map.GetClientsInRange(m_Location)) - { - if (state != m_NetState && state.Mobile.CanSee(this)) - { - var length = OutgoingMessagePackets.CreateMessageLocalized( - buffer, - Serial, - Body, - type, - hue, - 3, - number, - Name, - args - ); - - if (length != buffer.Length) - { - buffer = buffer[..length]; // Adjust to the actual size - } - - state.Send(buffer); - } - } - } - - public void NonlocalOverheadMessage(MessageType type, int hue, bool ascii, string text) - { - if (m_Map == null) - { - return; - } - - var buffer = stackalloc byte[OutgoingMessagePackets.GetMaxMessageLength(text)].InitializePacket(); - - foreach (var state in m_Map.GetClientsInRange(m_Location)) - { - if (state != m_NetState && state.Mobile.CanSee(this)) - { - var length = OutgoingMessagePackets.CreateMessage( - buffer, - Serial, - Body, - type, - hue, - 3, - ascii, - Language, - Name, - text - ); - - if (length != buffer.Length) - { - buffer = buffer[..length]; // Adjust to the actual size - } - - state.Send(buffer); - } - } - } - - public void SendLocalizedMessage(int number, string args = "", int hue = 0x3B2) => - m_NetState.SendMessageLocalized(Serial.MinusOne, -1, MessageType.Regular, hue, 3, number, "System", args); - - public void SendLocalizedMessage(int number, bool append, string affix, string args = "", int hue = 0x3B2) => - m_NetState.SendMessageLocalizedAffix( - Serial.MinusOne, - -1, - MessageType.Regular, - hue, - 3, - number, - "System", - (append ? AffixType.Append : AffixType.Prepend) | AffixType.System, - affix, - args - ); - - public void SendMessage(string text) => SendMessage(0x3B2, text); - - public void SendMessage(int hue, string text) => - m_NetState.SendMessage(Serial.MinusOne, -1, MessageType.Regular, hue, 3, false, "ENU", "System", text); - - public void SendAsciiMessage(string text) => SendAsciiMessage(0x3B2, text); - - public void SendAsciiMessage(int hue, string text) => - m_NetState.SendMessage(Serial.MinusOne, -1, MessageType.Regular, hue, 3, true, null, "System", text); - /// /// Overridable. Event invoked when the Mobile is double clicked. By default, this method can either dismount or open the /// paperdoll. diff --git a/Projects/Server/Network/Packets/IBroadcastFilter.cs b/Projects/Server/Network/Packets/IBroadcastFilter.cs new file mode 100644 index 000000000..5068b0a21 --- /dev/null +++ b/Projects/Server/Network/Packets/IBroadcastFilter.cs @@ -0,0 +1,21 @@ +/************************************************************************* + * ModernUO * + * Copyright 2019-2026 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: IBroadcastFilter.cs * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +namespace Server.Network; + +public interface IBroadcastFilter +{ + bool Allow(NetState state); +} diff --git a/Projects/Server/Network/Packets/OutgoingMessagePackets.Broadcast.cs b/Projects/Server/Network/Packets/OutgoingMessagePackets.Broadcast.cs new file mode 100644 index 000000000..dc48ff324 --- /dev/null +++ b/Projects/Server/Network/Packets/OutgoingMessagePackets.Broadcast.cs @@ -0,0 +1,182 @@ +/************************************************************************* + * ModernUO * + * Copyright 2019-2026 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: OutgoingMessagePackets.Broadcast.cs * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; + +namespace Server.Network; + +public static partial class OutgoingMessagePackets +{ + public static void BroadcastMessageLocalized( + Map map, Point3D location, + Serial serial, int graphic, MessageType type, int hue, int font, + int number, ReadOnlySpan name, ReadOnlySpan args, + TFilter filter + ) where TFilter : struct, IBroadcastFilter + { + if (map == null) + { + return; + } + + var buffer = stackalloc byte[GetMaxMessageLocalizedLength(args.Length)].InitializePacket(); + + foreach (var state in map.GetClientsInRange(location)) + { + if (filter.Allow(state)) + { + var length = CreateMessageLocalized( + buffer, serial, graphic, type, hue, font, number, name, args + ); + + if (length != buffer.Length) + { + buffer = buffer[..length]; + } + + state.Send(buffer); + } + } + } + + public static void BroadcastMessageLocalized( + Map map, Point3D location, int range, + Serial serial, int graphic, MessageType type, int hue, int font, + int number, ReadOnlySpan name, ReadOnlySpan args, + TFilter filter + ) where TFilter : struct, IBroadcastFilter + { + if (map == null) + { + return; + } + + var buffer = stackalloc byte[GetMaxMessageLocalizedLength(args.Length)].InitializePacket(); + + foreach (var state in map.GetClientsInRange(location, range)) + { + if (filter.Allow(state)) + { + var length = CreateMessageLocalized( + buffer, serial, graphic, type, hue, font, number, name, args + ); + + if (length != buffer.Length) + { + buffer = buffer[..length]; + } + + state.Send(buffer); + } + } + } + + public static void BroadcastMessageLocalizedAffix( + Map map, Point3D location, + Serial serial, int graphic, MessageType type, int hue, int font, + int number, ReadOnlySpan name, AffixType affixType, + ReadOnlySpan affix, ReadOnlySpan args, + TFilter filter + ) where TFilter : struct, IBroadcastFilter + { + if (map == null) + { + return; + } + + var buffer = stackalloc byte[GetMaxMessageLocalizedAffixLength(affix.Length, args.Length)].InitializePacket(); + + foreach (var state in map.GetClientsInRange(location)) + { + if (filter.Allow(state)) + { + var length = CreateMessageLocalizedAffix( + buffer, serial, graphic, type, hue, font, number, name, affixType, affix, args + ); + + if (length != buffer.Length) + { + buffer = buffer[..length]; + } + + state.Send(buffer); + } + } + } + + public static void BroadcastMessage( + Map map, Point3D location, + Serial serial, int graphic, MessageType type, int hue, int font, bool ascii, + string lang, ReadOnlySpan name, ReadOnlySpan text, + TFilter filter + ) where TFilter : struct, IBroadcastFilter + { + if (map == null) + { + return; + } + + var buffer = stackalloc byte[GetMaxMessageLength(text.Length)].InitializePacket(); + + foreach (var state in map.GetClientsInRange(location)) + { + if (filter.Allow(state)) + { + var length = CreateMessage( + buffer, serial, graphic, type, hue, font, ascii, lang, name, text + ); + + if (length != buffer.Length) + { + buffer = buffer[..length]; + } + + state.Send(buffer); + } + } + } + + public static void BroadcastMessage( + Map map, Point3D location, int range, + Serial serial, int graphic, MessageType type, int hue, int font, bool ascii, + string lang, ReadOnlySpan name, ReadOnlySpan text, + TFilter filter + ) where TFilter : struct, IBroadcastFilter + { + if (map == null) + { + return; + } + + var buffer = stackalloc byte[GetMaxMessageLength(text.Length)].InitializePacket(); + + foreach (var state in map.GetClientsInRange(location, range)) + { + if (filter.Allow(state)) + { + var length = CreateMessage( + buffer, serial, graphic, type, hue, font, ascii, lang, name, text + ); + + if (length != buffer.Length) + { + buffer = buffer[..length]; + } + + state.Send(buffer); + } + } + } +} diff --git a/Projects/Server/Network/Packets/OutgoingMessagePackets.Interpolated.cs b/Projects/Server/Network/Packets/OutgoingMessagePackets.Interpolated.cs new file mode 100644 index 000000000..e1798688c --- /dev/null +++ b/Projects/Server/Network/Packets/OutgoingMessagePackets.Interpolated.cs @@ -0,0 +1,57 @@ +/************************************************************************* + * ModernUO * + * Copyright 2019-2026 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: OutgoingMessagePackets.Interpolated.cs * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; +using Server.Buffers; + +namespace Server.Network; + +public static partial class OutgoingMessagePackets +{ + public static void SendMessageLocalized( + this NetState ns, + Serial serial, int graphic, MessageType type, int hue, int font, int number, + ReadOnlySpan name, + ref RawInterpolatedStringHandler args + ) + { + ns.SendMessageLocalized(serial, graphic, type, hue, font, number, name, args.Text); + args.Clear(); + } + + public static void SendMessageLocalizedAffix( + this NetState ns, + Serial serial, int graphic, MessageType type, int hue, int font, int number, + ReadOnlySpan name, AffixType affixType, ReadOnlySpan affix, + ref RawInterpolatedStringHandler args + ) + { + ns.SendMessageLocalizedAffix( + serial, graphic, type, hue, font, number, name, affixType, affix, args.Text + ); + args.Clear(); + } + + public static void SendMessage( + this NetState ns, + Serial serial, int graphic, MessageType type, int hue, int font, bool ascii, + string lang, ReadOnlySpan name, + ref RawInterpolatedStringHandler text + ) + { + ns.SendMessage(serial, graphic, type, hue, font, ascii, lang, name, text.Text); + text.Clear(); + } +} diff --git a/Projects/Server/Network/Packets/OutgoingMessagePackets.cs b/Projects/Server/Network/Packets/OutgoingMessagePackets.cs index cf13d3119..a531336b8 100644 --- a/Projects/Server/Network/Packets/OutgoingMessagePackets.cs +++ b/Projects/Server/Network/Packets/OutgoingMessagePackets.cs @@ -29,11 +29,12 @@ public enum AffixType : byte System = 0x02 } -public static class OutgoingMessagePackets +public static partial class OutgoingMessagePackets { public static void SendMessageLocalized( this NetState ns, - Serial serial, int graphic, MessageType type, int hue, int font, int number, string name = "", string args = "" + Serial serial, int graphic, MessageType type, int hue, int font, int number, + ReadOnlySpan name = default, ReadOnlySpan args = default ) { if (ns.CannotSendPackets()) @@ -41,7 +42,7 @@ public static class OutgoingMessagePackets return; } - var buffer = stackalloc byte[GetMaxMessageLocalizedLength(args)].InitializePacket(); + var buffer = stackalloc byte[GetMaxMessageLocalizedLength(args.Length)].InitializePacket(); var length = CreateMessageLocalized( buffer, serial, graphic, type, hue, font, number, name, args ); @@ -50,11 +51,16 @@ public static class OutgoingMessagePackets } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int GetMaxMessageLocalizedLength(string args) => 50 + (args?.Length ?? 0) * 2; + public static int GetMaxMessageLocalizedLength(int argsCharCount) => 50 + argsCharCount * 2; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int GetMaxMessageLocalizedLength(ReadOnlySpan args) => + GetMaxMessageLocalizedLength(args.Length); public static int CreateMessageLocalized( Span buffer, - Serial serial, int graphic, MessageType type, int hue, int font, int number, string name = "", string args = "" + Serial serial, int graphic, MessageType type, int hue, int font, int number, + ReadOnlySpan name = default, ReadOnlySpan args = default ) { if (buffer[0] != 0) @@ -62,9 +68,6 @@ public static class OutgoingMessagePackets return buffer.Length; } - name ??= ""; - args ??= ""; - if (hue == 0) { hue = 0x3B2; @@ -88,8 +91,9 @@ public static class OutgoingMessagePackets public static void SendMessageLocalizedAffix( this NetState ns, - Serial serial, int graphic, MessageType type, int hue, int font, int number, string name, - AffixType affixType, string affix = "", string args = "" + Serial serial, int graphic, MessageType type, int hue, int font, int number, + ReadOnlySpan name, AffixType affixType, + ReadOnlySpan affix = default, ReadOnlySpan args = default ) { if (ns.CannotSendPackets()) @@ -97,7 +101,7 @@ public static class OutgoingMessagePackets return; } - var buffer = stackalloc byte[GetMaxMessageLocalizedAffixLength(affix, args)].InitializePacket(); + var buffer = stackalloc byte[GetMaxMessageLocalizedAffixLength(affix.Length, args.Length)].InitializePacket(); var length = CreateMessageLocalizedAffix( buffer, serial, graphic, type, hue, font, number, name, affixType, affix, args ); @@ -106,13 +110,18 @@ public static class OutgoingMessagePackets } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int GetMaxMessageLocalizedAffixLength(string affix, string args) => - 52 + (affix?.Length ?? 0) + (args?.Length ?? 0) * 2; + public static int GetMaxMessageLocalizedAffixLength(int affixCharCount, int argsCharCount) => + 52 + affixCharCount + argsCharCount * 2; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int GetMaxMessageLocalizedAffixLength(ReadOnlySpan affix, ReadOnlySpan args) => + GetMaxMessageLocalizedAffixLength(affix.Length, args.Length); public static int CreateMessageLocalizedAffix( Span buffer, - Serial serial, int graphic, MessageType type, int hue, int font, int number, string name, - AffixType affixType, string affix = "", string args = "" + Serial serial, int graphic, MessageType type, int hue, int font, int number, + ReadOnlySpan name, AffixType affixType, + ReadOnlySpan affix = default, ReadOnlySpan args = default ) { if (buffer[0] != 0) @@ -120,10 +129,6 @@ public static class OutgoingMessagePackets return buffer.Length; } - name ??= ""; - affix ??= ""; - args ??= ""; - if (hue == 0) { hue = 0x3B2; @@ -149,7 +154,8 @@ public static class OutgoingMessagePackets public static void SendMessage( this NetState ns, - Serial serial, int graphic, MessageType type, int hue, int font, bool ascii, string lang, string name, string text + Serial serial, int graphic, MessageType type, int hue, int font, bool ascii, + string lang, ReadOnlySpan name, ReadOnlySpan text ) { if (ns.CannotSendPackets()) @@ -157,7 +163,7 @@ public static class OutgoingMessagePackets return; } - var buffer = stackalloc byte[GetMaxMessageLength(text)].InitializePacket(); + var buffer = stackalloc byte[GetMaxMessageLength(text.Length)].InitializePacket(); var length = CreateMessage( buffer, serial, @@ -175,7 +181,10 @@ public static class OutgoingMessagePackets } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int GetMaxMessageLength(string text) => 50 + (text?.Length ?? 0) * 2; + public static int GetMaxMessageLength(int textCharCount) => 50 + textCharCount * 2; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int GetMaxMessageLength(ReadOnlySpan text) => GetMaxMessageLength(text.Length); public static int CreateMessage( Span buffer, @@ -186,8 +195,8 @@ public static class OutgoingMessagePackets int font, bool ascii, string lang, - string name, - string text + ReadOnlySpan name, + ReadOnlySpan text ) { if (buffer[0] != 0) @@ -195,8 +204,6 @@ public static class OutgoingMessagePackets return buffer.Length; } - name ??= ""; - text ??= ""; lang ??= "ENU"; if (hue == 0) diff --git a/Projects/Server/World/World.cs b/Projects/Server/World/World.cs index 209779f24..f25ec163b 100644 --- a/Projects/Server/World/World.cs +++ b/Projects/Server/World/World.cs @@ -110,7 +110,7 @@ public static class World public static void Broadcast(int hue, bool ascii, string text) { - var length = OutgoingMessagePackets.GetMaxMessageLength(text); + var length = OutgoingMessagePackets.GetMaxMessageLength(text.Length); var buffer = stackalloc byte[length].InitializePacket(); @@ -140,7 +140,7 @@ public static class World public static void BroadcastStaff(int hue, bool ascii, string text) { - var length = OutgoingMessagePackets.GetMaxMessageLength(text); + var length = OutgoingMessagePackets.GetMaxMessageLength(text.Length); var buffer = stackalloc byte[length].InitializePacket(); diff --git a/Projects/UOContent/Engines/ML Quests/MLQuestSystem.cs b/Projects/UOContent/Engines/ML Quests/MLQuestSystem.cs index 077d1a7de..edde59c32 100644 --- a/Projects/UOContent/Engines/ML Quests/MLQuestSystem.cs +++ b/Projects/UOContent/Engines/ML Quests/MLQuestSystem.cs @@ -730,7 +730,7 @@ namespace Server.Engines.MLQuests } else if (quester is Item item) { - item.SendLocalizedMessageTo(pm, cliloc, args, SpeechColor); + item.SendLocalizedMessageTo(pm, cliloc, SpeechColor, args); } else { diff --git a/Projects/UOContent/Items/Special/Solen Items/PowderOfTranslocation.cs b/Projects/UOContent/Items/Special/Solen Items/PowderOfTranslocation.cs index 5b0fbb08b..1a4e86786 100644 --- a/Projects/UOContent/Items/Special/Solen Items/PowderOfTranslocation.cs +++ b/Projects/UOContent/Items/Special/Solen Items/PowderOfTranslocation.cs @@ -88,11 +88,11 @@ public partial class PowderOfTranslocation : Item // The ~1_translocationItem~ glows with green energy and absorbs magical power from the powder. if (_transItemName.Number > 0) { - item.SendLocalizedMessageTo(from, 1054139, $"#{_transItemName.Number}", 0x43); + item.SendLocalizedMessageTo(from, 1054139, 0x43, $"#{_transItemName.Number}"); } else if (_transItemName.String != null) { - item.SendLocalizedMessageTo(from, 1054139, _transItemName.String, 0x43); + item.SendLocalizedMessageTo(from, 1054139, 0x43, _transItemName.String); } } } diff --git a/Projects/UOContent/Misc/MessageHelper.cs b/Projects/UOContent/Misc/MessageHelper.cs deleted file mode 100644 index 82eabc37f..000000000 --- a/Projects/UOContent/Misc/MessageHelper.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Server.Network; - -namespace Server; - -public static class MessageHelper -{ - public static void SendLocalizedMessageTo(this Item from, Mobile to, int number, int hue) - { - SendLocalizedMessageTo(from, to, number, "", hue); - } - - public static void SendLocalizedMessageTo(this Item from, Mobile to, int number, string args, int hue) - { - to?.NetState.SendMessageLocalized(from.Serial, from.ItemID, MessageType.Regular, hue, 3, number, "", args); - } - - public static void SendMessageTo(this Item from, Mobile to, string text, int hue) - { - to?.NetState.SendMessage(from.Serial, from.ItemID, MessageType.Regular, hue, 3, false, "ENU", "", text); - } -}