db: prepare safebox load bootstrap
Some checks failed
build / Linux asan (push) Has been cancelled
build / Linux release (push) Has been cancelled
build / FreeBSD build (push) Has been cancelled

This commit is contained in:
server
2026-04-14 11:47:33 +02:00
parent aa862d829d
commit 84ed35cbda

View File

@@ -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<char*>(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<BYTE>(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<TPlayerItem> s_items;
CreateItemTableFromRes(msg->Get()->pSQLResult, &s_items, pi->account_id);
std::set<TItemAward *> * 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<TPlayerItem> s_items;
CreateItemTableFromRes(msg->Get()->pSQLResult, &s_items, pi->account_id);
std::set<TItemAward *> * 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<std::pair<DWORD, DWORD> > 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<std::pair<DWORD, DWORD> > 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)