diff --git a/src/game/config.cpp b/src/game/config.cpp index 190a3c9..5273fe6 100644 --- a/src/game/config.cpp +++ b/src/game/config.cpp @@ -21,6 +21,7 @@ #include "config.h" #include "db.h" #include "skill_power.h" +#include "libsql/Statement.h" using std::string; @@ -177,6 +178,19 @@ namespace else fprintf(stdout, "ADMIN_PAGE: enabled for %zu IP entries\n", g_stAdminPageIP.size()); } + + bool PrepareAccountStmt(CStmt& stmt, const std::string& query) + { + CAsyncSQL2* sql = AccountDB::instance().GetDirectSQL(); + + if (!sql) + { + fprintf(stderr, "AccountDB direct SQL handle is not initialized\n"); + return false; + } + + return stmt.Prepare(sql, query.c_str()); + } } BYTE g_bChannel = 0; @@ -913,27 +927,41 @@ void config_init(const string& st_localeServiceName) // 로케일 정보를 가져오자 // <경고> 쿼리문에 절대 조건문(WHERE) 달지 마세요. (다른 지역에서 문제가 생길수 있습니다) { - char szQuery[512]; - snprintf(szQuery, sizeof(szQuery), "SELECT mKey, mValue FROM locale"); + CStmt stmt; + char localeKey[256]; + char localeValue[4096]; + const char* localeQuery = "SELECT mKey, mValue FROM locale"; - auto pMsg = AccountDB::instance().DirectQuery(szQuery); + memset(localeKey, 0, sizeof(localeKey)); + memset(localeValue, 0, sizeof(localeValue)); - if (pMsg->Get()->uiNumRows == 0) + if (!PrepareAccountStmt(stmt, localeQuery) + || !stmt.BindResult(MYSQL_TYPE_STRING, localeKey, sizeof(localeKey)) + || !stmt.BindResult(MYSQL_TYPE_STRING, localeValue, sizeof(localeValue)) + || !stmt.Execute() + || stmt.iRows == 0) { - fprintf(stderr, "COMMON_SQL: DirectQuery failed : %s\n", szQuery); + fprintf(stderr, "COMMON_SQL: DirectQuery failed : %s\n", localeQuery); exit(1); } - MYSQL_ROW row; - - while (NULL != (row = mysql_fetch_row(pMsg->Get()->pSQLResult))) + for (int i = 0; i < stmt.iRows; ++i) { - // 로케일 세팅 - if (strcasecmp(row[0], "LOCALE") == 0) + memset(localeKey, 0, sizeof(localeKey)); + memset(localeValue, 0, sizeof(localeValue)); + + if (!stmt.Fetch()) { - if (LocaleService_Init(row[1]) == false) + fprintf(stderr, "COMMON_SQL: DirectQuery failed : %s\n", localeQuery); + exit(1); + } + + // 로케일 세팅 + if (strcasecmp(localeKey, "LOCALE") == 0) + { + if (LocaleService_Init(localeValue) == false) { - fprintf(stderr, "COMMON_SQL: invalid locale key %s\n", row[1]); + fprintf(stderr, "COMMON_SQL: invalid locale key %s\n", localeValue); exit(1); } } @@ -983,21 +1011,25 @@ void config_init(const string& st_localeServiceName) // 스트링 비교의 문제로 인해서 AccountDB::instance().SetLocale(g_stLocale) 후부터 한다. // 물론 국내는 별로 문제가 안된다(해외가 문제) { - char szQuery[256]; - snprintf(szQuery, sizeof(szQuery), "SELECT mValue FROM locale WHERE mKey='SKILL_POWER_BY_LEVEL'"); - auto pMsg = AccountDB::instance().DirectQuery(szQuery); + CStmt stmt; + char localeKey[] = "SKILL_POWER_BY_LEVEL"; + char skillPowerByLevel[4096]; + const char* localeQuery = "SELECT mValue FROM locale WHERE mKey=?"; - if (pMsg->Get()->uiNumRows == 0) + memset(skillPowerByLevel, 0, sizeof(skillPowerByLevel)); + + if (!PrepareAccountStmt(stmt, localeQuery) + || !stmt.BindParam(MYSQL_TYPE_STRING, localeKey) + || !stmt.BindResult(MYSQL_TYPE_STRING, skillPowerByLevel, sizeof(skillPowerByLevel)) + || !stmt.Execute() + || stmt.iRows == 0 + || !stmt.Fetch()) { - fprintf(stderr, "[SKILL_PERCENT] Query failed: %s", szQuery); + fprintf(stderr, "[SKILL_PERCENT] Query failed: %s", localeQuery); exit(1); } - MYSQL_ROW row; - - row = mysql_fetch_row(pMsg->Get()->pSQLResult); - - const char * p = row[0]; + const char * p = skillPowerByLevel; int cnt = 0; char num[128]; int aiBaseSkillPowerByLevelTable[SKILL_MAX_LEVEL+1]; @@ -1013,7 +1045,7 @@ void config_init(const string& st_localeServiceName) { if (cnt != (SKILL_MAX_LEVEL + 1)) { - fprintf(stderr, "[SKILL_PERCENT] locale table has not enough skill information! (count: %d query: %s)", cnt, szQuery); + fprintf(stderr, "[SKILL_PERCENT] locale table has not enough skill information! (count: %d query: %s)", cnt, localeQuery); exit(1); } @@ -1025,19 +1057,32 @@ void config_init(const string& st_localeServiceName) // 종족별 스킬 세팅 for (int job = 0; job < JOB_MAX_NUM * 2; ++job) { - snprintf(szQuery, sizeof(szQuery), "SELECT mValue from locale where mKey='SKILL_POWER_BY_LEVEL_TYPE%d' ORDER BY CAST(mValue AS unsigned)", job); - auto pMsg = AccountDB::instance().DirectQuery(szQuery); + CStmt jobStmt; + char jobLocaleKey[64]; + char skillPowerByJob[4096]; + const char* jobQuery = "SELECT mValue FROM locale WHERE mKey=? ORDER BY CAST(mValue AS unsigned)"; - // 세팅이 안되어있으면 기본테이블을 사용한다. - if (pMsg->Get()->uiNumRows == 0) + snprintf(jobLocaleKey, sizeof(jobLocaleKey), "SKILL_POWER_BY_LEVEL_TYPE%d", job); + memset(skillPowerByJob, 0, sizeof(skillPowerByJob)); + + if (!PrepareAccountStmt(jobStmt, jobQuery) + || !jobStmt.BindParam(MYSQL_TYPE_STRING, jobLocaleKey) + || !jobStmt.BindResult(MYSQL_TYPE_STRING, skillPowerByJob, sizeof(skillPowerByJob)) + || !jobStmt.Execute()) + { + CTableBySkill::instance().SetSkillPowerByLevelFromType(job, aiBaseSkillPowerByLevelTable); + continue; + } + + // 세팅이 안되어있으면 기본테이블을 사용한다. + if (jobStmt.iRows == 0 || !jobStmt.Fetch()) { CTableBySkill::instance().SetSkillPowerByLevelFromType(job, aiBaseSkillPowerByLevelTable); continue; } - row = mysql_fetch_row(pMsg->Get()->pSQLResult); cnt = 0; - p = row[0]; + p = skillPowerByJob; int aiSkillTable[SKILL_MAX_LEVEL + 1]; fprintf(stdout, "SKILL_POWER_BY_JOB %d %s\n", job, p); @@ -1051,7 +1096,7 @@ void config_init(const string& st_localeServiceName) { if (cnt != (SKILL_MAX_LEVEL + 1)) { - fprintf(stderr, "[SKILL_PERCENT] locale table has not enough skill information! (count: %d query: %s)", cnt, szQuery); + fprintf(stderr, "[SKILL_PERCENT] locale table has not enough skill information! (count: %d query: %s)", cnt, jobQuery); exit(1); } @@ -1300,4 +1345,3 @@ bool IsValidFileCRC(DWORD dwCRC) { return s_set_dwFileCRC.find(dwCRC) != s_set_dwFileCRC.end(); } - diff --git a/src/game/db.h b/src/game/db.h index 6bd9ffc..1f870da 100644 --- a/src/game/db.h +++ b/src/game/db.h @@ -166,6 +166,7 @@ class AccountDB : public singleton std::unique_ptr DirectQuery(const char* query); void ReturnQuery(int iType, DWORD dwIdent, void * pvData, const char * c_pszFormat, ...); void AsyncQuery(const char* query); + CAsyncSQL2* GetDirectSQL() { return &m_sql_direct; } void SetLocale(const std::string & stLocale);