diff --git a/Projects/Server.Tests/Tests/Network/Packets/Utilities/AttributeNormalizerUtilities.cs b/Projects/Server.Tests/Tests/Network/Packets/Utilities/AttributeNormalizerUtilities.cs deleted file mode 100644 index b11a832df..000000000 --- a/Projects/Server.Tests/Tests/Network/Packets/Utilities/AttributeNormalizerUtilities.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Buffers; -using Server.Network; - -namespace Server.Tests.Network -{ - public static class AttributeNormalizerUtilities - { - public static void WriteAttribute(this Span data, ref int pos, int cur, int max, bool normalize) - { - if (normalize && AttributeNormalizer.Enabled && max != 0) - { - var maximum = AttributeNormalizer.Maximum; - - data.Write(ref pos, (ushort)maximum); - data.Write(ref pos, (ushort)(cur * maximum / max)); - return; - } - - data.Write(ref pos, (ushort)max); - data.Write(ref pos, (ushort)cur); - } - - public static void WriteReverseAttribute(this Span data, ref int pos, int cur, int max, bool normalize) - { - if (normalize && AttributeNormalizer.Enabled && max != 0) - { - var maximum = AttributeNormalizer.Maximum; - - data.Write(ref pos, (ushort)(cur * maximum / max)); - data.Write(ref pos, (ushort)maximum); - return; - } - - data.Write(ref pos, (ushort)cur); - data.Write(ref pos, (ushort)max); - } - } -} diff --git a/Projects/Server/Buffers/SpanReadExtensions.cs b/Projects/Server/Buffers/SpanReadExtensions.cs deleted file mode 100644 index 015ab37aa..000000000 --- a/Projects/Server/Buffers/SpanReadExtensions.cs +++ /dev/null @@ -1,90 +0,0 @@ -/************************************************************************* - * ModernUO * - * Copyright 2019-2020 - ModernUO Development Team * - * Email: hi@modernuo.com * - * File: SpanReadExtensions.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.Buffers.Binary; -using System.Runtime.CompilerServices; - -namespace System.Buffers -{ - public static class SpanReadExtensions - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte ReadInt8(this Span span, ref int pos) => span[pos++]; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static short ReadInt16(this Span span, ref int pos) - { - var v = BinaryPrimitives.ReadInt16BigEndian(span.Slice(pos, 2)); - pos += 2; - return v; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ushort ReadUInt16(this Span span, ref int pos) - { - var v = BinaryPrimitives.ReadUInt16BigEndian(span.Slice(pos, 2)); - pos += 2; - return v; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ReadInt32(this Span span, ref int pos) - { - var v = BinaryPrimitives.ReadInt32BigEndian(span.Slice(pos, 4)); - pos += 4; - return v; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint ReadUInt32(this Span span, ref int pos) - { - var v = BinaryPrimitives.ReadUInt32BigEndian(span.Slice(pos, 4)); - pos += 4; - return v; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static short ReadInt16LE(this Span span, ref int pos) - { - var v = BinaryPrimitives.ReadInt16LittleEndian(span.Slice(pos, 2)); - pos += 2; - return v; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ushort ReadUInt16LE(this Span span, ref int pos) - { - var v = BinaryPrimitives.ReadUInt16LittleEndian(span.Slice(pos, 2)); - pos += 2; - return v; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ReadInt32LE(this Span span, ref int pos) - { - var v = BinaryPrimitives.ReadInt32LittleEndian(span.Slice(pos, 4)); - pos += 4; - return v; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint ReadUInt32LE(this Span span, ref int pos) - { - var v = BinaryPrimitives.ReadUInt32LittleEndian(span.Slice(pos, 4)); - pos += 4; - return v; - } - } -} diff --git a/Projects/Server/Buffers/SpanReader.cs b/Projects/Server/Buffers/SpanReader.cs index 754b9b350..b0f8757f8 100644 --- a/Projects/Server/Buffers/SpanReader.cs +++ b/Projects/Server/Buffers/SpanReader.cs @@ -66,6 +66,18 @@ namespace System.Buffers return value; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public short ReadInt16LE() + { + if (!BinaryPrimitives.TryReadInt16LittleEndian(_buffer.Slice(Position), out var value)) + { + throw new OutOfMemoryException(); + } + + Position += 2; + return value; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public ushort ReadUInt16() { @@ -78,6 +90,18 @@ namespace System.Buffers return value; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ushort ReadUInt16LE() + { + if (!BinaryPrimitives.TryReadUInt16LittleEndian(_buffer.Slice(Position), out var value)) + { + throw new OutOfMemoryException(); + } + + Position += 2; + return value; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public int ReadInt32() { @@ -102,6 +126,18 @@ namespace System.Buffers return value; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint ReadUInt32LE() + { + if (!BinaryPrimitives.TryReadUInt32LittleEndian(_buffer.Slice(Position), out var value)) + { + throw new OutOfMemoryException(); + } + + Position += 4; + return value; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public string ReadString(Encoding encoding, bool safeString = false, int fixedLength = -1) { diff --git a/Projects/Server/Buffers/SpanWriteExtensions.cs b/Projects/Server/Buffers/SpanWriteExtensions.cs deleted file mode 100644 index a6d99a870..000000000 --- a/Projects/Server/Buffers/SpanWriteExtensions.cs +++ /dev/null @@ -1,229 +0,0 @@ -/************************************************************************* - * ModernUO * - * Copyright 2019-2020 - ModernUO Development Team * - * Email: hi@modernuo.com * - * File: SpanWriteExtensions.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.Buffers.Binary; -using System.Runtime.CompilerServices; -using System.Text; -using Server; - -namespace System.Buffers -{ - public static class SpanWriteExtensions - { - // Extensions - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Write(this Span span, ushort value) => BinaryPrimitives.WriteUInt16BigEndian(span, value); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Write(this Span span, short value) => BinaryPrimitives.WriteInt16BigEndian(span, value); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Write(this Span span, uint value) => BinaryPrimitives.WriteUInt32BigEndian(span, value); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Write(this Span span, int value) => BinaryPrimitives.WriteInt32BigEndian(span, value); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Write(this Span span, byte value) => span[0] = value; - - // Ref Extensions - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Write(this Span span, ref int pos, ReadOnlySpan data) - { - data.CopyTo(span.Slice(pos, data.Length)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Write(this Span span, ref int pos, bool value) - { - span[pos++] = value ? (byte)1 : (byte)0; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Write(this Span span, ref int pos, byte value) => span[pos++] = value; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Write(this Span span, ref int pos, ushort value) - { - BinaryPrimitives.WriteUInt16BigEndian(span.Slice(pos, 2), value); - pos += 2; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Write(this Span span, ref int pos, short value) - { - BinaryPrimitives.WriteInt16BigEndian(span.Slice(pos, 2), value); - pos += 2; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Write(this Span span, ref int pos, uint value) - { - BinaryPrimitives.WriteUInt32BigEndian(span.Slice(pos, 4), value); - pos += 4; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteLE(this Span span, ref int pos, uint value) - { - BinaryPrimitives.WriteUInt32LittleEndian(span.Slice(pos, 4), value); - pos += 4; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Write(this Span span, ref int pos, int value) - { - BinaryPrimitives.WriteInt32BigEndian(span.Slice(pos, 4), value); - pos += 4; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteLE(this Span span, ref int pos, int value) - { - BinaryPrimitives.WriteInt32LittleEndian(span.Slice(pos, 4), value); - pos += 4; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Write(this Span span, ref int pos, Serial value) - { - BinaryPrimitives.WriteUInt32BigEndian(span.Slice(pos, 4), value); - pos += 4; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Write(this Span span, ref int pos, ulong value) - { - BinaryPrimitives.WriteUInt64BigEndian(span.Slice(pos, 8), value); - pos += 8; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Write(this Span span, ref int pos, long value) - { - BinaryPrimitives.WriteInt64BigEndian(span.Slice(pos, 8), value); - pos += 8; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteLE(this Span span, ref int pos, ulong value) - { - BinaryPrimitives.WriteUInt64LittleEndian(span.Slice(pos, 8), value); - pos += 8; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteLE(this Span span, ref int pos, long value) - { - BinaryPrimitives.WriteInt64LittleEndian(span.Slice(pos, 8), value); - pos += 8; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteAscii(this Span span, ref int pos, string value) - { - var length = value.Length; - pos += Encoding.ASCII.GetBytes(value.AsSpan(0, length), span.Slice(pos, length)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteAscii(this Span span, ref int pos, string value, int max) - { - var length = Math.Min(value.Length, max); - - pos += Encoding.ASCII.GetBytes(value.AsSpan(0, length), span.Slice(pos, length)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteAsciiNull(this Span span, ref int pos, string value) - { - var length = value.Length; - pos += Encoding.ASCII.GetBytes(value.AsSpan(0, length), span.Slice(pos, length)); -#if NO_LOCAL_INIT - span[pos] = 0; // Null terminator -#endif - pos++; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteAsciiNull(this Span span, ref int pos, string value, int max) - { - var length = Math.Min(value.Length, max - 1); - - pos += Encoding.ASCII.GetBytes(value.AsSpan(0, length), span.Slice(pos, length)); -#if NO_LOCAL_INIT - span[pos] = 0; // Null terminator -#endif - pos++; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteAsciiFixed(this Span span, ref int pos, string value, int amount) - { - var length = Math.Min(value.Length, amount); -#if NO_LOCAL_INIT - int bytesWritten = Encoding.ASCII.GetBytes(value.AsSpan(0, length), span.Slice(pos, length)); - - if (bytesWritten < amount) - span.Slice(pos + bytesWritten, amount - bytesWritten).Clear(); -#else - Encoding.ASCII.GetBytes(value.AsSpan(0, length), span.Slice(pos, length)); -#endif - - pos += amount; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteBigUni(this Span span, ref int pos, string value) - { - pos += Encoding.BigEndianUnicode.GetBytes(value, span.Slice(pos)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteLittleUni(this Span span, ref int pos, string value) - { - pos += Encoding.Unicode.GetBytes(value, span.Slice(pos)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteBigUniNull(this Span span, ref int pos, string value) - { - pos += Encoding.BigEndianUnicode.GetBytes(value, span.Slice(pos)); -#if NO_LOCAL_INIT - BinaryPrimitives.WriteUInt16BigEndian(span.Slice(pos, 2), 0); // Null terminator -#endif - pos += 2; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteLittleUniNull(this Span span, ref int pos, string value) - { - pos += Encoding.Unicode.GetBytes(value, span.Slice(pos)); -#if NO_LOCAL_INIT - BinaryPrimitives.WriteUInt16BigEndian(span.Slice(pos, 2), 0); // Null terminator -#endif - pos += 2; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Write(this Span span, ref int pos, Point3D p) - { - BinaryPrimitives.WriteUInt16BigEndian(span.Slice(pos, 2), (ushort)p.X); - BinaryPrimitives.WriteUInt16BigEndian(span.Slice(pos + 2, 2), (ushort)p.Y); - span[pos + 4] = (byte)p.Z; - pos += 5; - } - } -} diff --git a/Projects/Server/MultiData.cs b/Projects/Server/MultiData.cs index 58523f9ff..a2ab98598 100644 --- a/Projects/Server/MultiData.cs +++ b/Projects/Server/MultiData.cs @@ -173,17 +173,17 @@ namespace Server var tileList = new List(); - // Skip the first 4 bytes - var pos = 4; - var count = data.ReadUInt32LE(ref pos); + var reader = new SpanReader(data); + reader.Seek(4, SeekOrigin.Begin); + var count = reader.ReadUInt32LE(); for (uint i = 0; i < count; i++) { - var itemId = data.ReadUInt16LE(ref pos); - var x = data.ReadInt16LE(ref pos); - var y = data.ReadInt16LE(ref pos); - var z = data.ReadInt16LE(ref pos); - var flagValue = data.ReadUInt16LE(ref pos); + var itemId = reader.ReadUInt16LE(); + var x = reader.ReadInt16LE(); + var y = reader.ReadInt16LE(); + var z = reader.ReadInt16LE(); + var flagValue = reader.ReadUInt16LE(); var tileFlag = flagValue switch { @@ -192,8 +192,9 @@ namespace Server _ => TileFlag.Background // 0 }; - var clilocsCount = data.ReadUInt32LE(ref pos); - pos += (int)Math.Min(clilocsCount, int.MaxValue) * 4; // bypass binary block + var clilocsCount = reader.ReadUInt32LE(); + var skip = (int)Math.Min(clilocsCount, int.MaxValue) * 4; // bypass binary block + reader.Seek(skip, SeekOrigin.Current); tileList.Add(new MultiTileEntry(itemId, x, y, z, tileFlag)); } diff --git a/Projects/Server/ObjectPropertyList.cs b/Projects/Server/ObjectPropertyList.cs index 2bcf0900e..1b741563e 100644 --- a/Projects/Server/ObjectPropertyList.cs +++ b/Projects/Server/ObjectPropertyList.cs @@ -1,6 +1,9 @@ using System; using System.Buffers; +using System.IO; +using System.Runtime.CompilerServices; using System.Text; +using Server.Network; namespace Server { @@ -13,8 +16,6 @@ namespace Server public sealed class ObjectPropertyList { - private static readonly Encoding m_Encoding = Encoding.Unicode; - // Each of these are localized to "~1_NOTHING~" which allows the string argument to be used private static readonly int[] m_StringNumbers = { @@ -24,19 +25,21 @@ namespace Server private int _hash; private int _strings; - private byte[] _buffer = new byte[64]; + private byte[] _buffer; private int _position; public ObjectPropertyList(IEntity e) { Entity = e; - Span buffer = _buffer; - buffer.Write(ref _position, (byte)0xD6); // Packet ID - _position += 2; // Length - buffer.Write(ref _position, (ushort)1); - buffer.Write(ref _position, e.Serial); - buffer.Write(ref _position, (ushort)0); - _position += 4; // Hash + _buffer = GC.AllocateUninitializedArray(64); + + var writer = new SpanWriter(_buffer); + writer.Write((byte)0xD6); // Packet ID + writer.Seek(2, SeekOrigin.Current); + writer.Write((ushort)1); + writer.Write(e.Serial); + writer.Write((ushort)0); + _position = writer.Position + 4; // Hash } public IEntity Entity { get; } @@ -63,9 +66,12 @@ namespace Server Resize(_buffer.Length * 2); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private void Resize(int amount) { - Array.Resize(ref _buffer, amount); + var newBuffer = GC.AllocateUninitializedArray(amount); + _buffer.AsSpan(0, Math.Min(amount, _buffer.Length)).CopyTo(newBuffer); + _buffer = newBuffer; } public void Terminate() @@ -76,10 +82,13 @@ namespace Server Resize(length); } - Span buffer = _buffer; - buffer.Write(ref _position, 0); - buffer.Slice(11, 4).Write(_hash); - buffer.Slice(1, 2).Write((ushort)_position); + var writer = new SpanWriter(_buffer); + writer.Seek(_position, SeekOrigin.Begin); + writer.Write(0); + + writer.Seek(11, SeekOrigin.Begin); + writer.Write(_hash); + writer.WritePacketLength(); } public void AddHash(int val) @@ -109,7 +118,7 @@ namespace Server AddHash(arguments.GetHashCode(StringComparison.Ordinal)); } - int strLength = m_Encoding.GetByteCount(arguments); + int strLength = Utility.Unicode.GetByteCount(arguments); int length = _position + 6 + strLength; while (length > _buffer.Length) @@ -117,14 +126,11 @@ namespace Server Flush(); } - Span buffer = _buffer; - buffer.Write(ref _position, number); - buffer.Write(ref _position, (ushort)strLength); - if (strLength > 0) - { - m_Encoding.GetBytes(arguments, buffer.Slice(_position)); - _position += strLength; - } + var writer = new SpanWriter(_buffer); + writer.Seek(_position, SeekOrigin.Begin); + writer.Write(number); + writer.Write((ushort)strLength); + writer.WriteBigUni(arguments); } public void Add(int number, string format, object arg0)