From 063d92f876998b2444e765494dbab1b2ce253feb Mon Sep 17 00:00:00 2001 From: server Date: Mon, 13 Apr 2026 22:08:01 +0200 Subject: [PATCH] db: prepare guild and flag lookups --- src/db/ClientManagerEventFlag.cpp | 118 +++++++++++++++++++++------ src/db/ClientManagerGuild.cpp | 127 +++++++++++++++++++++++------- src/db/ClientManagerHorseName.cpp | 96 +++++++++++++++++----- 3 files changed, 267 insertions(+), 74 deletions(-) diff --git a/src/db/ClientManagerEventFlag.cpp b/src/db/ClientManagerEventFlag.cpp index 3bb2b81..ee72287 100644 --- a/src/db/ClientManagerEventFlag.cpp +++ b/src/db/ClientManagerEventFlag.cpp @@ -5,26 +5,104 @@ #include "Config.h" #include "DBManager.h" #include "QID.h" +#include "libsql/Statement.h" + +#include +#include + +namespace +{ + bool PrepareEventFlagStmt(CStmt& stmt, const std::string& query) + { + CAsyncSQL* sql = CDBManager::instance().GetDirectSQL(SQL_PLAYER); + + if (!sql) + { + sys_err("player SQL handle is not initialized"); + return false; + } + + return stmt.Prepare(sql, query.c_str()); + } + + bool LoadStoredEventFlags(std::vector& flags) + { + CStmt stmt; + char flagName[EVENT_FLAG_NAME_MAX_LEN + 1] = {}; + int32_t flagValue = 0; + const std::string query = std::string("SELECT szName, lValue FROM quest") + GetTablePostfix() + " WHERE dwPID = 0"; + + flags.clear(); + + if (!PrepareEventFlagStmt(stmt, query)) + return false; + + if (!stmt.BindResult(MYSQL_TYPE_STRING, flagName, sizeof(flagName)) + || !stmt.BindResult(MYSQL_TYPE_LONG, &flagValue) + || !stmt.Execute()) + { + return false; + } + + flags.reserve(stmt.iRows); + + for (int i = 0; i < stmt.iRows; ++i) + { + TPacketSetEventFlag packet = {}; + + memset(flagName, 0, sizeof(flagName)); + flagValue = 0; + + if (!stmt.Fetch()) + return false; + + size_t flagNameLen = stmt.GetResultLength(0); + if (flagNameLen >= sizeof(flagName)) + flagNameLen = sizeof(flagName) - 1; + + flagName[flagNameLen] = '\0'; + strlcpy(packet.szFlagName, flagName, sizeof(packet.szFlagName)); + packet.lValue = flagValue; + flags.push_back(packet); + } + + return true; + } + + bool ReplaceStoredEventFlag(const char* flagName, int32_t flagValue) + { + CStmt stmt; + const std::string query = std::string("REPLACE INTO quest") + GetTablePostfix() + + " (dwPID, szName, szState, lValue) VALUES(0, ?, '', ?)"; + + if (!PrepareEventFlagStmt(stmt, query)) + return false; + + if (!stmt.BindParam(MYSQL_TYPE_STRING, const_cast(flagName)) + || !stmt.BindParam(MYSQL_TYPE_LONG, &flagValue)) + { + return false; + } + + return stmt.Execute(); + } +} void CClientManager::LoadEventFlag() { - char szQuery[1024]; - snprintf(szQuery, sizeof(szQuery), "SELECT szName, lValue FROM quest%s WHERE dwPID = 0", GetTablePostfix()); - auto pmsg = CDBManager::instance().DirectQuery(szQuery); + std::vector flags; - SQLResult* pRes = pmsg->Get(); - if (pRes->uiNumRows) + if (!LoadStoredEventFlags(flags)) { - MYSQL_ROW row; - while ((row = mysql_fetch_row(pRes->pSQLResult))) - { - TPacketSetEventFlag p; - strlcpy(p.szFlagName, row[0], sizeof(p.szFlagName)); - str_to_number(p.lValue, row[1]); - sys_log(0, "EventFlag Load %s %d", p.szFlagName, p.lValue); - m_map_lEventFlag.insert(std::make_pair(std::string(p.szFlagName), p.lValue)); - ForwardPacket(DG::SET_EVENT_FLAG, &p, sizeof(TPacketSetEventFlag)); - } + sys_err("failed to load event flags"); + return; + } + + for (const auto& p : flags) + { + sys_log(0, "EventFlag Load %s %d", p.szFlagName, p.lValue); + m_map_lEventFlag.insert(std::make_pair(std::string(p.szFlagName), p.lValue)); + ForwardPacket(DG::SET_EVENT_FLAG, &p, sizeof(TPacketSetEventFlag)); } } @@ -48,14 +126,9 @@ void CClientManager::SetEventFlag(TPacketSetEventFlag* p) if (bChanged) { - char szQuery[1024]; - snprintf(szQuery, sizeof(szQuery), - "REPLACE INTO quest%s (dwPID, szName, szState, lValue) VALUES(0, '%s', '', %ld)", - GetTablePostfix(), p->szFlagName, static_cast(p->lValue)); - szQuery[1023] = '\0'; + if (!ReplaceStoredEventFlag(p->szFlagName, p->lValue)) + sys_err("failed to persist event flag %s", p->szFlagName); - //CDBManager::instance().ReturnQuery(szQuery, QID_QUEST_SAVE, 0, NULL); - CDBManager::instance().AsyncQuery(szQuery); sys_log(0, "GD::SET_EVENT_FLAG : Changed CClientmanager::SetEventFlag(%s %d) ", p->szFlagName, p->lValue); return; } @@ -73,4 +146,3 @@ void CClientManager::SendEventFlagsOnSetup(CPeer* peer) peer->Encode(&p, sizeof(TPacketSetEventFlag)); } } - diff --git a/src/db/ClientManagerGuild.cpp b/src/db/ClientManagerGuild.cpp index 74587fd..af34aa1 100644 --- a/src/db/ClientManagerGuild.cpp +++ b/src/db/ClientManagerGuild.cpp @@ -6,6 +6,96 @@ #include "DBManager.h" #include "QID.h" #include "GuildManager.h" +#include "libsql/Statement.h" + +#include + +namespace +{ + bool PrepareGuildStmt(CStmt& stmt, const std::string& query) + { + CAsyncSQL* sql = CDBManager::instance().GetDirectSQL(SQL_PLAYER); + + if (!sql) + { + sys_err("player SQL handle is not initialized"); + return false; + } + + return stmt.Prepare(sql, query.c_str()); + } + + bool InsertGuildMemberRow(uint32_t playerId, uint32_t guildId, uint8_t grade) + { + CStmt stmt; + const std::string query = std::string("INSERT INTO guild_member") + GetTablePostfix() + " VALUES(?, ?, ?, 0, 0)"; + + if (!PrepareGuildStmt(stmt, query)) + return false; + + if (!stmt.BindParam(MYSQL_TYPE_LONG, &playerId) + || !stmt.BindParam(MYSQL_TYPE_LONG, &guildId) + || !stmt.BindParam(MYSQL_TYPE_TINY, &grade)) + { + return false; + } + + return stmt.Execute(); + } + + bool LoadGuildMemberData(uint32_t guildId, uint32_t playerId, TPacketDGGuildMember* packet) + { + CStmt stmt; + uint32_t loadedPlayerId = 0; + uint8_t grade = 0; + uint8_t isGeneral = 0; + uint32_t offer = 0; + uint8_t level = 0; + uint8_t job = 0; + char name[CHARACTER_NAME_MAX_LEN + 1] = {}; + const std::string query = std::string("SELECT pid, grade, is_general, offer, level, job, name FROM guild_member") + + GetTablePostfix() + ", player" + GetTablePostfix() + " WHERE guild_id = ? and pid = id and pid = ?"; + + memset(packet, 0, sizeof(TPacketDGGuildMember)); + + if (!PrepareGuildStmt(stmt, query)) + return false; + + if (!stmt.BindParam(MYSQL_TYPE_LONG, &guildId) + || !stmt.BindParam(MYSQL_TYPE_LONG, &playerId) + || !stmt.BindResult(MYSQL_TYPE_LONG, &loadedPlayerId) + || !stmt.BindResult(MYSQL_TYPE_TINY, &grade) + || !stmt.BindResult(MYSQL_TYPE_TINY, &isGeneral) + || !stmt.BindResult(MYSQL_TYPE_LONG, &offer) + || !stmt.BindResult(MYSQL_TYPE_TINY, &level) + || !stmt.BindResult(MYSQL_TYPE_TINY, &job) + || !stmt.BindResult(MYSQL_TYPE_STRING, name, sizeof(name))) + { + return false; + } + + if (!stmt.Execute()) + return false; + + if (stmt.iRows == 0 || !stmt.Fetch()) + return false; + + size_t nameLen = stmt.GetResultLength(6); + if (nameLen >= sizeof(name)) + nameLen = sizeof(name) - 1; + + name[nameLen] = '\0'; + packet->dwGuild = guildId; + packet->dwPID = loadedPlayerId; + packet->bGrade = grade; + packet->isGeneral = isGeneral; + packet->dwOffer = offer; + packet->bLevel = level; + packet->bJob = job; + strlcpy(packet->szName, name, sizeof(packet->szName)); + return true; + } +} void CClientManager::GuildCreate(CPeer * peer, DWORD dwGuildID) @@ -27,40 +117,18 @@ void CClientManager::GuildAddMember(CPeer* peer, TPacketGDGuildAddMember * p) CGuildManager::instance().TouchGuild(p->dwGuild); sys_log(0, "GuildAddMember %u %u", p->dwGuild, p->dwPID); - char szQuery[512]; - - snprintf(szQuery, sizeof(szQuery), - "INSERT INTO guild_member%s VALUES(%u, %u, %d, 0, 0)", - GetTablePostfix(), p->dwPID, p->dwGuild, p->bGrade); - - auto pmsg_insert = CDBManager::instance().DirectQuery(szQuery); - - snprintf(szQuery, sizeof(szQuery), - "SELECT pid, grade, is_general, offer, level, job, name FROM guild_member%s, player%s WHERE guild_id = %u and pid = id and pid = %u", GetTablePostfix(), GetTablePostfix(), p->dwGuild, p->dwPID); - - auto pmsg = CDBManager::instance().DirectQuery(szQuery); - - if (pmsg->Get()->uiNumRows == 0) + if (!InsertGuildMemberRow(p->dwPID, p->dwGuild, p->bGrade)) { - sys_err("Query failed when getting guild member data %s", pmsg->stQuery.c_str()); + sys_err("failed to insert guild member %u for guild %u", p->dwPID, p->dwGuild); return; } - MYSQL_ROW row = mysql_fetch_row(pmsg->Get()->pSQLResult); - - if (!row[0] || !row[1]) - return; - TPacketDGGuildMember dg; - - dg.dwGuild = p->dwGuild; - str_to_number(dg.dwPID, row[0]); - str_to_number(dg.bGrade, row[1]); - str_to_number(dg.isGeneral, row[2]); - str_to_number(dg.dwOffer, row[3]); - str_to_number(dg.bLevel, row[4]); - str_to_number(dg.bJob, row[5]); - strlcpy(dg.szName, row[6], sizeof(dg.szName)); + if (!LoadGuildMemberData(p->dwGuild, p->dwPID, &dg)) + { + sys_err("failed to load guild member data for pid %u in guild %u", p->dwPID, p->dwGuild); + return; + } ForwardPacket(DG::GUILD_ADD_MEMBER, &dg, sizeof(TPacketDGGuildMember)); } @@ -241,4 +309,3 @@ void CClientManager::GuildChangeMaster(TPacketChangeGuildMaster* p) ForwardPacket(DG::ACK_CHANGE_GUILD_MASTER, &packet, sizeof(packet)); } } - diff --git a/src/db/ClientManagerHorseName.cpp b/src/db/ClientManagerHorseName.cpp index f8402a3..54e453e 100644 --- a/src/db/ClientManagerHorseName.cpp +++ b/src/db/ClientManagerHorseName.cpp @@ -1,40 +1,94 @@ // vim:ts=4 sw=4 #include "stdafx.h" #include "ClientManager.h" +#include "DBManager.h" +#include "libsql/Statement.h" + +#include + +namespace +{ + bool PrepareHorseStmt(CStmt& stmt, const std::string& query) + { + CAsyncSQL* sql = CDBManager::instance().GetDirectSQL(SQL_PLAYER); + + if (!sql) + { + sys_err("player SQL handle is not initialized"); + return false; + } + + return stmt.Prepare(sql, query.c_str()); + } + + bool ReplaceHorseName(uint32_t playerId, const char* horseName) + { + CStmt stmt; + const std::string query = "REPLACE INTO horse_name VALUES(?, ?)"; + + if (!PrepareHorseStmt(stmt, query)) + return false; + + if (!stmt.BindParam(MYSQL_TYPE_LONG, &playerId) + || !stmt.BindParam(MYSQL_TYPE_STRING, const_cast(horseName))) + { + return false; + } + + return stmt.Execute(); + } + + bool LoadHorseName(uint32_t playerId, char* horseName, size_t horseNameSize) + { + CStmt stmt; + const std::string query = "SELECT name FROM horse_name WHERE id=?"; + + horseName[0] = '\0'; + + if (!PrepareHorseStmt(stmt, query)) + return false; + + if (!stmt.BindParam(MYSQL_TYPE_LONG, &playerId) + || !stmt.BindResult(MYSQL_TYPE_STRING, horseName, static_cast(horseNameSize))) + { + return false; + } + + if (!stmt.Execute()) + return false; + + if (stmt.iRows == 0) + return true; + + if (!stmt.Fetch()) + return false; + + size_t horseNameLen = stmt.GetResultLength(0); + if (horseNameLen >= horseNameSize) + horseNameLen = horseNameSize - 1; + + horseName[horseNameLen] = '\0'; + return true; + } +} void CClientManager::UpdateHorseName(TPacketUpdateHorseName* data, CPeer* peer) { - char szQuery[512]; - - snprintf(szQuery, sizeof(szQuery), "REPLACE INTO horse_name VALUES(%u, '%s')", data->dwPlayerID, data->szHorseName); - - auto pmsg_insert = CDBManager::instance().DirectQuery(szQuery); + if (!ReplaceHorseName(data->dwPlayerID, data->szHorseName)) + sys_err("failed to update horse name for player %u", data->dwPlayerID); ForwardPacket(DG::UPDATE_HORSE_NAME, data, sizeof(TPacketUpdateHorseName), 0, peer); } void CClientManager::AckHorseName(DWORD dwPID, CPeer* peer) { - char szQuery[512]; - - snprintf(szQuery, sizeof(szQuery), "SELECT name FROM horse_name WHERE id = %u", dwPID); - - auto pmsg = CDBManager::instance().DirectQuery(szQuery); - TPacketUpdateHorseName packet; packet.dwPlayerID = dwPID; + memset(packet.szHorseName, 0, sizeof(packet.szHorseName)); - if (pmsg->Get()->uiNumRows == 0) - { - memset(packet.szHorseName, 0, sizeof (packet.szHorseName)); - } - else - { - MYSQL_ROW row = mysql_fetch_row(pmsg->Get()->pSQLResult); - strlcpy(packet.szHorseName, row[0], sizeof(packet.szHorseName)); - } + if (!LoadHorseName(dwPID, packet.szHorseName, sizeof(packet.szHorseName))) + sys_err("failed to load horse name for player %u", dwPID); peer->EncodeHeader(DG::ACK_HORSE_NAME, 0, sizeof(TPacketUpdateHorseName)); peer->Encode(&packet, sizeof(TPacketUpdateHorseName)); } -