// -------------------------------------------------------------------------------
        // OnAuthRequestMessage
        // @Client -> @Server
        // -------------------------------------------------------------------------------
        void OnAuthRequestMessage(NetworkConnection conn, AuthRequestMessage msg)
        {
            ServerResponseMessage message = new ServerResponseMessage
            {
                code             = successCode,
                text             = "",
                causesDisconnect = false
            };

            if (checkApplicationVersion && msg.clientVersion != Application.version)
            {
                message.text = systemText.versionMismatch;
                message.code = errorCode;
            }
            else
            {
                base.OnServerAuthenticated.Invoke(conn);
            }

            conn.Send(message);

            if (message.code == errorCode)
            {
                conn.isAuthenticated = false;
                conn.Disconnect();
            }
        }
        // -------------------------------------------------------------------------------
        // OnUserChangePasswordRequestMessage
        // @Client -> @Server
        // -------------------------------------------------------------------------------
        void OnUserChangePasswordRequestMessage(NetworkConnection conn, UserChangePasswordRequestMessage msg)
        {
            ServerResponseMessage message = new ServerResponseMessage
            {
                code             = successCode,
                text             = "",
                causesDisconnect = true
            };

            if (DatabaseManager.singleton.TryUserChangePassword(msg.username, msg.oldPassword, msg.newPassword))
            {
                message.text = systemText.userChangePasswordSuccess;
            }
            else
            {
                message.text = systemText.userChangePasswordFailure;
                message.code = errorCode;
            }

            conn.Send(message);
        }
        // -------------------------------------------------------------------------------
        // OnPlayerSwitchServerRequestMessage
        // @Client -> @Server
        // -------------------------------------------------------------------------------
        void OnPlayerSwitchServerRequestMessage(NetworkConnection conn, PlayerSwitchServerRequestMessage msg)
        {
            ServerResponseMessage message = new ServerResponseMessage
            {
                code             = successCode,
                text             = "",
                causesDisconnect = false
            };

            if (DatabaseManager.singleton.TryPlayerSwitchServer(msg.username, msg.token))
            {
                message.text = systemText.playerSwitchServerSuccess;
                eventListener.onPlayerSwitchServer.Invoke(msg.username);
            }
            else
            {
                message.text = systemText.playerSwitchServerFailure;
                message.code = errorCode;
            }

            conn.Send(message);
        }
        // -------------------------------------------------------------------------------
        // OnUserConfirmRequestMessage
        // @Client -> @Server
        // -------------------------------------------------------------------------------
        void OnUserConfirmRequestMessage(NetworkConnection conn, UserConfirmRequestMessage msg)
        {
            ServerResponseMessage message = new ServerResponseMessage
            {
                code             = successCode,
                text             = "",
                causesDisconnect = false
            };

            if (DatabaseManager.singleton.TryUserConfirm(msg.username, msg.password))
            {
                message.text = systemText.userConfirmSuccess;
                eventListener.onUserConfirm.Invoke(msg.username);
            }
            else
            {
                message.text = systemText.userConfirmFailure;
                message.code = errorCode;
            }

            conn.Send(message);
        }
        // ========================= MESSAGE HANDLERS - PLAYER ============================

        // -------------------------------------------------------------------------------
        // OnPlayerLoginRequestMessage
        // @Client -> @Server
        // -------------------------------------------------------------------------------
        void OnPlayerLoginRequestMessage(NetworkConnection conn, PlayerLoginRequestMessage msg)
        {
            ServerResponseMessage message = new ServerResponseMessage
            {
                code             = successCode,
                text             = "",
                causesDisconnect = false
            };

            if (DatabaseManager.singleton.TryPlayerLogin(msg.playername, msg.username))
            {
                NetworkManager.singleton.LoginPlayer(conn, msg.playername);

                message.text = systemText.playerLoginSuccess;
                eventListener.onPlayerLogin.Invoke(conn.identity.gameObject);
            }
            else
            {
                message.text = systemText.playerLoginFailure;
                message.code = errorCode;
            }

            conn.Send(message);
        }
        // -------------------------------------------------------------------------------
        // OnServerResponseMessage
        // @Server -> @Client
        // -------------------------------------------------------------------------------
        void OnServerResponseMessage(NetworkConnection conn, ServerResponseMessage msg)
        {
            // -- show popup if error message is not empty
            if (!String.IsNullOrWhiteSpace(msg.text))
            {
                UIPopupConfirm.singleton.Init(msg.text);
            }

            // -- send answer depending on action and ready client
            if (msg.code == successCode && !msg.causesDisconnect)
            {
                base.OnClientAuthenticated.Invoke(conn);

                switch (userAction)
                {
                // -- User
                case NetworkAction.LoginUser:
                    RequestLoginUser(conn, userName, userPassword);
                    break;

                case NetworkAction.RegisterUser:
                    RequestRegisterUser(conn, userName, userPassword);
                    break;

                case NetworkAction.DeleteUser:
                    RequestSoftDeleteUser(conn, userName, userPassword);
                    break;

                case NetworkAction.ChangePasswordUser:
                    RequestChangePasswordUser(conn, userName, userPassword, newPassword);
                    break;

                case NetworkAction.ConfirmUser:
                    RequestConfirmUser(conn, userName, userPassword);
                    break;

                // -- Player
                case NetworkAction.LoginPlayer:
                    if (RequestLoginPlayer(conn, userName))
                    {
                        ClientScene.Ready(conn);
                    }
                    break;

                case NetworkAction.RegisterPlayer:
                    RequestRegisterPlayer(conn, userName);
                    break;

                case NetworkAction.DeletePlayer:
                    RequestSoftDeletePlayer(conn, userName);
                    break;

                case NetworkAction.SwitchServerPlayer:
                    RequestSwitchServerPlayer(conn, userName);
                    break;
                }

                userAction = 0;
            }

            // -- disconnect and un-authenticate if anything went wrong
            if (msg.code == errorCode || msg.causesDisconnect)
            {
                conn.isAuthenticated = false;
                conn.Disconnect();
                NetworkManager.singleton.StopClient();
            }
        }