- [X] Cleans up gump packets
- [X] Adds event loop task synchronization
- [X] Moves timer pause and cleans up the delay task timer class
- [X] Cleans up the conserve cpu
- [X] Renames variables to make them consistent with the new style
- [X] Removes process delta recursion checking.
- [X] Properly diposes net states. This fixes edge cases that may cause hanging connections to stay open longer than they should.
- [X] Fixes an issue with gump items not compiling properly
Users can now utilize `Timer.Pause()` since the code will be executed on the proper thread.
```cs
public void async void Talk()
{
_canTalk = false;
await Timer.Pause(Utility.RandomMinMax(5000, 8000)); // Talk after 5-8 seconds
DoTalk();
await Timer.Pause(Utility.RandomMinMax(12000, 25000)); // Reset ability to talk after 12-25 seconds
_canTalk = true;
}
```
168 lines
5.9 KiB
C#
168 lines
5.9 KiB
C#
/*************************************************************************
|
|
* ModernUO *
|
|
* Copyright (C) 2019-2021 - ModernUO Development Team *
|
|
* Email: hi@modernuo.com *
|
|
* File: IncomingPackets.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.Collections.Generic;
|
|
|
|
namespace Server.Network
|
|
{
|
|
public static class IncomingPackets
|
|
{
|
|
private static readonly PacketHandler[] m_6017Handlers = new PacketHandler[0x100];
|
|
|
|
private static readonly EncodedPacketHandler[] m_EncodedHandlersLow = new EncodedPacketHandler[0x100];
|
|
|
|
private static readonly Dictionary<int, EncodedPacketHandler> m_EncodedHandlersHigh =
|
|
new();
|
|
|
|
public static PacketHandler[] Handlers { get; } = new PacketHandler[0x100];
|
|
|
|
public static void Register(int packetID, int length, bool ingame, OnPacketReceive onReceive)
|
|
{
|
|
Handlers[packetID] = new PacketHandler(packetID, length, ingame, onReceive);
|
|
m_6017Handlers[packetID] ??= new PacketHandler(packetID, length, ingame, onReceive);
|
|
}
|
|
|
|
public static PacketHandler GetHandler(int packetID) => Handlers[packetID];
|
|
|
|
public static void RegisterEncoded(int packetID, bool ingame, OnEncodedPacketReceive onReceive)
|
|
{
|
|
if (packetID >= 0 && packetID < 0x100)
|
|
{
|
|
m_EncodedHandlersLow[packetID] = new EncodedPacketHandler(packetID, ingame, onReceive);
|
|
}
|
|
else
|
|
{
|
|
m_EncodedHandlersHigh[packetID] = new EncodedPacketHandler(packetID, ingame, onReceive);
|
|
}
|
|
}
|
|
|
|
public static EncodedPacketHandler GetEncodedHandler(int packetID)
|
|
{
|
|
if (packetID >= 0 && packetID < 0x100)
|
|
{
|
|
return m_EncodedHandlersLow[packetID];
|
|
}
|
|
|
|
m_EncodedHandlersHigh.TryGetValue(packetID, out var handler);
|
|
return handler;
|
|
}
|
|
|
|
public static void RemoveEncodedHandler(int packetID)
|
|
{
|
|
if (packetID >= 0 && packetID < 0x100)
|
|
{
|
|
m_EncodedHandlersLow[packetID] = null;
|
|
}
|
|
else
|
|
{
|
|
m_EncodedHandlersHigh.Remove(packetID);
|
|
}
|
|
}
|
|
|
|
public static void RegisterThrottler(int packetID, ThrottlePacketCallback t)
|
|
{
|
|
var ph = GetHandler(packetID);
|
|
|
|
if (ph != null)
|
|
{
|
|
ph.ThrottleCallback = t;
|
|
}
|
|
}
|
|
|
|
public static int ProcessPacket(this NetState ns, ArraySegment<byte>[] buffer)
|
|
{
|
|
var reader = new CircularBufferReader(buffer);
|
|
|
|
var packetId = reader.ReadByte();
|
|
|
|
if (!ns.Seeded)
|
|
{
|
|
if (packetId == 0xEF)
|
|
{
|
|
// new packet in client 6.0.5.0 replaces the traditional seed method with a seed packet
|
|
// 0xEF = 239 = multicast IP, so this should never appear in a normal seed. So this is backwards compatible with older clients.
|
|
ns.Seeded = true;
|
|
}
|
|
else
|
|
{
|
|
var seed = (packetId << 24) | (reader.ReadByte() << 16) | (reader.ReadByte() << 8) | reader.ReadByte();
|
|
|
|
if (seed == 0)
|
|
{
|
|
ns.WriteConsole("Invalid client detected, disconnecting");
|
|
return -1;
|
|
}
|
|
|
|
ns._seed = seed;
|
|
ns.Seeded = true;
|
|
|
|
return 4;
|
|
}
|
|
}
|
|
|
|
if (ns.CheckEncrypted(packetId))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
// Get Handlers
|
|
var handler = ns.GetHandler(packetId);
|
|
|
|
if (handler == null)
|
|
{
|
|
reader.Trace(ns);
|
|
return -1;
|
|
}
|
|
|
|
// We use this for failing fast where we already know the length, but may not read it entirely
|
|
var packetLength = handler.Length;
|
|
|
|
if (handler.Length <= 0 && reader.Length >= 3)
|
|
{
|
|
packetLength = reader.ReadUInt16();
|
|
if (packetLength < 3)
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
// Not enough data, let's wait for more to come in
|
|
if (reader.Length < packetLength)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (handler.Ingame && ns.Mobile?.Deleted != false)
|
|
{
|
|
ns.WriteConsole("Sent ingame packet (0x{1:X2}) without being attached to a valid mobile.", ns, packetId);
|
|
return -1;
|
|
}
|
|
|
|
var throttled = handler.ThrottleCallback?.Invoke(ns) ?? TimeSpan.Zero;
|
|
|
|
if (throttled > TimeSpan.Zero)
|
|
{
|
|
ns.ThrottledUntil = DateTime.UtcNow + throttled;
|
|
}
|
|
|
|
// The packet length is sent in as a ref to support situations where a smaller/larger packet is read.
|
|
// Example is DropReq to support 6.0.1.7+ where the packet is 1 byte larger
|
|
handler.OnReceive(ns, reader, ref packetLength);
|
|
|
|
return packetLength;
|
|
}
|
|
}
|
|
}
|