From cc8fa1e78af90dc8885d43deface3a506ec904db Mon Sep 17 00:00:00 2001 From: server Date: Mon, 13 Apr 2026 21:42:22 +0200 Subject: [PATCH] game: prepare name lookup queries --- src/game/guild_manager.cpp | 68 +++++++++++++++++++++------ src/game/questlua_pc.cpp | 96 +++++++++++++++++++++++++++++++------- 2 files changed, 134 insertions(+), 30 deletions(-) diff --git a/src/game/guild_manager.cpp b/src/game/guild_manager.cpp index f8f93c3..0d74c1b 100644 --- a/src/game/guild_manager.cpp +++ b/src/game/guild_manager.cpp @@ -15,9 +15,55 @@ #include "locale_service.h" #include "guild_manager.h" #include "MarkManager.h" +#include "libsql/Statement.h" + +#include namespace { + bool PrepareGameStmt(CStmt& stmt, const std::string& query) + { + CAsyncSQL* sql = DBManager::instance().GetDirectSQL(); + + if (!sql) + { + sys_err("game direct SQL handle is not initialized"); + return false; + } + + return stmt.Prepare(sql, query.c_str()); + } + + bool GuildNameExists(const char* guildName, bool& exists) + { + CStmt stmt; + const std::string query = std::string("SELECT COUNT(*) FROM guild") + get_table_postfix() + " WHERE name=?"; + uint32_t count = 0; + + exists = false; + + if (!PrepareGameStmt(stmt, query)) + return false; + + if (!stmt.BindParam(MYSQL_TYPE_STRING, const_cast(guildName)) + || !stmt.BindResult(MYSQL_TYPE_LONG, &count)) + { + return false; + } + + if (!stmt.Execute()) + return false; + + if (stmt.iRows == 0) + return true; + + if (!stmt.Fetch()) + return false; + + exists = count != 0; + return true; + } + struct FGuildNameSender { @@ -81,25 +127,20 @@ DWORD CGuildManager::CreateGuild(TGuildCreateParameter& gcp) return 0; } - auto pmsg = DBManager::instance().DirectQuery("SELECT COUNT(*) FROM guild%s WHERE name = '%s'", - get_table_postfix(), gcp.name); + bool guildNameExists = false; - if (pmsg->Get()->uiNumRows > 0) - { - MYSQL_ROW row = mysql_fetch_row(pmsg->Get()->pSQLResult); - - if (!(row[0] && row[0][0] == '0')) - { - gcp.master->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 이미 같은 이름의 길드가 있습니다.")); - return 0; - } - } - else + if (!GuildNameExists(gcp.name, guildNameExists)) { gcp.master->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드를 생성할 수 없습니다.")); return 0; } + if (guildNameExists) + { + gcp.master->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 이미 같은 이름의 길드가 있습니다.")); + return 0; + } + // new CGuild(gcp) queries guild tables and tell dbcache to notice other game servers. // other game server calls CGuildManager::LoadGuild to load guild. CGuild * pg = M2_NEW CGuild(gcp); @@ -956,4 +997,3 @@ void CGuildManager::ChangeMaster(DWORD dwGID) "SELECT 1"); } - diff --git a/src/game/questlua_pc.cpp b/src/game/questlua_pc.cpp index 72940ea..34a7c09 100644 --- a/src/game/questlua_pc.cpp +++ b/src/game/questlua_pc.cpp @@ -19,9 +19,11 @@ #include "desc_client.h" #include "messenger_manager.h" #include "log.h" +#include "db.h" #include "utils.h" #include "unique_item.h" #include "mob_manager.h" +#include "libsql/Statement.h" #include #undef sys_err @@ -31,6 +33,69 @@ extern int g_nPortalLimitTime; extern LPCLIENT_DESC db_clientdesc; const int ITEM_BROKEN_METIN_VNUM = 28960; +namespace +{ + bool PrepareGameStmt(CStmt& stmt, const std::string& query) + { + CAsyncSQL* sql = DBManager::instance().GetDirectSQL(); + + if (!sql) + { + sys_err("game direct SQL handle is not initialized"); + return false; + } + + return stmt.Prepare(sql, query.c_str()); + } + + bool CharacterNameExists(const char* name, bool& exists) + { + CStmt stmt; + const std::string query = std::string("SELECT COUNT(*) FROM player") + get_table_postfix() + " WHERE name=?"; + uint32_t count = 0; + + exists = false; + + if (!PrepareGameStmt(stmt, query)) + return false; + + if (!stmt.BindParam(MYSQL_TYPE_STRING, const_cast(name)) + || !stmt.BindResult(MYSQL_TYPE_LONG, &count)) + { + return false; + } + + if (!stmt.Execute()) + return false; + + if (stmt.iRows == 0) + return true; + + if (!stmt.Fetch()) + return false; + + exists = count != 0; + return true; + } + + bool UpdateCharacterName(uint32_t playerId, const char* name) + { + CStmt stmt; + const std::string query = std::string("UPDATE player") + get_table_postfix() + " SET name=? WHERE id=?"; + + if (!PrepareGameStmt(stmt, query)) + return false; + + if (!stmt.BindParam(MYSQL_TYPE_STRING, const_cast(name)) + || !stmt.BindParam(MYSQL_TYPE_LONG, &playerId)) + { + return false; + } + + return stmt.Execute(); + } +} + namespace quest { // @@ -2114,23 +2179,19 @@ teleport_area: return 1; } - char szQuery[1024]; - snprintf(szQuery, sizeof(szQuery), "SELECT COUNT(*) FROM player%s WHERE name='%s'", get_table_postfix(), szName); - auto pmsg = DBManager::instance().DirectQuery(szQuery); + bool characterNameExists = false; - if ( pmsg->Get()->uiNumRows > 0 ) + if (!CharacterNameExists(szName, characterNameExists)) { - MYSQL_ROW row = mysql_fetch_row(pmsg->Get()->pSQLResult); + lua_pushnumber(L, 0); + return 1; + } - int count = 0; - str_to_number(count, row[0]); - - // 이미 해당 이름을 가진 캐릭터가 있음 - if ( count != 0 ) - { - lua_pushnumber(L, 3); - return 1; - } + // 이미 해당 이름을 가진 캐릭터가 있음 + if (characterNameExists) + { + lua_pushnumber(L, 3); + return 1; } DWORD pid = ch->GetPlayerID(); @@ -2144,8 +2205,11 @@ teleport_area: /* change_name_log */ LogManager::instance().ChangeNameLog(pid, ch->GetName(), szName, ch->GetDesc()->GetHostName()); - snprintf(szQuery, sizeof(szQuery), "UPDATE player%s SET name='%s' WHERE id=%u", get_table_postfix(), szName, pid); - DBManager::instance().DirectQuery(szQuery); + if (!UpdateCharacterName(pid, szName)) + { + lua_pushnumber(L, 0); + return 1; + } ch->SetNewName(szName); lua_pushnumber(L, 4);