From 84ed35cbdaf7ad9e019823908eb38cd216b67ac0 Mon Sep 17 00:00:00 2001 From: server Date: Tue, 14 Apr 2026 11:47:33 +0200 Subject: [PATCH] db: prepare safebox load bootstrap --- src/db/ClientManager.cpp | 359 +++++++++++++++++++++------------------ 1 file changed, 189 insertions(+), 170 deletions(-) diff --git a/src/db/ClientManager.cpp b/src/db/ClientManager.cpp index ed08a45..30c1431 100644 --- a/src/db/ClientManager.cpp +++ b/src/db/ClientManager.cpp @@ -40,6 +40,19 @@ int g_query_count[2]; namespace { +bool PrepareClientPlayerStmt(CStmt& stmt, const char* 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); +} + bool LoadSafeboxPasswordByAccountId(DWORD accountId, char* password, size_t passwordSize, bool* found) { char query[QUERY_MAX_LEN]; @@ -49,7 +62,7 @@ bool LoadSafeboxPasswordByAccountId(DWORD accountId, char* password, size_t pass password[0] = '\0'; CStmt stmt; - if (!stmt.Prepare(CDBManager::instance().GetDirectSQL(SQL_PLAYER), query)) + if (!PrepareClientPlayerStmt(stmt, query)) return false; if (!stmt.BindParam(MYSQL_TYPE_LONG, &accountId)) @@ -77,7 +90,7 @@ bool UpdateSafeboxPasswordByAccountId(DWORD accountId, const char* password) snprintf(query, sizeof(query), "UPDATE safebox%s SET password = ? WHERE account_id = ?", GetTablePostfix()); CStmt stmt; - if (!stmt.Prepare(CDBManager::instance().GetDirectSQL(SQL_PLAYER), query)) + if (!PrepareClientPlayerStmt(stmt, query)) return false; if (!stmt.BindParam(MYSQL_TYPE_STRING, const_cast(password), SAFEBOX_PASSWORD_MAX_LEN)) @@ -97,6 +110,88 @@ bool MatchesSafeboxPassword(const char* storedPassword, const char* providedPass return !strcmp("000000", providedPassword); } +bool LoadSafeboxTableByAccountId(DWORD accountId, const char* providedPassword, bool isMall, TSafeboxTable* safebox, bool* wrongPassword) +{ + char query[QUERY_MAX_LEN]; + snprintf(query, sizeof(query), "SELECT account_id, size, password FROM safebox%s WHERE account_id = ?", GetTablePostfix()); + + DWORD loadedAccountId = 0; + DWORD loadedSize = 0; + char storedPassword[SAFEBOX_PASSWORD_MAX_LEN + 1] = {}; + + CStmt stmt; + if (!PrepareClientPlayerStmt(stmt, query)) + return false; + + *wrongPassword = false; + memset(safebox, 0, sizeof(TSafeboxTable)); + + if (!stmt.BindParam(MYSQL_TYPE_LONG, &accountId)) + return false; + + if (!stmt.BindResult(MYSQL_TYPE_LONG, &loadedAccountId)) + return false; + + if (!stmt.BindResult(MYSQL_TYPE_LONG, &loadedSize)) + return false; + + if (!stmt.BindResult(MYSQL_TYPE_STRING, storedPassword, sizeof(storedPassword))) + return false; + + if (!stmt.Execute()) + return false; + + if (stmt.iRows == 0) + { + safebox->dwID = accountId; + *wrongPassword = strcmp("000000", providedPassword) != 0; + return true; + } + + if (!stmt.Fetch()) + return false; + + if (((!storedPassword[0]) && strcmp("000000", providedPassword)) + || (storedPassword[0] && strcmp(storedPassword, providedPassword))) + { + *wrongPassword = true; + return true; + } + + safebox->dwID = loadedAccountId == 0 ? accountId : loadedAccountId; + safebox->bSize = static_cast(loadedSize); + + if (isMall) + { + safebox->bSize = 1; + sys_log(0, "MALL id[%u] size[%u]", safebox->dwID, safebox->bSize); + } + else + { + sys_log(0, "SAFEBOX id[%u] size[%u]", safebox->dwID, safebox->bSize); + } + + return true; +} + +void QueueSafeboxItemsLoad(CPeer* peer, CClientManager::ClientHandleInfo* info) +{ + char query[512]; + snprintf(query, sizeof(query), + "SELECT id, window+0, pos, count, vnum, socket0, socket1, socket2, " + "attrtype0, attrvalue0, " + "attrtype1, attrvalue1, " + "attrtype2, attrvalue2, " + "attrtype3, attrvalue3, " + "attrtype4, attrvalue4, " + "attrtype5, attrvalue5, " + "attrtype6, attrvalue6 " + "FROM item%s WHERE owner_id=%u AND window='%s'", + GetTablePostfix(), info->account_id, info->ip[0] == 0 ? "SAFEBOX" : "MALL"); + + CDBManager::instance().ReturnQuery(query, QID_SAFEBOX_LOAD, peer->GetHandle(), info); +} + void EncodeSafeboxPasswordChangeAnswer(CPeer* pkPeer, DWORD dwHandle, BYTE success) { pkPeer->EncodeHeader(DG::SAFEBOX_CHANGE_PASSWORD_ANSWER, dwHandle, sizeof(BYTE)); @@ -517,16 +612,30 @@ void CClientManager::QUERY_SAFEBOX_LOAD(CPeer * pkPeer, DWORD dwHandle, TSafebox pi->account_index = 0; pi->ip[0] = bMall ? 1 : 0; strlcpy(pi->login, packet->szLogin, sizeof(pi->login)); - - char szQuery[QUERY_MAX_LEN]; - snprintf(szQuery, sizeof(szQuery), - "SELECT account_id, size, password FROM safebox%s WHERE account_id=%u", - GetTablePostfix(), packet->dwID); if (g_log) sys_log(0, "GD::SAFEBOX_LOAD (handle: %d account.id %u is_mall %d)", dwHandle, packet->dwID, bMall ? 1 : 0); - CDBManager::instance().ReturnQuery(szQuery, QID_SAFEBOX_LOAD, pkPeer->GetHandle(), pi); + TSafeboxTable* safebox = new TSafeboxTable; + bool wrongPassword = false; + + if (!LoadSafeboxTableByAccountId(packet->dwID, pi->safebox_password, bMall, safebox, &wrongPassword)) + { + delete safebox; + delete pi; + return; + } + + if (wrongPassword) + { + delete safebox; + delete pi; + pkPeer->EncodeHeader(DG::SAFEBOX_WRONG_PASSWORD, dwHandle, 0); + return; + } + + pi->pSafebox = safebox; + QueueSafeboxItemsLoad(pkPeer, pi); } void CClientManager::RESULT_SAFEBOX_LOAD(CPeer * pkPeer, SQLMsg * msg) @@ -534,168 +643,79 @@ void CClientManager::RESULT_SAFEBOX_LOAD(CPeer * pkPeer, SQLMsg * msg) CQueryInfo * qi = (CQueryInfo *) msg->pvUserData; ClientHandleInfo * pi = (ClientHandleInfo *) qi->pvData; DWORD dwHandle = pi->dwHandle; - - // 여기에서 사용하는 account_index는 쿼리 순서를 말한다. - // 첫번째 패스워드 알아내기 위해 하는 쿼리가 0 - // 두번째 실제 데이터를 얻어놓는 쿼리가 1 - - if (pi->account_index == 0) + if (!pi->pSafebox) { - char szSafeboxPassword[SAFEBOX_PASSWORD_MAX_LEN + 1]; - strlcpy(szSafeboxPassword, pi->safebox_password, sizeof(szSafeboxPassword)); - - TSafeboxTable * pSafebox = new TSafeboxTable; - memset(pSafebox, 0, sizeof(TSafeboxTable)); - - SQLResult * res = msg->Get(); - - if (res->uiNumRows == 0) - { - if (strcmp("000000", szSafeboxPassword)) - { - pkPeer->EncodeHeader(DG::SAFEBOX_WRONG_PASSWORD, dwHandle, 0); - delete pSafebox; - delete pi; - return; - } - } - else - { - MYSQL_ROW row = mysql_fetch_row(res->pSQLResult); - - // 비밀번호가 틀리면.. - if (((!row[2] || !*row[2]) && strcmp("000000", szSafeboxPassword)) || - ((row[2] && *row[2]) && strcmp(row[2], szSafeboxPassword))) - { - pkPeer->EncodeHeader(DG::SAFEBOX_WRONG_PASSWORD, dwHandle, 0); - delete pSafebox; - delete pi; - return; - } - - if (!row[0]) - pSafebox->dwID = 0; - else - str_to_number(pSafebox->dwID, row[0]); - - if (!row[1]) - pSafebox->bSize = 0; - else - str_to_number(pSafebox->bSize, row[1]); - /* - if (!row[3]) - pSafebox->dwGold = 0; - else - pSafebox->dwGold = atoi(row[3]); - */ - if (pi->ip[0] == 1) - { - pSafebox->bSize = 1; - sys_log(0, "MALL id[%d] size[%d]", pSafebox->dwID, pSafebox->bSize); - } - else - sys_log(0, "SAFEBOX id[%d] size[%d]", pSafebox->dwID, pSafebox->bSize); - } - - if (0 == pSafebox->dwID) - pSafebox->dwID = pi->account_id; - - pi->pSafebox = pSafebox; - - char szQuery[512]; - snprintf(szQuery, sizeof(szQuery), - "SELECT id, window+0, pos, count, vnum, socket0, socket1, socket2, " - "attrtype0, attrvalue0, " - "attrtype1, attrvalue1, " - "attrtype2, attrvalue2, " - "attrtype3, attrvalue3, " - "attrtype4, attrvalue4, " - "attrtype5, attrvalue5, " - "attrtype6, attrvalue6 " - "FROM item%s WHERE owner_id=%d AND window='%s'", - GetTablePostfix(), pi->account_id, pi->ip[0] == 0 ? "SAFEBOX" : "MALL"); - - pi->account_index = 1; - - CDBManager::instance().ReturnQuery(szQuery, QID_SAFEBOX_LOAD, pkPeer->GetHandle(), pi); + sys_err("null safebox pointer!"); + delete pi; + return; } - else + + // 쿼리에 에러가 있었으므로 응답할 경우 창고가 비어있는 것 처럼 + // 보이기 때문에 창고가 아얘 안열리는게 나음 + if (!msg->Get()->pSQLResult) + { + sys_err("null safebox result"); + delete pi; + return; + } + + static std::vector s_items; + CreateItemTableFromRes(msg->Get()->pSQLResult, &s_items, pi->account_id); + + std::set * pSet = ItemAwardManager::instance().GetByLogin(pi->login); + + if (pSet && !m_vec_itemTable.empty()) { - if (!pi->pSafebox) + CGrid grid(5, MAX(1, pi->pSafebox->bSize) * 9); + bool bEscape = false; + + for (DWORD i = 0; i < s_items.size(); ++i) { - sys_err("null safebox pointer!"); - delete pi; - return; - } + TPlayerItem & r = s_items[i]; + itertype(m_map_itemTableByVnum) it = m_map_itemTableByVnum.find(r.vnum); - // 쿼리에 에러가 있었으므로 응답할 경우 창고가 비어있는 것 처럼 - // 보이기 때문에 창고가 아얘 안열리는게 나음 - if (!msg->Get()->pSQLResult) - { - sys_err("null safebox result"); - delete pi; - return; - } - - static std::vector s_items; - CreateItemTableFromRes(msg->Get()->pSQLResult, &s_items, pi->account_id); - - std::set * pSet = ItemAwardManager::instance().GetByLogin(pi->login); - - if (pSet && !m_vec_itemTable.empty()) - { - - CGrid grid(5, MAX(1, pi->pSafebox->bSize) * 9); - bool bEscape = false; - - for (DWORD i = 0; i < s_items.size(); ++i) + if (it == m_map_itemTableByVnum.end()) { - TPlayerItem & r = s_items[i]; + bEscape = true; + sys_err("invalid item vnum %u in safebox: login %s", r.vnum, pi->login); + break; + } - itertype(m_map_itemTableByVnum) it = m_map_itemTableByVnum.find(r.vnum); + grid.Put(r.pos, 1, it->second->bSize); + } + + if (!bEscape) + { + std::vector > vec_dwFinishedAwardID; + + __typeof(pSet->begin()) it = pSet->begin(); + + char szQuery[512]; + + while (it != pSet->end()) + { + TItemAward * pItemAward = *(it++); + const DWORD& dwItemVnum = pItemAward->dwVnum; + + if (pItemAward->bTaken) + continue; + + if (pi->ip[0] == 0 && pItemAward->bMall) + continue; + + if (pi->ip[0] == 1 && !pItemAward->bMall) + continue; + + itertype(m_map_itemTableByVnum) it = m_map_itemTableByVnum.find(pItemAward->dwVnum); if (it == m_map_itemTableByVnum.end()) { - bEscape = true; - sys_err("invalid item vnum %u in safebox: login %s", r.vnum, pi->login); - break; + sys_err("invalid item vnum %u in item_award: login %s", pItemAward->dwVnum, pi->login); + continue; } - grid.Put(r.pos, 1, it->second->bSize); - } - - if (!bEscape) - { - std::vector > vec_dwFinishedAwardID; - - __typeof(pSet->begin()) it = pSet->begin(); - - char szQuery[512]; - - while (it != pSet->end()) - { - TItemAward * pItemAward = *(it++); - const DWORD& dwItemVnum = pItemAward->dwVnum; - - if (pItemAward->bTaken) - continue; - - if (pi->ip[0] == 0 && pItemAward->bMall) - continue; - - if (pi->ip[0] == 1 && !pItemAward->bMall) - continue; - - itertype(m_map_itemTableByVnum) it = m_map_itemTableByVnum.find(pItemAward->dwVnum); - - if (it == m_map_itemTableByVnum.end()) - { - sys_err("invalid item vnum %u in item_award: login %s", pItemAward->dwVnum, pi->login); - continue; - } - TItemTable * pItemTable = it->second; int iPos; @@ -833,22 +853,21 @@ void CClientManager::RESULT_SAFEBOX_LOAD(CPeer * pkPeer, SQLMsg * msg) grid.Put(iPos, 1, it->second->bSize); } - for (DWORD i = 0; i < vec_dwFinishedAwardID.size(); ++i) - ItemAwardManager::instance().Taken(vec_dwFinishedAwardID[i].first, vec_dwFinishedAwardID[i].second); - } + for (DWORD i = 0; i < vec_dwFinishedAwardID.size(); ++i) + ItemAwardManager::instance().Taken(vec_dwFinishedAwardID[i].first, vec_dwFinishedAwardID[i].second); } - - pi->pSafebox->wItemCount = s_items.size(); - - pkPeer->EncodeHeader(pi->ip[0] == 0 ? DG::SAFEBOX_LOAD : DG::MALL_LOAD, dwHandle, sizeof(TSafeboxTable) + sizeof(TPlayerItem) * s_items.size()); - - pkPeer->Encode(pi->pSafebox, sizeof(TSafeboxTable)); - - if (!s_items.empty()) - pkPeer->Encode(&s_items[0], sizeof(TPlayerItem) * s_items.size()); - - delete pi; } + + pi->pSafebox->wItemCount = s_items.size(); + + pkPeer->EncodeHeader(pi->ip[0] == 0 ? DG::SAFEBOX_LOAD : DG::MALL_LOAD, dwHandle, sizeof(TSafeboxTable) + sizeof(TPlayerItem) * s_items.size()); + + pkPeer->Encode(pi->pSafebox, sizeof(TSafeboxTable)); + + if (!s_items.empty()) + pkPeer->Encode(&s_items[0], sizeof(TPlayerItem) * s_items.size()); + + delete pi; } void CClientManager::QUERY_SAFEBOX_CHANGE_SIZE(CPeer * pkPeer, DWORD dwHandle, TSafeboxChangeSizePacket * p)