fix(core): Core cleanup, adds event loop synchronization, and fixes gumps (#429)

- [X] Cleans up gump packets
- [X] Adds event loop task synchronization
- [X] Moves timer pause and cleans up the delay task timer class
- [X] Cleans up the conserve cpu
- [X] Renames variables to make them consistent with the new style
- [X] Removes process delta recursion checking.
- [X] Properly diposes net states. This fixes edge cases that may cause hanging connections to stay open longer than they should.
- [X] Fixes an issue with gump items not compiling properly

Users can now utilize `Timer.Pause()` since the code will be executed on the proper thread.

```cs
public void async void Talk()
{
    _canTalk = false;
    await Timer.Pause(Utility.RandomMinMax(5000, 8000)); // Talk after 5-8 seconds
    DoTalk();
    await Timer.Pause(Utility.RandomMinMax(12000, 25000)); // Reset ability to talk after 12-25 seconds
    _canTalk = true;
}
```
This commit is contained in:
Kamron Batman 2021-01-25 21:06:46 -08:00 committed by GitHub
parent 07751654b7
commit 6f0e1a22f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 763 additions and 449 deletions

View file

@ -3,6 +3,7 @@
using System;
using System.Buffers;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Server.Network;
@ -13,6 +14,7 @@ namespace Server.Buffers
{
private char[] _arrayToReturnToPool;
private Span<char> _chars;
private int _length;
// If this ctor is used, you cannot pass in stackalloc ROS for append/replace.
public ValueStringBuilder(ReadOnlySpan<char> initialString) : this(initialString.Length)
@ -29,7 +31,7 @@ namespace Server.Buffers
{
_arrayToReturnToPool = null;
_chars = initialBuffer;
Length = 0;
_length = 0;
}
// If this ctor is used, you cannot pass in stackalloc ROS for append/replace.
@ -37,13 +39,20 @@ namespace Server.Buffers
{
_arrayToReturnToPool = ArrayPool<char>.Shared.Rent(initialCapacity);
_chars = _arrayToReturnToPool;
Length = 0;
_length = 0;
}
public int Length { get; set; }
public int Length => _length;
public int Capacity => _chars.Length;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Reset()
{
_length = 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void EnsureCapacity(int capacity)
{
if (capacity > _chars.Length)
@ -68,15 +77,16 @@ namespace Server.Buffers
{
if (terminate)
{
EnsureCapacity(Length + 1);
_chars[Length] = '\0';
EnsureCapacity(_length + 1);
_chars[_length] = '\0';
}
return ref MemoryMarshal.GetReference(_chars);
}
public ref char this[int index] => ref _chars[index];
public override string ToString() => _chars.SliceToLength(Length).ToString();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override string ToString() => _chars.SliceToLength(_length).ToString();
/// <summary>Returns the underlying storage of the builder.</summary>
public Span<char> RawChars => _chars;
@ -89,21 +99,27 @@ namespace Server.Buffers
{
if (terminate)
{
EnsureCapacity(Length + 1);
_chars[Length] = '\0';
EnsureCapacity(_length + 1);
_chars[_length] = '\0';
}
return _chars.SliceToLength(Length);
return _chars.SliceToLength(_length);
}
public ReadOnlySpan<char> AsSpan() => _chars.SliceToLength(Length);
public ReadOnlySpan<char> AsSpan(int start) => _chars.Slice(start, Length - start);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySpan<char> AsSpan() => _chars.SliceToLength(_length);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySpan<char> AsSpan(int start) => _chars.Slice(start, _length - start);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySpan<char> AsSpan(int start, int length) => _chars.Slice(start, length);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryCopyTo(Span<char> destination, out int charsWritten)
{
if (_chars.SliceToLength(Length).TryCopyTo(destination))
if (_chars.SliceToLength(_length).TryCopyTo(destination))
{
charsWritten = Length;
charsWritten = _length;
return true;
}
@ -111,19 +127,21 @@ namespace Server.Buffers
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Insert(int index, char value, int count)
{
if (Length > _chars.Length - count)
if (_length > _chars.Length - count)
{
Grow(count);
}
int remaining = Length - index;
int remaining = _length - index;
_chars.Slice(index, remaining).CopyTo(_chars.Slice(index + count));
_chars.Slice(index, count).Fill(value);
Length += count;
_length += count;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Insert(int index, string s)
{
if (s == null)
@ -133,25 +151,25 @@ namespace Server.Buffers
int count = s.Length;
if (Length > _chars.Length - count)
if (_length > _chars.Length - count)
{
Grow(count);
}
int remaining = Length - index;
int remaining = _length - index;
_chars.Slice(index, remaining).CopyTo(_chars.Slice(index + count));
s.AsSpan().CopyTo(_chars.Slice(index));
Length += count;
_length += count;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Append(char c)
{
int pos = Length;
int pos = _length;
if ((uint)pos < (uint)_chars.Length)
{
_chars[pos] = c;
Length = pos + 1;
_length = pos + 1;
}
else
{
@ -159,6 +177,50 @@ namespace Server.Buffers
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Append(int value, NumberFormatInfo info = null)
{
if (value >= 0)
{
Append((uint)value);
return;
}
Append((info ?? NumberFormatInfo.CurrentInfo).NegativeSign);
Append((uint)-value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe void Append(uint value)
{
int bufferLength = Utility.CountDigits(value);
int pos = _length;
if ((uint)pos + (uint)bufferLength >= _chars.Length)
{
Grow(bufferLength);
}
if (bufferLength == 1)
{
_chars[pos] = (char)(value + '0');
_length = pos + 1;
return;
}
fixed (char* buffer = _chars.Slice(pos))
{
char* p = buffer + bufferLength;
do
{
value = Utility.DivRem(value, 10, out uint remainder);
*--p = (char)(remainder + '0');
} while (value != 0);
}
_length = pos + bufferLength;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Append(string s)
{
@ -167,11 +229,11 @@ namespace Server.Buffers
return;
}
int pos = Length;
int pos = _length;
if (s.Length == 1 && (uint)pos < (uint)_chars.Length) // very common case, e.g. appending strings from NumberFormatInfo like separators, percent symbols, etc.
{
_chars[pos] = s[0];
Length = pos + 1;
_length = pos + 1;
}
else
{
@ -200,71 +262,75 @@ namespace Server.Buffers
Append(Environment.NewLine);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void AppendSlow(string s)
{
int pos = Length;
int pos = _length;
if (pos > _chars.Length - s.Length)
{
Grow(s.Length);
}
s.AsSpan().CopyTo(_chars.Slice(pos));
Length += s.Length;
_length += s.Length;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Append(char c, int count)
{
if (Length > _chars.Length - count)
if (_length > _chars.Length - count)
{
Grow(count);
}
Span<char> dst = _chars.Slice(Length, count);
Span<char> dst = _chars.Slice(_length, count);
for (int i = 0; i < dst.Length; i++)
{
dst[i] = c;
}
Length += count;
_length += count;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe void Append(char* value, int length)
{
int pos = Length;
int pos = _length;
if (pos > _chars.Length - length)
{
Grow(length);
}
Span<char> dst = _chars.Slice(Length, length);
Span<char> dst = _chars.Slice(_length, length);
for (int i = 0; i < dst.Length; i++)
{
dst[i] = *value++;
}
Length += length;
_length += length;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Append(ReadOnlySpan<char> value)
{
int pos = Length;
int pos = _length;
if (pos > _chars.Length - value.Length)
{
Grow(value.Length);
}
value.CopyTo(_chars.Slice(Length));
Length += value.Length;
value.CopyTo(_chars.Slice(_length));
_length += value.Length;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<char> AppendSpan(int length)
{
int origPos = Length;
int origPos = _length;
if (origPos > _chars.Length - length)
{
Grow(length);
}
Length = origPos + length;
_length = origPos + length;
return _chars.Slice(origPos, length);
}
@ -287,9 +353,9 @@ namespace Server.Buffers
[MethodImpl(MethodImplOptions.NoInlining)]
private void Grow(int additionalCapacityBeyondPos)
{
char[] poolArray = ArrayPool<char>.Shared.Rent(Math.Max(Length + additionalCapacityBeyondPos, _chars.Length * 2));
char[] poolArray = ArrayPool<char>.Shared.Rent(Math.Max(_length + additionalCapacityBeyondPos, _chars.Length * 2));
_chars.SliceToLength(Length).CopyTo(poolArray);
_chars.SliceToLength(_length).CopyTo(poolArray);
char[] toReturn = _arrayToReturnToPool;
_chars = _arrayToReturnToPool = poolArray;
@ -314,7 +380,7 @@ namespace Server.Buffers
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReplaceAny(ReadOnlySpan<char> oldChars, ReadOnlySpan<char> newChars, int startIndex, int count)
{
int currentLength = Length;
int currentLength = _length;
if ((uint)startIndex > (uint)currentLength)
{
throw new ArgumentOutOfRangeException(nameof(startIndex));
@ -345,7 +411,7 @@ namespace Server.Buffers
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Replace(char oldChar, char newChar, int startIndex, int count)
{
int currentLength = Length;
int currentLength = _length;
if ((uint)startIndex > (uint)currentLength)
{
throw new ArgumentOutOfRangeException(nameof(startIndex));
@ -384,7 +450,7 @@ namespace Server.Buffers
throw new ArgumentOutOfRangeException(nameof(startIndex));
}
if (length > Length - startIndex)
if (length > _length - startIndex)
{
throw new ArgumentOutOfRangeException(nameof(length));
}
@ -393,7 +459,7 @@ namespace Server.Buffers
{
_chars = _chars.Slice(length);
}
else if (startIndex + length == Length)
else if (startIndex + length == _length)
{
_chars = _chars.SliceToLength(startIndex);
}
@ -403,7 +469,7 @@ namespace Server.Buffers
_chars.Slice(startIndex + length).CopyTo(_chars.Slice(startIndex));
}
Length -= length;
_length -= length;
}
}
}