LibUv Networking (#65)

This commit is contained in:
Kamron Batman 2019-12-26 18:08:50 -08:00 committed by GitHub
parent ec6629fbe9
commit 5e2be2d7b6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
69 changed files with 5612 additions and 586 deletions

View file

@ -24,53 +24,54 @@ using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Libuv;
using Libuv.Internal;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Logging;
namespace Server.Network
{
public class Listener
{
private Socket m_Socket;
private IPEndPoint m_EndPoint;
private static readonly LibuvFunctions functions = new LibuvFunctions();
private readonly IPEndPoint m_EndPoint;
private LibuvConnectionListener m_Listener;
public Listener(IPEndPoint ipep)
{
#pragma warning disable IDE0068 // Use recommended dispose pattern
m_Socket = new Socket(ipep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
#pragma warning restore IDE0068 // Use recommended dispose pattern
m_Socket.LingerState.Enabled = false;
m_Socket.ExclusiveAddressUse = false;
m_EndPoint = ipep;
LibuvTransportContext transport = new LibuvTransportContext
{
Options = new LibuvTransportOptions(),
AppLifetime = new ApplicationLifetime(
LoggerFactory.Create(builder => { builder.AddConsole(); }).CreateLogger<ApplicationLifetime>()
),
Log = new LibuvTrace(LoggerFactory.Create(builder => { builder.AddConsole(); }).CreateLogger("network"))
};
m_Listener = new LibuvConnectionListener(functions, transport, ipep);
}
public virtual async Task Start(MessagePump pump)
{
try
{
m_Socket.Bind(m_EndPoint);
m_Socket.Listen(8);
await m_Listener.BindAsync();
}
catch (AddressInUseException)
{
Console.WriteLine("Listener Failed: {0}:{1} (In Use)", m_EndPoint.Address, m_EndPoint.Port);
m_Listener = null;
return;
}
catch (Exception e)
{
if (e is SocketException se)
{
if (se.ErrorCode == 10048)
{
// WSAEADDRINUSE
Console.WriteLine("Listener Failed: {0}:{1} (In Use)", m_EndPoint.Address, m_EndPoint.Port);
}
else if (se.ErrorCode == 10049)
{
// WSAEADDRNOTAVAIL
Console.WriteLine("Listener Failed: {0}:{1} (Unavailable)", m_EndPoint.Address, m_EndPoint.Port);
}
else
{
Console.WriteLine("Listener Exception:");
Console.WriteLine(e);
}
}
Console.WriteLine("Listener Exception:");
Console.WriteLine(e);
m_Socket = null;
m_Listener = null;
return;
}
@ -78,10 +79,10 @@ namespace Server.Network
while (true)
{
Socket s;
ConnectionContext context;
try
{
s = await m_Socket.AcceptAsync().ConfigureAwait(false);
context = await m_Listener.AcceptAsync();
}
catch (SocketException ex)
{
@ -89,16 +90,16 @@ namespace Server.Network
continue;
}
if (VerifySocket(s))
_ = new NetState(s, pump);
if (VerifySocket(context))
_ = new NetState(context, pump);
else
Release(s);
Release(context);
}
}
private void DisplayListener()
{
if (!(m_Socket.LocalEndPoint is IPEndPoint ipep))
if (!(m_Listener.EndPoint is IPEndPoint ipep))
return;
if (ipep.Address.Equals(IPAddress.Any) || ipep.Address.Equals(IPAddress.IPv6Any))
@ -113,16 +114,14 @@ namespace Server.Network
}
}
else
{
Console.WriteLine("Listening: {0}:{1}", ipep.Address, ipep.Port);
}
}
private bool VerifySocket(Socket socket)
private static bool VerifySocket(ConnectionContext context)
{
try
{
SocketConnectEventArgs args = new SocketConnectEventArgs(socket);
SocketConnectEventArgs args = new SocketConnectEventArgs(context);
EventSink.InvokeSocketConnect(args);
@ -131,44 +130,47 @@ namespace Server.Network
catch (Exception ex)
{
NetState.TraceException(ex);
return false;
}
}
private void Release(Socket socket)
private static void Release(ConnectionContext context)
{
try
{
socket.Shutdown(SocketShutdown.Both);
context.Abort(new ConnectionAbortedException("Failed socket verification."));
}
catch (SocketException ex)
catch (Exception ex)
{
NetState.TraceException(ex);
}
try
{
socket.Close();
// TODO: Is this needed?
context.DisposeAsync();
}
catch (SocketException ex)
{
NetState.TraceException(ex);
}
try
{
socket.Dispose();
}
catch (SocketException ex)
catch (Exception ex)
{
NetState.TraceException(ex);
}
}
public void Dispose()
public async Task Dispose()
{
Interlocked.Exchange(ref m_Socket, null)?.Close();
LibuvConnectionListener listener = Interlocked.Exchange(ref m_Listener, null);
if (listener != null)
try
{
await listener.UnbindAsync();
await listener.DisposeAsync();
}
catch (Exception ex)
{
Console.WriteLine("Listener: Failed to dispose.");
Console.WriteLine(ex);
}
GC.SuppressFinalize(this);
}
}

View file

@ -23,6 +23,8 @@ using System;
using System.Buffers;
using System.Collections.Concurrent;
using System.Net;
using System.Threading.Tasks;
using SignalR;
namespace Server.Network
{
@ -40,9 +42,9 @@ namespace Server.Network
listeners[Listeners.Length] = listener;
}
public void QueueWork(NetState ns, in ReadOnlySequence<byte> seq, OnPacketReceive onReceive)
public void QueueWork(NetState ns, IMemoryOwner<byte> memOwner, OnPacketReceive onReceive)
{
m_WorkQueue.Enqueue(new Work(ns, seq, onReceive));
m_WorkQueue.Enqueue(new Work(ns, memOwner, onReceive));
Core.Set();
}
@ -54,21 +56,22 @@ namespace Server.Network
if (!m_WorkQueue.TryDequeue(out Work work))
break;
work.OnReceive(work.State, new PacketReader(work.Sequence));
work.OnReceive(work.State, new PacketReader(new ReadOnlySequence<byte>(work.MemoryOwner.Memory)));
work.MemoryOwner.Dispose();
}
}
// TODO: Optimize this with a pool
private class Work
{
public NetState State;
public ReadOnlySequence<byte> Sequence;
public OnPacketReceive OnReceive;
public readonly NetState State;
// TODO: Force dispose?
public readonly IMemoryOwner<byte> MemoryOwner;
public readonly OnPacketReceive OnReceive;
public Work(NetState ns, in ReadOnlySequence<byte> seq, OnPacketReceive onReceive)
public Work(NetState ns, IMemoryOwner<byte> memOwner, OnPacketReceive onReceive)
{
State = ns;
Sequence = seq;
MemoryOwner = memOwner;
OnReceive = onReceive;
}
}

View file

@ -28,6 +28,7 @@ using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Connections;
using Server.Accounting;
using Server.Diagnostics;
using Server.Gumps;
@ -93,7 +94,6 @@ namespace Server.Network
{
private string m_ToString;
private ClientVersion m_Version;
private SendQueue<Packet> m_SendQueue = new SendQueue<Packet>();
public DateTime ConnectedOn { get; }
@ -266,11 +266,9 @@ namespace Server.Network
return newTrade.From.Container;
}
public bool Running { get; private set; }
public bool Seeded { get; set; }
public Socket Socket { get; private set; }
public ConnectionContext Connection { get; private set; }
public bool CompressionEnabled { get; set; }
@ -282,12 +280,16 @@ namespace Server.Network
public List<IMenu> Menus { get; private set; }
public PipeReader RecvPipe => Connection.Transport.Input;
public PipeWriter SendPipe => Connection.Transport.Output;
public static int GumpCap { get; set; } = 512;
public static int HuePickerCap { get; set; } = 512;
public static int MenuCap { get; set; } = 512;
public void WriteConsole(string text)
{
Console.WriteLine("Client: {0}: {1}", this, text);
@ -403,23 +405,24 @@ namespace Server.Network
public static List<NetState> Instances { get; } = new List<NetState>();
public NetState(Socket socket, MessagePump pump)
public void SetConnectionAlive() => m_NextCheckActivity = Core.TickCount + 60000;
public NetState(ConnectionContext connection, MessagePump pump)
{
Socket = socket;
Connection = connection;
Seeded = false;
Running = false;
Gumps = new List<Gump>();
HuePickers = new List<HuePicker>();
Menus = new List<IMenu>();
Trades = new List<SecureTrade>();
m_NextCheckActivity = Core.TickCount + 30000;
SetConnectionAlive();
Instances.Add(this);
try
{
Address = Utility.Intern(((IPEndPoint)Socket.RemoteEndPoint).Address);
Address = Utility.Intern(((IPEndPoint)Connection.RemoteEndPoint).Address);
m_ToString = Address.ToString();
}
catch (Exception ex)
@ -430,10 +433,11 @@ namespace Server.Network
}
ConnectedOn = DateTime.UtcNow;
_ = Start(pump);
Console.WriteLine("Client: {0}: Connected. [{1} Online]", this, Instances.Count);
_ = ProcessRecvs(pump);
CreatedCallback?.Invoke(this);
Console.WriteLine("Client: {0}: Connected. [{1} Online]", this, NetState.Instances.Count);
}
public static void Pause()
@ -448,13 +452,38 @@ namespace Server.Network
public virtual void Send(Packet p)
{
if (Socket == null || BlockAllPackets)
if (Connection == null || BlockAllPackets)
{
p.OnSend();
return;
}
m_SendQueue.Enqueue(p);
try
{
ReadOnlySpan<byte> buffer = p.Compile(CompressionEnabled, out int length);
if (buffer.Length <= 0 || length <= 0)
{
p.OnSend();
return;
}
buffer.Slice(0, length).CopyTo(SendPipe.GetSpan(length));
SendPipe.Advance(length);
SendPipe.FlushAsync().GetAwaiter().GetResult();
p.OnSend();
}
catch (SocketException ex)
{
Console.WriteLine(ex);
TraceException(ex);
Dispose();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
public bool CheckEncrypted(int packetID)
@ -470,121 +499,31 @@ namespace Server.Network
return false;
}
private Pipe m_RecvdPipe;
private async Task Start(MessagePump pump)
private async Task ProcessRecvs(MessagePump pump)
{
m_RecvdPipe = new Pipe();
Running = true;
await Task.WhenAll(ProcessSends(), ProcessRecvs(), HandlePackets(pump)).ConfigureAwait(false);
}
private async Task ProcessRecvs()
{
PipeWriter w = m_RecvdPipe.Writer;
while (true)
{
if (m_AsyncState.Paused)
{
await Timer.Pause(50).ConfigureAwait(false);
continue;
}
try
{
Memory<byte> memory = w.GetMemory();
int bytesRead = await Socket.ReceiveAsync(memory, SocketFlags.None).ConfigureAwait(false);
if (bytesRead == 0)
break;
Interlocked.Exchange(ref m_NextCheckActivity, Core.TickCount + 90000);
w.Advance(bytesRead);
FlushResult result = await w.FlushAsync().ConfigureAwait(false);
if (result.IsCompleted || result.IsCanceled)
break;
}
catch
{
break;
}
}
w.Complete();
Dispose();
}
private async Task ProcessSends()
{
while (true)
try
{
Packet p = await m_SendQueue?.DequeueAsync();
if (p == null)
break;
ReadOnlyMemory<byte> buffer = p.Compile(CompressionEnabled, out int length);
if (buffer.Length <= 0 || length <= 0)
{
p.OnSend();
return;
}
buffer = buffer.Slice(0, length);
PacketSendProfile prof = null;
if (Core.Profiling)
prof = PacketSendProfile.Acquire(p.GetType());
prof?.Start();
await Socket.SendAsync(buffer, SocketFlags.None).ConfigureAwait(false);
p.OnSend();
prof?.Finish(length);
}
catch (SocketException ex)
{
Console.WriteLine(ex);
TraceException(ex);
Dispose();
break;
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
private async Task HandlePackets(MessagePump pump)
{
PipeReader pr = m_RecvdPipe.Reader;
while (true)
{
ReadResult result = await pr.ReadAsync();
ReadResult result = await RecvPipe.ReadAsync();
ReadOnlySequence<byte> seq = result.Buffer;
if (seq.Length == 0)
if (seq.IsEmpty)
break;
long pos = PacketHandlers.ProcessPacket(pump, this, seq);
SetConnectionAlive();
int pos = PacketHandlers.ProcessPacket(pump, this, seq);
if (pos <= 0)
break;
pr.AdvanceTo(seq.GetPosition(pos, seq.Start));
RecvPipe.AdvanceTo(seq.Slice(0, pos).End);
if (result.IsCompleted || result.IsCanceled)
break;
}
pr.Complete();
RecvPipe.Complete();
Dispose();
}
public PacketHandler GetHandler(int packetID) =>
@ -595,7 +534,7 @@ namespace Server.Network
public void CheckAlive(long curTicks)
{
if (Socket == null || m_NextCheckActivity - curTicks >= 0)
if (Connection == null || m_NextCheckActivity - curTicks >= 0)
return;
Console.WriteLine("Client: {0}: Disconnecting due to inactivity...", this);
@ -637,21 +576,18 @@ namespace Server.Network
if (disposing == 1)
return;
Task.Run(async () =>
try
{
m_RecvdPipe.Reader.CancelPendingRead();
m_RecvdPipe.Reader.Complete();
await m_RecvdPipe.Writer.FlushAsync().ConfigureAwait(false);
m_RecvdPipe.Writer.Complete();
Connection.Abort();
Task.Run(Connection.DisposeAsync).Wait();
}
catch (Exception ex)
{
TraceException(ex);
}
try { Socket.Shutdown(SocketShutdown.Both); } catch (Exception ex) { TraceException(ex); }
try { Socket.Close(); } catch (Exception ex) { TraceException(ex); }
Socket = null;
m_RecvdPipe = null;
m_SendQueue = null;
m_Disposed.Enqueue(this);
});
Connection = null;
m_Disposed.Enqueue(this);
}
public static void Initialize()

View file

@ -28,7 +28,7 @@ namespace Server.Network
public class PacketHandler
{
public PacketHandler(int packetID, long length, bool ingame, OnPacketReceive onReceive)
public PacketHandler(int packetID, int length, bool ingame, OnPacketReceive onReceive)
{
PacketID = packetID;
Length = length;
@ -38,7 +38,7 @@ namespace Server.Network
public int PacketID{ get; }
public long Length{ get; }
public int Length{ get; }
public OnPacketReceive OnReceive{ get; }

View file

@ -109,43 +109,32 @@ namespace Server.Network
Register(0x01, 5, false, Disconnect);
Register(0x02, 7, true, MovementReq);
Register(0x03, 0, true, AsciiSpeech);
Register(0x04, 2, true, GodModeRequest);
Register(0x05, 5, true, AttackReq);
Register(0x06, 5, true, UseReq);
Register(0x07, 7, true, LiftReq);
Register(0x08, 14, true, DropReq);
Register(0x09, 5, true, LookReq);
Register(0x0A, 11, true, Edit);
Register(0x12, 0, true, TextCommand);
Register(0x13, 10, true, EquipReq);
Register(0x14, 6, true, ChangeZ);
Register(0x22, 3, true, Resynchronize);
Register(0x2C, 2, true, DeathStatusResponse);
Register(0x34, 10, true, MobileQuery);
Register(0x3A, 0, true, ChangeSkillLock);
Register(0x3B, 0, true, VendorBuyReply);
Register(0x47, 11, true, NewTerrain);
Register(0x48, 73, true, NewAnimData);
Register(0x58, 106, true, NewRegion);
Register(0x5D, 73, false, PlayCharacter);
Register(0x61, 9, true, DeleteStatic);
Register(0x6C, 19, true, TargetResponse);
Register(0x6F, 0, true, SecureTrade);
Register(0x72, 5, true, SetWarMode);
Register(0x73, 2, false, PingReq);
Register(0x75, 35, true, RenameRequest);
Register(0x79, 9, true, ResourceQuery);
Register(0x7E, 2, true, GodviewQuery);
Register(0x7D, 13, true, MenuResponse);
Register(0x80, 62, false, AccountLogin);
Register(0x83, 39, false, DeleteCharacter);
Register(0x91, 65, false, GameLogin);
Register(0x95, 9, true, HuePickerResponse);
Register(0x96, 0, true, GameCentralMoniter);
Register(0x98, 0, true, MobileNameRequest);
Register(0x9A, 0, true, AsciiPromptResponse);
Register(0x9B, 258, true, HelpRequest);
Register(0x9D, 51, true, GMSingle);
Register(0x9F, 0, true, VendorSellReply);
Register(0xA0, 3, false, PlayServer);
Register(0xA4, 149, false, SystemInfo);
@ -161,8 +150,6 @@ namespace Server.Network
Register(0xBF, 0, true, ExtendedCommand);
Register(0xC2, 0, true, UnicodePromptResponse);
Register(0xC8, 2, true, SetUpdateRange);
Register(0xC9, 6, true, TripTime);
Register(0xCA, 6, true, UTripTime);
Register(0xCF, 0, false, AccountLogin);
Register(0xD0, 0, true, ConfigurationFile);
Register(0xD1, 2, true, LogoutReq);
@ -172,6 +159,7 @@ namespace Server.Network
Register(0xEF, 21, false, LoginServerSeed);
Register(0xF4, 0, false, CrashReport);
Register(0xF8, 106, false, CreateCharacter70160);
Register(0xFB, 2, false, ShowPublicHouseContent);
Register6017(0x08, 15, true, DropReq6017);
@ -214,9 +202,7 @@ namespace Server.Network
public static void Register(int packetID, int length, bool ingame, OnPacketReceive onReceive)
{
Handlers[packetID] = new PacketHandler(packetID, length, ingame, onReceive);
if (m_6017Handlers[packetID] == null)
m_6017Handlers[packetID] = new PacketHandler(packetID, length, ingame, onReceive);
m_6017Handlers[packetID] ??= new PacketHandler(packetID, length, ingame, onReceive);
}
public static PacketHandler GetHandler(int packetID) => Handlers[packetID];
@ -291,7 +277,9 @@ namespace Server.Network
ph.ThrottleCallback = t;
}
public static long ProcessPacket(MessagePump pump, NetState ns, in ReadOnlySequence<byte> seq)
private static MemoryPool<byte> _memoryPool = SlabMemoryPoolFactory.Create();
public static int ProcessPacket(MessagePump pump, NetState ns, in ReadOnlySequence<byte> seq)
{
PacketReader r = new PacketReader(seq);
@ -342,7 +330,7 @@ namespace Server.Network
return -1;
}
long packetLength = handler.Length;
int packetLength = handler.Length;
if (handler.Length <= 0 && r.Length >= 3)
{
packetLength = r.ReadUInt16();
@ -373,16 +361,12 @@ namespace Server.Network
if (throttled > TimeSpan.Zero)
ns.ThrottledUntil = DateTime.UtcNow + throttled;
PacketReceiveProfile prof = null;
ReadOnlySequence<byte> packet = seq.Slice(r.Position);
IMemoryOwner<byte> memOwner = _memoryPool.Rent((int)packet.Length);
if (Core.Profiling)
prof = PacketReceiveProfile.Acquire(packetId);
packet.CopyTo(memOwner.Memory.Span);
prof?.Start();
pump.QueueWork(ns, seq.Slice(r.Position), handler.OnReceive);
prof?.Finish(packetLength);
pump.QueueWork(ns, memOwner, handler.OnReceive);
return packetLength;
}
@ -413,9 +397,9 @@ namespace Server.Network
public static void EncodedCommand(NetState state, PacketReader pvSrc)
{
IEntity e = World.FindEntity(pvSrc.ReadUInt32());
int packetID = pvSrc.ReadUInt16();
int packetId = pvSrc.ReadUInt16();
EncodedPacketHandler ph = GetEncodedHandler(packetID);
EncodedPacketHandler ph = GetEncodedHandler(packetId);
if (ph != null)
{
@ -423,7 +407,7 @@ namespace Server.Network
{
Console.WriteLine(
"Client: {0}: Sent ingame packet (0xD7x{1:X2}) before having been attached to a mobile", state,
packetID);
packetId);
state.Dispose();
}
else if (ph.Ingame && state.Mobile.Deleted)
@ -609,39 +593,6 @@ namespace Server.Network
EventSink.InvokeDeleteRequest(new DeleteRequestEventArgs(state, index));
}
public static void ResourceQuery(NetState state, PacketReader pvSrc)
{
if (VerifyGC(state))
{
}
}
public static void GameCentralMoniter(NetState state, PacketReader pvSrc)
{
if (VerifyGC(state))
{
int type = pvSrc.ReadByte();
int num1 = pvSrc.ReadInt32();
Console.WriteLine("God Client: {0}: Game central moniter", state);
Console.WriteLine(" - Type: {0}", type);
Console.WriteLine(" - Number: {0}", num1);
pvSrc.Trace(state);
}
}
public static void GodviewQuery(NetState state, PacketReader pvSrc)
{
if (VerifyGC(state)) Console.WriteLine("God Client: {0}: Godview query 0x{1:X}", state, pvSrc.ReadByte());
}
public static void GMSingle(NetState state, PacketReader pvSrc)
{
if (VerifyGC(state))
pvSrc.Trace(state);
}
public static void DeathStatusResponse(NetState state, PacketReader pvSrc)
{
// Ignored
@ -711,35 +662,7 @@ namespace Server.Network
huePicker.OnResponse(hue);
break;
}
}
public static void TripTime(NetState state, PacketReader pvSrc)
{
int unk1 = pvSrc.ReadByte();
int unk2 = pvSrc.ReadInt32();
state.Send(new TripTimeResponse(unk1));
}
public static void UTripTime(NetState state, PacketReader pvSrc)
{
int unk1 = pvSrc.ReadByte();
int unk2 = pvSrc.ReadInt32();
state.Send(new UTripTimeResponse(unk1));
}
public static void ChangeZ(NetState state, PacketReader pvSrc)
{
if (VerifyGC(state))
{
int x = pvSrc.ReadInt16();
int y = pvSrc.ReadInt16();
int z = pvSrc.ReadSByte();
Console.WriteLine("God Client: {0}: Change Z ({1}, {2}, {3})", state, x, y, z);
}
}
public static void SystemInfo(NetState state, PacketReader pvSrc)
@ -758,101 +681,10 @@ namespace Server.Network
int v8 = pvSrc.ReadInt32();
}
public static void Edit(NetState state, PacketReader pvSrc)
{
if (VerifyGC(state))
{
int type = pvSrc.ReadByte(); // 10 = static, 7 = npc, 4 = dynamic
int x = pvSrc.ReadInt16();
int y = pvSrc.ReadInt16();
int id = pvSrc.ReadInt16();
int z = pvSrc.ReadSByte();
int hue = pvSrc.ReadUInt16();
Console.WriteLine("God Client: {0}: Edit {6} ({1}, {2}, {3}) 0x{4:X} (0x{5:X})", state, x, y, z, id, hue,
type);
}
}
public static void DeleteStatic(NetState state, PacketReader pvSrc)
{
if (VerifyGC(state))
{
int x = pvSrc.ReadInt16();
int y = pvSrc.ReadInt16();
int z = pvSrc.ReadInt16();
int id = pvSrc.ReadUInt16();
Console.WriteLine("God Client: {0}: Delete Static ({1}, {2}, {3}) 0x{4:X}", state, x, y, z, id);
}
}
public static void NewAnimData(NetState state, PacketReader pvSrc)
{
if (VerifyGC(state))
{
Console.WriteLine("God Client: {0}: New tile animation", state);
pvSrc.Trace(state);
}
}
public static void NewTerrain(NetState state, PacketReader pvSrc)
{
if (VerifyGC(state))
{
int x = pvSrc.ReadInt16();
int y = pvSrc.ReadInt16();
int id = pvSrc.ReadUInt16();
int width = pvSrc.ReadInt16();
int height = pvSrc.ReadInt16();
Console.WriteLine("God Client: {0}: New Terrain ({1}, {2})+({3}, {4}) 0x{5:X4}", state, x, y, width, height,
id);
}
}
public static void NewRegion(NetState state, PacketReader pvSrc)
{
if (VerifyGC(state))
{
string name = pvSrc.ReadString(40);
int unk = pvSrc.ReadInt32();
int x = pvSrc.ReadInt16();
int y = pvSrc.ReadInt16();
int width = pvSrc.ReadInt16();
int height = pvSrc.ReadInt16();
int zStart = pvSrc.ReadInt16();
int zEnd = pvSrc.ReadInt16();
string desc = pvSrc.ReadString(40);
int soundFX = pvSrc.ReadInt16();
int music = pvSrc.ReadInt16();
int nightFX = pvSrc.ReadInt16();
int dungeon = pvSrc.ReadByte();
int light = pvSrc.ReadInt16();
Console.WriteLine("God Client: {0}: New Region '{1}' ('{2}')", state, name, desc);
}
}
public static void AccountID(NetState state, PacketReader pvSrc)
{
}
public static bool VerifyGC(NetState state)
{
if (state.Mobile == null || state.Mobile.AccessLevel <= AccessLevel.Counselor)
{
if (state.Running)
Console.WriteLine("Warning: {0}: Player using godclient, disconnecting", state);
state.Dispose();
return false;
}
return true;
}
public static void TextCommand(NetState state, PacketReader pvSrc)
{
int type = pvSrc.ReadByte();
@ -862,34 +694,6 @@ namespace Server.Network
switch (type)
{
case 0x00: // Go
{
if (VerifyGC(state))
try
{
string[] split = command.Split(' ');
int x = Utility.ToInt32(split[0]);
int y = Utility.ToInt32(split[1]);
int z;
if (split.Length >= 3)
z = Utility.ToInt32(split[2]);
else if (m.Map != null)
z = m.Map.GetAverageZ(x, y);
else
z = 0;
m.Location = new Point3D(x, y, z);
}
catch
{
// ignored
}
break;
}
case 0xC7: // Animate
{
EventSink.InvokeAnimateRequest(new AnimateRequestEventArgs(m, command));
@ -970,12 +774,6 @@ namespace Server.Network
}
}
public static void GodModeRequest(NetState state, PacketReader pvSrc)
{
if (VerifyGC(state))
state.Send(new GodModeReply(pvSrc.ReadBoolean()));
}
public static void AsciiPromptResponse(NetState state, PacketReader pvSrc)
{
uint serial = pvSrc.ReadUInt32();
@ -1550,9 +1348,7 @@ namespace Server.Network
uint value = pvSrc.ReadUInt32();
if ((value & ~0x7FFFFFFF) != 0)
{
from.OnPaperdollRequest();
}
else
{
Serial s = value;
@ -1576,9 +1372,7 @@ namespace Server.Network
from.NextActionTime = Core.TickCount + Mobile.ActionDelay;
}
else
{
from.SendActionMessage();
}
}
public static void LookReq(NetState state, PacketReader pvSrc)
@ -1594,9 +1388,7 @@ namespace Server.Network
if (m != null && from.CanSee(m) && Utility.InUpdateRange(from, m))
{
if (SingleClickProps)
{
m.OnAosSingleClick(from);
}
else
{
if (from.Region.OnSingleClick(from, m))
@ -1612,9 +1404,7 @@ namespace Server.Network
Utility.InUpdateRange(from.Location, item.GetWorldLocation()))
{
if (SingleClickProps)
{
item.OnAosSingleClick(from);
}
else if (from.Region.OnSingleClick(from, item))
{
if (item.Parent is Item item1)
@ -2062,13 +1852,6 @@ namespace Server.Network
if (m != null)
switch (type)
{
case 0x00: // Unknown, sent by godclient
{
if (VerifyGC(state))
Console.WriteLine("God Client: {0}: Query 0x{1:X2} on {2} '{3}'", state, type, m.Serial, m.Name);
break;
}
case 0x04: // Stats
{
m.OnStatsQuery(from);
@ -2094,44 +1877,10 @@ namespace Server.Network
string name = pvSrc.ReadString(30);
pvSrc.Seek(2, SeekOrigin.Current);
int flags = pvSrc.ReadInt32();
/* if (FeatureProtection.DisabledFeatures != 0 && ThirdPartyAuthCallback != null)
{
bool authOK = false;
ulong razorFeatures = ((ulong)pvSrc.ReadUInt32() << 32) | pvSrc.ReadUInt32();
if (razorFeatures == (ulong)FeatureProtection.DisabledFeatures)
{
bool doesNotMatch = false;
for (int i = 0; !doesNotMatch && i < m_ThirdPartyAuthKey.Length; i++)
doesNotMatch = pvSrc.ReadByte() != m_ThirdPartyAuthKey[i];
if (!doesNotMatch)
authOK = true;
}
else
{
pvSrc.Seek(16, SeekOrigin.Current);
}
ThirdPartyAuthCallback(state, authOK);
}*/
/* else
{*/
pvSrc.Seek(24, SeekOrigin.Current);
/* }*/
/* if (ThirdPartyHackedCallback != null)
{
pvSrc.Seek(-2, SeekOrigin.Current);
if (pvSrc.ReadUInt16() == 0xDEAD)
ThirdPartyHackedCallback(state, true);
}*/
if (!state.Running)
return;
pvSrc.Seek(24, SeekOrigin.Current);
int charSlot = pvSrc.ReadInt32();
int clientIP = pvSrc.ReadInt32();
@ -2181,6 +1930,11 @@ namespace Server.Network
}
}
public static void ShowPublicHouseContent(NetState state, PacketReader pvSrc)
{
bool showPublicHouseContent = pvSrc.ReadBoolean();
}
public static void DoLogin(NetState state, Mobile m)
{
state.Send(new LoginConfirm(m));
@ -2614,9 +2368,7 @@ namespace Server.Network
state.Send(new CharacterListOld(state.Account, state.CityInfo));
}
else
{
state.Dispose();
}
}
public static void PlayServer(NetState state, PacketReader pvSrc)
@ -2626,9 +2378,7 @@ namespace Server.Network
IAccount a = state.Account;
if (info == null || a == null || index < 0 || index >= info.Length)
{
state.Dispose();
}
else
{
ServerInfo si = info[index];

View file

@ -175,13 +175,13 @@ namespace Server.Network
return sb.ToString();
}
public bool IsSafeChar(int c) => c >= 0x20 && c < 0xFFFE;
private static bool IsSafeChar(int c) => c >= 0x20 && c < 0xFFFE;
public string ReadUTF8StringSafe(int fixedLength)
{
string s;
if (m_Reader.TryReadTo(out ReadOnlySpan<byte> span, (byte)'\0', true))
if (m_Reader.TryReadTo(out ReadOnlySpan<byte> span, (byte)'\0'))
s = Utility.UTF8.GetString(span.Length > fixedLength ? span.Slice(0, fixedLength) : span);
else
{
@ -203,7 +203,7 @@ namespace Server.Network
{
string s;
if (m_Reader.TryReadTo(out ReadOnlySpan<byte> span, (byte)'\0', true))
if (m_Reader.TryReadTo(out ReadOnlySpan<byte> span, (byte)'\0'))
s = Utility.UTF8.GetString(span);
else
{
@ -222,7 +222,7 @@ namespace Server.Network
public string ReadUTF8String() =>
Utility.UTF8.GetString(
m_Reader.TryReadTo(out ReadOnlySpan<byte> span, (byte)'\0', true) ? span :
m_Reader.TryReadTo(out ReadOnlySpan<byte> span, (byte)'\0') ? span :
m_Reader.Sequence.Slice(m_Reader.Position, m_Reader.Remaining).ToArray()
);

View file

@ -4142,14 +4142,6 @@ namespace Server.Network
}
}
public sealed class GodModeReply : Packet
{
public GodModeReply(bool reply) : base(0x2B, 2)
{
m_Stream.Write(reply);
}
}
public sealed class PlayServerAck : Packet
{
internal static int m_AuthID = -1;

View file

@ -1,22 +1,22 @@
/***************************************************************************
* SocketExtensions.cs
* -------------------
* begin : August 2, 2019
* copyright : (C) The ModernUO Team
* email : hi@modernuo.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: SocketExtensions.cs - Created: 2019/08/02 - Updated: 2019/12/24 *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
using System;
using System.Buffers;
@ -34,7 +34,7 @@ namespace Server.Network
public static ArraySegment<byte> GetArray(this ReadOnlyMemory<byte> memory)
{
if (MemoryMarshal.TryGetArray(memory, out var result))
if (MemoryMarshal.TryGetArray(memory, out ArraySegment<byte> result))
return result;
throw new InvalidOperationException("Buffer backed by array was expected");
@ -42,7 +42,7 @@ namespace Server.Network
public static ArraySegment<byte> GetArray(this ReadOnlySequence<byte> memory)
{
if (SequenceMarshal.TryGetArray(memory, out var result))
if (SequenceMarshal.TryGetArray(memory, out ArraySegment<byte> result))
return result;
throw new InvalidOperationException("Buffer backed by array was expected");

View file

@ -1,22 +1,23 @@
/***************************************************************************
* StaticPacketHandlers.cs
* -------------------
* begin : March 15, 2019
* copyright : (C) The ModernUO Team
* email : hi@modernuo.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: StaticPacketHandlers.cs *
* Created: 2019/03/15 - Updated: 2019/12/24 *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
using System.Collections.Concurrent;