Adds BufferReader and BufferWriter. Updates UOP handling. (#101)

This commit is contained in:
Kamron Batman 2020-04-12 21:33:24 -07:00 • committed by GitHub
parent 2c0d97cd36
commit 038c3be258
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
98 changed files with 2458 additions and 2185 deletions

View file

@ -68,6 +68,7 @@ namespace Server
var types = FindTypesByName(name, ignoreCase).ToList();
if (types.Count == 0)
return null;
if (predicate != null)
return types.FirstOrDefault(predicate);
if (types.Count == 1)
@ -76,10 +77,13 @@ namespace Server
// Check for exact match of the FullName or Name
// Then check for case-insensitive match of FullName or Name
// Otherwise just return the first entry
return (!ignoreCase ? types.FirstOrDefault(x => x.FullName == name || x.Name == name) : null)
?? types.FirstOrDefault(x => StringComparer.OrdinalIgnoreCase.Equals(x.FullName, name) || StringComparer.OrdinalIgnoreCase.Equals(x.Name, name))
?? types[0];
var stringComparer = ignoreCase ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal;
return types.FirstOrDefault(x =>
stringComparer.Equals(x.FullName, name) || stringComparer.Equals(x.Name, name)) ??
types[0];
}
public static IEnumerable<Type> FindTypesByName(string name, bool ignoreCase = false)
{
List<Type> types = new List<Type>();
@ -122,31 +126,30 @@ namespace Server
refs.Add(index);
else
{
refs = new HashSet<int>();
refs.Add(index);
refs = new HashSet<int> {index};
nameMap.Add(key, refs);
}
};
Type current;
Type aliasType = typeof(TypeAliasAttribute);
TypeAliasAttribute alias;
for (int i = 0, j = 0; i < m_Types.Length; i++)
for (int i = 0; i < m_Types.Length; i++)
{
current = m_Types[i];
addToRefs(i, current.Name);
addToRefs(i, current.Name.ToLower());
addToRefs(i, current.FullName);
addToRefs(i, current.FullName.ToLower());
addToRefs(i, current.FullName?.ToLower());
alias = current.GetCustomAttribute(aliasType, false) as TypeAliasAttribute;
if (alias != null)
for (j = 0; j < alias.Aliases.Length; j++)
for (int j = 0; j < alias.Aliases.Length; j++)
{
addToRefs(i, alias.Aliases[j]);
addToRefs(i, alias.Aliases[j].ToLower());
}
}
foreach (var entry in nameMap)
m_NameMap[entry.Key] = entry.Value.ToArray();
foreach (var (key, value) in nameMap)
m_NameMap[key] = value.ToArray();
}
}
}

View file

@ -0,0 +1,314 @@
// Copyright (c) Harry Pierson. All rights reserved.
// Licensed under the MIT license.
// See LICENSE file in the project root for full license information.
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Threading;
namespace System.Buffers
{
public ref struct BufferReader<T>
{
private readonly bool usingSequence;
private readonly ReadOnlySequence<T> sequence;
private SequencePosition currentPosition;
private SequencePosition nextPosition;
private bool moreData;
private readonly long length;
public BufferReader(ReadOnlySpan<T> span)
{
usingSequence = false;
CurrentSpanIndex = 0;
Consumed = 0;
sequence = default;
currentPosition = default;
length = span.Length;
CurrentSpan = span;
nextPosition = default;
moreData = span.Length > 0;
}
public BufferReader(in ReadOnlySequence<T> sequence)
{
usingSequence = true;
CurrentSpanIndex = 0;
Consumed = 0;
this.sequence = sequence;
currentPosition = sequence.Start;
length = -1;
var first = sequence.First.Span;
CurrentSpan = first;
nextPosition = sequence.GetPosition(first.Length);
moreData = first.Length > 0;
if (!moreData && !sequence.IsSingleSegment)
{
moreData = true;
GetNextSpan();
}
}
public readonly bool End => !moreData;
public ReadOnlySpan<T> CurrentSpan { get; private set; }
public int CurrentSpanIndex { get; private set; }
public readonly ReadOnlySpan<T> UnreadSpan
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => CurrentSpan.Slice(CurrentSpanIndex);
}
public long Consumed { get; private set; }
public readonly long Remaining => Length - Consumed;
public readonly long Length
{
get
{
if (length < 0)
{
Debug.Assert(usingSequence, "usingSequence");
// Cast-away readonly to initialize lazy field
Volatile.Write(ref Unsafe.AsRef(length), sequence.Length);
}
return length;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly bool TryPeek([MaybeNullWhen(false)] out T value)
{
if (moreData)
{
value = CurrentSpan[CurrentSpanIndex];
return true;
}
value = default!;
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryRead([MaybeNullWhen(false)] out T value)
{
if (End)
{
value = default!;
return false;
}
value = CurrentSpan[CurrentSpanIndex];
CurrentSpanIndex++;
Consumed++;
if (CurrentSpanIndex >= CurrentSpan.Length)
{
if (usingSequence)
GetNextSpan();
else
moreData = false;
}
return true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Rewind(long count)
{
if ((ulong)count > (ulong)Consumed) throw new ArgumentOutOfRangeException(nameof(count));
Consumed -= count;
if (CurrentSpanIndex >= count)
{
CurrentSpanIndex -= (int)count;
moreData = true;
}
else if (usingSequence)
{
// Current segment doesn't have enough data, scan backward through segments
RetreatToPreviousSpan(Consumed);
}
else
{
throw new ArgumentOutOfRangeException($"Rewind went past the start of the memory by {count}.", nameof(count));
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private void RetreatToPreviousSpan(long consumed)
{
Debug.Assert(usingSequence, "usingSequence");
ResetReader();
Advance(consumed);
}
private void ResetReader()
{
Debug.Assert(usingSequence, "usingSequence");
CurrentSpanIndex = 0;
Consumed = 0;
currentPosition = sequence.Start;
nextPosition = currentPosition;
if (sequence.TryGet(ref nextPosition, out ReadOnlyMemory<T> memory))
{
moreData = true;
if (memory.Length == 0)
{
CurrentSpan = default;
// No data in the first span, move to one with data
GetNextSpan();
}
else
{
CurrentSpan = memory.Span;
}
}
else
{
// No data in any spans and at end of sequence
moreData = false;
CurrentSpan = default;
}
}
private void GetNextSpan()
{
Debug.Assert(usingSequence, "usingSequence");
if (!sequence.IsSingleSegment)
{
SequencePosition previousNextPosition = nextPosition;
while (sequence.TryGet(ref nextPosition, out ReadOnlyMemory<T> memory))
{
currentPosition = previousNextPosition;
if (memory.Length > 0)
{
CurrentSpan = memory.Span;
CurrentSpanIndex = 0;
return;
}
CurrentSpan = default;
CurrentSpanIndex = 0;
previousNextPosition = nextPosition;
}
}
moreData = false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Advance(long count)
{
const long TooBigOrNegative = unchecked((long)0xFFFFFFFF80000000);
if ((count & TooBigOrNegative) == 0 && CurrentSpan.Length - CurrentSpanIndex > (int)count)
{
CurrentSpanIndex += (int)count;
Consumed += count;
}
else if (usingSequence)
{
// Can't satisfy from the current span
AdvanceToNextSpan(count);
}
else if (CurrentSpan.Length - CurrentSpanIndex == (int)count)
{
CurrentSpanIndex += (int)count;
Consumed += count;
moreData = false;
}
else
{
throw new ArgumentOutOfRangeException(nameof(count));
}
}
private void AdvanceToNextSpan(long count)
{
Debug.Assert(usingSequence, "usingSequence");
if (count < 0) throw new ArgumentOutOfRangeException(nameof(count));
Consumed += count;
while (moreData)
{
int remaining = CurrentSpan.Length - CurrentSpanIndex;
if (remaining > count)
{
CurrentSpanIndex += (int)count;
count = 0;
break;
}
// As there may not be any further segments we need to
// push the current index to the end of the span.
CurrentSpanIndex += remaining;
count -= remaining;
Debug.Assert(count >= 0);
GetNextSpan();
if (count == 0) break;
}
if (count != 0)
{
// Not enough data left- adjust for where we actually ended and throw
Consumed -= count;
throw new ArgumentOutOfRangeException(nameof(count));
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly bool TryCopyTo(Span<T> destination)
{
// This API doesn't advance to facilitate conditional advancement based on the data returned.
// We don't provide an advance option to allow easier utilizing of stack allocated destination spans.
// (Because we can make this method readonly we can guarantee that we won't capture the span.)
ReadOnlySpan<T> firstSpan = UnreadSpan;
if (firstSpan.Length >= destination.Length)
{
firstSpan.Slice(0, destination.Length).CopyTo(destination);
return true;
}
// Not enough in the current span to satisfy the request, fall through to the slow path
return TryCopyMultisegment(destination);
}
internal readonly bool TryCopyMultisegment(Span<T> destination)
{
// If we don't have enough to fill the requested buffer, return false
if (Remaining < destination.Length)
return false;
ReadOnlySpan<T> firstSpan = UnreadSpan;
Debug.Assert(firstSpan.Length < destination.Length);
firstSpan.CopyTo(destination);
int copied = firstSpan.Length;
SequencePosition next = nextPosition;
while (sequence.TryGet(ref next, out ReadOnlyMemory<T> nextSegment))
if (nextSegment.Length > 0)
{
ReadOnlySpan<T> nextSpan = nextSegment.Span;
int toCopy = Math.Min(nextSpan.Length, destination.Length - copied);
nextSpan.Slice(0, toCopy).CopyTo(destination.Slice(copied));
copied += toCopy;
if (copied >= destination.Length) break;
}
return true;
}
}
}

View file

@ -0,0 +1,181 @@
// Copyright (c) Harry Pierson. All rights reserved.
// Licensed under the MIT license.
// See LICENSE file in the project root for full license information.
using System.Buffers.Binary;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace System.Buffers
{
public static class BufferReaderExtensions
{
private static unsafe bool TryRead<T>(ref this BufferReader<byte> reader, out T value)
where T : unmanaged
{
ReadOnlySpan<byte> span = reader.UnreadSpan;
if (span.Length < sizeof(T)) return TryReadMultisegment(ref reader, out value);
value = Unsafe.ReadUnaligned<T>(ref MemoryMarshal.GetReference(span));
reader.Advance(sizeof(T));
return true;
}
private static unsafe bool TryReadMultisegment<T>(ref BufferReader<byte> reader, out T value)
where T : unmanaged
{
Debug.Assert(reader.UnreadSpan.Length < sizeof(T), "reader.UnreadSpan.Length < sizeof(T)");
// Not enough data in the current segment, try to peek for the data we need.
T buffer = default;
Span<byte> tempSpan = new Span<byte>(&buffer, sizeof(T));
if (!reader.TryCopyTo(tempSpan))
{
value = default;
return false;
}
value = Unsafe.ReadUnaligned<T>(ref MemoryMarshal.GetReference(tempSpan));
reader.Advance(sizeof(T));
return true;
}
public static bool TryRead(ref this BufferReader<byte> reader, out sbyte value)
{
if (TryRead(ref reader, out byte byteValue))
{
value = unchecked((sbyte)byteValue);
return true;
}
value = default;
return false;
}
public static bool TryReadLittleEndian(ref this BufferReader<byte> reader, out short value) =>
BitConverter.IsLittleEndian ? reader.TryRead(out value) : TryReadReverseEndianness(ref reader, out value);
public static bool TryReadBigEndian(ref this BufferReader<byte> reader, out short value) =>
!BitConverter.IsLittleEndian ? reader.TryRead(out value) : TryReadReverseEndianness(ref reader, out value);
private static bool TryReadReverseEndianness(ref BufferReader<byte> reader, out short value)
{
if (reader.TryRead(out value))
{
value = BinaryPrimitives.ReverseEndianness(value);
return true;
}
return false;
}
public static bool TryReadLittleEndian(ref this BufferReader<byte> reader, out ushort value)
{
if (TryReadLittleEndian(ref reader, out short signedvalue))
{
value = unchecked((ushort)signedvalue);
return true;
}
value = default;
return false;
}
public static bool TryReadBigEndian(ref this BufferReader<byte> reader, out ushort value)
{
if (TryReadBigEndian(ref reader, out short signedvalue))
{
value = unchecked((ushort)signedvalue);
return true;
}
value = default;
return false;
}
public static bool TryReadLittleEndian(ref this BufferReader<byte> reader, out int value) =>
BitConverter.IsLittleEndian ? reader.TryRead(out value) : TryReadReverseEndianness(ref reader, out value);
public static bool TryReadBigEndian(ref this BufferReader<byte> reader, out int value) =>
!BitConverter.IsLittleEndian ? reader.TryRead(out value) : TryReadReverseEndianness(ref reader, out value);
private static bool TryReadReverseEndianness(ref BufferReader<byte> reader, out int value)
{
if (reader.TryRead(out value))
{
value = BinaryPrimitives.ReverseEndianness(value);
return true;
}
return false;
}
public static bool TryReadLittleEndian(ref this BufferReader<byte> reader, out uint value)
{
if (TryReadLittleEndian(ref reader, out int signedvalue))
{
value = unchecked((uint)signedvalue);
return true;
}
value = default;
return false;
}
public static bool TryReadBigEndian(ref this BufferReader<byte> reader, out uint value)
{
if (TryReadBigEndian(ref reader, out int signedvalue))
{
value = unchecked((uint)signedvalue);
return true;
}
value = default;
return false;
}
public static bool TryReadLittleEndian(ref this BufferReader<byte> reader, out long value) =>
BitConverter.IsLittleEndian ? reader.TryRead(out value) : TryReadReverseEndianness(ref reader, out value);
public static bool TryReadBigEndian(ref this BufferReader<byte> reader, out long value) =>
!BitConverter.IsLittleEndian ? reader.TryRead(out value) : TryReadReverseEndianness(ref reader, out value);
private static bool TryReadReverseEndianness(ref BufferReader<byte> reader, out long value)
{
if (reader.TryRead(out value))
{
value = BinaryPrimitives.ReverseEndianness(value);
return true;
}
return false;
}
public static bool TryReadLittleEndian(ref this BufferReader<byte> reader, out ulong value)
{
if (TryReadLittleEndian(ref reader, out long signedvalue))
{
value = unchecked((ulong)signedvalue);
return true;
}
value = default;
return false;
}
public static bool TryReadBigEndian(ref this BufferReader<byte> reader, out ulong value)
{
if (TryReadBigEndian(ref reader, out long signedvalue))
{
value = unchecked((ulong)signedvalue);
return true;
}
value = default;
return false;
}
}
}

View file

@ -0,0 +1,143 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Runtime.CompilerServices;
namespace System.Buffers
{
/// <summary>
/// A fast access struct that wraps <see cref="IBufferWriter{T}"/>.
/// </summary>
/// <typeparam name="T">The type of element to be written.</typeparam>
internal ref struct BufferWriter<T> where T : IBufferWriter<byte>
{
/// <summary>
/// The underlying <see cref="IBufferWriter{T}"/>.
/// </summary>
private T _output;
/// <summary>
/// The result of the last call to <see cref="IBufferWriter{T}.GetSpan(int)"/>, less any bytes already "consumed" with <see cref="Advance(int)"/>.
/// Backing field for the <see cref="Span"/> property.
/// </summary>
private Span<byte> _span;
/// <summary>
/// The number of uncommitted bytes (all the calls to <see cref="Advance(int)"/> since the last call to <see cref="Commit"/>).
/// </summary>
private int _buffered;
/// <summary>
/// The total number of bytes written with this writer.
/// Backing field for the <see cref="BytesCommitted"/> property.
/// </summary>
private long _bytesCommitted;
/// <summary>
/// Initializes a new instance of the <see cref="BufferWriter{T}"/> struct.
/// </summary>
/// <param name="output">The <see cref="IBufferWriter{T}"/> to be wrapped.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferWriter(T output)
{
_buffered = 0;
_bytesCommitted = 0;
_output = output;
_span = output.GetSpan();
}
/// <summary>
/// Gets the result of the last call to <see cref="IBufferWriter{T}.GetSpan(int)"/>.
/// </summary>
public Span<byte> Span => _span;
/// <summary>
/// Gets the total number of bytes written with this writer.
/// </summary>
public long BytesCommitted => _bytesCommitted;
/// <summary>
/// Calls <see cref="IBufferWriter{T}.Advance(int)"/> on the underlying writer
/// with the number of uncommitted bytes.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Commit()
{
var buffered = _buffered;
if (buffered > 0)
{
_bytesCommitted += buffered;
_buffered = 0;
_output.Advance(buffered);
}
}
/// <summary>
/// Used to indicate that part of the buffer has been written to.
/// </summary>
/// <param name="count">The number of bytes written to.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Advance(int count)
{
_buffered += count;
_span = _span.Slice(count);
}
/// <summary>
/// Copies the caller's buffer into this writer and calls <see cref="Advance(int)"/> with the length of the source buffer.
/// </summary>
/// <param name="source">The buffer to copy in.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Write(ReadOnlySpan<byte> source)
{
if (_span.Length >= source.Length)
{
source.CopyTo(_span);
Advance(source.Length);
}
else
{
WriteMultiBuffer(source);
}
}
/// <summary>
/// Acquires a new buffer if necessary to ensure that some given number of bytes can be written to a single buffer.
/// </summary>
/// <param name="count">The number of bytes that must be allocated in a single buffer.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Ensure(int count = 1)
{
if (_span.Length < count) EnsureMore(count);
}
/// <summary>
/// Gets a fresh span to write to, with an optional minimum size.
/// </summary>
/// <param name="count">The minimum size for the next requested buffer.</param>
[MethodImpl(MethodImplOptions.NoInlining)]
private void EnsureMore(int count = 0)
{
if (_buffered > 0) Commit();
_span = _output.GetSpan(count);
}
/// <summary>
/// Copies the caller's buffer into this writer, potentially across multiple buffers from the underlying writer.
/// </summary>
/// <param name="source">The buffer to copy into this writer.</param>
private void WriteMultiBuffer(ReadOnlySpan<byte> source)
{
while (source.Length > 0)
{
if (_span.Length == 0) EnsureMore();
var writable = Math.Min(source.Length, _span.Length);
source.Slice(0, writable).CopyTo(_span);
source = source.Slice(writable);
Advance(writable);
}
}
}
}

View file

@ -1,132 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace System.Buffers
{
/// <summary>
/// Used to allocate and distribute re-usable blocks of memory.
/// </summary>
public class DiagnosticMemoryPool : MemoryPool<byte>
{
private readonly MemoryPool<byte> _pool;
private readonly bool _allowLateReturn;
private readonly bool _rentTracking;
private readonly object _syncObj;
private readonly HashSet<DiagnosticPoolBlock> _blocks;
private readonly List<Exception> _blockAccessExceptions;
private readonly TaskCompletionSource<object> _allBlocksReturned;
private int _totalBlocks;
/// <summary>
/// This default value passed in to Rent to use the default value for the pool.
/// </summary>
private const int AnySize = -1;
public DiagnosticMemoryPool(MemoryPool<byte> pool, bool allowLateReturn = false, bool rentTracking = false)
{
_pool = pool;
_allowLateReturn = allowLateReturn;
_rentTracking = rentTracking;
_blocks = new HashSet<DiagnosticPoolBlock>();
_syncObj = new object();
_allBlocksReturned = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
_blockAccessExceptions = new List<Exception>();
}
public bool IsDisposed { get; private set; }
public override IMemoryOwner<byte> Rent(int size = AnySize)
{
lock (_syncObj)
{
if (IsDisposed) MemoryPoolThrowHelper.ThrowObjectDisposedException(MemoryPoolThrowHelper.ExceptionArgument.MemoryPool);
var diagnosticPoolBlock = new DiagnosticPoolBlock(this, _pool.Rent(size));
if (_rentTracking) diagnosticPoolBlock.Track();
_totalBlocks++;
_blocks.Add(diagnosticPoolBlock);
return diagnosticPoolBlock;
}
}
public override int MaxBufferSize => _pool.MaxBufferSize;
internal void Return(DiagnosticPoolBlock block)
{
bool returnedAllBlocks;
lock (_syncObj)
{
_blocks.Remove(block);
returnedAllBlocks = _blocks.Count == 0;
}
if (IsDisposed)
{
if (!_allowLateReturn) MemoryPoolThrowHelper.ThrowInvalidOperationException_BlockReturnedToDisposedPool(block);
if (returnedAllBlocks) SetAllBlocksReturned();
}
}
internal void ReportException(Exception exception)
{
lock (_syncObj)
{
_blockAccessExceptions.Add(exception);
}
}
protected override void Dispose(bool disposing)
{
if (IsDisposed) MemoryPoolThrowHelper.ThrowInvalidOperationException_DoubleDispose();
bool allBlocksReturned = false;
try
{
lock (_syncObj)
{
IsDisposed = true;
allBlocksReturned = _blocks.Count == 0;
if (!allBlocksReturned && !_allowLateReturn) MemoryPoolThrowHelper.ThrowInvalidOperationException_DisposingPoolWithActiveBlocks(_totalBlocks - _blocks.Count, _totalBlocks, _blocks.ToArray());
if (_blockAccessExceptions.Any()) throw CreateAccessExceptions();
}
}
finally
{
if (allBlocksReturned) SetAllBlocksReturned();
}
}
private void SetAllBlocksReturned()
{
if (_blockAccessExceptions.Any())
_allBlocksReturned.SetException(CreateAccessExceptions());
else
_allBlocksReturned.SetResult(null);
}
private AggregateException CreateAccessExceptions() => new AggregateException("Exceptions occurred while accessing blocks", _blockAccessExceptions.ToArray());
public async Task WhenAllBlocksReturnedAsync(TimeSpan timeout)
{
var task = await Task.WhenAny(_allBlocksReturned.Task, Task.Delay(timeout));
if (task != _allBlocksReturned.Task)
MemoryPoolThrowHelper.ThrowInvalidOperationException_BlocksWereNotReturnedInTime(_totalBlocks - _blocks.Count, _totalBlocks, _blocks.ToArray());
await task;
}
}
}

View file

@ -1,188 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Threading;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace System.Buffers
{
/// <summary>
/// Block tracking object used by the byte buffer memory pool. A slab is a large allocation which is divided into smaller blocks. The
/// individual blocks are then treated as independent array segments.
/// </summary>
public sealed class DiagnosticPoolBlock : MemoryManager<byte>
{
/// <summary>
/// Back-reference to the memory pool which this block was allocated from. It may only be returned to this pool.
/// </summary>
private readonly DiagnosticMemoryPool _pool;
private readonly IMemoryOwner<byte> _memoryOwner;
private MemoryHandle? _memoryHandle;
private readonly Memory<byte> _memory;
private readonly object _syncObj = new object();
private bool _isDisposed;
private int _pinCount;
/// <summary>
/// This object cannot be instantiated outside of the static Create method
/// </summary>
internal DiagnosticPoolBlock(DiagnosticMemoryPool pool, IMemoryOwner<byte> memoryOwner)
{
_pool = pool;
_memoryOwner = memoryOwner;
_memory = memoryOwner.Memory;
}
public override Memory<byte> Memory
{
get
{
try
{
lock (_syncObj)
{
if (_isDisposed) MemoryPoolThrowHelper.ThrowObjectDisposedException(MemoryPoolThrowHelper.ExceptionArgument.MemoryPoolBlock);
if (_pool.IsDisposed) MemoryPoolThrowHelper.ThrowInvalidOperationException_BlockIsBackedByDisposedSlab(this);
return CreateMemory(_memory.Length);
}
}
catch (Exception exception)
{
_pool.ReportException(exception);
throw;
}
}
}
protected override void Dispose(bool disposing)
{
try
{
lock (_syncObj)
{
if (Volatile.Read(ref _pinCount) > 0) MemoryPoolThrowHelper.ThrowInvalidOperationException_ReturningPinnedBlock(this);
if (_isDisposed) MemoryPoolThrowHelper.ThrowInvalidOperationException_BlockDoubleDispose(this);
_memoryOwner.Dispose();
_pool.Return(this);
_isDisposed = true;
}
}
catch (Exception exception)
{
_pool.ReportException(exception);
throw;
}
}
public override Span<byte> GetSpan()
{
try
{
lock (_syncObj)
{
if (_isDisposed) MemoryPoolThrowHelper.ThrowObjectDisposedException(MemoryPoolThrowHelper.ExceptionArgument.MemoryPoolBlock);
if (_pool.IsDisposed) MemoryPoolThrowHelper.ThrowInvalidOperationException_BlockIsBackedByDisposedSlab(this);
return _memory.Span;
}
}
catch (Exception exception)
{
_pool.ReportException(exception);
throw;
}
}
public override MemoryHandle Pin(int byteOffset = 0)
{
try
{
lock (_syncObj)
{
if (_isDisposed) MemoryPoolThrowHelper.ThrowObjectDisposedException(MemoryPoolThrowHelper.ExceptionArgument.MemoryPoolBlock);
if (_pool.IsDisposed) MemoryPoolThrowHelper.ThrowInvalidOperationException_BlockIsBackedByDisposedSlab(this);
if (byteOffset < 0 || byteOffset > _memory.Length) MemoryPoolThrowHelper.ThrowArgumentOutOfRangeException(_memory.Length, byteOffset);
_pinCount++;
_memoryHandle ??= _memory.Pin();
unsafe
{
return new MemoryHandle(((IntPtr)_memoryHandle.Value.Pointer + byteOffset).ToPointer(), default, this);
}
}
}
catch (Exception exception)
{
_pool.ReportException(exception);
throw;
}
}
protected override bool TryGetArray(out ArraySegment<byte> segment)
{
try
{
lock (_syncObj)
{
if (_isDisposed) MemoryPoolThrowHelper.ThrowObjectDisposedException(MemoryPoolThrowHelper.ExceptionArgument.MemoryPoolBlock);
if (_pool.IsDisposed) MemoryPoolThrowHelper.ThrowInvalidOperationException_BlockIsBackedByDisposedSlab(this);
return MemoryMarshal.TryGetArray(_memory, out segment);
}
}
catch (Exception exception)
{
_pool.ReportException(exception);
throw;
}
}
public override void Unpin()
{
try
{
lock (_syncObj)
{
if (_pinCount == 0) MemoryPoolThrowHelper.ThrowInvalidOperationException_PinCountZero(this);
_pinCount--;
if (_pinCount == 0)
{
Debug.Assert(_memoryHandle.HasValue);
_memoryHandle.Value.Dispose();
_memoryHandle = null;
}
}
}
catch (Exception exception)
{
_pool.ReportException(exception);
throw;
}
}
public StackTrace Leaser { get; set; }
public void Track()
{
Leaser = new StackTrace(false);
}
}
}

View file

@ -7,7 +7,7 @@ using System.Text;
namespace System.Buffers
{
public class MemoryPoolThrowHelper
public static class MemoryPoolThrowHelper
{
public static void ThrowArgumentOutOfRangeException(int sourceLength, int offset)
{
@ -17,60 +17,6 @@ namespace System.Buffers
[MethodImpl(MethodImplOptions.NoInlining)]
private static ArgumentOutOfRangeException GetArgumentOutOfRangeException(int sourceLength, int offset) =>
(uint)offset > (uint)sourceLength ? new ArgumentOutOfRangeException(GetArgumentName(ExceptionArgument.offset)) : new ArgumentOutOfRangeException(GetArgumentName(ExceptionArgument.length));
public static void ThrowInvalidOperationException_PinCountZero(DiagnosticPoolBlock block)
{
throw new InvalidOperationException(GenerateMessage("Can't unpin, pin count is zero", block));
}
public static void ThrowInvalidOperationException_ReturningPinnedBlock(DiagnosticPoolBlock block)
{
throw new InvalidOperationException(GenerateMessage("Disposing pinned block", block));
}
public static void ThrowInvalidOperationException_DoubleDispose()
{
throw new InvalidOperationException("Object is being disposed twice");
}
public static void ThrowInvalidOperationException_BlockDoubleDispose(DiagnosticPoolBlock block)
{
throw new InvalidOperationException("Block is being disposed twice");
}
public static void ThrowInvalidOperationException_BlockReturnedToDisposedPool(DiagnosticPoolBlock block)
{
throw new InvalidOperationException(GenerateMessage("Block is being returned to disposed pool", block));
}
public static void ThrowInvalidOperationException_BlockIsBackedByDisposedSlab(DiagnosticPoolBlock block)
{
throw new InvalidOperationException(GenerateMessage("Block is backed by disposed slab", block));
}
public static void ThrowInvalidOperationException_DisposingPoolWithActiveBlocks(int returned, int total, DiagnosticPoolBlock[] blocks)
{
throw new InvalidOperationException(GenerateMessage($"Memory pool with active blocks is being disposed, {returned} of {total} returned", blocks));
}
public static void ThrowInvalidOperationException_BlocksWereNotReturnedInTime(int returned, int total, DiagnosticPoolBlock[] blocks)
{
throw new InvalidOperationException(GenerateMessage($"Blocks were not returned in time, {returned} of {total} returned ", blocks));
}
private static string GenerateMessage(string message, params DiagnosticPoolBlock[] blocks)
{
StringBuilder builder = new StringBuilder(message);
foreach (var diagnosticPoolBlock in blocks)
if (diagnosticPoolBlock.Leaser != null)
{
builder.AppendLine();
builder.AppendLine("Block leased from:");
builder.AppendLine(diagnosticPoolBlock.Leaser.ToString());
}
return builder.ToString();
}
public static void ThrowArgumentOutOfRangeException_BufferRequestTooLarge(int maxSize)
{

View file

@ -95,6 +95,12 @@ namespace Server
}
}
public static partial class EventSink
{
public static event Action<CommandEventArgs> Command;
public static void InvokeCommand(CommandEventArgs e) => Command?.Invoke(e);
}
public class CommandEntry : IComparable<CommandEntry>
{
public CommandEntry(string command, CommandEventHandler handler, AccessLevel accessLevel)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,52 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: AccountLoginEvent.cs *
* Created: 2020/04/11 - Updated: 2020/04/11 *
* *
* 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 Server.Network;
namespace Server
{
public class AccountLoginEventArgs : EventArgs
{
public AccountLoginEventArgs(NetState state, string username, string password)
{
State = state;
Username = username;
Password = password;
}
public NetState State{ get; }
public string Username{ get; }
public string Password{ get; }
public bool Accepted{ get; set; }
public ALRReason RejectReason{ get; set; }
}
public static partial class EventSink
{
public static event Action<AccountLoginEventArgs> AccountLogin;
public static void InvokeAccountLogin(AccountLoginEventArgs e) => AccountLogin?.Invoke(e);
}
}

View file

@ -0,0 +1,75 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: AggressiveActionEvent.cs *
* Created: 2020/04/11 - Updated: 2020/04/11 *
* *
* 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.Collections.Generic;
namespace Server
{
public class AggressiveActionEventArgs : EventArgs
{
private static Queue<AggressiveActionEventArgs> m_Pool = new Queue<AggressiveActionEventArgs>();
private AggressiveActionEventArgs(Mobile aggressed, Mobile aggressor, bool criminal)
{
Aggressed = aggressed;
Aggressor = aggressor;
Criminal = criminal;
}
public Mobile Aggressed{ get; private set; }
public Mobile Aggressor{ get; private set; }
public bool Criminal{ get; private set; }
public static AggressiveActionEventArgs Create(Mobile aggressed, Mobile aggressor, bool criminal)
{
AggressiveActionEventArgs args;
if (m_Pool.Count > 0)
{
args = m_Pool.Dequeue();
args.Aggressed = aggressed;
args.Aggressor = aggressor;
args.Criminal = criminal;
}
else
{
args = new AggressiveActionEventArgs(aggressed, aggressor, criminal);
}
return args;
}
public void Free()
{
m_Pool.Enqueue(this);
}
}
public static partial class EventSink
{
public static event Action<AggressiveActionEventArgs> AggressiveAction;
public static void InvokeAggressiveAction(AggressiveActionEventArgs e) => AggressiveAction?.Invoke(e);
}
}

View file

@ -0,0 +1,110 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: CharacterCreatedEvent.cs *
* Created: 2020/04/11 - Updated: 2020/04/11 *
* *
* 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 Server.Accounting;
using Server.Network;
namespace Server
{
public class CharacterCreatedEventArgs : EventArgs
{
public CharacterCreatedEventArgs(NetState state, IAccount a, string name, bool female, int hue, int str, int dex,
int intel, CityInfo city, SkillNameValue[] skills, int shirtHue, int pantsHue, int hairID, int hairHue,
int beardID, int beardHue, int profession, Race race)
{
State = state;
Account = a;
Name = name;
Female = female;
Hue = hue;
Str = str;
Dex = dex;
Int = intel;
City = city;
Skills = skills;
ShirtHue = shirtHue;
PantsHue = pantsHue;
HairID = hairID;
HairHue = hairHue;
BeardID = beardID;
BeardHue = beardHue;
Profession = profession;
Race = race;
}
public NetState State{ get; }
public IAccount Account{ get; }
public Mobile Mobile{ get; set; }
public string Name{ get; }
public bool Female{ get; }
public int Hue{ get; }
public int Str{ get; }
public int Dex{ get; }
public int Int{ get; }
public CityInfo City{ get; }
public SkillNameValue[] Skills{ get; }
public int ShirtHue{ get; }
public int PantsHue{ get; }
public int HairID{ get; }
public int HairHue{ get; }
public int BeardID{ get; }
public int BeardHue{ get; }
public int Profession{ get; set; }
public Race Race{ get; }
}
public struct SkillNameValue
{
public SkillName Name{ get; }
public int Value{ get; }
public SkillNameValue(SkillName name, int value)
{
Name = name;
Value = value;
}
}
public static partial class EventSink {
public static event Action<CharacterCreatedEventArgs> CharacterCreated;
public static void InvokeCharacterCreated(CharacterCreatedEventArgs e) => CharacterCreated?.Invoke(e);
}
}

View file

@ -0,0 +1,41 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: CreateGuildEvent.cs *
* Created: 2020/04/11 - Updated: 2020/04/11 *
* *
* 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 Server.Guilds;
namespace Server
{
public class CreateGuildEventArgs : EventArgs
{
public CreateGuildEventArgs(uint id) => Id = id;
public uint Id{ get; set; }
public BaseGuild Guild{ get; set; }
}
public static partial class EventSink
{
public static event Action<CreateGuildEventArgs> CreateGuild;
public static void InvokeCreateGuild(CreateGuildEventArgs e) => CreateGuild?.Invoke(e);
}
}

View file

@ -0,0 +1,150 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: EventSink.cs *
* Created: 2020/04/11 - Updated: 2020/04/11 *
* *
* 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.Collections.Generic;
using Server.Network;
namespace Server
{
public static partial class EventSink
{
public static event Action<Mobile> OpenDoorMacroUsed;
public static void InvokeOpenDoorMacroUsed(Mobile m) => OpenDoorMacroUsed?.Invoke(m);
public static event Action<Mobile> Login;
public static void InvokeLogin(Mobile m) => Login?.Invoke(m);
public static event Action<Mobile, int> HungerChanged;
public static void InvokeHungerChanged(Mobile mobile, int oldValue) => HungerChanged?.Invoke(mobile, oldValue);
public static event Action Shutdown;
public static void InvokeShutdown() => Shutdown?.Invoke();
public static event Action<Mobile> HelpRequest;
public static void InvokeHelpRequest(Mobile m) => HelpRequest?.Invoke(m);
public static event Action<Mobile> DisarmRequest;
public static void InvokeDisarmRequest(Mobile m) => DisarmRequest?.Invoke(m);
public static event Action<Mobile> StunRequest;
public static void InvokeStunRequest(Mobile m) => StunRequest?.Invoke(m);
public static event Action<Mobile, int> OpenSpellbookRequest;
public static void InvokeOpenSpellbookRequest(Mobile m, int type) => OpenSpellbookRequest?.Invoke(m, type);
public static event Action<Mobile, int, Item> CastSpellRequest;
public static void InvokeCastSpellRequest(Mobile m, int spellID, Item book) => CastSpellRequest?.Invoke(m, spellID, book);
public static event Action<Mobile, Item, Mobile> BandageTargetRequest;
public static void InvokeBandageTargetRequest(Mobile m, Item bandage, Mobile target) => BandageTargetRequest?.Invoke(m, bandage, target);
public static event Action<Mobile, string> AnimateRequest;
public static void InvokeAnimateRequest(Mobile m, string action) => AnimateRequest?.Invoke(m, action);
public static event Action<Mobile> Logout;
public static void InvokeLogout(Mobile m) => Logout?.Invoke(m);
public static event Action<Mobile> Connected;
public static void InvokeConnected(Mobile m) => Connected?.Invoke(m);
public static event Action<Mobile> Disconnected;
public static void InvokeDisconnected(Mobile m) => Disconnected?.Invoke(m);
public static event Action<Mobile, Mobile, string> RenameRequest;
public static void InvokeRenameRequest(Mobile from, Mobile target, string name) => RenameRequest?.Invoke(from, target, name);
public static event Action<Mobile> PlayerDeath;
public static void InvokePlayerDeath(Mobile m) => PlayerDeath?.Invoke(m);
public static event Action<Mobile, Mobile> VirtueGumpRequest;
public static void InvokeVirtueGumpRequest(Mobile beholder, Mobile beheld) => VirtueGumpRequest?.Invoke(beholder, beheld);
public static event Action<Mobile, Mobile, int> VirtueItemRequest;
public static void InvokeVirtueItemRequest(Mobile beholder, Mobile beheld, int gumpID) => VirtueItemRequest?.Invoke(beholder, beheld, gumpID);
public static event Action<Mobile, int> VirtueMacroRequest;
public static void InvokeVirtueMacroRequest(Mobile mobile, int virtueID) => VirtueMacroRequest?.Invoke(mobile, virtueID);
public static event Action<Mobile> ChatRequest;
public static void InvokeChatRequest(Mobile m) => ChatRequest?.Invoke(m);
public static event Action<Mobile, Mobile> PaperdollRequest;
public static void InvokePaperdollRequest(Mobile beholder, Mobile beheld) => PaperdollRequest?.Invoke(beholder ,beheld);
public static event Action<Mobile, Mobile> ProfileRequest;
public static void InvokeProfileRequest(Mobile beholder, Mobile beheld) => ProfileRequest?.Invoke(beholder, beheld);
public static event Action<Mobile, Mobile, string> ChangeProfileRequest;
public static void InvokeChangeProfileRequest(Mobile beholder, Mobile beheld, string text) =>
ChangeProfileRequest?.Invoke(beholder, beheld, text);
public static event Action<NetState, int> DeleteRequest;
public static void InvokeDeleteRequest(NetState state, int index) => DeleteRequest?.Invoke(state, index);
public static event Action WorldLoad;
public static void InvokeWorldLoad() => WorldLoad?.Invoke();
public static event Action<bool> WorldSave;
public static void InvokeWorldSave(bool sendMessage) => WorldSave?.Invoke(sendMessage);
public static event Action<Mobile, int> SetAbility;
public static void InvokeSetAbility(Mobile mobile, int index) => SetAbility?.Invoke(mobile, index);
public static event Action ServerStarted;
public static void InvokeServerStarted() => ServerStarted?.Invoke();
public static event Action<Mobile> GuildGumpRequest;
public static void InvokeGuildGumpRequest(Mobile m) => GuildGumpRequest?.Invoke(m);
public static event Action<Mobile> QuestGumpRequest;
public static void InvokeQuestGumpRequest(Mobile m) => QuestGumpRequest?.Invoke(m);
public static event Action<NetState, ClientVersion> ClientVersionReceived;
public static void InvokeClientVersionReceived(NetState state, ClientVersion cv) => ClientVersionReceived?.Invoke(state, cv);
public static event Action<Mobile, List<Serial>> EquipMacro;
public static void InvokeEquipMacro(Mobile m, List<Serial> list)
{
if (list?.Count > 0)
EquipMacro?.Invoke(m, list);
}
public static event Action<Mobile, List<Layer>> UnequipMacro;
public static void InvokeUnequipMacro(Mobile m, List<Layer> layers)
{
if (layers?.Count > 0)
UnequipMacro?.Invoke(m, layers);
}
public static event Action<Mobile, IEntity, int> TargetedSpell;
public static void InvokeTargetedSpell(Mobile m, IEntity target, int spellId) => TargetedSpell?.Invoke(m, target, spellId);
public static event Action<Mobile, IEntity, int> TargetedSkillUse;
public static void InvokeTargetedSkillUse(Mobile m, IEntity target, int skillId) => TargetedSkillUse?.Invoke(m, target, skillId);
public static event Action<Mobile, Item, short> TargetByResourceMacro;
public static void InvokeTargetByResourceMacro(Mobile m, Item item, short resourceType) => TargetByResourceMacro?.Invoke(m, item, resourceType);
}
}

View file

@ -0,0 +1,45 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: FastWalkEvent.cs *
* Created: 2020/04/11 - Updated: 2020/04/11 *
* *
* 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 Server.Network;
namespace Server
{
public class FastWalkEventArgs : EventArgs
{
public FastWalkEventArgs(NetState state)
{
NetState = state;
Blocked = false;
}
public NetState NetState{ get; }
public bool Blocked{ get; set; }
}
public static partial class EventSink
{
public static event Action<FastWalkEventArgs> FastWalk;
public static void InvokeFastWalk(FastWalkEventArgs e) => FastWalk?.Invoke(e);
}
}

View file

@ -0,0 +1,52 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: GameLoginEvent.cs *
* Created: 2020/04/11 - Updated: 2020/04/11 *
* *
* 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 Server.Network;
namespace Server
{
public class GameLoginEventArgs : EventArgs
{
public GameLoginEventArgs(NetState state, string un, string pw)
{
State = state;
Username = un;
Password = pw;
}
public NetState State{ get; }
public string Username{ get; }
public string Password{ get; }
public bool Accepted{ get; set; }
public CityInfo[] CityInfo{ get; set; }
}
public static partial class EventSink
{
public static event Action<GameLoginEventArgs> GameLogin;
public static void InvokeGameLogin(GameLoginEventArgs e) => GameLogin?.Invoke(e);
}
}

View file

@ -0,0 +1,74 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: MovementEvent.cs *
* Created: 2020/04/11 - Updated: 2020/04/11 *
* *
* 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.Collections.Generic;
namespace Server
{
public class MovementEventArgs : EventArgs
{
private static Queue<MovementEventArgs> m_Pool = new Queue<MovementEventArgs>();
public MovementEventArgs(Mobile mobile, Direction dir)
{
Mobile = mobile;
Direction = dir;
}
public Mobile Mobile{ get; private set; }
public Direction Direction{ get; private set; }
public bool Blocked{ get; set; }
public static MovementEventArgs Create(Mobile mobile, Direction dir)
{
MovementEventArgs args;
if (m_Pool.Count > 0)
{
args = m_Pool.Dequeue();
args.Mobile = mobile;
args.Direction = dir;
args.Blocked = false;
}
else
{
args = new MovementEventArgs(mobile, dir);
}
return args;
}
public void Free()
{
m_Pool.Enqueue(this);
}
}
public static partial class EventSink
{
public static event Action<MovementEventArgs> Movement;
public static void InvokeMovement(MovementEventArgs e) => Movement?.Invoke(e);
}
}

View file

@ -0,0 +1,40 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: ServerCrashedEvent.cs *
* Created: 2020/04/11 - Updated: 2020/04/11 *
* *
* 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;
namespace Server
{
public class ServerCrashedEventArgs : EventArgs
{
public ServerCrashedEventArgs(Exception e) => Exception = e;
public Exception Exception{ get; }
public bool Close{ get; set; }
}
public static partial class EventSink
{
public static event Action<ServerCrashedEventArgs> ServerCrashed;
public static void InvokeServerCrashed(ServerCrashedEventArgs e) => ServerCrashed?.Invoke(e);
}
}

View file

@ -0,0 +1,63 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: ServerListEvent.cs *
* Created: 2020/04/11 - Updated: 2020/04/11 *
* *
* 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.Collections.Generic;
using System.Net;
using Server.Accounting;
using Server.Network;
namespace Server
{
public class ServerListEventArgs : EventArgs
{
public ServerListEventArgs(NetState state, IAccount account)
{
State = state;
Account = account;
Servers = new List<ServerInfo>();
}
public NetState State{ get; }
public IAccount Account{ get; }
public bool Rejected{ get; set; }
public List<ServerInfo> Servers{ get; }
public void AddServer(string name, IPEndPoint address)
{
AddServer(name, 0, TimeZoneInfo.Local, address);
}
public void AddServer(string name, int fullPercent, TimeZoneInfo tz, IPEndPoint address)
{
Servers.Add(new ServerInfo(name, fullPercent, tz, address));
}
}
public static partial class EventSink
{
public static event Action<ServerListEventArgs> ServerList;
public static void InvokeServerList(ServerListEventArgs e) => ServerList?.Invoke(e);
}
}

View file

@ -0,0 +1,45 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: SocketConnectionEvent.cs *
* Created: 2020/04/11 - Updated: 2020/04/11 *
* *
* 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 Microsoft.AspNetCore.Connections;
namespace Server
{
public class SocketConnectEventArgs : EventArgs
{
public SocketConnectEventArgs(ConnectionContext c)
{
Context = c;
AllowConnection = true;
}
public ConnectionContext Context{ get; }
public bool AllowConnection{ get; set; }
}
public static partial class EventSink
{
public static event Action<SocketConnectEventArgs> SocketConnect;
public static void InvokeSocketConnect(SocketConnectEventArgs e) => SocketConnect?.Invoke(e);
}
}

View file

@ -0,0 +1,46 @@
using System;
using Server.Network;
namespace Server
{
public class SpeechEventArgs : EventArgs
{
public SpeechEventArgs(Mobile mobile, string speech, MessageType type, int hue, int[] keywords)
{
Mobile = mobile;
Speech = speech;
Type = type;
Hue = hue;
Keywords = keywords;
}
public Mobile Mobile{ get; }
public string Speech{ get; set; }
public MessageType Type{ get; }
public int Hue{ get; }
public int[] Keywords{ get; }
public bool Handled{ get; set; }
public bool Blocked{ get; set; }
public bool HasKeyword(int keyword)
{
for (int i = 0; i < Keywords.Length; ++i)
if (Keywords[i] == keyword)
return true;
return false;
}
}
public static partial class EventSink
{
public static event Action<SpeechEventArgs> Speech;
public static void InvokeSpeech(SpeechEventArgs e) => Speech?.Invoke(e);
}
}

View file

@ -251,9 +251,9 @@ namespace Server
try
{
CrashedEventArgs args = new CrashedEventArgs(e.ExceptionObject as Exception);
ServerCrashedEventArgs args = new ServerCrashedEventArgs(e.ExceptionObject as Exception);
EventSink.InvokeCrashed(args);
EventSink.InvokeServerCrashed(args);
close = args.Close;
}
@ -318,7 +318,7 @@ namespace Server
World.WaitForWriteCompletion();
if (!m_Crashed)
EventSink.InvokeShutdown(new ShutdownEventArgs());
EventSink.InvokeShutdown();
Timer.TimerThread.Set();

View file

@ -707,7 +707,7 @@ namespace Server
{
m_Hunger = value;
EventSink.InvokeHungerChanged(new HungerChangedEventArgs(this, oldValue));
EventSink.InvokeHungerChanged(this, oldValue);
}
}
}
@ -1461,7 +1461,7 @@ namespace Server
if (m_NetState == null)
{
OnDisconnected();
EventSink.InvokeDisconnected(new DisconnectedEventArgs(this));
EventSink.InvokeDisconnected(this);
// Disconnected, start the logout timer
@ -1476,7 +1476,7 @@ namespace Server
else
{
OnConnected();
EventSink.InvokeConnected(new ConnectedEventArgs(this));
EventSink.InvokeConnected(this);
// Connected, stop the logout timer and if needed, move to the world
@ -1818,16 +1818,7 @@ namespace Server
public virtual bool KeepsItemsOnDeath => m_AccessLevel > AccessLevel.Player;
public bool HasTrade
{
get
{
if (m_NetState != null)
return m_NetState.Trades.Count > 0;
return false;
}
}
public bool HasTrade => m_NetState?.Trades.Count > 0;
public bool NoMoveHS{ get; set; }
@ -4394,7 +4385,7 @@ namespace Server
Stam = 0;
Mana = 0;
EventSink.InvokePlayerDeath(new PlayerDeathEventArgs(this));
EventSink.InvokePlayerDeath(this);
ProcessDeltaQueue();
@ -6456,10 +6447,10 @@ namespace Server
return false;
return this == m || m.m_Map == m_Map &&
(!m.Hidden || m_AccessLevel != AccessLevel.Player &&
(m_AccessLevel >= m.AccessLevel || m_AccessLevel >= AccessLevel.Administrator)) &&
(m.Alive || Core.SE && Skills.SpiritSpeak.Value >= 100.0 || !Alive ||
m_AccessLevel > AccessLevel.Player || m.Warmode);
(!m.Hidden || m_AccessLevel != AccessLevel.Player &&
(m_AccessLevel >= m.AccessLevel || m_AccessLevel >= AccessLevel.Administrator)) &&
(m.Alive || Core.SE && Skills.SpiritSpeak.Value >= 100.0 || !Alive ||
m_AccessLevel > AccessLevel.Player || m.Warmode);
}
public virtual bool CanBeRenamedBy(Mobile from) => from.AccessLevel >= AccessLevel.GameMaster && from.m_AccessLevel > m_AccessLevel;
@ -7069,7 +7060,7 @@ namespace Server
public virtual void DisplayPaperdollTo(Mobile to)
{
EventSink.InvokePaperdollRequest(new PaperdollRequestEventArgs(to, this));
EventSink.InvokePaperdollRequest(to, this);
}
/// <summary>
@ -7548,7 +7539,7 @@ namespace Server
{
if (m_Mobile.m_Map != Map.Internal)
{
EventSink.InvokeLogout(new LogoutEventArgs(m_Mobile));
EventSink.InvokeLogout(m_Mobile);
m_Mobile.LogoutLocation = m_Mobile.m_Location;
m_Mobile.LogoutMap = m_Mobile.m_Map;
@ -7725,8 +7716,8 @@ namespace Server
m_Callback(from, "");
else
m_CancelCallback?.Invoke(@from, "");
}
}
}
public Prompt BeginPrompt(PromptCallback callback, PromptCallback cancelCallback)
{

View file

@ -19,91 +19,203 @@
***************************************************************************/
using System;
using System.Buffers;
using System.Collections.Generic;
using System.IO;
using Server.Network;
namespace Server
{
public static class MultiData
{
private static readonly MultiComponentList[] m_Components;
public static Dictionary<int, MultiComponentList> Components { get; } = new Dictionary<int, MultiComponentList>();
private static readonly FileStream m_Index;
private static readonly FileStream m_Stream;
private static readonly BinaryReader m_IndexReader;
private static readonly BinaryReader m_StreamReader;
private static readonly bool UsingUOPFormat;
static MultiData()
{
string multiUOPPath = Core.FindDataFile("MultiCollection.uop");
if (File.Exists(multiUOPPath))
{
LoadUOP(multiUOPPath);
UsingUOPFormat = true;
return;
}
string idxPath = Core.FindDataFile("multi.idx");
string mulPath = Core.FindDataFile("multi.mul");
if (File.Exists(idxPath) && File.Exists(mulPath))
{
m_Index = new FileStream(idxPath, FileMode.Open, FileAccess.Read, FileShare.Read);
m_IndexReader = new BinaryReader(m_Index);
var idx = new FileStream(idxPath, FileMode.Open, FileAccess.Read, FileShare.Read);
m_IndexReader = new BinaryReader(idx);
m_Stream = new FileStream(mulPath, FileMode.Open, FileAccess.Read, FileShare.Read);
m_StreamReader = new BinaryReader(m_Stream);
m_Components = new MultiComponentList[(int)(m_Index.Length / 12)];
var stream = new FileStream(mulPath, FileMode.Open, FileAccess.Read, FileShare.Read);
m_StreamReader = new BinaryReader(stream);
string vdPath = Core.FindDataFile("verdata.mul");
if (File.Exists(vdPath))
if (!File.Exists(vdPath)) return;
using FileStream fs = new FileStream(vdPath, FileMode.Open, FileAccess.Read, FileShare.Read);
BinaryReader bin = new BinaryReader(fs);
int count = bin.ReadInt32();
for (int i = 0; i < count; ++i)
{
using FileStream fs = new FileStream(vdPath, FileMode.Open, FileAccess.Read, FileShare.Read);
BinaryReader bin = new BinaryReader(fs);
int file = bin.ReadInt32();
int index = bin.ReadInt32();
int lookup = bin.ReadInt32();
int length = bin.ReadInt32();
bin.ReadInt32(); // extra
int count = bin.ReadInt32();
for (int i = 0; i < count; ++i)
if (file == 14 && index >= 0 && lookup >= 0 && length > 0)
{
int file = bin.ReadInt32();
int index = bin.ReadInt32();
int lookup = bin.ReadInt32();
int length = bin.ReadInt32();
int extra = bin.ReadInt32();
bin.BaseStream.Seek(lookup, SeekOrigin.Begin);
if (file == 14 && index >= 0 && index < m_Components.Length && lookup >= 0 && length > 0)
{
bin.BaseStream.Seek(lookup, SeekOrigin.Begin);
Components[index] = new MultiComponentList(bin, length / 12);
m_Components[index] = new MultiComponentList(bin, length / 12);
bin.BaseStream.Seek(24 + i * 20, SeekOrigin.Begin);
}
bin.BaseStream.Seek(24 + i * 20, SeekOrigin.Begin);
}
bin.Close();
}
bin.Close();
}
else
{
Console.WriteLine("Warning: Multi data files not found");
m_Components = new MultiComponentList[0];
}
}
public static MultiComponentList GetComponents(int multiID)
{
MultiComponentList mcl;
if (multiID >= 0 && multiID < m_Components.Length)
{
mcl = m_Components[multiID];
multiID &= 0x3FFF;
if (mcl == null)
m_Components[multiID] = mcl = Load(multiID);
}
if (Components.ContainsKey(multiID))
mcl = Components[multiID];
else if (!UsingUOPFormat)
Components[multiID] = mcl = Load(multiID);
else
{
mcl = MultiComponentList.Empty;
}
return mcl;
}
public static void LoadUOP(string path)
{
var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
BinaryReader streamReader = new BinaryReader(stream);
// Head Information Start
if (streamReader.ReadInt32() != 0x0050594D) // Not a UOP Files
return;
if (streamReader.ReadInt32() > 5) // Bad Version
return;
// Multi ID List Array Start
UOPHash.BuildChunkIDs(out var chunkIds);
// Multi ID List Array End
streamReader.ReadUInt32(); // format timestamp? 0xFD23EC43
long startAddress = streamReader.ReadInt64();
streamReader.ReadInt32();
streamReader.ReadInt32();
stream.Seek(startAddress, SeekOrigin.Begin); // Head Information End
long nextBlock;
do
{
int blockFileCount = streamReader.ReadInt32();
nextBlock = streamReader.ReadInt64();
int index = 0;
do
{
long offset = streamReader.ReadInt64();
int headerSize = streamReader.ReadInt32(); // header length
int compressedSize = streamReader.ReadInt32(); // compressed size
int decompressedSize = streamReader.ReadInt32(); // decompressed size
ulong filehash = streamReader.ReadUInt64(); // filename hash (HashLittle2)
streamReader.ReadUInt32();
short compressionMethod = streamReader.ReadInt16(); // compression method (0 = none, 1 = zlib)
index++;
if (offset == 0 || decompressedSize == 0 || filehash == 0x126D1E99DDEDEE0A) // Exclude housing.bin
continue;
chunkIds.TryGetValue(filehash, out var chunkID);
long position = stream.Position; // save current position
stream.Seek(offset + headerSize, SeekOrigin.Begin);
Span<byte> sourceData = new byte[compressedSize];
if (stream.Read(sourceData) != compressedSize)
continue;
Span<byte> data;
if (compressionMethod == 1)
{
data = new byte[decompressedSize];
Compression.Unpack(data, ref decompressedSize, sourceData, compressedSize);
}
else
data = sourceData;
var tileList = new List<MultiTileEntry>();
// Skip the first 4 bytes
BufferReader<byte> reader = new BufferReader<byte>(data);
reader.Advance(4); // ???
reader.TryReadLittleEndian(out uint count);
for (uint i = 0; i < count; i++)
{
reader.TryReadLittleEndian(out ushort itemid);
reader.TryReadLittleEndian(out short x);
reader.TryReadLittleEndian(out short y);
reader.TryReadLittleEndian(out short z);
reader.TryReadLittleEndian(out ushort flagValue);
TileFlag tileFlag = flagValue switch
{
1 => TileFlag.None,
257 => TileFlag.Generic,
_ => TileFlag.Background // 0
};
reader.TryReadLittleEndian(out uint clilocsCount);
reader.Advance(clilocsCount * 4); // bypass binary block
tileList.Add(new MultiTileEntry(itemid, x, y, z, tileFlag));
}
Components[chunkID] = new MultiComponentList(tileList);
stream.Seek(position, SeekOrigin.Begin); // back to position
}
while (index < blockFileCount);
}
while (stream.Seek(nextBlock, SeekOrigin.Begin) != 0);
}
// TODO: Change this to read the file all during load time
public static MultiComponentList Load(int multiID)
{
try
@ -131,9 +243,9 @@ namespace Server
{
public ushort m_ItemID;
public short m_OffsetX, m_OffsetY, m_OffsetZ;
public int m_Flags;
public TileFlag m_Flags;
public MultiTileEntry(ushort itemID, short xOffset, short yOffset, short zOffset, int flags)
public MultiTileEntry(ushort itemID, short xOffset, short yOffset, short zOffset, TileFlag flags)
{
m_ItemID = itemID;
m_OffsetX = xOffset;
@ -205,7 +317,7 @@ namespace Server
allTiles[i].m_OffsetX = reader.ReadShort();
allTiles[i].m_OffsetY = reader.ReadShort();
allTiles[i].m_OffsetZ = reader.ReadShort();
allTiles[i].m_Flags = reader.ReadInt();
allTiles[i].m_Flags = (TileFlag)reader.ReadInt();
}
else
for (int i = 0; i < length; ++i)
@ -214,7 +326,7 @@ namespace Server
allTiles[i].m_OffsetX = reader.ReadShort();
allTiles[i].m_OffsetY = reader.ReadShort();
allTiles[i].m_OffsetZ = reader.ReadShort();
allTiles[i].m_Flags = reader.ReadInt();
allTiles[i].m_Flags = (TileFlag)reader.ReadInt();
}
TileList[][] tiles = new TileList[Width][];
@ -253,10 +365,11 @@ namespace Server
allTiles[i].m_OffsetX = reader.ReadInt16();
allTiles[i].m_OffsetY = reader.ReadInt16();
allTiles[i].m_OffsetZ = reader.ReadInt16();
allTiles[i].m_Flags = reader.ReadInt32();
if (PostHSFormat)
reader.ReadInt32(); // ??
allTiles[i].m_Flags = (TileFlag)reader.ReadUInt64();
else
allTiles[i].m_Flags = (TileFlag)reader.ReadUInt32();
MultiTileEntry e = allTiles[i];
@ -306,6 +419,63 @@ namespace Server
Tiles[x][y] = tiles[x][y].ToArray();
}
public MultiComponentList(List<MultiTileEntry> list)
{
var allTiles = List = new MultiTileEntry[list.Count];
for (int i = 0; i < list.Count; ++i)
{
allTiles[i].m_ItemID = list[i].m_ItemID;
allTiles[i].m_OffsetX = list[i].m_OffsetX;
allTiles[i].m_OffsetY = list[i].m_OffsetY;
allTiles[i].m_OffsetZ = list[i].m_OffsetZ;
allTiles[i].m_Flags = list[i].m_Flags;
MultiTileEntry e = allTiles[i];
if (i == 0 || e.m_Flags != 0)
{
if (e.m_OffsetX < m_Min.m_X) m_Min.m_X = e.m_OffsetX;
if (e.m_OffsetY < m_Min.m_Y) m_Min.m_Y = e.m_OffsetY;
if (e.m_OffsetX > m_Max.m_X) m_Max.m_X = e.m_OffsetX;
if (e.m_OffsetY > m_Max.m_Y) m_Max.m_Y = e.m_OffsetY;
}
}
Center = new Point2D(-m_Min.m_X, -m_Min.m_Y);
Width = (m_Max.m_X - m_Min.m_X) + 1;
Height = (m_Max.m_Y - m_Min.m_Y) + 1;
var tiles = new TileList[Width][];
Tiles = new StaticTile[Width][][];
for (int x = 0; x < Width; ++x)
{
tiles[x] = new TileList[Height];
Tiles[x] = new StaticTile[Height][];
for (int y = 0; y < Height; ++y) tiles[x][y] = new TileList();
}
for (int i = 0; i < allTiles.Length; ++i)
if (i == 0 || allTiles[i].m_Flags != 0)
{
int xOffset = allTiles[i].m_OffsetX + Center.m_X;
int yOffset = allTiles[i].m_OffsetY + Center.m_Y;
int itemID = ((allTiles[i].m_ItemID & TileData.MaxItemValue) | 0x10000);
tiles[xOffset][yOffset].Add((ushort)itemID, (sbyte)allTiles[i].m_OffsetZ);
}
for (int x = 0; x < Width; ++x)
for (int y = 0; y < Height; ++y)
Tiles[x][y] = tiles[x][y].ToArray();
}
private MultiComponentList()
{
Tiles = new StaticTile[0][][];
@ -368,7 +538,7 @@ namespace Server
for (int i = 0; i < oldList.Length; ++i)
newList[i] = oldList[i];
newList[oldList.Length] = new MultiTileEntry((ushort)itemID, (short)x, (short)y, (short)z, 1);
newList[oldList.Length] = new MultiTileEntry((ushort)itemID, (short)x, (short)y, (short)z, TileFlag.Background);
List = newList;
@ -552,7 +722,7 @@ namespace Server
if (vy > m_Max.m_Y)
m_Max.m_Y = vy;
List[index++] = new MultiTileEntry((ushort)tile.ID, (short)vx, (short)vy, (short)tile.Z, 1);
List[index++] = new MultiTileEntry((ushort)tile.ID, (short)vx, (short)vy, (short)tile.Z, TileFlag.Background);
}
}
}
@ -578,8 +748,86 @@ namespace Server
writer.Write(ent.m_OffsetX);
writer.Write(ent.m_OffsetY);
writer.Write(ent.m_OffsetZ);
writer.Write(ent.m_Flags);
writer.Write((int)ent.m_Flags);
}
}
}
}
public static class UOPHash
{
public static void BuildChunkIDs(out Dictionary<ulong, int> chunkIds)
{
const int maxId = 0x10000;
chunkIds = new Dictionary<ulong, int>();
for (int i = 0; i < maxId; ++i)
chunkIds[HashLittle2($"build/multicollection/{i:000000}.bin")] = i;
}
private static ulong HashLittle2(string s)
{
int length = s.Length;
uint b, c;
uint a = b = c = 0xDEADBEEF + (uint)length;
int k = 0;
while (length > 12)
{
a += s[k];
a += (uint)s[k + 1] << 8;
a += (uint)s[k + 2] << 16;
a += (uint)s[k + 3] << 24;
b += s[k + 4];
b += (uint)s[k + 5] << 8;
b += (uint)s[k + 6] << 16;
b += (uint)s[k + 7] << 24;
c += s[k + 8];
c += (uint)s[k + 9] << 8;
c += (uint)s[k + 10] << 16;
c += (uint)s[k + 11] << 24;
a -= c; a ^= (c << 4) | (c >> 28); c += b;
b -= a; b ^= (a << 6) | (a >> 26); a += c;
c -= b; c ^= (b << 8) | (b >> 24); b += a;
a -= c; a ^= (c << 16) | (c >> 16); c += b;
b -= a; b ^= (a << 19) | (a >> 13); a += c;
c -= b; c ^= (b << 4) | (b >> 28); b += a;
length -= 12;
k += 12;
}
if (length != 0)
{
switch (length)
{
case 12: c += (uint)s[k + 11] << 24; goto case 11;
case 11: c += (uint)s[k + 10] << 16; goto case 10;
case 10: c += (uint)s[k + 9] << 8; goto case 9;
case 9: c += s[k + 8]; goto case 8;
case 8: b += (uint)s[k + 7] << 24; goto case 7;
case 7: b += (uint)s[k + 6] << 16; goto case 6;
case 6: b += (uint)s[k + 5] << 8; goto case 5;
case 5: b += s[k + 4]; goto case 4;
case 4: a += (uint)s[k + 3] << 24; goto case 3;
case 3: a += (uint)s[k + 2] << 16; goto case 2;
case 2: a += (uint)s[k + 1] << 8; goto case 1;
case 1: a += s[k]; break;
}
c ^= b; c -= (b << 14) | (b >> 18);
a ^= c; a -= (c << 11) | (c >> 21);
b ^= a; b -= (a << 25) | (a >> 7);
c ^= b; c -= (b << 16) | (b >> 16);
a ^= c; a -= (c << 4) | (c >> 28);
b ^= a; b -= (a << 14) | (a >> 18);
c ^= b; c -= (b << 24) | (b >> 8);
}
return ((ulong)b << 32) | c;
}
}
}

View file

@ -1,23 +1,23 @@
/***************************************************************************
* MessagePump.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* 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 2 of the License, or
* (at your option) any later version.
*
***************************************************************************/
/*************************************************************************
* ModernUO *
* Copyright (C) 2019 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: MessagePumpService.cs *
* Created: 2020/04/12 - Updated: 2020/04/12 *
* *
* 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.Buffers;
using System.Collections.Concurrent;

View file

@ -285,7 +285,6 @@ namespace Server.Network
public static int MenuCap { get; set; } = 512;
public void WriteConsole(string text)
{
Console.WriteLine("Client: {0}: {1}", this, text);
@ -395,8 +394,8 @@ namespace Server.Network
public IAccount Account { get; set; }
public override string ToString() => m_ToString;
public NetState(ConnectionContext connection)
{
Connection = connection;
Seeded = false;

View file

@ -157,6 +157,8 @@ namespace Server.Network
Register(0xD7, 0, true, EncodedCommand);
Register(0xE1, 0, false, ClientType);
Register(0xEF, 21, false, LoginServerSeed);
Register(0xEC, 0, false, EquipMacro);
Register(0xED, 0, false, UnequipMacro);
Register(0xF4, 0, false, CrashReport);
Register(0xF8, 106, false, CreateCharacter70160);
Register(0xFB, 2, false, ShowPublicHouseContent);
@ -179,6 +181,9 @@ namespace Server.Network
RegisterExtended(0x1C, true, CastSpell);
RegisterExtended(0x24, false, UnhandledBF);
RegisterExtended(0x2C, true, BandageTarget);
RegisterExtended(0x2D, true, TargetedSpell);
RegisterExtended(0x2E, true, TargetedSkillUse);
RegisterExtended(0x30, true, TargetByResourceMacro);
RegisterExtended(0x32, true, ToggleFlying);
RegisterEncoded(0x19, true, SetAbility);
@ -289,6 +294,8 @@ namespace Server.Network
return -1;
}
Console.WriteLine("Processing Packet... {0:X}", packetId);
if (!ns.Seeded)
{
if (packetId == 0xEF)
@ -381,17 +388,17 @@ namespace Server.Network
public static void SetAbility(NetState state, IEntity e, EncodedReader reader)
{
EventSink.InvokeSetAbility(new SetAbilityEventArgs(state.Mobile, reader.ReadInt32()));
EventSink.InvokeSetAbility(state.Mobile, reader.ReadInt32());
}
public static void GuildGumpRequest(NetState state, IEntity e, EncodedReader reader)
{
EventSink.InvokeGuildGumpRequest(new GuildGumpRequestArgs(state.Mobile));
EventSink.InvokeGuildGumpRequest(state.Mobile);
}
public static void QuestGumpRequest(NetState state, IEntity e, EncodedReader reader)
{
EventSink.InvokeQuestGumpRequest(new QuestGumpRequestArgs(state.Mobile));
EventSink.InvokeQuestGumpRequest(state.Mobile);
}
public static void EncodedCommand(NetState state, PacketReader pvSrc)
@ -431,12 +438,12 @@ namespace Server.Network
Mobile targ = World.FindMobile(pvSrc.ReadUInt32());
if (targ != null)
EventSink.InvokeRenameRequest(new RenameRequestEventArgs(from, targ, pvSrc.ReadStringSafe()));
EventSink.InvokeRenameRequest(from, targ, pvSrc.ReadStringSafe());
}
public static void ChatRequest(NetState state, PacketReader pvSrc)
{
EventSink.InvokeChatRequest(new ChatRequestEventArgs(state.Mobile));
EventSink.InvokeChatRequest(state.Mobile);
}
public static void SecureTrade(NetState state, PacketReader pvSrc)
@ -591,7 +598,7 @@ namespace Server.Network
pvSrc.Seek(30, SeekOrigin.Current);
int index = pvSrc.ReadInt32();
EventSink.InvokeDeleteRequest(new DeleteRequestEventArgs(state, index));
EventSink.InvokeDeleteRequest(state, index);
}
public static void DeathStatusResponse(NetState state, PacketReader pvSrc)
@ -697,7 +704,7 @@ namespace Server.Network
{
case 0xC7: // Animate
{
EventSink.InvokeAnimateRequest(new AnimateRequestEventArgs(m, command));
EventSink.InvokeAnimateRequest(m, command);
break;
}
@ -715,7 +722,7 @@ namespace Server.Network
if (!int.TryParse(command, out int booktype))
booktype = 1;
EventSink.InvokeOpenSpellbookRequest(new OpenSpellbookRequestEventArgs(m, booktype));
EventSink.InvokeOpenSpellbookRequest(m, booktype);
break;
}
@ -728,14 +735,14 @@ namespace Server.Network
int spellID = Utility.ToInt32(split[0]) - 1;
uint serial = split.Length > 1 ? Utility.ToUInt32(split[1]) : (uint)Serial.MinusOne;
EventSink.InvokeCastSpellRequest(new CastSpellRequestEventArgs(m, spellID, World.FindItem(serial)));
EventSink.InvokeCastSpellRequest(m, spellID, World.FindItem(serial));
}
break;
}
case 0x58: // Open door
{
EventSink.InvokeOpenDoorMacroUsed(new OpenDoorMacroEventArgs(m));
EventSink.InvokeOpenDoorMacroUsed(m);
break;
}
@ -743,7 +750,7 @@ namespace Server.Network
{
int spellID = Utility.ToInt32(command) - 1;
EventSink.InvokeCastSpellRequest(new CastSpellRequestEventArgs(m, spellID, null));
EventSink.InvokeCastSpellRequest(m, spellID, null);
break;
}
@ -751,7 +758,7 @@ namespace Server.Network
{
int virtueID = Utility.ToInt32(command) - 1;
EventSink.InvokeVirtueMacroRequest(new VirtueMacroRequestEventArgs(m, virtueID));
EventSink.InvokeVirtueMacroRequest(m, virtueID);
break;
}
@ -863,7 +870,7 @@ namespace Server.Network
{
case 0x00: // display request
{
EventSink.InvokeProfileRequest(new ProfileRequestEventArgs(beholder, beheld));
EventSink.InvokeProfileRequest(beholder, beheld);
break;
}
@ -877,7 +884,7 @@ namespace Server.Network
string text = pvSrc.ReadUnicodeString(length);
EventSink.InvokeChangeProfileRequest(new ChangeProfileRequestEventArgs(beholder, beheld, text));
EventSink.InvokeChangeProfileRequest(beholder, beheld, text);
break;
}
@ -1011,7 +1018,7 @@ namespace Server.Network
public static void HelpRequest(NetState state, PacketReader pvSrc)
{
EventSink.InvokeHelpRequest(new HelpRequestEventArgs(state.Mobile));
EventSink.InvokeHelpRequest(state.Mobile);
}
public static void TargetResponse(NetState state, PacketReader pvSrc)
@ -1216,14 +1223,14 @@ namespace Server.Network
Mobile beheld = World.FindMobile(pvSrc.ReadUInt32());
if (beheld != null)
EventSink.InvokeVirtueGumpRequest(new VirtueGumpRequestEventArgs(state.Mobile, beheld));
EventSink.InvokeVirtueGumpRequest(state.Mobile, beheld);
}
else
{
Mobile beheld = World.FindMobile(serial);
if (beheld != null)
EventSink.InvokeVirtueItemRequest(new VirtueItemRequestEventArgs(state.Mobile, beheld, buttonID));
EventSink.InvokeVirtueItemRequest(state.Mobile, beheld, buttonID);
}
}
}
@ -1513,7 +1520,7 @@ namespace Server.Network
int spellID = pvSrc.ReadInt16() - 1;
EventSink.InvokeCastSpellRequest(new CastSpellRequestEventArgs(from, spellID, spellbook));
EventSink.InvokeCastSpellRequest(from, spellID, spellbook);
}
public static void BandageTarget(NetState state, PacketReader pvSrc)
@ -1535,7 +1542,7 @@ namespace Server.Network
if (target == null)
return;
EventSink.InvokeBandageTargetRequest(new BandageTargetRequestEventArgs(from, bandage, target));
EventSink.InvokeBandageTargetRequest(from, bandage, target);
from.NextActionTime = Core.TickCount + Mobile.ActionDelay;
}
@ -1691,12 +1698,12 @@ namespace Server.Network
public static void StunRequest(NetState state, PacketReader pvSrc)
{
EventSink.InvokeStunRequest(new StunRequestEventArgs(state.Mobile));
EventSink.InvokeStunRequest(state.Mobile);
}
public static void DisarmRequest(NetState state, PacketReader pvSrc)
{
EventSink.InvokeDisarmRequest(new DisarmRequestEventArgs(state.Mobile));
EventSink.InvokeDisarmRequest(state.Mobile);
}
public static void StatLockChange(NetState state, PacketReader pvSrc)
@ -1828,7 +1835,7 @@ namespace Server.Network
{
CV version = state.Version = new CV(pvSrc.ReadString());
EventSink.InvokeClientVersionReceived(new ClientVersionReceivedArgs(state, version));
EventSink.InvokeClientVersionReceived(state, version);
}
public static void ClientType(NetState state, PacketReader pvSrc)
@ -1838,7 +1845,7 @@ namespace Server.Network
int type = pvSrc.ReadUInt16();
CV version = state.Version = new CV(pvSrc.ReadString());
//EventSink.InvokeClientVersionReceived( new ClientVersionReceivedArgs( state, version ) );//todo
EventSink.InvokeClientVersionReceived(state, version);
}
public static void MobileQuery(NetState state, PacketReader pvSrc)
@ -2025,7 +2032,7 @@ namespace Server.Network
state.Send(SeasonChange.Instantiate(m.GetSeason(), true));
state.Send(new MapChange(m));
EventSink.InvokeLogin(new LoginEventArgs(m));
EventSink.InvokeLogin(m);
m.ClearFastwalkStack();
}
@ -2493,6 +2500,47 @@ namespace Server.Network
state.Dispose();
}
public static void EquipMacro(NetState ns, PacketReader pvSrc)
{
int count = pvSrc.ReadByte();
List<Serial> serialList = new List<Serial>(count);
for (int i = 0; i < count; ++i)
serialList.Add(pvSrc.ReadUInt32());
EventSink.InvokeEquipMacro(ns.Mobile, serialList);
}
public static void UnequipMacro(NetState ns, PacketReader pvSrc)
{
int count = pvSrc.ReadByte();
List<Layer> layers = new List<Layer>(count);
for (int i = 0; i < count; ++i)
layers.Add((Layer)pvSrc.ReadUInt16());
EventSink.InvokeUnequipMacro(ns.Mobile, layers);
}
public static void TargetedSpell(NetState ns, PacketReader pvSrc)
{
short spellId = (short)(pvSrc.ReadInt16() - 1); // zero based;
EventSink.InvokeTargetedSpell(ns.Mobile, World.FindEntity(pvSrc.ReadUInt32()), spellId);
}
public static void TargetedSkillUse(NetState ns, PacketReader pvSrc)
{
short skillId = pvSrc.ReadInt16();
EventSink.InvokeTargetedSkillUse(ns.Mobile, World.FindEntity(pvSrc.ReadUInt32()), skillId);
}
public static void TargetByResourceMacro(NetState ns, PacketReader pvSrc)
{
Serial serial = pvSrc.ReadUInt32();
if (serial.IsItem) EventSink.InvokeTargetByResourceMacro(ns.Mobile, World.FindItem(serial), pvSrc.ReadInt16());
}
private class LoginTimer : Timer
{
private readonly Mobile m_Mobile;

View file

@ -1,3 +1,24 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2019 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: ServerConnectionHandler.cs *
* Created: 2020/04/12 - Updated: 2020/04/12 *
* *
* 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.Buffers;
using System.IO.Pipelines;

View file

@ -1,7 +1,27 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2019 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: ServerStartup.cs *
* Created: 2020/04/12 - Updated: 2020/04/12 *
* *
* 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.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Server.Network;
namespace Server.Network
{

View file

@ -1,3 +1,24 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2019 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: TcpServer.cs *
* Created: 2020/04/12 - Updated: 2020/04/12 *
* *
* 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.Collections.Generic;
using System.Net;

View file

@ -49,11 +49,7 @@ namespace Server
{
PermitBackgroundWrite = permitBackgroundWrite;
Task.WaitAll(new Task[3] {
Task.Factory.StartNew(() => SaveMobiles()),
Task.Factory.StartNew(() => SaveItems()),
Task.Factory.StartNew(() => SaveGuilds())
});
Task.WaitAll(Task.Factory.StartNew(SaveMobiles), Task.Factory.StartNew(SaveItems), Task.Factory.StartNew(SaveGuilds));
if (permitBackgroundWrite && UseSequentialWriters
) //If we're permitted to write in the background, but we don't anyways, then notify.
@ -155,7 +151,10 @@ namespace Server
foreach (Item item in items.Values)
{
if (item.Decays && item.Parent == null && item.Map != Map.Internal && item.LastMoved + item.DecayTime <= n)
{
Console.WriteLine($"Decay Item {item.Name ?? item.DefaultName} ({item.GetType().FullName})");
_decayQueue.Enqueue(item);
}
long start = bin.Position;
@ -217,7 +216,8 @@ namespace Server
{
Item item = _decayQueue.Dequeue();
if (item.OnDecay()) item.Delete();
if (item.OnDecay())
item.Delete();
}
}
}

View file

@ -183,116 +183,7 @@ namespace Server
{
string filePath = Core.FindDataFile("tiledata.mul");
if (File.Exists(filePath))
{
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
BinaryReader bin = new BinaryReader(fs);
if (fs.Length == 3188736)
{
// 7.0.9.0
LandTable = new LandData[0x4000];
for (int i = 0; i < 0x4000; ++i)
{
if (i == 1 || i > 0 && (i & 0x1F) == 0) bin.ReadInt32(); // header
TileFlag flags = (TileFlag)bin.ReadInt64();
bin.ReadInt16(); // skip 2 bytes -- textureID
LandTable[i] = new LandData(ReadNameString(bin), flags);
}
ItemTable = new ItemData[0x10000];
for (int i = 0; i < 0x10000; ++i)
{
if ((i & 0x1F) == 0) bin.ReadInt32(); // header
TileFlag flags = (TileFlag)bin.ReadInt64();
int weight = bin.ReadByte();
int quality = bin.ReadByte();
bin.ReadInt16();
bin.ReadByte();
int quantity = bin.ReadByte();
bin.ReadInt32();
bin.ReadByte();
int value = bin.ReadByte();
int height = bin.ReadByte();
ItemTable[i] = new ItemData(ReadNameString(bin), flags, weight, quality, quantity, value,
height);
}
}
else
{
LandTable = new LandData[0x4000];
for (int i = 0; i < 0x4000; ++i)
{
if ((i & 0x1F) == 0) bin.ReadInt32(); // header
TileFlag flags = (TileFlag)bin.ReadInt32();
bin.ReadInt16(); // skip 2 bytes -- textureID
LandTable[i] = new LandData(ReadNameString(bin), flags);
}
if (fs.Length == 1644544)
{
// 7.0.0.0
ItemTable = new ItemData[0x8000];
for (int i = 0; i < 0x8000; ++i)
{
if ((i & 0x1F) == 0) bin.ReadInt32(); // header
TileFlag flags = (TileFlag)bin.ReadInt32();
int weight = bin.ReadByte();
int quality = bin.ReadByte();
bin.ReadInt16();
bin.ReadByte();
int quantity = bin.ReadByte();
bin.ReadInt32();
bin.ReadByte();
int value = bin.ReadByte();
int height = bin.ReadByte();
ItemTable[i] = new ItemData(ReadNameString(bin), flags, weight, quality, quantity, value,
height);
}
}
else
{
ItemTable = new ItemData[0x4000];
for (int i = 0; i < 0x4000; ++i)
{
if ((i & 0x1F) == 0) bin.ReadInt32(); // header
TileFlag flags = (TileFlag)bin.ReadInt32();
int weight = bin.ReadByte();
int quality = bin.ReadByte();
bin.ReadInt16();
bin.ReadByte();
int quantity = bin.ReadByte();
bin.ReadInt32();
bin.ReadByte();
int value = bin.ReadByte();
int height = bin.ReadByte();
ItemTable[i] = new ItemData(ReadNameString(bin), flags, weight, quality, quantity, value,
height);
}
}
}
}
MaxLandValue = LandTable.Length - 1;
MaxItemValue = ItemTable.Length - 1;
}
else
if (!File.Exists(filePath))
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("tiledata.mul was not found");
@ -302,6 +193,111 @@ namespace Server
throw new Exception($"TileData: {filePath} not found");
}
using FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
BinaryReader bin = new BinaryReader(fs);
if (fs.Length == 3188736)
{
// 7.0.9.0
LandTable = new LandData[0x4000];
for (int i = 0; i < 0x4000; ++i)
{
if (i == 1 || i > 0 && (i & 0x1F) == 0) bin.ReadInt32(); // header
TileFlag flags = (TileFlag)bin.ReadInt64();
bin.ReadInt16(); // skip 2 bytes -- textureID
LandTable[i] = new LandData(ReadNameString(bin), flags);
}
ItemTable = new ItemData[0x10000];
for (int i = 0; i < 0x10000; ++i)
{
if ((i & 0x1F) == 0) bin.ReadInt32(); // header
TileFlag flags = (TileFlag)bin.ReadInt64();
int weight = bin.ReadByte();
int quality = bin.ReadByte();
bin.ReadInt16();
bin.ReadByte();
int quantity = bin.ReadByte();
bin.ReadInt32();
bin.ReadByte();
int value = bin.ReadByte();
int height = bin.ReadByte();
ItemTable[i] = new ItemData(ReadNameString(bin), flags, weight, quality, quantity, value,
height);
}
}
else
{
LandTable = new LandData[0x4000];
for (int i = 0; i < 0x4000; ++i)
{
if ((i & 0x1F) == 0) bin.ReadInt32(); // header
TileFlag flags = (TileFlag)bin.ReadInt32();
bin.ReadInt16(); // skip 2 bytes -- textureID
LandTable[i] = new LandData(ReadNameString(bin), flags);
}
if (fs.Length == 1644544)
{
// 7.0.0.0
ItemTable = new ItemData[0x8000];
for (int i = 0; i < 0x8000; ++i)
{
if ((i & 0x1F) == 0) bin.ReadInt32(); // header
TileFlag flags = (TileFlag)bin.ReadInt32();
int weight = bin.ReadByte();
int quality = bin.ReadByte();
bin.ReadInt16();
bin.ReadByte();
int quantity = bin.ReadByte();
bin.ReadInt32();
bin.ReadByte();
int value = bin.ReadByte();
int height = bin.ReadByte();
ItemTable[i] = new ItemData(ReadNameString(bin), flags, weight, quality, quantity, value,
height);
}
}
else
{
ItemTable = new ItemData[0x4000];
for (int i = 0; i < 0x4000; ++i)
{
if ((i & 0x1F) == 0) bin.ReadInt32(); // header
TileFlag flags = (TileFlag)bin.ReadInt32();
int weight = bin.ReadByte();
int quality = bin.ReadByte();
bin.ReadInt16();
bin.ReadByte();
int quantity = bin.ReadByte();
bin.ReadInt32();
bin.ReadByte();
int value = bin.ReadByte();
int height = bin.ReadByte();
ItemTable[i] = new ItemData(ReadNameString(bin), flags, weight, quality, quantity, value,
height);
}
}
}
MaxLandValue = LandTable.Length - 1;
MaxItemValue = ItemTable.Length - 1;
}
public static LandData[] LandTable{ get; }

View file

@ -34,6 +34,14 @@ namespace Server
private readonly int m_FileIndex;
private readonly List<TileMatrix> m_FileShare = new List<TileMatrix>();
private readonly FileStream m_MapStream;
public FileStream IndexStream { get; }
public FileStream DataStream { get; }
private readonly BinaryReader m_IndexReader;
private readonly LandTile[] m_InvalidLandBlock;
private readonly int[][] m_LandPatches;
private readonly LandTile[][][] m_LandTiles;
@ -53,7 +61,6 @@ namespace Server
private StaticTile[] m_TileBuffer = new StaticTile[128];
private readonly TileList m_TilesList = new TileList();
// private int m_Width, m_Height;
public TileMatrix(Map owner, int fileIndex, int mapID, int width, int height)
{
@ -78,8 +85,6 @@ namespace Server
}
m_FileIndex = fileIndex;
// m_Width = width;
// m_Height = height;
BlockWidth = width >> 3;
BlockHeight = height >> 3;
@ -87,21 +92,19 @@ namespace Server
if (fileIndex != 0x7F)
{
string mapPath = Core.FindDataFile("map{0}.mul", fileIndex);
string mapPath = Core.FindDataFile("map{0}LegacyMUL.uop", fileIndex);
if (File.Exists(mapPath))
{
MapStream = new FileStream(mapPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
m_MapStream = new FileStream(mapPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
m_MapIndex = new UOPIndex(m_MapStream);
}
else
{
mapPath = Core.FindDataFile("map{0}LegacyMUL.uop", fileIndex);
mapPath = Core.FindDataFile("map{0}.mul", fileIndex);
if (File.Exists(mapPath))
{
MapStream = new FileStream(mapPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
m_MapIndex = new UOPIndex(MapStream);
}
m_MapStream = new FileStream(mapPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
}
string indexPath = Core.FindDataFile("staidx{0}.mul", fileIndex);
@ -109,7 +112,7 @@ namespace Server
if (File.Exists(indexPath))
{
IndexStream = new FileStream(indexPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
IndexReader = new BinaryReader(IndexStream);
m_IndexReader = new BinaryReader(IndexStream);
}
string staticsPath = Core.FindDataFile("statics{0}.mul", fileIndex);
@ -138,51 +141,12 @@ namespace Server
Patch = new TileMatrixPatch(this, mapID);
}
/*public Map Owner
{
get
{
return m_Owner;
}
}*/
public TileMatrixPatch Patch{ get; }
public int BlockWidth{ get; }
public int BlockHeight{ get; }
/*public int Width
{
get
{
return m_Width;
}
}
public int Height
{
get
{
return m_Height;
}
}*/
public FileStream MapStream{ get; set; }
/*public bool MapUOPPacked
{
get{ return ( m_MapIndex != null ); }
}*/
public FileStream IndexStream{ get; set; }
public FileStream DataStream{ get; set; }
public BinaryReader IndexReader{ get; set; }
public bool Exists => MapStream != null && IndexStream != null && DataStream != null;
public StaticTile[][][] EmptyStaticBlock{ get; }
[MethodImpl(MethodImplOptions.Synchronized)]
@ -292,7 +256,7 @@ namespace Server
[MethodImpl(MethodImplOptions.Synchronized)]
public LandTile[] GetLandBlock(int x, int y)
{
if (x < 0 || y < 0 || x >= BlockWidth || y >= BlockHeight || MapStream == null)
if (x < 0 || y < 0 || x >= BlockWidth || y >= BlockHeight || m_MapStream == null)
return m_InvalidLandBlock;
m_LandTiles[x] ??= new LandTile[BlockHeight][];
@ -339,10 +303,10 @@ namespace Server
{
try
{
IndexReader.BaseStream.Seek((x * BlockHeight + y) * 12, SeekOrigin.Begin);
m_IndexReader.BaseStream.Seek((x * BlockHeight + y) * 12, SeekOrigin.Begin);
int lookup = IndexReader.ReadInt32();
int length = IndexReader.ReadInt32();
int lookup = m_IndexReader.ReadInt32();
int length = m_IndexReader.ReadInt32();
if (lookup < 0 || length <= 0)
return EmptyStaticBlock;
@ -423,13 +387,13 @@ namespace Server
if (m_MapIndex != null)
offset = m_MapIndex.Lookup(offset);
MapStream.Seek(offset, SeekOrigin.Begin);
m_MapStream.Seek(offset, SeekOrigin.Begin);
LandTile[] tiles = new LandTile[64];
fixed (LandTile* pTiles = tiles)
{
NativeReader.Read(MapStream.SafeFileHandle.DangerousGetHandle(), pTiles, 192);
NativeReader.Read(m_MapStream.SafeFileHandle.DangerousGetHandle(), pTiles, 192);
}
return tiles;
@ -448,14 +412,10 @@ namespace Server
public void Dispose()
{
if (m_MapIndex != null)
m_MapIndex.Close();
else
MapStream?.Close();
m_MapIndex?.Close();
m_MapStream?.Close();
DataStream?.Close();
IndexReader?.Close();
m_IndexReader?.Close();
}
}
@ -670,16 +630,8 @@ namespace Server
{
public static readonly IComparer<UOPEntry> Instance = new OffsetComparer();
public int Compare(UOPEntry x, UOPEntry y)
{
if (x == null)
return y == null ? 0 : 1;
if (y == null)
return -1;
return x.m_Offset.CompareTo(y.m_Offset);
}
public int Compare(UOPEntry x, UOPEntry y) =>
x == null ? y == null ? 0 : 1 : y == null ? -1 : x.m_Offset.CompareTo(y.m_Offset);
}
}
}

View file

@ -19,8 +19,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
#nullable enable
using System;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;

View file

@ -645,7 +645,7 @@ namespace Server
try
{
EventSink.InvokeWorldSave(new WorldSaveEventArgs(message));
EventSink.InvokeWorldSave(message);
}
catch (Exception e)
{