diff --git a/Projects/Server/Buffers/SpanWriter.cs b/Projects/Server/Buffers/SpanWriter.cs index 0cf840dd2..2baa4294f 100644 --- a/Projects/Server/Buffers/SpanWriter.cs +++ b/Projects/Server/Buffers/SpanWriter.cs @@ -145,6 +145,14 @@ namespace System.Buffers Position += 2; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteLE(short value) + { + GrowIfNeeded(2); + BinaryPrimitives.WriteInt16LittleEndian(_buffer.Slice(_position), value); + Position += 2; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Write(ushort value) { @@ -153,6 +161,14 @@ namespace System.Buffers Position += 2; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteLE(ushort value) + { + GrowIfNeeded(2); + BinaryPrimitives.WriteUInt16LittleEndian(_buffer.Slice(_position), value); + Position += 2; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Write(int value) { diff --git a/Projects/Server/Network/Packets/IncomingMessagePackets.cs b/Projects/Server/Network/Packets/IncomingMessagePackets.cs index 7933cf106..d60a281e2 100644 --- a/Projects/Server/Network/Packets/IncomingMessagePackets.cs +++ b/Projects/Server/Network/Packets/IncomingMessagePackets.cs @@ -1,8 +1,8 @@ /************************************************************************* * ModernUO * - * Copyright 2019-2020 - ModernUO Development Team * + * Copyright (C) 2019-2021 - ModernUO Development Team * * Email: hi@modernuo.com * - * File: Packets.Messages.cs * + * File: IncomingMessagePackets.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 * diff --git a/Projects/Server/Network/Packets/IncomingPackets.cs b/Projects/Server/Network/Packets/IncomingPackets.cs index 0082c5e7e..784f5a4aa 100644 --- a/Projects/Server/Network/Packets/IncomingPackets.cs +++ b/Projects/Server/Network/Packets/IncomingPackets.cs @@ -1,8 +1,8 @@ /************************************************************************* * ModernUO * - * Copyright 2019-2020 - ModernUO Development Team * + * Copyright (C) 2019-2021 - ModernUO Development Team * * Email: hi@modernuo.com * - * File: Packets.cs * + * File: IncomingPackets.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 * diff --git a/Projects/UOContent.Tests/Tests/Network/Packets/ArrowPacketTests.cs b/Projects/UOContent.Tests/Tests/Network/Packets/ArrowPacketTests.cs index 85b4c12ee..0f769f6cd 100644 --- a/Projects/UOContent.Tests/Tests/Network/Packets/ArrowPacketTests.cs +++ b/Projects/UOContent.Tests/Tests/Network/Packets/ArrowPacketTests.cs @@ -18,7 +18,10 @@ namespace Server.Tests.Network AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } - [Theory, InlineData(0, 0), InlineData(100, 10), InlineData(100000, 100000)] + [Theory] + [InlineData(0, 0)] + [InlineData(100, 10)] + [InlineData(100000, 100000)] public void TestSetArrow(int x, int y) { var expected = new SetArrow(x, y).Compile(); @@ -30,7 +33,10 @@ namespace Server.Tests.Network AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } - [Theory, InlineData(0, 0), InlineData(100, 10), InlineData(100000, 100000)] + [Theory] + [InlineData(0, 0)] + [InlineData(100, 10)] + [InlineData(100000, 100000)] public void TestCancelArrowHS(int x, int y) { Serial serial = 0x1024; @@ -45,7 +51,10 @@ namespace Server.Tests.Network AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } - [Theory, InlineData(0, 0), InlineData(100, 10), InlineData(100000, 100000)] + [Theory] + [InlineData(0, 0)] + [InlineData(100, 10)] + [InlineData(100000, 100000)] public void TestSetArrowHS(int x, int y) { Serial serial = 0x1024; diff --git a/Projects/UOContent.Tests/Tests/Network/Packets/BuffIconPacketTests.cs b/Projects/UOContent.Tests/Tests/Network/Packets/BuffIconPacketTests.cs new file mode 100644 index 000000000..530af34ba --- /dev/null +++ b/Projects/UOContent.Tests/Tests/Network/Packets/BuffIconPacketTests.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Tests; +using Server.Tests.Network; +using Xunit; + +namespace UOContent.Tests +{ + public class BuffIconPacketTests + { + [Theory] + [InlineData(0x1024u, BuffIcon.Clumsy, 500100, 300200, "123456", 8000)] + [InlineData(0x2048u, BuffIcon.Disguised, 500102, 300203, null, 9000)] + public void TestAddBuffIcon(uint mob, BuffIcon iconID, int titleCliloc, int secondaryCliloc, string args, int ts) + { + var timeSpan = new TimeSpan(ts); + var expected = new AddBuffPacket( + mob, iconID, titleCliloc, secondaryCliloc, args, timeSpan + ).Compile(); + + using var ns = PacketTestUtilities.CreateTestNetState(); + BuffInfo.SendAddBuffPacket(ns, mob, iconID, titleCliloc, secondaryCliloc, args, timeSpan); + + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); + } + + [Fact] + public void TestRemoveBuffIcon() + { + Serial m = 0x1024; + var buffIcon = BuffIcon.Disguised; + var expected = new RemoveBuffPacket(m, buffIcon).Compile(); + + using var ns = PacketTestUtilities.CreateTestNetState(); + BuffInfo.SendRemoveBuffPacket(ns, m, buffIcon); + + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); + } + } +} diff --git a/Projects/UOContent.Tests/Tests/Network/Packets/BuffIconPackets.cs b/Projects/UOContent.Tests/Tests/Network/Packets/BuffIconPackets.cs new file mode 100644 index 000000000..72f050458 --- /dev/null +++ b/Projects/UOContent.Tests/Tests/Network/Packets/BuffIconPackets.cs @@ -0,0 +1,89 @@ +using System; +using Server.Network; + +namespace Server +{ + public sealed class AddBuffPacket : Packet + { + public AddBuffPacket(Serial m, BuffInfo info) + : this( + m, + info.ID, + info.TitleCliloc, + info.SecondaryCliloc, + info.Args, + info.TimeStart != DateTime.MinValue ? info.TimeStart + info.TimeLength - DateTime.UtcNow : TimeSpan.Zero + ) + { + } + + public AddBuffPacket( + Serial mob, BuffIcon iconID, int titleCliloc, int secondaryCliloc, TextDefinition args, + TimeSpan length + ) + : base(0xDF) + { + var hasArgs = args != null; + + EnsureCapacity(hasArgs ? 48 + args.ToString().Length * 2 : 44); + Stream.Write(mob); + + Stream.Write((short)iconID); // ID + Stream.Write((short)0x1); // Type 0 for removal. 1 for add 2 for Data + + Stream.Fill(4); + + Stream.Write((short)iconID); // ID + Stream.Write((short)0x01); // Type 0 for removal. 1 for add 2 for Data + + Stream.Fill(4); + + if (length < TimeSpan.Zero) + { + length = TimeSpan.Zero; + } + + Stream.Write((short)length.TotalSeconds); // Time in seconds + + Stream.Fill(3); + Stream.Write(titleCliloc); + Stream.Write(secondaryCliloc); + + if (!hasArgs) + { + // m_Stream.Fill( 2 ); + Stream.Fill(10); + } + else + { + Stream.Fill(4); + Stream.Write((short)0x1); // Unknown -> Possibly something saying 'hey, I have more data!'? + Stream.Fill(2); + + // m_Stream.WriteLittleUniNull( "\t#1018280" ); + Stream.WriteLittleUniNull($"\t{args}"); + + Stream.Write((short)0x1); // Even more Unknown -> Possibly something saying 'hey, I have more data!'? + Stream.Fill(2); + } + } + } + + public sealed class RemoveBuffPacket : Packet + { + public RemoveBuffPacket(Serial mob, BuffInfo info) : this(mob, info.ID) + { + } + + public RemoveBuffPacket(Serial mob, BuffIcon iconID) : base(0xDF) + { + EnsureCapacity(13); + Stream.Write(mob); + + Stream.Write((short)iconID); // ID + Stream.Write((short)0x0); // Type 0 for removal. 1 for add 2 for Data + + Stream.Fill(4); + } + } +} diff --git a/Projects/UOContent/Misc/BuffIcons.cs b/Projects/UOContent/Misc/BuffIcons.cs index fe6794d4c..8aec8d3cd 100644 --- a/Projects/UOContent/Misc/BuffIcons.cs +++ b/Projects/UOContent/Misc/BuffIcons.cs @@ -1,4 +1,5 @@ using System; +using System.Buffers; using Server.Mobiles; using Server.Network; @@ -143,6 +144,82 @@ namespace Server { (m as PlayerMobile)?.RemoveBuff(b); } + + public void SendAddBuffPacket(NetState ns, Serial m) => SendAddBuffPacket( + ns, + m, + ID, + TitleCliloc, + SecondaryCliloc, + Args, + TimeStart != DateTime.MinValue ? TimeStart + TimeLength - DateTime.UtcNow : TimeSpan.Zero + ); + + public static void SendAddBuffPacket( + NetState ns, Serial mob, BuffIcon iconID, int titleCliloc, int secondaryCliloc, TextDefinition args, + TimeSpan ts + ) + { + if (ns == null) + { + return; + } + + var hasArgs = args != null; + var length = hasArgs ? args.ToString().Length * 2 + 52 : 46; + var writer = new SpanWriter(stackalloc byte[length]); + writer.Write((byte)0xDF); // Packet ID + writer.Write((ushort)length); + writer.Write(mob); + writer.Write((short)iconID); + writer.Write((short)0x1); // command (0 = remove, 1 = add, 2 = data) + writer.Write(0); + + writer.Write((short)iconID); + writer.Write((short)0x1); // command (0 = remove, 1 = add, 2 = data) + writer.Write(0); + writer.Write((short)(ts <= TimeSpan.Zero ? 0 : ts.TotalSeconds)); + writer.Clear(3); + writer.Write(titleCliloc); + writer.Write(secondaryCliloc); + + if (hasArgs) + { + writer.Write(0); + writer.Write((short)0x1); + writer.Write((ushort)0); + writer.WriteLE('\t'); + writer.WriteLittleUniNull(args); + writer.Write((short)0x1); + writer.Write((ushort)0); + } + else + { + writer.Clear(10); + } + + ns.Send(writer.Span); + } + + public void SendRemoveBuffPacket(NetState ns, Serial mob) => SendRemoveBuffPacket(ns, mob, ID); + + public static void SendRemoveBuffPacket(NetState ns, Serial mob, BuffIcon iconID) + { + if (ns == null) + { + return; + } + + var writer = new SpanWriter(stackalloc byte[15]); + writer.Write((byte)0xDF); // Packet ID + writer.Write((ushort)15); + writer.Write(mob); + writer.Write((short)iconID); + writer.Write((short)0x0); // command (0 = remove, 1 = add, 2 = data) + writer.Write(0); + + ns.Send(writer.Span); + } } public enum BuffIcon : short @@ -202,90 +279,4 @@ namespace Server NetherBolt, Fly } - - public sealed class AddBuffPacket : Packet - { - public AddBuffPacket(Mobile m, BuffInfo info) - : this( - m, - info.ID, - info.TitleCliloc, - info.SecondaryCliloc, - info.Args, - info.TimeStart != DateTime.MinValue ? info.TimeStart + info.TimeLength - DateTime.UtcNow : TimeSpan.Zero - ) - { - } - - public AddBuffPacket( - Mobile mob, BuffIcon iconID, int titleCliloc, int secondaryCliloc, TextDefinition args, - TimeSpan length - ) - : base(0xDF) - { - var hasArgs = args != null; - - EnsureCapacity(hasArgs ? 48 + args.ToString().Length * 2 : 44); - Stream.Write(mob.Serial); - - Stream.Write((short)iconID); // ID - Stream.Write((short)0x1); // Type 0 for removal. 1 for add 2 for Data - - Stream.Fill(4); - - Stream.Write((short)iconID); // ID - Stream.Write((short)0x01); // Type 0 for removal. 1 for add 2 for Data - - Stream.Fill(4); - - if (length < TimeSpan.Zero) - { - length = TimeSpan.Zero; - } - - Stream.Write((short)length.TotalSeconds); // Time in seconds - - Stream.Fill(3); - Stream.Write(titleCliloc); - Stream.Write(secondaryCliloc); - - if (!hasArgs) - { - // m_Stream.Fill( 2 ); - Stream.Fill(10); - } - else - { - Stream.Fill(4); - Stream.Write((short)0x1); // Unknown -> Possibly something saying 'hey, I have more data!'? - Stream.Fill(2); - - // m_Stream.WriteLittleUniNull( "\t#1018280" ); - Stream.WriteLittleUniNull($"\t{args}"); - - Stream.Write((short)0x1); // Even more Unknown -> Possibly something saying 'hey, I have more data!'? - Stream.Fill(2); - } - } - } - - public sealed class RemoveBuffPacket : Packet - { - public RemoveBuffPacket(Mobile mob, BuffInfo info) - : this(mob, info.ID) - { - } - - public RemoveBuffPacket(Mobile mob, BuffIcon iconID) - : base(0xDF) - { - EnsureCapacity(13); - Stream.Write(mob.Serial); - - Stream.Write((short)iconID); // ID - Stream.Write((short)0x0); // Type 0 for removal. 1 for add 2 for Data - - Stream.Fill(4); - } - } } diff --git a/Projects/UOContent/Mobiles/PlayerMobile.cs b/Projects/UOContent/Mobiles/PlayerMobile.cs index ec99b39e4..092ba7143 100644 --- a/Projects/UOContent/Mobiles/PlayerMobile.cs +++ b/Projects/UOContent/Mobiles/PlayerMobile.cs @@ -4574,7 +4574,7 @@ namespace Server.Mobiles { foreach (var info in m_BuffTable.Values) { - NetState.Send(new AddBuffPacket(this, info)); + info.SendAddBuffPacket(NetState, Serial); } } } @@ -4594,7 +4594,7 @@ namespace Server.Mobiles if (NetState?.BuffIcon == true) { - NetState.Send(new AddBuffPacket(this, b)); + b.SendAddBuffPacket(NetState, Serial); } } @@ -4622,7 +4622,7 @@ namespace Server.Mobiles if (NetState?.BuffIcon == true) { - NetState.Send(new RemoveBuffPacket(this, b)); + BuffInfo.SendRemoveBuffPacket(NetState, Serial, b); } if (m_BuffTable.Count <= 0)