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>
1384 lines
47 KiB
C++
1384 lines
47 KiB
C++
// SkillRebalanceConverter.cpp : 콘솔 응용 프로그램에 대한 진입점을 정의합니다.
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
|
|
#pragma warning(disable:4800)
|
|
|
|
#include <winsock2.h>
|
|
#include <windows.h>
|
|
|
|
#include <DB/DBComponent.h>
|
|
#include <DB/GameDBComponent.h>
|
|
|
|
#include <map>
|
|
#include <boost/pool/pool_alloc.hpp>
|
|
#include <Item/ItemMgr.h>
|
|
#include <Item/Item.h>
|
|
#include <Item/ItemContainer.h>
|
|
#include <Item/ItemFactory.h>
|
|
#include <Item/ItemStructure.h>
|
|
|
|
#include <Skill/SkillMgr.h>
|
|
|
|
#include <Log/ServerLog.h>
|
|
|
|
#include <Network/Packet/PacketStruct/ServerInfo.h>
|
|
#include <Utility/Setup/ServerSetup.h>
|
|
|
|
#include "ItemSerialMgr.h"
|
|
#include "3DArrayChecker.h"
|
|
|
|
|
|
#pragma pack(1)
|
|
|
|
struct SkillData
|
|
{
|
|
unsigned long m_dwCID;
|
|
SKILL m_skill;
|
|
};
|
|
|
|
struct CharData
|
|
{
|
|
unsigned long m_dwCID;
|
|
INVEN m_Inventory;
|
|
EXTRA m_Extra;
|
|
EXCHANGE m_Exchange;
|
|
};
|
|
|
|
struct StoreData
|
|
{
|
|
unsigned long m_dwUID;
|
|
STORE m_store1;
|
|
STORE m_store2;
|
|
};
|
|
|
|
#pragma pack()
|
|
|
|
struct SkillBookData
|
|
{
|
|
enum { MAX_SKILL_LOCKCOUNT = 5 };
|
|
unsigned long m_dwSkillBookNum[MAX_SKILL_LOCKCOUNT];
|
|
};
|
|
|
|
typedef std::map<unsigned long, SkillBookData, std::less<unsigned long>,
|
|
boost::fast_pool_allocator<std::pair<unsigned long, SkillBookData> > > SkillBookMap;
|
|
/*
|
|
typedef std::map<unsigned long, SkillBookData> SkillBookMap;
|
|
*/
|
|
bool ProcessCharData(CDBComponent& readDB, CDBComponent& writeDB,
|
|
SkillBookMap& skillBookMap, bool bDelCharHistory, bool bWriteDB);
|
|
|
|
bool ProcessStoreData(CDBComponent& readDB, CDBComponent& writeDB,
|
|
SkillBookMap& skillBookMap, bool bWriteDB);
|
|
|
|
bool ReadSkillData(CDBComponent& readDB, SkillBookMap& cidSkillBookMap, bool bReadDelCharHistory);
|
|
|
|
bool RemoveSkills(unsigned long dwKey, const char* szContainerName, SkillBookMap& skillBookMap,
|
|
const char* szInputData, unsigned long dwInputDataSize,
|
|
char* szResultData, unsigned long& dwResultDataSize);
|
|
|
|
unsigned long InsertSkillBookTicket(unsigned long dwKey, const char* szContainerName,
|
|
C3DArrayChecker& arrayChecker, SkillBookMap& skillBookMap,
|
|
char* szData, unsigned long& dwDataSize_InOut, unsigned long dwMaxDataSize);
|
|
|
|
bool InsertToTempInven(CDBComponent& readDB, unsigned long dwCID, SkillBookMap& cidBookMap);
|
|
bool InsertToCharDelTempInven(CDBComponent& writeDB, unsigned long dwCID, SkillBookMap& cidBookMap);
|
|
|
|
void WriteSkillClear(CDBComponent& writeDB, bool bDelCharHistory);
|
|
void WriteBackCharacterData(CDBComponent& writeDB, CharData& originalData, CharData& newData);
|
|
void WriteBackStoreData(CDBComponent& writeDB, StoreData& originalData, StoreData& newData);
|
|
void WriteBackCharDelHistoryData(CDBComponent& writeDB, CharData& originalData, CharData& newData);
|
|
|
|
void AddCharGold(CDBComponent& writeDB, unsigned long dwGold, unsigned long dwCID, bool bCharDelHistory);
|
|
void AddStoreGold(CDBComponent& writeDB, unsigned long dwGold, unsigned long dwUID);
|
|
|
|
namespace DBComponent
|
|
{
|
|
namespace GameDB
|
|
{
|
|
|
|
bool UpdateDelHistoryInven(CDBComponent& DBComponent, unsigned long CharID_In, LPINVEN lpInven_In);
|
|
bool UpdateDelHistoryExtra(CDBComponent& DBComponent, unsigned long CharID_In, LPEXTRA lpExtra_In);
|
|
bool UpdateDelHistoryExchange(CDBComponent& DBComponent, unsigned long CharID_In, LPEXCHANGE lpExchange_In);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
void PrintUsage()
|
|
{
|
|
printf("Usage : SkillRebalanceConverter DBServerName DBName DBAccount DBPassword "
|
|
"ServerGroup(GroupNum) ConvertDelHistroy(0/1) DBWrite(0/1)\n");
|
|
}
|
|
|
|
CServerLog g_GoldLog("GoldLog.log");
|
|
|
|
int _tmain(int argc, _TCHAR* argv[])
|
|
{
|
|
if(argc != 8)
|
|
{
|
|
PrintUsage();
|
|
return -1;
|
|
}
|
|
|
|
int nGroupNum = atoi(argv[5]);
|
|
bool bConvertDelHistory = (0 == strcmp("1", argv[6]));
|
|
bool bWriteDB = (0 == strcmp("1", argv[7]));
|
|
|
|
CDBComponent readDB;
|
|
if(!readDB.Connect(argv[1], argv[2], argv[3], argv[4]))
|
|
{
|
|
printf("Open readDB failed\n");
|
|
return -1;
|
|
}
|
|
|
|
CDBComponent writeDB;
|
|
if(!writeDB.Connect(argv[1], argv[2], argv[3], argv[4]))
|
|
{
|
|
printf("Open writeDB failed\n");
|
|
return -1;
|
|
}
|
|
|
|
if(!Item::CItemMgr::GetInstance().LoadItemProtoType("./NewItemScript.txt"))
|
|
{
|
|
printf("ItemScript load failed\n");
|
|
return -1;
|
|
}
|
|
|
|
if(!CSkillMgr::GetInstance().LoadSkillsFromFile("./NewSkillScript.txt"))
|
|
{
|
|
printf("SkillScript load failed\n");
|
|
return -1;
|
|
}
|
|
|
|
SERVER_ID serverID;
|
|
serverID.sID.Type = CServerSetup::AdminToolServer;
|
|
serverID.sID.Group = nGroupNum;
|
|
serverID.sID.Channel = 1;
|
|
serverID.sID.ID = SERVER_ID::ADMIN_TOOL_ZONE;
|
|
|
|
CItemSerialMgr itemSerialMgr;
|
|
|
|
if(!itemSerialMgr.LoadItemSerial(readDB, serverID.dwID))
|
|
{
|
|
printf("AdminTool serial setting failed\n");
|
|
return -1;
|
|
}
|
|
|
|
Item::CItemFactory::GetInstance().SetItemUID(itemSerialMgr.GetItemSerial());
|
|
|
|
/*
|
|
1. 기존 스킬을 읽어 카운팅하고 리셋한다
|
|
4단계/3단계/2단계/1단계 개수 카운팅
|
|
|
|
2. 기존 스킬북을 읽어서 Container에 Serialize한 후 iterator 로 돌면서 제거한다
|
|
4단계/3단계/2단계/1단계 개수 카운팅
|
|
|
|
3. 빈공간을 검색해서, 3/4단계 스킬에 대해서 보상 아이템을 넣어준다
|
|
4. 빈공간이 없으면 임시 인벤토리에 넣어 준다.
|
|
|
|
5. 다시 Serialize해서 DB에 저장한다.
|
|
|
|
|
|
6. 1/2단계 스킬북에 대한 보상 금액을 DB에 갱신한다.
|
|
*/
|
|
|
|
SkillBookMap m_cidBookMap;
|
|
SkillBookMap m_uidBookMap;
|
|
|
|
/*
|
|
SkillBookData data;
|
|
memset(&data, 0, sizeof(SkillBookData));
|
|
data.m_dwSkillBookNum[2] = 10;
|
|
data.m_dwSkillBookNum[3] = 10;
|
|
m_cidBookMap.insert(std::make_pair(277715, data));
|
|
|
|
InsertToTempInven(writeDB, 277715, m_cidBookMap);
|
|
*/
|
|
|
|
// 제거 성공했으면, 인벤토리에 스킬북 교환권을 넣어준다.
|
|
if(bConvertDelHistory)
|
|
{
|
|
printf("Convert CharDelHistory\n");
|
|
INFLOG0(g_Log, "Convert CharDelHistory");
|
|
|
|
if(!ReadSkillData(readDB, m_cidBookMap, true))
|
|
{
|
|
printf("Skill data read failed\n");
|
|
return -1;
|
|
}
|
|
|
|
if(!ProcessCharData(readDB, writeDB, m_cidBookMap, true, bWriteDB))
|
|
{
|
|
printf("CharDelHistory : Character data convert failed\n");
|
|
return -1;
|
|
}
|
|
|
|
SkillBookMap::iterator pos = m_cidBookMap.begin();
|
|
SkillBookMap::iterator end = m_cidBookMap.end();
|
|
|
|
for(; pos != end; ++pos)
|
|
{
|
|
unsigned long dwCID = pos->first;
|
|
SkillBookData& skillBookData = pos->second;
|
|
|
|
ERRLOG5(g_Log, "CID:%10u / 0:%u / 1:%u / 2:%u / 3:%u / CharDelHistory : 다음 스킬을 캐릭터에 지급하지 못했습니다",
|
|
dwCID, skillBookData.m_dwSkillBookNum[0], skillBookData.m_dwSkillBookNum[1],
|
|
skillBookData.m_dwSkillBookNum[2], skillBookData.m_dwSkillBookNum[3]);
|
|
}
|
|
|
|
m_cidBookMap.clear();
|
|
|
|
WriteSkillClear(writeDB, true);
|
|
}
|
|
|
|
printf("Read SkillData\n");
|
|
INFLOG0(g_Log, "Read SkillData");
|
|
|
|
if(!ReadSkillData(readDB, m_cidBookMap, false))
|
|
{
|
|
printf("Skill data read failed\n");
|
|
return -1;
|
|
}
|
|
|
|
printf("Convert CharData\n");
|
|
INFLOG0(g_Log, "Convert CharData");
|
|
|
|
if(!ProcessCharData(readDB, writeDB, m_cidBookMap, false, bWriteDB))
|
|
{
|
|
printf("Character data convert failed\n");
|
|
return -1;
|
|
}
|
|
|
|
printf("Convert StoreData\n");
|
|
INFLOG0(g_Log, "Convert Store");
|
|
|
|
if(!ProcessStoreData(readDB, writeDB, m_uidBookMap, bWriteDB))
|
|
{
|
|
printf("Store data convert failed\n");
|
|
return -1;
|
|
}
|
|
|
|
SkillBookMap::iterator pos = m_cidBookMap.begin();
|
|
SkillBookMap::iterator end = m_cidBookMap.end();
|
|
|
|
for(; pos != end; ++pos)
|
|
{
|
|
unsigned long dwCID = pos->first;
|
|
SkillBookData& skillBookData = pos->second;
|
|
|
|
ERRLOG5(g_Log, "CID:%10u / 0:%u / 1:%u / 2:%u / 3:%u / 다음 스킬을 캐릭터에 지급하지 못했습니다",
|
|
dwCID, skillBookData.m_dwSkillBookNum[0], skillBookData.m_dwSkillBookNum[1],
|
|
skillBookData.m_dwSkillBookNum[2], skillBookData.m_dwSkillBookNum[3]);
|
|
}
|
|
|
|
m_cidBookMap.clear();
|
|
|
|
pos = m_uidBookMap.begin();
|
|
end = m_uidBookMap.end();
|
|
|
|
for(; pos != end; ++pos)
|
|
{
|
|
unsigned long dwUID = pos->first;
|
|
SkillBookData& skillBookData = pos->second;
|
|
|
|
ERRLOG5(g_Log, "UID:%10u / 0:%u / 1:%u / 2:%u / 3:%u / 다음 스킬을 창고에 지급하지 못했습니다",
|
|
dwUID, skillBookData.m_dwSkillBookNum[0], skillBookData.m_dwSkillBookNum[1],
|
|
skillBookData.m_dwSkillBookNum[2], skillBookData.m_dwSkillBookNum[3]);
|
|
}
|
|
|
|
m_uidBookMap.clear();
|
|
|
|
|
|
printf("Clear Skill\n");
|
|
INFLOG0(g_Log, "Clear Skill");
|
|
|
|
if(bWriteDB)
|
|
{
|
|
// 스킬을 초기화한다.
|
|
WriteSkillClear(writeDB, false);
|
|
|
|
printf("Clear Skill Complete\n");
|
|
INFLOG0(g_Log, "Clear Skill Complete");
|
|
|
|
// 아이템 시리얼을 저장한다.
|
|
itemSerialMgr.SetItemSerial(Item::CItemFactory::GetInstance().GetItemUID());
|
|
|
|
if(!itemSerialMgr.SaveItemSerial(writeDB, serverID.dwID))
|
|
{
|
|
printf("AdminTool serial save failed\n");
|
|
}
|
|
}
|
|
|
|
printf("Convert Complete\n");
|
|
INFLOG0(g_Log, "Convent Complete");
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
bool ProcessCharData(CDBComponent& readDB, CDBComponent& writeDB, SkillBookMap& skillBookMap,
|
|
bool bDelCharHistory, bool bWriteDB)
|
|
{
|
|
const char* szQuery = bDelCharHistory ?
|
|
"Select UID, Inventory, Extra from CharDelHistory..DelCharItem" :
|
|
"Select a.UID, a.Inventory, a.Extra, b.Exchange from CharItem a join CharItemEX b on a.UID = b.UID";
|
|
|
|
const int MAX_CHAR_DATA = 1024;
|
|
CharData* lpCharData = new CharData[MAX_CHAR_DATA];
|
|
|
|
if(0 == lpCharData)
|
|
{
|
|
printf("Memory allocation failed : CharData\n");
|
|
return false;
|
|
}
|
|
|
|
memset(lpCharData, 0, sizeof(CharData) * MAX_CHAR_DATA);
|
|
|
|
// 캐릭터 인벤 뒤져서 스킬북 제거하고, 카운팅하기.
|
|
if(!readDB.ExecuteQuery(szQuery))
|
|
{
|
|
printf("DBQuery failed : %s : %s\n", szQuery, readDB.GetErrorString());
|
|
return false;
|
|
}
|
|
|
|
int nCount = 0;
|
|
int nGetRowNum = 0;
|
|
while(readDB.GetData((void**)lpCharData, sizeof(CharData), MAX_CHAR_DATA, &nGetRowNum))
|
|
{
|
|
if(0 == nGetRowNum)
|
|
{
|
|
break;
|
|
}
|
|
|
|
CharData* lpCharDataPos = lpCharData;
|
|
CharData* lpCharDataEnd = lpCharData + nGetRowNum;
|
|
|
|
for(; lpCharDataPos != lpCharDataEnd; ++lpCharDataPos, ++nCount)
|
|
{
|
|
unsigned long dwCID = lpCharDataPos->m_dwCID;
|
|
|
|
CharData resultData;
|
|
memset(&resultData, 0, sizeof(CharData));
|
|
|
|
resultData.m_dwCID = dwCID;
|
|
|
|
// 인벤토리에서 제거
|
|
if(sizeof(unsigned long) <= lpCharDataPos->m_Inventory.dwSize)
|
|
{
|
|
lpCharDataPos->m_Inventory.dwSize -= sizeof(unsigned long);
|
|
}
|
|
|
|
resultData.m_Inventory.dwSize = INVEN::MAX_INVEN_SIZE;
|
|
|
|
RemoveSkills(dwCID, "Inventory", skillBookMap,
|
|
lpCharDataPos->m_Inventory.Data, lpCharDataPos->m_Inventory.dwSize,
|
|
resultData.m_Inventory.Data, resultData.m_Inventory.dwSize);
|
|
|
|
|
|
// 교환창에서 제거
|
|
if(sizeof(unsigned long) <= lpCharDataPos->m_Exchange.dwSize)
|
|
{
|
|
lpCharDataPos->m_Exchange.dwSize -= sizeof(unsigned long);
|
|
}
|
|
|
|
resultData.m_Exchange.dwSize = EXCHANGE::MAX_EXCHANGE_SIZE;
|
|
|
|
RemoveSkills(dwCID, "Exchange", skillBookMap,
|
|
lpCharDataPos->m_Exchange.Data, lpCharDataPos->m_Exchange.dwSize,
|
|
resultData.m_Exchange.Data, resultData.m_Exchange.dwSize);
|
|
|
|
// Extra에서 제거
|
|
if(sizeof(unsigned long) <= lpCharDataPos->m_Extra.dwSize)
|
|
{
|
|
lpCharDataPos->m_Extra.dwSize -= sizeof(unsigned long);
|
|
}
|
|
|
|
resultData.m_Extra.dwSize = EXTRA::MAX_EXTRA_SIZE;
|
|
|
|
RemoveSkills(dwCID, "Extra", skillBookMap,
|
|
lpCharDataPos->m_Extra.Data, lpCharDataPos->m_Extra.dwSize,
|
|
resultData.m_Extra.Data, resultData.m_Extra.dwSize);
|
|
|
|
// 제거 성공했으면, 인벤토리에 스킬북 교환권을 넣어준다.
|
|
C3DItemArrayChecker<6, 6, 3> invenArrayChecker(TakeType::TS_INVEN);
|
|
|
|
unsigned long dwGold =
|
|
InsertSkillBookTicket(dwCID, "Inventory", invenArrayChecker, skillBookMap,
|
|
resultData.m_Inventory.Data, resultData.m_Inventory.dwSize, INVEN::MAX_INVEN_SIZE);
|
|
|
|
// 제거 성공했으면, 다시 DB에 기록
|
|
if(bWriteDB)
|
|
{
|
|
if(0 < dwGold)
|
|
{
|
|
AddCharGold(writeDB, dwGold, dwCID, bDelCharHistory);
|
|
}
|
|
|
|
// 캐릭터 데이터 DB에 기록
|
|
if(bDelCharHistory)
|
|
{
|
|
InsertToCharDelTempInven(writeDB, dwCID, skillBookMap);
|
|
WriteBackCharDelHistoryData(writeDB, *lpCharDataPos, resultData);
|
|
}
|
|
else
|
|
{
|
|
// 임시 인벤토리에 데이터 삽입.
|
|
InsertToTempInven(writeDB, dwCID, skillBookMap);
|
|
WriteBackCharacterData(writeDB, *lpCharDataPos, resultData);
|
|
}
|
|
}
|
|
|
|
if(0 == (nCount % 1000))
|
|
{
|
|
printf(".");
|
|
}
|
|
}
|
|
|
|
memset(lpCharData, 0, sizeof(CharData) * MAX_CHAR_DATA);
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
delete [] lpCharData;
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
bool ProcessStoreData(CDBComponent& readDB, CDBComponent& writeDB, SkillBookMap& skillBookMap, bool bWriteDB)
|
|
{
|
|
|
|
if(!readDB.ExecuteQuery(
|
|
"Select a.UID, a.Store, b.Store from ItemStore1 a join ItemStore2 b on a.UID = b.UID"))
|
|
{
|
|
printf("Store query failed : %s\n", readDB.GetErrorString());
|
|
return false;
|
|
}
|
|
|
|
const int MAX_STORE_DATA_NUM = 1024;
|
|
StoreData* lpStoreData = new StoreData[MAX_STORE_DATA_NUM];
|
|
|
|
if(0 == lpStoreData)
|
|
{
|
|
printf("Store memory allocation failed\n");
|
|
return false;
|
|
}
|
|
|
|
int nCount = 0;
|
|
|
|
int nGetRowNum = 0;
|
|
while(readDB.GetData((void**)lpStoreData, sizeof(StoreData), MAX_STORE_DATA_NUM, &nGetRowNum))
|
|
{
|
|
if(0 == nGetRowNum)
|
|
{
|
|
break;
|
|
}
|
|
|
|
StoreData* lpStoreDataPos = lpStoreData;
|
|
StoreData* lpStoreDataEnd = lpStoreData + nGetRowNum;
|
|
|
|
for(; lpStoreDataPos != lpStoreDataEnd; ++lpStoreDataPos, ++nCount)
|
|
{
|
|
unsigned long dwUID = lpStoreDataPos->m_dwUID;
|
|
|
|
StoreData resultData;
|
|
memset(&resultData, 0, sizeof(StoreData));
|
|
|
|
if(sizeof(unsigned long) <= lpStoreDataPos->m_store1.dwSize) { lpStoreDataPos->m_store1.dwSize -= sizeof(unsigned long); }
|
|
if(sizeof(unsigned long) <= lpStoreDataPos->m_store2.dwSize) { lpStoreDataPos->m_store2.dwSize -= sizeof(unsigned long); }
|
|
|
|
resultData.m_store1.dwSize = STORE::MAX_STORE_SIZE;
|
|
resultData.m_store2.dwSize = STORE::MAX_STORE_SIZE;
|
|
|
|
// 창고 1 스킬북 읽어서 제거
|
|
RemoveSkills(dwUID, "Store1", skillBookMap,
|
|
lpStoreDataPos->m_store1.Data, lpStoreDataPos->m_store1.dwSize,
|
|
resultData.m_store1.Data, resultData.m_store1.dwSize);
|
|
|
|
// 창고 2 스킬북 읽어서 제거
|
|
RemoveSkills(dwUID, "Store2", skillBookMap,
|
|
lpStoreDataPos->m_store2.Data, lpStoreDataPos->m_store2.dwSize,
|
|
resultData.m_store2.Data, resultData.m_store2.dwSize);
|
|
|
|
// 제거 성공했으면, 창고에 스킬북 교환권을 넣어준다.
|
|
C3DItemArrayChecker<8, 12, 4> storeArrayChecker(TakeType::TS_DEPOSIT);
|
|
|
|
unsigned long dwStoreGold =
|
|
InsertSkillBookTicket(dwUID, "store1", storeArrayChecker, skillBookMap,
|
|
resultData.m_store1.Data, resultData.m_store1.dwSize, STORE::MAX_STORE_SIZE);
|
|
|
|
// 창고 1/2탭에 아이템이 꽉차서 못넣은 경우가 생길 수 있다. 이때는 창고 3/4탭에 넣는다.
|
|
InsertSkillBookTicket(dwUID, "store2", storeArrayChecker, skillBookMap,
|
|
resultData.m_store2.Data, resultData.m_store2.dwSize, STORE::MAX_STORE_SIZE);
|
|
|
|
// 제거 성공했으면, 다시 DB에 기록
|
|
if(bWriteDB)
|
|
{
|
|
if(0 < dwStoreGold)
|
|
{
|
|
AddStoreGold(writeDB, dwStoreGold, dwUID);
|
|
}
|
|
|
|
// 창고 데이터 DB에 기록
|
|
WriteBackStoreData(writeDB, *lpStoreDataPos, resultData);
|
|
}
|
|
|
|
if(0 == (nCount % 1000))
|
|
{
|
|
printf(".");
|
|
}
|
|
}
|
|
|
|
memset(lpStoreData, 0, sizeof(StoreData) * MAX_STORE_DATA_NUM);
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
delete [] lpStoreData;
|
|
return true;
|
|
}
|
|
|
|
bool RemoveSkills(unsigned long dwKey, const char* szContainerName,
|
|
SkillBookMap& skillBookMap,
|
|
const char* szInputData, unsigned long dwInputDataSize,
|
|
char* szResultData, unsigned long& dwResultDataSize)
|
|
{
|
|
if(dwResultDataSize < dwInputDataSize)
|
|
{
|
|
ERRLOG4(g_Log, "Key:%10u / ResultData:%10u / InputData:%10u / %s : ResultBuffer is too small",
|
|
dwKey, dwResultDataSize, dwInputDataSize, szContainerName);
|
|
|
|
return false;
|
|
}
|
|
|
|
const char* szPos = szInputData;
|
|
const char* szEnd = szInputData + dwInputDataSize;
|
|
|
|
char* szResultPos = szResultData;
|
|
|
|
for(; szPos < szEnd; )
|
|
{
|
|
const Item::ItemData* lpItemData = reinterpret_cast<const Item::ItemData*>(szPos);
|
|
|
|
const Item::ItemInfo* lpItemInfo =
|
|
Item::CItemMgr::GetInstance().GetItemInfo(lpItemData->m_usProtoTypeID);
|
|
|
|
if(0 == lpItemInfo)
|
|
{
|
|
ERRLOG4(g_Log, "Key:%10u / Serial:0x%016I64X / ProtoType:%6d / %s : Script has not this item",
|
|
dwKey, lpItemData->m_dwUID, lpItemData->m_usProtoTypeID, szContainerName);
|
|
}
|
|
else if(Item::ItemType::SKILLBOOK == lpItemInfo->m_DetailData.m_cItemType)
|
|
{
|
|
// 교환권 배열에 카운팅하고, 아이템을 복사하지 않는다.
|
|
SkillBookMap::iterator pos = skillBookMap.find(dwKey);
|
|
SkillBookMap::iterator end = skillBookMap.end();
|
|
|
|
if(pos != end)
|
|
{
|
|
pos->second.m_dwSkillBookNum[lpItemInfo->m_UseItemInfo.m_usSkill_LockCount] +=
|
|
lpItemData->m_cNumOrDurability;
|
|
}
|
|
else
|
|
{
|
|
SkillBookData bookData;
|
|
memset(&bookData, 0, sizeof(SkillBookData));
|
|
|
|
bookData.m_dwSkillBookNum[lpItemInfo->m_UseItemInfo.m_usSkill_LockCount] +=
|
|
lpItemData->m_cNumOrDurability;
|
|
|
|
skillBookMap.insert(std::make_pair(dwKey, bookData));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// 그냥 아이템을 복사한다.
|
|
memcpy(szResultPos, lpItemData, lpItemData->m_cItemSize);
|
|
szResultPos += lpItemData->m_cItemSize;
|
|
}
|
|
|
|
szPos += lpItemData->m_cItemSize;
|
|
}
|
|
|
|
dwResultDataSize = static_cast<unsigned long>(szResultPos - szResultData);
|
|
return true;
|
|
}
|
|
|
|
|
|
unsigned long InsertSkillBookTicket(unsigned long dwKey, const char* szContainerName, C3DArrayChecker& arrayChecker,
|
|
SkillBookMap& skillBookMap,
|
|
char* szData, unsigned long& dwDataSize_InOut, unsigned long dwMaxDataSize)
|
|
{
|
|
unsigned long dwGold = 0;
|
|
|
|
if(dwMaxDataSize < dwDataSize_InOut + sizeof(Item::ItemData) * 2)
|
|
{
|
|
ERRLOG2(g_Log, "Key:%10u / %s : give skillbook failed - data overflow", dwKey, szContainerName);
|
|
return 0;
|
|
}
|
|
|
|
SkillBookMap::iterator pos = skillBookMap.find(dwKey);
|
|
SkillBookMap::iterator end = skillBookMap.end();
|
|
|
|
if(pos != end)
|
|
{
|
|
SkillBookData& bookData = pos->second;
|
|
|
|
dwGold = bookData.m_dwSkillBookNum[0] * 1000 + bookData.m_dwSkillBookNum[1] * 10000;
|
|
|
|
bookData.m_dwSkillBookNum[0] = 0;
|
|
bookData.m_dwSkillBookNum[1] = 0;
|
|
|
|
unsigned long dw3rdBookNum = bookData.m_dwSkillBookNum[2];
|
|
unsigned long dw4thBookNum = bookData.m_dwSkillBookNum[3];
|
|
|
|
if(0 < dw3rdBookNum || 0 < dw4thBookNum)
|
|
{
|
|
const char* szDataPos = szData;
|
|
const char* szDataEnd = szData + dwDataSize_InOut;
|
|
|
|
for(; szDataPos < szDataEnd; )
|
|
{
|
|
const Item::ItemData* lpItemData = reinterpret_cast<const Item::ItemData*>(szDataPos);
|
|
|
|
const Item::ItemInfo* lpItemInfo =
|
|
Item::CItemMgr::GetInstance().GetItemInfo(lpItemData->m_usProtoTypeID);
|
|
|
|
if(0 != lpItemInfo)
|
|
{
|
|
arrayChecker.Set(lpItemData->m_ItemPos,
|
|
lpItemInfo->m_DetailData.m_cXSize, lpItemInfo->m_DetailData.m_cYSize);
|
|
}
|
|
else
|
|
{
|
|
ERRLOG4(g_Log, "Key:%10u / Serial:0x%016I64X / ProtoType:%6d / %s : Script has not this item",
|
|
dwKey, lpItemData->m_dwUID, lpItemData->m_usProtoTypeID, szContainerName);
|
|
}
|
|
|
|
szDataPos += lpItemData->m_cItemSize;
|
|
}
|
|
|
|
if(0 < dw3rdBookNum)
|
|
{
|
|
Item::ItemData thirdSkillBook;
|
|
memset(&thirdSkillBook, 0, sizeof(Item::ItemData));
|
|
|
|
thirdSkillBook.m_dwUID = Item::CItemFactory::GetInstance().GetItemUID() + 1;
|
|
thirdSkillBook.m_usProtoTypeID = 3401;
|
|
thirdSkillBook.m_cItemSize = sizeof(Item::ItemData);
|
|
thirdSkillBook.m_cNumOrDurability = static_cast<unsigned char>(dw3rdBookNum);
|
|
|
|
if(arrayChecker.FindEmptyPos(thirdSkillBook.m_ItemPos, 1, 1))
|
|
{
|
|
Item::CItemFactory::GetInstance().SetItemUID(thirdSkillBook.m_dwUID);
|
|
memcpy(szData + dwDataSize_InOut, &thirdSkillBook, sizeof(Item::ItemData));
|
|
dwDataSize_InOut += sizeof(Item::ItemData);
|
|
|
|
arrayChecker.Set(thirdSkillBook.m_ItemPos, 1, 1);
|
|
|
|
bookData.m_dwSkillBookNum[2] = 0;
|
|
}
|
|
else
|
|
{
|
|
DETLOG3(g_Log, "Key:%10u / 3rdBookNum:%10u / %s : 빈 공간이 없어서 3단계 스킬북 교환권을 임시 인벤에 넣습니다.",
|
|
dwKey, dw3rdBookNum, szContainerName);
|
|
}
|
|
}
|
|
|
|
if(0 < dw4thBookNum)
|
|
{
|
|
Item::ItemData forthSkillBook;
|
|
memset(&forthSkillBook, 0, sizeof(Item::ItemData));
|
|
|
|
forthSkillBook.m_dwUID = Item::CItemFactory::GetInstance().GetItemUID() + 1;
|
|
forthSkillBook.m_usProtoTypeID = 3402;
|
|
forthSkillBook.m_cItemSize = sizeof(Item::ItemData);
|
|
forthSkillBook.m_cNumOrDurability = static_cast<unsigned char>(dw4thBookNum);
|
|
|
|
if(arrayChecker.FindEmptyPos(forthSkillBook.m_ItemPos, 1, 1))
|
|
{
|
|
Item::CItemFactory::GetInstance().SetItemUID(forthSkillBook.m_dwUID);
|
|
memcpy(szData + dwDataSize_InOut, &forthSkillBook, sizeof(Item::ItemData));
|
|
dwDataSize_InOut += sizeof(Item::ItemData);
|
|
|
|
arrayChecker.Set(forthSkillBook.m_ItemPos, 1, 1);
|
|
|
|
bookData.m_dwSkillBookNum[3] = 0;
|
|
}
|
|
else
|
|
{
|
|
DETLOG3(g_Log, "Key:%10u / 4thBookNum:%10u / %s : 빈 공간이 없어서 4단계 스킬북 교환권을 임시 인벤에 넣습니다.",
|
|
dwKey, dw4thBookNum, szContainerName);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(0 == bookData.m_dwSkillBookNum[0] && 0 == bookData.m_dwSkillBookNum[1] &&
|
|
0 == bookData.m_dwSkillBookNum[2] && 0 == bookData.m_dwSkillBookNum[3])
|
|
{
|
|
// 제대로 다 지급했으면 맵에서 지운다.
|
|
skillBookMap.erase(pos);
|
|
}
|
|
}
|
|
|
|
return dwGold;
|
|
}
|
|
|
|
|
|
|
|
bool InsertToTempInven(CDBComponent& writeDB, unsigned long dwCID, SkillBookMap& cidBookMap)
|
|
{
|
|
SkillBookMap::iterator pos = cidBookMap.find(dwCID);
|
|
SkillBookMap::iterator end = cidBookMap.end();
|
|
|
|
if(pos != end)
|
|
{
|
|
// 아직 스킬북 지급이 끝나지 않았다. 임시 인벤에 넣어준다.
|
|
SkillBookData& bookData = pos->second;
|
|
|
|
unsigned long dw3rdBookNum = bookData.m_dwSkillBookNum[2];
|
|
unsigned long dw4thBookNum = bookData.m_dwSkillBookNum[3];
|
|
|
|
TEMPINVEN tempInven;
|
|
memset(&tempInven, 0, sizeof(TEMPINVEN));
|
|
|
|
if(!DBComponent::GameDB::GetTempInven(writeDB, dwCID, &tempInven))
|
|
{
|
|
printf("Read temp inventory faild : CID:%10u / %s\n", dwCID, writeDB.GetErrorString());
|
|
ERRLOG2(g_Log, "CID:%10u / Read temp inventory failed : %s", dwCID, writeDB.GetErrorString());
|
|
return false;
|
|
}
|
|
|
|
const char* szDataPos = tempInven.Data;
|
|
const char* szDataEnd = tempInven.Data + tempInven.dwSize;
|
|
|
|
int nCount = 0;
|
|
|
|
for(; szDataPos < szDataEnd; )
|
|
{
|
|
const Item::ItemData* lpItemData = reinterpret_cast<const Item::ItemData*>(szDataPos);
|
|
|
|
szDataPos += lpItemData->m_cItemSize;
|
|
++nCount;
|
|
}
|
|
|
|
if(0 < dw3rdBookNum)
|
|
{
|
|
Item::ItemData thirdSkillBook;
|
|
memset(&thirdSkillBook, 0, sizeof(Item::ItemData));
|
|
|
|
thirdSkillBook.m_dwUID = Item::CItemFactory::GetInstance().GetItemUID() + 1;
|
|
thirdSkillBook.m_usProtoTypeID = 3401;
|
|
thirdSkillBook.m_cItemSize = sizeof(Item::ItemData);
|
|
thirdSkillBook.m_cNumOrDurability = static_cast<unsigned char>(dw3rdBookNum);
|
|
|
|
thirdSkillBook.m_ItemPos = Item::ItemPos(TakeType::TS_TEMPINVEN, nCount);
|
|
++nCount;
|
|
|
|
if(tempInven.dwSize + sizeof(Item::ItemData) < TEMPINVEN::MAX_TEMPINVEN_SIZE)
|
|
{
|
|
Item::CItemFactory::GetInstance().SetItemUID(thirdSkillBook.m_dwUID);
|
|
memcpy(tempInven.Data + tempInven.dwSize, &thirdSkillBook, sizeof(Item::ItemData));
|
|
tempInven.dwSize += sizeof(Item::ItemData);
|
|
|
|
DETLOG2(g_Log, "CID:%10u / 3rdBookNum:%10u / 3단계 스킬북 교환권을 임시 인벤에 넣습니다.", dwCID, dw3rdBookNum);
|
|
}
|
|
else
|
|
{
|
|
ERRLOG2(g_Log, "CID:%10u / Num:%d / Insert 3rdBook to tempinven failed - not enough space", dwCID, dw3rdBookNum);
|
|
}
|
|
}
|
|
|
|
if(0 < dw4thBookNum)
|
|
{
|
|
Item::ItemData forthSkillBook;
|
|
memset(&forthSkillBook, 0, sizeof(Item::ItemData));
|
|
|
|
forthSkillBook.m_dwUID = Item::CItemFactory::GetInstance().GetItemUID() + 1;
|
|
forthSkillBook.m_usProtoTypeID = 3402;
|
|
forthSkillBook.m_cItemSize = sizeof(Item::ItemData);
|
|
forthSkillBook.m_cNumOrDurability = static_cast<unsigned char>(dw4thBookNum);
|
|
|
|
forthSkillBook.m_ItemPos = Item::ItemPos(TakeType::TS_TEMPINVEN, nCount);
|
|
++nCount;
|
|
|
|
if(tempInven.dwSize + sizeof(Item::ItemData) < TEMPINVEN::MAX_TEMPINVEN_SIZE)
|
|
{
|
|
Item::CItemFactory::GetInstance().SetItemUID(forthSkillBook.m_dwUID);
|
|
memcpy(tempInven.Data + tempInven.dwSize, &forthSkillBook, sizeof(Item::ItemData));
|
|
tempInven.dwSize += sizeof(Item::ItemData);
|
|
|
|
DETLOG2(g_Log, "CID:%10u / 4thBookNum:%10u / 4단계 스킬북 교환권을 임시 인벤에 넣습니다.", dwCID, dw4thBookNum);
|
|
}
|
|
else
|
|
{
|
|
ERRLOG2(g_Log, "CID:%10u / Num:%d / Insert 3rdBook to tempinven failed - not enough space",
|
|
dwCID, dw3rdBookNum);
|
|
}
|
|
}
|
|
|
|
if(!DBComponent::GameDB::UpdateTempInven(writeDB, dwCID, &tempInven))
|
|
{
|
|
printf("Write temp inventory faild : CID:%10u / %s\n", dwCID, writeDB.GetErrorString());
|
|
ERRLOG2(g_Log, "CID:%10u / Write temp inventory failed : %s", dwCID, writeDB.GetErrorString());
|
|
return false;
|
|
}
|
|
|
|
cidBookMap.erase(pos);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool InsertToCharDelTempInven(CDBComponent& writeDB, unsigned long dwCID, SkillBookMap& cidBookMap)
|
|
{
|
|
SkillBookMap::iterator pos = cidBookMap.find(dwCID);
|
|
SkillBookMap::iterator end = cidBookMap.end();
|
|
|
|
if(pos != end)
|
|
{
|
|
// 아직 스킬북 지급이 끝나지 않았다. 임시 인벤에 넣어준다.
|
|
SkillBookData& bookData = pos->second;
|
|
|
|
unsigned long dw3rdBookNum = bookData.m_dwSkillBookNum[2];
|
|
unsigned long dw4thBookNum = bookData.m_dwSkillBookNum[3];
|
|
|
|
TEMPINVEN tempInven;
|
|
memset(&tempInven, 0, sizeof(TEMPINVEN));
|
|
|
|
_snprintf(writeDB.GetQueryBuffer(), CDBComponent::MAX_QUERY_LENGTH,
|
|
"SELECT TempInven FROM CharDelHistory..DelCharItemEx WHERE UID = %d", dwCID);
|
|
|
|
if(!writeDB.ExecuteQueryGetData(writeDB.GetQueryBuffer(), &tempInven))
|
|
{
|
|
printf("Read temp inventory faild : CID:%10u / %s\n", dwCID, writeDB.GetErrorString());
|
|
ERRLOG2(g_Log, "CID:%10u / Read temp inventory failed : %s", dwCID, writeDB.GetErrorString());
|
|
return false;
|
|
}
|
|
|
|
if(sizeof(unsigned long) <= tempInven.dwSize)
|
|
{
|
|
tempInven.dwSize -= sizeof(unsigned long);
|
|
}
|
|
|
|
const char* szDataPos = tempInven.Data;
|
|
const char* szDataEnd = tempInven.Data + tempInven.dwSize;
|
|
|
|
int nCount = 0;
|
|
|
|
for(; szDataPos < szDataEnd; )
|
|
{
|
|
const Item::ItemData* lpItemData = reinterpret_cast<const Item::ItemData*>(szDataPos);
|
|
|
|
szDataPos += lpItemData->m_cItemSize;
|
|
++nCount;
|
|
}
|
|
|
|
if(0 < dw3rdBookNum)
|
|
{
|
|
Item::ItemData thirdSkillBook;
|
|
memset(&thirdSkillBook, 0, sizeof(Item::ItemData));
|
|
|
|
thirdSkillBook.m_dwUID = Item::CItemFactory::GetInstance().GetItemUID() + 1;
|
|
thirdSkillBook.m_usProtoTypeID = 3401;
|
|
thirdSkillBook.m_cItemSize = sizeof(Item::ItemData);
|
|
thirdSkillBook.m_cNumOrDurability = static_cast<unsigned char>(dw3rdBookNum);
|
|
|
|
thirdSkillBook.m_ItemPos = Item::ItemPos(TakeType::TS_TEMPINVEN, nCount);
|
|
++nCount;
|
|
|
|
if(tempInven.dwSize + sizeof(Item::ItemData) < TEMPINVEN::MAX_TEMPINVEN_SIZE)
|
|
{
|
|
Item::CItemFactory::GetInstance().SetItemUID(thirdSkillBook.m_dwUID);
|
|
memcpy(tempInven.Data + tempInven.dwSize, &thirdSkillBook, sizeof(Item::ItemData));
|
|
tempInven.dwSize += sizeof(Item::ItemData);
|
|
|
|
DETLOG2(g_Log, "CID:%10u / 3rdBookNum:%10u / 3단계 스킬북 교환권을 임시 인벤에 넣습니다.", dwCID, dw3rdBookNum);
|
|
}
|
|
else
|
|
{
|
|
ERRLOG2(g_Log, "CID:%10u / Num:%d / Insert 3rdBook to tempinven failed - not enough space", dwCID, dw3rdBookNum);
|
|
}
|
|
}
|
|
|
|
if(0 < dw4thBookNum)
|
|
{
|
|
Item::ItemData forthSkillBook;
|
|
memset(&forthSkillBook, 0, sizeof(Item::ItemData));
|
|
|
|
forthSkillBook.m_dwUID = Item::CItemFactory::GetInstance().GetItemUID() + 1;
|
|
forthSkillBook.m_usProtoTypeID = 3402;
|
|
forthSkillBook.m_cItemSize = sizeof(Item::ItemData);
|
|
forthSkillBook.m_cNumOrDurability = static_cast<unsigned char>(dw4thBookNum);
|
|
|
|
forthSkillBook.m_ItemPos = Item::ItemPos(TakeType::TS_TEMPINVEN, nCount);
|
|
++nCount;
|
|
|
|
if(tempInven.dwSize + sizeof(Item::ItemData) < TEMPINVEN::MAX_TEMPINVEN_SIZE)
|
|
{
|
|
Item::CItemFactory::GetInstance().SetItemUID(forthSkillBook.m_dwUID);
|
|
memcpy(tempInven.Data + tempInven.dwSize, &forthSkillBook, sizeof(Item::ItemData));
|
|
tempInven.dwSize += sizeof(Item::ItemData);
|
|
|
|
DETLOG2(g_Log, "CID:%10u / 4thBookNum:%10u / 4단계 스킬북 교환권을 임시 인벤에 넣습니다.", dwCID, dw4thBookNum);
|
|
}
|
|
else
|
|
{
|
|
ERRLOG2(g_Log, "CID:%10u / Num:%d / Insert 3rdBook to tempinven failed - not enough space",
|
|
dwCID, dw3rdBookNum);
|
|
}
|
|
}
|
|
|
|
_snprintf(writeDB.GetQueryBuffer(), CDBComponent::MAX_QUERY_LENGTH,
|
|
"SELECT TempInven FROM CharDelHistory..DelCharItemEx WHERE UID = %d", dwCID);
|
|
|
|
tempInven.dwSize += sizeof(unsigned long);
|
|
if (!writeDB.ExecuteQuery(writeDB.GetQueryBuffer(), OleDB::Rowset_Update) ||
|
|
!writeDB.SetBinaryData(1, (OleDB::LPSET_BINARY)&tempInven))
|
|
{
|
|
printf("Write temp inventory faild : CID:%10u / %s\n", dwCID, writeDB.GetErrorString());
|
|
ERRLOG2(g_Log, "CID:%10u / Write temp inventory failed : %s", dwCID, writeDB.GetErrorString());
|
|
return false;
|
|
}
|
|
|
|
cidBookMap.erase(pos);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool ReadSkillData(CDBComponent& readDB, SkillBookMap& cidSkillBookMap, bool bReadCharDelHistory)
|
|
{
|
|
const int MAX_SKILL_DATA = 1024;
|
|
SkillData* lpSkillData = new SkillData[MAX_SKILL_DATA];
|
|
|
|
if(0 == lpSkillData)
|
|
{
|
|
printf("ReadSkillData : Memory allocation failed\n");
|
|
return false;
|
|
}
|
|
|
|
const char* szQuery = bReadCharDelHistory ?
|
|
"select UID, Skill From CharDelHistory..DelCharSkill" :
|
|
"select UID, SKill From CharSkill";
|
|
|
|
if(!readDB.ExecuteQuery(szQuery))
|
|
{
|
|
printf("ReadSkillData : Query failed : %s : %s\n", szQuery, readDB.GetErrorString());
|
|
return false;
|
|
}
|
|
|
|
int nCount = 0;
|
|
int nGetRowNum = 0;
|
|
|
|
memset(lpSkillData, 0, sizeof(SkillData) * MAX_SKILL_DATA);
|
|
while(readDB.GetData((void**)lpSkillData, sizeof(SkillData), MAX_SKILL_DATA, &nGetRowNum))
|
|
{
|
|
if(0 == nGetRowNum)
|
|
{
|
|
break;
|
|
}
|
|
|
|
SkillData* lpSkillPos = lpSkillData;
|
|
SkillData* lpSkillEnd = lpSkillData + nGetRowNum;
|
|
|
|
for(; lpSkillPos != lpSkillEnd; ++lpSkillPos, ++nCount)
|
|
{
|
|
unsigned long dwCID = lpSkillPos->m_dwCID;
|
|
SKILL& skill = lpSkillPos->m_skill;
|
|
|
|
SkillBookData bookData;
|
|
memset(&bookData, 0, sizeof(SkillBookData));
|
|
|
|
for(int nSkillCount = 0; nSkillCount < skill.wSlotNum; ++nSkillCount)
|
|
{
|
|
SKILLSLOT& skillSlot = skill.SSlot[nSkillCount];
|
|
|
|
if(skillSlot.SKILLINFO.cLockCount < CSkillMgr::MAX_SKILL_LOCKCOUNT &&
|
|
skillSlot.SKILLINFO.cSkillLevel <= CSkillMgr::MAX_SKILL_LEVEL &&
|
|
0 != CSkillMgr::GetInstance().GetSkillProtoType(skillSlot.SKILLINFO.wSkill))
|
|
{
|
|
// 스킬의 종류에 관계 없이 지급
|
|
for(int nLockCount = 0; nLockCount < skillSlot.SKILLINFO.cLockCount; ++nLockCount)
|
|
{
|
|
bookData.m_dwSkillBookNum[nLockCount] += CSkillMgr::MAX_SKILL_LEVEL;
|
|
}
|
|
|
|
bookData.m_dwSkillBookNum[skillSlot.SKILLINFO.cLockCount] +=
|
|
skillSlot.SKILLINFO.cSkillLevel;
|
|
}
|
|
else
|
|
{
|
|
ERRLOG4(g_Log, "CID:%10u / Skill_ID:0x%04X / LockCount:%6d / Level:%6d / 알 수 없는 스킬입니다",
|
|
dwCID, skillSlot.SKILLINFO.wSkill, skillSlot.SKILLINFO.cLockCount, skillSlot.SKILLINFO.cSkillLevel);
|
|
}
|
|
}
|
|
|
|
cidSkillBookMap.insert(std::make_pair(dwCID, bookData));
|
|
|
|
if(0 == (nCount % 1000))
|
|
{
|
|
printf(".");
|
|
}
|
|
}
|
|
|
|
memset(lpSkillData, 0, sizeof(SkillData) * MAX_SKILL_DATA);
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
delete [] lpSkillData;
|
|
return true;
|
|
}
|
|
|
|
|
|
// 변경된 점을 DB에 기록한다.
|
|
void WriteBackCharacterData(CDBComponent& writeDB, CharData& originalData, CharData& newData)
|
|
{
|
|
unsigned long dwCID = originalData.m_dwCID;
|
|
|
|
// 인벤토리 기록
|
|
if((newData.m_Inventory.dwSize != originalData.m_Inventory.dwSize ||
|
|
0 != memcmp(newData.m_Inventory.Data, originalData.m_Inventory.Data, newData.m_Inventory.dwSize)) &&
|
|
!DBComponent::GameDB::UpdateInven(writeDB, dwCID, &newData.m_Inventory))
|
|
{
|
|
ERRLOG1(g_Log, "CID:%10u / 인벤토리 기록에 실패했습니다.", dwCID);
|
|
}
|
|
|
|
// 교환창 기록
|
|
if((newData.m_Exchange.dwSize != originalData.m_Exchange.dwSize ||
|
|
0 != memcmp(newData.m_Exchange.Data, originalData.m_Exchange.Data, newData.m_Exchange.dwSize)) &&
|
|
!DBComponent::GameDB::UpdateExchange(writeDB, dwCID, &newData.m_Exchange))
|
|
{
|
|
ERRLOG1(g_Log, "CID:%10u / Exchange 기록에 실패했습니다.", dwCID);
|
|
}
|
|
|
|
// Extra 기록
|
|
if((newData.m_Extra.dwSize != originalData.m_Extra.dwSize ||
|
|
0 != memcmp(newData.m_Extra.Data, originalData.m_Extra.Data, newData.m_Extra.dwSize)) &&
|
|
!DBComponent::GameDB::UpdateExtra(writeDB, dwCID, &newData.m_Extra))
|
|
{
|
|
ERRLOG1(g_Log, "CID:%10u / Extra 기록에 실패했습니다.", dwCID);
|
|
}
|
|
}
|
|
|
|
void WriteBackCharDelHistoryData(CDBComponent& writeDB, CharData& originalData, CharData& newData)
|
|
{
|
|
unsigned long dwCID = originalData.m_dwCID;
|
|
|
|
// 인벤토리 기록
|
|
if((newData.m_Inventory.dwSize != originalData.m_Inventory.dwSize ||
|
|
0 != memcmp(newData.m_Inventory.Data, originalData.m_Inventory.Data, newData.m_Inventory.dwSize)) &&
|
|
!DBComponent::GameDB::UpdateDelHistoryInven(writeDB, dwCID, &newData.m_Inventory))
|
|
{
|
|
ERRLOG1(g_Log, "CID:%10u / DelHistory 인벤토리 기록에 실패했습니다.", dwCID);
|
|
}
|
|
|
|
// 교환창 기록
|
|
if((newData.m_Exchange.dwSize != originalData.m_Exchange.dwSize ||
|
|
0 != memcmp(newData.m_Exchange.Data, originalData.m_Exchange.Data, newData.m_Exchange.dwSize)) &&
|
|
!DBComponent::GameDB::UpdateDelHistoryExchange(writeDB, dwCID, &newData.m_Exchange))
|
|
{
|
|
ERRLOG1(g_Log, "CID:%10u / DelHistory Exchange 기록에 실패했습니다.", dwCID);
|
|
}
|
|
|
|
// Extra 기록
|
|
if((newData.m_Extra.dwSize != originalData.m_Extra.dwSize ||
|
|
0 != memcmp(newData.m_Extra.Data, originalData.m_Extra.Data, newData.m_Extra.dwSize)) &&
|
|
!DBComponent::GameDB::UpdateDelHistoryExtra(writeDB, dwCID, &newData.m_Extra))
|
|
{
|
|
ERRLOG1(g_Log, "CID:%10u / DelHistory Extra 기록에 실패했습니다.", dwCID);
|
|
}
|
|
}
|
|
|
|
void WriteBackStoreData(CDBComponent& writeDB, StoreData& originalData, StoreData& newData)
|
|
{
|
|
unsigned long dwUID = originalData.m_dwUID;
|
|
|
|
if((newData.m_store1.dwSize != originalData.m_store1.dwSize ||
|
|
0 != memcmp(newData.m_store1.Data, originalData.m_store1.Data, newData.m_store1.dwSize)) &&
|
|
!DBComponent::GameDB::UpdateItemStore1(writeDB, dwUID, &newData.m_store1))
|
|
{
|
|
ERRLOG1(g_Log, "UID:%10u / 창고 1 기록에 실패했습니다.", dwUID);
|
|
}
|
|
|
|
if((newData.m_store2.dwSize != originalData.m_store2.dwSize ||
|
|
0 != memcmp(newData.m_store2.Data, originalData.m_store2.Data, newData.m_store2.dwSize)) &&
|
|
!DBComponent::GameDB::UpdateItemStore2(writeDB, dwUID, &newData.m_store2))
|
|
{
|
|
ERRLOG1(g_Log, "UID:%10u / 창고 2 기록에 실패했습니다.", dwUID);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void WriteSkillClear(CDBComponent& writeDB, bool bDelCharHistory)
|
|
{
|
|
const int MAX_QUERY = 4;
|
|
|
|
const char* szQuery[MAX_QUERY] =
|
|
{
|
|
"Update CharSkill_1 set Skill = NULL",
|
|
"Update CharSkill_2 set Skill = NULL",
|
|
"Update CharSkill_3 set Skill = NULL",
|
|
"Update CharSkill_4 set Skill = NULL"
|
|
};
|
|
|
|
const char* szQuickSlotQuery = "Update CharItem set Quick = NULL";
|
|
|
|
if(bDelCharHistory)
|
|
{
|
|
szQuery[0] = "Update CharDelHistory..DelCharSkill_1 set Skill = NULL";
|
|
szQuery[1] = "Update CharDelHistory..DelCharSkill_2 set Skill = NULL";
|
|
szQuery[2] = "Update CharDelHistory..DelCharSkill_3 set Skill = NULL";
|
|
szQuery[3] = "Update CharDelHistory..DelCharSkill_4 set Skill = NULL";
|
|
|
|
szQuickSlotQuery = "Update CharDelHistory..DelCharItem set Quick = NULL";
|
|
}
|
|
|
|
for(int nCount = 0; nCount < MAX_QUERY; ++nCount)
|
|
{
|
|
if(!writeDB.ExecuteQuery(szQuery[nCount]))
|
|
{
|
|
printf("Query failed : %s : %s\n", szQuery[nCount], writeDB.GetErrorString());
|
|
ERRLOG2(g_Log, "Query failed : %s : %s\n", szQuery[nCount], writeDB.GetErrorString());
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!writeDB.ExecuteQuery(szQuickSlotQuery))
|
|
{
|
|
printf("Query failed : %s : %s\n", szQuickSlotQuery, writeDB.GetErrorString());
|
|
ERRLOG2(g_Log, "Query failed : %s : %s\n", szQuickSlotQuery, writeDB.GetErrorString());
|
|
}
|
|
}
|
|
|
|
void AddCharGold(CDBComponent& writeDB, unsigned long dwGold, unsigned long dwCID, bool bCharDelHistory)
|
|
{
|
|
unsigned long dwOldGold = 0;
|
|
unsigned long dwNewGold = 0;
|
|
|
|
if(bCharDelHistory)
|
|
{
|
|
unsigned long dwIndex = (dwCID % 4) + 1;
|
|
|
|
const int MAX_QUERY_LEN = 1024;
|
|
char szGetQuery[MAX_QUERY_LEN];
|
|
char szUpdateQuery[MAX_QUERY_LEN];
|
|
|
|
_snprintf(szGetQuery, MAX_QUERY_LEN, "select Gold from CharDelHistory..DelCharInfo_%u where UID = %d",
|
|
dwIndex, dwCID);
|
|
|
|
if(!writeDB.ExecuteQueryGetData(szGetQuery, &dwOldGold))
|
|
{
|
|
ERRLOG2(g_Log, "CID:%10u / Gold:%10u / CharDelHistory : 돈을 넣어주기 위해 캐릭터 데이터 읽어오기 실패", dwCID, dwGold);
|
|
}
|
|
else
|
|
{
|
|
if(dwOldGold < ULONG_MAX - dwGold)
|
|
{
|
|
dwNewGold = dwOldGold + dwGold;
|
|
}
|
|
else
|
|
{
|
|
dwNewGold = ULONG_MAX;
|
|
}
|
|
|
|
_snprintf(szUpdateQuery, MAX_QUERY_LEN, "UPDATE CharDelHistory..DelCharInfo_%u SET Gold = %d where UID = %d",
|
|
dwIndex, dwNewGold, dwCID);
|
|
|
|
if(!writeDB.ExecuteQuery(szUpdateQuery))
|
|
{
|
|
dwNewGold = 0;
|
|
ERRLOG2(g_Log, "CID:%10u / Gold:%10u / 돈을 넣어주기 위해 캐릭터 데이터 저장하기 실패", dwCID, dwGold);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const int MAX_EQUIP_VIEW = 15;
|
|
|
|
CHAR_INFOST charInfoST;
|
|
unsigned short usEquipView[MAX_EQUIP_VIEW];
|
|
|
|
memset(&charInfoST, 0, sizeof(CHAR_INFOST));
|
|
memset(usEquipView, 0, sizeof(unsigned short) * MAX_EQUIP_VIEW);
|
|
|
|
if(!DBComponent::GameDB::GetCharInfo(writeDB, dwCID,
|
|
&charInfoST, usEquipView, MAX_EQUIP_VIEW))
|
|
{
|
|
ERRLOG2(g_Log, "CID:%10u / Gold:%10u / 돈을 넣어주기 위해 캐릭터 데이터 읽어오기 실패", dwCID, dwGold);
|
|
}
|
|
else
|
|
{
|
|
dwOldGold = charInfoST.Gold;
|
|
|
|
if(charInfoST.Gold < ULONG_MAX - dwGold)
|
|
{
|
|
charInfoST.Gold += dwGold;
|
|
}
|
|
else
|
|
{
|
|
charInfoST.Gold = ULONG_MAX;
|
|
}
|
|
|
|
if(!DBComponent::GameDB::UpdateCharInfo(writeDB, dwCID,
|
|
&charInfoST, usEquipView, MAX_EQUIP_VIEW))
|
|
{
|
|
ERRLOG2(g_Log, "CID:%10u / Gold:%10u / 돈을 넣어주기 위해 캐릭터 데이터 저장하기 실패", dwCID, dwGold);
|
|
}
|
|
else
|
|
{
|
|
dwNewGold = charInfoST.Gold;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(0 != dwNewGold && 0 != dwGold)
|
|
{
|
|
DETLOG4(g_GoldLog, "CID:%10u / OldGold:%10u / NewGold:%10u / GetGold:%10u / 캐릭터에 돈을 지급했습니다.",
|
|
dwCID, dwOldGold, dwNewGold, dwGold);
|
|
}
|
|
}
|
|
|
|
|
|
void AddStoreGold(CDBComponent& writeDB, unsigned long dwGold, unsigned long dwUID)
|
|
{
|
|
STORE_INFO storeInfo;
|
|
memset(&storeInfo, 0, sizeof(STORE_INFO));
|
|
|
|
unsigned long dwOldGold = 0;
|
|
unsigned long dwNewGold = 0;
|
|
|
|
if(!DBComponent::GameDB::GetItemStoreInfo(writeDB, dwUID, &storeInfo))
|
|
{
|
|
ERRLOG2(g_Log, "UID:%10u / Gold:%10u / 돈 더하기 실패 : 창고 정보 읽기 실패", dwUID, dwGold);
|
|
}
|
|
else
|
|
{
|
|
dwOldGold = storeInfo.Gold;
|
|
|
|
if(storeInfo.Gold < ULONG_MAX - dwGold)
|
|
{
|
|
storeInfo.Gold += dwGold;
|
|
}
|
|
else
|
|
{
|
|
storeInfo.Gold = ULONG_MAX;
|
|
}
|
|
|
|
if(!DBComponent::GameDB::SetItemStoreInfo(writeDB, dwUID, &storeInfo))
|
|
{
|
|
ERRLOG2(g_Log, "UID:%10u / Gold:%10u / 돈 더히기 실패 : 창고 정보 저장 실패", dwUID, dwGold);
|
|
}
|
|
else
|
|
{
|
|
dwNewGold = storeInfo.Gold;
|
|
}
|
|
}
|
|
|
|
if(0 != dwNewGold && 0 != dwGold)
|
|
{
|
|
DETLOG4(g_GoldLog, "UID:%10u / OldGold:%10u / NewGold:%10u / GetGold:%10u / 창고에 돈을 지급했습니다.",
|
|
dwUID, dwOldGold, dwNewGold, dwGold);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// UpdateInven [ public ]
|
|
// - 인벤 업데이트
|
|
//
|
|
// Parameter :
|
|
// 1st : 캐릭터 아이디[In]
|
|
// 2st : 인벤 데이터[Out]
|
|
//
|
|
// Return :
|
|
// 생성 성공 시 true, 실패시 false
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
bool DBComponent::GameDB::UpdateDelHistoryInven(CDBComponent& DBComponent, unsigned long CharID_In, LPINVEN lpInven_In)
|
|
{
|
|
_snprintf(DBComponent.GetQueryBuffer(), CDBComponent::MAX_QUERY_LENGTH,
|
|
"SELECT Inventory FROM CharDelHistory..DelCharItem WHERE UID = %d", CharID_In );
|
|
|
|
lpInven_In->dwSize += sizeof(unsigned long);
|
|
if (DBComponent.ExecuteQuery(DBComponent.GetQueryBuffer(), OleDB::Rowset_Update)) {
|
|
if (DBComponent.SetBinaryData(1, (OleDB::LPSET_BINARY)lpInven_In)) {
|
|
lpInven_In->dwSize -= sizeof(unsigned long);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
SERLOG3(g_Log, "CID:%10u %s %s", CharID_In, DBComponent.GetErrorString(), DBComponent.GetQueryBuffer());
|
|
lpInven_In->dwSize -= sizeof(unsigned long);
|
|
return false;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// UpdateExtra [ public ]
|
|
// - 인벤 퀵 슬롯
|
|
//
|
|
// Parameter :
|
|
// 1st : 캐릭터 아이디[In]
|
|
// 2st : 퀵[Out]
|
|
//
|
|
// Return :
|
|
// 생성 성공 시 true, 실패시 false
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
bool DBComponent::GameDB::UpdateDelHistoryExtra(CDBComponent& DBComponent, unsigned long CharID_In, LPEXTRA lpExtra_In)
|
|
{
|
|
_snprintf(DBComponent.GetQueryBuffer(), CDBComponent::MAX_QUERY_LENGTH,
|
|
"SELECT Extra FROM CharDelHistory..DelCharItem WHERE UID = %d", CharID_In );
|
|
|
|
lpExtra_In->dwSize += sizeof(unsigned long);
|
|
if (DBComponent.ExecuteQuery(DBComponent.GetQueryBuffer(), OleDB::Rowset_Update)) {
|
|
if (DBComponent.SetBinaryData(1, (OleDB::LPSET_BINARY)lpExtra_In)) {
|
|
lpExtra_In->dwSize -= sizeof(unsigned long);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
ERRLOG3(g_Log, "CID:%10u %s %s", CharID_In, DBComponent.GetErrorString(), DBComponent.GetQueryBuffer());
|
|
lpExtra_In->dwSize -= sizeof(unsigned long);
|
|
return false;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// UpdateExchange [ public ]
|
|
// - 교환 업데이트
|
|
//
|
|
// Parameter :
|
|
// 1st : 캐릭터 아이디[In]
|
|
// 2st : 교환[In]
|
|
//
|
|
// Return :
|
|
// 생성 성공 시 true, 실패시 false
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
bool DBComponent::GameDB::UpdateDelHistoryExchange(CDBComponent& DBComponent, unsigned long CharID_In, LPEXCHANGE lpExchange_In)
|
|
{
|
|
_snprintf(DBComponent.GetQueryBuffer(), CDBComponent::MAX_QUERY_LENGTH,
|
|
"SELECT Exchange FROM CharDelHistory..DelCharItemEx WHERE UID = %d", CharID_In );
|
|
|
|
lpExchange_In->dwSize += sizeof(unsigned long);
|
|
if (DBComponent.ExecuteQuery(DBComponent.GetQueryBuffer(), OleDB::Rowset_Update)) {
|
|
if (DBComponent.SetBinaryData(1, (OleDB::LPSET_BINARY)lpExchange_In)) {
|
|
lpExchange_In->dwSize -= sizeof(unsigned long);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
ERRLOG3(g_Log, "CID:%10u %s %s", CharID_In, DBComponent.GetErrorString(), DBComponent.GetQueryBuffer());
|
|
lpExchange_In->dwSize -= sizeof(unsigned long);
|
|
return false;
|
|
} |