Move git root from Client/ to src/ to track all source code: - Client: Game client source (moved to Client/Client/) - Server: Game server source - GameTools: Development tools - CryptoSource: Encryption utilities - database: Database scripts - Script: Game scripts - rylCoder_16.02.2008_src: Legacy coder tools - GMFont, Game: Additional resources 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
423 lines
11 KiB
C++
423 lines
11 KiB
C++
#include "RylDBLibrary.h"
|
|
#include "RylDBStoreCommand.h"
|
|
#include "RylDBCharCommand.h"
|
|
|
|
#include <Log/ServerLog.h>
|
|
#include <Network/Packet/PacketStruct/ServerInfo.h>
|
|
#include <sqloledb.h>
|
|
|
|
const int MAX_READ_NUM = 100000;
|
|
|
|
CNoneCounter& CNoneCounter::GetInstance()
|
|
{
|
|
static CNoneCounter noneCounter;
|
|
return noneCounter;
|
|
}
|
|
|
|
bool CConsoleCounter::ShowCounter(const char* szProcessName, int nCount, bool bForceWrite)
|
|
{
|
|
if(bForceWrite || 0 == (nCount % m_nCounterPerLine))
|
|
{
|
|
printf("[%s] : %12d\n", szProcessName, nCount);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
HRESULT CRylDBProcess::ConnectDB(ATL::CDataSource& ds, const char* szDBAddress, const char* szDBName,
|
|
const char* szDBAccount, const char* szDBPassword)
|
|
{
|
|
ATL::CDBPropSet dsPropSet;
|
|
dsPropSet.SetGUID(DBPROPSET_DBINIT);
|
|
dsPropSet.AddProperty(DBPROP_INIT_DATASOURCE, szDBAddress);
|
|
dsPropSet.AddProperty(DBPROP_INIT_CATALOG, szDBName);
|
|
dsPropSet.AddProperty(DBPROP_AUTH_USERID, szDBAccount);
|
|
dsPropSet.AddProperty(DBPROP_AUTH_PASSWORD, szDBPassword);
|
|
|
|
// 데이터베이스 오픈
|
|
return ds.Open(CLSID_SQLOLEDB, &dsPropSet, 1);
|
|
}
|
|
|
|
template<class CAccessorData, class IDBProcess>
|
|
HRESULT EnumerateTable(ATL::CSession& dataSession,
|
|
const char* szTableName,
|
|
IDBProcess& dbProcess,
|
|
IShowCounter& showCounter)
|
|
{
|
|
ATL::CTable< CAccessor<CAccessorData>, CBulkRowset> data;
|
|
|
|
CDBPropSet dbPropSet;
|
|
dbPropSet.SetGUID(DBPROPSET_ROWSET);
|
|
dbPropSet.AddProperty(DBPROP_IRowsetUpdate, true);
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
data.SetRows(MAX_READ_NUM);
|
|
|
|
if (FAILED(hr = data.Open(dataSession, szTableName, &dbPropSet, 1)))
|
|
{
|
|
ERRLOG2(g_Log, "hr:0x%08X / %s table open failed", hr, szTableName);
|
|
}
|
|
else
|
|
{
|
|
CAccessorData oldData;
|
|
bool bUpdate = false;
|
|
|
|
int nCount = 0;
|
|
|
|
// 테이블 여는 데 성공했다. 돌면서 처리한다.
|
|
while(S_OK == (hr = data.MoveNext()))
|
|
{
|
|
oldData = data;
|
|
|
|
data.AdjustSize(false);
|
|
|
|
switch(dbProcess(data))
|
|
{
|
|
case CONVERT_FAILED:
|
|
data.LogError(RylDBCommand::DBERR_CONVERT_FAILED, hr);
|
|
bUpdate = false;
|
|
break;
|
|
|
|
case CONVERT_SUCCEEDED:
|
|
bUpdate = (oldData != data);
|
|
break;
|
|
|
|
case CONVERT_DO_NOT_WRITE:
|
|
bUpdate = false;
|
|
break;
|
|
|
|
case CONVERT_FORCE_WRITE:
|
|
bUpdate = true;
|
|
}
|
|
|
|
data.AdjustSize(true);
|
|
|
|
if (bUpdate)
|
|
{
|
|
if (FAILED(hr = data.SetData(1)))
|
|
{
|
|
data.LogError(RylDBCommand::DBERR_SETDATA_FAILED, hr);
|
|
}
|
|
else if (FAILED(hr = data.Update()))
|
|
{
|
|
data.LogError(RylDBCommand::DBERR_UPDATE_FAILED, hr);
|
|
}
|
|
}
|
|
|
|
showCounter.ShowCounter(szTableName, ++nCount, false);
|
|
data.Init();
|
|
}
|
|
|
|
showCounter.ShowCounter(szTableName, ++nCount, true);
|
|
g_Log.Flush();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
template<class CAccessorData, class IDBProcess>
|
|
HRESULT EnumerateCommand(ATL::CSession& dataSession,
|
|
char* szTableName,
|
|
char* szQuery,
|
|
IDBProcess& dbProcess,
|
|
IShowCounter& showCounter)
|
|
{
|
|
ATL::CCommand<CAccessor<CAccessorData>, CBulkRowset, CMultipleResults> data;
|
|
|
|
CDBPropSet dbPropSet;
|
|
dbPropSet.SetGUID(DBPROPSET_ROWSET);
|
|
/*dbPropSet.AddProperty(DBPROP_IRowsetUpdate, true);
|
|
dbPropSet.AddProperty(DBPROP_UPDATABILITY, DBPROPVAL_UP_CHANGE);
|
|
*/
|
|
HRESULT hr = S_OK;
|
|
|
|
data.SetRows(MAX_READ_NUM);
|
|
|
|
if (FAILED(hr = data.Open(dataSession, szQuery, &dbPropSet)))
|
|
{
|
|
ERRLOG2(g_Log, "hr:0x%08X / %s table open failed", hr, szTableName);
|
|
}
|
|
else
|
|
{
|
|
CAccessorData oldData;
|
|
bool bUpdate = false;
|
|
|
|
int nCount = 0;
|
|
|
|
// 테이블 여는 데 성공했다. 돌면서 처리한다.
|
|
while(S_OK == (hr = data.MoveNext()))
|
|
{
|
|
oldData = data;
|
|
|
|
data.AdjustSize(false);
|
|
|
|
switch(dbProcess(data))
|
|
{
|
|
case CONVERT_FAILED:
|
|
data.LogError(RylDBCommand::DBERR_CONVERT_FAILED, hr);
|
|
bUpdate = false;
|
|
break;
|
|
|
|
case CONVERT_SUCCEEDED:
|
|
bUpdate = (oldData != data);
|
|
break;
|
|
|
|
case CONVERT_DO_NOT_WRITE:
|
|
bUpdate = false;
|
|
break;
|
|
|
|
case CONVERT_FORCE_WRITE:
|
|
bUpdate = true;
|
|
}
|
|
|
|
data.AdjustSize(true);
|
|
|
|
if (bUpdate)
|
|
{
|
|
if (FAILED(hr = data.SetData(1)))
|
|
{
|
|
data.LogError(RylDBCommand::DBERR_SETDATA_FAILED, hr);
|
|
}
|
|
else if (FAILED(hr = data.Update()))
|
|
{
|
|
data.LogError(RylDBCommand::DBERR_UPDATE_FAILED, hr);
|
|
}
|
|
}
|
|
|
|
showCounter.ShowCounter(szTableName, ++nCount, false);
|
|
data.Init();
|
|
}
|
|
|
|
showCounter.ShowCounter(szTableName, ++nCount, true);
|
|
g_Log.Flush();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CRylDBProcess::CharInfo(IDBCharInfoProcess& charInfoProcess, IShowCounter& showCounter, char* szQuery)
|
|
{
|
|
if(NULL == szQuery)
|
|
{
|
|
return EnumerateTable<RylDBCommand::CCharData, IDBCharInfoProcess>(
|
|
m_DataSession, "CharInfo", charInfoProcess, showCounter);
|
|
}
|
|
else
|
|
{
|
|
return EnumerateCommand<RylDBCommand::CCharData, IDBCharInfoProcess>(
|
|
m_DataSession, "CharInfo", szQuery, charInfoProcess, showCounter);
|
|
}
|
|
}
|
|
|
|
HRESULT CRylDBProcess::CharSkill(IDBCharSkillProcess& charSkillProcess, IShowCounter& showCounter, char* szQuery)
|
|
{
|
|
if(NULL == szQuery)
|
|
{
|
|
return EnumerateTable<RylDBCommand::CSkillData, IDBCharSkillProcess>(
|
|
m_DataSession, "CharSkill", charSkillProcess, showCounter);
|
|
}
|
|
}
|
|
|
|
HRESULT CRylDBProcess::CharItem(IDBCharItemProcess& charItemProcess, IShowCounter& showCounter, char* szQuery)
|
|
{
|
|
if(NULL == szQuery)
|
|
{
|
|
return EnumerateTable<RylDBCommand::CCharItem, IDBCharItemProcess>(
|
|
m_DataSession, "CharItem", charItemProcess, showCounter);
|
|
}
|
|
else
|
|
{
|
|
return EnumerateCommand<RylDBCommand::CCharItem, IDBCharItemProcess>(
|
|
m_DataSession, "CharItem", szQuery, charItemProcess, showCounter);
|
|
}
|
|
}
|
|
|
|
HRESULT CRylDBProcess::CharItemEx(IDBCharItemExProcess& charItemExProcess, IShowCounter& showCounter, char* szQuery)
|
|
{
|
|
if(NULL == szQuery)
|
|
{
|
|
return EnumerateTable<RylDBCommand::CCharItemEx, IDBCharItemExProcess>(
|
|
m_DataSession, "CharItemEx", charItemExProcess, showCounter);
|
|
}
|
|
else
|
|
{
|
|
return EnumerateCommand<RylDBCommand::CCharItemEx, IDBCharItemExProcess>(
|
|
m_DataSession, "CharItemEx", szQuery, charItemExProcess, showCounter);
|
|
}
|
|
}
|
|
|
|
HRESULT CRylDBProcess::CharQuest(IDBCharQuestProcess& charQuestProcess, IShowCounter& showCounter, char* szQuery)
|
|
{
|
|
if(NULL == szQuery)
|
|
{
|
|
return EnumerateTable<RylDBCommand::CCharQuest, IDBCharQuestProcess>(
|
|
m_DataSession, "Quest", charQuestProcess, showCounter);
|
|
}
|
|
}
|
|
|
|
HRESULT CRylDBProcess::Party(IDBPartyProcess& partyProcess, IShowCounter& showCounter, char* szQuery)
|
|
{
|
|
if(NULL == szQuery)
|
|
{
|
|
return EnumerateTable<RylDBCommand::CPartyData, IDBPartyProcess>(
|
|
m_DataSession, "PartyInfo", partyProcess, showCounter);
|
|
}
|
|
}
|
|
|
|
HRESULT CRylDBProcess::Friend(IDBFriendProcess& friendProcess, IShowCounter& showCounter, char* szQuery)
|
|
{
|
|
if(NULL == szQuery)
|
|
{
|
|
return EnumerateTable<RylDBCommand::CFriendData, IDBFriendProcess>(
|
|
m_DataSession, "Friend", friendProcess, showCounter);
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT CRylDBProcess::UnifiedStore1(IDBStoreProcess& storeProcess, IShowCounter& showCounter, char* szQuery)
|
|
{
|
|
if(NULL == szQuery)
|
|
{
|
|
return EnumerateTable<RylDBCommand::CUnifiedStore1, IDBStoreProcess>(
|
|
m_DataSession, "TblUnifiedItemStore1", storeProcess, showCounter);
|
|
}
|
|
else
|
|
{
|
|
return EnumerateCommand<RylDBCommand::CUnifiedStore1, IDBStoreProcess>(
|
|
m_DataSession, "TblUnifiedItemStore1", szQuery, storeProcess, showCounter);
|
|
}
|
|
}
|
|
|
|
HRESULT CRylDBProcess::UnifiedStore2(IDBStoreProcess& storeProcess, IShowCounter& showCounter, char* szQuery)
|
|
{
|
|
if(NULL == szQuery)
|
|
{
|
|
return EnumerateTable<RylDBCommand::CUnifiedStore2, IDBStoreProcess>(
|
|
m_DataSession, "TblUnifiedItemStore2", storeProcess, showCounter);
|
|
}
|
|
else
|
|
{
|
|
return EnumerateCommand<RylDBCommand::CUnifiedStore2, IDBStoreProcess>(
|
|
m_DataSession, "TblUnifiedItemStore2", szQuery, storeProcess, showCounter);
|
|
}
|
|
}
|
|
|
|
HRESULT CRylDBProcess::UnifiedCharList(IDBUnifiedCharInfoProcess& process, IShowCounter& showCounter, char* szQuery)
|
|
{
|
|
if(NULL == szQuery)
|
|
{
|
|
return EnumerateTable<RylDBCommand::CUnifiedCharList, IDBUnifiedCharInfoProcess>(
|
|
m_DataSession, "TblUnifiedCharLIst", process, showCounter);
|
|
}
|
|
}
|
|
|
|
|
|
CDBItemSerialMgr::CDBItemSerialMgr()
|
|
: m_dwItemSerial(0LL), m_dwServerID(0)
|
|
{
|
|
|
|
}
|
|
|
|
CDBItemSerialMgr::~CDBItemSerialMgr()
|
|
{
|
|
|
|
}
|
|
|
|
bool CDBItemSerialMgr::SetItemSerial(unsigned __int64 dwItemSerial)
|
|
{
|
|
if(m_dwItemSerial < dwItemSerial)
|
|
{
|
|
m_dwItemSerial = dwItemSerial;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
HRESULT CDBItemSerialMgr::LoadItemSerialDB(ATL::CSession& DBSession, unsigned long dwServerID)
|
|
{
|
|
m_dwItemSerial = 0LL;
|
|
m_dwServerID = dwServerID;
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
const int MAX_QUERY_LEN = 512;
|
|
|
|
char szQuery[MAX_QUERY_LEN];
|
|
_snprintf(szQuery, MAX_QUERY_LEN - 1,
|
|
"SELECT Server, Item FROM ItemUID WHERE Server = %d", dwServerID);
|
|
|
|
ATL::CCommand< CAccessor< RylDBCommand::CReadItemSerial >, CRowset, CMultipleResults > itemCommand;
|
|
|
|
if (FAILED(hr = itemCommand.Open(DBSession, szQuery)))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
if(S_OK != itemCommand.MoveNext())
|
|
{
|
|
itemCommand.Close();
|
|
|
|
SERVER_ID serverID;
|
|
serverID.dwID = dwServerID;
|
|
|
|
// 아이템 시리얼 막 커지는 건 버그였음.. 전과 같이 존 / 채널 2byte체제로 간다.
|
|
m_dwItemSerial = ((static_cast<unsigned __int64>(serverID.GetZone()) << 56) & 0xFF00000000000000LL) |
|
|
((static_cast<unsigned __int64>(serverID.GetChannel()) << 48) & 0x00FF000000000000LL);
|
|
|
|
ATL::CCommand< CAccessor< RylDBCommand::CUpdateItemSerial> > insertCommand;
|
|
|
|
insertCommand.SetServerID(dwServerID);
|
|
insertCommand.SetItemSerial(m_dwItemSerial);
|
|
|
|
// 등록되지 않은 서버
|
|
if (FAILED(hr = insertCommand.Open(DBSession,
|
|
L"INSERT INTO ItemUID (Item, Server) VALUES(?, ?)")))
|
|
{
|
|
ERRLOG1(g_Log, "ServerID:0x%08X / 아이템 시리얼 얻기 실패 - Insert실패", m_dwServerID);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_dwItemSerial = itemCommand.GetItemSerial();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CDBItemSerialMgr::SaveItemSerialDB(ATL::CSession& DBSession, unsigned long dwServerID)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if(m_dwServerID != dwServerID)
|
|
{
|
|
ERRLOG2(g_Log, "OldServerID:0x%08X / NewServerID:0x%08X / 아이템 시리얼 저장 실패 : 서버 ID가 다릅니다",
|
|
m_dwServerID, dwServerID);
|
|
|
|
hr = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
ATL::CCommand< CAccessor<RylDBCommand::CUpdateItemSerial> > updateItemSerial;
|
|
|
|
updateItemSerial.SetServerID(dwServerID);
|
|
updateItemSerial.SetItemSerial(m_dwItemSerial);
|
|
|
|
if (FAILED(hr = updateItemSerial.Open(DBSession,
|
|
L"UPDATE ItemUID SET Item=? WHERE Server=?")))
|
|
{
|
|
ERRLOG2(g_Log, "ServerID:0x%08X / ItemSerial : 0x016I64X / 아이템 시리얼 저장 실패 : DB에 시리얼 저장 실패",
|
|
m_dwServerID, m_dwItemSerial);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CDBItemSerialMgr::ClearAllSerialDB(ATL::CSession& DBSession)
|
|
{
|
|
ATL::CCommand<> deleteCommand;
|
|
return deleteCommand.Open(DBSession, L"DELETE FROM ItemUID");
|
|
}
|