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>
This commit is contained in:
921
Server/ToolProject/SkillConvert/SkillConvert.cpp
Normal file
921
Server/ToolProject/SkillConvert/SkillConvert.cpp
Normal file
@@ -0,0 +1,921 @@
|
||||
// SkillConvert.cpp : 콘솔 응용 프로그램에 대한 진입점을 정의합니다.
|
||||
//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include <iostream>
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
#include <Log/ServerLog.h>
|
||||
#include <DB/DBComponent.h>
|
||||
#include <DB/GameDBComponent.h>
|
||||
#include <Skill/SkillMgr.h>
|
||||
#include <Utility/Math/Math.h>
|
||||
#include <list>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
const int nHammerID = 0x8406;
|
||||
const int nFirstAidID = 0x8405;
|
||||
|
||||
|
||||
class CSkillConvert
|
||||
{
|
||||
public:
|
||||
|
||||
CSkillConvert() : m_fSrc(NULL), m_fConverted(NULL) { }
|
||||
~CSkillConvert()
|
||||
{
|
||||
if(NULL != m_fSrc) { fclose(m_fSrc); m_fSrc = NULL; }
|
||||
if(NULL != m_fConverted) { fclose(m_fConverted); m_fConverted = NULL; }
|
||||
}
|
||||
|
||||
bool Initialize(char* szDBServerName, char* szDBName, char* szDBAccount, char* szDBPass);
|
||||
bool Process();
|
||||
void Test(const char* szFileName);
|
||||
|
||||
private:
|
||||
|
||||
bool ProcessSkill();
|
||||
bool ProcessSkillBook();
|
||||
bool ProcessSkillLevel();
|
||||
|
||||
// return : 업데이트 여부 - 업데이트시 True, 아니면 False
|
||||
static bool ProcessEraseHammerOfLight(unsigned long dwCID, SKILL& Skill);
|
||||
static int ProcessEraseHammerOfLightQuickSlot(unsigned long dwCID, QUICK& Quick);
|
||||
|
||||
// return : 업데이트한 아이템 갯수.
|
||||
static int ProcessSkillBookConvert(unsigned long dwUID, unsigned long dwCID, const char* lpBuffer, int nSize);
|
||||
static bool RecalculateSkill(unsigned long dwCID, SKILL& Skill);
|
||||
static void EraseSkill(SKILL& Skill, unsigned short usErasePos);
|
||||
|
||||
// return : 업데이트 여부
|
||||
bool AdjustSkillLevel(SKILL& skill);
|
||||
bool AdjustQSlotSkillLevel(QUICK& quick);
|
||||
|
||||
CDBComponent m_ReadDB;
|
||||
CDBComponent m_WriteDB;
|
||||
|
||||
FILE* m_fSrc;
|
||||
FILE* m_fConverted;
|
||||
};
|
||||
|
||||
|
||||
void PrintUsage()
|
||||
{
|
||||
cout << "다음과 같이 입력하세요 : SkillConvert DB서버주소 DB이름 DB계정 DB패스워드" << endl
|
||||
<< " 또는 : SkillConvert test testFileName" << endl << endl
|
||||
|
||||
<< " 테스트 파일의 포맷은 다음과 같은 포맷입니다. 엑셀로 작성한 후 cvs포맷으로 뽑으십시오" << endl
|
||||
<< " CID,SkillNum,SlotNum,Skill_1,Skill_1_LockCount,Skill_1_Level,Skill_2,Skill_2_LockCount,Skill_2_Level,..." << endl;
|
||||
}
|
||||
|
||||
|
||||
void LogSkillToFile(FILE* fWriteFile, unsigned long dwCID, SKILL& Skill)
|
||||
{
|
||||
fprintf(fWriteFile, "%d,%d,%d,", dwCID, Skill.wSkillNum, Skill.wSlotNum);
|
||||
|
||||
for(int nSlot = 0; nSlot < SKILL::MAX_SLOT_NUM; ++nSlot)
|
||||
{
|
||||
if(0 != Skill.SSlot[nSlot].SKILLINFO.wSkill)
|
||||
{
|
||||
fprintf(fWriteFile, "0x%04x,%d,%d,", Skill.SSlot[nSlot].SKILLINFO.wSkill,
|
||||
Skill.SSlot[nSlot].SKILLINFO.cLockCount,
|
||||
Skill.SSlot[nSlot].SKILLINFO.cSkillLevel);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(fWriteFile, "\n");
|
||||
}
|
||||
|
||||
|
||||
int _tmain(int argc, _TCHAR* argv[])
|
||||
{
|
||||
CSkillConvert Convert;
|
||||
|
||||
if(argc == 5)
|
||||
{
|
||||
if(!Convert.Initialize(argv[1], argv[2], argv[3], argv[4]))
|
||||
{
|
||||
cout << "[DB연결 실패]" << endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if(argc == 3)
|
||||
{
|
||||
if(0 == strcmp("test", argv[1]))
|
||||
{
|
||||
Convert.Test(argv[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintUsage();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintUsage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
cout << "[DB 연결 성공]" << endl;
|
||||
|
||||
time_t CurrentTime = time(NULL);
|
||||
DETLOG1(g_Log, "현재시간 : %s", ctime(&CurrentTime));
|
||||
|
||||
Convert.Process();
|
||||
|
||||
CurrentTime = time(NULL);
|
||||
DETLOG1(g_Log, "종료시간 : %s", ctime(&CurrentTime));
|
||||
|
||||
cout << "Press Enter Key" << endl;
|
||||
|
||||
string temp;
|
||||
getline(cin, temp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool CSkillConvert::Initialize(char* szDBServerName, char* szDBName, char* szDBAccount, char* szDBPass)
|
||||
{
|
||||
// DB 연결
|
||||
if(!m_ReadDB.Connect(szDBServerName, szDBName, szDBAccount, szDBPass))
|
||||
{
|
||||
cout << "[ReadDB 연결 실패]" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!m_WriteDB.Connect(szDBServerName, szDBName, szDBAccount, szDBPass))
|
||||
{
|
||||
cout << "[WriteDB 연결 실패]" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_fSrc = fopen("SrcSkillLog.txt", "wt");
|
||||
|
||||
if(NULL == m_fSrc)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_fConverted = fopen("ConvertedSkillLog.txt", "wt");
|
||||
|
||||
if(NULL == m_fConverted)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CSkillConvert::Process()
|
||||
{
|
||||
//ProcessSkill();
|
||||
//ProcessSkillBook();
|
||||
|
||||
ProcessSkillLevel();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSkillConvert::ProcessSkill()
|
||||
{
|
||||
char* szQuery = "select UID, Skill from CharSkill";
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
struct SkillData
|
||||
{
|
||||
unsigned long m_dwCID;
|
||||
SKILL m_Skill;
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
if(!m_ReadDB.ExecuteQuery(szQuery))
|
||||
{
|
||||
cout << "[Skill 쿼리 실패] : " << m_ReadDB.GetErrorString() << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
const int MAX_ROWS = 10240;
|
||||
int nGetRows = 0;
|
||||
SkillData* skillData = new SkillData[MAX_ROWS];
|
||||
memset(skillData, 0, sizeof(SkillData) * MAX_ROWS);
|
||||
|
||||
while(m_ReadDB.GetData((void**)skillData, sizeof(SkillData), MAX_ROWS, &nGetRows))
|
||||
{
|
||||
if(0 == nGetRows)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
for(SkillData* lpSkillData = skillData;
|
||||
0 < nGetRows; --nGetRows, ++lpSkillData)
|
||||
{
|
||||
const unsigned long dwCID = lpSkillData->m_dwCID;
|
||||
SKILL& skill = lpSkillData->m_Skill;
|
||||
SKILL oldSkill = lpSkillData->m_Skill;
|
||||
|
||||
bool bChanged = false;
|
||||
|
||||
if(ProcessEraseHammerOfLight(dwCID, skill))
|
||||
{
|
||||
bChanged = true;
|
||||
}
|
||||
|
||||
// 마지막에 해 줄 것
|
||||
if(RecalculateSkill(dwCID, skill))
|
||||
{
|
||||
bChanged = true;
|
||||
}
|
||||
|
||||
if(bChanged)
|
||||
{
|
||||
LogSkillToFile(m_fSrc, dwCID, oldSkill);
|
||||
LogSkillToFile(m_fConverted, dwCID, skill);
|
||||
|
||||
DBComponent::GameDB::UpdateCharSkill(m_WriteDB, dwCID, &skill);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete [] skillData;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CSkillConvert::ProcessEraseHammerOfLight(unsigned long dwCID, SKILL& Skill)
|
||||
{
|
||||
/*
|
||||
|
||||
리턴값. 고치는 데 성공하면, true.
|
||||
|
||||
2. SKILL이, 해머 오브 라이트가 있는지 본다.
|
||||
해머 오브 라이트가 있는 경우.. 퍼스트 에이드가 있는지 확인한다
|
||||
퍼스트 에이드가 있으면,
|
||||
해머 오브 라이트보다 레벨이 높거나 같다 - 해머 오브 라이트를 지운다.
|
||||
해머 오브 라이트보다 레벨이 낮다 - 퍼스트에이드를 지우고, 해머오브라이트를 퍼스트에이드로 바꾼다.
|
||||
퍼스트 에이드가 없으면, 해머 오브 라이트를 퍼스트 에이드로 바꾼다.
|
||||
|
||||
*/
|
||||
|
||||
if(20 < Skill.wSlotNum)
|
||||
{
|
||||
ERRLOG2(g_Log, "CID:%10d : 스킬 슬롯 개수가 이상합니다. %d개입니다.", dwCID, Skill.wSlotNum);
|
||||
Skill.wSlotNum = 20;
|
||||
}
|
||||
|
||||
for(int nHammerPos = 0; nHammerPos < Skill.wSlotNum; ++nHammerPos)
|
||||
{
|
||||
// 해머오브라이트가 있는지 확인
|
||||
if(nHammerID == Skill.SSlot[nHammerPos].SKILLINFO.wSkill)
|
||||
{
|
||||
// 퍼스트에이드가 있는지 확인
|
||||
for(int nFirstAidPos = 0; nFirstAidPos < Skill.wSlotNum; ++nFirstAidPos)
|
||||
{
|
||||
if(nFirstAidID == Skill.SSlot[nFirstAidPos].SKILLINFO.wSkill)
|
||||
{
|
||||
const int nHammerLevel = Skill.SSlot[nHammerPos].SKILLINFO.cLockCount * CSkillMgr::MAX_SKILL_LEVEL + Skill.SSlot[nHammerPos].SKILLINFO.cSkillLevel;
|
||||
const int nFirstAidLevel = Skill.SSlot[nFirstAidPos].SKILLINFO.cLockCount * CSkillMgr::MAX_SKILL_LEVEL + Skill.SSlot[nFirstAidPos].SKILLINFO.cSkillLevel;
|
||||
|
||||
if(nHammerLevel <= nFirstAidLevel)
|
||||
{
|
||||
// 퍼스트에이드가 해머오브라이트보다 레벨이 높거나 같다. - 해머오브라이트를 지운다
|
||||
EraseSkill(Skill, nHammerPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 퍼스트에이드가 해머오브라이트보다 레벨이 낮다 -
|
||||
// 퍼스트에이드를 지우고, 해머오브라이트를 퍼스트에이드로 바꾼다.
|
||||
Skill.SSlot[nHammerPos].SKILLINFO.wSkill = nFirstAidID;
|
||||
EraseSkill(Skill, nFirstAidPos);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 퍼스트에이드가 없다.. -> 해머 오브 라이트를 퍼스트에이드로 바꾼다.
|
||||
Skill.SSlot[nHammerPos].SKILLINFO.wSkill = nFirstAidID;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CSkillConvert::EraseSkill(SKILL& Skill, unsigned short usErasePos)
|
||||
{
|
||||
if(usErasePos < Skill.wSlotNum)
|
||||
{
|
||||
const int nEraseSkillLevel =
|
||||
Skill.SSlot[usErasePos].SKILLINFO.cLockCount * CSkillMgr::MAX_SKILL_LEVEL +
|
||||
Skill.SSlot[usErasePos].SKILLINFO.cSkillLevel;
|
||||
|
||||
int nEraseCount = usErasePos;
|
||||
for (; nEraseCount < Skill.wSlotNum - 1; ++nEraseCount)
|
||||
{
|
||||
Skill.SSlot[nEraseCount] = Skill.SSlot[nEraseCount + 1];
|
||||
}
|
||||
|
||||
Skill.SSlot[nEraseCount].SKILLINFO.wSkill = 0;
|
||||
Skill.SSlot[nEraseCount].SKILLINFO.cLockCount = 0;
|
||||
Skill.SSlot[nEraseCount].SKILLINFO.cSkillLevel = 0;
|
||||
|
||||
Skill.wSkillNum -= nEraseSkillLevel;
|
||||
--Skill.wSlotNum;
|
||||
}
|
||||
}
|
||||
|
||||
bool CSkillConvert::RecalculateSkill(unsigned long dwCID, SKILL& Skill)
|
||||
{
|
||||
unsigned short usOldSkillNum = Skill.wSkillNum;
|
||||
unsigned short usOldSlotNum = Skill.wSlotNum;
|
||||
|
||||
unsigned short usNewSkillNum = 0;
|
||||
unsigned short usNewSlotNum = 0;
|
||||
|
||||
for(int nCount = 0; nCount < SKILL::MAX_SLOT_NUM; ++nCount)
|
||||
{
|
||||
if(0 == Skill.SSlot[nCount].SKILLINFO.wSkill)
|
||||
{
|
||||
for(; nCount < SKILL::MAX_SLOT_NUM; ++nCount)
|
||||
{
|
||||
Skill.SSlot[nCount].SKILLINFO.wSkill = 0;
|
||||
Skill.SSlot[nCount].SKILLINFO.cLockCount = 0;
|
||||
Skill.SSlot[nCount].SKILLINFO.cSkillLevel = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
usNewSkillNum += Skill.SSlot[nCount].SKILLINFO.cLockCount * (CSkillMgr::MAX_SKILL_LEVEL - 1) +
|
||||
Skill.SSlot[nCount].SKILLINFO.cSkillLevel;
|
||||
|
||||
++usNewSlotNum;
|
||||
}
|
||||
}
|
||||
|
||||
if(usNewSkillNum != usOldSkillNum || usNewSlotNum != usOldSlotNum)
|
||||
{
|
||||
Skill.wSkillNum = usNewSkillNum;
|
||||
Skill.wSlotNum = usNewSlotNum;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CSkillConvert::ProcessSkillBook()
|
||||
{
|
||||
char Query[MAX_PATH] = "";
|
||||
int Rows = 0;
|
||||
|
||||
STORE Store1 = {0,};
|
||||
STORE Store2 = {0,};
|
||||
|
||||
EQUIP EquipData = {0,};
|
||||
INVEN InvenData = {0,};
|
||||
EXTRA ExtraData = {0,};
|
||||
EXCHANGE Exchange = {0,};
|
||||
|
||||
typedef std::list<DWORD> UIDList;
|
||||
UIDList m_UIDList;
|
||||
|
||||
DWORD UIDs[CDBSingleObject::MaxRowNum];
|
||||
sprintf(Query, "select UID from UserInfo");
|
||||
for(int StartRows = 0;; StartRows += Rows)
|
||||
{
|
||||
memset(UIDs, 0, sizeof(DWORD) * CDBSingleObject::MaxRowNum);
|
||||
if(!m_ReadDB.Select(Query, (void**)&UIDs, sizeof(DWORD), StartRows, CDBSingleObject::MaxRowNum, &Rows))
|
||||
{
|
||||
ERRLOG0(g_Log, "UID 얻기 실패");
|
||||
return false;
|
||||
}
|
||||
|
||||
for(int Count = 0; Count < Rows; ++Count)
|
||||
{
|
||||
m_UIDList.push_back(UIDs[Count]);
|
||||
}
|
||||
|
||||
if(Rows != CDBSingleObject::MaxRowNum)
|
||||
break;
|
||||
}
|
||||
|
||||
DETLOG1(g_Log, "리스트 유저 숫자 : %d", m_UIDList.size());
|
||||
|
||||
DWORD UserID = 0;
|
||||
|
||||
USER_INFO UserInfo = {0,};
|
||||
DWORD CharID[3] = {0,};
|
||||
|
||||
SKILL Skill;
|
||||
SKILL oldSkill;
|
||||
|
||||
QUICK Quick;
|
||||
|
||||
int nCurrentCount = 0;
|
||||
int nTotalCount = m_UIDList.size();
|
||||
|
||||
for(UIDList::iterator itr = m_UIDList.begin(); itr != m_UIDList.end(); ++itr)
|
||||
{
|
||||
UserID = *itr;
|
||||
|
||||
memset(&UserInfo, 0, sizeof(USER_INFO));
|
||||
memset(&CharID, 0, sizeof(DWORD) * 3);
|
||||
|
||||
if(!DBComponent::GameDB::GetUserInfo(m_ReadDB, UserID, &UserInfo))
|
||||
continue;
|
||||
|
||||
CharID[0] = UserInfo.Char1;
|
||||
CharID[1] = UserInfo.Char2;
|
||||
CharID[2] = UserInfo.Char3;
|
||||
|
||||
memset(&Store1, 0, sizeof(STORE));
|
||||
memset(&Store2, 0, sizeof(STORE));
|
||||
|
||||
for(int Count = 0; Count < 3; ++Count)
|
||||
{
|
||||
if(0 == CharID[Count])
|
||||
continue;
|
||||
|
||||
memset(&EquipData, 0, sizeof(EQUIP));
|
||||
memset(&InvenData, 0, sizeof(INVEN));
|
||||
memset(&ExtraData, 0, sizeof(EXTRA));
|
||||
memset(&Exchange, 0, sizeof(EXCHANGE));
|
||||
|
||||
// 장비
|
||||
if(!DBComponent::GameDB::GetEquip(m_ReadDB, CharID[Count], &EquipData))
|
||||
{
|
||||
ERRLOG2(g_Log, "장비 읽기 실패 UID: %d CID: %d", UserID, CharID[Count]);
|
||||
}
|
||||
else if(0 < ProcessSkillBookConvert(UserID, CharID[Count], EquipData.Data, EquipData.dwSize))
|
||||
{
|
||||
if(!DBComponent::GameDB::UpdateEquip(m_WriteDB, CharID[Count], &EquipData))
|
||||
{
|
||||
ERRLOG2(g_Log, "장비 쓰기 실패 UID: %d CID: %d", UserID, CharID[Count]);
|
||||
}
|
||||
}
|
||||
|
||||
// 인벤
|
||||
if(!DBComponent::GameDB::GetInven(m_ReadDB, CharID[Count], &InvenData))
|
||||
{
|
||||
ERRLOG2(g_Log, "인벤 읽기 실패 UID: %d CID: %d", UserID, CharID[Count]);
|
||||
}
|
||||
else if(0 < ProcessSkillBookConvert(UserID, CharID[Count], InvenData.Data, InvenData.dwSize))
|
||||
{
|
||||
if(!DBComponent::GameDB::UpdateInven(m_WriteDB, CharID[Count], &InvenData))
|
||||
{
|
||||
ERRLOG2(g_Log, "인벤 쓰기 실패 UID: %d CID: %d", UserID, CharID[Count]);
|
||||
}
|
||||
}
|
||||
|
||||
// 여분
|
||||
if(!DBComponent::GameDB::GetExtra(m_ReadDB, CharID[Count], &ExtraData))
|
||||
{
|
||||
ERRLOG2(g_Log, "여분 읽기 실패 UID: %d CID: %d", UserID, CharID[Count]);
|
||||
}
|
||||
else if(0 < ProcessSkillBookConvert(UserID, CharID[Count], ExtraData.Data, ExtraData.dwSize))
|
||||
{
|
||||
if(!DBComponent::GameDB::UpdateExtra(m_WriteDB, CharID[Count], &ExtraData))
|
||||
{
|
||||
ERRLOG2(g_Log, "여분 쓰기 실패 UID: %d CID: %d", UserID, CharID[Count]);
|
||||
}
|
||||
}
|
||||
|
||||
// 교환
|
||||
if(!DBComponent::GameDB::GetExchange(m_ReadDB, CharID[Count], &Exchange))
|
||||
{
|
||||
ERRLOG2(g_Log, "교환 읽기 실패 UID: %d CID: %d", UserID, CharID[Count]);
|
||||
}
|
||||
else if(0 < ProcessSkillBookConvert(UserID, CharID[Count], Exchange.Data, Exchange.dwSize))
|
||||
{
|
||||
if(!DBComponent::GameDB::UpdateExchange(m_WriteDB, CharID[Count], &Exchange))
|
||||
{
|
||||
ERRLOG2(g_Log, "교환 쓰기 실패 UID: %d CID: %d", UserID, CharID[Count]);
|
||||
}
|
||||
}
|
||||
|
||||
// 퀵슬롯
|
||||
if(!DBComponent::GameDB::GetQuick(m_ReadDB, CharID[Count], &Quick))
|
||||
{
|
||||
ERRLOG2(g_Log, "퀵슬롯 읽기 실패 UID:%d, CID:%d", CharID[Count], UserID);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(0 < ProcessEraseHammerOfLightQuickSlot(CharID[Count], Quick))
|
||||
{
|
||||
if(!DBComponent::GameDB::UpdateQuick(m_WriteDB, CharID[Count], &Quick))
|
||||
{
|
||||
ERRLOG2(g_Log, "퀵슬롯 쓰기 실패 UID:%d, CID:%d", CharID[Count], UserID);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 스킬
|
||||
if(!DBComponent::GameDB::GetCharSkill(m_ReadDB, CharID[Count], &Skill))
|
||||
{
|
||||
ERRLOG2(g_Log, "스킬 읽기 실패 UID:%d, CID:%d", CharID[Count], UserID);
|
||||
}
|
||||
else
|
||||
{
|
||||
oldSkill = Skill;
|
||||
|
||||
bool bChanged = false;
|
||||
|
||||
if(ProcessEraseHammerOfLight(CharID[Count], Skill))
|
||||
{
|
||||
bChanged = true;
|
||||
}
|
||||
|
||||
// 마지막에 해 줄 것
|
||||
if(RecalculateSkill(CharID[Count], Skill))
|
||||
{
|
||||
bChanged = true;
|
||||
}
|
||||
|
||||
if(bChanged)
|
||||
{
|
||||
LogSkillToFile(m_fSrc, CharID[Count], oldSkill);
|
||||
LogSkillToFile(m_fConverted, CharID[Count], Skill);
|
||||
|
||||
if(!DBComponent::GameDB::UpdateCharSkill(m_WriteDB, CharID[Count], &Skill))
|
||||
{
|
||||
ERRLOG2(g_Log, "스킬 쓰기 실패 UID:%d, CID:%d", CharID[Count], UserID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 창고1
|
||||
if(!DBComponent::GameDB::GetItemStore1(m_ReadDB, UserID, &Store1))
|
||||
{
|
||||
ERRLOG1(g_Log, "창고1 읽기 실패 UID: %d", UserID);
|
||||
}
|
||||
else if(0 < ProcessSkillBookConvert(UserID, 0, Store1.Data, Store1.dwSize))
|
||||
{
|
||||
if(!DBComponent::GameDB::UpdateItemStore1(m_WriteDB, UserID, &Store1))
|
||||
{
|
||||
ERRLOG1(g_Log, "창고1 쓰기 실패 UID: %d", UserID);
|
||||
}
|
||||
}
|
||||
|
||||
// 창고 2
|
||||
if(!DBComponent::GameDB::GetItemStore2(m_ReadDB, UserID, &Store2))
|
||||
{
|
||||
ERRLOG1(g_Log, "창고2 읽기 실패 UID: %d", UserID);
|
||||
}
|
||||
else if(0 < ProcessSkillBookConvert(UserID, 0, Store2.Data, Store2.dwSize))
|
||||
{
|
||||
if(!DBComponent::GameDB::UpdateItemStore2(m_WriteDB, UserID, &Store2))
|
||||
{
|
||||
ERRLOG1(g_Log, "창고2 쓰기 실패 UID: %d", UserID);
|
||||
}
|
||||
}
|
||||
|
||||
cout << ".";
|
||||
|
||||
if(0 != (nCurrentCount % 10000))
|
||||
{
|
||||
cout << endl << nCurrentCount << "/" << nTotalCount << endl;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int CSkillConvert::ProcessSkillBookConvert(unsigned long dwUID, unsigned long dwCID, const char* lpBuffer, int nSize)
|
||||
{
|
||||
const char* lpItemBuff = lpBuffer;
|
||||
int nItemSize = nSize;
|
||||
|
||||
int nConvertNum = 0;
|
||||
|
||||
int nLoopCount = 0;
|
||||
|
||||
while(nItemSize > 0)
|
||||
{
|
||||
Item::ItemData* lpItem = (Item::ItemData*)lpItemBuff;
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// 해머오브라이트 계열 스킬북을 퍼스트에이드 계열 스킬북으로 바꿉니다.
|
||||
switch(lpItem->m_usProtoTypeID)
|
||||
{
|
||||
case 3558: lpItem->m_usProtoTypeID = 3553; ++nConvertNum; break;
|
||||
case 3559: lpItem->m_usProtoTypeID = 3554; ++nConvertNum; break;
|
||||
case 3560: lpItem->m_usProtoTypeID = 3555; ++nConvertNum; break;
|
||||
case 3561: lpItem->m_usProtoTypeID = 3556; ++nConvertNum; break;
|
||||
case 3562: lpItem->m_usProtoTypeID = 3557; ++nConvertNum; break;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// 다음 아이템을 진행합니다.
|
||||
|
||||
lpItemBuff += lpItem->m_cItemSize;
|
||||
nItemSize -= lpItem->m_cItemSize;
|
||||
|
||||
++nLoopCount;
|
||||
|
||||
if(10000 < ++nLoopCount)
|
||||
{
|
||||
// 뭔가 이상하다. break한다.
|
||||
SERLOG2(g_Log, "UID:%u/CID:%u/ 이상한 아이템을 지니고 있습니다. 확인해 주세요", dwUID, dwCID);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return nConvertNum;
|
||||
}
|
||||
|
||||
|
||||
int CSkillConvert::ProcessEraseHammerOfLightQuickSlot(unsigned long dwCID, QUICK& Quick)
|
||||
{
|
||||
int nErased = 0;
|
||||
|
||||
for(int nCount = 0; nCount < QUICK::MAX_QUICK_NUM; ++nCount)
|
||||
{
|
||||
if(Quick.Slots[nCount].nType == QUICKSLOT::SKILL &&
|
||||
(Quick.Slots[nCount].wID == nHammerID || Quick.Slots[nCount].wID == nFirstAidID))
|
||||
{
|
||||
Quick.Slots[nCount].wID = 0;
|
||||
Quick.Slots[nCount].nType = QUICKSLOT::NONE;
|
||||
Quick.Slots[nCount].nSkillLevel = 0;
|
||||
Quick.Slots[nCount].nSkillLockCount = 0;
|
||||
|
||||
++nErased;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nErased;
|
||||
}
|
||||
|
||||
void CSkillConvert::Test(const char* szFileName)
|
||||
{
|
||||
const char* szDelimit = ",";
|
||||
unsigned long dwCID = 0;
|
||||
SKILL Skill;
|
||||
|
||||
FILE* fReadFile = fopen(szFileName, "rt");
|
||||
if(NULL != fReadFile)
|
||||
{
|
||||
char szWriteFile[MAX_PATH];
|
||||
|
||||
_snprintf(szWriteFile, MAX_PATH, "Result%s", szFileName);
|
||||
szWriteFile[MAX_PATH - 1] = 0;
|
||||
|
||||
FILE* fWriteFile = fopen(szWriteFile, "wt");
|
||||
if(NULL != fWriteFile)
|
||||
{
|
||||
const int MAX_DATA_LEN = 4096;
|
||||
char szData[MAX_DATA_LEN];
|
||||
|
||||
while(fgets(szData, MAX_DATA_LEN, fReadFile))
|
||||
{
|
||||
memset(&Skill, 0, sizeof(SKILL));
|
||||
|
||||
char* szBuffer = strtok(szData, szDelimit);
|
||||
if(NULL == szBuffer)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
dwCID = atoi(szBuffer);
|
||||
|
||||
szBuffer = strtok(NULL, szDelimit);
|
||||
if(NULL == szBuffer)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Skill.wSkillNum = atoi(szBuffer);
|
||||
|
||||
szBuffer = strtok(NULL, szDelimit);
|
||||
if(NULL == szBuffer)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Skill.wSlotNum = atoi(szBuffer);
|
||||
|
||||
szBuffer = strtok(NULL, szDelimit);
|
||||
|
||||
int nSlot = 0;
|
||||
while(NULL != szBuffer && nSlot < SKILL::MAX_SLOT_NUM)
|
||||
{
|
||||
Skill.SSlot[nSlot].SKILLINFO.wSkill = Math::Convert::Atos(szBuffer); // 스킬 ID
|
||||
|
||||
szBuffer = strtok(NULL, szDelimit);
|
||||
if(NULL == szBuffer)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Skill.SSlot[nSlot].SKILLINFO.cLockCount = Math::Convert::Atoc(szBuffer);
|
||||
|
||||
szBuffer = strtok(NULL, szDelimit);
|
||||
if(NULL == szBuffer)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Skill.SSlot[nSlot].SKILLINFO.cSkillLevel = Math::Convert::Atoc(szBuffer);
|
||||
|
||||
++nSlot;
|
||||
szBuffer = strtok(NULL, szDelimit);
|
||||
}
|
||||
|
||||
ProcessEraseHammerOfLight(dwCID, Skill);
|
||||
RecalculateSkill(dwCID, Skill);
|
||||
|
||||
LogSkillToFile(fWriteFile, dwCID, Skill);
|
||||
}
|
||||
|
||||
fclose(fWriteFile);
|
||||
}
|
||||
|
||||
fclose(fReadFile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CSkillConvert::ProcessSkillLevel()
|
||||
{
|
||||
char* szQuery = "select UID, Skill from CharSkill";
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
struct SkillData
|
||||
{
|
||||
unsigned long m_dwCID;
|
||||
SKILL m_Skill;
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
if(!m_ReadDB.ExecuteQuery(szQuery))
|
||||
{
|
||||
cout << "[Skill 쿼리 실패] : " << m_ReadDB.GetErrorString() << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
const int MAX_ROWS = 10240;
|
||||
int nGetRows = 0;
|
||||
SkillData* skillData = new SkillData[MAX_ROWS];
|
||||
memset(skillData, 0, sizeof(SkillData) * MAX_ROWS);
|
||||
|
||||
while(m_ReadDB.GetData((void**)skillData, sizeof(SkillData), MAX_ROWS, &nGetRows))
|
||||
{
|
||||
if(0 == nGetRows)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
for(SkillData* lpSkillData = skillData;
|
||||
0 < nGetRows; --nGetRows, ++lpSkillData)
|
||||
{
|
||||
const unsigned long dwCID = lpSkillData->m_dwCID;
|
||||
|
||||
SKILL& skill = lpSkillData->m_Skill;
|
||||
SKILL oldSkill = lpSkillData->m_Skill;
|
||||
|
||||
bool bChanged = false;
|
||||
|
||||
if(AdjustSkillLevel(skill))
|
||||
{
|
||||
bChanged = true;
|
||||
}
|
||||
|
||||
// 스킬 레벨을 조정한다.
|
||||
if(bChanged)
|
||||
{
|
||||
LogSkillToFile(m_fSrc, dwCID, oldSkill);
|
||||
LogSkillToFile(m_fConverted, dwCID, skill);
|
||||
|
||||
DBComponent::GameDB::UpdateCharSkill(m_WriteDB, dwCID, &skill);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete [] skillData;
|
||||
|
||||
|
||||
szQuery = "select UID, Quick from CharItem";
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
struct QSlotData
|
||||
{
|
||||
unsigned long m_dwCID;
|
||||
QUICK m_Quick;
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
if(!m_ReadDB.ExecuteQuery(szQuery))
|
||||
{
|
||||
cout << "[Quick 쿼리 실패] : " << m_ReadDB.GetErrorString() << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
nGetRows = 0;
|
||||
QSlotData* qslotdata = new QSlotData[MAX_ROWS];
|
||||
memset(qslotdata, 0, sizeof(QSlotData) * MAX_ROWS);
|
||||
|
||||
while(m_ReadDB.GetData((void**)qslotdata, sizeof(QSlotData), MAX_ROWS, &nGetRows))
|
||||
{
|
||||
if(0 == nGetRows)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
for(QSlotData* lpQSlotData = qslotdata;
|
||||
0 < nGetRows; --nGetRows, ++lpQSlotData)
|
||||
{
|
||||
const unsigned long dwCID = lpQSlotData->m_dwCID;
|
||||
|
||||
QUICK& quick = lpQSlotData->m_Quick;
|
||||
QUICK oldquick = lpQSlotData->m_Quick;
|
||||
|
||||
bool bChanged = false;
|
||||
|
||||
if(AdjustQSlotSkillLevel(quick))
|
||||
{
|
||||
bChanged = true;
|
||||
}
|
||||
|
||||
// 스킬 레벨을 조정한다.
|
||||
if(bChanged)
|
||||
{
|
||||
DBComponent::GameDB::UpdateQuick(m_WriteDB, dwCID, &quick);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete [] qslotdata;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSkillConvert::AdjustSkillLevel(SKILL& skill)
|
||||
{
|
||||
int nChangedCount = 0;
|
||||
|
||||
for(int nCount = 0; nCount < SKILL::MAX_SLOT_NUM; ++nCount)
|
||||
{
|
||||
if(6 == skill.SSlot[nCount].SKILLINFO.cSkillLevel)
|
||||
{
|
||||
if(skill.SSlot[nCount].SKILLINFO.cLockCount < 3)
|
||||
{
|
||||
++skill.SSlot[nCount].SKILLINFO.cLockCount;
|
||||
skill.SSlot[nCount].SKILLINFO.cSkillLevel = 0;
|
||||
|
||||
++nChangedCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
skill.SSlot[nCount].SKILLINFO.cLockCount = 3;
|
||||
skill.SSlot[nCount].SKILLINFO.cSkillLevel = 6;
|
||||
|
||||
++nChangedCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (0 < nChangedCount);
|
||||
}
|
||||
|
||||
bool CSkillConvert::AdjustQSlotSkillLevel(QUICK& quick)
|
||||
{
|
||||
int nChangedCount = 0;
|
||||
|
||||
for(int nCount = 0; nCount < QUICK::MAX_QUICK_NUM; ++nCount)
|
||||
{
|
||||
if(QUICKSLOT::SKILL == quick.Slots[nCount].nType &&
|
||||
6 == quick.Slots[nCount].nSkillLevel)
|
||||
{
|
||||
if(quick.Slots[nCount].nSkillLockCount < 3)
|
||||
{
|
||||
++quick.Slots[nCount].nSkillLockCount;
|
||||
quick.Slots[nCount].nSkillLevel = 0;
|
||||
|
||||
++nChangedCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
quick.Slots[nCount].nSkillLockCount = 3;
|
||||
quick.Slots[nCount].nSkillLevel = 6;
|
||||
|
||||
++nChangedCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (0 < nChangedCount);
|
||||
}
|
||||
Reference in New Issue
Block a user