/// <summary>
 /// Initializes a new instance of the IntroductionPacket class.
 /// </summary>
 /// <param name="inventoryPacket">The inventory packet which is part of the initialization.</param>
 /// <param name="orientationPacket">The orientation packet which is part of the initialization.</param>
 /// <param name="otherPlayersOrientation">The orientation packets representing the orientation of other players.</param>
 public IntroductionPacket(InventoryPacket inventoryPacket, OrientationPacket orientationPacket, params OrientationPacket[] otherPlayersOrientation)
     : base()
 {
     this.InventoryPacket = inventoryPacket;
     this.OrientationPacket = orientationPacket;
     this.OtherPlayersOrientation = new ReadOnlyCollection<OrientationPacket>(otherPlayersOrientation);
 }
        /// <summary>
        /// Initializes a new instance of the IntroductionPacket class.
        /// </summary>
        /// <param name="inventoryPacket">The inventory packet which is part of the initialization.</param>
        /// <param name="orientationPacket">The orientation packet which is part of the initialization.</param>
        /// <param name="otherPlayers">The players to generate orientation packets from. Will automatically exclude an element if it's Username property is equal to that of orientationPacket.</param>
        public IntroductionPacket(InventoryPacket inventoryPacket, OrientationPacket orientationPacket, params Player[] otherPlayers)
            : base()
        {
            this.InventoryPacket = inventoryPacket;
            this.OrientationPacket = orientationPacket;

            Collection<OrientationPacket> otherOrientations = new Collection<OrientationPacket>();
            for (int i = 0; i < otherPlayers.Length; i++)
            {
                if (otherPlayers[i].UserName != orientationPacket.UserName)
                {
                    otherOrientations.Add(new OrientationPacket(otherPlayers[i]));
                }
            }

            this.OtherPlayersOrientation = new ReadOnlyCollection<OrientationPacket>(otherOrientations);
        }
        /// <summary>
        /// Logs into a player account. If the player is already signed in, this simply returns true.
        /// </summary>
        /// <param name="userName">The user name of the client player.</param>
        /// <param name="password">The password of the client player.</param>
        /// <returns>Whether the login was successful.</returns>
        public bool ClientLogOn(string userName, string password)
        {
            lock (this)
            {
                bool loadedData = this.Load(userName);

                // Only try to login if the player hasn't already
                if (!this.LoggedIn)
                {
                    // If a player data file was not successfully loaded, destroy the connection
                    if (!loadedData)
                    {
                        PacketSender.Send(AuthenticationResultPacket.FailedInvalidUserName, this);
                        this.Dispose();
                        return false;
                    }

                    // Get the MD5 of the player's password
                    string passwordHash = SimpleCryptography.MD5(password);

                    // If X minutes have passed, reset the attempted login count
                    if ((DateTime.UtcNow.Ticks - this.LastLogOnAttempt) > PlayerHandler.LoginWaitTime)
                    {
                        this.AttemptedLogOnCount = 0;
                    }

                    // Set last login attempt time to now
                    this.LastLogOnAttempt = DateTime.UtcNow.Ticks;
                    this.LastLogOnAttemptIP = NetworkUtilities.GetRemoteIP(this.Connection.Connection.Client);

                    // If there's not been too many wrong logins in a row and player is not banned
                    if (this.AttemptedLogOnCount < PlayerHandler.MaxAttemptsIp && this.UserLevel != UserPermissionLevel.Disabled)
                    {
                        // If the password supplied by the login is equal to the password stored in the database, continue
                        if (passwordHash.ToUpperInvariant() == this.PasswordHash.ToUpperInvariant())
                        {
                            // Set the player logged in to true, player is now logged in!
                            this.LoggedIn = true;

                            // Reset the attempted logins since player is now authenticated
                            if ((DateTime.UtcNow.Ticks - this.LastLogOnAttempt) > PlayerHandler.LoginWaitTime)
                            {
                                this.AttemptedLogOnCount = 0;
                            }

                            // Set the login success time and IP
                            this.LastLogOnSuccess = DateTime.UtcNow.Ticks;
                            this.LastLogOnSuccessIP = NetworkUtilities.GetRemoteIP(this.Connection.Connection.Client);

                            // Tell the client his or her login was successful and tell other users he or she logged in
                            PacketSender.Send(AuthenticationResultPacket.Success, this);

                            InventoryPacket inv = new InventoryPacket(this.Inventory);
                            OrientationPacket ori = new OrientationPacket(this);
                            PacketSender.Send(new IntroductionPacket(inv, ori, this.server.Clients.ToArray()), this);

                            PacketSender.SendToAll(new PlayerLoggedPacket(this, true));
                        }
                        else
                        {
                            // Wrong password, increment login attempts and send message informing the
                            // player that an incorrect password has been supplied, then terminate the connection
                            this.AttemptedLogOnCount++;
                            PacketSender.Send(AuthenticationResultPacket.FailedInvalidPassword, this);
                            this.Dispose();
                            return false;
                        }
                    }
                    else
                    {
                        // Too many wrong logins or player banned... increment attempted logins
                        this.AttemptedLogOnCount++;

                        if (this.AttemptedLogOnCount >= PlayerHandler.MaxAttemptsAll)
                        {
                            // If the player attempted to login far too many times set their user level
                            // to banned (if it wasn't already), send message telling player that their
                            // account has been disabled, and destroy the connection
                            this.UserLevel = UserPermissionLevel.Disabled;
                            this.DisableReason = DisableReason.ExcessLogins;
                            PacketSender.Send(AuthenticationResultPacket.FailedAccountDisabled, this);
                            this.Dispose();
                            return false;
                        }
                        else if (this.UserLevel == UserPermissionLevel.Disabled)
                        {
                            // The player is banned - deny 'em
                            PacketSender.Send(AuthenticationResultPacket.FailedAccountDisabled, this);
                            this.Dispose();
                            return false;
                        }
                        else if (this.AttemptedLogOnCount >= PlayerHandler.MaxAttemptsIp)
                        {
                            // Otherwise, if they only attempted to login a few too many times,
                            // tell them that they have tried to login too many times and will
                            // have to wait a while before trying again
                            PacketSender.Send(AuthenticationResultPacket.FailedTooManyIncorrectLogins, this);
                            this.Dispose();
                            return false;
                        }
                    }
                }
                else
                {
                    // Tell the client he's already logged in
                    PacketSender.Send(AuthenticationResultPacket.AlreadyLoggedIn, this);
                }

                return this.LoggedIn;
            }
        }