#include "stdafx.h" #include "SStringDB.h" #include #include #include "KResourceManager.h" #include #include #include "KTypes.h" #include "GameDefine.h" #include "SkillBaseFile.h" #include "KTextRender.h" //#include "Util.h" #include #include "XAbuseFilter.h" #include #include #include #include #include "SDebug_Util.h" // #define LOG_STRING_OCCUR_RATE std::map< int, int > g_StringOccurMap; SStringDB::SStringDB() { Init(); } SStringDB::~SStringDB() { Destroy(); } const char * SStringDB::GetString( int nID ) { #ifdef _DEV if( nID < 0 ) { char error_msg[512]; s_sprintf( error_msg, _countof( error_msg ), "Received an unmapped string ID (%d) that hasn’t been changed yet. Please contact the programming team", nID ); ::MessageBox( NULL, error_msg, "ERROR", MB_OK | MB_ICONERROR ); } #endif m_strErrorCode.clear(); _STRING_TABLE_INFO * strData = GetStringData( nID ); if( strData ) { #ifndef _RAPPELZ_CONFIG extern bool g_bLogStringRate; if( g_bLogStringRate ) { ++g_StringOccurMap[nID]; } #endif return strData->pStrDesc; } m_strErrorCode = CStringUtil::StringFormat( "<#FF0000>[Empty String: %d]", nID ); return m_strErrorCode.c_str(); } /* const char* SStringDB::GetString( const char* szKeyName ) { m_strErrorCode.clear(); _STRING_TABLE_INFO* pData = NULL; bool bLoop = m_hashString.get_first_value( pData ); while( bLoop ) { if( ::_stricmp( pData->pStrKey, szKeyName ) == 0 ) return pData->pStrDesc; bLoop = m_hashString.get_next_value( pData ); } m_strErrorCode = CStringUtil::StringFormat( "empty string : %s", szKeyName ); return m_strErrorCode.c_str(); }*/ _STRING_TABLE_INFO * SStringDB::GetStringData( int nID ) { _STRING_TABLE_INFO * pFindStrTable = NULL; if( m_hashString.lookup( nID, pFindStrTable ) == false ) { return NULL; } else { return pFindStrTable; } return NULL; } void SStringDB::Init() { LoadStringDB(); m_strErrorCode.clear(); // UI 와 엮어준다. struct SStringTable : public KTextRender::StringTableHandler { virtual const char* getString( int nId ) { struct _STRING_TABLE_INFO * pTableInfo = GetStringDB().GetStringData( nId ); if( !pTableInfo ) return NULL; return pTableInfo->pStrDesc; } }; static SStringTable _string_table; KTextRender::SetStringTable( &_string_table ); } void SStringDB::Destroy() { _STRING_TABLE_INFO* pStrTable = NULL; bool res; res = m_hashString.get_first_value( pStrTable ); while ( res ) { if ( pStrTable != NULL ) { delete pStrTable; } res = m_hashString.get_next_value( pStrTable ); } m_hashString.clear(); } /// 2011.03.14 나중에 또 쓸것 같아서 남겨 놓음- prodongi void SStringDB::addTestString(int id, char const* desc) { _STRING_TABLE_INFO * pFindStrTable = NULL; if( m_hashString.lookup(id, pFindStrTable ) == false) { _STRING_TABLE_INFO * pStrInfo = new _STRING_TABLE_INFO; memset( pStrInfo, 0, sizeof(_STRING_TABLE_INFO) ); pStrInfo->SetInfo( id, 0, desc ); m_hashString.add( pStrInfo->nID, pStrInfo ); } else { delete [] pFindStrTable->pStrDesc; pFindStrTable->pStrDesc = allocString( desc); } } void SStringDB::LoadStringDB() { // gmpbigsun( 20130423 ) : In English-speaking regions, it is said that if an apostrophe (') appears, the following string gets truncated. // I applied the database but could not find the issue. Destroy(); std::string strResourceFileName = "db_String"; if( m_strLocale.size() ) { strResourceFileName += "("; strResourceFileName += m_strLocale; //strResourceFileName += ENV().GetString("lang", "en"); strResourceFileName += ")"; } strResourceFileName += ".rdb"; KStream * pRes = KFileManager::Instance().CreateStreamFromResource( strResourceFileName.c_str() ); if( !pRes && m_strLocale.size()) { pRes = KFileManager::Instance().CreateStreamFromResource( "db_String.rdb" ); if( !pRes ) return; } if( !pRes ) return; GAME_DB db_hdr; pRes->Read( &db_hdr, sizeof(db_hdr) ); _STRING_TABLE StrData; char* szKey = NULL; size_t nKeyAllocSize = 0; char* szDesc = NULL; size_t nDescAllocSize = 0; unsigned int nKey = 0, nDesc = 0; for( int i(0); db_hdr.nCount>i; i++ ) { memset( &StrData, 0, sizeof(StrData) ); pRes->Read( &nKey, sizeof( nKey ) ); //KeySize pRes->Read( &nDesc, sizeof( nDesc ) ); //DescSize if( nKey+1 > nKeyAllocSize ) { nKeyAllocSize = nKey+1; if( szKey != NULL ) { delete [] szKey; szKey = NULL; } szKey = new char[nKeyAllocSize]; } if( nDesc+1 > nDescAllocSize ) { nDescAllocSize = nDesc+1; if( szDesc != NULL ) { delete [] szDesc; szDesc = NULL; } szDesc = new char[nDescAllocSize]; } pRes->Read( szKey, sizeof(char) * nKey ); //KeySize pRes->Read( szDesc, sizeof(char) * nDesc ); //DescSize szKey[nKey] = '\0'; szDesc[nDesc] = '\0'; pRes->Read( &StrData, sizeof(StrData) ); StrData.szKey = szKey; StrData.szDesc = szDesc; _STRING_TABLE_INFO * pFindStrTable = NULL; if( m_hashString.lookup( StrData.nID, pFindStrTable ) == false ) { _STRING_TABLE_INFO * pStrInfo = new _STRING_TABLE_INFO; memset( pStrInfo, 0, sizeof(_STRING_TABLE_INFO) ); pStrInfo->SetInfo( &StrData ); m_hashString.add( pStrInfo->nID, pStrInfo ); } else { // assert(0); //기획팀에 알려 주세여. 바로 수정 해야 합니다. } // _oprint( "String Info : %d, %s\n", pStrData->nID, pStrData->strDesc ); } StrData.szDesc = NULL; StrData.szKey = NULL; nKeyAllocSize = 0; nDescAllocSize = 0; if( szKey != NULL ) { delete [] szKey; szKey = NULL; } if( szDesc != NULL ) { delete [] szDesc; szDesc = NULL; } KFileManager::Instance().DeleteStream( pRes ); // { tab-separated text 에서 읽는루틴. { std::string strResourceFileName = "string_resource"; if (m_strLocale.size()) { strResourceFileName += "("; strResourceFileName += m_strLocale; //strResourceFileName += ENV().GetString("lang", "en"); strResourceFileName += ")"; } strResourceFileName += ".txt"; KStream* pTextRes = KFileManager::Instance().CreateStreamFromResource(strResourceFileName.c_str()); if (!pTextRes && m_strLocale.size()) { pTextRes = KFileManager::Instance().CreateStreamFromResource("string_resource.txt"); } if( pTextRes ) { // string_id "string" const char* buffer = static_cast(pTextRes->GetMappedPtr(KStream::MAPPED_READ)); std::string strText = buffer; csv_traits< char > traits( "\t" ); csv_string_stream< char > stream( strText ); while( stream.eof() == false ) { auto vValues = csv_parser< char >::get_row( stream, traits ); if( vValues.empty() || vValues.size() < 2 ) { continue; } XStringUtil::Trim( vValues[0] ); XStringUtil::Trim( vValues[1] ); if( vValues[0].front() == '#' ) // 주석 { continue; } int nID = atoi( vValues[0].c_str() ); if( nID == 0 ) { continue; } _STRING_TABLE_INFO * pFindStrTable = NULL; if( m_hashString.lookup( nID, pFindStrTable ) == false ) { _STRING_TABLE_INFO * pStrInfo = new _STRING_TABLE_INFO; memset( pStrInfo, 0, sizeof(_STRING_TABLE_INFO) ); pStrInfo->SetInfo( nID, 0, vValues[1].c_str() ); m_hashString.add( pStrInfo->nID, pStrInfo ); } else { delete [] pFindStrTable->pStrDesc; pFindStrTable->pStrDesc = allocString( vValues[1].c_str() ); } } KFileManager::Instance().DeleteStream( pTextRes ); } } // } // { string -> string id 변환 테이블 { KStream * pTextRes = KFileManager::Instance().CreateStreamFromResource( "string_table.txt" ); if( pTextRes ) { //"string" string_id const char* buffer = static_cast(pTextRes->GetMappedPtr(KStream::MAPPED_READ)); std::string strText = buffer; csv_traits< char > traits( "\t" ); csv_string_stream< char > stream( strText ); while( stream.eof() == false ) { auto vValues = csv_parser< char >::get_row( stream, traits ); if( vValues.empty() || vValues.size() < 2 ) { continue; } XStringUtil::Trim( vValues[0] ); XStringUtil::Trim( vValues[1] ); if( vValues[0].front() == '#' ) // 주석 { continue; } int nID = atoi( vValues[1].c_str() ); if( nID == 0 ) { continue; } if( m_hashTable.has( vValues[0].c_str() ) == false ) { m_hashTable.add( vValues[0].c_str(), nID ); } else { m_hashTable.modify( vValues[0].c_str(), nID ); } } KFileManager::Instance().DeleteStream( pTextRes ); } } // } } ////////////////////////////////////////////////////////////////////////// const char * SStringDB::GetCobFileName( int nRace, int nSex ) { if( nRace == GCLAN_GAIA && nSex == SEX_FEMALE ) return "gaf"; else if( nRace == GCLAN_GAIA && nSex == SEX_MALE ) return "gam"; else if( nRace == GCLAN_DEVA && nSex == SEX_FEMALE ) return "def"; else if( nRace == GCLAN_DEVA && nSex == SEX_MALE ) return "dem"; else if( nRace == GCLAN_ASURA && nSex == SEX_FEMALE ) return "asf"; else if( nRace == GCLAN_ASURA && nSex == SEX_MALE ) return "asm"; return ""; } std::string SStringDB::GetTaggedHttpLink( const std::string& strText ) { size_t sTagStart = strText.find( "", sTagStart ); if( sTagEnd != std::string::npos ) { return strText.substr( sTagStart+2, (sTagEnd-sTagStart-2) ); } } return std::string(); } int SStringDB::GetTaggedStringID( const std::string& strText ) { std::string::size_type sTagStart = strText.find( "<$" ); if( sTagStart != std::string::npos ) { std::string::size_type sTagEnd = strText.find_first_of( ">", sTagStart ); if( sTagEnd != std::string::npos ) { std::string strId = strText.substr( sTagStart+2, (sTagEnd-sTagStart-2) ); std::string::size_type sep = strId.find( ":" ); if( sep != std::string::npos ) { strId = strId.substr( 0, sep ); } if( !strId.empty() ) { return atoi( strId.c_str() ); } } } return 0; } SStringDB* SStringDB::m_pThis = NULL; SStringDB & GetStringDB() { if( NULL == SStringDB::m_pThis ) SStringDB::m_pThis = new SStringDB; return *SStringDB::m_pThis; } const char * SStringDB::GetString( const char *szString ) { int nID = 0; if( m_hashTable.lookup( szString, nID ) == false ) { return szString; } return GetString( nID ); } int SStringDB::GetGroupID( int nID ) { #ifdef _DEV if( nID < 0 ) { char error_msg[512]; s_sprintf( error_msg, _countof( error_msg ), "아직 변경되지 않은 Mapping string Group id(%d) 입력 받음 프로그램팀에게 연락바람", nID ); ::MessageBox( NULL, error_msg, "ERROR", MB_OK | MB_ICONERROR ); } #endif _STRING_TABLE_INFO * strData = GetStringData( nID ); if( strData ) { return strData->nGroupID; } return -1; } bool SStringDB::SetLocale( const char *szLocale ) { if( _stricmp( m_strLocale.c_str(), szLocale ) == 0 ) { return true; } LoadStringDB(); return true; } std::string SStringDB::ParseString( int nID, const char *szFrom1 , const char *szTo1 , const char *szFrom2 , const char *szTo2 , const char *szFrom3 , const char *szTo3 , const char *szFrom4 , const char *szTo4 ) { return ParseString( GetStringDB().GetString( nID ), szFrom1, szTo1, szFrom2, szTo2, szFrom3, szTo3, szFrom4, szTo4 ); } std::string SStringDB::ParseString( const char *szString, const char *szFrom1, const char *szTo1, const char *szFrom2, const char *szTo2, const char *szFrom3, const char *szTo3, const char *szFrom4, const char *szTo4 ) { std::string strTemp = szString; if( szFrom1 ) XStringUtil::Replace( strTemp, szFrom1, szTo1 ); if( szFrom2 ) XStringUtil::Replace( strTemp, szFrom2, szTo2 ); if( szFrom3 ) XStringUtil::Replace( strTemp, szFrom3, szTo3 ); if( szFrom4 ) XStringUtil::Replace( strTemp, szFrom4, szTo4 ); return strTemp; } std::string SStringDB::ToString( int nValue ) { std::string strTmp; XStringUtil::Format( strTmp, "%d", nValue ); return strTmp; } std::string SStringDB::ToString( __int64 nValue ) { std::string strTmp; XStringUtil::Format( strTmp, "%I64d", nValue ); return strTmp; } // sonador 10.4.1 스킬 툴팁 리뉴얼 std::string SStringDB::ToString( float fValue ) { std::string strTmp; XStringUtil::Format( strTmp, "%.2f", fValue ); return strTmp; } ////////////////////////////////////////////////////////////////////////// // SAbuseDB::SAbuseDB() { Init(); } SAbuseDB::~SAbuseDB() { Destroy(); } void SAbuseDB::Init() { Load(); } void SAbuseDB::Destroy() { AbuseFilter::ClearRule(); } void SAbuseDB::Load() { KStream * pRes = KFileManager::Instance().CreateStreamFromResource( "abuse_list.txt" ); if( !pRes ) return; size_t nLen = pRes->GetLength(); char * pstrTemp = new char[nLen+1]; pstrTemp[nLen] = '\0'; for( size_t i(0); nLen>i; i++ ) { pRes->Read( &pstrTemp[i], 1 ); } std::vector< std::string > vString; /// 2011.11.16 특수키 체크를 안한다. 대만 중문 같은 경우에 특수키가 체크되어서 백스페이스가 삭제되면 /// 구분자 체크가 제대로 안되는 경우가 생김- prodongi //XStringUtil::Split( pstrTemp, vString, "\t\r\n", false ); char newCmd[512]; int nCount = 0; for ( unsigned i = 0 ; i <= nLen ; i++ ) { newCmd[nCount] = pstrTemp[i]; if ( pstrTemp[i] == '\n' || pstrTemp[i] == '\0' ) { if ( pstrTemp[i-1] == '\r' ) newCmd[nCount-1] = '\0'; newCmd[nCount] = '\0'; vString.push_back( newCmd ); memset ( newCmd, 0, sizeof ( newCmd ) ); nCount = 0; } else nCount++; } int nLoop = (int)vString.size()/2; int n=0; // AziaMafia CP_UTF8 //DWORD CodePage = GetCodePageFromLang((LANGID)GetSystemDefaultLangID()); DWORD CodePage = GetCodePageFromLang((LANGID)GetSystemDefaultLangID()); //for( int i(0); nLoop>i; i++ ) //{ // std::string abuse = vString[n++].c_str(); // std::string change = vString[n++].c_str(); // std::wstring strAbuse = nsl::uni::conv( abuse ); // std::wstring strChange = nsl::uni::conv( change ); // // WCHAR strWChar[1024] = {0,}; // MultiByteToWideChar(CodePage, NULL, abuse.c_str(), -1, strWChar, sizeof ( strWChar )); // //AbuseFilter::AddRule( strAbuse.c_str(), strChange.c_str() ); // AbuseFilter::AddRule( strWChar, strChange.c_str() ); //} for( int i(0); iGetLength(); char * pstrTemp = new char[nLen+1]; pstrTemp[nLen] = '\0'; for( size_t i(0); nLen>i; i++ ) { pRes->Read( &pstrTemp[i], 1 ); } std::vector< std::string > vString; XStringUtil::Split( pstrTemp, vString, "|\r\n" ); int nLoop = (int)vString.size()/4; int n=0; for( int i(0); nLoop>i; i++ ) { _SEND_TOWN_INFO_ send_town_info; send_town_info.nID = atoi( vString[n++].c_str() ); send_town_info.strName = vString[n++].c_str(); send_town_info.strXpos = vString[n++].c_str(); send_town_info.strYpos = vString[n++].c_str(); m_vSendTownList.push_back( send_town_info ); } vString.clear(); delete [] pstrTemp; KFileManager::Instance().DeleteStream( pRes ); } bool SSendTownDB::GetSendTownPosition( int nIndex, std::string & strX, std::string & strY ) { for( unsigned int i(0); m_vSendTownList.size()>i; i++ ) { if( m_vSendTownList[i].nID == nIndex ) { strX = m_vSendTownList[i].strXpos; strY = m_vSendTownList[i].strYpos; return true; } } return false; } SSendTownDB & GetSendTownDB() { static SSendTownDB sendtowndb; return sendtowndb; } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// SSkinColorTable::SSkinColorTable() { Init(); } SSkinColorTable::~SSkinColorTable() { Destroy(); } void SSkinColorTable::Init() { Load(); } void SSkinColorTable::Destroy() { } void SSkinColorTable::Load() { KStream * pRes = KFileManager::Instance().CreateStreamFromResource( "ColorTableforSkin.txt" ); if( !pRes ) return; size_t nLen = pRes->GetLength(); char * pstrTemp = new char[nLen+1]; pstrTemp[nLen] = '\0'; for( size_t i(0); nLen > i; i++ ) { pRes->Read( &pstrTemp[i], 1 ); } std::vector< std::string > vString; XStringUtil::Split( pstrTemp, vString, "|\r\n" ); int nLoop = (int)vString.size() / 9; int n = 0; char *HEX_P; for( int i(0); nLoop > i; i++ ) { vString[n++].c_str(); //종족 _SKIN_COLOR_ color1; _SKIN_COLOR_ color2; _SKIN_COLOR_ color3; _SKIN_COLOR_ color4; // Four colors used for each race color1.color_value = strtoul(vString[n++].c_str(), &HEX_P, 10); color2.color_value = strtoul(vString[n++].c_str(), &HEX_P, 10); color3.color_value = strtoul(vString[n++].c_str(), &HEX_P, 10); color4.color_value = strtoul(vString[n++].c_str(), &HEX_P, 10); // Value displayed in the UI color1.color_view = strtoul(vString[n++].c_str(), &HEX_P, 10); color2.color_view = strtoul(vString[n++].c_str(), &HEX_P, 10); color3.color_view = strtoul(vString[n++].c_str(), &HEX_P, 10); color4.color_view = strtoul(vString[n++].c_str(), &HEX_P, 10); color1.color_value |= 0xff000000; color2.color_value |= 0xff000000; color3.color_value |= 0xff000000; color4.color_value |= 0xff000000; color1.color_view |= 0xff000000; color2.color_view |= 0xff000000; color3.color_view |= 0xff000000; color4.color_view |= 0xff000000; m_vColorTable[i].push_back(color1); m_vColorTable[i].push_back(color2); m_vColorTable[i].push_back(color3); m_vColorTable[i].push_back(color4); } vString.clear(); delete [] pstrTemp; KFileManager::Instance().DeleteStream( pRes ); } unsigned long SSkinColorTable::GetColorValue( int nRaceIndex, int nColorIndex ) { //현재 종족 3개 임. if( nRaceIndex < 0 || nRaceIndex > 2 ) { assert(0); return 0; } if( nColorIndex < 0 || nColorIndex >= (int)m_vColorTable[nRaceIndex].size() ) { assert(0); return 0; } return m_vColorTable[nRaceIndex][nColorIndex].color_value; } void SSkinColorTable::GetColorTable( int nRaceIndex, std::vector& color_list ) { if( nRaceIndex < 0 || nRaceIndex > 2 ) return; for( unsigned int i(0); m_vColorTable[nRaceIndex].size() > i; i++ ) { color_list.push_back( m_vColorTable[nRaceIndex][i].color_view ); } } void SSkinColorTable::GetAllColorTable( std::vector& color_list ) { for( unsigned int n(0); 3>n; n++ ) { for( unsigned int i(0); m_vColorTable[n].size()>i; i++ ) { color_list.push_back( m_vColorTable[n][i].color_view ); } } } SSkinColorTable& GetSkinColorTable() { static SSkinColorTable skincolortable; return skincolortable; }