/** @brief pCenter(or vCenter)를 중심으로 radius범위내의 유닛들을 얻어 어레이에 담는다. @return 얻어낸 타겟수 @param pCenter 중심타겟. null이면 vCenter를 사용한다. @param vCenter 중심좌표. pCenter가 있다면 사용되지 않는다. @param pixelRadius 픽셀단위 반지름. @param bitSideFilter 검색해야할 진영 @param numCost 총 코스트값. 각 유닛은 크기 코스트가 있으며 타겟이 검색될때마다 numCost에서 차감한다. 0이되면 더이상 담지 않는다. 차감한 코스값이 마이너스가 될수는 없다. 0은 코스트에 관계없이 무조건 타겟1개만 검색. -1은 무효값. @param bIncludeCenter 중심타겟(pCenter가 있을경우)을 대상에 포함할지 말지. pCenter가 없다면 이 옵션은 무시된다. */ int XEObjMngWithType::GetListUnitRadius2( XVector<XSPUnit> *pOutAry, XEBaseWorldObj *pCenter, const XE::VEC2& vCenter, float pixelRadius, BIT bitSideFilter, int numCost, bool bIncludeCenter, BIT bitFlag ) const // 생존필터 { if( numCost < 0 ) return 0; // XVector<XSPUnit> aryInNew; // pOutAry에 이미 타겟이 있는채로 들어왔을때 그것은 제한 리스트 XVector<XSPUnit> aryIn = *pOutAry; // 기존타겟에 반경검사타겟까지 포함. int costSum = 0; for( auto spUnit : m_listUnits ) { if( spUnit->IsDestroy() ) continue; XBREAK( spUnit == nullptr ); if( (spUnit->GetCamp() & bitSideFilter) == 0 ) continue; if( (bitFlag & XSKILL::xTF_LIVE) == 0 && spUnit->IsLive() ) continue; if( (bitFlag & XSKILL::xTF_DEAD) == 0 && spUnit->IsDead() ) continue; // 시전대상을 포함하지 않는 조건일때 유닛이 시전대상이면 스킵 if( pCenter && pCenter->GetsnObj() == spUnit->GetsnObj() // spUnit이 중심타겟일때 && bIncludeCenter == false ) // 중심타겟안포함 옵션이면 스킵한다. continue; if( bitFlag & XSKILL::xTF_DIFF_SQUAD ) { // spUnit이 이미 찾은 유닛과 같은 부대면 스킵 bool bExisted = false; for( auto& spFinded : aryIn ) { if( spUnit->GetpSquadObj()->GetsnSquadObj() == spFinded->GetpSquadObj()->GetsnSquadObj() ) { bExisted = true; break; } } if( bExisted ) continue; } const XE::VEC2 vDist = spUnit->GetvwPos().ToVec2() - vCenter; const float distsq = vDist.Lengthsq(); // 코스트와 관계없이 일단 범위안에 들어가는 타겟은 모두 담은후 거기서 다시 코스트에 따라 랜덤으로 꺼낸다. if( distsq <= pixelRadius * pixelRadius ) { aryIn.Add( spUnit ); aryInNew.Add( spUnit ); costSum += spUnit->GetSizeCost(); // 배열에 들어간 유닛들의 토탈코스트 } // in radius } // for // 목표코스트를 다 채우지 못했거나 딱맞게 채웠을때는 전체 리스트에서 랜덤으로 뽑을필요가 없으므로 그냥 검색된 리스트를 모두 리턴한다. if( costSum <= numCost ) { *pOutAry = aryIn; return pOutAry->Size(); } int currCost = numCost; // XVector<XSPUnit> ary = *pOutAry; // pOutAry->Clear(); // 영역안에 들어온 타겟들을 대상으로 다시 코스트에 따라 실제 타겟을 선정한다. while( aryInNew.Size() > 0 ) { auto spUnit = aryInNew.PopFromRandom(); if( numCost == 0 ) { if( pOutAry->Size() == 0 ) pOutAry->Add( spUnit ); return 1; } else { const auto costUnit = spUnit->GetSizeCost(); if( costUnit <= currCost ) { // 유닛 코스트가 남은 코스트를 깔수 있을때만. currCost -= costUnit; XBREAK( currCost < 0 ); pOutAry->Add( spUnit ); if( currCost == 0 ) // 코스트를 다 채웠으면 리턴. return pOutAry->Size(); } } } return pOutAry->size(); }
/** 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 ); } }
void XEWinSocketSvr::ProcessLoginedList() { XVector<XSPWinConnInServer> aryDestroy; auto llMilli1 = GET_FREQ_TIME(); XPROF_OBJ( "listLogined" ); auto plistLogined = &m_Logined.m_shoList.GetSharedObj(); // 동접이 많으면 이 많은 커넥션들 다 패킷펌핑하기전까진 워커스레드 접속스레드 멈춰야 되는데... 이래선 싱글스레드와 다를바 없지 않은가. // 로그인된 커넥션들 프로세스 XINT64 llProcessTotal = 0; XINT64 lllock = 0; // for( auto spConnect : *plistLogined ) { XINT64 llStart = XE::GetFreqTime();; for( auto itor = (*plistLogined).begin(); itor != (*plistLogined).end(); ) { auto spConnect = (*itor); auto pConnect = spConnect.get(); XINT64 lllock1 = XE::GetFreqTime();; if( lllock1 - llStart > 100000 ) // 처리속도가 너무 올래걸릴거 같으면 일단 그냥 루프 빠져나감. break; pConnect->GetspLock()->Lock( __TFUNC__ ); lllock += GET_FREQ_TIME() - lllock1; const int cntUse = spConnect.use_count(); if( XASSERT( pConnect ) ) { if( pConnect->IsDisconnected() ) { OnDisconnectConnection( spConnect ); pConnect->OnDisconnect(); } if( !pConnect->GetbDestroy() ) { auto llProcess = GET_FREQ_TIME(); pConnect->Process(); llProcessTotal += (GET_FREQ_TIME() - llProcess); // if( pConnect->IsDisconnected() ) { // 연결은 끊어졌어도 클라측에서 중요한 패킷을 보냈을수도 있으므로 패킷펌핑은 다 끝내고 삭제하도록 바뀜. pConnect->SetbDestroy( true ); } // 커넥션이 비동기 파괴명령을 처리 pConnect->ProcesssAsyncDisconnect(); } if( pConnect->GetbDestroy() ) { ++m_numDestroyAdd; aryDestroy.Add( spConnect ); plistLogined->erase( itor++ ); } else ++itor; } pConnect->GetspLock()->Unlock(); } auto llPass = GET_FREQ_TIME() - llMilli1; m_aryTime.Add( xProfile(_T("process list"), llPass ) ); m_aryTime.Add( xProfile(_T("process"), llProcessTotal ) ); m_aryTime.Add( xProfile( _T( "lock" ), lllock ) ); m_aryTime.Add( xProfile( _T( "num process" ), plistLogined->size() ) ); // Logined 프로세스 & destroy ////////////////////////////////////////////////////////////////////////// auto pListConnected = &m_Connected.m_shoList.GetSharedObj(); m_numConnected = pListConnected->size(); // 멀티스레드이므로 여기에 값이 있을 수 있음. if( m_numConnected > m_maxConnected ) m_maxConnected = m_numConnected; m_Connected.m_shoList.ReleaseSharedObj(); m_numLogined = plistLogined->size(); if( m_numLogined > m_maxLogined ) m_maxLogined = m_numLogined; // 순간적으로 numConnect수보다 커넥션객체의 생성수가 훨씬 많을때가 있다. // leak으로 보이지만 봇 클라이언트를 종료시키는 순간 모두 사라지는걸로 보아 순간적으로 접속이 몰릴때 메인스레드 프로세스에서 // 다 처리를 못해서 그런듯 하다. // unlock m_Logined.m_shoList.ReleaseSharedObj(); // 삭제예정된 커넥션들 참조해제 ProcessDestroyList( aryDestroy ); aryDestroy.clear(); } // process & destroy