Streamlines packet tests (#175)
This commit is contained in:
parent
6a727c3401
commit
7d20cf7642
29 changed files with 1782 additions and 1684 deletions
195
Projects/Server/Buffers/SpanExtensions.cs
Normal file
195
Projects/Server/Buffers/SpanExtensions.cs
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
using System.Buffers.Binary;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using Server;
|
||||
|
||||
namespace System.Buffers
|
||||
{
|
||||
public static class SpanExtensions
|
||||
{
|
||||
// Extensions
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Write(this Span<byte> span, ushort value) => BinaryPrimitives.WriteUInt16BigEndian(span, value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Write(this Span<byte> span, short value) => BinaryPrimitives.WriteInt16BigEndian(span, value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Write(this Span<byte> span, uint value) => BinaryPrimitives.WriteUInt32BigEndian(span, value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Write(this Span<byte> span, int value) => BinaryPrimitives.WriteInt32BigEndian(span, value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Write(this Span<byte> span, byte value) => span[0] = value;
|
||||
|
||||
// Ref Extensions
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Write(this Span<byte> span, ref int pos, ReadOnlySpan<byte> data)
|
||||
{
|
||||
data.CopyTo(span.Slice(pos, data.Length));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Write(this Span<byte> span, ref int pos, bool value)
|
||||
{
|
||||
span[pos++] = value ? (byte)1 : (byte)0;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Write(this Span<byte> span, ref int pos, byte value) => span[pos++] = value;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Write(this Span<byte> span, ref int pos, ushort value)
|
||||
{
|
||||
BinaryPrimitives.WriteUInt16BigEndian(span.Slice(pos, 2), value);
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Write(this Span<byte> span, ref int pos, short value)
|
||||
{
|
||||
BinaryPrimitives.WriteInt16BigEndian(span.Slice(pos, 2), value);
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Write(this Span<byte> span, ref int pos, uint value)
|
||||
{
|
||||
BinaryPrimitives.WriteUInt32BigEndian(span.Slice(pos, 4), value);
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void WriteLE(this Span<byte> span, ref int pos, uint value)
|
||||
{
|
||||
BinaryPrimitives.WriteUInt32LittleEndian(span.Slice(pos, 4), value);
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Write(this Span<byte> span, ref int pos, int value)
|
||||
{
|
||||
BinaryPrimitives.WriteInt32BigEndian(span.Slice(pos, 4), value);
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void WriteLE(this Span<byte> span, ref int pos, int value)
|
||||
{
|
||||
BinaryPrimitives.WriteInt32LittleEndian(span.Slice(pos, 4), value);
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Write(this Span<byte> span, ref int pos, Serial value)
|
||||
{
|
||||
BinaryPrimitives.WriteUInt32BigEndian(span.Slice(pos, 4), value);
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Write(this Span<byte> span, ref int pos, ulong value)
|
||||
{
|
||||
BinaryPrimitives.WriteUInt64BigEndian(span.Slice(pos, 8), value);
|
||||
pos += 8;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Write(this Span<byte> span, ref int pos, long value)
|
||||
{
|
||||
BinaryPrimitives.WriteInt64BigEndian(span.Slice(pos, 8), value);
|
||||
pos += 8;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void WriteLE(this Span<byte> span, ref int pos, ulong value)
|
||||
{
|
||||
BinaryPrimitives.WriteUInt64LittleEndian(span.Slice(pos, 8), value);
|
||||
pos += 8;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void WriteLE(this Span<byte> span, ref int pos, long value)
|
||||
{
|
||||
BinaryPrimitives.WriteInt64LittleEndian(span.Slice(pos, 8), value);
|
||||
pos += 8;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void WriteAscii(this Span<byte> span, ref int pos, string value)
|
||||
{
|
||||
int length = value.Length;
|
||||
pos += Encoding.ASCII.GetBytes(value.AsSpan(0, length), span.Slice(pos, length));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void WriteAscii(this Span<byte> span, ref int pos, string value, int max)
|
||||
{
|
||||
int length = value.Length <= max ? value.Length : max;
|
||||
|
||||
pos += Encoding.ASCII.GetBytes(value.AsSpan(0, length), span.Slice(pos, length));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void WriteAsciiNull(this Span<byte> span, ref int pos, string value)
|
||||
{
|
||||
int length = value.Length;
|
||||
pos += Encoding.ASCII.GetBytes(value.AsSpan(0, length), span.Slice(pos, length));
|
||||
span[pos++] = 0; // Null terminator
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void WriteAsciiNull(this Span<byte> span, ref int pos, string value, int max)
|
||||
{
|
||||
var length = value.Length < max ? value.Length : max - 1;
|
||||
|
||||
pos += Encoding.ASCII.GetBytes(value.AsSpan(0, length), span.Slice(pos, length));
|
||||
span[pos++] = 0; // Null terminator
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void WriteAsciiFixed(this Span<byte> span, ref int pos, string value, int amount)
|
||||
{
|
||||
var length = value.Length <= amount ? 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 WriteAsciiFixedNull(this Span<byte> span, ref int pos, string value, int amount)
|
||||
{
|
||||
var length = value.Length < amount ? value.Length : amount - 1;
|
||||
#if NO_LOCAL_INIT
|
||||
int bytesWritten = Encoding.ASCII.GetBytes(value.AsSpan(0, amount), span.Slice(pos, amount));
|
||||
|
||||
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<byte> span, ref int pos, string value)
|
||||
{
|
||||
pos += Encoding.BigEndianUnicode.GetBytes(value, span.Slice(pos));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void WriteLittleUni(this Span<byte> span, ref int pos, string value)
|
||||
{
|
||||
pos += Encoding.Unicode.GetBytes(value, span.Slice(pos));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,300 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright (C) 2019-2020 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SpanWriter.cs - Created: 2019/08/05 - Updated: 2019/12/24 *
|
||||
* *
|
||||
* 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. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace Server.Buffers
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides functionality for writing primitive binary data.
|
||||
/// </summary>
|
||||
public ref struct SpanWriter
|
||||
{
|
||||
private int m_Position;
|
||||
|
||||
/// <summary>
|
||||
/// Underlying Span.
|
||||
/// </summary>
|
||||
public Span<byte> RawSpan { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Underlying Span up to the bytes written.
|
||||
/// </summary>
|
||||
public Span<byte> Span => RawSpan.Slice(0, WrittenCount);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total length of the span.
|
||||
/// </summary>
|
||||
public int Length => RawSpan.Length;
|
||||
|
||||
/// <summary>
|
||||
/// Total bytes written to the span.
|
||||
/// </summary>
|
||||
public int WrittenCount { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Current position in the the span.
|
||||
/// </summary>
|
||||
public int Position
|
||||
{
|
||||
get => m_Position;
|
||||
set
|
||||
{
|
||||
m_Position = value;
|
||||
|
||||
if (value > WrittenCount)
|
||||
WrittenCount = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates a new SpanWriter instance.
|
||||
/// </summary>
|
||||
public SpanWriter(Span<byte> span)
|
||||
{
|
||||
RawSpan = span;
|
||||
m_Position = 0;
|
||||
WrittenCount = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 1-byte boolean value to the span.
|
||||
/// </summary>
|
||||
public unsafe void Write(bool value)
|
||||
{
|
||||
RawSpan[Position++] = *(byte*)&value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 1-byte unsigned integer value to the span.
|
||||
/// </summary>
|
||||
public void Write(byte value)
|
||||
{
|
||||
RawSpan[Position++] = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 1-byte signed integer value to the span.
|
||||
/// </summary>
|
||||
public void Write(sbyte value)
|
||||
{
|
||||
RawSpan[Position++] = (byte)value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 2-byte signed integer value to the span.
|
||||
/// </summary>
|
||||
public void Write(short value)
|
||||
{
|
||||
Write((byte)(value >> 8));
|
||||
Write((byte)value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 2-byte unsigned integer value to the span.
|
||||
/// </summary>
|
||||
public void Write(ushort value)
|
||||
{
|
||||
Write((byte)(value >> 8));
|
||||
Write((byte)value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 4-byte signed integer value to the span.
|
||||
/// </summary>
|
||||
public void Write(int value)
|
||||
{
|
||||
Write((byte)(value >> 24));
|
||||
Write((byte)(value >> 16));
|
||||
Write((byte)(value >> 8));
|
||||
Write((byte)value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 4-byte unsigned integer value to the span.
|
||||
/// </summary>
|
||||
public void Write(uint value)
|
||||
{
|
||||
Write((byte)(value >> 24));
|
||||
Write((byte)(value >> 16));
|
||||
Write((byte)(value >> 8));
|
||||
Write((byte)value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes an 8-byte signed integer value to the span.
|
||||
/// </summary>
|
||||
public void Write(long value)
|
||||
{
|
||||
Write((byte)(value >> 56));
|
||||
Write((byte)(value >> 48));
|
||||
Write((byte)(value >> 40));
|
||||
Write((byte)(value >> 32));
|
||||
|
||||
Write((byte)(value >> 24));
|
||||
Write((byte)(value >> 16));
|
||||
Write((byte)(value >> 8));
|
||||
Write((byte)value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes an 8-byte unsigned integer value to the span.
|
||||
/// </summary>
|
||||
public void Write(ulong value)
|
||||
{
|
||||
Write((byte)(value >> 56));
|
||||
Write((byte)(value >> 48));
|
||||
Write((byte)(value >> 40));
|
||||
Write((byte)(value >> 32));
|
||||
|
||||
Write((byte)(value >> 24));
|
||||
Write((byte)(value >> 16));
|
||||
Write((byte)(value >> 8));
|
||||
Write((byte)value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a sequence of bytes to the span.
|
||||
/// </summary>
|
||||
public void Write(ReadOnlySpan<byte> input)
|
||||
{
|
||||
var size = Math.Min(input.Length, Length - Position);
|
||||
|
||||
input.Slice(0, size).CopyTo(RawSpan.Slice(Position));
|
||||
Position += size;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes an ASCII-encoded string value to the span.
|
||||
/// </summary>
|
||||
public void WriteAscii(string value)
|
||||
{
|
||||
Position += Encoding.ASCII.GetBytes(value ?? "", RawSpan.Slice(Position));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a fixed-length ASCII-encoded string value to the span.
|
||||
/// </summary>
|
||||
public void WriteAsciiFixed(string value, int size, bool zero = false)
|
||||
{
|
||||
value ??= "";
|
||||
|
||||
var length = Math.Min(size, value.Length);
|
||||
|
||||
Encoding.ASCII.GetBytes(value.AsSpan(0, length), RawSpan.Slice(Position));
|
||||
|
||||
if (zero)
|
||||
{
|
||||
Position += length;
|
||||
Fill(size - length);
|
||||
}
|
||||
else
|
||||
{
|
||||
Position += size;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a dynamic-length ASCII-encoded string value to the span, followed by a 1-byte null character.
|
||||
/// </summary>
|
||||
public void WriteAsciiNull(string value)
|
||||
{
|
||||
Position += Encoding.ASCII.GetBytes(value ?? "", RawSpan.Slice(Position));
|
||||
Write((byte)0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a dynamic-length ASCII-encoded string value to the span, followed by a 1-byte null character.
|
||||
/// </summary>
|
||||
public void WriteAsciiNull(string value, int size)
|
||||
{
|
||||
value ??= "";
|
||||
|
||||
size = Math.Min(size, value.Length);
|
||||
Position += Encoding.ASCII.GetBytes(value.AsSpan(0, size), RawSpan.Slice(Position));
|
||||
Write((byte)0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a dynamic-length little-endian unicode string value to the span.
|
||||
/// </summary>
|
||||
public void WriteLittleUni(string value)
|
||||
{
|
||||
Position += Encoding.Unicode.GetBytes(value ?? "", RawSpan.Slice(Position));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a dynamic-length little-endian unicode string value to the span, followed by a 2-byte null character.
|
||||
/// </summary>
|
||||
public void WriteLittleUniNull(string value)
|
||||
{
|
||||
WriteLittleUni(value);
|
||||
Write((ushort)0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a dynamic-length big-endian unicode string value to the span.
|
||||
/// </summary>
|
||||
public void WriteBigUni(string value)
|
||||
{
|
||||
Position += Encoding.BigEndianUnicode.GetBytes(value ?? "", RawSpan.Slice(Position));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a dynamic-length big-endian unicode string value to the span, followed by a 2-byte null character.
|
||||
/// </summary>
|
||||
public void WriteBigUniNull(string value, bool zero = false)
|
||||
{
|
||||
WriteBigUni(value);
|
||||
|
||||
if (zero)
|
||||
Fill(2);
|
||||
else
|
||||
Position += 2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a dynamic-length utf-8 string value, followed by a 1-byte null character.
|
||||
/// </summary>
|
||||
public void WriteUTF8Null(string value)
|
||||
{
|
||||
Position += Encoding.UTF8.GetBytes(value ?? "", RawSpan.Slice(Position)) + 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the span to the destination.
|
||||
/// </summary>
|
||||
public void CopyTo(Span<byte> destination)
|
||||
{
|
||||
RawSpan.CopyTo(destination);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fills the buffer with zeroes up to count
|
||||
/// </summary>
|
||||
public void Fill(int count)
|
||||
{
|
||||
count = Math.Min(count, RawSpan.Length - Position);
|
||||
RawSpan.Slice(Position, count).Clear();
|
||||
Position += count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -76,7 +76,7 @@ namespace Server
|
|||
{
|
||||
}
|
||||
|
||||
// TOOD: Can we make this higher for newer clients?
|
||||
// TODO: Can we make this higher for newer clients?
|
||||
public static uint FakeSerial(Mobile parent) => 0x7FFFFFFF - 0x400 - parent.Serial * 4;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ namespace Server.Menus.ItemLists
|
|||
{
|
||||
public ItemListEntry(string name, int itemID, int hue = 0)
|
||||
{
|
||||
Name = name;
|
||||
Name = name?.Trim() ?? "";
|
||||
ItemID = itemID;
|
||||
Hue = hue;
|
||||
}
|
||||
|
|
@ -44,7 +44,7 @@ namespace Server.Menus.ItemLists
|
|||
|
||||
public ItemListMenu(string question, ItemListEntry[] entries)
|
||||
{
|
||||
Question = question;
|
||||
Question = question.Trim();
|
||||
Entries = entries;
|
||||
|
||||
do
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ namespace Server.Menus.Questions
|
|||
|
||||
public QuestionMenu(string question, string[] answers)
|
||||
{
|
||||
Question = question;
|
||||
Question = question?.Trim() ?? "";
|
||||
Answers = answers;
|
||||
|
||||
do
|
||||
|
|
@ -38,7 +38,7 @@ namespace Server.Menus.Questions
|
|||
} while (Serial == 0);
|
||||
}
|
||||
|
||||
public string Question { get; set; }
|
||||
public string Question { get; }
|
||||
|
||||
public string[] Answers { get; }
|
||||
|
||||
|
|
|
|||
|
|
@ -449,9 +449,9 @@ namespace Server.Network
|
|||
EnsureCapacity(12);
|
||||
|
||||
Stream.Write(m.Serial);
|
||||
Stream.Write((short)1);
|
||||
Stream.Write((short)1); // Show Bar?
|
||||
|
||||
Stream.Write((short)1);
|
||||
Stream.Write((short)1); // Poison Bar
|
||||
|
||||
var p = m.Poison;
|
||||
|
||||
|
|
@ -527,7 +527,7 @@ namespace Server.Network
|
|||
|
||||
public sealed class MobileIncoming : Packet
|
||||
{
|
||||
private static readonly ThreadLocal<int[]> m_DupedLayersTL = new ThreadLocal<int[]>(() => { return new int[256]; });
|
||||
private static readonly ThreadLocal<int[]> m_DupedLayersTL = new ThreadLocal<int[]>(() => new int[256]);
|
||||
private static readonly ThreadLocal<int> m_VersionTL = new ThreadLocal<int>();
|
||||
|
||||
public MobileIncoming(Mobile beholder, Mobile beheld) : base(0x78)
|
||||
|
|
@ -636,7 +636,7 @@ namespace Server.Network
|
|||
|
||||
public sealed class MobileIncomingSA : Packet
|
||||
{
|
||||
private static readonly ThreadLocal<int[]> m_DupedLayersTL = new ThreadLocal<int[]>(() => { return new int[256]; });
|
||||
private static readonly ThreadLocal<int[]> m_DupedLayersTL = new ThreadLocal<int[]>(() => new int[256]);
|
||||
private static readonly ThreadLocal<int> m_VersionTL = new ThreadLocal<int>();
|
||||
|
||||
public MobileIncomingSA(Mobile beholder, Mobile beheld) : base(0x78)
|
||||
|
|
@ -754,7 +754,7 @@ namespace Server.Network
|
|||
// Pre-7.0.0.0 Mobile Incoming
|
||||
public sealed class MobileIncomingOld : Packet
|
||||
{
|
||||
private static readonly ThreadLocal<int[]> m_DupedLayersTL = new ThreadLocal<int[]>(() => { return new int[256]; });
|
||||
private static readonly ThreadLocal<int[]> m_DupedLayersTL = new ThreadLocal<int[]>(() => new int[256]);
|
||||
private static readonly ThreadLocal<int> m_VersionTL = new ThreadLocal<int>();
|
||||
|
||||
public MobileIncomingOld(Mobile beholder, Mobile beheld) : base(0x78)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue