2015-06-20 19:43:28 -07:00

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();
}
}
}