Files
2026-06-01 12:46:52 +02:00

855 lines
19 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "stdafx.h"
#include "SStringDB.h"
#include <Windows.h>
#include <kfile/KStream.h>
#include "KResourceManager.h"
#include <toolkit/XStringUtil.h>
#include <toolkit/csv_parser.h>
#include "KTypes.h"
#include "GameDefine.h"
#include "SkillBaseFile.h"
#include "KTextRender.h"
//#include "Util.h"
#include <kfile/KFileManager.h>
#include "XAbuseFilter.h"
#include <toolkit/nsl.h>
#include <toolkit/nsluni.h>
#include <sstream>
#include <map>
#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 hasnt 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><B>[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<const char*>(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<const char*>(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( "</http" );
if( sTagStart != std::string::npos )
{
size_t sTagEnd = strText.find_first_of( ">", 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); i<vString.size(); i++,n++ )
{
int nToggle = vString[n].find ( "\t" );
std::string abuse = vString[n].substr(0,nToggle);
std::string change = vString[n].substr(nToggle+1);
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( strWChar, strChange.c_str() );
}
vString.clear();
delete [] pstrTemp;
KFileManager::Instance().DeleteStream( pRes );
}
SAbuseDB & GetAbuseDB()
{
static SAbuseDB abusedb;
return abusedb;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//
SSendTownDB::SSendTownDB()
{
Init();
}
SSendTownDB::~SSendTownDB()
{
Destroy();
}
void SSendTownDB::Init()
{
Load();
}
void SSendTownDB::Destroy()
{
}
void SSendTownDB::Load()
{
KStream * pRes = KFileManager::Instance().CreateStreamFromResource( "sendtown_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;
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<unsigned long>& 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<unsigned long>& 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;
}