Fix bad serials (#304)
- [X] Fixes bad serial calculations - [X] Tightens HexStrings Bumps release version Updates documentation
This commit is contained in:
parent
b0c1076cb5
commit
ae436cb55f
46 changed files with 76 additions and 51 deletions
15
Projects/Server.Tests/Helpers/AssertExtensions.cs
Normal file
15
Projects/Server.Tests/Helpers/AssertExtensions.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Server.Tests
|
||||||
|
{
|
||||||
|
public static class AssertThat
|
||||||
|
{
|
||||||
|
// TODO: Swap actual and expected to match Assert
|
||||||
|
public static void Equal(ReadOnlySpan<byte> actual, ReadOnlySpan<byte> expected) =>
|
||||||
|
Xunit.Assert.True(
|
||||||
|
expected.SequenceEqual(actual),
|
||||||
|
$"Expected does not match actual.\nExpected:\t{expected.ToDelimitedHexString()}\nActual:\t\t{actual.ToDelimitedHexString()}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,13 +7,20 @@ namespace Server.Tests.Accounting
|
||||||
{
|
{
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("ABCDEF1234", new byte[] { 0xAB, 0xCD, 0xEF, 0x12, 0x34 })]
|
[InlineData("ABCDEF1234", new byte[] { 0xAB, 0xCD, 0xEF, 0x12, 0x34 })]
|
||||||
public void ConvertsProperly(string input, byte[] bytes)
|
public void TestGetBytes(string input, byte[] bytes)
|
||||||
{
|
{
|
||||||
Span<byte> outputBytes = stackalloc byte[input.Length / 2];
|
Span<byte> outputBytes = stackalloc byte[input.Length / 2];
|
||||||
HexStringConverter.GetBytes(input, outputBytes);
|
HexStringConverter.GetBytes(input, outputBytes);
|
||||||
|
|
||||||
Assert.Equal(bytes, outputBytes.ToArray());
|
Assert.Equal(bytes, outputBytes.ToArray());
|
||||||
Assert.Equal(input, HexStringConverter.GetString(bytes));
|
Assert.Equal(input, bytes.ToHexString());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("[AB, CD, EF, 12, 34]", new byte[] { 0xAB, 0xCD, 0xEF, 0x12, 0x34 })]
|
||||||
|
public void TestsGetStringDelimited(string expected, byte[] bytes)
|
||||||
|
{
|
||||||
|
Assert.Equal(expected, bytes.ToDelimitedHexString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Server.Tests
|
|
||||||
{
|
|
||||||
public static class AssertThat
|
|
||||||
{
|
|
||||||
public static string SpanToString(ReadOnlySpan<byte> bytes)
|
|
||||||
{
|
|
||||||
var builder = new StringBuilder();
|
|
||||||
builder.Append("[");
|
|
||||||
builder.AppendJoin(", ", bytes.ToArray());
|
|
||||||
builder.Append("]");
|
|
||||||
|
|
||||||
return builder.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Equal(ReadOnlySpan<byte> actual, ReadOnlySpan<byte> expected) =>
|
|
||||||
Xunit.Assert.True(
|
|
||||||
expected.SequenceEqual(actual),
|
|
||||||
$"Expected does not match actual.\nExpected:\t{SpanToString(expected)}\nActual:\t\t{SpanToString(actual)}"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -17,7 +17,7 @@ using System;
|
||||||
|
|
||||||
namespace Server
|
namespace Server
|
||||||
{
|
{
|
||||||
public class HexStringConverter
|
public static class HexStringConverter
|
||||||
{
|
{
|
||||||
public static readonly uint[] m_Lookup32Chars = CreateLookup32Chars();
|
public static readonly uint[] m_Lookup32Chars = CreateLookup32Chars();
|
||||||
|
|
||||||
|
|
@ -40,7 +40,11 @@ namespace Server
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static unsafe string GetString(ReadOnlySpan<byte> bytes)
|
public static string ToHexString(this byte[] bytes) => new ReadOnlySpan<byte>(bytes).ToHexString();
|
||||||
|
|
||||||
|
public static string ToHexString(this Span<byte> bytes) => ((ReadOnlySpan<byte>)bytes).ToHexString();
|
||||||
|
|
||||||
|
public static unsafe string ToHexString(this ReadOnlySpan<byte> bytes)
|
||||||
{
|
{
|
||||||
var result = new string((char)0, bytes.Length * 2);
|
var result = new string((char)0, bytes.Length * 2);
|
||||||
fixed (char* resultP = result)
|
fixed (char* resultP = result)
|
||||||
|
|
@ -55,6 +59,36 @@ namespace Server
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string ToDelimitedHexString(this byte[] bytes) => ((ReadOnlySpan<byte>)bytes).ToDelimitedHexString();
|
||||||
|
|
||||||
|
public static unsafe string ToDelimitedHexString(this ReadOnlySpan<byte> bytes)
|
||||||
|
{
|
||||||
|
const uint delimiter = 0x20002C; // ", "
|
||||||
|
const char openBracket = '[';
|
||||||
|
const char closeBracket = ']';
|
||||||
|
var length = bytes.Length * 4; // len * 2 + (len - 1) * 2 + 2
|
||||||
|
|
||||||
|
var result = new string((char)0, length);
|
||||||
|
fixed (char* resultP = result)
|
||||||
|
{
|
||||||
|
resultP[0] = openBracket;
|
||||||
|
resultP[length - 1] = closeBracket;
|
||||||
|
|
||||||
|
var resultP2 = (uint*)(resultP + 1);
|
||||||
|
for (int a = 0, i = 0; a < bytes.Length; a++, i++)
|
||||||
|
{
|
||||||
|
if (a > 0)
|
||||||
|
{
|
||||||
|
resultP2[i++] = delimiter;
|
||||||
|
}
|
||||||
|
|
||||||
|
resultP2[i] = m_Lookup32Chars[bytes[a]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public static unsafe void GetBytes(string str, Span<byte> bytes)
|
public static unsafe void GetBytes(string str, Span<byte> bytes)
|
||||||
{
|
{
|
||||||
fixed (char* strP = str)
|
fixed (char* strP = str)
|
||||||
|
|
|
||||||
|
|
@ -39,15 +39,14 @@ namespace Server
|
||||||
public static class World
|
public static class World
|
||||||
{
|
{
|
||||||
private static readonly ManualResetEvent m_DiskWriteHandle = new ManualResetEvent(true);
|
private static readonly ManualResetEvent m_DiskWriteHandle = new ManualResetEvent(true);
|
||||||
|
private static readonly Dictionary<Serial, IEntity> _pendingAdd = new Dictionary<Serial, IEntity>();
|
||||||
private static Dictionary<Serial, IEntity> _pendingAdd;
|
private static readonly Dictionary<Serial, IEntity> _pendingDelete = new Dictionary<Serial, IEntity>();
|
||||||
private static Dictionary<Serial, IEntity> _pendingDelete;
|
private static readonly ConcurrentQueue<Item> _decayQueue = new ConcurrentQueue<Item>();
|
||||||
private static ConcurrentQueue<Item> _decayQueue = new ConcurrentQueue<Item>();
|
|
||||||
|
|
||||||
public const uint ItemOffset = 0x40000000;
|
public const uint ItemOffset = 0x40000000;
|
||||||
public const uint MaxItemSerial = 0x7FFFFFFF;
|
public const uint MaxItemSerial = 0x7FFFFFFF;
|
||||||
private const uint _maxItems = int.MaxValue - ItemOffset;
|
public const uint MaxMobileSerial = ItemOffset - 1;
|
||||||
private const uint _maxMobiles = ItemOffset;
|
private const uint _maxItems = MaxItemSerial - ItemOffset + 1;
|
||||||
|
|
||||||
private static Serial _lastMobile = Serial.Zero;
|
private static Serial _lastMobile = Serial.Zero;
|
||||||
private static Serial _lastItem = ItemOffset;
|
private static Serial _lastItem = ItemOffset;
|
||||||
|
|
@ -59,19 +58,18 @@ namespace Server
|
||||||
{
|
{
|
||||||
uint last = _lastMobile;
|
uint last = _lastMobile;
|
||||||
|
|
||||||
for (int i = 0; i < _maxMobiles; i++)
|
for (int i = 0; i < MaxMobileSerial; i++)
|
||||||
{
|
{
|
||||||
last++;
|
last++;
|
||||||
|
|
||||||
if (last >= _lastMobile)
|
if (last > MaxMobileSerial)
|
||||||
{
|
{
|
||||||
last = 0;
|
last = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FindMobile(last) == null)
|
if (FindMobile(last) == null)
|
||||||
{
|
{
|
||||||
_lastMobile = last;
|
return _lastMobile = last;
|
||||||
return last;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -89,15 +87,14 @@ namespace Server
|
||||||
{
|
{
|
||||||
last++;
|
last++;
|
||||||
|
|
||||||
if (last - ItemOffset >= _maxItems)
|
if (last > MaxItemSerial)
|
||||||
{
|
{
|
||||||
last = ItemOffset;
|
last = ItemOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FindItem(last) == null)
|
if (FindItem(last) == null)
|
||||||
{
|
{
|
||||||
_lastItem = last;
|
return _lastItem = last;
|
||||||
return last;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -117,7 +114,6 @@ namespace Server
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal static int _Saves;
|
internal static int _Saves;
|
||||||
internal static List<Type> ItemTypes { get; } = new List<Type>();
|
internal static List<Type> ItemTypes { get; } = new List<Type>();
|
||||||
internal static List<Type> MobileTypes { get; } = new List<Type>();
|
internal static List<Type> MobileTypes { get; } = new List<Type>();
|
||||||
|
|
@ -361,9 +357,6 @@ namespace Server
|
||||||
|
|
||||||
var watch = Stopwatch.StartNew();
|
var watch = Stopwatch.StartNew();
|
||||||
|
|
||||||
_pendingAdd = new Dictionary<Serial, IEntity>();
|
|
||||||
_pendingDelete = new Dictionary<Serial, IEntity>();
|
|
||||||
|
|
||||||
List<EntityIndex<Item>> items;
|
List<EntityIndex<Item>> items;
|
||||||
List<EntityIndex<Mobile>> mobiles;
|
List<EntityIndex<Mobile>> mobiles;
|
||||||
List<EntityIndex<BaseGuild>> guilds;
|
List<EntityIndex<BaseGuild>> guilds;
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ namespace Server.Accounting.Security
|
||||||
var bytes = new byte[Encoding.ASCII.GetByteCount(password)];
|
var bytes = new byte[Encoding.ASCII.GetByteCount(password)];
|
||||||
Encoding.ASCII.GetBytes(password, bytes);
|
Encoding.ASCII.GetBytes(password, bytes);
|
||||||
|
|
||||||
return HexStringConverter.GetString(m_MD5HashProvider.ComputeHash(bytes));
|
return m_MD5HashProvider.ComputeHash(bytes).ToHexString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ValidatePassword(string encryptedPassword, string plainPassword) =>
|
public bool ValidatePassword(string encryptedPassword, string plainPassword) =>
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ namespace Server.Accounting.Security
|
||||||
rfc2898.Salt.CopyTo(output.Slice(2, m_SaltSize));
|
rfc2898.Salt.CopyTo(output.Slice(2, m_SaltSize));
|
||||||
rfc2898.GetBytes(m_HashSize).CopyTo(output.Slice(m_SaltSize + 2));
|
rfc2898.GetBytes(m_HashSize).CopyTo(output.Slice(m_SaltSize + 2));
|
||||||
|
|
||||||
return HexStringConverter.GetString(output);
|
return output.ToHexString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ValidatePassword(string encryptedPassword, string plainPassword)
|
public bool ValidatePassword(string encryptedPassword, string plainPassword)
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ namespace Server.Accounting.Security
|
||||||
var bytes = new byte[Encoding.ASCII.GetByteCount(password)];
|
var bytes = new byte[Encoding.ASCII.GetByteCount(password)];
|
||||||
Encoding.ASCII.GetBytes(password, bytes);
|
Encoding.ASCII.GetBytes(password, bytes);
|
||||||
|
|
||||||
return HexStringConverter.GetString(m_SHA1HashProvider.ComputeHash(bytes));
|
return m_SHA1HashProvider.ComputeHash(bytes).ToHexString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ValidatePassword(string encryptedPassword, string plainPassword) =>
|
public bool ValidatePassword(string encryptedPassword, string plainPassword) =>
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ namespace Server.Accounting.Security
|
||||||
var bytes = new byte[Encoding.ASCII.GetByteCount(password)];
|
var bytes = new byte[Encoding.ASCII.GetByteCount(password)];
|
||||||
Encoding.ASCII.GetBytes(password, bytes);
|
Encoding.ASCII.GetBytes(password, bytes);
|
||||||
|
|
||||||
return HexStringConverter.GetString(m_SHA2HashProvider.ComputeHash(bytes));
|
return m_SHA2HashProvider.ComputeHash(bytes).ToHexString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ValidatePassword(string encryptedPassword, string plainPassword) =>
|
public bool ValidatePassword(string encryptedPassword, string plainPassword) =>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json",
|
"$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json",
|
||||||
"version": "0.8.0"
|
"version": "0.8.1"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue