/// <summary>
        /// Sends a handshake packet
        /// </summary>
        /// <param name="user">The user.</param>
        /// <remarks></remarks>
        protected void SendHandshake(User user)
        {
            lock (lockObject)
            {
                WebClient c = new WebClient();
                if (!string.IsNullOrWhiteSpace(user.Password))
                {
                    SessionID = c.DownloadString(string.Format(SessionIDUrl, user.UserName, user.Password));
                    if (SessionID == "Bad Login")
                        throw new Exception("Invalid credentials.");
                    string[] sessionValues = SessionID.Split(':');
                    user.UserName = sessionValues[2];
                    SessionID = sessionValues[3];
                }

                // Do handshake
                netStream.WriteByte((byte)PacketID.Handshake);
                WriteString(netStream, user.UserName);
                netStream.Flush();

                PacketID response = (PacketID)netStream.ReadByte();

                if (response != PacketID.Handshake)
                    throw new Exception("Unrecognized response from server.");

                ServerID = ReadString(netStream);

                if (ServerID == "-")
                {
                    // No further action required as of 1.1
                }
                else if (ServerID == "+")
                {
                    // Password authentication required (presently unsupported by official
                    // software, so it's unsupported by us, too)
                }
                else
                {
                    HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(string.Format(ServerIDUrl, user.UserName, SessionID, ServerID));
                    try
                    {
                        wr.GetResponse().Close();
                    }
                    catch
                    {
                        throw new Exception("Failed to authenticate with the server.");
                    }
                }
            }
        }
        /// <summary>
        /// Sends a login packet
        /// </summary>
        /// <param name="user">The user.</param>
        /// <param name="protocolVersion">The protocol version.</param>
        /// <remarks></remarks>
        protected void SendLogin(User user, int protocolVersion)
        {
            lock (lockObject)
            {
                // Send login packet
                netStream.WriteByte((byte)PacketID.LoginRequest);
                WriteInt(netStream, protocolVersion);
                WriteString(netStream, user.UserName);
                WriteLong(netStream, 0);
                WriteString(netStream, "");
                WriteInt(netStream, 0);
                netStream.WriteByte(0);
                netStream.WriteByte(0);
                netStream.WriteByte(0);
                netStream.WriteByte(0);
                netStream.Flush();

                // Receive response
                PacketID response = (PacketID)netStream.ReadByte();

                if (response == PacketID.Disconnect)
                {
                    ForceDisconnect();
                    throw new Exception(ReadString(netStream));
                }

                if (response != PacketID.LoginRequest)
                {
                    string dump = ReadString(netStream);
                    throw new Exception("Unrecognized response from server.");
                }

                Player = new PlayerEntity();
                //World = new World();
                //Player.ID = ReadInt(netStream);
                //ReadString(netStream);
                //World.Seed = ReadLong(netStream);
                //World.WorldGenerator = null;
                //World.Mode = (GameMode)ReadInt(netStream);
                //Player.Dimension = (Dimension)((sbyte)netStream.ReadByte());
                //CurrentServer.Difficulty = (Difficulty)netStream.ReadByte();
                //(byte)netStream.ReadByte();
                CurrentServer.MaxPlayers = netStream.ReadByte();
                netStream.Flush();
                Player.Name = user.UserName;
            }
        }
        /// <summary>
        /// Logs the specified user into the server
        /// </summary>
        /// <param name="user">The user.</param>
        /// <remarks></remarks>
        public void LogIn(User user)
        {
            if (CurrentServer == null)
                throw new Exception("You must connect to a server before logging in.");
            if (user.UserName.Length > 16)
                throw new Exception("User name is too long.  The maximum length is 16 characters.");

            SendHandshake(user);
            SendLogin(user, ProtocolVersion);

            // Start server updater
            worker = new Timer(new TimerCallback(DoWork), null, 0, TickTime);
        }