db: prepare player delete cleanup flow
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 12:48:48 +02:00
parent d85fa6c12c
commit 5f11a4fef0

View File

@@ -175,6 +175,26 @@ bool UpdatePlayerIndexSlot(DWORD accountId, BYTE accountIndex, DWORD playerId)
return stmt.GetAffectedRows() != 0;
}
bool ArchiveDeletedPlayerById(DWORD playerId)
{
char query[QUERY_MAX_LEN];
snprintf(query, sizeof(query), "INSERT INTO player%s_deleted SELECT * FROM player%s WHERE id = ?",
GetTablePostfix(), GetTablePostfix());
CStmt stmt;
if (!PreparePlayerStmt(stmt, query))
return false;
if (!stmt.BindParam(MYSQL_TYPE_LONG, &playerId))
return false;
if (!stmt.Execute())
return false;
const unsigned long long affectedRows = stmt.GetAffectedRows();
return affectedRows != 0 && affectedRows != static_cast<unsigned long long>(-1);
}
void DeletePlayerById(DWORD playerId)
{
char query[QUERY_MAX_LEN];
@@ -189,6 +209,51 @@ void DeletePlayerById(DWORD playerId)
stmt.Execute();
}
bool ResetPlayerIndexSlotForDelete(BYTE accountIndex, DWORD playerId)
{
char query[QUERY_MAX_LEN];
snprintf(query, sizeof(query), "UPDATE player_index%s SET pid%u = 0 WHERE pid%u = ?",
GetTablePostfix(), accountIndex + 1, accountIndex + 1);
CStmt stmt;
if (!PreparePlayerStmt(stmt, query))
return false;
if (!stmt.BindParam(MYSQL_TYPE_LONG, &playerId))
return false;
if (!stmt.Execute())
return false;
const unsigned long long affectedRows = stmt.GetAffectedRows();
return affectedRows != 0 && affectedRows != static_cast<unsigned long long>(-1);
}
void DeletePlayerItemsByOwnerId(DWORD playerId)
{
char query[QUERY_MAX_LEN];
snprintf(query, sizeof(query), "DELETE FROM item%s WHERE owner_id = ? AND (window < ? OR window = ?)",
GetTablePostfix());
int32_t safeboxWindow = SAFEBOX;
int32_t dragonSoulInventory = DRAGON_SOUL_INVENTORY;
CStmt stmt;
if (!PreparePlayerStmt(stmt, query))
return;
if (!stmt.BindParam(MYSQL_TYPE_LONG, &playerId))
return;
if (!stmt.BindParam(MYSQL_TYPE_LONG, &safeboxWindow))
return;
if (!stmt.BindParam(MYSQL_TYPE_LONG, &dragonSoulInventory))
return;
stmt.Execute();
}
}
//
@@ -1192,11 +1257,7 @@ void CClientManager::__RESULT_PLAYER_DELETE(CPeer *peer, SQLMsg* msg)
char queryStr[QUERY_MAX_LEN];
snprintf(queryStr, sizeof(queryStr), "INSERT INTO player%s_deleted SELECT * FROM player%s WHERE id=%d",
GetTablePostfix(), GetTablePostfix(), pi->player_id);
auto pIns = CDBManager::instance().DirectQuery(queryStr);
if (pIns->Get()->uiAffectedRows == 0 || pIns->Get()->uiAffectedRows == (uint32_t)-1)
if (!ArchiveDeletedPlayerById(pi->player_id))
{
sys_log(0, "PLAYER_DELETE FAILED %u CANNOT INSERT TO player%s_deleted", dwPID, GetTablePostfix());
@@ -1208,10 +1269,6 @@ void CClientManager::__RESULT_PLAYER_DELETE(CPeer *peer, SQLMsg* msg)
// 삭제 성공
sys_log(0, "PLAYER_DELETE SUCCESS %u", dwPID);
char account_index_string[16];
snprintf(account_index_string, sizeof(account_index_string), "player_id%d", m_iPlayerIDStart + pi->account_index);
// 플레이어 테이블을 캐쉬에서 삭제한다.
CPlayerTableCache * pkPlayerCache = GetPlayerCache(pi->player_id);
@@ -1240,15 +1297,7 @@ void CClientManager::__RESULT_PLAYER_DELETE(CPeer *peer, SQLMsg* msg)
m_map_pkItemCacheSetPtr.erase(pi->player_id);
}
snprintf(queryStr, sizeof(queryStr), "UPDATE player_index%s SET pid%u=0 WHERE pid%u=%d",
GetTablePostfix(),
pi->account_index + 1,
pi->account_index + 1,
pi->player_id);
auto pMsg = CDBManager::instance().DirectQuery(queryStr);
if (pMsg->Get()->uiAffectedRows == 0 || pMsg->Get()->uiAffectedRows == (uint32_t)-1)
if (!ResetPlayerIndexSlotForDelete(pi->account_index, pi->player_id))
{
sys_log(0, "PLAYER_DELETE FAIL WHEN UPDATE account table");
peer->EncodeHeader(DG::PLAYER_DELETE_FAILED, pi->dwHandle, 1);
@@ -1256,11 +1305,9 @@ void CClientManager::__RESULT_PLAYER_DELETE(CPeer *peer, SQLMsg* msg)
return;
}
snprintf(queryStr, sizeof(queryStr), "DELETE FROM player%s WHERE id=%d", GetTablePostfix(), pi->player_id);
CDBManager::instance().DirectQuery(queryStr);
DeletePlayerById(pi->player_id);
snprintf(queryStr, sizeof(queryStr), "DELETE FROM item%s WHERE owner_id=%d AND (window < %d or window = %d)", GetTablePostfix(), pi->player_id, SAFEBOX, DRAGON_SOUL_INVENTORY);
CDBManager::instance().DirectQuery(queryStr);
DeletePlayerItemsByOwnerId(pi->player_id);
snprintf(queryStr, sizeof(queryStr), "DELETE FROM quest%s WHERE dwPID=%d", GetTablePostfix(), pi->player_id);
CDBManager::instance().AsyncQuery(queryStr);