//////////////////////////////////////////////////////////////////////////////
// 이 패킷은 클라이언트가 아이디와 패스워드를 암호화해서 
// 로그인 서버로 전송한다. 로그인 서버는 이 패킷을 받아서
// 플레이어의 아이디와 패스워드가 정확한지 DB로부터 읽어서
// 비교한 후, 로그인의 성공 여부를 전송한다.
//////////////////////////////////////////////////////////////////////////////
void CLAgreementHandler::execute (CLAgreement* pPacket , Player* pPlayer)
	 throw(ProtocolException , Error)
{
	__BEGIN_TRY __BEGIN_DEBUG_EX
		
#ifdef __LOGIN_SERVER__
#ifdef __NETMARBLE_SERVER__

	Assert(pPacket != NULL);
	Assert(pPlayer != NULL);

	LoginPlayer* pLoginPlayer = dynamic_cast<LoginPlayer*>(pPlayer);
	Assert(pLoginPlayer != NULL);

	if (pPacket->isAgree() )
	{
		Statement*   pStmt        = NULL;

		BEGIN_DB
		{
			//----------------------------------------------------------------------
			// 넷마블 약관 미동의 리스트에서 삭제
			//----------------------------------------------------------------------
			pStmt   = g_pDatabaseManager->getConnection("DARKEDEN")->createStatement();
			pStmt->executeQuery("DELETE FROM PrivateAgreementRemain WHERE PlayerID = '%s'", pLoginPlayer->getID().c_str());

			// 다음 단계로 진행할 수 있게 설정
			pLoginPlayer->setAgree(true);

			SAFE_DELETE(pStmt);
		}
		END_DB(pStmt)
	}
Exemple #2
0
BOOL LoginPlayerManager::ProcessInputs( )
{
    __ENTER_FUNCTION

    BOOL ret = FALSE ;

    if (m_MinFD == INVALID_SOCKET && m_MaxFD == INVALID_SOCKET) // no player exist
    {
        return TRUE ;
    }

    //新连接接入:
    if( FD_ISSET(m_SocketID,&m_ReadFDs[SELECT_USE]) )
    {
        for( INT i=0; i<ACCEPT_ONESTEP; i++ )
        {
            if( !AcceptNewConnection() )
                break;
        }
    }

    //数据读取
    uint nPlayerCount = GetPlayerNumber() ;
    for( uint i=0; i<nPlayerCount; i++ )
    {
        if( m_pPlayers[i]==INVALID_ID )
            continue ;

        LoginPlayer* pPlayer = g_pPlayerPool->GetPlayer(m_pPlayers[i]) ;
        Assert( pPlayer ) ;

        SOCKET s = pPlayer->GetSocket()->getSOCKET() ;
        if( s == m_SocketID )
            continue ;

        if( pPlayer->GetSocket()->isSockError() )
        {   //连接出现错误
            RemovePlayer( pPlayer ) ;
        }
        else if( FD_ISSET( s, &m_ReadFDs[SELECT_USE] ) )
        {   //连接正常
            _MY_TRY
            {
                ret = pPlayer->ProcessInput( ) ;
                if( !ret )
                {
                    RemovePlayer( pPlayer ) ;
                }
            }
            _MY_CATCH
            {
                RemovePlayer( pPlayer ) ;
            }
        }
    }
Exemple #3
0
bool LoginPlayerManager::ProcessOutputs( )
{
__ENTER_FUNCTION

	bool ret = false ;

	if (m_MinFD == INVALID_SOCKET && m_MaxFD == INVALID_SOCKET) // no player exist
	{ 
		return true ;
	}

	//数据发送
	uint32_t nPlayerCount = GetPlayerNumber() ;
	for( uint32_t i=0; i<nPlayerCount; i++ )
	{
		if( m_pPlayers[i]==INVALID_ID )
			continue ;

		LoginPlayer* pPlayer = g_pPlayerPool->GetPlayer(m_pPlayers[i]) ;
		Assert( pPlayer ) ;

		SOCKET s = pPlayer->GetSocket().getSOCKET() ;
		if( s == m_SocketID )
			continue ;

		if( FD_ISSET( s, &m_WriteFDs[SELECT_USE] ) )
		{
			if( pPlayer->GetSocket().isSockError() )
			{//连接出现错误
				RemovePlayer( pPlayer ) ;
			}
			else
			{//连接正常
				_MY_TRY
				{
					ret = pPlayer->ProcessOutput( ) ;
					if( !ret )
					{
						RemovePlayer( pPlayer ) ;
					}
				}
				_MY_CATCH
				{
					RemovePlayer( pPlayer ) ;
				}
			}
		}
	}

	return true ;

__LEAVE_FUNCTION

	return false ;
}
BOOL LoginPlayerManager::ProcessOutputs()
{
    __ENTER_FUNCTION

        BOOL ret = FALSE ;

        if ( INVALID_SOCKET == m_MinFD && INVALID_SOCKET == m_MaxFD ) // no player exist
        { 
            return TRUE ;
        }

        //数据发送
        UINT nPlayerCount = GetPlayerNumber() ;
        for ( UINT i=0 ; i<nPlayerCount ; i++ )
        {
            if ( INVALID_ID == m_pPlayers[ i ] ) continue ;

            LoginPlayer* pPlayer = g_pPlayerPool->GetPlayer( m_pPlayers[ i ] ) ;
            Assert( pPlayer ) ;

            SOCKET s = pPlayer->GetSocket()->getSOCKET() ;
            if ( s == m_SocketID ) continue ;

            if ( FD_ISSET( s, &m_WriteFDs[ SELECT_USE ] ) )
            {
                if( pPlayer->GetSocket()->isSockError() )
                {//连接出现错误
                    RemovePlayer( pPlayer ) ;
                }
                else
                {//连接正常
                    _MY_TRY
                    {
                        ret = pPlayer->ProcessOutput() ;
                        if ( !ret )
                        {
                            RemovePlayer( pPlayer ) ;
                        }
                    }
                    _MY_CATCH
                    {
                        RemovePlayer( pPlayer ) ;
                    }
                }
            }
        }

        return TRUE ;

    __LEAVE_FUNCTION

        return FALSE ;
}
//////////////////////////////////////////////////////////////////////////////
// 클라이언트가 PC 의 리스트를 달라고 요청해오면, 로그인 서버는 DB로부터
// PC들의 정보를 로딩해서 LCPCList 패킷에 담아서 전송한다.
//////////////////////////////////////////////////////////////////////////////
void CLChangeServerHandler::execute (CLChangeServer* pPacket , Player* pPlayer)
	 throw(ProtocolException , Error)
{
	__BEGIN_TRY __BEGIN_DEBUG_EX

#ifdef __LOGIN_SERVER__

	Assert(pPacket != NULL);
	Assert(pPlayer != NULL);

	LoginPlayer* pLoginPlayer = dynamic_cast<LoginPlayer*>(pPlayer);

	ServerGroupID_t CurrentServerGroupID = pPacket->getServerGroupID();
	pLoginPlayer->setServerGroupID(CurrentServerGroupID);

	Statement* pStmt       = NULL;

	try
	{
		pStmt    = g_pDatabaseManager->getConnection("DARKEDEN" )->createStatement();	

		//----------------------------------------------------------------------
		// 이제 LCPCList 패킷을 만들어서 보내자
		//----------------------------------------------------------------------
		LCPCList lcPCList;

		pLoginPlayer->makePCList(lcPCList);
		pLoginPlayer->sendPacket(&lcPCList);
		pLoginPlayer->setPlayerStatus(LPS_PC_MANAGEMENT);

		pStmt->executeQuery("UPDATE Player set CurrentServerGroupID = %d WHERE PlayerID = '%s'", (int)pPacket->getServerGroupID(), pLoginPlayer->getID().c_str());

		// 쿼리 결과 및 쿼리문 객체를 삭제한다.
		SAFE_DELETE(pStmt);
	}
	catch (SQLQueryException & sce) 
	{
		//cout << sce.toString() << endl;

		// 쿼리 결과 및 쿼리문 객체를 삭제한다.
		SAFE_DELETE(pStmt);

		throw DisconnectException(sce.toString());
	}

#endif

	__END_DEBUG_EX __END_CATCH
}
void CLCreatePCHandler::execute (CLCreatePC* pPacket , Player* pPlayer)
	 throw(ProtocolException , Error)
{
	__BEGIN_TRY __BEGIN_DEBUG_EX

#ifdef __LOGIN_SERVER__

	Assert(pPacket != NULL);
	Assert(pPlayer != NULL);

	LoginPlayer*    pLoginPlayer = dynamic_cast<LoginPlayer*>(pPlayer);
	Statement*      pStmt        = NULL;
	Result*         pResult      = NULL;
	LCCreatePCError lcCreatePCError;
	WorldID_t		WorldID      = pLoginPlayer->getWorldID();

#ifdef __CONNECT_CBILLING_SYSTEM__
	if (pLoginPlayer->isCBillingVerified() )
	{
		if (!pLoginPlayer->isPayPlayer() )
		{
			lcCreatePCError.setErrorID(CANNOT_CREATE_PC_BILLING);
			pLoginPlayer->sendPacket(&lcCreatePCError);
			return;
		}
	}
	else
	{
		lcCreatePCError.setErrorID(CANNOT_AUTHORIZE_BILLING);
		pLoginPlayer->sendPacket(&lcCreatePCError);
		return;
	}
#endif

	try
	{
		pStmt = g_pDatabaseManager->getConnection((TID)WorldID )->createStatement();

		// 시스템에서 사용하거나, 금지된 이름은 아닌기 검증한다.
		// NONE, ZONE***, INV***, QUICK...
		//string text = pPacket->getName();

		if (!isAvailableID(pPacket->getName().c_str() ))
		{
			lcCreatePCError.setErrorID(ALREADY_REGISTER_ID);
			throw DuplicatedException("이미 존재하는 아이디입니다.");
		}

		/*
		list<string>::const_iterator itr = InvalidTokenList.begin();
		for (; itr != InvalidTokenList.end(); itr++)
		{
			if (text.find(*itr) != string::npos)
			{
				lcCreatePCError.setErrorID(ALREADY_REGISTER_ID);
				throw DuplicatedException("이미 존재하는 아이디입니다.");
			}
		}
		*/
#if defined(__THAILAND_SERVER__) || defined(__CHINA_SERVER__)

        /*
         * 태국어 문자셋 tis620 thailand charset 에서 허용하는 문자만을 케릭터 이름으로
         * 쓸 수 있도록 제어한다.
         *
         * */

         /*
         * 중국어 문자코드셋 gb2312-simple chinese 에서 허용하는 문자만을 케릭터 이름으로
         * 쓸 수 있도록 제어한다.
         *
         * */

       string tmpStr = pPacket->getName();
        bool isAllowStr = isAllowString(tmpStr);

        if(isAllowStr == false)
        {
            lcCreatePCError.setErrorID(ETC_ERROR);
            throw DuplicatedException("허용하지 않는 문자가 포함되어 있음");

        }

#endif



		// 이미 존재하는 캐릭터 이름이 아닌지 검증한다.
		///*
		pResult = pStmt->executeQuery("SELECT Name FROM Slayer WHERE Name = '%s'", pPacket->getName().c_str());
		if (pResult->getRowCount() != 0)
		{
			lcCreatePCError.setErrorID(ALREADY_REGISTER_ID);
			throw DuplicatedException("이미 존재하는 아이디입니다.");
		}

		// 해당 슬랏에 캐릭터가 이미 있지는 않은지 검증한다.
		pResult = pStmt->executeQuery("SELECT Name FROM Slayer WHERE PlayerID ='%s' and Slot ='%s' AND Active='ACTIVE'", pLoginPlayer->getID().c_str(), Slot2String[pPacket->getSlot()].c_str());
		if (pResult->getRowCount() != 0)
		{
			lcCreatePCError.setErrorID(ALREADY_REGISTER_ID);
			throw DuplicatedException("이미 존재하는 아이디입니다.");
		}
		//*/
		// 두 쿼리를 하나로. 2002. 7. 13 by sigi. 이거 안좋다. - -;
		/*
		pResult = pStmt->executeQuery("SELECT Name FROM Slayer WHERE Name='%s' OR PlayerID='%s' AND Slot='%s'",
											pPacket->getName().c_str(),
											pLoginPlayer->getID().c_str(),
											Slot2String[pPacket->getSlot()].c_str());

		if (pResult->getRowCount() != 0)
		{
			lcCreatePCError.setErrorID(ALREADY_REGISTER_ID);
			throw DuplicatedException("이미 존재하는 아이디입니다.");
		}
		*/


		// 잘못된 능력치를 가지고 캐릭터를 생성하려 하는 것은 아닌지 검증한다.


		bool bInvalidAttr = false;
		int  nSTR         = pPacket->getSTR();
		int  nSTRExp      = 0;
		int  nSTRGoalExp  = 0;
		int  nDEX         = pPacket->getDEX();
		int  nDEXExp      = 0;
		int  nDEXGoalExp  = 0;
		int  nINT         = pPacket->getINT();
		int  nINTExp      = 0;
		int  nINTGoalExp  = 0;

		//int  Rank         = 1;
		//int  RankExp      = 0;

		//
		static int  RankGoalExpSlayer  = -1;
		static int  GoalExpVampire  = -1;	// by sigi. 2002.12.20
		static int  RankGoalExpVampire  = -1;
		static int  GoalExpOusters = -1;
		static int  RankGoalExpOusters = -1;

		if (RankGoalExpSlayer==-1)
		{
			pResult = pStmt->executeQuery("SELECT GoalExp FROM RankEXPInfo WHERE Level=1 AND RankType=0");
			if (pResult->next()) RankGoalExpSlayer = pResult->getInt(1);
		}

		if (GoalExpVampire==-1)	// by sigi. 2002.12.20
		{
			pResult = pStmt->executeQuery("SELECT GoalExp FROM VampEXPBalanceInfo WHERE Level=1");
			if (pResult->next()) GoalExpVampire = pResult->getInt(1);
		}

		if (GoalExpOusters==-1)
		{
			pResult = pStmt->executeQuery("SELECT GoalExp FROM OustersEXPBalanceInfo WHERE Level=1");
			if (pResult->next()) GoalExpOusters = pResult->getInt(1);
		}

		if (RankGoalExpVampire==-1)
		{
			pResult = pStmt->executeQuery("SELECT GoalExp FROM RankEXPInfo WHERE Level=1 AND RankType=1");
			if (pResult->next()) RankGoalExpVampire = pResult->getInt(1);
		}

		if (RankGoalExpOusters==-1)
		{
			pResult = pStmt->executeQuery("SELECT GoalExp FROM RankEXPInfo WHERE Level=1 AND RankType=2");
			if (pResult->next()) RankGoalExpOusters = pResult->getInt(1);
		}

		if (pPacket->getRace() == RACE_SLAYER)
		{
			if (nSTR < 5 || nSTR > 20)  bInvalidAttr = true;
			if (nDEX < 5 || nDEX > 20)  bInvalidAttr = true;
			if (nINT < 5 || nINT > 20)  bInvalidAttr = true;
			if (nSTR + nDEX + nINT > 30) bInvalidAttr = true;

			//cout << "Slayer: " << nSTR << ", " << nDEX << ", " << nINT << endl;
		}
		else if (pPacket->getRace() == RACE_VAMPIRE )	// vampire인 경우. 무조건 20. by sigi. 2002.10.31
		{
			if (nSTR != 20
				|| nDEX != 20
				|| nINT != 20)
			{
				bInvalidAttr = true;
			}
			else
			{
				// 정상적인 vampire인 경우
				// Slayer의 능력치를 다시 설정해줘야 한다. -_-;
				// by sigi. 2002.11.7
				nSTR = 5 + rand()%16;	// 5~20
				nDEX = 5 + rand()%(21-nSTR);
				nINT = 30 - nSTR - nDEX;

				pPacket->setSTR(nSTR);
				pPacket->setDEX(nDEX);
				pPacket->setINT(nINT);
			}
			//

			//cout << "Vampire: " << nSTR << ", " << nDEX << ", " << nINT << endl;
		}
		else if (pPacket->getRace() == RACE_OUSTERS )
		{
/*			if (nSTR < 10 ) bInvalidAttr = true;
			if (nDEX < 10 ) bInvalidAttr = true;
			if (nINT < 10 ) bInvalidAttr = true;*/

			if (nSTR < 10 || nDEX < 10 || nINT < 10 )
			{
				filelog("CreatePC.log", "Illegal PC Create [%s:%s] : %u/%u/%u", pPlayer->getID().c_str(), pPacket->getName().c_str(), nSTR, nDEX, nINT);
			}

			if (nSTR + nDEX + nINT != 45 )
				bInvalidAttr = true;
		}

		if (bInvalidAttr)
		{
			SAFE_DELETE(pStmt);
			throw InvalidProtocolException("CLCreatePCHandler::too large character attribute");
		}

		// 모든 검사를 만족했다면 이제 캐릭터를 생성한다.
		ServerGroupID_t CurrentServerGroupID = pPlayer->getServerGroupID();

		// 우헤헤.. 일단 쿼리를 줄일려고 static으로 삽질을 했다.
		// 나중에 아예 로그인 서버 뜰때에 경험치 table들을 loading해 두도록해야할 것이다. 2002.7.13 by sigi
		static int STRGoalExp[100] = { 0, };
		static int STRAccumExp[100] = { 0, };
		static int DEXGoalExp[100] = { 0, };
		static int DEXAccumExp[100] = { 0, };
		static int INTGoalExp[100] = { 0, };
		static int INTAccumExp[100] = { 0, };

		nSTRGoalExp = STRGoalExp[nSTR];
		if (nSTRGoalExp==0)
		{
			pResult = pStmt->executeQuery("SELECT GoalExp FROM STRBalanceInfo WHERE Level = %d", nSTR);
			if (pResult->next()) nSTRGoalExp = STRGoalExp[nSTR] = pResult->getInt(1);
		}

		nSTRExp = STRAccumExp[nSTR-1];
		if (nSTRExp==0)
		{
			pResult = pStmt->executeQuery("SELECT AccumExp FROM STRBalanceInfo WHERE Level = %d", nSTR - 1);
			if (pResult->next()) nSTRExp = STRAccumExp[nSTR-1] = pResult->getInt(1);
		}

		nDEXGoalExp = DEXGoalExp[nDEX];
		if (nDEXGoalExp==0)
		{
			pResult = pStmt->executeQuery("SELECT GoalExp FROM DEXBalanceInfo WHERE Level = %d", nDEX);
			if (pResult->next()) nDEXGoalExp = DEXGoalExp[nDEX] = pResult->getInt(1);
		}

		nDEXExp = DEXAccumExp[nDEX-1];
		if (nDEXExp==0)
		{
			pResult = pStmt->executeQuery("SELECT AccumExp FROM DEXBalanceInfo WHERE Level = %d", nDEX - 1);
			if (pResult->next()) nDEXExp = DEXAccumExp[nDEX-1] = pResult->getInt(1);
		}

		nINTGoalExp = INTGoalExp[nINT];
		if (nINTGoalExp==0)
		{
			pResult = pStmt->executeQuery("SELECT GoalExp FROM INTBalanceInfo WHERE Level = %d", nINT);
			if (pResult->next()) nINTGoalExp = INTGoalExp[nINT] = pResult->getInt(1);
		}

		nINTExp = INTAccumExp[nINT-1];
		if (nINTExp==0)
		{
			pResult = pStmt->executeQuery("SELECT AccumExp FROM INTBalanceInfo WHERE Level = %d", nINT - 1);
			if (pResult->next()) nINTExp = INTAccumExp[nINT-1] = pResult->getInt(1);
		}

		// 일단 복장은 없고.. 남/녀 구분만..
		DWORD slayerShape = (pPacket->getSex()==1? 1 : 0);
		DWORD vampireShape = slayerShape;

		slayerShape |= (pPacket->getHairStyle() << PCSlayerInfo::SLAYER_BIT_HAIRSTYLE1);

		Color_t	HelmetColor = 0;
		Color_t JacketColor = 0;
		Color_t	PantsColor  = 0;
		Color_t	WeaponColor = 0;
		Color_t	ShieldColor = 0;

		/*
		StringStream slayerSQL;
		slayerSQL << "INSERT INTO Slayer ("
			<< " Race, Name, PlayerID, Slot, ServerGroupID, Active,"
			<< " Sex, HairStyle, HairColor, SkinColor, Phone, "
			<< " STR, STRExp, STRGoalExp, DEX, DEXExp, DEXGoalExp, INTE, INTExp, INTGoalExp, HP, CurrentHP, MP, CurrentMP,"
			<< " ZoneID, XCoord, YCoord, Sight, Gold, Alignment,"
			<< " Shape, HelmetColor, JacketColor, PantsColor, WeaponColor, ShieldColor,"
			<< " creation_date) VALUES ('"
			<< "SLAYER" << "', '"
			<< pPacket->getName() << "', '"
			<< pLoginPlayer->getID() << "', '"
			<< Slot2String[pPacket->getSlot()] << "', "
			<< (int)CurrentServerGroupID << " , "
			<< "'ACTIVE', '"
			<< Sex2String[pPacket->getSex()] << "', '"
			<< HairStyle2String[pPacket->getHairStyle()] << "', "
			<< (int)pPacket->getHairColor() << ", "
			<< (int)pPacket->getSkinColor() << ", '"
			<< (int)0 << "', "
			<< (int)pPacket->getSTR() << ", "
			<< nSTRExp << ", "
			<< nSTRGoalExp << ", "
			<< (int)pPacket->getDEX() << ", "
			<< nDEXExp << ", "
			<< nDEXGoalExp << ", "
			<< (int)pPacket->getINT() << ", "
			<< nINTExp << ", "
			<< nINTGoalExp << ", "
			<< (int)pPacket->getSTR()*2 << ","
			<< (int)pPacket->getSTR()*2 << ","
			<< (int)pPacket->getINT()*2 << ","
			<< (int)pPacket->getINT()*2 << ","
			<< "2101, 65, 45, 13, 0, 7500, "
			<< slayerShape << ", "
			<< (int)HelmetColor << ", "
			<< (int)JacketColor << ", "
			<< (int)PantsColor << ", "
			<< (int)WeaponColor << ", "
			<< (int)ShieldColor << ", "
			<< "now() "
			<< ")";

		StringStream vampireSQL;
		vampireSQL << "INSERT INTO Vampire ("
			<< " Name, PlayerID, Slot, ServerGroupID, Active,"
			<< " Sex, HairColor, SkinColor,"
			<< " STR, DEX, INTE, HP, CurrentHP,"
			<< " ZoneID, XCoord, YCoord, Sight, Alignment, Exp, GoalExp, Shape) VALUES ('"
			<< pPacket->getName() << "', '"
			<< pLoginPlayer->getID() << "', '"
			<< Slot2String[pPacket->getSlot()] << "', "
			<< (int)CurrentServerGroupID << " , "
			<< "'ACTIVE', '"
			<< Sex2String[pPacket->getSex()] << "', "
			<< (int)pPacket->getHairColor() << ", "
			<< (int)pPacket->getSkinColor() << ", "
			<< "20, 20, 20, 50, 50, "
			<< "2020, 233, 55, 13, 7500, 0, 125, "
			<< vampireShape
			<< ")";

		pStmt->executeQuery(slayerSQL.toString());
		pStmt->executeQuery(vampireSQL.toString());
		*/

		// 캐릭터 생성시에 뱀파이어를 선택할 수 있다.
		// by sigi. 2002.10.31
		string race;
		switch (pPacket->getRace() )
		{
			case RACE_SLAYER:
				race = "SLAYER";
				break;
			case RACE_VAMPIRE:
				race = "VAMPIRE";
				break;
			case RACE_OUSTERS:
				race = "OUSTERS";
				break;
			default:
				lcCreatePCError.setErrorID(ETC_ERROR);
				pLoginPlayer->sendPacket(&lcCreatePCError); // 클라이언트에게 PC 생성 실패 패킷을 날린다.
				return;
		}

		pStmt->executeQuery(
				"INSERT INTO Slayer (Race, Name, PlayerID, Slot, ServerGroupID, Active, Sex, HairStyle, HairColor, SkinColor, Phone, STR, STRExp, STRGoalExp, DEX, DEXExp, DEXGoalExp, INTE, INTExp, INTGoalExp, Rank, RankExp, RankGoalExp, HP, CurrentHP, MP, CurrentMP, ZoneID, XCoord, YCoord, Sight, Gold, Alignment, Shape, HelmetColor, JacketColor, PantsColor, WeaponColor, ShieldColor, creation_date) VALUES ('%s', '%s', '%s', '%s', %d, 'ACTIVE', '%s', '%s', %d, %d, 0, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, 12, 237, 138, 13, 0, 7500, %d, %d, %d, %d, %d, %d, now())",
				race.c_str(),
				pPacket->getName().c_str(),
				pLoginPlayer->getID().c_str(),
				Slot2String[pPacket->getSlot()].c_str(),
				(int)CurrentServerGroupID,
				Sex2String[pPacket->getSex()].c_str(),
				HairStyle2String[pPacket->getHairStyle()].c_str(),
				(int)pPacket->getHairColor(),
				(int)pPacket->getSkinColor(),
				(int)pPacket->getSTR(), nSTRExp, nSTRGoalExp,
				(int)pPacket->getDEX(), nDEXExp, nDEXGoalExp,
				(int)pPacket->getINT(), nINTExp, nINTGoalExp,
				1, 0, RankGoalExpSlayer,
				(int)pPacket->getSTR()*2,
				(int)pPacket->getSTR()*2,
				(int)pPacket->getINT()*2,
				(int)pPacket->getINT()*2,
				slayerShape,
				(int)HelmetColor,
				(int)JacketColor,
				(int)PantsColor,
				(int)WeaponColor,
				(int)ShieldColor);

		// 생성 위치 변경. by sigi. 2002.10.31
		// 아우스터스로의 종족간 변신이 없으므로 둘중에 하나만 만든다.
		// 근데 왠지 종족간 변신이 들어갈지도 모른다는 불길한 예간이 들고
		// 항상 그런 예감들은 맞아 왔기때문에 언젠가 이 주석을 보고 둘다 풀어주는게....으아~~
		if ( pPacket->getRace() != RACE_OUSTERS )
		{
			pStmt->executeQuery(
					"INSERT INTO Vampire (Name, PlayerID, Slot, ServerGroupID, Active, Sex, SkinColor, STR, DEX, INTE, HP, CurrentHP, ZoneID, XCoord, YCoord, Sight, Alignment, Exp, GoalExp, Rank, RankExp, RankGoalExp, Shape, CoatColor) VALUES ('%s', '%s', '%s', %d, 'ACTIVE', '%s', %d, 20, 20, 20, 50, 50, 1003, 62, 64, 13, 7500, 0, %d, 1, 0, %d, %d, 377 )",
					pPacket->getName().c_str(),
					pLoginPlayer->getID().c_str(),
					Slot2String[pPacket->getSlot()].c_str(),
					(int)CurrentServerGroupID,
					Sex2String[pPacket->getSex()].c_str(),
					(int)pPacket->getSkinColor(),
					GoalExpVampire,	// by sigi. 2002.12.20
					RankGoalExpVampire,
					vampireShape);
		} else
		{
			pStmt->executeQuery(
					"INSERT INTO Ousters (Name, PlayerID, Slot, ServerGroupID, Active, Sex, STR, DEX, INTE, BONUS, HP, CurrentHP, MP, CurrentMP, ZoneID, XCoord, YCoord, Sight, Alignment, Exp, GoalExp, Rank, RankExp, RankGoalExp, CoatColor, HairColor, ArmColor, BootsColor ) Values ('%s', '%s', '%s', %d, 'ACTIVE', 'FEMALE', %d, %d, %d, 0, 50, 50, 50, 50, 1311, 24, 73, 13, 7500, 0, %d, 1, 0,	%d, 377, %d, 377, 377 )",
					pPacket->getName().c_str(),
					pLoginPlayer->getID().c_str(),
					Slot2String[pPacket->getSlot()].c_str(),
					(int)CurrentServerGroupID,
					(int)pPacket->getSTR(),
					(int)pPacket->getDEX(),
					(int)pPacket->getINT(),
					GoalExpOusters,
					RankGoalExpOusters,
					(int)pPacket->getHairColor());
		}

		if (pPacket->getRace()==RACE_SLAYER)
		{
			pStmt->executeQuery("INSERT IGNORE INTO FlagSet (OwnerID, FlagData) VALUES ('%s','11110010001')", pPacket->getName().c_str());
		}
		else
		{
			pStmt->executeQuery("INSERT IGNORE INTO FlagSet (OwnerID, FlagData) VALUES ('%s','00000000001')", pPacket->getName().c_str());
		}

		// 클라이언트에게 PC 생성 성공 패킷을 날린다.
		LCCreatePCOK lcCreatePCOK;
		pLoginPlayer->sendPacket(&lcCreatePCOK);
		pLoginPlayer->setPlayerStatus(LPS_WAITING_FOR_CL_GET_PC_LIST);

		SAFE_DELETE(pStmt);
	}
	catch (DuplicatedException & de)
	{
		SAFE_DELETE(pStmt);
		pLoginPlayer->sendPacket(&lcCreatePCError); // 클라이언트에게 PC 생성 실패 패킷을 날린다.
	}
	catch (SQLQueryException & sqe)
	{
		SAFE_DELETE(pStmt);
		lcCreatePCError.setErrorID(ETC_ERROR);
		pLoginPlayer->sendPacket(&lcCreatePCError); // 클라이언트에게 PC 생성 실패 패킷을 날린다.
	}

#endif

	__END_DEBUG_EX __END_CATCH
}
//////////////////////////////////////////////////////////////////////////////
// 클라이언트가 서버의 리스트를 달라고 요청해오면, 로그인 서버는 DB로부터
// 서버들의 정보를 로딩해서 LCServerList 패킷에 담아서 전송한다.
//////////////////////////////////////////////////////////////////////////////
void CLGetServerListHandler::execute (CLGetServerList* pPacket , Player* pPlayer)
	 throw(ProtocolException , Error)
{
	__BEGIN_TRY __BEGIN_DEBUG_EX

#ifdef __LOGIN_SERVER__

	Assert(pPacket != NULL);
	Assert(pPlayer != NULL);
	//cout << "Start execute" << endl;

	LoginPlayer* pLoginPlayer = dynamic_cast<LoginPlayer*>(pPlayer);

	WorldID_t WorldID = pLoginPlayer->getWorldID();

	try 
	{
		int GroupNum = g_pGameServerGroupInfoManager->getSize(WorldID);

		//cout << "ServerNum : " << GroupNum << endl;

		ServerGroupInfo* aServerGroupInfo[GroupNum];

		for(int i = 0 ; i < GroupNum; i++) 
		{
			ServerGroupInfo* pServerGroupInfo = new ServerGroupInfo();
			GameServerGroupInfo* pGameServerGroupInfo = g_pGameServerGroupInfoManager->getGameServerGroupInfo(i, WorldID);
			pServerGroupInfo->setGroupID(pGameServerGroupInfo->getGroupID());
			pServerGroupInfo->setGroupName(pGameServerGroupInfo->getGroupName());
			pServerGroupInfo->setStat(SERVER_FREE);

			UserInfo * pUserInfo = g_pUserInfoManager->getUserInfo(pGameServerGroupInfo->getGroupID(), WorldID);


			WORD UserModify = 800;
			WORD UserMax = 1500;

			if (pUserInfo->getUserNum() < 100 + UserModify )
			{
				pServerGroupInfo->setStat(SERVER_FREE);
			}
			else if (pUserInfo->getUserNum() < 250 + UserModify )
			{
				pServerGroupInfo->setStat(SERVER_NORMAL);
			}
			else if (pUserInfo->getUserNum() < 400 + UserModify )
			{
				pServerGroupInfo->setStat(SERVER_BUSY);
			}
			else if (pUserInfo->getUserNum() < 500 + UserModify )
			{
				pServerGroupInfo->setStat(SERVER_VERY_BUSY);
			}
			else //if (pUserInfo->getUserNum() >= 500 + UserModify )
			{
				pServerGroupInfo->setStat(SERVER_FULL);
			}
			//else
			{
			//pServerGroupInfo->setStat(SERVER_DOWN);
			}

			if (pUserInfo->getUserNum() >= UserMax)
			{
				pServerGroupInfo->setStat(SERVER_FULL);
			}
			
			if (pGameServerGroupInfo->getStat() == SERVER_DOWN )
			{
				pServerGroupInfo->setStat(SERVER_DOWN);
			}

			aServerGroupInfo[i] = pServerGroupInfo;

			//cout << "AddServer : " << pServerGroupInfo->getGroupName() << endl;
		}

		LCServerList lcServerList;

		Statement * pStmt = NULL;

		BEGIN_DB
		{
			pStmt = g_pDatabaseManager->getConnection("DARKEDEN")->createStatement();

			Result * pResult = pStmt->executeQuery("SELECT CurrentWorldID, CurrentServerGroupID FROM Player where PlayerID='%s'" , pLoginPlayer->getID().c_str());

			if(pResult->next() ) {
				lcServerList.setCurrentServerGroupID(pResult->getInt(1));
				lcServerList.setCurrentServerGroupID(pResult->getInt(2));
			}

			SAFE_DELETE(pStmt);	// by sigi
		}
		END_DB(pStmt)	// by sigi

		for(int k = 0; k < GroupNum; k++) 
		{
			lcServerList.addListElement(aServerGroupInfo[k]);
		}

		pLoginPlayer->sendPacket(&lcServerList);
	
		pLoginPlayer->setPlayerStatus(LPS_PC_MANAGEMENT);
	} 
	catch (Throwable & t) 
	{
		//cout << t.toString() << endl;
	}
	//cout << "End execute" << endl;

#endif

	__END_DEBUG_EX __END_CATCH
}
UINT    CLAskCharListHandler::Execute(CLAskCharList* pPacket, Player* pPlayer )
{
    __ENTER_FUNCTION
    
    TID CurrentThreadID = MyGetCurrentThreadID();
    
    //检查线程执行资源是否正确
    if(CurrentThreadID == g_pProcessPlayerManager->m_ThreadID) 
    {    
        LoginPlayer* pLoginPlayer = static_cast<LoginPlayer*>(pPlayer);
        Assert(pLoginPlayer);

        if( !StrSafeCheck( pPacket->GetAccount(), MAX_ACCOUNT ) )
        {
            Log::SaveLog(LOGIN_LOGFILE, "ERROR: CLAskCharListHandler Get IllegalString,acc = %s",
                pLoginPlayer->GetAccount()) ;
            return PACKET_EXE_ERROR;
        }

        //检查GUID 是否正确
        if(strcmp(pLoginPlayer->GetAccount(),pPacket->GetAccount())!= 0)
        {
            Log::SaveLog(LOGIN_LOGFILE, "ERROR: CLAskCharListHandler Get Guid Errors,acc = %s,Packet acc = %s",
                pLoginPlayer->GetAccount(),pPacket->GetAccount()) ;
            return PACKET_EXE_ERROR;
        }

        UINT uTime = g_pTimeManager->CurrentTime();

        if(uTime<pLoginPlayer->m_LastDBOpTime+DB_OPERATION_TIME)
        {
            LCRetCharList Msg;
            Msg.SetResult(ASKCHARLIST_OP_TIMES);
            pLoginPlayer->SendPacket(&Msg);
            return PACKET_EXE_CONTINUE;
        }

        if(pLoginPlayer->GetPlayerStatus()!=PS_LOGIN_NORMAL)
        {
            return PACKET_EXE_CONTINUE;
        }

        pPacket->SetPlayerID(pLoginPlayer->PlayerID());
        //将玩家操作加入DB 队列
        //并且设置最后操作时间

        if(g_pDBThreadManager->SendPacket(pPacket,pLoginPlayer->PlayerID()))
        {//加入成功,将消息发送到DB处理
            pLoginPlayer->m_LastDBOpTime = uTime;
            return PACKET_EXE_NOTREMOVE;    
        }
        else
        {//DB 压力过大,让用户重新尝试
            LCRetCharList Msg;
            Msg.SetResult(ASKCHARLIST_SERVER_BUSY);
            pLoginPlayer->SendPacket(&Msg);
            pLoginPlayer->m_LastDBOpTime = uTime;
            return PACKET_EXE_CONTINUE;
        }
        
    }
    else if(g_pDBThreadManager->IsPoolTID(CurrentThreadID))
    {


        PlayerID_t    PlayerID    = pPacket->GetPlayerID();
        LoginPlayer* pLoginPlayer = static_cast<LoginPlayer*>(pPlayer);
        Assert(pLoginPlayer);
        LCRetCharList* pMsg = (LCRetCharList*)g_pPacketFactoryManager->CreatePacket(PACKET_LC_RETCHARLIST)    ;
        if(!pMsg)
        {   //不能进行操作
            AssertEx(FALSE,"创建 LCRetCharList 消息失败");

        }
        if(pLoginPlayer->GetDBOperating() == TRUE||!g_pDBThreadManager->GetInterface(CurrentThreadID)->IsConnected())
        {
            pMsg->SetAccount(pPacket->GetAccount());
            pMsg->SetResult(ASKCHARLIST_SERVER_BUSY);
            pMsg->SetCharNumber(0);
            g_pProcessManager->SendPacket(pMsg,PlayerID);
            Log::SaveLog(LOGIN_LOGFILE, "CLAskCharListHandler::Execute()....数据库操作冲突 ,Acc = %s",
                pLoginPlayer->GetAccount()) ;
            return PACKET_EXE_CONTINUE;
        }

        //检查GUID 是否正确
        if(strcmp(pLoginPlayer->GetAccount(),pPacket->GetAccount())!= 0)
        {
            //应该是一次错误操作
            Log::SaveLog(LOGIN_LOGFILE, "ERROR: CLAskCharListHandler DBOperation Errors,acc = %s,Packet acc = %s",
                pLoginPlayer->GetAccount(),pPacket->GetAccount()) ;
            return PACKET_EXE_CONTINUE;
        }


        pLoginPlayer->SetDBOperating(TRUE);

        ODBCInterface*    pInterface = g_pDBThreadManager->GetInterface(CurrentThreadID);
        Assert(pInterface);
        DBCharList    CharListObject(pInterface);
        CharListObject.SetAccount(pPacket->GetAccount());
        
        BOOL bLoadRet = CharListObject.Load();
        if(!bLoadRet)
        {
            Log::SaveLog(LOGIN_LOGFILE,"CharListObject.Load() ... Get Errors: %s",
                CharListObject.GetErrorMessage());
            pMsg->SetAccount(pPacket->GetAccount());
            pMsg->SetResult(ASKCHARLIST_OP_FAILS);
            pMsg->SetCharNumber(0);
            g_pProcessManager->SendPacket(pMsg,PlayerID);
            Log::SaveLog( LOGIN_LOGFILE, "CLAskCharListHandler::Execute()....Fails!,code = ASKCHARLIST_OP_FAILS" ) ;
            
            pLoginPlayer->SetDBOperating(FALSE);
            return PACKET_EXE_CONTINUE;
        }
        //取结果
        CharListObject.ParseResult(pMsg->GetCharBaseInfo()); 

        //判断是否没有进入过场景
        INT iCharNumber = CharListObject.GetCharNumber();
    
        //把参数设置到pMsg
        pMsg->SetAccount(pPacket->GetAccount());
        pMsg->SetResult(ASKCHARLIST_SUCCESS);
        pMsg->SetCharNumber(iCharNumber);
        pLoginPlayer->SetCharNumber(iCharNumber);
        for(INT i=0;i<pLoginPlayer->GetCharNumber();i++)
        {
            pLoginPlayer->SetCharGUID(pMsg->GetCharBaseInfo(i)->m_GUID,i);
            pLoginPlayer->SetPlayerCamp( pMsg->GetCharBaseInfo(i)->m_Camp );
        }
        g_pProcessManager->SendPacket(pMsg,PlayerID);
        
        pLoginPlayer->SetDBOperating(FALSE);

        Log::SaveLog( LOGIN_LOGFILE, "CLAskCharListHandler::Execute()....OK! Acc=%s CharNum=%d",
            pPacket->GetAccount(), pLoginPlayer->GetCharNumber() ) ;
    }


    
    
    return PACKET_EXE_CONTINUE;

    __LEAVE_FUNCTION

    return PACKET_EXE_ERROR;
}
//////////////////////////////////////////////////////////////////////////////
// 클라이언트에서 플레이어 등록 정보를 날릴 경우, 서버에서는 우선
// 현재 아이디가 "guest"인지 체크하고, 최초의 패킷인지 체크한 후,
// 사용자 정보를 DB에 등록하고나서, 연결을 차단한다.
//////////////////////////////////////////////////////////////////////////////
void CLRegisterPlayerHandler::execute (CLRegisterPlayer* pPacket , Player* pPlayer)
throw(ProtocolException , Error)
{
    __BEGIN_TRY __BEGIN_DEBUG_EX

#ifdef __LOGIN_SERVER__

    Assert(pPacket != NULL);
    Assert(pPlayer != NULL);

    __BEGIN_DEBUG

    LoginPlayer* pLoginPlayer = dynamic_cast<LoginPlayer*>(pPlayer);

    //cout << "Registering Player... " << endl;

    //----------------------------------------------------------------------
    // 로그인 플레이어의 아이디가 guest 인지 체크한다.
    //----------------------------------------------------------------------
//	if (pLoginPlayer->getID() != "guest")
//		throw InvalidProtocolException("must be guest user");

    //----------------------------------------------------------------------
    // 플레이어 정보 검증
    // 각 스트링의 길이 및 NULL 여부를 체크한다.
    //----------------------------------------------------------------------
    LCRegisterPlayerError lcRegisterPlayerError;

    try {

        //cout << "플레이어 정보 검증 : " << pPacket->toString() << endl;

        if (pPacket->getID() == "") {
            lcRegisterPlayerError.setErrorID(EMPTY_ID);
            throw string("ID field is empty");
        }

        if (pPacket->getID().size() < 4) {
            lcRegisterPlayerError.setErrorID(SMALL_ID_LENGTH);
            throw string("too small ID length");
        }

        if (pPacket->getPassword() == "")
        {
            lcRegisterPlayerError.setErrorID(EMPTY_PASSWORD);
            throw string("Password field is empty");
        }
        else
        {
            string password = pPacket->getPassword();
            if (password.find("\'") < password.size()) throw string("Invalid Password");
            if (password.find("'") < password.size()) throw string("Invalid Password");
            else if (password.find("\\") < password.size()) throw string("Invalid Password");
            else if (password.find("\"") < password.size()) throw string("Invalid Password");
            else if (password.find(";") < password.size()) throw string("Invalid Password");
        }

        if (pPacket->getPassword().size() < 6) {
            lcRegisterPlayerError.setErrorID(SMALL_PASSWORD_LENGTH);
            throw string("too small password length");
        }

        if (pPacket->getName() == "") {
            lcRegisterPlayerError.setErrorID(EMPTY_NAME);
            throw string("Name field is empty");
        }

        if (pPacket->getSSN() == "") {
            lcRegisterPlayerError.setErrorID(EMPTY_SSN);
            throw string("SSN field is empty");
        }

    } catch (string & errstr) {

        pLoginPlayer->sendPacket(&lcRegisterPlayerError);

        //cout << lcRegisterPlayerError.toString() << endl;

        // 일단 버퍼를 플러시하고, 연결을 차단한다.
        //
        // *TODO*
        // 실패 회수를 저장한 후, 그 회수보다 작은 경우에는 계속 연결을 유지하도록 한다.
        //
        throw DisconnectException(lcRegisterPlayerError.toString());
    }


    //----------------------------------------------------------------------
    // 이제 데이타베이스에 등록하도록 한다.
    //----------------------------------------------------------------------

    Statement* pStmt;
    Result* pResult;

    try {

        pStmt = g_pDatabaseManager->getConnection("DARKEDEN")->createStatement();

        //--------------------------------------------------------------------------------
        // 아이디 중복 여부를 체크한다.
        //--------------------------------------------------------------------------------
        pResult = pStmt->executeQuery("SELECT PlayerID FROM Player WHERE PlayerID = '%s'" , pPacket->getID().c_str());

        if (pResult->getRowCount() != 0) {
            lcRegisterPlayerError.setErrorID(ALREADY_REGISTER_ID);
            throw DuplicatedException("그런 아이디가 이미 존재합니다.");
        }


        //--------------------------------------------------------------------------------
        // 주민등록번호를 검증한다. 나중에.. -_-;
        //--------------------------------------------------------------------------------


        //--------------------------------------------------------------------------------
        // 주민등록번호 중복 여부를 체크한다.
        //--------------------------------------------------------------------------------
        pResult = pStmt->executeQuery("SELECT SSN FROM Player WHERE SSN = '%s'" , pPacket->getSSN().c_str());

        if (pResult->getRowCount() != 0) {
            lcRegisterPlayerError.setErrorID(ALREADY_REGISTER_SSN);
            throw DuplicatedException("이미 등록된 주민등록번호입니다.");
        }


        //--------------------------------------------------------------------------------
        // 플레이어를 등록한다.
        //--------------------------------------------------------------------------------
        pResult = pStmt->executeQuery(
                      "INSERT INTO Player (PlayerID , Password , Name , Sex , SSN , Telephone , Cellular , Zipcode , Address , Nation , Email , Homepage , Profile , Pub) VALUES ('%s' , PASSWORD('%s') , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , %d , '%s' , '%s' , '%s' , '%s')" ,
                      pPacket->getID().c_str() ,
                      pPacket->getPassword().c_str() ,
                      pPacket->getName().c_str() ,
                      Sex2String[ pPacket->getSex() ].c_str() ,
                      pPacket->getSSN().c_str() ,
                      pPacket->getTelephone().c_str() ,
                      pPacket->getCellular().c_str() ,
                      pPacket->getZipCode().c_str() ,
                      pPacket->getAddress().c_str() ,
                      (int)pPacket->getNation() ,
                      pPacket->getEmail().c_str() ,
                      pPacket->getHomepage().c_str() ,
                      pPacket->getProfile().c_str() ,
                      (pPacket->getPublic() == true) ? "PUBLIC" : "PRIVATE"
                  );

        // 여기까지 왔다면, DB에 플레이어가 잘 추가되었다는 의미가 된다.
        // 플레이어에게 등록이 잘 되었다는 LCRegisterPlayerOK 패킷을 보내자.
        Assert(pResult == NULL);
        Assert(pStmt->getAffectedRowCount() == 1);

        // 등록한 후 디폴트 서버의 그룹 아이디를 받아온다.
        pResult = pStmt->executeQuery("SELECT CurrentWorldID, CurrentServerGroupID FROM Player WHERE PlayerID = '%s'" , pPacket->getID().c_str());

        if (pResult->getRowCount() == 0) {
            lcRegisterPlayerError.setErrorID(ETC_ERROR);
            throw SQLQueryException("정상적으로 데이터베이스가 입력, 출력 되지 않았습니다.");
        }

        WorldID_t 		 WorldID = 0;
        ServerGroupID_t  ServerGroupID = 0;

        if (pResult->next()) throw SQLQueryException("데이터베이스에 치명적인 문제가 있습니다.");

        WorldID = pResult->getInt(1);
        ServerGroupID = pResult->getInt(2);

        pLoginPlayer->setServerGroupID(ServerGroupID);

        LCRegisterPlayerOK lcRegisterPlayerOK;

        lcRegisterPlayerOK.setGroupName(g_pGameServerGroupInfoManager->getGameServerGroupInfo(ServerGroupID, WorldID)->getGroupName());

        string SSN = pPacket->getSSN();
        string preSSN;
        bool isChina = false;
        // 한국
        if (strstr(SSN.c_str(), "-") != NULL )
        {
            preSSN = SSN.substr(0, 6);
        }
        // 중국
        else
        {
            isChina = true;
            if (SSN.size() == 15)
            {
                preSSN = SSN.substr(6, 12);
            }
            else if (SSN.size() == 18)
            {
                preSSN = SSN.substr(8, 14);
            }
            else
            {
                // 이런 경우는 없다고 하지만 -_- 머 암튼
                preSSN = SSN.substr(0, 6);
            }
        }
//        string preSSN = pPacket->getSSN().substr(0, 6).c_str();

        StringStream AdultSSN;

        time_t daytime = time(0);
        tm Timec;
        localtime_r(&daytime, &Timec);
        AdultSSN << Timec.tm_year - 20 << Timec.tm_mon << Timec.tm_mday;

        // 성인인지 아닌지 주민등록 번호 체크
        if (atoi(preSSN.c_str()) <= atoi(AdultSSN.toString().c_str())) {
            lcRegisterPlayerOK.setAdult(true);
        } else {
            lcRegisterPlayerOK.setAdult(false);
        }

        // 중국이면 무조건 성인
        if (isChina )
        {
            lcRegisterPlayerOK.setAdult(true);
        }

        pLoginPlayer->sendPacket(&lcRegisterPlayerOK);

        // 이름을 변경해줘야 한다.
        pLoginPlayer->setID(pPacket->getID());

        // 등록에 성공했을 경우, CLGetPCList 패킷을 기다린다.
        pLoginPlayer->setPlayerStatus(LPS_WAITING_FOR_CL_GET_PC_LIST);

        SAFE_DELETE(pStmt);
    }
    catch (DuplicatedException & de)
    {
        SAFE_DELETE(pStmt);

        //cout << de.toString() << endl;

        //--------------------------------------------------------------------------------
        // 등록 실패 패킷을 전송한다.
        //--------------------------------------------------------------------------------
        pLoginPlayer->sendPacket(&lcRegisterPlayerError);

        //--------------------------------------------------------------------------------
        // 실패 회수를 증가시킨다. 너무 많이 실패했을 경우, 연결을 종료한다.
        //--------------------------------------------------------------------------------
        uint nFailed = pLoginPlayer->getFailureCount();

        //cout << pLoginPlayer->getID() << "'s Failure Count = " << ++nFailed << endl;

        if (nFailed > 3)
            throw DisconnectException("too many failure");

        pLoginPlayer->setFailureCount(nFailed);

        // 등록에 실패할 경우, 다시 CLRegisterPlayer 패킷을 기다린다.
        pLoginPlayer->setPlayerStatus(LPS_WAITING_FOR_CL_REGISTER_PLAYER);

    }
    catch (SQLQueryException & sqe)
    {
        SAFE_DELETE(pStmt);

        // 흠. SQL 에러이든지 등록이 잘 안되었다는 소리다.
        //cout << sqe.toString() << endl;

        //--------------------------------------------------------------------------------
        // 등록 실패 패킷을 전송한다.
        //--------------------------------------------------------------------------------
        lcRegisterPlayerError.setErrorID(ETC_ERROR);

        pLoginPlayer->sendPacket(&lcRegisterPlayerError);

        //--------------------------------------------------------------------------------
        // 실패 회수를 증가시킨다. 너무 많이 실패했을 경우, 연결을 종료한다.
        //--------------------------------------------------------------------------------
        uint nFailed = pLoginPlayer->getFailureCount();

        //cout << pLoginPlayer->getID() << "'s Failure Count = " << ++nFailed << endl;

        if (nFailed > 3)
            throw DisconnectException("too many failure");

        pLoginPlayer->setFailureCount(nFailed);

        // 등록에 실패할 경우, 다시 CLRegisterPlayer 패킷을 기다린다.
        pLoginPlayer->setPlayerStatus(LPS_WAITING_FOR_CL_REGISTER_PLAYER);

    }

    __END_DEBUG

#endif

    __END_DEBUG_EX __END_CATCH
}
//////////////////////////////////////////////////////////////////////////////
// CLSelectPCHandler::execute()
//
// ·Î±×ÀÎ ¼­¹ö´Â ÀÌ ÆÐŶÀ» ¹ÞÀ¸¸é, ÁöÁ¤µÈ Name + PCType ¸¦ °¡Áø PC ¸¦ ·ÎµùÇÑ´Ù.°
// ÀÌ PC°¡ Ç÷¹À̾îÀÇ Ä³¸¯ÅͶó¸é ÀÌ PC°¡ ±âÁ¸¿¡ ÀÖ´ø Á¸À» ¾Ë¾Æ³»¼­
// ±× Á¸À» ´ã´çÇÑ °ÔÀÓ ¼­¹ö¿¡°Ô LGIncomingConnection À» Àü¼ÛÇÑ´Ù.
// Á÷ÈÄ Å¬¶óÀ̾ðÆ®¿¡°Ô LCReconnect ÆÐŶÀ» º¸³»¼­, °ÔÀÓ ¼­¹ö·Î ¿¬°áÇϵµ·Ï
// ÇØÁØ´Ù.
//////////////////////////////////////////////////////////////////////////////
void CLSelectPCHandler::execute (CLSelectPC* pPacket , Player* pPlayer)
	 throw(ProtocolException , Error)
{
	__BEGIN_TRY __BEGIN_DEBUG_EX

#ifdef __LOGIN_SERVER__

	Assert(pPacket != NULL);
	Assert(pPlayer != NULL);

	LoginPlayer* pLoginPlayer = dynamic_cast<LoginPlayer*>(pPlayer);

	bool bCheckATTR = false;

	// ·Î±×ÀÎ ¼­¹ö¿¡¼­ billing ¿¬°á ºÎºÐÀ» »©±â·Î ÇÑ´Ù.
    // ¾Öµåºô ¿äû »çÇ×. by bezz 2003.04.22
/*#ifdef __CONNECT_BILLING_SYSTEM__

	// ºô¸µ ½Ã½ºÅÛÀ¸·ÎºÎÅÍ Ã¼Å©¸¦ ¹Þ´Â °æ¿ì
	// by sigi. 2002.11.21
	if (pLoginPlayer->isBillingLoginVerified())
	{
		if (pLoginPlayer->isBillingPlayAvaiable()
			&& pLoginPlayer->getBillingUserStatus()!="XX")
		{
			cout << "isBillingPlay: " << pLoginPlayer->getID().c_str() << endl;
		}
		else if (pLoginPlayer->isPayPlaying())
		{
			// °Á Åë°ú~
			cout << "isPayPlaying: " << pLoginPlayer->getID().c_str() << endl;

			// ±×·¯³ª.. ¹Ø¿¡¼­ ´É·ÂÄ¡ üũ¸¦ ÇؾßÇÑ´Ù.
			if (pLoginPlayer->getPayType()!=PAY_TYPE_FREE)
			{
				bCheckATTR = true;
			}
		}
		else
		{
			cout <<  "CannotPlay: " << pLoginPlayer->getID().c_str() << endl;

			// °ÔÀÓ ÇÒ ¼ö ¾ø´Â ij¸¯ÅÍ(ºô¸µ °ü·Ã)
			LCSelectPCError lcSelectPCError;
			lcSelectPCError.setCode(SELECT_PC_CANNOT_PLAY);
			pLoginPlayer->sendPacket(&lcSelectPCError);

			//throw DisconnectException("cannot playing");
			return;
		}
	}
	else
	{
		// ¾ÆÁ÷ ºô¸µ½Ã½ºÅÛÀ¸·ÎºÎÅÍ °ËÁõÀÌ µÇÁö ¾ÊÀº »óÅÂ
		// Ŭ¶óÀ̾ðÆ®¿¡¼­ ´õ ±â´Ù¸®µµ·Ï ÇؾßÇÑ´Ù.
		// ¾Æ´Ï¸é, ÀÏ´Ü ±×³É ³Ñ¾î°¡°í.. °× ¼­¹ö¿¡¼­ ©¸®µµ·Ï ÇÒ±î?
		// ¾ÆÁ÷ °áÁ¦ Á¤º¸°¡ üũµÇÁö ¾Ê¾Ò´Ù.
		cout << "NotBillingChecked: " << pLoginPlayer->getID().c_str();

		if (pLoginPlayer->isPayPlaying()
			&& pLoginPlayer->getPayType()==PAY_TYPE_FREE)
		{
			// ¿ÏÀü ¹«·á »ç¿ëÀÚ´Â ±×³É Åë°úÇÑ´Ù.
			cout << "But PAY_TYPE_FREE" << endl;
		}
		else
		{
			cout << endl;

			LCSelectPCError lcSelectPCError;
			lcSelectPCError.setCode(SELECT_PC_NOT_BILLING_CHECK);
			pLoginPlayer->sendPacket(&lcSelectPCError);

			//throw DisconnectException("cannot playing");
			return;
		}
	}
*/
#ifdef __NETMARBLE_SERVER__
	if (!pLoginPlayer->isAgree() )
	{
		LCSelectPCError lcSelectPCError;
		lcSelectPCError.setCode(SELECT_PC_DIDNOT_AGREE);
		pLoginPlayer->sendPacket(&lcSelectPCError);

		return;
	}
#endif

#ifdef __CONNECT_CBILLING_SYSTEM__
	if (pLoginPlayer->isCBillingVerified() )
	{
		if (!pLoginPlayer->isPayPlayer() )
		{
			LCSelectPCError lcSelectPCError;
			lcSelectPCError.setCode(SELECT_PC_CANNOT_PLAY);
			pLoginPlayer->sendPacket(&lcSelectPCError);

			return;
		}
	}
	else
	{
		LCSelectPCError lcSelectPCError;
		lcSelectPCError.setCode(SELECT_PC_NOT_BILLING_CHECK);
		pLoginPlayer->sendPacket(&lcSelectPCError);

		return;
	}

#endif

// ¾Öµåºô ºô¸µÀº »ç¿ëÇÏÁö ¾Ê¾Æµµ..
// ´É·ÂÄ¡ Á¦ÇÑ Ã¼Å©´Â ÇؾßÇÏ´Â °æ¿ì
#ifdef __PAY_SYSTEM_FREE_LIMIT__
	// À¯·á »ç¿ëÀÚ°¡ ¾Æ´Ñ °æ¿ì´Â ... ´É·ÂÄ¡ üũÇÑ´Ù.
	if (!pLoginPlayer->isPayPlaying())
	{
		bCheckATTR = true;
	}
#endif


	if (pLoginPlayer->getPlayerStatus() != LPS_PC_MANAGEMENT)
		throw DisconnectException("invalid player status");

	// PC ÀÇ Á¤º¸¸¦ µ¥ÀÌŸº£À̽º·ÎºÎÅÍ °¡Á® ¿Â´Ù.
	Statement* pStmt = NULL;
	Statement* pStmt1 = NULL;	// (!)
	Result* pResult;
	WorldID_t WorldID = pLoginPlayer->getWorldID();

	try
	{
		pStmt1 = g_pDatabaseManager->getConnection("DARKEDEN")->createStatement(); // (!)
		pStmt = g_pDatabaseManager->getConnection((TID)WorldID )->createStatement();

		//----------------------------------------------------------------------
		// PC °¡ ¸¶Áö¸·À¸·Î Ç÷¹ÀÌÇÑ Á¸ÀÇ ¾ÆÀ̵𸦠°¡Á®¿Â´Ù.
		//----------------------------------------------------------------------

		// ½½·¹À̾î ȤÀº ¹ìÆÄÀ̾î Å×ÀÌºí¿¡¼­ ³»°¡ ¼ÒÀ¯ÇÑ ¾×Ƽºê ij¸¯Å͸¦ ã´Â´Ù.
		/*
		pResult = pStmt->executeQuery(
			"SELECT ZoneID, Slot FROM %s WHERE Name = '%s' AND PlayerID = '%s' AND Active = 'ACTIVE'",
			pPacket->getPCType() == PC_SLAYER ? "Slayer" : "Vampire" ,
			pPacket->getPCName().c_str() ,
			pLoginPlayer->getID().c_str()
		);
		*/

		bool isSlayer =  (pPacket->getPCType() == PC_SLAYER);
		bool isVampire =  (pPacket->getPCType() == PC_VAMPIRE);

		if (isSlayer)
		{
			pResult = pStmt->executeQuery(
				"SELECT ZoneID, Slot, GREATEST(SwordLevel,BladeLevel,GunLevel,EnchantLevel,HealLevel), Competence FROM Slayer WHERE Name = '%s' AND PlayerID = '%s' AND Active = 'ACTIVE'",
				pPacket->getPCName().c_str() ,
				pLoginPlayer->getID().c_str()
			);
		}
		else if (isVampire)
		{
			pResult = pStmt->executeQuery(
				"SELECT ZoneID, Slot, Level, Competence FROM Vampire WHERE Name = '%s' AND PlayerID = '%s' AND Active = 'ACTIVE'",
				pPacket->getPCName().c_str() ,
				pLoginPlayer->getID().c_str()
			);
		}
		else
		{
			pResult = pStmt->executeQuery(
				"SELECT ZoneID, Slot, Level, Competence FROM Ousters WHERE Name = '%s' AND PlayerID = '%s' AND Active = 'ACTIVE'",
				pPacket->getPCName().c_str() ,
				pLoginPlayer->getID().c_str()
			);
		}

		// ±×·± PC°¡ ¾øÀ» °æ¿ì
		if (pResult->getRowCount() != 1)
		{
			SAFE_DELETE(pStmt);
			throw InvalidProtocolException("no such PC exist.");
		}

		pResult->next();

		ZoneID_t zoneID = pResult->getWORD(1);
		string slotStr 	= pResult->getString(2);

		// ´É·ÂÄ¡ üũ. by sigi. 2002.11.22
		if (bCheckATTR)
		{
		#ifdef __PAY_SYSTEM_FREE_LIMIT__
			if (isSlayer)
			{
				static int slayerSum = g_pConfig->getPropertyInt("FreePlaySlayerDomainSum");

				int DomainSUM = pResult->getInt(3);

				if (DomainSUM > slayerSum)
				{
					LCSelectPCError lcSelectPCError;
					lcSelectPCError.setCode(SELECT_PC_CANNOT_PLAY_BY_ATTR);
					pLoginPlayer->sendPacket(&lcSelectPCError);
					SAFE_DELETE(pStmt);
					return;
				}
			}
			else
			{
				static int vampireLevel = g_pConfig->getPropertyInt("FreePlayVampireLevel");

				int Level = pResult->getInt(3);

				if (Level > vampireLevel)
				{
					LCSelectPCError lcSelectPCError;
					lcSelectPCError.setCode(SELECT_PC_CANNOT_PLAY_BY_ATTR);
					pLoginPlayer->sendPacket(&lcSelectPCError);
					SAFE_DELETE(pStmt);
					return;
				}
			}
		#endif
		}

		//////////////////////////////////////////////////////////////////////////////////////
		// PK Server üũ
		//////////////////////////////////////////////////////////////////////////////////////
		bool bNonPKServer = g_pGameServerInfoManager->getGameServerInfo(1, pLoginPlayer->getServerGroupID(), pLoginPlayer->getWorldID() )->isNonPKServer();
		if (bNonPKServer )
		{
			cout << "WorldID:" << (int)(pLoginPlayer->getWorldID()) << " ServerGroupID:" << (int)(pLoginPlayer->getServerGroupID()) << endl;

			int playerLevel = pResult->getInt(3);
			int competence = pResult->getInt(4);

			// 40 ·¹º§ º¸´Ù ³ôÀº Ç÷¹À̾î´Â µé¾î°¥ ¼ö ¾ø´Ù.
			// ¿î¿µÀÚ´Â µé¾î°¡¾ßÇÑ´Ù.
			if (playerLevel > 80 && competence == 3 )
			{
				LCSelectPCError lcSelectPCError;
				lcSelectPCError.setCode(SELECT_PC_CANNOT_PLAY_BY_ATTR);
				pLoginPlayer->sendPacket(&lcSelectPCError);
				SAFE_DELETE(pStmt);
				return;
			}
		}
		//////////////////////////////////////////////////////////////////////////////////////

		if (slotStr.size()!=5)
		{
			SAFE_DELETE(pStmt);
			throw InvalidProtocolException("no slot exist.");
		}

		int slot = slotStr.at(4) - '0';

		//----------------------------------------------------------------------
		// ÀÌ Á¸À» °ü¸®ÇÏ´Â °ÔÀÓ ¼­¹ö Á¤º¸¸¦ °¡Á®¿Â´Ù.
		//----------------------------------------------------------------------
		GameServerInfo* pGameServerInfo;
		if (zoneID > 10000 && zoneID < 30000 )
		{
			// ij¸¯ÅÍ°¡ ±æµå ¾ÆÁöÆ®¿¡ ÀÖ´Ù. ±æµå ¾ÆÁöÆ® Á¸ÀÇ Á¤º¸´Â login server¿¡ ¾øÀ¸¹Ç·Î ´ëÃæ ¶«»§ÇÑ´Ù.
			pGameServerInfo = g_pGameServerInfoManager->getGameServerInfo(1, pLoginPlayer->getServerGroupID(), WorldID);
		}
		else
		{
			ZoneInfo* pZoneInfo = g_pZoneInfoManager->getZoneInfo(zoneID);
			ZoneGroupInfo* pZoneGroupInfo = g_pZoneGroupInfoManager->getZoneGroupInfo(pZoneInfo->getZoneGroupID());
			//cout << "ConnctServerGroup: " << (int)pLoginPlayer->getServerGroupID() << ", ServerID: " << (int)pZoneGroupInfo->getServerID();
			cout << "WorldID " << (int)WorldID << ", ServerGroupID : " << (int)pLoginPlayer->getServerGroupID() << ", ServerID : " << (int)pZoneGroupInfo->getServerID() << endl;
			pGameServerInfo = g_pGameServerInfoManager->getGameServerInfo(pZoneGroupInfo->getServerID(), pLoginPlayer->getServerGroupID(), WorldID);
		}

		//----------------------------------------------------------------------
		// ÀÌ »ç¿ëÀÚÀÇ ÇöÀç Á¢¼Ó ¼­¹ö Á¤º¸¸¦ °¡Á®¿Â´Ù.
		//----------------------------------------------------------------------
//		GameServerInfo* pGameServerInfo = g_pGameServerInfoManager->getGameServerInfo(pPlayer->getServerID());


		//----------------------------------------------------------------------
		// °ÔÀÓ¼­¹ö¿¡°Ô incoming connection ÀÌ ¿Ã °Å¶ó°í ¾Ë·ÁÁØ´Ù.
		//----------------------------------------------------------------------
		LGIncomingConnection lgIncomingConnection;
		lgIncomingConnection.setClientIP(pLoginPlayer->getSocket()->getHost());
		lgIncomingConnection.setPlayerID(pLoginPlayer->getID());
		lgIncomingConnection.setPCName(pPacket->getPCName());

		//--------------------------------------------------------------------------------
		//
		// *CAUTION*
		//
		// LoginPlayer::setPlayerStatus()¿Í GameServerManager::sendPacket()ÀÇ ¼ø¼­¿¡ ÁÖÀÇÇ϶ó.
		// ´Ü¼øÇÏ°Ô »ý°¢Çϸé sendPacket()ÈÄ¿¡ setPlayerStatus()¸¦ È£ÃâÇÏ´Â °ÍÀÌ ³í¸®¿¡ ÇÕ´ç
		// ÇÏÁö¸¸, ½ÇÁ¦·Î ±×·¸°Ô Çϸé setPlayerStatus()¸¦ È£ÃâÇϱâ Àü¿¡ °ÔÀÓ ¼­¹ö·ÎºÎÅÍ
		// GLIncomingConnectionXXX ÆÐŶÀÌ ³¯¾Æ¿Í¼­ ±× Çڵ鷯°¡ ½ÇÇàµÈ´Ù. - -;
		// µû¶ó¼­, ¾Æ·¡¿Í °°ÀÌ »óŸ¦ ¸ÕÀú ÁöÁ¤ÇÑ ÈÄ¿¡ UDP ÆÐŶÀ» Àü¼ÛÇØ¾ß ÇÑ´Ù.
		//
		//--------------------------------------------------------------------------------
		pLoginPlayer->setPlayerStatus(LPS_AFTER_SENDING_LG_INCOMING_CONNECTION);

/*
		// ¾î¿ ¼ö ¾øÀÌ user name À» »ç¿ëÇؼ­ ÇϵåÄÚµùÇÑ´Ù. -_-;
		g_pGameServerManager->sendPacket(pGameServerInfo->getIP() , pGameServerInfo->getUDPPort() , &lgIncomingConnection);
*/

		if (g_pConfig->getProperty("User") == "excel96")
			//g_pGameServerManager->sendPacket(pGameServerInfo->getIP() , g_pConfig->getPropertyInt("GameServerUDPPort"), &lgIncomingConnection);
			g_pGameServerManager->sendPacket(pGameServerInfo->getIP() , pGameServerInfo->getUDPPort(), &lgIncomingConnection);
		else if (g_pConfig->getProperty("User") == "beowulf")
			g_pGameServerManager->sendPacket(pGameServerInfo->getIP() , g_pConfig->getPropertyInt("GameServerUDPPort"), &lgIncomingConnection);
//			g_pGameServerManager->sendPacket(pGameServerInfo->getIP() , 8886 , &lgIncomingConnection);
		else if (g_pConfig->getProperty("User") == "crazydog")
			g_pGameServerManager->sendPacket(pGameServerInfo->getIP() , g_pConfig->getPropertyInt("GameServerUDPPort"), &lgIncomingConnection);
//			g_pGameServerManager->sendPacket(pGameServerInfo->getIP() , 6665, &lgIncomingConnection);
		else if (g_pConfig->getProperty("User") == "elcastle")
			g_pGameServerManager->sendPacket(pGameServerInfo->getIP() , g_pConfig->getPropertyInt("GameServerUDPPort"), &lgIncomingConnection);
//			g_pGameServerManager->sendPacket(pGameServerInfo->getIP() , 8885 , &lgIncomingConnection);
		else if (g_pConfig->getProperty("User") == "elca")
			g_pGameServerManager->sendPacket(pGameServerInfo->getIP() , g_pConfig->getPropertyInt("GameServerUDPPort"), &lgIncomingConnection);
//			g_pGameServerManager->sendPacket(pGameServerInfo->getIP() , 3335 , &lgIncomingConnection);

		// ¸¶Áö¸·À¸·Î Á¢¼ÓÇÑ slot ±â¾ï. by sigi. 2002.5.6
		pStmt1->executeQuery(	// (!)
		//pStmt->executeQuery(
			"UPDATE Player Set CurrentWorldID = %d, CurrentServerGroupID = %d, LastSlot = %d WHERE PlayerID = '%s'",
			WorldID,
			pLoginPlayer->getServerGroupID(),
			slot,
			pLoginPlayer->getID().c_str()
		);

		pStmt->executeQuery("UPDATE Slayer Set ServerGroupID = %d WHERE Name='%s'", pLoginPlayer->getServerGroupID(), pPacket->getPCName().c_str());
		pStmt->executeQuery("UPDATE Vampire Set ServerGroupID = %d WHERE Name='%s'", pLoginPlayer->getServerGroupID(), pPacket->getPCName().c_str());
		pStmt->executeQuery("UPDATE Ousters Set ServerGroupID = %d WHERE Name='%s'", pLoginPlayer->getServerGroupID(), pPacket->getPCName().c_str());

		SAFE_DELETE(pStmt);
		SAFE_DELETE(pStmt1); //(!)

		//cout << "CLSelectPC SendPacket to Server IP : " << pGameServerInfo->getIP() << endl;
	}
	catch (SQLQueryException & sqe)
	{
		//cout << sqe.toString() << endl;

		SAFE_DELETE(pStmt);
		SAFE_DELETE(pStmt1); //(!)

		throw DisconnectException(sqe.toString());
	}
	catch (NoSuchElementException & nsee)
	{
		StringStream msg;

		msg << "Critical Error : data intergrity broken at ZoneInfo - ZoneGroupInfo - GameServerInfo : " << nsee.toString();

		SAFE_DELETE(pStmt);
		SAFE_DELETE(pStmt1); //(!)

		throw Error(msg.toString());
	}

#endif

	__END_DEBUG_EX __END_CATCH
}
UINT CLAskCharLoginHandler::Execute(CLAskCharLogin* pPacket, Player* pPlayer )
{
	__ENTER_FUNCTION
	
	TID CurrentThreadID = MyGetCurrentThreadID();
	
	if(CurrentThreadID== g_pProcessPlayerManager->m_ThreadID)
	{
		LoginPlayer* pLoginPlayer = static_cast<LoginPlayer*>(pPlayer);
		Assert(pLoginPlayer);

		if(pLoginPlayer->GetPlayerStatus()!=PS_LOGIN_NORMAL)
		{
			return PACKET_EXE_CONTINUE;
		}
		
		UINT uTime = g_pTimeManager->CurrentTime();
		if(uTime<pLoginPlayer->m_LastDBOpTime+DB_OPERATION_TIME)
		{
			//用户操作过于频繁
			LCRetCharLogin Msg;
			Msg.SetResult(ASKCHARLOGIN_OP_TIMES);
			pLoginPlayer->SendPacket(&Msg);

			Log::SaveLog( LOGIN_LOGFILE, "CLAskCharLoginHandler::Execute()....Fails!,code = ASKCHARLOGIN_OP_TIMES") ;
			return PACKET_EXE_CONTINUE;
		}
		GUID_t	TryLoginGuid = pPacket->GetCharGuid();
		if(!pLoginPlayer->IsGUIDOwner(TryLoginGuid))
		{
			//用户操作非法,用户不是请求角色的所有者
			LCRetCharLogin Msg;
			Msg.SetResult(ASKCHARLOGIN_NOT_OWNER);
			pLoginPlayer->SendPacket(&Msg);
			Log::SaveLog( LOGIN_LOGFILE, "CLAskCharLoginHandler::Execute()....Fails!,code = ASKCHARLOGIN_NOT_OWNER") ;
			return PACKET_EXE_CONTINUE;
		}

		//检查是否是合法SID
		
		//if(g_DBSceneTable.isValidSceneID(pPacket->GetSceneID(),CT_NORMAL))
		//{
		//	pLoginPlayer->SetChooseSceneID(pPacket->GetSceneID());
		//}
		//else
		//{
		//	LCRetCharLogin Msg;
		//	Msg.SetResult(ASKCHARLOGIN_NOT_OWNER);
		//	pLoginPlayer->SendPacket(&Msg);
		//	DiskLog(LOGIN_LOGFILE, "CLAskCharLoginHandler::Execute()....Choose Scene error,acc=%s,guid=%X",
		//	pLoginPlayer->GetAccount(),pPacket->GetCharGuid()) ;
		//	return PACKET_EXE_CONTINUE;
		//}

		pLoginPlayer->SetUserKey(rand());
		pPacket->SetPlayerID(pLoginPlayer->PlayerID());
		if(g_pDBThreadManager->SendPacket(pPacket,pLoginPlayer->PlayerID()))
		{   //加入成功,将消息发送到DB处理
			//将修改数据库操作时间的步骤移动到实际数据库操作进行的部分
			return PACKET_EXE_NOTREMOVE;	
		}
		else
		{//DB 压力过大,让用户重新尝试
			LCRetCharLogin Msg;
			Msg.SetResult(ASKCHARLOGIN_SERVER_BUSY);
			pLoginPlayer->SendPacket(&Msg);
			pLoginPlayer->m_LastDBOpTime = uTime;
			Log::SaveLog( LOGIN_LOGFILE, "CLAskCharLoginHandler::Execute()....Fails!, code = ASKCHARLOGIN_SERVER_BUSY") ;

			return PACKET_EXE_CONTINUE;
		}
	}
	else if(g_pDBThreadManager->IsPoolTID(CurrentThreadID))
	{//将玩家加入到World 队列中
		
		PlayerID_t	PlayerID			= pPacket->GetPlayerID();
		GUID_t	    PlayerCharGUID		= pPacket->GetCharGuid();
		//SceneID_t	PlayerSceneID			= pPacket->GetSceneID();

		UINT        QueuePos;

		LoginPlayer* pLoginPlayer = static_cast<LoginPlayer*>(pPlayer);
		Assert(pLoginPlayer);

		GUID_t	TryLoginGuid = pPacket->GetCharGuid();
		if(!pLoginPlayer->IsGUIDOwner(TryLoginGuid))
		{
			//一次错误的数据操作
			Log::SaveLog(LOGIN_LOGFILE, "CLAskCharLoginHandler Wrong operation,acc=%s,guid=%X",
				pLoginPlayer->GetAccount(),pPacket->GetCharGuid()) ;
			return PACKET_EXE_CONTINUE;
		}
	
		
		if(g_pWorldPlayerQueue->AddInPlayer(PlayerID,
			pLoginPlayer->GetAccount(),
			pPacket->GetCharGuid(),
			pLoginPlayer->GetPlayerAge(),
			QueuePos))
		{ //加入成功
			
			Log::SaveLog( LOGIN_LOGFILE, "CLAskCharLoginHandler::Execute()....OK!, PlayerCharGUID = %X ",PlayerCharGUID ) ;

			return PACKET_EXE_CONTINUE;
			
		}
		else //加入失败
		{
			//queue 都满了,World爆满 ,但是不应该出现,因为World状态已经通知过Login
			//并且不是所有玩家都在排队
			Log::SaveLog( LOGIN_LOGFILE, "CLAskCharLoginHandler::Execute()....Fail,World is Full,PlayerCharGUID = %X ",PlayerCharGUID ) ;
		}
		
	}
	else
	{
		Log::SaveLog( LOGIN_LOGFILE, "ERROR::CLAskCharLoginHandler::Execute() ... Fail, Invalid Thread Handler") ;
		Assert(FALSE);
		return PACKET_EXE_CONTINUE;
	}
	
	return PACKET_EXE_CONTINUE;

	__LEAVE_FUNCTION

	return PACKET_EXE_ERROR;
}
UINT BLRetAuthHandler::Execute(BLRetAuth* pPacket, Player* pPlayer )
{
    __ENTER_FUNCTION

    PlayerID_t PlayerID ;
    LoginPlayer* pLoginPlayer = NULL ;
    Assert( pPlayer ) ;
    if( pPlayer->IsServerPlayer() )
    {
        PlayerID = pPacket->GetPlayerID();

        pLoginPlayer = g_pPlayerPool->GetPlayer(PlayerID) ;
        if( pLoginPlayer==NULL )
        {
            Assert(FALSE) ;
            return PACKET_EXE_CONTINUE ;
        }
    }
    else if( pPlayer->IsLoginPlayer() )
    {
        PlayerID = pPlayer->PlayerID() ;
        pLoginPlayer = (LoginPlayer*)pPlayer ;
        
        if( pLoginPlayer==NULL )
        {
            Assert(FALSE) ;
            return PACKET_EXE_CONTINUE ;
        }
    }
    else
    {
        Assert(FALSE) ;
        return PACKET_EXE_CONTINUE ;
    }

    TID CurrentThreadID = MyGetCurrentThreadID();
    
    if(CurrentThreadID == g_pServerManager->m_ThreadID)
    {
        if(pLoginPlayer->GetPlayerStatus() == PS_LOGIN_WAIT_AUTH)
        {   //ServerManager 中执行
            g_pLoginPlayerManager->SendPacket(pPacket,PlayerID);
            return PACKET_EXE_NOTREMOVE; 
        }
        return PACKET_EXE_CONTINUE;
    }
    else if ( CurrentThreadID == g_pLoginPlayerManager->m_ThreadID)
    {

        //检查GUID 是否正确
        if(strcmp(pLoginPlayer->GetAccount(),pPacket->GetAccount())!= 0)
        {
            //应该是一次错误操作
            Log::SaveLog(LOGIN_LOGFILE, "ERROR: BLRetAuthHandler::Execute Errors,acc = %s,Packet acc = %s",
                pLoginPlayer->GetAccount(),pPacket->GetAccount()) ;
            return PACKET_EXE_CONTINUE;
        }

        if (pLoginPlayer->GetPlayerStatus() == PS_LOGIN_WAIT_AUTH)
        {
            if(pPacket->GetResult() == LOGINR_SUCCESS)
            {
                pLoginPlayer->SetAccount(pPacket->GetAccount());
                pLoginPlayer->SetPlayerStatus(PS_LOGIN_AUTHED);
                pLoginPlayer->SetPlayerAge( (BYTE)pPacket->GetAge() );
                //把客户端从当前LoginPlayerManager 中释放
                g_pLoginPlayerManager->DelPlayer(pLoginPlayer->PlayerID());
                //并且向ProcessManager 发送消息
                g_pProcessManager->SendPacket(pPacket,pLoginPlayer->PlayerID());
                //修改客户端状态为 PS_LOGIN_WAIT_PROCESS_TURN
                pLoginPlayer->SetPlayerStatus(PS_LOGIN_WAIT_PROCESS_TURN);
                return PACKET_EXE_NOTREMOVE ;
            }
            else
            {
                pLoginPlayer->SetAccount(pPacket->GetAccount());
                pLoginPlayer->SetWrongPWCount(pLoginPlayer->GetWrongPWCount()+1);
                LCRetLogin Msg;
                Msg.SetAccount(pLoginPlayer->GetAccount());
                Msg.SetResult(LOGINR_AUTH_FAIL);
                pLoginPlayer->SendPacket(&Msg);

                if(pLoginPlayer->GetWrongPWCount()>=MAX_WRONGPW_TIMES)
                {
                    Log::SaveLog(LOGIN_LOGFILE, "ERROR: BLRetAuthHandler Reach Max Password Wrong Times acc=%s",
                        pLoginPlayer->GetAccount()) ;
                    return PACKET_EXE_ERROR;
                }
                else
                    return PACKET_EXE_CONTINUE;
            }
            
        }
    }
    else if (CurrentThreadID == g_pProcessPlayerManager->m_ThreadID )
    {
        //检查GUID 是否正确
        if(strcmp(pLoginPlayer->GetAccount(),pPacket->GetAccount())!= 0)
        {
            //应该是一次错误操作
            Log::SaveLog(LOGIN_LOGFILE, "ERROR: BLRetAuthHandler::Execute Process Errors,acc = %s,Packet acc = %s",
                pLoginPlayer->GetAccount(),pPacket->GetAccount()) ;
            return PACKET_EXE_CONTINUE;
        }

        //加入到g_pProcessPlayerManager 中,能够处理对应的HeartBeat
        g_pProcessPlayerManager->AddPlayer(pLoginPlayer);
        //先处理login 结果
        LCRetLogin Msg;
        Msg.SetAccount(pLoginPlayer->GetAccount());
        Msg.SetResult(LOGINR_SUCCESS);
        pLoginPlayer->SendPacket(&Msg);
        UINT QueuePos;
        //加入到g_pProcessPlayerQueue 中,能够对客户端排队
        if(g_pProcessPlayerQueue->AddInPlayer(pLoginPlayer->PlayerID(),
            pLoginPlayer->GetAccount(),QueuePos))
        {
            pLoginPlayer->SetQueuePos(QueuePos);
            //设置当前玩家状态
            pLoginPlayer->SetPlayerStatus(PS_LOGIN_PROCESS_TURN);
            pLoginPlayer->SetLastSendTurnTime(g_pTimeManager->CurrentTime());    
            //发送开始排队消息(HeartBeat 中执行)
        }
        else
        {    //排队玩家都超过MAX_TURN_PLAYER个
            //所以只能断开此玩家的网络连接
            BOOL boo = pLoginPlayer->FreeOwn() ;
            Log::SaveLog( LOGIN_LOGFILE, "ERROR: BLRetAuthHandler::FreeOwn " ) ;
            Assert( boo ) ;
            return PACKET_EXE_ERROR ;

        }
    }
    
    Log::SaveLog( LOGIN_LOGFILE, "BLRetAuthHandler::Execute()....OK! " ) ;

    return PACKET_EXE_CONTINUE;

    __LEAVE_FUNCTION

    return PACKET_EXE_ERROR;
}
Exemple #13
0
UINT BLRetAuthHandler::Execute(BLRetAuth* pPacket, Player* pPlayer )
{
	__ENTER_FUNCTION

	PlayerID_t PlayerID ;
	LoginPlayer* pLoginPlayer = NULL ;
	Assert( pPlayer ) ;
	if( pPlayer->IsServerPlayer() )
	{
		PlayerID = pPacket->GetPlayerID();

		pLoginPlayer = g_pPlayerPool->GetPlayer(PlayerID) ;
		if( pLoginPlayer==NULL )
		{
			Assert(FALSE) ;
			return PACKET_EXE_CONTINUE ;
		}
	}
	else if( pPlayer->IsLoginPlayer() )
	{
		PlayerID = pPlayer->PlayerID() ;
		pLoginPlayer = (LoginPlayer*)pPlayer ;
		
		if( pLoginPlayer==NULL )
		{
			Assert(FALSE) ;
			return PACKET_EXE_CONTINUE ;
		}
	}
	else
	{
		Assert(FALSE) ;
		return PACKET_EXE_CONTINUE ;
	}

	TID CurrentThreadID = MyGetCurrentThreadID();
	
	if(CurrentThreadID == g_pServerManager->m_ThreadID)
	{
		if(pLoginPlayer->GetPlayerStatus() == PS_LOGIN_WAIT_AUTH)
		{   //ServerManager 中执行
			g_pLoginPlayerManager->SendPacket(pPacket,PlayerID);
			return PACKET_EXE_NOTREMOVE; 
		}
		return PACKET_EXE_CONTINUE;
	}
	else if ( CurrentThreadID == g_pLoginPlayerManager->m_ThreadID)
	{
		//检查GUID 是否正确
		if(strcmp(pLoginPlayer->GetAccount(),pPacket->GetAccount())!= 0)
		{
			//应该是一次错误操作
			g_pLog->FastSaveLog(LOG_FILE_0, "ERROR: BLRetAuthHandler::Execute Errors,acc = %s,Packet acc = %s",
				pLoginPlayer->GetAccount(),pPacket->GetAccount()) ;
			return PACKET_EXE_CONTINUE;
		}

		if (pLoginPlayer->GetPlayerStatus() == PS_LOGIN_WAIT_AUTH)
		{
			if( pPacket->GetResult() == LOGINR_SUCCESS ||
				pPacket->GetResult() == LOGINR_REG_SUCCESS)
			{
				//设置帐号的防沉迷标识[7/10/2007]
				pLoginPlayer->SetAccFatigueSign(pPacket->GetFatigueSign());
				pLoginPlayer->SetAccOnlineTime(pPacket->GetTotalOnlineTime());
				pLoginPlayer->SetPhoneBind(pPacket->GetPhoneBind());
				pLoginPlayer->SetIPBind(pPacket->GetIPBind());
				pLoginPlayer->SetMiBaoBind(pPacket->GetMiBaoBind());
				pLoginPlayer->SetMacBind(pPacket->GetMacBind());
				pLoginPlayer->SetRealNameBind(pPacket->GetRealNameBind());
				pLoginPlayer->SetInputNameBind(pPacket->GetInputNameBind());

				INT nSafeSign = g_Config.m_LoginInfo.NotifySafeSign;
				if(nSafeSign<=0)
				{
					//pLoginPlayer->SetAccount(pPacket->GetAccount());	// no need to set[11/24/2006]
					pLoginPlayer->SetPlayerStatus(PS_LOGIN_AUTHED);
					//把客户端从当前LoginPlayerManager 中释放
					g_pLoginPlayerManager->DelPlayer(pLoginPlayer->PlayerID());
					//并且向ProcessManager 发送消息
					g_pProcessManager->SendPacket(pPacket,pLoginPlayer->PlayerID());
					//修改客户端状态为 PS_LOGIN_WAIT_PROCESS_TURN
					pLoginPlayer->SetPlayerStatus(PS_LOGIN_WAIT_PROCESS_TURN);

					return PACKET_EXE_NOTREMOVE;
				}
				else
				{
					LCRetLogin Msg;
					Msg.SetAccount(pLoginPlayer->GetAccount());
					Msg.SetResult(LOGINR_NOTIFY_SAFESIGN);
					//Msg.SetSafeSign(pLoginPlayer->m_AccountSafeSign);

					pLoginPlayer->SendPacket(&Msg);

					//修改客户端状态为等待确认安全标识
					pLoginPlayer->SetPlayerStatus(PS_LOGIN_WAIT_SAFESIGN_CLIENT);

					g_pLog->FastSaveLog(LOG_FILE_0, "BLRetAuthHandler Wait Client NotifySafeSign acc=%s",
						pLoginPlayer->GetAccount());

					return PACKET_EXE_CONTINUE;
				}

				return PACKET_EXE_CONTINUE;
			}
			else if(pPacket->GetResult() == LOGINR_ONLY_SUCCESS)
			{
				INT nSafeSign = g_Config.m_LoginInfo.NotifySafeSign;
				if(nSafeSign<=0)
				{
					pPacket->SetResult(LOGINR_SUCCESS);
					//pLoginPlayer->SetAccount(pPacket->GetAccount());	// no need to set[11/24/2006]
					pLoginPlayer->SetPlayerStatus(PS_LOGIN_AUTHED);
					//把客户端从当前LoginPlayerManager 中释放
					g_pLoginPlayerManager->DelPlayer(pLoginPlayer->PlayerID());
					//并且向ProcessManager 发送消息
					g_pProcessManager->SendPacket(pPacket,pLoginPlayer->PlayerID());
					//修改客户端状态为 PS_LOGIN_WAIT_PROCESS_TURN
					pLoginPlayer->SetPlayerStatus(PS_LOGIN_WAIT_PROCESS_TURN);

					return PACKET_EXE_NOTREMOVE;
				}
				else
				{
					LCRetLogin Msg;
					Msg.SetAccount(pLoginPlayer->GetAccount());
					Msg.SetResult(LOGINR_NOTIFY_SAFESIGN);
					Msg.SetSafeSign(pLoginPlayer->m_AccountSafeSign);

					pLoginPlayer->SendPacket(&Msg);

					//修改客户端状态为等待确认安全标识
					pLoginPlayer->SetPlayerStatus(PS_LOGIN_WAIT_SAFESIGN_CLIENT);

					g_pLog->FastSaveLog(LOG_FILE_0, "BLRetAuthHandler Wait Client NotifySafeSign acc=%s",
						pLoginPlayer->GetAccount());

					return PACKET_EXE_CONTINUE;
				}

				return PACKET_EXE_CONTINUE;
			}
			else if(pPacket->GetResult() == LOGINR_SAFESIGN_SUCCESS)
			{
				pPacket->SetResult(LOGINR_SUCCESS);
				//pLoginPlayer->SetAccount(pPacket->GetAccount());	// no need to set[11/24/2006]
				pLoginPlayer->SetPlayerStatus(PS_LOGIN_AUTHED);
				//把客户端从当前LoginPlayerManager 中释放
				g_pLoginPlayerManager->DelPlayer(pLoginPlayer->PlayerID());
				//并且向ProcessManager 发送消息
				g_pProcessManager->SendPacket(pPacket,pLoginPlayer->PlayerID());
				//修改客户端状态为 PS_LOGIN_WAIT_PROCESS_TURN
				pLoginPlayer->SetPlayerStatus(PS_LOGIN_WAIT_PROCESS_TURN);

				return PACKET_EXE_NOTREMOVE;
			}
			else if(pPacket->GetResult() == LOGINR_NEED_REG)
			{
				LCRetLogin Msg;
				Msg.SetAccount(pLoginPlayer->GetAccount());
				Msg.SetResult(LOGINR_NEED_REG);
				pLoginPlayer->SendPacket(&Msg);

				//修改客户端状态为等待注册PassPort
				pLoginPlayer->SetPlayerStatus(PS_LOGIN_WAIT_REG_PASSPORT);

				g_pLog->FastSaveLog(LOG_FILE_0, "REG: BLRetAuthHandler Wait Client Send PassPort Reg Info acc=%s",
					pLoginPlayer->GetAccount()) ;

				return PACKET_EXE_CONTINUE;
			}
			else if(pPacket->GetResult() == LOGINR_NO_NEW_LICENSE)
			{
				LCRetLogin Msg;
				Msg.SetAccount(pLoginPlayer->GetAccount());
				Msg.SetResult(LOGINR_NO_NEW_LICENSE);
				pLoginPlayer->SendPacket(&Msg);

				//修改客户端状态为等待确认新注册协议
				pLoginPlayer->SetPlayerStatus(PS_LOGIN_WAIT_LICENSE_CLIENT);
				//设置帐号的防沉迷标识[7/10/2007]
				pLoginPlayer->SetAccFatigueSign(pPacket->GetFatigueSign());
				pLoginPlayer->SetAccOnlineTime(pPacket->GetTotalOnlineTime());
				pLoginPlayer->SetPhoneBind(pPacket->GetPhoneBind());
				pLoginPlayer->SetIPBind(pPacket->GetIPBind());
				pLoginPlayer->SetMiBaoBind(pPacket->GetMiBaoBind());
				pLoginPlayer->SetMacBind(pPacket->GetMacBind());
				pLoginPlayer->SetRealNameBind(pPacket->GetRealNameBind());
				pLoginPlayer->SetInputNameBind(pPacket->GetInputNameBind());

				g_pLog->FastSaveLog(LOG_FILE_0, "BLRetAuthHandler Wait Client Send New License Info acc=%s",
					pLoginPlayer->GetAccount()) ;

				return PACKET_EXE_CONTINUE;
			}
			else if(pPacket->GetResult() == LOGINR_AUTH_FAIL || 
				    pPacket->GetResult() == LOGINR_MIBAO_ERROR ||
					pPacket->GetResult() == LOGINR_MAC_ERROR)
			{
				//pLoginPlayer->SetAccount(pPacket->GetAccount());	// no need to set[11/24/2006]
				pLoginPlayer->SetWrongPWCount(pLoginPlayer->GetWrongPWCount()+1);
				LCRetLogin Msg;
				Msg.SetAccount(pLoginPlayer->GetAccount());
				Msg.SetResult(pPacket->GetResult());
				pLoginPlayer->SendPacket(&Msg);

				if(pLoginPlayer->GetWrongPWCount()>=MAX_WRONGPW_TIMES)
				{
					g_pLog->FastSaveLog(LOG_FILE_0, "ERROR: BLRetAuthHandler Reach Max Password Wrong Times acc=%s",
						pLoginPlayer->GetAccount()) ;
					return PACKET_EXE_ERROR;
				}
				else
					return PACKET_EXE_CONTINUE;
			}
			else
			{
				//pLoginPlayer->SetAccount(pPacket->GetAccount());	// no need to set[11/24/2006]
				LCRetLogin Msg;
				Msg.SetAccount(pLoginPlayer->GetAccount());
				Msg.SetResult(pPacket->GetResult());
				Msg.SetServerIP(pPacket->GetServerIP());
				pLoginPlayer->SendPacket(&Msg);
				return PACKET_EXE_CONTINUE;
			}
			
		}
	}
	else if (CurrentThreadID == g_pProcessPlayerManager->m_ThreadID )
	{
		//检查GUID 是否正确
		if(strcmp(pLoginPlayer->GetAccount(),pPacket->GetAccount())!= 0)
		{
			//应该是一次错误操作
			g_pLog->FastSaveLog(LOG_FILE_0, "ERROR: BLRetAuthHandler::Execute Process Errors,acc = %s,Packet acc = %s",
				pLoginPlayer->GetAccount(),pPacket->GetAccount()) ;
			return PACKET_EXE_CONTINUE;
		}

		//加入到g_pProcessPlayerManager 中,能够处理对应的HeartBeat
		if(FALSE == g_pProcessPlayerManager->AddPlayer(pLoginPlayer))
		{
			g_pLog->FastSaveLog(LOG_FILE_0, "ERROR: BLRetAuthHandler::Execute Process Errors,acc = %s,Packet acc = %s maybe online",
				pLoginPlayer->GetAccount(),pPacket->GetAccount());

			//已有的这个玩家的状态置成等待被踢的状态
			LoginPlayer* pAlreadyInPlayer = (LoginPlayer*)(g_pProcessPlayerManager->FindAccName(pLoginPlayer->GetAccount()));
			if(pAlreadyInPlayer)
			{
				if(pAlreadyInPlayer->GetPlayerStatus() != PS_LOGIN_WAIT_WORLD_KICK)
				{
					//请求World踢掉此已有玩家
					LWNotifyUser* ptMsg = (LWNotifyUser*)g_pPacketFactoryManager->CreatePacket(PACKET_LW_NOTIFYUSER);
					ptMsg->SetAccount(pAlreadyInPlayer->GetAccount());
					ptMsg->SetNotifyStatus(LNOTIFY_KICK_REQUEST);
					ptMsg->SetUserKey(pAlreadyInPlayer->GetUserKey());

					g_pServerManager->SendPacket(ptMsg, WORLD_PLAYER_ID);
				}
				
				//设为等待被踢状态
				pAlreadyInPlayer->SetPlayerStatus(PS_LOGIN_WAIT_WORLD_KICK);
			}

			//主动断开当前的玩家
			return PACKET_EXE_ERROR;
		}

		pLoginPlayer->SetUserKey(rand());

		g_pLog->FastSaveLog(LOG_FILE_0, "BLRetAuthHandler Acc=%s, SetAccFatigueSign=%s, SetAccOnlineTime=%us,PhoneBind=%s,IPBind=%s,MiBaoBind=%s,MacBind=%s,ReadNameBind=%s,InputNameBind=%s",
			pLoginPlayer->GetAccount(),
			pLoginPlayer->GetAccFatigueSign()?"Y":"N",
			pLoginPlayer->GetAccOnlineTime(),
			pLoginPlayer->GetPhoneBind()?"Y":"N",
			pLoginPlayer->GetIPBind()?"Y":"N",
			pLoginPlayer->GetMiBaoBind()?"Y":"N",
			pLoginPlayer->GetMacBind()?"Y":"N",
			pLoginPlayer->GetRealNameBind()?"Y":"N",
			pLoginPlayer->GetInputNameBind()?"Y":"N");

		//先处理login 结果
		LCRetLogin Msg;
		Msg.SetAccount(pLoginPlayer->GetAccount());
		Msg.SetResult(pPacket->GetResult());
		pLoginPlayer->SendPacket(&Msg);

		UINT QueuePos;
		//加入到g_pProcessPlayerQueue 中,能够对客户端排队
		if(g_pProcessPlayerQueue->AddInPlayer(pLoginPlayer->PlayerID(),
			pLoginPlayer->GetAccount(),QueuePos))
		{
			//pLoginPlayer->SetQueuePos(0);
			//设置当前玩家状态
			pLoginPlayer->SetPlayerStatus(PS_LOGIN_PROCESS_TURN);
			pLoginPlayer->SetLastSendTurnTime(g_pTimeManager->CurrentTime());	
			//发送开始排队消息(HeartBeat 中执行)
		}
		else
		{	//排队玩家都超过MAX_TURN_PLAYER个
			//所以只能断开此玩家的网络连接
			
			g_pLog->FastSaveLog(LOG_FILE_0, "ERROR: BLRetAuthHandler Reach MAX_TURN_PLAYER Acc = %s",
				pLoginPlayer->GetAccount()) ;

			//由管理器来清除此玩家
			//return PACKET_EXE_ERROR ;

			/**	doing 29929,2007-12-25,alan
			*	达到排队人数上限,通知客户端,并让该用户进入退出倒计时。
			*/
			pLoginPlayer->SetPlayerStatus(PS_LOGIN_PROCESS_OVER_TURN);

			LCStatus errMsg;
			errMsg.SetClientStatus(CTS_OVER);
			pLoginPlayer->SendPacket(&errMsg);
			pLoginPlayer->TrigerDisconnectCountDown(3000);//3秒后断开连接
			return PACKET_EXE_CONTINUE;
		}
	}
	
	g_pLog->FastSaveLog(LOG_FILE_0, "BLRetAuthHandler::Execute()....OK! acc = %s ",pLoginPlayer->GetAccount()) ;

	return PACKET_EXE_CONTINUE;

	__LEAVE_FUNCTION

	return PACKET_EXE_ERROR;
}
UINT CLAskDeleteCharHandler::Execute(CLAskDeleteChar* pPacket, Player* pPlayer )
{
	__ENTER_FUNCTION

	TID CurrentThreadID = MyGetCurrentThreadID();

	if(CurrentThreadID == g_pProcessPlayerManager->m_ThreadID) 
	{
		LoginPlayer* pLoginPlayer = static_cast<LoginPlayer*>(pPlayer);
		Assert(pLoginPlayer);

		if( !StrSafeCheck( pPacket->GetAccount(), MAX_ACCOUNT ) )
		{
			Log::SaveLog(LOGIN_LOGFILE, "ERROR: CLAskDeleteCharHandler Get IllegalString,acc = %s",
				pLoginPlayer->GetAccount()) ;
			return PACKET_EXE_ERROR;
		}

		if(pLoginPlayer->GetPlayerStatus()!=PS_LOGIN_NORMAL)
		{
			//没有权限,什么也不做
			return PACKET_EXE_CONTINUE;
		}

		GUID_t	TryLoginGuid = pPacket->GetCharGuid();

		if(!pLoginPlayer->IsGUIDOwner(TryLoginGuid))
		{
			//用户操作非法,用户不是请求角色的所有者
			LCRetDeleteChar Msg;
			Msg.SetResult(ASKDELETECHAR_NOT_OWNER);
			pLoginPlayer->SendPacket(&Msg);
			Log::SaveLog( LOGIN_LOGFILE, "CLAskDeleteCharHandler::Execute()....Fails!,code = ASKDELETECHAR_NOT_OWNER") ;
			return PACKET_EXE_CONTINUE;
		}

		UINT uTime = g_pTimeManager->CurrentTime();
		if(uTime<pLoginPlayer->m_LastDBOpTime+DB_OPERATION_TIME)
		{
			LCRetDeleteChar Msg;
			Msg.SetResult(ASKDELETECHAR_OP_TIMES);
			//发送DB操作频繁消息
			pLoginPlayer->SendPacket(&Msg);
			Log::SaveLog(LOGIN_LOGFILE, "CLAskDeleteCharHandler::Execute()....database busy,acc=%s,tryguid=%X",
			pLoginPlayer->GetAccount(),TryLoginGuid) ;
			return PACKET_EXE_CONTINUE;
		}

		//________________________________________
		//pPacket->SetPlayerID(pLoginPlayer->PlayerID());
		//pPacket->SetAccount(pLoginPlayer->GetAccount());

		////将玩家操作加入DB 队列
		////并且设置最后操作时间
		//if(g_pDBThreadManager->SendPacket(pPacket,pLoginPlayer->PlayerID()))
		//{//加入成功,将消息发送到DB处理
		//	pLoginPlayer->m_LastDBOpTime = uTime;	
		//	return PACKET_EXE_NOTREMOVE;	
		//}
		//else
		//{//DB 压力过大,让用户重新尝试
		//	LCRetDeleteChar Msg;
		//	Msg.SetResult(ASKDELETECHAR_SERVER_BUSY);
		//	pLoginPlayer->SendPacket(&Msg);
		//	return PACKET_EXE_CONTINUE;
		//}
		//________________________________________

		LWAskDeleteChar	MsgDeleteChar;
		MsgDeleteChar.SetAccount( pLoginPlayer->GetAccount() );
		MsgDeleteChar.SetPlayerID( pLoginPlayer->PlayerID() );
		MsgDeleteChar.SetPlayerGUID( pPacket->GetCharGuid() );
		g_pServerManager->GetServerPlayer(WORLD_PLAYER_ID)->SendPacket(&MsgDeleteChar);

		return PACKET_EXE_CONTINUE;

	}
	else if(g_pDBThreadManager->IsPoolTID(CurrentThreadID))
	{

		PlayerID_t	PlayerID	= pPacket->GetPlayerID();
		LoginPlayer* pLoginPlayer = static_cast<LoginPlayer*>(pPlayer);
		Assert(pLoginPlayer);
		
		ASKDELETECHAR_RESULT	Result;
		LCRetDeleteChar* pMsg = (LCRetDeleteChar*)g_pPacketFactoryManager->CreatePacket(PACKET_LC_RETDELETECHAR);
		if(!pMsg)
		{
			AssertEx(FALSE,"创建 LCRetDeleteChar 消息失败");
		}

		if(pLoginPlayer->GetDBOperating() == TRUE)
		{
			pMsg->SetAccount(pPacket->GetAccount());
			pMsg->SetResult(ASKDELETECHAR_SERVER_BUSY);
			g_pProcessManager->SendPacket(pMsg,PlayerID);
			Log::SaveLog( LOGIN_LOGFILE, "CLAskDeleteCharHandler::Execute()....数据库操作冲突!") ;
			return PACKET_EXE_NOTREMOVE;
		}

		//检查GUID 是否正确
		if(strcmp(pLoginPlayer->GetAccount(),pPacket->GetAccount())!= 0)
		{
			//应该是一次错误操作
			Log::SaveLog(LOGIN_LOGFILE, "ERROR: CLAskDeleteChar DBOperation Errors,acc = %s,Packet acc = %s",
				pLoginPlayer->GetAccount(),pPacket->GetAccount()) ;
			return PACKET_EXE_CONTINUE;
		}
		pLoginPlayer->SetDBOperating(TRUE);
		
		LCRetCharList* pRetListMsg = (LCRetCharList*)g_pPacketFactoryManager->CreatePacket(PACKET_LC_RETCHARLIST)	;
		if(!pRetListMsg)
		{
			
			AssertEx(FALSE,"创建 LCRetCharList 消息失败");
		}
		
		INT CharNumber = pLoginPlayer->GetCharNumber();
		if(CharNumber==0)
		{
			pRetListMsg->SetAccount(pPacket->GetAccount());
			Result = ASKDELETECHARR_EMPTY; //角色空了
		}
		else if(CharNumber ==-1)
		{
			pRetListMsg->SetAccount(pPacket->GetAccount());
			Result = ASKDELETECHAR_OP_ERROR;
		}
		else
		{

			ODBCInterface*	pInterface = g_pDBThreadManager->GetInterface(CurrentThreadID);
			Assert(pInterface);

			//删除纪录
			DBDeleteCharOp DeleteCharOp(pInterface);
			DeleteCharOp.SetAccount(pPacket->GetAccount());
			DeleteCharOp.SetCharGuid(pPacket->GetCharGuid());
			BOOL bRetDelete = 	DeleteCharOp.Delete();
			if(!bRetDelete)
			{
				Log::SaveLog(LOGIN_LOGFILE,"DeleteCharOp.Delete()....Get Errors: %s ",DeleteCharOp.GetErrorMessage());
				INT ErrorCode = DeleteCharOp.GetErrorCode();
				pMsg->SetAccount(pPacket->GetAccount());
				pMsg->SetResult(ASKDELETECHAR_INTERNAL_ERROR);
				g_pProcessManager->SendPacket(pMsg,PlayerID);
				pLoginPlayer->SetDBOperating(FALSE);
				Log::SaveLog( LOGIN_LOGFILE, "CLAskDeleteCharHandler::Execute()....Fails! code = ASKDELETECHAR_INTERNAL_ERROR \
				 CharGUID = %d,Account = %s",pPacket->GetCharGuid(),pPacket->GetAccount()) ;
				return PACKET_EXE_NOTREMOVE;

			}
			DeleteCharOp.ParseResult(&Result);

			//返回新的角色列表
			DBCharList	CharListObject(pInterface);
			CharListObject.SetAccount(pPacket->GetAccount());
			BOOL bRetLoad = 	CharListObject.Load();
			if(bRetLoad)
			{

				CharListObject.ParseResult(pRetListMsg->GetCharBaseInfo());
				pRetListMsg->SetAccount(pPacket->GetAccount());
				pRetListMsg->SetResult(ASKCHARLIST_SUCCESS);
				pRetListMsg->SetCharNumber(CharListObject.GetCharNumber());

				if(CharListObject.GetCharNumber()<(UINT)CharNumber)
				{
					Result = ASKDELETECHAR_SUCCESS;
				}
				else
				{
					Result = ASKDELETECHAR_INTERNAL_ERROR;
				}
				pLoginPlayer->SetCharNumber(CharListObject.GetCharNumber());

				for(INT i=0;i<pLoginPlayer->GetCharNumber();i++)
				{
					pLoginPlayer->SetCharGUID(pRetListMsg->GetCharBaseInfo(i)->m_GUID,i);
				}
			}
			else //操作失败,可能是断开连接了
			{
				Log::SaveLog(LOGIN_LOGFILE,"CharListObject.Load()....Get Errors: %s ",
					CharListObject.GetErrorMessage());
				pRetListMsg->SetAccount(pPacket->GetAccount());
				pRetListMsg->SetResult(ASKCHARLIST_OP_FAILS);
				pRetListMsg->SetCharNumber(CharListObject.GetCharNumber());
			}

		}
//////////////////////////////////////////////////////////////////////////////
// 클라이언트가 PC 의 리스트를 달라고 요청해오면, 로그인 서버는 DB로부터
// PC들의 정보를 로딩해서 LCPCList 패킷에 담아서 전송한다.
//////////////////////////////////////////////////////////////////////////////
void CLSelectServerHandler::execute (CLSelectServer* pPacket , Player* pPlayer)
	 throw(ProtocolException , Error)
{
	__BEGIN_TRY __BEGIN_DEBUG_EX

#ifdef __LOGIN_SERVER__

	Assert(pPacket != NULL);
	Assert(pPlayer != NULL);

	LoginPlayer* pLoginPlayer = dynamic_cast<LoginPlayer*>(pPlayer);

	ServerGroupID_t CurrentServerGroupID = pPacket->getServerGroupID();

	WorldID_t WorldID = pLoginPlayer->getWorldID();

	//Assert (WorldID <= g_pGameWorldInfoManager->getSize());
	int MaxWorldID = g_pGameWorldInfoManager->getSize();
	if (WorldID>MaxWorldID)
	{
		WorldID = MaxWorldID;
	}

	//Assert (CurrentServerGroupID <= g_pGameServerGroupInfoManager->getSize(WorldID ));
	int MaxServerGroupID = g_pGameServerGroupInfoManager->getSize(WorldID);
	if  (CurrentServerGroupID>MaxServerGroupID)
	{
		CurrentServerGroupID = MaxServerGroupID;
	}


	// by sigi. 2003.1.7
	GameServerGroupInfo* pGameServerGroupInfo 
		= g_pGameServerGroupInfoManager->getGameServerGroupInfo(CurrentServerGroupID, WorldID);

	Assert(pGameServerGroupInfo!=NULL);
	if (pGameServerGroupInfo->getStat() == SERVER_DOWN)
	{
		filelog("errorLogin.txt", "Server Closed: %d", CurrentServerGroupID);
		throw DisconnectException("ServerClosed");
	}


	pLoginPlayer->setServerGroupID(CurrentServerGroupID);

	//----------------------------------------------------------------------
	// 이제 LCPCList 패킷을 만들어 보내자
	//----------------------------------------------------------------------
	LCPCList lcPCList;
	pLoginPlayer->makePCList(lcPCList);

#ifdef __NETMARBLE_SERVER__
	// 넷마블 사용자 약관 동의 여부 확인
	lcPCList.setAgree(pLoginPlayer->isAgree());
#endif

	pLoginPlayer->sendPacket(&lcPCList);
	pLoginPlayer->setPlayerStatus(LPS_PC_MANAGEMENT);

/*	try
	{
		pStmt    = g_pDatabaseManager->getConnection("DARKEDEN" )->createStatement();	

		pStmt->executeQuery("UPDATE Player set CurrentServerGroupID = %d WHERE PlayerID = '%s'", (int)pPacket->getServerGroupID(), pLoginPlayer->getID().c_str());

		// 쿼리 결과 및 쿼리문 객체를 삭제한다.
		SAFE_DELETE(pStmt);
	}
	catch (SQLQueryException & sce) 
	{
		//cout << sce.toString() << endl;

		// 쿼리 결과 및 쿼리문 객체를 삭제한다.
		SAFE_DELETE(pStmt);

		throw DisconnectException(sce.toString());
	}*/

#endif

	__END_DEBUG_EX __END_CATCH
}
Exemple #16
0
void CLLoginHandler::execute (CLLogin* pPacket , Player* pPlayer)
	 throw(ProtocolException , Error)
{
	__BEGIN_TRY __BEGIN_DEBUG_EX
		
#ifdef __LOGIN_SERVER__

	Assert(pPacket != NULL);
	Assert(pPlayer != NULL);

	//cout << pPacket->toString().c_str() << endl;

	LoginPlayer* pLoginPlayer = dynamic_cast<LoginPlayer*>(pPlayer);
	Statement*   pStmt        = NULL;

	// 좌우 공백 제거. by sigi. 2002.12.6
	pPacket->setID(trim(pPacket->getID()));

	string          connectIP            = pLoginPlayer->getSocket()->getHost();
	string			connectMAC			 = pPacket->getMacAddress();
	string          ID                   = pPacket->getID();

	// MAC address setting
	pLoginPlayer->setMacAddress(pPacket->getRareMacAddress());

	bool bFreePass = false;	//by sigi. 2002.10.23j

	// web login
	bool bWebLogin = pPacket->isWebLogin();
//	static bool bWebLogin = g_pConfig->getPropertyInt("WebLogin") != 0;

	// set web login player
	if (bWebLogin ) 
		pLoginPlayer->setWebLogin();

//	cout << pPacket->toString() << endl;

	if (isBlockIP(connectIP) )
	{
		LCLoginError lcLoginError;
		lcLoginError.setErrorID(IP_DENYED);
		pLoginPlayer->sendPacket(&lcLoginError);

		filelog("loginfail.txt", "Error Code: IP_DENYED, 1, PlayerID : %s", pPacket->getID().c_str());
		return;
	}

	// 사내테스트 버전에서는 '#sigi'  <-- 이런 식으로 계정이 들어온다.
	if (ID[0]==SYMBOL_TEST_CLIENT)
	{
		ID = ID.c_str()+1;
		pPacket->setID(ID);

		// 웹 로그인 체크
		if (bWebLogin )
		{
			//cout << "WebLogin" << endl;

			if (!checkWebLogin(pPacket, pPlayer ) )
			{
				return;
			}
			//else
				//cout << "Web Login OK" << endl;
		}
		else
		{
			//cout << "not WebLogin" << endl;

			// 넷마블에서 접속하는 경우
			// by sigi. 2002.10.23
			if (!checkNetMarbleClient(pPacket, pPlayer ))
			{
				return;
			}
		}
	
		bFreePass = pLoginPlayer->isFreePass();
		if (!bWebLogin && bFreePass)
		{
			// 웹로그인이 아닌 FreePass 는 넷마블 사용자로 ID 앞에 예약문자가 하나더 있다.
			ID = ID.c_str()+1;
			pPacket->setID(ID);
		}

//		cout << "테스트 클라이언트" << endl;
		BEGIN_DB
		{
			// 증거를 남긴다.
			pStmt = g_pDatabaseManager->getConnection("DARKEDEN")->createStatement();
			pStmt->executeQuery(
				"INSERT INTO TestClientUser (PlayerID, IP, LoginDate) VALUES ('%s', '%s', now())", 
				ID.c_str(), connectIP.c_str());

			SAFE_DELETE(pStmt);
		} 
		END_DB(pStmt)
	}
//////////////////////////////////////////////////////////////////////////////
// 클라이언트가 서버의 리스트를 달라고 요청해오면, 로그인 서버는 DB로부터
// 서버들의 정보를 로딩해서 LCWorldList 패킷에 담아서 전송한다.
//////////////////////////////////////////////////////////////////////////////
void CLGetWorldListHandler::execute (CLGetWorldList* pPacket , Player* pPlayer)
	 throw(ProtocolException , Error)
{
	__BEGIN_TRY __BEGIN_DEBUG_EX

#ifdef __LOGIN_SERVER__

	Assert(pPacket != NULL);
	Assert(pPlayer != NULL);
	//cout << "Start execute" << endl;

	LoginPlayer* pLoginPlayer = dynamic_cast<LoginPlayer*>(pPlayer);

	try 
	{
		int Num = g_pGameWorldInfoManager->getSize();

		//cout << "WorldNum : " << Num << endl;

		WorldInfo* aWorldInfo[Num];

		for(int i = 1 ; i < Num + 1; i++) 
		{
			WorldInfo* pWorldInfo = new WorldInfo();
			GameWorldInfo* pGameWorldInfo = g_pGameWorldInfoManager->getGameWorldInfo(i);
			pWorldInfo->setID(pGameWorldInfo->getID());
			pWorldInfo->setName(pGameWorldInfo->getName());

			// by bezz. 2002.12.20 
			pWorldInfo->setStat(pGameWorldInfo->getStatus());

			aWorldInfo[i] = pWorldInfo;

			// 트랜실(2) 빼기
			//if (i==2) pWorldInfo->setStat(WORLD_CLOSE);

			//cout << "AddWorld : " << pWorldInfo->getName() << endl;
		}

		LCWorldList lcWorldList;

		Statement * pStmt = NULL;

		BEGIN_DB
		{
			pStmt = g_pDatabaseManager->getConnection("DARKEDEN")->createStatement();

			Result * pResult = pStmt->executeQuery("SELECT CurrentWorldID FROM Player where PlayerID='%s'" , pLoginPlayer->getID().c_str());

			if(pResult->next() ) {
				lcWorldList.setCurrentWorldID(pResult->getInt(1));
			}

			SAFE_DELETE(pStmt); // by sigi
		}
		END_DB(pStmt) // by sigi

		for(int k = 1; k < Num + 1; k++) 
		{
			lcWorldList.addListElement(aWorldInfo[k]);
		}

		pLoginPlayer->sendPacket(&lcWorldList);
	
//		pLoginPlayer->setPlayerStatus(LPS_PC_MANAGEMENT);
	} 
	catch (Throwable & t) 
	{
		//cout << t.toString() << endl;
	}
	//cout << "End execute" << endl;

#endif

	__END_DEBUG_EX __END_CATCH
}
//////////////////////////////////////////////////////////////////////////////
// DB 로부터 특정 플레이어 아이디를 찾아서 그 여부를 클라이언트로 리턴해준다.
//////////////////////////////////////////////////////////////////////////////
void CLQueryPlayerIDHandler::execute (CLQueryPlayerID* pPacket , Player* pPlayer)
	 throw(ProtocolException , Error)
{
	__BEGIN_TRY __BEGIN_DEBUG_EX
		
#ifdef __LOGIN_SERVER__

	Assert(pPacket != NULL);
	Assert(pPlayer != NULL);

	LoginPlayer* pLoginPlayer = dynamic_cast<LoginPlayer*>(pPlayer);

	Statement* pStmt;

	try {

		pStmt = g_pDatabaseManager->getConnection("DARKEDEN")->createStatement();

		Result* pResult = pStmt->executeQuery(
			"SELECT Name FROM Player WHERE PlayerID = '%s'" , 
			pPacket->getPlayerID().c_str() 
		); 

		LCQueryResultPlayerID lcQueryResultPlayerID;

		//cout << "Query Result : " << pPacket->getPlayerID() << " is ";

		lcQueryResultPlayerID.setPlayerID(pPacket->getPlayerID());

		if (pResult->getRowCount() == 0) {
		
			lcQueryResultPlayerID.setExist(false);

			//cout << "not ";

		} else {

			lcQueryResultPlayerID.setExist(true);

		}

		//cout << "exist..." << endl;
		
		pLoginPlayer->sendPacket(&lcQueryResultPlayerID);

		// 쿼리가 여러 번 올 수 있으므로, 여전히 LWFRP 이다.
		// 문제는 누군가가 프로그램을 짜서 DOS 공격을 할 수 있으므로,
		// 최소 시간을 둬야 한다는 점이다.
		pLoginPlayer->setPlayerStatus(LPS_WAITING_FOR_CL_REGISTER_PLAYER);
			
		SAFE_DELETE(pStmt);
		//delete pStmt;		// 2002.1.16 by sigi
	} 
	catch (SQLQueryException & sqe) 
	{
		SAFE_DELETE(pStmt);
		throw;
	}
	
#endif
		
	__END_DEBUG_EX __END_CATCH
}
UINT	CLAskCreateCharHandler::Execute(CLAskCreateChar* pPacket, Player* pPlayer)
{
	__ENTER_FUNCTION

	TID CurrentThreadID = MyGetCurrentThreadID();

	if(CurrentThreadID == g_pProcessPlayerManager->m_ThreadID) 
	{
		LoginPlayer* pLoginPlayer = static_cast<LoginPlayer*>(pPlayer);
		Assert(pLoginPlayer);

		if( !StrSafeCheck( pPacket->GetAccount(), MAX_ACCOUNT ) )
		{
			Log::SaveLog(LOGIN_LOGFILE, "ERROR: CLAskDeleteCharHandler Get IllegalString,acc = %s",
				pLoginPlayer->GetAccount()) ;
			return PACKET_EXE_ERROR;
		}

		if( CheckIllegalString( pPacket->GetName(), MAX_CHARACTER_NAME, CHECK_STRING_CHARNAME ) )
		{
			LCRetCreateChar Msg;
			Msg.SetAccount(pPacket->GetAccount());
			Msg.SetResult(ASKCREATECHAR_INVALID_NAME);

			//发送DB操作频繁消息
			pLoginPlayer->SendPacket(&Msg);

			Log::SaveLog( LOGIN_LOGFILE, "CLAskCreateCharHandler....Fails!, code = ASKCREATECHAR_INVALID_NAME") ;

			return PACKET_EXE_CONTINUE;
		}

		if(pLoginPlayer->GetPlayerStatus()!=PS_LOGIN_NORMAL)
		{
			//没有权限,什么也不做
			return PACKET_EXE_CONTINUE;
		}

		UINT uTime = g_pTimeManager->CurrentTime();

		if(uTime<pLoginPlayer->m_LastDBOpTime+DB_OPERATION_TIME)
		{
			LCRetCreateChar Msg;
			Msg.SetAccount(pPacket->GetAccount());
			Msg.SetResult(ASKCREATECHAR_OP_TIMES);

			//发送DB操作频繁消息
			pLoginPlayer->SendPacket(&Msg);

			Log::SaveLog( LOGIN_LOGFILE, "CLAskCreateCharHandler....Fails!, code = ASKCREATECHAR_OP_TIMES") ;

			return PACKET_EXE_CONTINUE;
		}

		pPacket->SetPlayerID(pLoginPlayer->PlayerID());
		pPacket->SetAccount(pLoginPlayer->GetAccount());
		//将玩家操作加入DB 队列
		//并且设置最后操作时间

		if(g_pDBThreadManager->SendPacket(pPacket,pLoginPlayer->PlayerID()))
		{//加入成功,将消息发送到DB处理
			pLoginPlayer->m_LastDBOpTime = uTime;	
			return PACKET_EXE_NOTREMOVE;	
		}
		else
		{//DB 压力过大,让用户重新尝试
			LCRetCreateChar Msg;
			Msg.SetAccount(pPacket->GetAccount());
			Msg.SetResult(ASKCREATECHAR_SERVER_BUSY);
			pLoginPlayer->SendPacket(&Msg);

			Log::SaveLog( LOGIN_LOGFILE, "CLAskCreateCharHandler....Fails!, code = ASKCREATECHAR_SERVER_BUSY") ;
			return PACKET_EXE_CONTINUE;
		}

	}
	else if(g_pDBThreadManager->IsPoolTID(CurrentThreadID))
	{

		PlayerID_t	PlayerID	= pPacket->GetPlayerID();

		GUID_t	PlayerCharGUID = 1;

		LoginPlayer* pLoginPlayer = static_cast<LoginPlayer*>(pPlayer);
		Assert(pLoginPlayer);

		ASKCREATECHAR_RESULT	Result;
		LCRetCreateChar* pMsg = (LCRetCreateChar*)g_pPacketFactoryManager->CreatePacket(PACKET_LC_RETCREATECHAR);
		if(!pMsg)
		{
			AssertEx(FALSE,"创建 LCRetCreateChar 消息失败");
		}

		if(pLoginPlayer->GetDBOperating() == TRUE)
		{
			pMsg->SetAccount(pPacket->GetAccount());
			pMsg->SetResult(ASKCREATECHAR_SERVER_BUSY);
			g_pProcessManager->SendPacket(pMsg,PlayerID);

			Log::SaveLog(LOGIN_LOGFILE, "CLAskCreateCharHandler::Execute()....数据库操作冲突!,acc = %s",
				pPacket->GetAccount()) ;
			return PACKET_EXE_CONTINUE;
		}

		//检查GUID 是否正确
		if(strcmp(pLoginPlayer->GetAccount(),pPacket->GetAccount())!= 0)
		{
			//应该是一次错误操作
			Log::SaveLog(LOGIN_LOGFILE, "ERROR: CLAskCreateChar DBOperation Errors,acc = %s,Packet acc = %s",
				pLoginPlayer->GetAccount(),pPacket->GetAccount()) ;
			return PACKET_EXE_CONTINUE;
		}

		pLoginPlayer->SetDBOperating(TRUE);

		LCRetCharList* pRetListMsg = (LCRetCharList*)g_pPacketFactoryManager->CreatePacket(PACKET_LC_RETCHARLIST)	;
		if(!pRetListMsg)
		{
			AssertEx(FALSE,"创建 LCRetCharList 消息失败");
		}


		INT CharNumber = pLoginPlayer->GetCharNumber();

		if(CharNumber>=MAX_CREATE_PLAYER_NUM )
		{
			pRetListMsg->SetAccount(pPacket->GetAccount());
			Result = ASKCREATECHAR_FULL; //角色满了
		}
		else if(CharNumber ==-1)
		{
			pRetListMsg->SetAccount(pPacket->GetAccount());
			Result = ASKCREATECHAR_OP_ERROR;
		}
		else
		{
			CampID_t PlayerCampType ;
			if( CharNumber > 0 )
				PlayerCampType = pLoginPlayer->GetPlayerCamp(); //如果建立过角色,强制用上一个角色的阵营ID
			else
			{
				PlayerCampType = pPacket->GetCharCamp();
				pLoginPlayer->SetPlayerCamp( PlayerCampType );
			}

			if( PlayerCampType != CAMP1_PLAYER && PlayerCampType != CAMP2_PLAYER )
			{
				pMsg->SetAccount(pPacket->GetAccount());
				pMsg->SetResult(ASKCREATECHAR_OP_ERROR);
				g_pProcessManager->SendPacket(pMsg,PlayerID);

				Log::SaveLog( LOGIN_LOGFILE, "CLAskCreateCharHandler::Execute()....玩家阵营数据错误!") ;
				return PACKET_EXE_CONTINUE;
			}
			if( pPacket->GetMenPai() != MATTRIBUTE_SHAOLIN &&
				pPacket->GetMenPai() != MATTRIBUTE_WUDANG &&
				pPacket->GetMenPai() != MATTRIBUTE_EMEI )
			{
				//目前就只有3个职业
				pMsg->SetAccount(pPacket->GetAccount());
				pMsg->SetResult(ASKCREATECHAR_OP_ERROR);
				g_pProcessManager->SendPacket(pMsg,PlayerID);

				Log::SaveLog( LOGIN_LOGFILE, "CLAskCreateCharHandler::Execute()....玩家选择门派数据错误!") ;
				return PACKET_EXE_CONTINUE;
			}

			ODBCInterface*	pInterface = g_pDBThreadManager->GetInterface(CurrentThreadID);
			Assert(pInterface);

			//插入纪录
			DBCreateCharOp CreateCharOp(pInterface);
			CreateCharOp.SetAccount(pPacket->GetAccount());
			CreateCharOp.SetCharName(pPacket->GetName());
			CreateCharOp.SetCharGuid(pPacket->GetCharGuid());
			CreateCharOp.SetSex(pPacket->GetSex());
			CreateCharOp.SetHairColor(pPacket->GetHairColor());
			CreateCharOp.SetHairModel(pPacket->GetHairModel());
			CreateCharOp.SetFaceColor(pPacket->GetFaceColor());
			CreateCharOp.SetFaceModel(pPacket->GetFaceModel());
			CreateCharOp.SetHeadID(pPacket->GetHeadID());
			CreateCharOp.SetCampID(PlayerCampType);
			CreateCharOp.SetMenPaiID(pPacket->GetMenPai());
			BOOL bRetAddNew	 = CreateCharOp.AddNew();
			if(!bRetAddNew)
			{ 

				Log::SaveLog(LOGIN_LOGFILE,"CreateCharOp.AddNew()...Get Errors: %s",CreateCharOp.GetErrorMessage());

				//添加新角色失败
				pMsg->SetAccount(pPacket->GetAccount());

				INT  ErrorCode = CreateCharOp.GetErrorCode();

				switch(ErrorCode) 
				{
				case ODBCBase::DB_SAME_PRI_KEY: //用户需要知道的错误
					{
						pMsg->SetResult(ASKCREATECHAR_SAME_NAME);
						Log::SaveLog( LOGIN_LOGFILE, "CLAskCreateCharHandler::Execute()....Fails! DBCreateCharOP ErrorCode = ASKCREATECHAR_SAME_NAME") ;
					}
					break;
				default:
					{
						pMsg->SetResult(ASKCREATECHAR_INTERNAL_ERROR);
						Log::SaveLog( LOGIN_LOGFILE, "CLAskCreateCharHandler::Execute() ...Fails! DBCreateCharOP ErrorCode = %d",ErrorCode) ;
						break;
					}
				}

				g_pProcessManager->SendPacket(pMsg,PlayerID);
				pLoginPlayer->SetDBOperating(FALSE);
				return PACKET_EXE_NOTREMOVE;
			}
			CreateCharOp.ParseResult(&Result);

			PlayerCharGUID = CreateCharOp.GetCharGuid();

			Assert(PlayerCharGUID!=INVALID_ID);
			//设置基本属性

			FULLUSERDATA		UserData;
			DBCharFullData		CharFullDataObject(pInterface);
			CharFullDataObject.SetCharGuid(PlayerCharGUID);

			BOOL bRetLoad =	CharFullDataObject.Load();
			if(!bRetLoad)
			{	
				//验证数据失败
				pMsg->SetAccount(pPacket->GetAccount());
				pMsg->SetResult(ASKCREATECHAR_INTERNAL_ERROR);
				g_pProcessManager->SendPacket(pMsg,PlayerID);
				pLoginPlayer->SetDBOperating(FALSE);
				Log::SaveLog( LOGIN_LOGFILE, "CLAskCreateCharHandler::Execute() ...CharFullDataObject.Load()....Fails!") ;
				return PACKET_EXE_NOTREMOVE;
			}

			CharFullDataObject.ParseResult(&UserData);



			g_CharConfig.InitCharAttr(&UserData);

			BOOL bRetSave = CharFullDataObject.Save(&UserData); //保存出始化信息
			if(!bRetSave)
			{
				//初始化数据设置失败
				pMsg->SetAccount(pPacket->GetAccount());
				pMsg->SetResult(ASKCREATECHAR_INTERNAL_ERROR);
				g_pProcessManager->SendPacket(pMsg,PlayerID);
				Log::SaveLog( LOGIN_LOGFILE, "CLAskCreateCharHandler::Execute() ...CharFullDataObject.Save()....Fails!") ;
				pLoginPlayer->SetDBOperating(FALSE);
				return PACKET_EXE_NOTREMOVE;
			}
			bRetSave	=	CharFullDataObject.ParseResult(&UserData);//保存全部档案
			if(!bRetSave)
			{
				//初始化数据设置失败
				pMsg->SetAccount(pPacket->GetAccount());
				pMsg->SetResult(ASKCREATECHAR_INTERNAL_ERROR);
				g_pProcessManager->SendPacket(pMsg,PlayerID);
				Log::SaveLog( LOGIN_LOGFILE, "CLAskCreateCharHandler::Execute() ...CharFullDataObject.ParseResult....Fails!") ;
				pLoginPlayer->SetDBOperating(FALSE);
				return PACKET_EXE_NOTREMOVE;
			}

			//返回新的角色列表
			DBCharList	CharListObject(pInterface);
			CharListObject.SetAccount(pPacket->GetAccount());
			bRetLoad = 	CharListObject.Load();
			if(bRetLoad)
			{
				CharListObject.ParseResult(pRetListMsg->GetCharBaseInfo());

				pRetListMsg->SetAccount(pPacket->GetAccount());
				pRetListMsg->SetResult(ASKCHARLIST_SUCCESS);
				pRetListMsg->SetCharNumber(CharListObject.GetCharNumber());

				if(CharListObject.GetCharNumber()> (UINT)CharNumber)
				{
					Result = ASKCREATECHAR_SUCCESS;
				}
				else
				{
					Result = ASKCREATECHAR_INTERNAL_ERROR;
				}
				pLoginPlayer->SetCharNumber(CharListObject.GetCharNumber());

				for(INT i=0;i<pLoginPlayer->GetCharNumber();i++)
				{
					pLoginPlayer->SetCharGUID(pRetListMsg->GetCharBaseInfo(i)->m_GUID,i);
				}
			}
			else //操作失败,可能是断开连接了
			{
				pRetListMsg->SetAccount(pPacket->GetAccount());
				pRetListMsg->SetResult(ASKCHARLIST_OP_FAILS);
				pRetListMsg->SetCharNumber(CharListObject.GetCharNumber());
			}

		}
		pMsg->SetAccount(pPacket->GetAccount());
		pMsg->SetResult(Result);
		g_pProcessManager->SendPacket(pMsg,PlayerID);
		g_pProcessManager->SendPacket(pRetListMsg,PlayerID);
		pLoginPlayer->SetDBOperating(FALSE);
		Log::SaveLog( LOGIN_LOGFILE, "CLAskCreateCharHandler::Execute()....OK! \
									 Account = %s CharGuid = %X CharName = %s",\
									 pPacket->GetAccount(),PlayerCharGUID,pPacket->GetName()) ;
		return PACKET_EXE_NOTREMOVE;
	}