Files
Client/Server/DBProcess/QuestChange/QuestChange.cpp
LGram16 dd97ddec92 Restructure repository to include all source folders
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>
2025-11-29 20:17:20 +09:00

353 lines
10 KiB
C++

// QuestChange.cpp : 콘솔 응용 프로그램에 대한 진입점을 정의합니다.
//
/*
스크립트 구조
REMOVE 퀘스트ID
CHANGE 퀘스트ID 퀘스트ID
퀘스트ID 는 10진수 혹은 0x로 시작하는 16진수이다.
주석은 C스타일의 주석 // 만 지원한다
*/
#pragma warning(disable:4800)
#include "stdafx.h"
#include <algorithm>
#include <vector>
#include <RylDBLibrary/RylDBLibrary.h>
#include <RylDBLibrary/RylDBCharCommand.h>
#include <Network/Packet/PacketStruct/CharQuestPacket.h>
#include <Log/ServerLog.h>
#include <boost/pool/pool_alloc.hpp>
#include <Creature/CreatureStructure.h>
#include <Creature/Character/CharacterClass.h>
// Quest Script Command
class CProcessQuest : public IDBCharQuestProcess
{
public:
bool LoadScript(const char* szScriptName);
private:
typedef std::pair<unsigned short, unsigned short> QuestChangePair;
typedef std::vector<unsigned short> QuestRemoveVector;
typedef std::vector<QuestChangePair> QuestChangeVector;
virtual ConvertResult operator()(RylDBCommand::CCharQuest& charQuest_InOut);
QuestRemoveVector m_QuestRemoveVector;
QuestChangeVector m_QuestChangeVector;
};
template<class Data, class Pair>
struct match_first
{
bool operator () (const Data& lhs, const Data& rhs) { return lhs < rhs; }
bool operator () (const Pair& lhs, const Pair& rhs) { return lhs.first < rhs.first; }
bool operator () (const Data& lhs, const Pair& rhs) { return lhs < rhs.first; }
bool operator () (const Pair& lhs, const Data& rhs) { return lhs.first < rhs; }
};
void PrintUsage()
{
printf("usage : QuestChange.exe DBAddress DBName DBAccount DBPassword QuestChangeScriptName \n");
}
unsigned short ConvertStringToQuestID(const char* szQuestID)
{
unsigned short wQuestID = 0;
if (0 != szQuestID)
{
const char* szHexHeader = "0X";
size_t nHexHeaderLen = strlen(szHexHeader);
char* szStopPtr = 0;
int nBase = (0 == strncmp(szQuestID, szHexHeader, nHexHeaderLen)) ? 16 : 10;
wQuestID = static_cast<unsigned short>(strtoul(szQuestID, &szStopPtr, nBase));
}
return wQuestID;
}
int _tmain(int argc, _TCHAR* argv[])
{
if(6 != argc)
{
PrintUsage();
return -1;
}
const char* szProcessQuestScript = argv[5];
CProcessQuest processQuest;
if(FAILED(processQuest.LoadScript(szProcessQuestScript)))
{
printf("%s 스크립트 로드 실패", szProcessQuestScript);
return -1;
}
CoInitialize(0);
HRESULT hr = S_OK;
ATL::CDataSource dataSource;
ATL::CSession Session;
#define LOG_CONVERT0(str) { ERRLOG0(g_Log, (str)); printf(str "\n"); }
#define LOG_CONVERT1(str, arg1) { ERRLOG1(g_Log, (str), (arg1)); printf(str "\n", (arg1)); }
#define LOG_CONVERT2(str, arg1, arg2) { ERRLOG2(g_Log, (str), (arg1), (arg2)); printf(str "\n", (arg1), (arg2)); }
if(FAILED(hr = CRylDBProcess::ConnectDB(dataSource, argv[1], argv[2], argv[3], argv[4])))
{
LOG_CONVERT1("Connect DB failed : hr:0x%08X", hr);
}
else if(FAILED(hr = Session.Open(dataSource)))
{
LOG_CONVERT1("Open session failed : hr:0x%08X", hr);
}
else
{
CRylDBProcess rylDBProcess(Session);
CConsoleCounter consoleCounter(1000);
if (!rylDBProcess.CharQuest(processQuest, consoleCounter))
{
LOG_CONVERT1("CharQuest process failed : hr:0x%08X", hr);
}
}
INFLOG0(g_Log, "Remove Complete");
Session.Close();
dataSource.Close();
CoUninitialize();
return 0;
}
bool CProcessQuest::LoadScript(const char* szScriptName)
{
bool bResult = true;
FILE* lpFile = fopen(szScriptName, "rt");
if (0 != lpFile)
{
const int MAX_BUFFER = 1024;
char szBuffer[MAX_BUFFER];
const char* szDelimiter = "\r\n\t: ";
int nLine = 0;
const char* szComment = "//";
size_t nCommentLen = strlen(szComment);
char* szStopPtr = 0;
int nBase = 10;
while(fgets(szBuffer, MAX_BUFFER - 1, lpFile))
{
++nLine;
char* szCommand = strtok(szBuffer, szDelimiter);
char* szQuestID = strtok(0, szDelimiter);
char* szChangeID = strtok(0, szDelimiter);
if (0 != szCommand && 0 != szQuestID)
{
strupr(szCommand);
strupr(szQuestID);
unsigned short wQuestID = ConvertStringToQuestID(szQuestID);
if (0 != wQuestID && 0 == strcmp(szCommand, "REMOVE"))
{
m_QuestRemoveVector.push_back(wQuestID);
}
else if (0 != szChangeID && 0 == strcmp(szCommand, "CHANGE"))
{
strupr(szChangeID);
unsigned short wChangeID = ConvertStringToQuestID(szChangeID);
if (0 != wChangeID)
{
m_QuestChangeVector.push_back(
QuestChangePair(wQuestID, wChangeID));
}
}
}
}
fclose(lpFile);
}
else
{
LOG_CONVERT1("파일 열기에 실패했습니다 : %s", szScriptName);
bResult = false;
}
std::sort(m_QuestRemoveVector.begin(), m_QuestRemoveVector.end());
std::sort(m_QuestChangeVector.begin(), m_QuestChangeVector.end());
return bResult;
}
ConvertResult CProcessQuest::operator() (RylDBCommand::CCharQuest& charQuest_InOut)
{
unsigned long dwCID = charQuest_InOut.GetCID();
unsigned long dwTotalChangedCount = 0;
const QUEST& quest_In = charQuest_InOut.GetQuest();
const HISTORY history_In = charQuest_InOut.GetHistory();
QuestRemoveVector::iterator remove_pos = m_QuestRemoveVector.begin();
QuestRemoveVector::iterator remove_end = m_QuestRemoveVector.end();
QuestChangeVector::iterator change_pos = m_QuestChangeVector.begin();
QuestChangeVector::iterator change_end = m_QuestChangeVector.end();
QuestChangeVector::iterator change_find;
if (0 < quest_In.dwSize)
{
unsigned long dwChangedCount = 0;
QUEST quest_Out;
memset(&quest_Out, 0, sizeof(QUEST));
const PktQuestDB::ExecutingQuest* lpExecutingQuestPos =
reinterpret_cast<const PktQuestDB::ExecutingQuest*>(quest_In.Data);
const PktQuestDB::ExecutingQuest* lpExecutingQuestEnd =
reinterpret_cast<const PktQuestDB::ExecutingQuest*>(quest_In.Data + quest_In.dwSize);
PktQuestDB::ExecutingQuest* lpDst = reinterpret_cast<PktQuestDB::ExecutingQuest*>(quest_Out.Data);
for(; lpExecutingQuestPos < lpExecutingQuestEnd; ++lpExecutingQuestPos)
{
if (std::binary_search(remove_pos, remove_end, lpExecutingQuestPos->m_wQuestID))
{
// 퀘스트를 복사하지 않는다.
INFLOG2(g_Log, "CID:%10u / QuestID:0x%04X / 진행중인 퀘스트를 제거했습니다",
dwCID, lpExecutingQuestPos->m_wQuestID);
++dwChangedCount;
}
else
{
change_find = std::lower_bound(
m_QuestChangeVector.begin(), m_QuestChangeVector.end(),
lpExecutingQuestPos->m_wQuestID, match_first<unsigned short, QuestChangePair>());
if (change_find != change_end && change_find->first == lpExecutingQuestPos->m_wQuestID)
{
// 진행중인 퀘스트의 ID가 변경되었다.
*lpDst = *lpExecutingQuestPos;
lpDst->m_wQuestID = change_find->second;
INFLOG4(g_Log, "CID:%10u / QuestID:0x%04X / Phase:%d / ChangedID:0x%04X / "
"진행중인 퀘스트의 ID를 변경했습니다",
dwCID, lpExecutingQuestPos->m_wQuestID,
lpExecutingQuestPos->m_cPhase, lpDst->m_wQuestID);
++dwChangedCount;
}
else
{
// 목록에 없는 경우에만 복사한다.
*lpDst = *lpExecutingQuestPos;
}
++lpDst;
}
}
if (0 < dwChangedCount)
{
quest_Out.dwSize = static_cast<unsigned long>(
reinterpret_cast<char*>(lpDst) - quest_Out.Data);
charQuest_InOut.SetQuest(quest_Out);
dwTotalChangedCount += dwChangedCount;
}
}
if (0 < history_In.dwSize)
{
unsigned long dwChangedCount = 0;
HISTORY history_Out;
memset(&history_Out, 0, sizeof(HISTORY));
const unsigned short* lpHistoryPos = reinterpret_cast<const unsigned short*>(history_In.Data);
const unsigned short* lpHistoryEnd = reinterpret_cast<const unsigned short*>(history_In.Data + history_In.dwSize);
unsigned short* lpDst = reinterpret_cast<unsigned short*>(history_Out.Data);
for(; lpHistoryPos < lpHistoryEnd; ++lpHistoryPos)
{
if (std::binary_search(remove_pos, remove_end, *lpHistoryPos))
{
// 퀘스트를 복사하지 않는다.
INFLOG2(g_Log, "CID:%10u / QuestID:0x%04X / 수행 완료된 퀘스트를 제거했습니다",
dwCID, *lpHistoryPos);
++dwChangedCount;
}
else
{
change_find = std::lower_bound(
m_QuestChangeVector.begin(), m_QuestChangeVector.end(),
*lpHistoryPos, match_first<unsigned short, QuestChangePair>());
if (change_find != change_end && change_find->first == *lpHistoryPos)
{
// 수행 완료된 퀘스트의 ID가 변경되었다. 맞춰서 변경해준다.
*lpDst = change_find->second;
INFLOG3(g_Log, "CID:%10u / QuestID:0x%04X / ChangedID:0x%04X / 수행 완료된 퀘스트 ID 변경",
dwCID, *lpHistoryPos, *lpDst);
++dwChangedCount;
}
else
{
// 목록에 없는 경우에만 복사한다.
*lpDst = *lpHistoryPos;
}
++lpDst;
}
}
if (0 < dwChangedCount)
{
history_Out.dwSize = static_cast<unsigned long>(
reinterpret_cast<char*>(lpDst) - history_Out.Data);
charQuest_InOut.SetHistory(history_Out);
dwTotalChangedCount += dwChangedCount;
}
}
return (0 < dwTotalChangedCount) ? CONVERT_SUCCEEDED : CONVERT_DO_NOT_WRITE;
}