/// <summary>
        /// Protocol 001F
        /// </summary>
        /// <param name="session"></param>
        /// <param name="packet"></param>
        /// <returns></returns>
        public async void UserLogin(EcoSession session, BasePacket packet)
        {
            try
            {
                var login_data = new LoginData(packet.Data);
                Logger.Debug($"Received Login Request, Username: {login_data.Username}, Password:{login_data.Password}, MacAddress:{login_data.MacAddress.ToHexString()}, SingleSignOn:{login_data.SingleSignOn.ToString()}");
                LoginAuthResult loginAuthResult;
                //select user info from db
                Account userAccount = await DatabaseManager.SelectAsync <Account>("username", $@"'{login_data.Username}'");

                if (userAccount.is_online)
                {
                    loginAuthResult = new LoginAuthResult(LoginResultEnum.GAME_SMSG_LOGIN_ERR_ALREADY, 1);
                    session.Send(loginAuthResult.ToPacket());
                    return;
                }

                if (userAccount.is_banned)
                {
                    loginAuthResult = new LoginAuthResult(LoginResultEnum.GAME_SMSG_LOGIN_ERR_BFALOCK, 1);
                    session.Send(loginAuthResult.ToPacket());
                    return;
                }

                string pass_hash = Utilities.PasswordHash(userAccount.password, session.FrontWord.ToString(), session.BackWord.ToString()).ToHexString();

                if (login_data.Password == pass_hash)
                {
                    loginAuthResult          = new LoginAuthResult(LoginResultEnum.GAME_SMSG_LOGIN_SUCCESS, 1);
                    session.UserLoginSuccess = true;
                    session.AccountID        = userAccount.id;
                }
                else
                {
                    loginAuthResult = new LoginAuthResult(LoginResultEnum.GAME_SMSG_LOGIN_ERR_BADPASS, 0);
                }

                session.Send(loginAuthResult.ToPacket());

                if (session.UserLoginSuccess)
                {
                    CharaSelectionInfo     sci = new CharaSelectionInfo();
                    EquipmentSelectionInfo sei = new EquipmentSelectionInfo();
                    //select chara data from db
                    List <SingleCharaSelectionInfoExt> lscsiws = await DatabaseManager.SelectMultiAsync <SingleCharaSelectionInfoExt>("account_id", session.AccountID.ToString(), "Chara");

                    foreach (var scsiws in lscsiws)
                    {
                        sci.AddChara(scsiws, scsiws.Slot);
                        SingleCharaEquipmentSelectionInfoExt scesi = await DatabaseManager.SelectAsync <SingleCharaEquipmentSelectionInfoExt>(scsiws.id, "Equip");

                        sei.AddEquipmentInfo(scesi, scsiws.Slot);
                    }

                    //test use
                    //sci.AddChara(new SingleCharaSelectionInfo {
                    //    Name = "TEST",
                    //    RebirthLv = 10, Sex = 1, HairStyle = 7, HairColor = 50, Wig = 0xffff, IsEmptySlot = 0xff, Face = 0, Map = 0x0098f058, Job = 91, LvBase = 15, LvJob1 = 15, LvJob2t = 50, LvJob2x = 1, LvJob3 = 1, Quest = 5 });

                    session.Send(sci.ToPacket());

                    //for test use
                    //sei.AddEquipmentInfo(new SingleCharaEquipmentSelectionInfo { Chestacce = 0x02fc6a3c, Tops = 0x0395d924, Backpack = 0x02fc3328, Shoes = 0x02fe8678 });

                    session.Send(sei.ToPacket());
                }
            }
            catch (Exception e)
            {
                Logger.Error(e);
            }
        }
        /// <summary>
        /// Protocol 00A0
        /// </summary>
        /// <param name="session"></param>
        /// <param name="packet"></param>
        /// <returns></returns>
        public async void CreateChara(EcoSession session, BasePacket packet)
        {
            CharaCreationInfo cci = new CharaCreationInfo(packet.Data);

            Logger.Debug($"Received Chara Creation Request at slot:{cci.chara_slot}, chara name:{cci.chara_name}, race:{cci.race},sex:{cci.sex}, hair:{cci.hair}, hair color:{cci.hair_color}, face:{cci.face}");

            #region validation check

            if (session.AccountID == 0)
            {
                //error
                Logger.Error($"Create chara failed, AccountID is 0");
                return;
            }

            if (cci.chara_name.Length < 3)
            {
                session.Send(new CharaCreationResult(CharaCreationResultEnum.GAME_SMSG_CHRCREATE_E_NAME_TOO_SHORT).ToPacket());
                return;
            }

            if (cci.chara_name.Length > 8)
            {
                session.Send(new CharaCreationResult(CharaCreationResultEnum.GAME_SMSG_CHRCREATE_E_NAME_TOO_LONG).ToPacket());
                return;
            }

            Regex r = new Regex(@"[.,\/#!$%\^&\*;:{}=\-_~()\s]");
            if (r.IsMatch(cci.chara_name))
            {
                session.Send(new CharaCreationResult(CharaCreationResultEnum.GAME_SMSG_CHRCREATE_E_NAME_BADCHAR).ToPacket());
                return;
            }

            uint repeat_slot_count = await DatabaseManager.SelectCountAsync($@"SELECT COUNT(id) AS COUNT FROM Chara WHERE 'account_id' = {session.AccountID} AND 'Slot' = {cci.chara_slot}");

            if (repeat_slot_count > 0)
            {
                session.Send(new CharaCreationResult(CharaCreationResultEnum.GAME_SMSG_CHRCREATE_E_ALREADY_SLOT).ToPacket());
                return;
            }

            uint repeat_name_count = await DatabaseManager.SelectCountAsync("Name", $@"'{cci.chara_name}'", "Chara", "id");

            if (repeat_name_count > 0)
            {
                session.Send(new CharaCreationResult(CharaCreationResultEnum.GAME_SMSG_CHRCREATE_E_NAME_CONFLICT).ToPacket());
                return;
            }
            #endregion

            #region insert chara info
            Dictionary <string, object> charaInsertDict = new Dictionary <string, object>();
            charaInsertDict.Add("account_id", session.AccountID);
            charaInsertDict.Add("Slot", cci.chara_slot);
            charaInsertDict.Add("Name", cci.chara_name);
            charaInsertDict.Add("Race", cci.race);
            charaInsertDict.Add("Sex", cci.sex);
            charaInsertDict.Add("HairStyle", cci.hair);
            charaInsertDict.Add("HairColor", cci.hair_color);
            charaInsertDict.Add("Face", cci.face);
            charaInsertDict.Add("Map", 10999000); //start map

            if (await DatabaseManager.InsertAsync("Chara", charaInsertDict) <= 0)
            {
                session.Send(new CharaCreationResult(CharaCreationResultEnum.GAME_SMSG_CHRCREATE_E_ERROR).ToPacket());
                return;
            }

            #region  insert default equipments for the chara

            uint chara_id = await DatabaseManager.SelectAsync($@"SELECT id FROM Chara WHERE account_id = {session.AccountID} AND Slot = {cci.chara_slot}");

            if (chara_id == 0)
            {
                Logger.Error("Get chara id error.");
            }

            SingleCharaEquipmentSelectionInfoExt scesi           = new SingleCharaEquipmentSelectionInfoExt(chara_id);
            Dictionary <string, object>          equipInsertDict = new Dictionary <string, object>();

            equipInsertDict.Add("id", chara_id);
            // Head
            equipInsertDict.Add("Head", scesi.Head);
            // Headacce
            equipInsertDict.Add("Headacce", scesi.Headacce);
            // Face
            equipInsertDict.Add("Face", scesi.Face);
            //Faceacce
            equipInsertDict.Add("Faceacce", scesi.Faceacce);
            //Chestacce
            equipInsertDict.Add("Chestacce", scesi.Chestacce);
            //Tops
            equipInsertDict.Add("Top", scesi.Top);
            //Bottoms
            equipInsertDict.Add("Bottom", scesi.Bottom);
            //Backpack
            equipInsertDict.Add("Backpack", scesi.Backpack);
            //Right
            equipInsertDict.Add("Right", scesi.Right);
            //Left
            equipInsertDict.Add("Left", scesi.Left);
            //Shoes
            equipInsertDict.Add("Shoes", scesi.Shoes);
            //Socks
            equipInsertDict.Add("Socks", scesi.Socks);
            //Pet
            equipInsertDict.Add("Pet", scesi.Pet);
            //Effect
            equipInsertDict.Add("Effect", scesi.Effect);

            if (await DatabaseManager.InsertAsync("Equip", equipInsertDict) <= 0)
            {
                Logger.Error("Insert Equip failed.");
            }

            #endregion
            #endregion

            //send success message
            session.Send(new CharaCreationResult(CharaCreationResultEnum.GAME_SMSG_CHRCREATE_SUCCESS).ToPacket());
        }