From 10a6e17640dc2084dff33f0ec85a5c21b848a63f Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Thu, 24 Dec 2020 17:13:55 -0800 Subject: [PATCH] fix(core): Converts mobile moving packet (#357) - [X] Converts mobile moving packet --- Directory.Build.props | 2 + .../Packets/Outgoing/MobilePacketTests.cs | 49 +++----- .../Network/Packets/Outgoing/MobilePackets.cs | 35 ++++++ Projects/Server/Mobiles/Mobile.cs | 114 +++--------------- Projects/Server/Network/PacketUtilities.cs | 13 ++ .../Server/Network/Packets/MobilePackets.cs | 35 ------ .../Network/Packets/OutgoingMobilePackets.cs | 63 ++++++++++ Projects/Server/Utilities/Utility.cs | 2 + Projects/UOContent/Mobiles/PlayerMobile.cs | 4 +- 9 files changed, 147 insertions(+), 170 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 352e3d34c..5da56f81a 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -17,6 +17,7 @@ true true + true true true @@ -24,6 +25,7 @@ OSX LINUX UNIX + NO_LOCAL_INIT true diff --git a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/MobilePacketTests.cs b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/MobilePacketTests.cs index bd7b5502d..d14b4e604 100644 --- a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/MobilePacketTests.cs +++ b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/MobilePacketTests.cs @@ -26,52 +26,35 @@ namespace Server.Tests.Network public void TestBondStatus() { Serial petSerial = 0x1; - var bonded = true; + const bool bonded = true; - var data = new BondedStatus(petSerial, bonded).Compile(); + var expected = new BondedStatus(petSerial, bonded).Compile(); - Span expectedData = stackalloc byte[11]; - var pos = 0; + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendBondedStatus(petSerial, bonded); - expectedData.Write(ref pos, (byte)0xBF); // Packet ID - expectedData.Write(ref pos, (ushort)0x0B); // Length - expectedData.Write(ref pos, (ushort)0x19); // Sub-packet - -#if NO_LOCAL_INIT - expectedData.Write(ref pos, (byte)0); // Command -#else - pos++; -#endif - - expectedData.Write(ref pos, petSerial); - expectedData.Write(ref pos, bonded); - - AssertThat.Equal(data, expectedData); + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } - [Fact] - public void TestMobileMoving() + [Theory] + [InlineData(ProtocolChanges.StygianAbyss)] + [InlineData(ProtocolChanges.None)] + public void TestMobileMoving(ProtocolChanges protocolChanges) { var m = new Mobile(0x1); m.DefaultMobileInit(); var noto = 10; - var data = new MobileMoving(m, noto, true).Compile(); + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.ProtocolChanges = protocolChanges; + var expected = new MobileMoving(m, noto, ns.StygianAbyss).Compile(); - Span expectedData = stackalloc byte[17]; - var pos = 0; + ns.SendMobileMoving(m, noto); - expectedData.Write(ref pos, (byte)0x77); // Packet ID - expectedData.Write(ref pos, m.Serial); - expectedData.Write(ref pos, (ushort)m.Body); - expectedData.Write(ref pos, m.Location); - expectedData.Write(ref pos, (byte)m.Direction); - expectedData.Write(ref pos, (ushort)m.Hue); - expectedData.Write(ref pos, (byte)m.GetPacketFlags(true)); - expectedData.Write(ref pos, (byte)noto); - - AssertThat.Equal(data, expectedData); + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } [Fact] diff --git a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/MobilePackets.cs b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/MobilePackets.cs index a2802dd83..6f14a62d8 100644 --- a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/MobilePackets.cs +++ b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/MobilePackets.cs @@ -14,4 +14,39 @@ namespace Server.Tests.Network Stream.Write((byte)(bonded ? 1 : 0)); } } + + public sealed class DeathAnimation : Packet + { + public DeathAnimation(Serial killed, Serial corpse) : base(0xAF, 13) + { + Stream.Write(killed); + Stream.Write(corpse); + Stream.Write(0); + } + } + + public sealed class MobileMoving : Packet + { + public MobileMoving(Mobile m, int noto, bool stygianAbyss) : base(0x77, 17) + { + var loc = m.Location; + + var hue = m.Hue; + + if (m.SolidHueOverride >= 0) + { + hue = m.SolidHueOverride; + } + + Stream.Write(m.Serial); + Stream.Write((short)m.Body); + Stream.Write((short)loc.X); + Stream.Write((short)loc.Y); + Stream.Write((sbyte)loc.Z); + Stream.Write((byte)m.Direction); + Stream.Write((short)hue); + Stream.Write((byte)m.GetPacketFlags(stygianAbyss)); + Stream.Write((byte)noto); + } + } } diff --git a/Projects/Server/Mobiles/Mobile.cs b/Projects/Server/Mobiles/Mobile.cs index 676a479fc..3838f73c4 100644 --- a/Projects/Server/Mobiles/Mobile.cs +++ b/Projects/Server/Mobiles/Mobile.cs @@ -435,12 +435,6 @@ namespace Server private static readonly TimeSpan ExpireCombatantDelay = TimeSpan.FromMinutes(1.0); private static readonly TimeSpan ExpireAggressorsDelay = TimeSpan.FromSeconds(5.0); - private static readonly Packet[][] m_MovingPacketCache = - { - new Packet[8], - new Packet[8] - }; - private static readonly List m_MoveList = new(); private static readonly List m_MoveClientList = new(); @@ -3055,7 +3049,8 @@ namespace Server sendFacialHair = true; } - var cache = new[] { new Packet[8], new Packet[8] }; + Span mobileMovingPackets = stackalloc byte[OutgoingMobilePackets.MobileMovingPacketCacheLength]; + mobileMovingPackets.InitializePackets(OutgoingMobilePackets.MobileMovingPacketLength); var ourState = m.m_NetState; @@ -3072,14 +3067,13 @@ namespace Server ourState.Send(new MobileIncoming(ourState, m, m)); } + if (sendMoving || !ourState.StygianAbyss && (sendHealthbarPoison || sendHealthbarYellow)) + { + ourState.SendMobileMovingUsingCache(mobileMovingPackets, m, m); + } + if (ourState.StygianAbyss) { - if (sendMoving) - { - var noto = Notoriety.Compute(m, m); - ourState.Send(cache[0][noto] = Packet.Acquire(new MobileMoving(m, noto, true))); - } - if (sendHealthbarPoison) { ourState.Send(new HealthbarPoison(m)); @@ -3090,14 +3084,6 @@ namespace Server ourState.Send(new HealthbarYellow(m)); } } - else - { - if (sendMoving || sendHealthbarPoison || sendHealthbarYellow) - { - var noto = Notoriety.Compute(m, m); - ourState.Send(cache[1][noto] = Packet.Acquire(new MobileMoving(m, noto, false))); - } - } if (sendPublicStats || sendPrivateStats) { @@ -3218,22 +3204,13 @@ namespace Server } } + if (sendMoving || !state.StygianAbyss && (sendHealthbarPoison || sendHealthbarYellow)) + { + state.SendMobileMovingUsingCache(mobileMovingPackets, beholder, m); + } + if (state.StygianAbyss) { - if (sendMoving) - { - var noto = Notoriety.Compute(beholder, m); - - var p = cache[0][noto]; - - if (p == null) - { - cache[0][noto] = p = Packet.Acquire(new MobileMoving(m, noto, true)); - } - - state.Send(p); - } - if (sendHealthbarPoison) { hbpPacket ??= Packet.Acquire(new HealthbarPoison(m)); @@ -3248,22 +3225,6 @@ namespace Server state.Send(hbyPacket); } } - else - { - if (sendMoving || sendHealthbarPoison || sendHealthbarYellow) - { - var noto = Notoriety.Compute(beholder, m); - - var p = cache[1][noto]; - - if (p == null) - { - cache[1][noto] = p = Packet.Acquire(new MobileMoving(m, noto, false)); - } - - state.Send(p); - } - } if (sendPublicStats) { @@ -3319,17 +3280,6 @@ namespace Server eable.Free(); } - - if (sendMoving || sendNonlocalMoving || sendHealthbarPoison || sendHealthbarYellow) - { - for (var i = 0; i < cache.Length; ++i) - { - for (var j = 0; j < cache[i].Length; ++j) - { - Packet.Release(ref cache[i][j]); - } - } - } } public ISpawner Spawner { get; set; } @@ -4580,11 +4530,8 @@ namespace Server eable.Free(); - var cache = m_MovingPacketCache; - - /*for( int i = 0; i < cache.Length; ++i ) - for( int j = 0; j < cache[i].Length; ++j ) - Packet.Release( ref cache[i][j] );*/ + Span mobileMovingPackets = stackalloc byte[OutgoingMobilePackets.MobileMovingPacketCacheLength]; + mobileMovingPackets.InitializePackets(OutgoingMobilePackets.MobileMovingPacketLength); foreach (var m in m_MoveClientList) { @@ -4592,38 +4539,7 @@ namespace Server if (ns != null && Utility.InUpdateRange(m_Location, m.m_Location) && m.CanSee(this)) { - if (ns.StygianAbyss) - { - var noto = Notoriety.Compute(m, this); - var p = cache[0][noto]; - - if (p == null) - { - cache[0][noto] = p = Packet.Acquire(new MobileMoving(this, noto, true)); - } - - ns.Send(p); - } - else - { - var noto = Notoriety.Compute(m, this); - var p = cache[1][noto]; - - if (p == null) - { - cache[1][noto] = p = Packet.Acquire(new MobileMoving(this, noto, false)); - } - - ns.Send(p); - } - } - } - - for (var i = 0; i < cache.Length; ++i) - { - for (var j = 0; j < cache[i].Length; ++j) - { - Packet.Release(ref cache[i][j]); + ns.SendMobileMovingUsingCache(mobileMovingPackets, m, this); } } diff --git a/Projects/Server/Network/PacketUtilities.cs b/Projects/Server/Network/PacketUtilities.cs index 65d3e4301..69ff69b95 100644 --- a/Projects/Server/Network/PacketUtilities.cs +++ b/Projects/Server/Network/PacketUtilities.cs @@ -13,6 +13,7 @@ * along with this program. If not, see . * *************************************************************************/ +using System; using System.Buffers; using System.IO; using System.Runtime.CompilerServices; @@ -38,5 +39,17 @@ namespace Server.Network writer.Write((ushort)length); writer.Seek(length, SeekOrigin.Begin); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void InitializePackets(this Span buffer, int chunkLength) + { + var index = 0; + + while (index < buffer.Length) + { + buffer[index] = 0; + index += chunkLength; + } + } } } diff --git a/Projects/Server/Network/Packets/MobilePackets.cs b/Projects/Server/Network/Packets/MobilePackets.cs index a185f3479..4f6a5e107 100644 --- a/Projects/Server/Network/Packets/MobilePackets.cs +++ b/Projects/Server/Network/Packets/MobilePackets.cs @@ -17,41 +17,6 @@ using System.Threading; namespace Server.Network { - public sealed class DeathAnimation : Packet - { - public DeathAnimation(Serial killed, Serial corpse) : base(0xAF, 13) - { - Stream.Write(killed); - Stream.Write(corpse); - Stream.Write(0); - } - } - - public sealed class MobileMoving : Packet - { - public MobileMoving(Mobile m, int noto, bool stygianAbyss) : base(0x77, 17) - { - var loc = m.Location; - - var hue = m.Hue; - - if (m.SolidHueOverride >= 0) - { - hue = m.SolidHueOverride; - } - - Stream.Write(m.Serial); - Stream.Write((short)m.Body); - Stream.Write((short)loc.m_X); - Stream.Write((short)loc.m_Y); - Stream.Write((sbyte)loc.m_Z); - Stream.Write((byte)m.Direction); - Stream.Write((short)hue); - Stream.Write((byte)m.GetPacketFlags(stygianAbyss)); - Stream.Write((byte)noto); - } - } - public sealed class MobileHits : Packet { public MobileHits(Mobile m) : base(0xA1, 9) diff --git a/Projects/Server/Network/Packets/OutgoingMobilePackets.cs b/Projects/Server/Network/Packets/OutgoingMobilePackets.cs index cf94ef353..dde0e0806 100644 --- a/Projects/Server/Network/Packets/OutgoingMobilePackets.cs +++ b/Projects/Server/Network/Packets/OutgoingMobilePackets.cs @@ -15,6 +15,7 @@ using System; using System.Buffers; +using System.Runtime.CompilerServices; namespace Server.Network { @@ -22,6 +23,8 @@ namespace Server.Network { public const int BondedStatusPacketLength = 11; public const int DeathAnimationPacketLength = 13; + public const int MobileMovingPacketLength = 17; + public const int MobileMovingPacketCacheLength = MobileMovingPacketLength * 8 * 2; // 8 notoriety, 2 client versions public static void CreateBondedStatus(ref Span buffer, Serial serial, bool bonded) { @@ -72,5 +75,65 @@ namespace Server.Network CreateDeathAnimation(ref span, killed, corpse); ns.Send(span); } + + public static void CreateMobileMoving(ref Span buffer, Mobile m, int noto, bool stygianAbyss) + { + var loc = m.Location; + var hue = m.SolidHueOverride >= 0 ? m.SolidHueOverride : m.Hue; + + var writer = new SpanWriter(buffer); + writer.Write((byte)0x77); // Packet ID + writer.Write(m.Serial); + writer.Write((short)m.Body); + writer.Write((short)loc.m_X); + writer.Write((short)loc.m_Y); + writer.Write((sbyte)loc.m_Z); + writer.Write((byte)m.Direction); + writer.Write((short)hue); + writer.Write((byte)m.GetPacketFlags(stygianAbyss)); + writer.Write((byte)noto); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SendMobileMoving(this NetState ns, Mobile source, Mobile target) => + ns.SendMobileMoving(target, Notoriety.Compute(source, target)); + + public static void SendMobileMoving(this NetState ns, Mobile target, int noto) + { + if (ns == null) + { + return; + } + + Span span = stackalloc byte[MobileMovingPacketLength]; + CreateMobileMoving(ref span, target, noto, ns.StygianAbyss); + ns.Send(span); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SendMobileMovingUsingCache(this NetState ns, Span cache, Mobile source, Mobile target) => + ns.SendMobileMovingUsingCache(cache, target, Notoriety.Compute(source, target)); + + // Requires a buffer of 16 packets, 17bytes per packet (272 bytes). + // Requires cache to have the first byte of each packet zeroed. + public static void SendMobileMovingUsingCache(this NetState ns, Span cache, Mobile target, int noto) + { + if (ns == null) + { + return; + } + + var stygianAbyss = ns.StygianAbyss; + var startIndex = (noto * 2 + (stygianAbyss ? 1 : 0)) * MobileMovingPacketLength; + var buffer = cache.Slice(startIndex, MobileMovingPacketLength); + + // Packet not created yet + if (buffer[0] == 0) + { + CreateMobileMoving(ref buffer, target, noto, stygianAbyss); + } + + ns.Send(buffer); + } } } diff --git a/Projects/Server/Utilities/Utility.cs b/Projects/Server/Utilities/Utility.cs index 5df39a574..32b445038 100644 --- a/Projects/Server/Utilities/Utility.cs +++ b/Projects/Server/Utilities/Utility.cs @@ -1438,6 +1438,7 @@ namespace Server return string.Join(lineSeparator, parts); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Tidy(this List list) where T : ISerializable { for (int i = list.Count - 1; i >= 0; i--) @@ -1452,6 +1453,7 @@ namespace Server list.TrimExcess(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Tidy(this HashSet set) where T : ISerializable { set.RemoveWhere(entry => entry?.Deleted != false); diff --git a/Projects/UOContent/Mobiles/PlayerMobile.cs b/Projects/UOContent/Mobiles/PlayerMobile.cs index bc348cff4..b2853dd4f 100644 --- a/Projects/UOContent/Mobiles/PlayerMobile.cs +++ b/Projects/UOContent/Mobiles/PlayerMobile.cs @@ -4276,9 +4276,7 @@ namespace Server.Mobiles if (t == oldType || t == newType) { - var ns = NetState; - - ns?.Send(new MobileMoving(m, Notoriety.Compute(this, m), ns.StygianAbyss)); + m.NetState.SendMobileMoving(this, m); } } }