db: prepare guild and flag lookups

This commit is contained in:
server
2026-04-13 22:08:01 +02:00
parent 8721d9ba3e
commit 063d92f876
3 changed files with 267 additions and 74 deletions

View File

@@ -5,26 +5,104 @@
#include "Config.h"
#include "DBManager.h"
#include "QID.h"
#include "libsql/Statement.h"
#include <string>
#include <vector>
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<TPacketSetEventFlag>& 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<char*>(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<TPacketSetEventFlag> 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<long>(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));
}
}

View File

@@ -6,6 +6,96 @@
#include "DBManager.h"
#include "QID.h"
#include "GuildManager.h"
#include "libsql/Statement.h"
#include <string>
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));
}
}

View File

@@ -1,40 +1,94 @@
// vim:ts=4 sw=4
#include "stdafx.h"
#include "ClientManager.h"
#include "DBManager.h"
#include "libsql/Statement.h"
#include <string>
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<char*>(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<int>(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));
}