// 생성자 // client mode XSessionWinsock::XSessionWinsock( XSessionDelegate *pDelegate, const char *cIP, unsigned short port ) : XSession( pDelegate ) { Init(); // if( WSAStartup( MAKEWORD(1,1), &m_WSAData ) != 0 ) { XALERT( "WSAStartup failed" ); return; } // m_Socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); if( m_Socket == INVALID_SOCKET ) { XALERT( "create socket failed" ); return; } // SOCKADDR_IN addr; addr.sin_family = AF_INET; addr.sin_port = htons(0); addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); if( bind( m_Socket, (struct sockaddr *)&addr, sizeof(addr) ) == SOCKET_ERROR ) { XALERT( "Network bind error" ); Destroy(); return; } strcpy_s( m_cIP, sizeof(m_cIP), cIP ); m_Port = port; m_Mode = xCLIENT; // InitializeCriticalSection( &m_cs ); }
/** @brief 테이블형태로 된 스트링을 읽어 어레이에 담는다. */ int XESkillMng::ReadTableAry2( LPCTSTR szAttrName, LPCTSTR idsSkill, XVector<float>* pOutAry, LPCTSTR szStr, xtValType valType ) { CToken token; token.LoadStr( szStr ); int idx = 0; // pOutAry.size() != 0 경우도 있다. 상위블럭에서 값을 입력한 경우 하위에 상속되기때문에. 그러므로 그런경우는 클리어 시키고 다시 읽는다. pOutAry->Clear(); pOutAry->Add( 0.f ); // index0은 쓰지 않음. int level = 0; float numFirst = 0; while( 1 ) { if( token.IsEof() ) break; numFirst = token.GetNumberF(); if( numFirst == TOKEN_ERROR ) break; if( token.IsEof() ) break; level = (int)numFirst; if( level != idx + 1 ) { XALERT( "skill %s(%s):레벨번호가 순차적이지 않습니다.level:%d", idsSkill, szAttrName, level ); return 0; } token.GetToken(); // : float ability = token.GetNumberF(); if( token.IsError() ) { XALERT( "skill %s(%s):잘못된 숫자입니다..level:%d", idsSkill, szAttrName, level ); return 0; } if( valType == xPERCENT ) { pOutAry->Add( ability / 100.f ); } else { pOutAry->Add( ability ); } ++idx; // 레벨 10을 넘어가도 더이상 읽지 않는다. if( idx >= XGAME::MAX_SKILL_LEVEL ) break; } // 만약 스트링이 테이블형태가 아니고 숫자하나일경우 0번인덱스에 값을 넣는다. if( pOutAry->size() == 1 ) { if( valType == xPERCENT ) ( *pOutAry )[0] = numFirst / 100.f; else ( *pOutAry )[0] = numFirst; } return pOutAry->size(); }
// server mode XSessionWinsock::XSessionWinsock( XSessionDelegate *pDelegate, unsigned short port ) : XSession( pDelegate ) { Init(); // if( WSAStartup( MAKEWORD(1,1), &m_WSAData ) != 0 ) { XALERT( "WSAStartup failed" ); return; } // m_Socket = socket( AF_INET, SOCK_STREAM, 0 ); if( m_Socket == INVALID_SOCKET ) { XALERT( "create socket failed" ); return; } // SOCKADDR_IN addr; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); if( bind( m_Socket, (struct sockaddr *)&addr, sizeof(addr) ) == SOCKET_ERROR ) { XALERT( "Network bind error" ); Destroy(); return; } // if( listen( m_Socket, SOMAXCONN ) == SOCKET_ERROR ) { XALERT( "Network::listen error" ); Destroy(); return; } // // m_pDelegate = pDelegate; // strcpy_s( m_cIP, strlen(cIP), cIP ); m_Port = port; m_Mode = xSERVER; // 리쓴완료, 억셉트 대기중 if( m_pDelegate ) m_pDelegate->DelegateFinishListen( this ); // InitializeCriticalSection( &m_cs ); DWORD idThread; m_hAcceptThread = CreateThread( NULL, 0, _AcceptThread, (LPVOID)this, 0, &idThread); }
//==================================================== //#include "etc/InputMng.h" BOOL XConnectINI::Load( LPCTSTR szFile ) { CToken token; if( token.LoadFromDoc( szFile, XE::TXT_EUCKR ) == xFAIL ) { #ifdef WIN32 #ifdef _DEBUG strcpy_s( m_cIP, "192.168.100.44" ); #else _tstring strDocPath = XE::MakeDocFullPath( _T(""), szFile ); XALERT( "%s file not found", strDocPath.c_str() ); exit(1); // strcpy_s( m_cIP, "49.239.180.50" ); #endif #else if( XInputMng::s_Device == XE::DEVICE_IPAD || XInputMng::s_Device == XE::DEVICE_IPOD ) strcpy_s( m_cIP, XIP_LOGIN ); else if( XInputMng::s_Device == XE::DEVICE_ANDROID ) strcpy_s( m_cIP, XIP_LOGIN ); else { strcpy_s( m_cIP, XIP_LOGIN ); // strcpy_s( m_cIP, "59.5.5.245" ); } #endif m_Port = XPORT_LOGIN; strcpy_s( m_cIPPatch, XIP_PATCH ); strcpy_s( m_cID, "test3" ); return FALSE; } AXLOGXN("try read ip"); strcpy_s( m_cIP, Convert_TCHAR_To_char( token.GetToken() ) ); // ip AXLOGXN("login ip:%s", token.m_Token); if( XE::IsEmpty(m_cIP) ) strcpy_s( m_cIP, "211.52.84.50" ); AXLOGXN("try read port"); m_Port = token.GetNumber(); AXLOGXN("login port:%d", m_Port); #ifdef _XBOT2 #ifdef _XPATCH #error "봇 클라이언트에서는 _XPATCH를 빼시오" #endif token.GetNumber(); // dummy m_numBot = token.GetNumber(); #endif #ifdef _XPATCH AXLOGXN("try read patch ip"); strcpy_s( m_cIPPatch, SZ2C( token.GetToken() ) ); // patchsvr ip AXLOGXN("patch ip:%s", token.m_Token); if( XE::IsEmpty(m_cIPPatch) ) strcpy_s( m_cIPPatch, "49.239.180.50" ); #endif return TRUE; }
XFontDatSpr::XFontDatSpr( LPCTSTR szFontSpr ) : XBaseFontDat( szFontSpr, 0 ) { Init(); const bool bBatch = true; m_spDat = SPRMNG->Load( szFontSpr, XE::xHSL(), true, TRUE, false, bBatch, nullptr ); if( m_spDat == nullptr ) { XALERT( "%s읽기 실패", szFontSpr ); } }
XSkillDat* XESkillMng::Add( XSkillDat *pSkillDat ) { for( auto pDat : m_listSkillDat ) { if( pDat->GetstrIdentifier() == pSkillDat->GetstrIdentifier() ) { XALERT("중복된 스킬식별자: %s", pSkillDat->GetstrIdentifier().c_str() ); } } m_listSkillDat.push_back( pSkillDat ); return pSkillDat; }
BOOL XESocketClientInServer::CreateSocket() { XAUTO_LOCK; m_Socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); if( m_Socket == INVALID_SOCKET ) { XALERT( "create socket failed" ); return FALSE; } SOCKADDR_IN addr; addr.sin_family = AF_INET; addr.sin_port = htons(0); addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); if( bind( m_Socket, (struct sockaddr *)&addr, sizeof(addr) ) == SOCKET_ERROR ) { XBREAK( 1 ); XALERT( "Network bind error" ); Destroy(); return FALSE; } return TRUE; }
/** @brief 비보정 파라메터 효과를 적용한다. */ int XSkillReceiver::ApplyEffectNotAdjParam( XSkillDat *pDat, XSkillUser *pCaster, const EFFECT *pEff, int level ) { // 보정파라메터이거나 invalid한것은 0을 리턴 ///< 발동되는 효과를 직접 하드코딩 하고 싶을때는 발동파라메터가 보통 0이기때문에 하위에서 상속받을수 있는 이곳에서 검사하게 했다. 웒하면 상속받는쪽에서 검사안할수 있으니까 // if( IsAdjParam( pEffect->invokeParameter ) >= 0 ) return 0; // 함수명이 모호해서 삭제 if( pEff->invokeParameter >= 0 ) return 0; // if( pEffect->invokeParameter < 0 ) { float ivkAbilMin = pEff->GetAbilityMin(level); if( pEff->invokeAddAbility != 0.f ) { if( pEff->idAddAbilityToClass == 0 ) XALERT("경고:%s:추가능력치는 있는데 추가능력치대상이 없습니다.", pDat->GetstrIdentifier().c_str() ); if( IsInvokeAddTarget( pEff->idAddAbilityToClass ) == TRUE ) ivkAbilMin += pEff->invokeAddAbility; } // 커스텀 추가 증폭 // 루프( 증폭버프 = 증폭스킬리스트 ) 이와같은 방식으로 시스템화. // { // 증폭Effect = 증폭버프->GetEffectIndex(0); // if( 증폭이펙트->증폭파라메터 == 능력치 ) // { // float add = 0.f; // // float addMultiply = 0.f; // add = 증폭이펙트->능력치[level]; // invokeAbilityMin += add; // // invokeAbilityMin = invokeAbilityMin + invokeAbilityMin * addMultiply; // } // } float add = 0.f; float addMultiply = 0.f; pCaster->OnSkillAmplifyUser( pDat, this, pEff, xEA_ABILITY, &addMultiply, &add ); ivkAbilMin += add; ivkAbilMin = ivkAbilMin + ivkAbilMin * addMultiply; // 능력치값을 다른 다른형태로 변형해서 사용하고 싶다면 아래 핸들러를 정의해서 바꾼다. pCaster->OnAdjustEffectAbility( pDat, pEff, pEff->invokeParameter, &ivkAbilMin ); // return OnApplyEffectNotAdjParam( pCaster, pDat, pEff, ivkAbilMin ); // } // return 0; }
void XAppMain::OnError( XE::xtError codeError, DWORD p1, DWORD p2 ) { switch( codeError ) { // 기본 시스템 폰트가 없거나 손상되었다. case XE::xERR_FAIL_CREATE_ASIC_FONT: { if( XE::GetLoadType() == XE::xLT_WORK_TO_PACKAGE_COPY ) { // 패키지에 있는 파일을 워크에 카피해 넣는다. LPCTSTR szFont = (LPCTSTR)p1; XE::CopyPackageToWork( XE::MakePath( DIR_FONT, szFont ) ); XALERT("error! app restart please."); DoExit(); } } break; } }
/** @brief 객체가 생성된 후 가장먼저 불려짐. */ bool XESocketClientInServer::OnCreate( const std::string& strcIP , WORD port , XNetworkDelegate* pDelegate , DWORD param/* = 0*/ ) { if( XBREAK(strcIP.empty() || port == 0) ) { return false; } m_strcIP = strcIP; m_strtIP = C2SZ(strcIP); m_Port = port; m_dwConnectParam = param; SetpDelegate( pDelegate ); if( !XWinNetwork::sStartUp() ) { XALERT( "WSAStartup failed" ); return false; } return CreateSocket() != FALSE; }
/** @brief 확률표에따라 주사위를 굴려 테이블의 인덱스를 리턴한다. 확률표는 확률의 합이 1.0(100%)이 되어야 한다. */ int GetDiceChance( const std::vector<float>& aryChance ) { DWORD maxDice = 1000; DWORD dice = random( maxDice ); double addChance = 0; int size = aryChance.size(); for( int i = 0; i < size; ++i ) { addChance += aryChance[ i ]; if( i == size - 1 && addChance != 1.0f ) { if( aryChance[ i ] == 0 ) return i - 1; addChance = 1.f; } if( addChance > 1.01 ) XALERT( "warning: Go beyond the sum of the probability of 1.0" ); if( dice < (DWORD)( maxDice * addChance ) ) return i; } // 확률표 합이 100미만일경우 여기까지 오는경우도 있다. return -1; }
/** full_list.txt를 만든다. core_list.txt를 만든다.(apk50메가선을 유지하도록) */ void XMain::DoExtract( void ) { // 일단 모든 리소스 파일의 목록을 뽑는다. // XArrayLinear<XSYSTEM::XFILE_INFO> aryAll; XVector<XSYSTEM::XFILE_INFO> aryAll; // XSYSTEM::CreateFileList( XE::_GetPathPackageRoot(), _T("*.*"), &aryAll ); XSYSTEM::GetFileList( XE::_GetPathPackageRoot(), _T("*.*"), &aryAll, _T("") ); if( aryAll.Size() > 1500 ) { } // full_list.txt를 만든다. { // XArrayLinear<XPatch::XRES_INFO> ary; // ary.Create( aryAll.size() ); XVector<XPatch::XRES_INFO> ary; int cnt = 1; // 파일별로 체크섬을 뽑아 둔다. // XARRAYLINEAR_LOOP( aryAll, XSYSTEM::XFILE_INFO, info ) for( auto& info : aryAll ) { XPatch::XRES_INFO resInfo; resInfo.strFile = info.strFile; resInfo.size = info.size; resInfo.llChecksum = XE::CalcCheckSum( info.strFile.c_str() ); _tstring strFilename = XE::GetFileName( resInfo.strFile.c_str() ); int idxDuplicate = GetResIdxByCheckSum( ary, resInfo.llChecksum ); if( idxDuplicate != -1 ) { XALERT( "duplicate checksum file: idx=%d,%d", idxDuplicate, cnt ); } ary.Add( resInfo ); CONSOLE( "%d:%s.... %d byte ....checksum=0x%I64x", cnt++, strFilename.c_str(), resInfo.size, resInfo.llChecksum ); } // full_list.txt를 생성한다. WriteFullList( ary ); } // core_list.txt를 뽑아낸다. { // XArrayLinear<_tstring> aryCore; // aryCore.Create( aryAll.size() ); XVector<_tstring> aryCore; int i = 0; // XARRAYLINEAR_LOOP( aryAll, XSYSTEM::XFILE_INFO, info ) for( auto& info : aryAll ) { // TCHAR szFlename[ 256 ]; // _tcscpy_s( szFlename, XE::GetFileName( info.strFile.c_str() ) ); const _tstring strFileName = XE::GetFileName( info.strFile ); // 테마에 속하지 않는 몬스터중에 mob_ 으로 시작하는 몬스터는 // 제작은 되었으나 아직 테마에 반영이 안된 몬스터이므로 제외시킨다. BOOL bCore = TRUE; // TCHAR szExt[ 16 ]; // _tcscpy_s( szExt, XE::GetFileExt( strFileName ) ); const _tstring strExt = XE::GetFileExt( strFileName ); // 다음 단어가 포함되어 있는 파일은 모두 제외 // if( _tcsstr( szFlename, _T( "treant" ) ) || // _tcsstr( szFlename, _T( "rock" ) ) ) // bCore = FALSE; // 액셀 파일 제외 // if( XE::IsSame( szExt, _T("xlsx") ) ) if( strExt == _T("xlsx") ) bCore = FALSE; // if( XE::IsSame( szFlename, _T("core_list.txt") ) || // XE::IsSame( szFlename, _T("full_list.txt") ) ) // bCore = FALSE; if( strFileName == _T("core_list.txt") || strFileName == _T("full_list.txt") ) bCore = FALSE; if( _tcsstr( strFileName.c_str(), _T("sample")) ) bCore = FALSE; // if( bCore ) { aryCore.Add( info.strFile ); XTRACE( "%d: %s", i ++, info.strFile.c_str() ); } else { // 제외된 파일명 XTRACE( "-----------%s", info.strFile.c_str() ); } } // core_list.txt로 저장한다. WriteCoreList( aryCore ); } }
// pRoot의 모든 스킬을 읽는다. XSkillDat* XESkillMng::LoadSkill( TiXmlElement *pRoot, XSkillDat *pParentDat, EFFECT *pParentEffect ) { XSkillDat *pSkillDat = NULL; EFFECT *pEffect = NULL; ////////////////////////////////////////////////////////////////////////// // 먼저 Attribute(폴더가 아닌것)가 있는지 살펴본다. TiXmlAttribute *pAttr = pRoot->FirstAttribute(); if( pAttr ) { const char *cAttrName = pAttr->Name(); if( cAttrName ) { // 속성이 하나라도 있으면 skillDat객체를 생성한다. // Attribute가 있으면 일단 스킬로 인식하고 Dat객체를 생성한다. pSkillDat = CreateSkillDat(); if( pParentDat ) { ID idSkill = pSkillDat->GetidSkill(); *pSkillDat = *pParentDat; // 부모의 데이타를 상속받는다. pSkillDat->SetidSkill( idSkill ); _tstring strIdentifier = U82SZ( pRoot->Value() ); pSkillDat->SetstrIdentifier( strIdentifier ); } // 디폴트 이펙트버퍼도 하나 받는다. pEffect = new EFFECT; if( pParentEffect ) *pEffect = *pParentEffect; // 루프 시작 do { const char *cAttrName = pAttr->Name(); const char *cParam = pAttr->Value(); if( cAttrName && cAttrName[ 0 ] != '_' ) { XU8LOG( cAttrName ); XU8LOG( cParam ); // 변수명과 값을 파싱해서 pSkillDat에 넣는다. ParsingAttr( pAttr, cAttrName, cParam, pSkillDat, pEffect ); } } while (( pAttr = pAttr->Next() )); } } // pRoot에 폴더가 있는지 찾는다. TiXmlElement *pElemChild = pRoot->FirstChildElement(); if( pElemChild ) { do { // pRoot하의 모든 폴더를 하나씩 꺼낸다. const char *cFolderName = pElemChild->Value(); if( cFolderName && cFolderName[0] != '_' ) { XU8LOG( cFolderName ); ////////////////////////////////////////////////////////////////////////// // "효과"블럭은 따로 처리 if( XSAME( pElemChild->Value(), 96 ) || XSAME( pElemChild->Value(), 226 ) ) { // 효과/발동효과 if( pSkillDat == NULL ) { pSkillDat = CreateSkillDat(); if( pParentDat ) { ID idSkill = pSkillDat->GetidSkill(); *pSkillDat = *pParentDat; // 부모의 데이타를 상속받는다. pSkillDat->SetidSkill( idSkill ); _tstring strIdentifier = U82SZ( pRoot->Value() ); pSkillDat->SetstrIdentifier( strIdentifier ); } } EFFECT *pEffBlock = new EFFECT; if( pEffect ) *pEffBlock = *pEffect; // 하위상속을 위해 내용 복사. else *pEffBlock = *pParentEffect; // 스킬블럭에 디폴트 파라메터가 없으면 부모것을 디폴트로 쓴다. int numAttr = LoadEffect( pElemChild, pSkillDat, pEffBlock ); // 효과블럭안에 아무것도 없었으면 지운다. if( numAttr == 0 ) SAFE_DELETE( pEffBlock ); if( pEffBlock ) pSkillDat->AddEffect( pEffBlock ); } else if( XSAME( pElemChild->Value(), 235 ) ) { // 발동조건 if( pEffect == nullptr ) { pEffect = new EFFECT; if( pParentEffect ) *pEffect = *pParentEffect; } LoadCond( pElemChild, pEffect ); } else if( cFolderName[0] != '_' ) // 스킬이름이 _로 시작되면 읽지 않는다. { // 그외 폴더는 일단 스킬로 인식한다. XSkillDat* pNewSkillDat = NULL; pNewSkillDat = LoadSkill( pElemChild, ( pSkillDat ) ? pSkillDat : pParentDat, ( pEffect ) ? pEffect : pParentEffect ); if( pNewSkillDat ) { Add( pNewSkillDat ); } } } } while (( pElemChild = pElemChild->NextSiblingElement() )); } if( pSkillDat ) { // "효과"블럭이 추가된게 있었으면 디폴트용으로 생성되었던 이펙트 블럭은 필요없으므로 지운다. if( pSkillDat->GetNumEffect() > 0 ) { SAFE_DELETE( pEffect ); } else // 효과폴더가 없고 발동파라메터가 지정되지 않은 폴더는 스킬이 아니라고 보고 지운다. if( pSkillDat->GetNumEffect() == 0 ) { if( pEffect->invokeParameter == 0 && pEffect->invokeState == 0 && pEffect->strInvokeSkill.empty() && pEffect->idInvokeSkill == 0 && pEffect->invokeAbilityMin.size() == 0 && pEffect->invokeJuncture != 99 ) { // 발동시점:하드코딩 SAFE_RELEASE_REF( pSkillDat ); SAFE_DELETE( pEffect ); } else // "효과"블럭으로 추가된게 없고 발동파라메터는 지정되었으면 디폴트 이펙트를 이펙트로 추가한다. pSkillDat->AddEffect( pEffect ); } else { XBREAK(1); } if( pSkillDat ) { XBREAK( pSkillDat->GetTargetEff().IsHave() && pSkillDat->GetTargetEff().m_Loop == xAL_LOOP ); if( pSkillDat->m_strShootObj.empty() == false && pSkillDat->m_idShootObj == 0 ) pSkillDat->m_idShootObj = 1; // 파라메터 보정 for( const auto pEffect : pSkillDat->GetlistEffects() ) { // 지속시간이 있는데 발동시점이 지정안되면 디폴트로 persist동작을 하도록 수정.(버프라도 지속시간계속 발동하는게 있고 버프받는최초에만 적용되는게 있다, 버프끝날때 발동되는것도 있고. if( pEffect->IsDuration() && pEffect->invokeJuncture == xJC_NONE ) { pEffect->invokeJuncture = xJC_PERSIST; } LCONSOLE( !pEffect->IsDuration() && pEffect->invokeJuncture == xJC_PERSIST , "%s", _T("지속시간이 없는스킬인데 지속발동으로 지정되어 있음.") ); // 발동시점스킬이 지정되어 있다면 발동시점은 무조건 스킬발동시가 된다. if( pEffect->strInvokeTimeSkill.empty() == false ) { pEffect->invokeJuncture = xJC_INVOKE_SKILL; // 이걸하지않으면 지속형 스킬이 되어버림. } // 발동대상우호가 지정되지 않았으면 시전대상우호를 가져다 쓴다. if( pEffect->invokefiltFriendship == xfNONESHIP ) pEffect->invokefiltFriendship = pEffect->castfiltFriendship; // 시전거리는 정해졌는데 시전범위타입이 지정되지 않았으면 디폴트로 원형이 됨 if( pEffect->castSize.w > 0.f && pEffect->castSize.h > 0.f && pEffect->castTargetRange == xTR_ONE ) pEffect->castTargetRange = xTR_LINE; if( pEffect->castSize.w > 0.f && pEffect->castTargetRange == xTR_ONE ) pEffect->castTargetRange = xTR_CIRCLE; if( pEffect->invokeTarget == xIVT_NONE ) pEffect->invokeTarget = xIVT_CAST_TARGET; if( pEffect->invokeTarget == xIVT_CAST_TARGET_RADIUS || pEffect->invokeTarget == xIVT_CAST_TARGET_SURROUND ) { if( pEffect->IsHaveInvokeSize() == false ) XALERT("스킬\"%s\":발동범위가 지정되지 않음", pSkillDat->GetstrIdentifier().c_str() ); } // 지속시간스킬이면서 발동스킬이 있는건 에러(매프레임 스킬을 발동시키게 됨) XBREAK( pEffect->IsDuration() && pEffect->secInvokeDOT == 0 && pEffect->invokeJuncture == xJC_PERSIST && !pEffect->strInvokeSkill.empty() ); XBREAK( pEffect->castTarget == xCST_BASE_TARGET_POS // 시전대상이 좌표형 && pEffect->IsDuration() // 지속시간형 && pEffect->m_PersistEff.IsEmpty() ); // 일때 지속효과 spr이 없으면 안됨.(투명 객체됨) AdjustEffectParam( pSkillDat, pEffect ); // virtual } // for effect } } else { SAFE_DELETE( pEffect ); } return pSkillDat; }
/** @brief */ BOOL XESkillMng::ParsingEffect( TiXmlAttribute *pAttr, const char *cAttrName, const char *cParam, XSkillDat* pSkillDat, EFFECT *pEffect ) { #ifdef _DEBUG _tstring strUTF16 = U82SZ(cAttrName); #endif if( XSAME( cAttrName, 2 ) ) { // 시전대상 pEffect->castTarget = (xtCastTarget) ParsingParam( cParam ); } else if( XSAME( cAttrName, 15 ) ) // 시전대상 우호 { pEffect->castfiltFriendship = (xtFriendshipFilt) ParsingParam( cParam ); } else if( XSAME( cAttrName, 199 ) ) // 시전조건 { pEffect->castTargetCond = (xtTargetCond) ParsingParam( cParam ); } else if( XSAME( cAttrName, 17 ) ) // 시전대상플레이어 { pEffect->castfiltPlayerType = (xtPlayerTypeFilt) ParsingParam( cParam ); } else if( XSAME( cAttrName, 126 ) ) // 시전범위타입 { pEffect->castTargetRange = (xtTargetRangeType) ParsingParam( cParam ); } else if( XSAME( cAttrName, 20 ) ) // 시전대상이펙트 { pEffect->m_CastTargetEff.m_strSpr = U82SZ( cParam ); } else if( XSAME( cAttrName, 21 ) ) // 시전대상이펙트id { pEffect->m_CastTargetEff.m_idAct = (int)pAttr->IntValue(); } else if( XSAME( cAttrName, 261 ) ) // 시전대상이펙트반복 { pEffect->m_CastTargetEff.m_Loop = (xtAniLoop)ParsingParam( cParam ); } else if( XSAME( cAttrName, 156 ) ) // 시전대상이펙트생성지점 { pEffect->m_CastTargetEff.m_Point = (xtPoint) ParsingParam( cParam ); } else if( XSAME( cAttrName, 60 ) || XSAME( cAttrName, 127 ) ) // /시전범위 시전길이 { pEffect->castSize.w = (float)pAttr->DoubleValue(); } else if( XSAME( cAttrName, 128 ) ) // 시전폭 { pEffect->castSize.h = (float)pAttr->DoubleValue(); } else if( XSAME( cAttrName, 22 ) ) // 지속시간 { // pEffect->secDuration = (float)pAttr->DoubleValue(); _tstring strParam = U82SZ( cParam ); _tstring strAttrName = U82SZ( cAttrName ); ReadTableAry( strAttrName.c_str(), pSkillDat->GetstrIdentifier().c_str(), &pEffect->arySecDuration, strParam.c_str(), xVAL ); } else if( XSAME( cAttrName, 233 ) ) // 발동지속시간 { pEffect->secDurationInvoke = (float)pAttr->DoubleValue(); } else if( XSAME( cAttrName, 23 ) ) // 시전사운드 { pEffect->idCastSound = (int)pAttr->IntValue(); } else if( XSAME( cAttrName, 3 ) ) // 발동대상 { pEffect->invokeTarget = (xtInvokeTarget) ParsingParam( cParam ); } else if( XSAME( cAttrName, 10 ) ) // 발동대상 우호 { pEffect->invokefiltFriendship = (xtFriendshipFilt) ParsingParam( cParam ); } else if( XSAME( cAttrName, 24 ) ) // 발동대상플레이어 { pEffect->invokefiltPlayerType = (xtPlayerTypeFilt) ParsingParam( cParam ); } else if( XSAME( cAttrName, 122 ) ) // 발동시점 { pEffect->invokeJuncture = (xtJuncture) ParsingParam( cParam ); } else if( XSAME( cAttrName, 25 ) ) // 발동대상조건 { pEffect->invokeTargetCondition = (xtCondition) ParsingParam( cParam ); } else if( XSAME( cAttrName, 99 ) ) // 발동스킬id { pEffect->idInvokeSkill = (ID)pAttr->IntValue(); } else if( XSAME( cAttrName, 26 ) ) // 발동스킬 { pEffect->strInvokeSkill = U82SZ( cParam ); } else if( XSAME( cAttrName, 232 ) ) // 발동시점스킬 { pEffect->strInvokeTimeSkill = U82SZ( cParam ); } else if( XSAME( cAttrName, 239 ) ) // 발동조건스킬 { pEffect->strInvokeIfHaveBuff = U82SZ( cParam ); } else if( XSAME( cAttrName, 116 ) ) // 발동확률 { const _tstring strParam = U82SZ( cParam ); const _tstring strAttrName = U82SZ( cAttrName ); ReadTableAry( strAttrName.c_str(), pSkillDat->GetstrIdentifier().c_str(), &pEffect->aryInvokeRatio, strParam.c_str(), xPERCENT ); } else if( XSAME( cAttrName, 257 ) ) {// 발동적용확률 const _tstring strParam = U82SZ( cParam ); const _tstring strAttrName = U82SZ( cAttrName ); ReadTableAry2( strAttrName.c_str(), pSkillDat->GetstrIdentifier().c_str(), &pEffect->m_aryInvokeApplyRatio, strParam.c_str(), xPERCENT ); } else if( XSAME( cAttrName, 7 ) || XSAME( cAttrName, 161 ) ) // 발동파라메터/효과인덱스. { pEffect->invokeParameter = (int)ParsingParam( cParam ); } else if( XSAME( cAttrName, 30 ) ) // 발동대상이펙트 { pEffect->m_invokeTargetEff.m_strSpr = U82SZ( cParam ); } else if( XSAME( cAttrName, 31 ) ) // 발동대상이펙트id { pEffect->m_invokeTargetEff.m_idAct = (int)pAttr->IntValue(); } else if( XSAME( cAttrName, 157 ) ) // 발동대상이펙트생성지점 { pEffect->m_invokeTargetEff.m_Point = (xtPoint) ParsingParam( cParam ); } else if( XSAME( cAttrName, 262 ) ) // 발동대상이펙트반복 { pEffect->m_invokeTargetEff.m_Loop = (xtAniLoop)ParsingParam( cParam ); } else if( XSAME( cAttrName, 228) ) // 증폭파라메터 { pEffect->attrAmplify = (xtEffectAttr)ParsingParam( cParam ); } else if( XSAME( cAttrName, 8 ) ) // 능력치 { CToken token; token.LoadStr( U82SZ( cParam ) ); token.GetToken(); pEffect->valtypeInvokeAbility = GetValType( token.m_Token[0] ); if( pEffect->valtypeInvokeAbility == xNONE_VALTYPE ) { XALERT( "skill %s:unknown valtype.", pSkillDat->GetszIdentifier() ); return FALSE; } // %#기호뒤에 숫자가 더 있을때만 읽는다. if( token.IsEof() == FALSE ) { float ability = token.GetNumberF(); if( pEffect->invokeAbilityMin.size() != 0 ) { XALERT( "skill %s(%s):이미 능력치값이 존재합니다.", pSkillDat->GetszIdentifier(), U82SZ( cAttrName ) ); return FALSE; } // "능력치"만 단독으로 쓰일때는 index 0을 사용한다. if( pEffect->valtypeInvokeAbility == xPERCENT ) pEffect->invokeAbilityMin.Add( ability / 100.f ); else pEffect->invokeAbilityMin.Add( ability ); } } else if( XSAME( cAttrName, 125 )) // 능력치테이블 { _tstring strParam = U82SZ( cParam ); _tstring strAttrName = U82SZ( cAttrName ); ReadTableAry( strAttrName.c_str(), pSkillDat->GetstrIdentifier().c_str(), &pEffect->invokeAbilityMin, strParam.c_str(), pEffect->valtypeInvokeAbility ); if( pEffect->invokeParameter == 0 ) { XALERT( "skill %s(%s):발동파라메터가 없거나(해석하지 못했거나) 능력치테이블의 앞에 있지 않습니다.", pSkillDat->GetszIdentifier(), U82SZ( cAttrName ) ); } } else if( XSAME( cAttrName, 101 ) ) // 상태발동 { pEffect->invokeState = (int)ParsingParam( cParam ); } else if( XSAME( cAttrName, 65 ) || XSAME( cAttrName, 28 ) ) // 발동반경/범위 { _tstring strParam = U82SZ( cParam ); _tstring strAttrName = U82SZ( cAttrName ); ReadTableAry( strAttrName.c_str(), pSkillDat->GetstrIdentifier().c_str(), &pEffect->aryInvokeSize, strParam.c_str(), xVAL ); } else if( XSAME( cAttrName, 159 ) ) // 발동길이 { pEffect->_invokeSize.w = (float)pAttr->DoubleValue(); } else if( XSAME( cAttrName, 160 ) ) // 발동폭 { pEffect->_invokeSize.h = (float)pAttr->DoubleValue(); } else if( XSAME( cAttrName, 29 ) ) // 발동주기 { pEffect->secInvokeDOT = (float)pAttr->DoubleValue(); } else if( XSAME( cAttrName, 32 ) ) // 적용대상수 { pEffect->invokeNumApply = pAttr->IntValue(); } else if( XSAME( cAttrName, 162 ) ) // 발동자이펙트 { if( pEffect->m_invokerEff.m_strSpr.empty() == false ) XLOGXN("%s: 중복입력. 기존값:%s", U82SZ(cAttrName), pEffect->m_invokerEff.m_strSpr.c_str() ); pEffect->m_invokerEff.m_strSpr = U82SZ( cParam ); } else if( XSAME( cAttrName, 163 ) ) // 발동자대상이펙트id { pEffect->m_invokerEff.m_idAct = (int)pAttr->IntValue(); } else if( XSAME( cAttrName, 258 ) ) // 발동자이펙트생성지점 { pEffect->m_invokerEff.m_Point = (xtPoint) ParsingParam( cParam ); } else if( XSAME( cAttrName, 33 ) ) // 발동사운드 { pEffect->idInvokeSound = (int)pAttr->IntValue(); } else if( XSAME( cAttrName, 34 ) ) // 중복가능 { pEffect->bDuplicate = (BOOL)ParsingParam( cParam ); } else if( XSAME( cAttrName, 100 ) ) // 버프중첩 { pEffect->numOverlap = (int)pAttr->IntValue(); } else if( XSAME( cAttrName, 175 ) ) // 대상생존 { pEffect->liveTarget = (xtTargetLive) ParsingParam( cParam ); } else if( XSAME( cAttrName, 129 ) ) // 소환 { pEffect->strCreateObj = U82SZ( cParam ); } else if( XSAME( cAttrName, 134 ) ) // 소환id { pEffect->idCreateObj = (ID)pAttr->IntValue(); } else if( XSAME( cAttrName, 130 ) ) // 소환변수1 { pEffect->createObjParam[0] = (float) pAttr->DoubleValue(); } else if( XSAME( cAttrName, 130 ) ) // 소환변수1 { pEffect->createObjParam[0] = (float) pAttr->DoubleValue(); } else if( XSAME( cAttrName, 131 ) ) // 소환변수2 { pEffect->createObjParam[1] = (float) pAttr->DoubleValue(); } else if( XSAME( cAttrName, 132 ) ) // 소환변수3 { pEffect->createObjParam[2] = (float) pAttr->DoubleValue(); } else if( XSAME( cAttrName, 133 ) ) // 소환변수4 { pEffect->createObjParam[1] = (float) pAttr->DoubleValue(); } else if( XSAME( cAttrName, 44 ) ) // 사용 { pEffect->scriptUse = cParam; } else if( XSAME( cAttrName, 43 ) ) // 대상시전 { pEffect->scriptCast = cParam; } else if( XSAME( cAttrName, 39 ) ) // 발동시작 { pEffect->scriptInit = cParam; } else if( XSAME( cAttrName, 40 ) ) // 발동중 { pEffect->scriptProcess = cParam; } else if( XSAME( cAttrName, 41 ) ) // 발동끝 { pEffect->scriptUninit = cParam; } else if( XSAME( cAttrName, 42 ) ) // 도트 { pEffect->scriptDOT = cParam; } else if( XSAME( cAttrName, 171 ) ) // 면역여부 { pEffect->bImmunity = (BOOL) ParsingParam( cParam ); } else if( XSAME( cAttrName, 189 ) ) // 지속이펙트 { pEffect->m_PersistEff.m_strSpr = U82SZ( cParam ); } else if( XSAME( cAttrName, 191 ) ) // 지속이펙트생성지점 { pEffect->m_PersistEff.m_Point = (xtPoint) ParsingParam( cParam ); } else if( XSAME( cAttrName, 190 ) ) // 지속이펙트id { pEffect->m_PersistEff.m_idAct = (int)pAttr->IntValue(); } else if( XSAME( cAttrName, 207 ) ) // 파라메터1 { pEffect->dwParam[ 0 ] = ParsingConstantAndNumber( cParam ); } else if( XSAME( cAttrName, 208 ) ) // 파라메터2 { pEffect->dwParam[1] = ParsingConstantAndNumber( cParam ); } else if( XSAME( cAttrName, 209 ) ) // 파라메터3 { pEffect->dwParam[2] = ParsingConstantAndNumber( cParam ); } else if( XSAME( cAttrName, 210 ) ) // 파라메터4 { pEffect->dwParam[3] = ParsingConstantAndNumber( cParam ); } else if( XE::IsSame(cAttrName, "debug") ) { int a = pAttr->IntValue(); pEffect->m_Debug = a; } else if( CustomParsingEffect( pAttr, cAttrName, cParam, pSkillDat, pEffect ) == FALSE ) { XLOGXN( "unknown variable name: %s", U82SZ( cAttrName ) ); return FALSE; } return TRUE; }
/** @brief @param numWorkThread 0이면 시스템 코어에 맞춰 자동 */ void XEWinSocketSvr::Create( WORD port, int numWorkThread ) { XBREAK( port == 0 ); if( XWinNetwork::sStartUp() == false ) { XALERT( "WSAStartup failed" ); return; } // // m_Socket = socket( AF_INET, SOCK_STREAM, 0 ); m_Socket = WSASocket( PF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED ); if( m_Socket == INVALID_SOCKET ) { XALERT( "create socket failed" ); return; } SOCKADDR_IN addr; addr.sin_family = AF_INET; addr.sin_port = htons( port ); addr.sin_addr.S_un.S_addr = htonl( INADDR_ANY ); if( bind( m_Socket, ( struct sockaddr * )&addr, sizeof( addr ) ) == SOCKET_ERROR ) { XBREAK(1); XALERT( "Network bind error" ); Destroy(); return; } // m_Port = port; // 클라로부터 접속을 받을 준비 if( listen( m_Socket, SOMAXCONN ) == SOCKET_ERROR ) { XALERT( "Network::listen error" ); Destroy(); return; } // m_pUserMng = CreateUserMng( m_maxConnect ); XBREAK( m_pUserMng == NULL ); // 유저 커스텀 create OnCreate(); // virtual // IOCP 객체 생성 m_hIOCP = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 0 ); // 워커 스레드 생성 SYSTEM_INFO si; memset( &si, 0, sizeof(si)); GetSystemInfo( &si ); #if defined(_DEBUG) && !defined(_XBOT) const int numThread = 4; // 개발중엔 편의상 스레드 적게쓴다. #else const int numThread = (numWorkThread == 0)? (int)(si.dwNumberOfProcessors * 2) : numWorkThread; #endif XBREAK( numThread <= 0 || numThread > 32 ); for( int i = 0; i < numThread; ++i ) { m_aryThreadWork.push_back( CreateWorkThread() ); } // accept( 클라이언트로부터의 접속대기 ) 스레드 생성 m_thAccept = CreateAcceptThread(); // #if _DEV_LEVEL <= DLV_OPEN_BETA m_timerSec.Set( 1.f ); #endif }
/** @brief */ int __xLog( int type, LPCTSTR str, ...) { XCheckRecursive checkRecursive; if( checkRecursive.IsRecursive() ) return 1; TCHAR szBuff[1024]; // utf8이 길어서 넉넉하게 잡았다. va_list vl; va_start(vl, str); _vstprintf_s(szBuff, str, vl); va_end(vl); #ifdef _DEBUG #else // 릴리즈 모드에선 로그나 에러모두 파일에 써야 한다 { char szChar[8192]; memset( szChar, 0, sizeof(szChar) ); WideCharToMultiByte(CP_ACP, 0, szBuff, -1, szChar, 1024, NULL, NULL); int len = strlen(szChar); szChar[len] = '\n'; szChar[len+1] = 0; FILE *fp; #ifdef _XTOOL CString str = XE::GetCwd(); str += "error.txt"; fopen_s( &fp, Convert_TCHAR_To_char( str ), "a+" ); #else fopen_s( &fp, "error.txt", "a+" ); #endif //XBREAK( fp == NULL ); if( XASSERT(fp) ) { xPutsTimeString( fp ); fputs( szChar, fp ); int size = ftell( fp ); fclose(fp); } #ifdef _GAME // 게임에서만... // 로그파일이 무한정 쌓이지 않도록 한다. if( size >= 0xffff ) { fopen_s( &fp, "error.txt", "w+" ); if( fp ) { xPutsTimeString( fp ); fputs( szChar, fp ); fclose( fp ); #ifndef _MASTER // 마스터본이 아닐때만 XALERT( "로그파일 삭제" ); #endif } } #endif } #endif TCHAR szTitle[256] = {0,}; if( type == XLOGTYPE_ERROR ) { _tcscpy_s( szTitle, _T("Error!") ); // ::OutputDebugString( szBuff ); // TRACE로 한글출력이 안되서 이걸로 바꿈 #ifdef _XTOOL AfxDebugBreak(); AfxMessageBox( szBuff, MB_OK ); // 툴에선 XERROR를 불러도 exit()시키지 않는다. 데이터를 저장하지 않은상태이기때문에 어떻게 해서든 살리려고 시도해야한다 #else // ::MessageBox( NULL, szBuff, szTitle, MB_OK ); AfxMessageBox( szBuff, MB_OK ); AfxDebugBreak(); exit(1); #endif } else if( type == XLOGTYPE_LOG ) { // LOG _tcscpy_s( szTitle, _T("Message!") ); _tcscat_s( szBuff, _T("\n") ); // ::OutputDebugString( szBuff ); // TRACE로 한글출력이 안되서 이걸로 바꿈 } else if( type == XLOGTYPE_ALERT ) { AfxDebugBreak(); _tcscpy_s( szTitle, _T("Message!") ); // ::OutputDebugString( szBuff ); // TRACE로 한글출력이 안되서 이걸로 바꿈 #ifdef _XTOOL AfxMessageBox( szBuff, MB_OK ); #else // int retv = ::MessageBox( NULL, szBuff, szTitle, MB_OK ); AfxMessageBox( szBuff, MB_OK ); #endif } #ifdef _XCONSOLE CONSOLE( "%s", szBuff ); // 툴에서는 콘솔뷰로도 보낸다 #endif return 1; // XBREAK()같은데서 쓰이므로 항상 1을 리턴해야함 }