Esempio n. 1
0
        public async Task ClientSettings()
        {
            var locale       = "locale";
            var viewDistance = sbyte.MaxValue;
            var chatMode     = int.MaxValue;
            var chatColors   = true;
            var skinParts    = byte.MaxValue;
            var mainHand     = int.MaxValue;

            using var stream = new MinecraftStream();
            await stream.WriteStringAsync(locale);

            await stream.WriteByteAsync(viewDistance);

            await stream.WriteIntAsync(chatMode);

            await stream.WriteBooleanAsync(chatColors);

            await stream.WriteUnsignedByteAsync(skinParts);

            await stream.WriteIntAsync(mainHand);

            stream.Position = 0;

            var packet = PacketSerializer.FastDeserialize <ClientSettings>(stream);

            Assert.Equal(locale, packet.Locale);
            Assert.Equal(viewDistance, packet.ViewDistance);
            Assert.Equal(chatMode, packet.ChatMode);
            Assert.Equal(chatColors, packet.ChatColors);
            Assert.Equal(skinParts, packet.SkinParts);
            Assert.Equal(mainHand, packet.MainHand);
        }
Esempio n. 2
0
        public async Task Handshake()
        {
            var version       = ProtocolVersion.v1_13_2;
            var serverAddress = "serverAddress";
            var serverPort    = ushort.MaxValue;
            var nextState     = ClientState.Status;

            using var stream = new MinecraftStream();
            await stream.WriteVarIntAsync(version);

            await stream.WriteStringAsync(serverAddress);

            await stream.WriteUnsignedShortAsync(serverPort);

            await stream.WriteVarIntAsync(nextState);

            stream.Position = 0;

            var packet = PacketSerializer.FastDeserialize <Handshake>(stream);

            Assert.Equal(version, packet.Version);
            Assert.Equal(serverAddress, packet.ServerAddress);
            Assert.Equal(serverPort, packet.ServerPort);
            Assert.Equal(nextState, packet.NextState);
        }
Esempio n. 3
0
        public async Task PlayerBlockPlacement()
        {
            var location = new Position(1.0, 2.0, 3.0);
            var face     = BlockFace.Top;
            var hand     = int.MaxValue;
            var cursorX  = float.MaxValue;
            var cursorY  = float.MaxValue;
            var cursorZ  = float.MaxValue;

            using var stream = new MinecraftStream();
            await stream.WritePositionAsync(location);

            await stream.WriteVarIntAsync(face);

            await stream.WriteIntAsync(hand);

            await stream.WriteFloatAsync(cursorX);

            await stream.WriteFloatAsync(cursorY);

            await stream.WriteFloatAsync(cursorZ);

            stream.Position = 0;

            var packet = PacketSerializer.FastDeserialize <PlayerBlockPlacement>(stream);

            Assert.Equal(location.X, packet.Location.X);
            Assert.Equal(location.Y, packet.Location.Y);
            Assert.Equal(location.Z, packet.Location.Z);
            Assert.Equal((Hand)hand, packet.Hand);
            Assert.Equal(cursorX, packet.CursorX);
            Assert.Equal(cursorY, packet.CursorY);
            Assert.Equal(cursorZ, packet.CursorZ);
        }
Esempio n. 4
0
        public async Task PlayerPositionLook()
        {
            var pitch      = new Angle(byte.MaxValue - 1);
            var yaw        = new Angle(byte.MaxValue);
            var position   = new Position(1.0, 2.0, 3.0);
            var flags      = PositionFlags.X | PositionFlags.Y_ROT;
            var teleportId = int.MaxValue;

            using var stream = new MinecraftStream();
            await stream.WriteAsync(DataType.Position, null, position);

            await stream.WriteFloatAsync(yaw.Degrees);

            await stream.WriteFloatAsync(pitch.Degrees);

            await stream.WriteUnsignedByteAsync((byte)flags);

            await stream.WriteVarIntAsync(teleportId);

            stream.Position = 0;

            var packet = PacketSerializer.FastDeserialize <ClientPlayerPositionLook>(stream);

            Assert.Equal(position.X, packet.Position.X);
            Assert.Equal(position.Y, packet.Position.Y);
            Assert.Equal(position.Z, packet.Position.Z);
            Assert.Equal(yaw.Degrees, packet.Pitch);
            Assert.Equal(pitch.Degrees, packet.Yaw);
            Assert.Equal(flags, packet.Flags);
            Assert.Equal(teleportId, packet.TeleportId);
        }
Esempio n. 5
0
        public async Task LoginStart()
        {
            var username = "******";

            using var stream = new MinecraftStream();
            await stream.WriteStringAsync(username);

            stream.Position = 0;

            var packet = PacketSerializer.FastDeserialize <LoginStart>(stream);

            Assert.Equal(username, packet.Username);
        }
Esempio n. 6
0
        public async Task IncomingChatMessage()
        {
            var message = "message";

            using var stream = new MinecraftStream();
            await stream.WriteStringAsync(message);

            stream.Position = 0;

            var packet = PacketSerializer.FastDeserialize <IncomingChatMessage>(stream);

            Assert.Equal(message, packet.Message);
        }
Esempio n. 7
0
        public async Task AnimationServerPacket()
        {
            var hand = Hand.OffHand;

            using var stream = new MinecraftStream();
            await stream.WriteVarIntAsync(hand);

            stream.Position = 0;

            var packet = PacketSerializer.FastDeserialize <Animation>(stream);

            Assert.Equal(hand, packet.Hand);
        }
Esempio n. 8
0
        public async Task KeepAlive()
        {
            var keepAliveId = long.MaxValue;

            using var stream = new MinecraftStream();
            await stream.WriteLongAsync(keepAliveId);

            stream.Position = 0;

            var packet = PacketSerializer.FastDeserialize <KeepAlive>(stream);

            Assert.Equal(keepAliveId, packet.KeepAliveId);
        }
Esempio n. 9
0
        public async Task EncryptionResponse()
        {
            var sharedSecret = new byte[] { 1, 2, 3, 4, 5 };
            var verifyToken  = new byte[] { 6, 7, 8, 9, 10 };

            using var stream = new MinecraftStream();
            await stream.WriteVarIntAsync(sharedSecret.Length);

            await stream.WriteAsync(sharedSecret);

            await stream.WriteVarIntAsync(verifyToken.Length);

            await stream.WriteAsync(verifyToken);

            stream.Position = 0;

            var packet = PacketSerializer.FastDeserialize <EncryptionResponse>(stream);

            Assert.Equal(sharedSecret, packet.SharedSecret);
            Assert.Equal(verifyToken, packet.VerifyToken);
        }
Esempio n. 10
0
        public async Task PlayerLook()
        {
            var yaw      = float.MaxValue;
            var pitch    = float.MaxValue;
            var onGround = true;

            using var stream = new MinecraftStream();
            await stream.WriteFloatAsync(yaw);

            await stream.WriteFloatAsync(pitch);

            await stream.WriteBooleanAsync(onGround);

            stream.Position = 0;

            var packet = PacketSerializer.FastDeserialize <PlayerRotation>(stream);

            Assert.Equal(yaw, packet.Yaw);
            Assert.Equal(pitch, packet.Pitch);
            Assert.Equal(onGround, packet.OnGround);
        }
Esempio n. 11
0
        public async Task PlayerPosition()
        {
            var position = new Position(1.0, 2.0, 3.0);
            var onGround = true;

            using var stream = new MinecraftStream();
            await stream.WriteDoubleAsync(position.X);

            await stream.WriteDoubleAsync(position.Y);

            await stream.WriteDoubleAsync(position.Z);

            await stream.WriteBooleanAsync(onGround);

            stream.Position = 0;

            var packet = PacketSerializer.FastDeserialize <PlayerPosition>(stream);

            Assert.Equal(position.X, packet.Position.X);
            Assert.Equal(position.Y, packet.Position.Y);
            Assert.Equal(position.Z, packet.Position.Z);
            Assert.Equal(onGround, packet.OnGround);
        }
Esempio n. 12
0
        public async Task PlayerDigging()
        {
            var status   = int.MaxValue;
            var location = new Position(1.0, 2.0, 3.0);
            var face     = sbyte.MaxValue;

            using var stream = new MinecraftStream();
            await stream.WriteVarIntAsync(status);

            await stream.WritePositionAsync(location);

            await stream.WriteByteAsync(face);

            stream.Position = 0;

            var packet = PacketSerializer.FastDeserialize <PlayerDigging>(stream);

            Assert.Equal((DiggingStatus)status, packet.Status);
            Assert.Equal(location.X, packet.Location.X);
            Assert.Equal(location.Y, packet.Location.Y);
            Assert.Equal(location.Z, packet.Location.Z);
            Assert.Equal((BlockFace)face, packet.Face);
        }
Esempio n. 13
0
        public static async Task HandlePlayPackets(Packet packet, Client client)
        {
            Server server = client.Server;
            Player player = client.Player;

            switch (packet.id)
            {
            case 0x00:     // Teleport Confirm
                var confirm = PacketSerializer.FastDeserialize <TeleportConfirm>(packet.data);

                if (confirm.TeleportId == player.TeleportId)
                {
                    break;
                }

                await player.KickAsync("Invalid teleport... cheater?");

                //await player.TeleportAsync(player.LastLocation);//Teleport them back we didn't send this packet
                break;

            case 0x01:
                // Query Block NBT
                Logger.LogDebug("Received query block nbt");
                break;

            case 0x02:    //Set difficulty

                break;

            case 0x03:
                // Incoming chat message
                var message = await PacketSerializer.FastDeserializeAsync <IncomingChatMessage>(packet.data);

                await server.ParseMessageAsync(message.Message, client);

                break;

            case 0x04:
                // Client status
                break;

            case 0x05:
                // Client Settings
                client.ClientSettings = PacketSerializer.FastDeserialize <ClientSettings>(packet.data);
                Logger.LogDebug("Received client settings");
                break;

            case 0x06:
                // Tab-Complete
                Logger.LogDebug("Received tab-complete");
                break;

            case 0x07:
                //TODO look more into this
                // Window Confirmation (serverbound)
                var conf = PacketSerializer.FastDeserialize <WindowConfirmation>(packet.data);

                Logger.LogDebug("Window Confirmation (serverbound)");
                break;

            case 0x08:
                // Click Window Button
                var clicked = PacketSerializer.FastDeserialize <ClickWindowButton>(packet.data);

                break;

            case 0x09:    // Click Window
            {
                var window = PacketSerializer.FastDeserialize <ClickWindow>(packet.data);

                Logger.LogDebug("Click window");

                if (window.WindowId == 0)
                {
                    //This is the player inventory
                    switch (window.Mode)
                    {
                    case InventoryOperationMode.MouseClick:            //TODO InventoryClickEvent
                    {
                        if (window.Button == 0)
                        {
                            player.Inventory.RemoveItem(window.ClickedSlot, 64);
                        }
                        else
                        {
                            player.Inventory.RemoveItem(window.ClickedSlot, window.Item.Count / 2);
                        }
                        break;
                    }

                    case InventoryOperationMode.ShiftMouseClick:
                        break;

                    case InventoryOperationMode.NumberKeys:
                        break;

                    case InventoryOperationMode.MiddleMouseClick:
                        break;

                    case InventoryOperationMode.Drop:
                    {
                        //If clicked slot is -999 that means they clicked outside the inventory
                        if (window.ClickedSlot != -999)
                        {
                            Logger.LogDebug("Dropped Item");
                            if (window.Button == 0)
                            {
                                player.Inventory.RemoveItem(window.ClickedSlot);
                            }
                            else
                            {
                                player.Inventory.RemoveItem(window.ClickedSlot, 64);
                            }
                        }
                        break;
                    }

                    case InventoryOperationMode.MouseDrag:
                    {
                        if (window.ClickedSlot == -999)
                        {
                            if (window.Button == 0 || window.Button == 4 || window.Button == 8)
                            {
                                client.isDragging = true;
                            }
                            else if (window.Button == 2 || window.Button == 6 || window.Button == 10)
                            {
                                client.isDragging = false;
                            }
                        }
                        else if (client.isDragging)
                        {
                            if (player.Gamemode == Gamemode.Creative)
                            {
                                if (window.Button != 9)
                                {
                                    break;
                                }

                                //creative copy
                                player.Inventory.SetItem(window.ClickedSlot, new ItemStack(window.Item.Id, window.Item.Count)
                                        {
                                            Nbt = window.Item.Nbt
                                        });
                            }
                            else
                            {
                                if (window.Button != 1 || window.Button != 5)
                                {
                                    break;
                                }

                                //survival painting
                                player.Inventory.SetItem(window.ClickedSlot, new ItemStack(window.Item.Id, window.Item.Count)
                                        {
                                            Nbt = window.Item.Nbt
                                        });
                            }
                        }
                        else
                        {
                            //It shouldn't get here
                        }

                        break;
                    }

                    case InventoryOperationMode.DoubleClick:
                        break;

                    default:
                        break;
                    }
                }
                else
                {
                }
                break;
            }

            case 0x0A:
                // Close Window (serverbound)
                var closedWindow = PacketSerializer.FastDeserialize <CloseWindow>(packet.data);

                Logger.LogDebug("Received close window");
                break;

            case 0x0B:     // Plugin Message (serverbound)
            {
                var msg = await PacketSerializer.DeserializeAsync <PluginMessage>(packet.data);

                var result = await msg.HandleAsync();

                switch (result.Type)
                {
                case PluginMessageType.Brand:
                    client.Brand = result.Value.ToString();
                    break;

                case PluginMessageType.Register:
                {
                    using var stream = new MinecraftStream(msg.PluginData);
                    var len = await stream.ReadVarIntAsync();

                    //Idk how this would work so I'm assuming a length will be sent first
                    for (int i = 0; i < len; i++)
                    {
                        server.RegisteredChannels.Add(await stream.ReadStringAsync());
                    }

                    break;
                }

                case PluginMessageType.UnRegister:
                    server.RegisteredChannels.RemoveWhere(x => x == msg.Channel.ToLower());
                    break;

                case PluginMessageType.Custom:            //This can be ignored for now
                default:
                    break;
                }

                Logger.LogDebug($"Received plugin message: {msg.Channel}");
            }
            break;

            case 0x0C:
                // Edit Book
                Logger.LogDebug("Received edit book");
                break;

            case 0x0E:
                //Interact Entity
                Logger.LogDebug("Interact entity");
                break;

            case 0x0F:
                //Generate structure
                break;

            case 0x10:
                // Keep Alive (serverbound)
                var keepalive = PacketSerializer.FastDeserialize <KeepAlive>(packet.data);
                Logger.LogDebug($"Successfully kept alive player {player.Username} with ka id " +
                                $"{keepalive.KeepAliveId} previously missed {client.missedKeepalives - 1} ka's"); // missed is 1 more bc we just handled one

                // Server is alive, reset missed keepalives.
                client.missedKeepalives = 0;
                break;

            case 0x11:    //Lock Difficulty
                break;

            case 0x12:
                // Player Position
                var pos = PacketSerializer.FastDeserialize <PlayerPosition>(packet.data);

                await player.UpdateAsync(server, pos.Position, pos.OnGround);

                break;

            case 0x13:
                //Player Position And rotation (serverbound)
                var ppos = PacketSerializer.FastDeserialize <ServerPlayerPositionLook>(packet.data);

                await player.UpdateAsync(server, ppos.Position, ppos.Yaw, ppos.Pitch, ppos.OnGround);

                break;

            case 0x14:    // Player rotation
                var look = PacketSerializer.FastDeserialize <PlayerRotation>(packet.data);

                await player.UpdateAsync(server, look.Yaw, look.Pitch, look.OnGround);

                break;

            case 0x15:    //Player movement
                break;

            case 0x16:    // Vehicle Move (serverbound)
                break;

            case 0x17:    //Steer boat
                break;

            case 0x18:
                // Pick Item
                var item = PacketSerializer.FastDeserialize <PickItem>(packet.data);

                Logger.LogDebug("Received pick item");

                break;

            case 0x19:
                // Craft Recipe Request
                Logger.LogDebug("Received craft recipe request");

                break;

            case 0x1A:
                // Player Abilities (serverbound)
                Logger.LogDebug("Received player abilities");
                break;

            case 0x1B:
                // Player Digging

                var digging = PacketSerializer.FastDeserialize <PlayerDigging>(packet.data);

                await server.BroadcastPlayerDigAsync(new PlayerDiggingStore
                {
                    Player = player.Uuid,
                    Packet = digging
                });

                break;

            case 0x1C:
                //TODO Entity Action
                var action = PacketSerializer.FastDeserialize <EntityAction>(packet.data);


                switch (action.Action)
                {
                case EAction.StartSneaking:
                    player.Sneaking = true;
                    break;

                case EAction.StopSneaking:
                    player.Sneaking = false;
                    break;

                case EAction.LeaveBed:
                    player.Sleeping = false;
                    break;

                case EAction.StartSprinting:
                    player.Sprinting = true;
                    break;

                case EAction.StopSprinting:
                    player.Sprinting = false;
                    break;

                case EAction.StartJumpWithHorse:
                    break;

                case EAction.StopJumpWithHorse:
                    break;

                case EAction.OpenHorseInventory:
                    player.InHorseInventory = true;
                    break;

                case EAction.StartFlyingWithElytra:
                    player.FlyingWithElytra = true;
                    break;

                default:
                    break;
                }
                Logger.LogDebug("Received entity action");
                break;

            case 0x1D:
                // Steer Vehicle
                break;

            case 0x1E:    // Set Displayed Recipe
                break;

            case 0x1F:    //Set recipe book state
                break;

            case 0x20:    // Name Item
                var nameItem = PacketSerializer.FastDeserialize <NameItem>(packet.data);
                break;

            case 0x21:    //Resource pack status
                break;

            case 0x22:    //Advancement tab
                break;

            case 0x23:    //Select trade
                break;

            case 0x24:    //Set beacon effect
                break;

            case 0x25:    // Held Item Change (serverbound)
                var heldItemChange = PacketSerializer.FastDeserialize <ServerHeldItemChange>(packet.data);
                player.CurrentSlot = (short)(heldItemChange.Slot + 36);

                var heldItem = player.GetHeldItem();

                await server.BroadcastPacketAsync(new EntityEquipment
                {
                    EntityId = client.id,
                    Slot     = ESlot.MainHand,
                    Item     = new ItemStack
                    {
                        Present = heldItem.Present,
                        Count   = (sbyte)heldItem.Count,
                        Id      = heldItem.Id,
                        Nbt     = heldItem.Nbt
                    }
                }, player);

                Logger.LogDebug("Held item change");
                break;

            case 0x26:    //Update command block
                break;

            case 0x27:    //Update command block minecart
                break;

            case 0x28:    // Creative Inventory Action in creative they send this to replace whatever item existed in the slot
            {
                var ca = PacketSerializer.FastDeserialize <CreativeInventoryAction>(packet.data);

                player.Inventory.SetItem(ca.ClickedSlot, new ItemStack(ca.ClickedItem.Id, ca.ClickedItem.Count)
                    {
                        Nbt     = ca.ClickedItem.Nbt,
                        Present = ca.ClickedItem.Present
                    });

                if (ca.ClickedSlot >= 36 && ca.ClickedSlot <= 44)
                {
                    heldItem = player.GetHeldItem();
                    await server.BroadcastPacketAsync(new EntityEquipment
                        {
                            EntityId = client.id,
                            Slot     = ESlot.MainHand,
                            Item     = new ItemStack
                            {
                                Present = heldItem.Present,
                                Count   = (sbyte)heldItem.Count,
                                Id      = heldItem.Id,
                                Nbt     = heldItem.Nbt
                            }
                        }, player);
                }
            }
            break;

            case 0x29:    //Update jigsaw block
                break;

            case 0x2A:    //Update structure block
                break;

            case 0x2B:    //Update sign
                break;

            case 0x2C:    // Animation (serverbound)
                var serverAnim = PacketSerializer.FastDeserialize <Animation>(packet.data);

                //TODO broadcast entity animation to nearby players
                switch (serverAnim.Hand)
                {
                case Hand.MainHand:
                    await server.BroadcastPacketAsync(new EntityAnimation
                    {
                        EntityId  = client.id,
                        Animation = EAnimation.SwingMainArm
                    }, player);

                    break;

                case Hand.OffHand:
                    await server.BroadcastPacketAsync(new EntityAnimation
                    {
                        EntityId  = client.id,
                        Animation = EAnimation.SwingOffhand
                    }, player);

                    break;

                default:
                    break;
                }
                break;

            case 0x2D:    //Spectate
                break;

            case 0x2E:    // Player Block Placement
            {
                var pbp = PacketSerializer.FastDeserialize <PlayerBlockPlacement>(packet.data);

                var currentItem = player.GetHeldItem();

                var block = Registry.GetBlock(currentItem.Type);

                var location = pbp.Location;

                var interactedBlock = server.World.GetBlock(location);

                if (interactedBlock.CanInteract() && !player.Sneaking)
                {
                    var arg = await server.Events.InvokeBlockInteractAsync(new BlockInteractEventArgs(player, block, pbp.Location));

                    if (arg.Cancel)
                    {
                        return;
                    }

                    //TODO open chests/Crafting inventory ^ ^

                    Logger.LogDebug($"Block Interact: {interactedBlock} - {location}");

                    return;
                }

                if (player.Gamemode != Gamemode.Creative)
                {
                    player.Inventory.RemoveItem(player.CurrentSlot);
                }

                switch (pbp.Face)         // TODO fix this for logs
                {
                case BlockFace.Bottom:
                    location.Y -= 1;
                    break;

                case BlockFace.Top:
                    location.Y += 1;
                    break;

                case BlockFace.North:
                    location.Z -= 1;
                    break;

                case BlockFace.South:
                    location.Z += 1;
                    break;

                case BlockFace.West:
                    location.X -= 1;
                    break;

                case BlockFace.East:
                    location.X += 1;
                    break;

                default:
                    break;
                }

                block.Location = location;
                server.World.SetBlock(location, block);

                await server.BroadcastBlockPlacementAsync(player, block, location);

                break;
            }

            case 0x2F:    //Use item
                Logger.LogDebug("Use item");
                break;
            }
        }
Esempio n. 14
0
        public async Task StartConnectionAsync()
        {
            while (!Cancellation.IsCancellationRequested && this.tcp.Connected)
            {
                Packet packet = await this.GetNextPacketAsync();

                if (this.State == ClientState.Play && packet.data.Length < 1)
                {
                    this.Disconnect();
                }

                switch (this.State)
                {
                case ClientState.Status:     // Server ping/list
                    switch (packet.id)
                    {
                    case 0x00:
                        var status = new ServerStatus(Server);
                        await this.SendPacketAsync(new RequestResponse(status));

                        break;

                    case 0x01:
                        await this.SendPacketAsync(new PingPong(packet.data));

                        this.Disconnect();
                        break;
                    }
                    break;

                case ClientState.Handshaking:
                    if (packet.id == 0x00)
                    {
                        if (packet == null)
                        {
                            throw new InvalidOperationException();
                        }

                        var handshake = await PacketSerializer.FastDeserializeAsync <Handshake>(packet.data);

                        var nextState = handshake.NextState;

                        if (nextState != ClientState.Status && nextState != ClientState.Login)
                        {
                            this.Logger.LogDebug($"Client sent unexpected state ({(int)nextState}), forcing it to disconnect");
                            await this.DisconnectAsync(ChatMessage.Simple("you seem suspicious"));
                        }

                        this.State = nextState;
                        this.Logger.LogInformation($"Handshaking with client (protocol: {handshake.Version}, server: {handshake.ServerAddress}:{handshake.ServerPort})");
                    }
                    else
                    {
                        // Handle legacy ping
                    }
                    break;

                case ClientState.Login:
                    switch (packet.id)
                    {
                    default:
                        this.Logger.LogError("Client in state Login tried to send an unimplemented packet. Forcing it to disconnect.");
                        await this.DisconnectAsync("Unknown Packet Id.");

                        break;

                    case 0x00:
                        var loginStart = await PacketSerializer.FastDeserializeAsync <LoginStart>(packet.data);

                        string username = config.MulitplayerDebugMode ? $"Player{Globals.Random.Next(1, 999)}" : loginStart.Username;

                        this.Logger.LogDebug($"Received login request from user {loginStart.Username}");

                        await this.Server.DisconnectIfConnectedAsync(username);

                        if (this.config.OnlineMode)
                        {
                            var user = await MinecraftAPI.GetUserAsync(loginStart.Username);

                            this.Player = new Player(Guid.Parse(user.Id), loginStart.Username, this)
                            {
                                World = this.Server.World
                            };

                            this.packetCryptography.GenerateKeyPair();

                            var values = this.packetCryptography.GeneratePublicKeyAndToken();

                            this.randomToken = values.randomToken;

                            await this.SendPacketAsync(new EncryptionRequest(values.publicKey, this.randomToken));

                            break;
                        }

                        this.Player = new Player(UUIDFactory.CreateUUID(3, 1, $"OfflinePlayer:{username}"), username, this)
                        {
                            World = this.Server.World
                        };

                        //await this.SetCompression();
                        await this.ConnectAsync();

                        break;

                    case 0x01:
                        var encryptionResponse = PacketSerializer.FastDeserialize <EncryptionResponse>(packet.data);

                        this.sharedKey = this.packetCryptography.Decrypt(encryptionResponse.SharedSecret);
                        var decryptedToken = this.packetCryptography.Decrypt(encryptionResponse.VerifyToken);

                        if (!decryptedToken.SequenceEqual(this.randomToken))
                        {
                            await this.DisconnectAsync("Invalid token..");

                            break;
                        }

                        var serverId = sharedKey.Concat(this.packetCryptography.PublicKey).ToArray().MinecraftShaDigest();

                        JoinedResponse response = await MinecraftAPI.HasJoined(this.Player.Username, serverId);

                        if (response is null)
                        {
                            this.Logger.LogWarning($"Failed to auth {this.Player.Username}");
                            await this.DisconnectAsync("Unable to authenticate..");

                            break;
                        }

                        this.encryptionEnabled = true;
                        this.minecraftStream   = new AesStream(this.debugStream ?? (Stream)this.tcp.GetStream(), this.sharedKey);

                        //await this.SetCompression();
                        await ConnectAsync();

                        break;

                    case 0x02:
                        // Login Plugin Response
                        break;
                    }
                    break;

                case ClientState.Play:

                    //await this.Logger.LogDebugAsync($"Received Play packet with Packet ID 0x{packet.id.ToString("X")}");

                    await PacketHandler.HandlePlayPackets(packet, this);

                    break;
                }

                //await Task.Delay(50);
            }

            Logger.LogInformation($"Disconnected client");

            if (this.State == ClientState.Play)
            {
                await this.Server.Events.InvokePlayerLeaveAsync(new PlayerLeaveEventArgs(this.Player));
            }

            if (tcp.Connected)
            {
                this.tcp.Close();

                if (this.Player != null)
                {
                    this.Server.OnlinePlayers.TryRemove(this.Player.Uuid, out var _);
                }
            }
        }