149 lines
9.1 KiB
C#
149 lines
9.1 KiB
C#
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Linq.Expressions;
|
|
using TrueCraft.API.Networking;
|
|
using TrueCraft.Core.Networking.Packets;
|
|
|
|
namespace TrueCraft.Core.Networking
|
|
{
|
|
public class PacketReader : IPacketReader
|
|
{
|
|
public static readonly int Version = 14;
|
|
public int ProtocolVersion { get { return Version; } }
|
|
|
|
internal Func<IPacket>[] ClientboundPackets = new Func<IPacket>[0x100];
|
|
internal Func<IPacket>[] ServerboundPackets = new Func<IPacket>[0x100];
|
|
|
|
public ConcurrentDictionary<object, IPacketSegmentProcessor> Processors { get; private set; }
|
|
|
|
private static readonly byte[] EmptyBuffer = new byte[0];
|
|
|
|
public PacketReader()
|
|
{
|
|
Processors = new ConcurrentDictionary<object, IPacketSegmentProcessor>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Registers TrueCraft.Core implementations of all packets used by vanilla Minecraft.
|
|
/// </summary>
|
|
public void RegisterCorePackets()
|
|
{
|
|
RegisterPacketType<KeepAlivePacket>(); // 0x00
|
|
RegisterPacketType<LoginRequestPacket>(serverbound: true, clientbound: false); // 0x01
|
|
RegisterPacketType<LoginResponsePacket>(serverbound: false, clientbound: true); // 0x01
|
|
RegisterPacketType<HandshakePacket>(serverbound: true, clientbound: false); // 0x02
|
|
RegisterPacketType<HandshakeResponsePacket>(serverbound: false, clientbound: true); // 0x02
|
|
RegisterPacketType<ChatMessagePacket>(); // 0x03
|
|
RegisterPacketType<TimeUpdatePacket>(serverbound: false, clientbound: true); // 0x04
|
|
RegisterPacketType<EntityEquipmentPacket>(serverbound: false, clientbound: true); // 0x05 // NOTE: serverbound not confirmed
|
|
RegisterPacketType<SpawnPositionPacket>(serverbound: false, clientbound: true); // 0x06
|
|
RegisterPacketType<UseEntityPacket>(serverbound: true, clientbound: false); // 0x07
|
|
RegisterPacketType<UpdateHealthPacket>(serverbound: false, clientbound: true); // 0x08
|
|
RegisterPacketType<RespawnPacket>(); // 0x09
|
|
RegisterPacketType<PlayerGroundedPacket>(serverbound: true, clientbound: false); // 0x0A
|
|
RegisterPacketType<PlayerPositionPacket>(serverbound: true, clientbound: false); // 0x0B
|
|
RegisterPacketType<PlayerLookPacket>(serverbound: true, clientbound: false); // 0x0C
|
|
RegisterPacketType<PlayerPositionAndLookPacket>(serverbound: true, clientbound: false); // 0x0D
|
|
RegisterPacketType<SetPlayerPositionPacket>(serverbound: false, clientbound: true); // 0x0D
|
|
RegisterPacketType<PlayerDiggingPacket>(serverbound: true, clientbound: false); // 0x0E
|
|
RegisterPacketType<PlayerBlockPlacementPacket>(serverbound: true, clientbound: false); // 0x0F
|
|
RegisterPacketType<ChangeHeldItemPacket>(serverbound: true, clientbound: false); // 0x10
|
|
RegisterPacketType<UseBedPacket>(serverbound: false, clientbound: true); // 0x11
|
|
RegisterPacketType<AnimationPacket>(); // 0x12
|
|
RegisterPacketType<PlayerActionPacket>(serverbound: true, clientbound: false); // 0x13
|
|
RegisterPacketType<SpawnPlayerPacket>(serverbound: false, clientbound: true); // 0x14
|
|
RegisterPacketType<SpawnItemPacket>(serverbound: true, clientbound: true); // 0x15
|
|
RegisterPacketType<CollectItemPacket>(serverbound: false, clientbound: true); // 0x16
|
|
RegisterPacketType<SpawnGenericEntityPacket>(serverbound: false, clientbound: true); // 0x17
|
|
RegisterPacketType<SpawnMobPacket>(serverbound: false, clientbound: true); // 0x18
|
|
RegisterPacketType<SpawnPaintingPacket>(serverbound: false, clientbound: true); // 0x19
|
|
|
|
RegisterPacketType<EntityVelocityPacket>(serverbound: false, clientbound: true); // 0x1C
|
|
RegisterPacketType<DestroyEntityPacket>(serverbound: false, clientbound: true); // 0x1D
|
|
RegisterPacketType<UselessEntityPacket>(serverbound: false, clientbound: true); // 0x1E
|
|
RegisterPacketType<EntityRelativeMovePacket>(serverbound: false, clientbound: true); // 0x1F
|
|
RegisterPacketType<EntityLookPacket>(serverbound: false, clientbound: true); // 0x20
|
|
RegisterPacketType<EntityLookAndRelativeMovePacket>(serverbound: false, clientbound: true); // 0x21
|
|
RegisterPacketType<EntityTeleportPacket>(serverbound: false, clientbound: true); // 0x22
|
|
|
|
RegisterPacketType<EntityStatusPacket>(serverbound: false, clientbound: true); // 0x26
|
|
RegisterPacketType<AttachEntityPacket>(serverbound: false, clientbound: true); // 0x27
|
|
RegisterPacketType<EntityMetadataPacket>(serverbound: false, clientbound: true); // 0x28
|
|
|
|
RegisterPacketType<ChunkPreamblePacket>(serverbound: false, clientbound: true); // 0x32
|
|
RegisterPacketType<ChunkDataPacket>(serverbound: false, clientbound: true); // 0x33
|
|
RegisterPacketType<BulkBlockChangePacket>(serverbound: false, clientbound: true); // 0x34
|
|
RegisterPacketType<BlockChangePacket>(serverbound: false, clientbound: true); // 0x35
|
|
RegisterPacketType<BlockActionPacket>(serverbound: false, clientbound: true); // 0x36
|
|
|
|
RegisterPacketType<ExplosionPacket>(serverbound: false, clientbound: true); // 0x3C
|
|
RegisterPacketType<SoundEffectPacket>(serverbound: false, clientbound: true); // 0x3D
|
|
|
|
RegisterPacketType<EnvironmentStatePacket>(serverbound: false, clientbound: true); // 0x46
|
|
RegisterPacketType<LightningPacket>(serverbound: false, clientbound: true); // 0x47
|
|
|
|
RegisterPacketType<OpenWindowPacket>(serverbound: false, clientbound: true); // 0x64
|
|
RegisterPacketType<CloseWindowPacket>(); // 0x65
|
|
RegisterPacketType<ClickWindowPacket>(serverbound: true, clientbound: false); // 0x66
|
|
RegisterPacketType<SetSlotPacket>(serverbound: false, clientbound: true); // 0x67
|
|
RegisterPacketType<WindowItemsPacket>(serverbound: false, clientbound: true); // 0x68
|
|
RegisterPacketType<UpdateProgressPacket>(serverbound: false, clientbound: true); // 0x69
|
|
RegisterPacketType<TransactionStatusPacket>(serverbound: false, clientbound: true); // 0x6A
|
|
|
|
RegisterPacketType<UpdateSignPacket>(); // 0x82
|
|
RegisterPacketType<MapDataPacket>(serverbound: false, clientbound: true); // 0x83
|
|
|
|
RegisterPacketType<UpdateStatisticPacket>(serverbound: false, clientbound: true); // 0xC8
|
|
|
|
RegisterPacketType<DisconnectPacket>(); // 0xFF
|
|
}
|
|
|
|
public void RegisterPacketType<T>(bool clientbound = true, bool serverbound = true) where T : IPacket
|
|
{
|
|
var func = Expression.Lambda<Func<IPacket>>(Expression.Convert(Expression.New(typeof(T)), typeof(IPacket))).Compile();
|
|
var packet = func();
|
|
|
|
if (clientbound)
|
|
ClientboundPackets[packet.ID] = func;
|
|
if (serverbound)
|
|
ServerboundPackets[packet.ID] = func;
|
|
}
|
|
|
|
public IEnumerable<IPacket> ReadPackets(object key, byte[] buffer, int offset, int length, bool serverbound = true)
|
|
{
|
|
if (!Processors.ContainsKey(key))
|
|
Processors[key] = new PacketSegmentProcessor(this, serverbound);
|
|
|
|
IPacketSegmentProcessor processor = Processors[key];
|
|
|
|
IPacket packet;
|
|
processor.ProcessNextSegment(buffer, offset, length, out packet);
|
|
|
|
if (packet == null)
|
|
yield break;
|
|
|
|
while (true)
|
|
{
|
|
yield return packet;
|
|
|
|
if (!processor.ProcessNextSegment(EmptyBuffer, 0, 0, out packet))
|
|
{
|
|
if (packet != null)
|
|
{
|
|
yield return packet;
|
|
}
|
|
|
|
yield break;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void WritePacket(IMinecraftStream stream, IPacket packet)
|
|
{
|
|
stream.WriteUInt8(packet.ID);
|
|
packet.WritePacket(stream);
|
|
stream.BaseStream.Flush();
|
|
}
|
|
}
|
|
} |