Update Readers/Writers for Buffers & Fixes bugs (#283)

- [X] Renames PacketReader to CircularBufferReader
- [X] Fixes bugs with CircularBufferReader
- [X] Adds CircularBufferWriter
- [X] Adds SpanWriter
- [X] Adds SpanReader

Bumps release version
This commit is contained in:
Kamron Batman 2020-10-24 14:46:59 -07:00 committed by GitHub
parent 3b7f648c27
commit 6bd4f0d265
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 1302 additions and 351 deletions

View file

@ -2,9 +2,9 @@ namespace Server.Network
{
public ref struct EncodedReader
{
private PacketReader m_Reader;
private CircularBufferReader m_Reader;
public EncodedReader(PacketReader reader) => m_Reader = reader;
public EncodedReader(CircularBufferReader reader) => m_Reader = reader;
public void Trace(NetState state)
{

View file

@ -14,6 +14,7 @@
*************************************************************************/
using System;
using System.Buffers;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;

View file

@ -227,22 +227,22 @@ namespace Server.Network
m_CompiledLength = length;
}
if (length > 0)
if (m_CompiledLength > 0)
{
var old = m_CompiledBuffer;
if ((m_State & State.Static) != 0)
{
m_CompiledBuffer = new byte[length];
m_CompiledBuffer = new byte[m_CompiledLength];
}
else
{
// Release it later using Release()
m_CompiledBuffer = ArrayPool<byte>.Shared.Rent(length);
m_CompiledBuffer = ArrayPool<byte>.Shared.Rent(m_CompiledLength);
m_State |= State.Buffered;
}
Buffer.BlockCopy(old, 0, m_CompiledBuffer, 0, length);
Buffer.BlockCopy(old, 0, m_CompiledBuffer, 0, m_CompiledLength);
if (compress)
{

View file

@ -2,7 +2,7 @@ using System;
namespace Server.Network
{
public delegate void OnPacketReceive(NetState state, PacketReader reader);
public delegate void OnPacketReceive(NetState state, CircularBufferReader reader);
public delegate TimeSpan ThrottlePacketCallback(NetState state);

View file

@ -283,7 +283,7 @@ namespace Server.Network
public static int ProcessPacket(NetState ns, ArraySegment<byte>[] segments)
{
var reader = new PacketReader(segments);
var reader = new CircularBufferReader(segments);
var packetId = reader.ReadByte();
@ -360,11 +360,11 @@ namespace Server.Network
return packetLength;
}
private static void UnhandledBF(NetState state, PacketReader reader)
private static void UnhandledBF(NetState state, CircularBufferReader reader)
{
}
public static void Empty(NetState state, PacketReader reader)
public static void Empty(NetState state, CircularBufferReader reader)
{
}
@ -383,7 +383,7 @@ namespace Server.Network
EventSink.InvokeQuestGumpRequest(state.Mobile);
}
public static void EncodedCommand(NetState state, PacketReader reader)
public static void EncodedCommand(NetState state, CircularBufferReader reader)
{
var e = World.FindEntity(reader.ReadUInt32());
int packetId = reader.ReadUInt16();
@ -415,7 +415,7 @@ namespace Server.Network
}
}
public static void RenameRequest(NetState state, PacketReader reader)
public static void RenameRequest(NetState state, CircularBufferReader reader)
{
var from = state.Mobile;
var targ = World.FindMobile(reader.ReadUInt32());
@ -426,7 +426,7 @@ namespace Server.Network
}
}
public static void SecureTrade(NetState state, PacketReader reader)
public static void SecureTrade(NetState state, CircularBufferReader reader)
{
switch (reader.ReadByte())
{
@ -498,7 +498,7 @@ namespace Server.Network
}
}
public static void VendorBuyReply(NetState state, PacketReader reader)
public static void VendorBuyReply(NetState state, CircularBufferReader reader)
{
var vendor = World.FindMobile(reader.ReadUInt32());
var flag = reader.ReadByte();
@ -545,7 +545,7 @@ namespace Server.Network
}
}
public static void VendorSellReply(NetState state, PacketReader reader)
public static void VendorSellReply(NetState state, CircularBufferReader reader)
{
Serial serial = reader.ReadUInt32();
var vendor = World.FindMobile(serial);
@ -587,7 +587,7 @@ namespace Server.Network
}
}
public static void DeleteCharacter(NetState state, PacketReader reader)
public static void DeleteCharacter(NetState state, CircularBufferReader reader)
{
reader.Seek(30, SeekOrigin.Current);
var index = reader.ReadInt32();
@ -595,12 +595,12 @@ namespace Server.Network
EventSink.InvokeDeleteRequest(state, index);
}
public static void DeathStatusResponse(NetState state, PacketReader reader)
public static void DeathStatusResponse(NetState state, CircularBufferReader reader)
{
// Ignored
}
public static void ObjectHelpRequest(NetState state, PacketReader reader)
public static void ObjectHelpRequest(NetState state, CircularBufferReader reader)
{
var from = state.Mobile;
@ -629,7 +629,7 @@ namespace Server.Network
}
}
public static void MobileNameRequest(NetState state, PacketReader reader)
public static void MobileNameRequest(NetState state, CircularBufferReader reader)
{
var m = World.FindMobile(reader.ReadUInt32());
@ -639,13 +639,13 @@ namespace Server.Network
}
}
public static void RequestScrollWindow(NetState state, PacketReader reader)
public static void RequestScrollWindow(NetState state, CircularBufferReader reader)
{
int lastTip = reader.ReadInt16();
int type = reader.ReadByte();
}
public static void AttackReq(NetState state, PacketReader reader)
public static void AttackReq(NetState state, CircularBufferReader reader)
{
var from = state.Mobile;
var m = World.FindMobile(reader.ReadUInt32());
@ -656,7 +656,7 @@ namespace Server.Network
}
}
public static void HuePickerResponse(NetState state, PacketReader reader)
public static void HuePickerResponse(NetState state, CircularBufferReader reader)
{
var serial = reader.ReadUInt32();
_ = reader.ReadInt16(); // Item ID
@ -677,7 +677,7 @@ namespace Server.Network
}
}
public static void SystemInfo(NetState state, PacketReader reader)
public static void SystemInfo(NetState state, CircularBufferReader reader)
{
int v1 = reader.ReadByte();
int v2 = reader.ReadUInt16();
@ -693,11 +693,11 @@ namespace Server.Network
var v8 = reader.ReadInt32();
}
public static void AccountID(NetState state, PacketReader reader)
public static void AccountID(NetState state, CircularBufferReader reader)
{
}
public static void TextCommand(NetState state, PacketReader reader)
public static void TextCommand(NetState state, CircularBufferReader reader)
{
int type = reader.ReadByte();
var command = reader.ReadAscii();
@ -790,7 +790,7 @@ namespace Server.Network
}
}
public static void AsciiPromptResponse(NetState state, PacketReader reader)
public static void AsciiPromptResponse(NetState state, CircularBufferReader reader)
{
var serial = reader.ReadUInt32();
var prompt = reader.ReadInt32();
@ -820,7 +820,7 @@ namespace Server.Network
}
}
public static void UnicodePromptResponse(NetState state, PacketReader reader)
public static void UnicodePromptResponse(NetState state, CircularBufferReader reader)
{
var serial = reader.ReadUInt32();
var prompt = reader.ReadInt32();
@ -851,7 +851,7 @@ namespace Server.Network
}
}
public static void MenuResponse(NetState state, PacketReader reader)
public static void MenuResponse(NetState state, CircularBufferReader reader)
{
var serial = reader.ReadUInt32();
int menuID = reader.ReadInt16(); // unused in our implementation
@ -881,7 +881,7 @@ namespace Server.Network
}
}
public static void ProfileReq(NetState state, PacketReader reader)
public static void ProfileReq(NetState state, CircularBufferReader reader)
{
int type = reader.ReadByte();
Serial serial = reader.ReadUInt32();
@ -921,12 +921,12 @@ namespace Server.Network
}
}
public static void Disconnect(NetState state, PacketReader reader)
public static void Disconnect(NetState state, CircularBufferReader reader)
{
var minusOne = reader.ReadInt32();
}
public static void LiftReq(NetState state, PacketReader reader)
public static void LiftReq(NetState state, CircularBufferReader reader)
{
Serial serial = reader.ReadUInt32();
int amount = reader.ReadUInt16();
@ -935,7 +935,7 @@ namespace Server.Network
state.Mobile.Lift(item, amount, out var rejected, out var reject);
}
public static void EquipReq(NetState state, PacketReader reader)
public static void EquipReq(NetState state, CircularBufferReader reader)
{
var from = state.Mobile;
var item = from.Holding;
@ -960,7 +960,7 @@ namespace Server.Network
item.ClearBounce();
}
public static void DropReq(NetState state, PacketReader reader)
public static void DropReq(NetState state, CircularBufferReader reader)
{
reader.ReadInt32(); // serial, ignored
int x = reader.ReadInt16();
@ -997,7 +997,7 @@ namespace Server.Network
}
}
public static void DropReq6017(NetState state, PacketReader reader)
public static void DropReq6017(NetState state, CircularBufferReader reader)
{
reader.ReadInt32(); // serial, ignored
int x = reader.ReadInt16();
@ -1035,28 +1035,28 @@ namespace Server.Network
}
}
public static void ConfigurationFile(NetState state, PacketReader reader)
public static void ConfigurationFile(NetState state, CircularBufferReader reader)
{
}
public static void LogoutReq(NetState state, PacketReader reader)
public static void LogoutReq(NetState state, CircularBufferReader reader)
{
state.Send(new LogoutAck());
}
public static void ChangeSkillLock(NetState state, PacketReader reader)
public static void ChangeSkillLock(NetState state, CircularBufferReader reader)
{
var s = state.Mobile.Skills[reader.ReadInt16()];
s?.SetLockNoRelay((SkillLock)reader.ReadByte());
}
public static void HelpRequest(NetState state, PacketReader reader)
public static void HelpRequest(NetState state, CircularBufferReader reader)
{
EventSink.InvokeHelpRequest(state.Mobile);
}
public static void TargetResponse(NetState state, PacketReader reader)
public static void TargetResponse(NetState state, CircularBufferReader reader)
{
int type = reader.ReadByte();
var targetID = reader.ReadInt32();
@ -1170,7 +1170,7 @@ namespace Server.Network
}
}
public static void DisplayGumpResponse(NetState state, PacketReader reader)
public static void DisplayGumpResponse(NetState state, CircularBufferReader reader)
{
var serial = reader.ReadUInt32();
var typeID = reader.ReadInt32();
@ -1292,12 +1292,12 @@ namespace Server.Network
}
}
public static void SetWarMode(NetState state, PacketReader reader)
public static void SetWarMode(NetState state, CircularBufferReader reader)
{
state.Mobile.DelayChangeWarmode(reader.ReadBoolean());
}
public static void Resynchronize(NetState state, PacketReader reader)
public static void Resynchronize(NetState state, CircularBufferReader reader)
{
var m = state.Mobile;
@ -1319,7 +1319,7 @@ namespace Server.Network
m.ClearFastwalkStack();
}
public static void AsciiSpeech(NetState state, PacketReader reader)
public static void AsciiSpeech(NetState state, CircularBufferReader reader)
{
var from = state.Mobile;
@ -1341,7 +1341,7 @@ namespace Server.Network
from.DoSpeech(text, m_EmptyInts, type, Utility.ClipDyedHue(hue));
}
public static void UnicodeSpeech(NetState state, PacketReader reader)
public static void UnicodeSpeech(NetState state, CircularBufferReader reader)
{
var from = state.Mobile;
@ -1420,7 +1420,7 @@ namespace Server.Network
from.DoSpeech(text, keywords, type, Utility.ClipDyedHue(hue));
}
public static void UseReq(NetState state, PacketReader reader)
public static void UseReq(NetState state, CircularBufferReader reader)
{
var from = state.Mobile;
@ -1464,7 +1464,7 @@ namespace Server.Network
}
}
public static void LookReq(NetState state, PacketReader reader)
public static void LookReq(NetState state, CircularBufferReader reader)
{
var from = state.Mobile;
@ -1513,17 +1513,17 @@ namespace Server.Network
}
}
public static void PingReq(NetState state, PacketReader reader)
public static void PingReq(NetState state, CircularBufferReader reader)
{
state.Send(PingAck.Instantiate(reader.ReadByte()));
}
public static void SetUpdateRange(NetState state, PacketReader reader)
public static void SetUpdateRange(NetState state, CircularBufferReader reader)
{
state.Send(ChangeUpdateRange.Instantiate(18));
}
public static void MovementReq(NetState state, PacketReader reader)
public static void MovementReq(NetState state, CircularBufferReader reader)
{
var dir = (Direction)reader.ReadByte();
int seq = reader.ReadByte();
@ -1551,7 +1551,7 @@ namespace Server.Network
}
}
public static void Animate(NetState state, PacketReader reader)
public static void Animate(NetState state, CircularBufferReader reader)
{
var from = state.Mobile;
var action = reader.ReadInt32();
@ -1569,7 +1569,7 @@ namespace Server.Network
}
}
public static void QuestArrow(NetState state, PacketReader reader)
public static void QuestArrow(NetState state, CircularBufferReader reader)
{
var rightClick = reader.ReadBoolean();
var from = state.Mobile;
@ -1577,7 +1577,7 @@ namespace Server.Network
from?.QuestArrow?.OnClick(rightClick);
}
public static void ExtendedCommand(NetState state, PacketReader reader)
public static void ExtendedCommand(NetState state, CircularBufferReader reader)
{
int packetID = reader.ReadUInt16();
@ -1607,7 +1607,7 @@ namespace Server.Network
}
}
public static void CastSpell(NetState state, PacketReader reader)
public static void CastSpell(NetState state, CircularBufferReader reader)
{
var from = state.Mobile;
@ -1628,7 +1628,7 @@ namespace Server.Network
EventSink.InvokeCastSpellRequest(from, spellID, spellbook);
}
public static void BandageTarget(NetState state, PacketReader reader)
public static void BandageTarget(NetState state, CircularBufferReader reader)
{
var from = state.Mobile;
@ -1663,12 +1663,12 @@ namespace Server.Network
}
}
public static void ToggleFlying(NetState state, PacketReader reader)
public static void ToggleFlying(NetState state, CircularBufferReader reader)
{
state.Mobile.ToggleFlying();
}
public static void BatchQueryProperties(NetState state, PacketReader reader)
public static void BatchQueryProperties(NetState state, CircularBufferReader reader)
{
if (!ObjectPropertyList.Enabled)
{
@ -1710,7 +1710,7 @@ namespace Server.Network
}
}
public static void QueryProperties(NetState state, PacketReader reader)
public static void QueryProperties(NetState state, CircularBufferReader reader)
{
if (!ObjectPropertyList.Enabled)
{
@ -1742,7 +1742,7 @@ namespace Server.Network
}
}
public static void PartyMessage(NetState state, PacketReader reader)
public static void PartyMessage(NetState state, CircularBufferReader reader)
{
if (state.Mobile == null)
{
@ -1778,17 +1778,17 @@ namespace Server.Network
}
}
public static void PartyMessage_AddMember(NetState state, PacketReader reader)
public static void PartyMessage_AddMember(NetState state, CircularBufferReader reader)
{
PartyCommands.Handler?.OnAdd(state.Mobile);
}
public static void PartyMessage_RemoveMember(NetState state, PacketReader reader)
public static void PartyMessage_RemoveMember(NetState state, CircularBufferReader reader)
{
PartyCommands.Handler?.OnRemove(state.Mobile, World.FindMobile(reader.ReadUInt32()));
}
public static void PartyMessage_PrivateMessage(NetState state, PacketReader reader)
public static void PartyMessage_PrivateMessage(NetState state, CircularBufferReader reader)
{
PartyCommands.Handler?.OnPrivateMessage(
state.Mobile,
@ -1797,37 +1797,37 @@ namespace Server.Network
);
}
public static void PartyMessage_PublicMessage(NetState state, PacketReader reader)
public static void PartyMessage_PublicMessage(NetState state, CircularBufferReader reader)
{
PartyCommands.Handler?.OnPublicMessage(state.Mobile, reader.ReadBigUniSafe());
}
public static void PartyMessage_SetCanLoot(NetState state, PacketReader reader)
public static void PartyMessage_SetCanLoot(NetState state, CircularBufferReader reader)
{
PartyCommands.Handler?.OnSetCanLoot(state.Mobile, reader.ReadBoolean());
}
public static void PartyMessage_Accept(NetState state, PacketReader reader)
public static void PartyMessage_Accept(NetState state, CircularBufferReader reader)
{
PartyCommands.Handler?.OnAccept(state.Mobile, World.FindMobile(reader.ReadUInt32()));
}
public static void PartyMessage_Decline(NetState state, PacketReader reader)
public static void PartyMessage_Decline(NetState state, CircularBufferReader reader)
{
PartyCommands.Handler?.OnDecline(state.Mobile, World.FindMobile(reader.ReadUInt32()));
}
public static void StunRequest(NetState state, PacketReader reader)
public static void StunRequest(NetState state, CircularBufferReader reader)
{
EventSink.InvokeStunRequest(state.Mobile);
}
public static void DisarmRequest(NetState state, PacketReader reader)
public static void DisarmRequest(NetState state, CircularBufferReader reader)
{
EventSink.InvokeDisarmRequest(state.Mobile);
}
public static void StatLockChange(NetState state, PacketReader reader)
public static void StatLockChange(NetState state, CircularBufferReader reader)
{
int stat = reader.ReadByte();
int lockValue = reader.ReadByte();
@ -1856,13 +1856,13 @@ namespace Server.Network
}
}
public static void ScreenSize(NetState state, PacketReader reader)
public static void ScreenSize(NetState state, CircularBufferReader reader)
{
var width = reader.ReadInt32();
var unk = reader.ReadInt32();
}
public static void ContextMenuResponse(NetState state, PacketReader reader)
public static void ContextMenuResponse(NetState state, CircularBufferReader reader)
{
var from = state.Mobile;
@ -1918,7 +1918,7 @@ namespace Server.Network
}
}
public static void ContextMenuRequest(NetState state, PacketReader reader)
public static void ContextMenuRequest(NetState state, CircularBufferReader reader)
{
var from = state.Mobile;
var target = World.FindEntity(reader.ReadUInt32());
@ -1962,12 +1962,12 @@ namespace Server.Network
}
}
public static void CloseStatus(NetState state, PacketReader reader)
public static void CloseStatus(NetState state, CircularBufferReader reader)
{
Serial serial = reader.ReadUInt32();
}
public static void Language(NetState state, PacketReader reader)
public static void Language(NetState state, CircularBufferReader reader)
{
var lang = reader.ReadAscii(4);
@ -1977,20 +1977,20 @@ namespace Server.Network
}
}
public static void AssistVersion(NetState state, PacketReader reader)
public static void AssistVersion(NetState state, CircularBufferReader reader)
{
var unk = reader.ReadInt32();
var av = reader.ReadAscii();
}
public static void ClientVersion(NetState state, PacketReader reader)
public static void ClientVersion(NetState state, CircularBufferReader reader)
{
var version = state.Version = new CV(reader.ReadAscii());
EventSink.InvokeClientVersionReceived(state, version);
}
public static void ClientType(NetState state, PacketReader reader)
public static void ClientType(NetState state, CircularBufferReader reader)
{
reader.ReadUInt16();
@ -2000,7 +2000,7 @@ namespace Server.Network
EventSink.InvokeClientVersionReceived(state, version);
}
public static void MobileQuery(NetState state, PacketReader reader)
public static void MobileQuery(NetState state, CircularBufferReader reader)
{
var from = state.Mobile;
@ -2031,7 +2031,7 @@ namespace Server.Network
}
}
public static void PlayCharacter(NetState state, PacketReader reader)
public static void PlayCharacter(NetState state, CircularBufferReader reader)
{
reader.ReadInt32(); // 0xEDEDEDED
@ -2093,7 +2093,7 @@ namespace Server.Network
}
}
public static void ShowPublicHouseContent(NetState state, PacketReader reader)
public static void ShowPublicHouseContent(NetState state, CircularBufferReader reader)
{
var showPublicHouseContent = reader.ReadBoolean();
}
@ -2201,7 +2201,7 @@ namespace Server.Network
m.ClearFastwalkStack();
}
public static void CreateCharacter(NetState state, PacketReader reader)
public static void CreateCharacter(NetState state, CircularBufferReader reader)
{
var unk1 = reader.ReadInt32();
var unk2 = reader.ReadInt32();
@ -2337,7 +2337,7 @@ namespace Server.Network
}
}
public static void CreateCharacter70160(NetState state, PacketReader reader)
public static void CreateCharacter70160(NetState state, CircularBufferReader reader)
{
var unk1 = reader.ReadInt32();
var unk2 = reader.ReadInt32();
@ -2499,7 +2499,7 @@ namespace Server.Network
return authID;
}
public static void GameLogin(NetState state, PacketReader reader)
public static void GameLogin(NetState state, CircularBufferReader reader)
{
if (state.SentFirstPacket)
{
@ -2567,7 +2567,7 @@ namespace Server.Network
}
}
public static void PlayServer(NetState state, PacketReader reader)
public static void PlayServer(NetState state, CircularBufferReader reader)
{
int index = reader.ReadInt16();
var info = state.ServerInfo;
@ -2588,7 +2588,7 @@ namespace Server.Network
}
}
public static void LoginServerSeed(NetState state, PacketReader reader)
public static void LoginServerSeed(NetState state, CircularBufferReader reader)
{
state.m_Seed = reader.ReadInt32();
state.Seeded = true;
@ -2608,7 +2608,7 @@ namespace Server.Network
state.Version = new ClientVersion(clientMaj, clientMin, clientRev, clientPat);
}
public static void CrashReport(NetState state, PacketReader reader)
public static void CrashReport(NetState state, CircularBufferReader reader)
{
var clientMaj = reader.ReadByte();
var clientMin = reader.ReadByte();
@ -2642,7 +2642,7 @@ namespace Server.Network
}
}
public static void AccountLogin(NetState state, PacketReader reader)
public static void AccountLogin(NetState state, CircularBufferReader reader)
{
if (state.SentFirstPacket)
{
@ -2696,7 +2696,7 @@ namespace Server.Network
state.Dispose();
}
public static void EquipMacro(NetState state, PacketReader reader)
public static void EquipMacro(NetState state, CircularBufferReader reader)
{
int count = reader.ReadByte();
var serialList = new List<Serial>(count);
@ -2708,7 +2708,7 @@ namespace Server.Network
EventSink.InvokeEquipMacro(state.Mobile, serialList);
}
public static void UnequipMacro(NetState state, PacketReader reader)
public static void UnequipMacro(NetState state, CircularBufferReader reader)
{
int count = reader.ReadByte();
var layers = new List<Layer>(count);
@ -2720,21 +2720,21 @@ namespace Server.Network
EventSink.InvokeUnequipMacro(state.Mobile, layers);
}
public static void TargetedSpell(NetState state, PacketReader reader)
public static void TargetedSpell(NetState state, CircularBufferReader reader)
{
var spellId = (short)(reader.ReadInt16() - 1); // zero based;
EventSink.InvokeTargetedSpell(state.Mobile, World.FindEntity(reader.ReadUInt32()), spellId);
}
public static void TargetedSkillUse(NetState state, PacketReader reader)
public static void TargetedSkillUse(NetState state, CircularBufferReader reader)
{
var skillId = reader.ReadInt16();
EventSink.InvokeTargetedSkillUse(state.Mobile, World.FindEntity(reader.ReadUInt32()), skillId);
}
public static void TargetByResourceMacro(NetState state, PacketReader reader)
public static void TargetByResourceMacro(NetState state, CircularBufferReader reader)
{
Serial serial = reader.ReadUInt32();

View file

@ -1,351 +0,0 @@
/*************************************************************************
* ModernUO *
* Copyright 2019-2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: PacketReader.cs *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
using System;
using System.Buffers.Binary;
using System.Data;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
namespace Server.Network
{
public ref struct PacketReader
{
public Span<byte> First;
public Span<byte> Second;
public int Length { get; }
public int Position { get; private set; }
public int Remaining => Length - Position;
public PacketReader(ArraySegment<byte>[] buffers)
{
First = buffers[0];
Second = buffers[1];
Position = 0;
Length = First.Length + Second.Length;
}
public PacketReader(Span<byte> first, Span<byte> second)
{
First = first;
Second = second;
Position = 0;
Length = first.Length + second.Length;
}
public void Trace(NetState state)
{
// We don't have data, so nothing to trace
if (First.Length == 0)
{
return;
}
try
{
using var sw = new StreamWriter("Packets.log", true);
sw.WriteLine("Client: {0}: Unhandled packet 0x{1:X2}", state, First[0]);
Utility.FormatBuffer(sw, First.ToArray(), new Memory<byte>(Second.ToArray()));
sw.WriteLine();
sw.WriteLine();
}
catch
{
// ignored
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public byte ReadByte()
{
if (Position < First.Length)
{
return First[Position++];
}
if (Position < Length)
{
return Second[Position++ - First.Length];
}
throw new OutOfMemoryException();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool ReadBoolean() => ReadByte() > 0;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public sbyte ReadSByte() => (sbyte)ReadByte();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public short ReadInt16()
{
short value;
if (Position < First.Length)
{
if (!BinaryPrimitives.TryReadInt16BigEndian(First.Slice(Position), out value))
{
// Not enough space. Split the spans
return (short)((ReadByte() >> 8) | ReadByte());
}
}
else if (!BinaryPrimitives.TryReadInt16BigEndian(Second.Slice(Position - First.Length), out value))
{
throw new OutOfMemoryException();
}
Position += 2;
return value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ushort ReadUInt16()
{
ushort value;
if (Position < First.Length)
{
if (!BinaryPrimitives.TryReadUInt16BigEndian(First.Slice(Position), out value))
{
// Not enough space. Split the spans
return (ushort)((ReadByte() >> 8) | ReadByte());
}
}
else if (!BinaryPrimitives.TryReadUInt16BigEndian(Second.Slice(Position - First.Length), out value))
{
throw new OutOfMemoryException();
}
Position += 2;
return value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int ReadInt32()
{
int value;
if (Position < First.Length)
{
if (!BinaryPrimitives.TryReadInt32BigEndian(First.Slice(Position), out value))
{
// Not enough space. Split the spans
return (ReadByte() >> 24) | (ReadByte() >> 16) | (ReadByte() >> 8) | ReadByte();
}
}
else if (!BinaryPrimitives.TryReadInt32BigEndian(Second.Slice(Position - First.Length), out value))
{
throw new OutOfMemoryException();
}
Position += 4;
return value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public uint ReadUInt32()
{
uint value;
if (Position < First.Length)
{
if (!BinaryPrimitives.TryReadUInt32BigEndian(First.Slice(Position), out value))
{
// Not enough space. Split the spans
return (uint)((ReadByte() >> 24) | (ReadByte() >> 16) | (ReadByte() >> 8) | ReadByte());
}
}
else if (!BinaryPrimitives.TryReadUInt32BigEndian(Second.Slice(Position - First.Length), out value))
{
throw new OutOfMemoryException();
}
Position += 4;
return value;
}
private static bool IsSafeChar(ushort c) => c >= 0x20 && c < 0xFFFE;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ReadString<T>(Encoding encoding, bool safeString = false, int fixedLength = -1) where T : struct, IEquatable<T>
{
int sizeT = Unsafe.SizeOf<T>();
if (sizeT > 2)
{
throw new InvalidConstraintException("ReadString only accepts byte, sbyte, char, short, and ushort as a constraint");
}
bool isFixedLength = fixedLength > -1;
var remaining = Remaining;
int size;
// Not fixed length
if (isFixedLength)
{
size = fixedLength * sizeT;
if (fixedLength > Remaining)
{
throw new OutOfMemoryException();
}
}
else
{
size = remaining - (remaining & (sizeT - 1));
}
Span<byte> span;
int index;
if (Position < First.Length)
{
// Find terminator
index = MemoryMarshal
.Cast<byte, T>(First.Slice(Position, Math.Min(size, First.Length)))
.IndexOf(default(T)) * sizeT;
if (index < 0)
{
remaining = size - First.Length;
// We don't have a terminator, but a fixed size to the end of the first span, so stop there
if (remaining <= 0)
{
index = First.Length;
}
else
{
index = MemoryMarshal
.Cast<byte, T>(Second.Slice(0, remaining))
.IndexOf(default(T)) * sizeT;
int secondLength = index < 0 ? remaining : index;
int length = First.Length + secondLength;
// Assume no strings should be too long for the stack
Span<byte> bytes = stackalloc byte[length];
First.Slice(Position).CopyTo(bytes);
Second.Slice(0, secondLength).CopyTo(bytes.Slice(First.Length));
Position += length;
return GetString(bytes, encoding, safeString);
}
}
span = First.Slice(Position, index);
}
else
{
span = Second.Slice( Position - First.Length, Math.Min(remaining, size));
index = MemoryMarshal.Cast<byte, T>(span).IndexOf(default(T)) * sizeT;
if (index >= 0)
{
span = span.Slice(0, index);
}
}
Position += isFixedLength ? size : index;
return GetString(span, encoding, safeString);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static string GetString(Span<byte> span, Encoding encoding, bool safeString = false)
{
string s = encoding.GetString(span);
if (!safeString)
{
return s;
}
ReadOnlySpan<char> chars = s.AsSpan();
StringBuilder stringBuilder = null;
for (int i = 0, last = 0; i < chars.Length; i++)
{
if (!IsSafeChar(chars[i]) || stringBuilder != null && i == chars.Length - 1)
{
(stringBuilder ??= new StringBuilder()).Append(chars.Slice(last, i - last));
last = i + 1; // Skip the unsafe char
}
}
return stringBuilder?.ToString() ?? s;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ReadLittleUniSafe(int fixedLength) => ReadString<char>(Utility.UnicodeLE, true, fixedLength);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ReadLittleUniSafe() => ReadString<char>(Utility.UnicodeLE, true);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ReadLittleUni(int fixedLength) => ReadString<char>(Utility.UnicodeLE, false, fixedLength);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ReadLittleUni() => ReadString<char>(Utility.UnicodeLE);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ReadBigUniSafe(int fixedLength) => ReadString<char>(Utility.Unicode, true, fixedLength);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ReadBigUniSafe() => ReadString<char>(Utility.Unicode, true);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ReadBigUni(int fixedLength) => ReadString<char>(Utility.Unicode, false, fixedLength);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ReadBigUni() => ReadString<char>(Utility.Unicode);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ReadUTF8Safe(int fixedLength) => ReadString<byte>(Utility.UTF8, true, fixedLength);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ReadUTF8Safe() => ReadString<byte>(Utility.UTF8, true);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ReadUTF8() => ReadString<byte>(Utility.UTF8);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ReadAsciiSafe(int fixedLength) => ReadString<byte>(Encoding.ASCII, true, fixedLength);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ReadAsciiSafe() => ReadString<byte>(Encoding.ASCII, true);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ReadAscii(int fixedLength) => ReadString<byte>(Encoding.ASCII, false, fixedLength);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ReadAscii() => ReadString<byte>(Encoding.ASCII);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int Seek(int offset, SeekOrigin origin) =>
Position = origin switch
{
SeekOrigin.Begin => offset,
SeekOrigin.End => Length - offset,
_ => Position + offset // Current
};
}
}

View file

@ -118,55 +118,55 @@ namespace Server.Network
return result;
}
public void Advance(uint bytes)
public void Advance(uint count)
{
var read = _pipe._readIdx;
var write = _pipe._writeIdx;
if (bytes == 0)
if (count == 0)
{
return;
}
if (bytes > _pipe.Size - 1)
if (count > _pipe.Size - 1)
{
throw new InvalidOperationException();
}
if (read <= write)
{
if (bytes > read + _pipe.Size - write - 1)
if (count > read + _pipe.Size - write - 1)
{
throw new InvalidOperationException();
}
var sz = Math.Min(bytes, _pipe.Size - write);
var sz = Math.Min(count, _pipe.Size - write);
write += sz;
if (write > _pipe.Size - 1)
{
write = 0;
}
bytes -= sz;
count -= sz;
if (bytes > 0)
if (count > 0)
{
if (bytes >= read)
if (count >= read)
{
throw new InvalidOperationException();
}
write = bytes;
write = count;
}
}
else
{
if (bytes > read - write - 1)
if (count > read - write - 1)
{
throw new InvalidOperationException();
}
write += bytes;
write += count;
}
// It's never valid to advance the write pointer to become equal to
@ -216,7 +216,7 @@ namespace Server.Network
internal PipeReader(Pipe<T> pipe) => _pipe = pipe;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public uint GetRemaining()
public uint GetAvailable()
{
var read = _pipe._readIdx;
var write = _pipe._writeIdx;
@ -260,39 +260,39 @@ namespace Server.Network
return this;
}
public void Advance(uint bytes)
public void Advance(uint count)
{
var read = _pipe._readIdx;
var write = _pipe._writeIdx;
if (read <= write)
{
if (bytes > write - read)
if (count > write - read)
{
throw new InvalidOperationException();
}
read += bytes;
read += count;
}
else
{
var sz = Math.Min(bytes, _pipe.Size - read);
var sz = Math.Min(count, _pipe.Size - read);
read += sz;
if (read > _pipe.Size - 1)
{
read = 0;
}
bytes -= sz;
count -= sz;
if (bytes > 0)
if (count > 0)
{
if (bytes > write)
if (count > write)
{
throw new InvalidOperationException();
}
read = bytes;
read = count;
}
}
@ -309,7 +309,7 @@ namespace Server.Network
{
get
{
if (GetRemaining() > 0)
if (GetAvailable() > 0)
{
return true;
}