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>
1309 lines
43 KiB
C++
1309 lines
43 KiB
C++
#include "stdafx.h"
|
|
#include "CharacterData.h"
|
|
#include "SessionData.h"
|
|
#include "DBDataMgr.h"
|
|
#include "DBItemSerialMgr.h"
|
|
|
|
#include <DB/DBComponent.h>
|
|
#include <DB/GameDBComponent.h>
|
|
#include <Log/ServerLog.h>
|
|
|
|
#include <Item/ItemStructure.h>
|
|
|
|
#include <Item/ItemStructure.h>
|
|
#include <Item/ItemConstants.h>
|
|
#include <Item/Container/ContainerConstant.h>
|
|
#include <Item/RebalanceConvert/ContainerChecker.h>
|
|
#include <Item/RebalanceConvert/RebalanceItem.h>
|
|
#include <Utility/Debug/PerformanceCheck.h>
|
|
|
|
#include <Network/Packet/PacketStruct/CharLoginOutPacketStruct.h>
|
|
#include <mmsystem.h>
|
|
|
|
#include <Network/Dispatch/GameDispatch.h>
|
|
#include <Creature/Character/CharacterCreate.h>
|
|
#include <Creature/Character/ExpTable.h>
|
|
|
|
#include <Community/FriendList.h>
|
|
|
|
#include <DataStorage/SessionDataMgr.h>
|
|
|
|
#include <GameTime/GameTimeDBMgr.h>
|
|
|
|
namespace DBAgent
|
|
{
|
|
namespace DataStorage
|
|
{
|
|
|
|
CCharacterData::CCharacterData()
|
|
: m_FriendList(0), m_BanList(0), m_dwUpdateData(0), m_dwLastDBUpdateTime(0)
|
|
{
|
|
ClearData();
|
|
}
|
|
|
|
CCharacterData::~CCharacterData()
|
|
{
|
|
|
|
}
|
|
|
|
void CCharacterData::SetUID(unsigned long dwUID)
|
|
{
|
|
m_dwUID = dwUID;
|
|
}
|
|
|
|
void CCharacterData::SetPID(unsigned long dwPID)
|
|
{
|
|
m_CharInfo.PID = dwPID;
|
|
m_dwUpdateData |= CHANGED_CHAR_INFOST;
|
|
}
|
|
|
|
|
|
void CCharacterData::SetGID(unsigned long dwGID)
|
|
{
|
|
m_CharInfo.GID = dwGID;
|
|
m_dwUpdateData |= CHANGED_CHAR_INFOST;
|
|
}
|
|
|
|
void CCharacterData::SetServerID(unsigned long dwServerID)
|
|
{
|
|
m_CharInfoEx.ServerID = dwServerID;
|
|
m_dwUpdateData |= CHANGED_CHAR_INFOEX;
|
|
}
|
|
|
|
bool CCharacterData::SetInfo(const CHAR_INFOST& charInfoST, bool bChangeName)
|
|
{
|
|
CHAR_INFOST local_InfoST = charInfoST;
|
|
|
|
if(!bChangeName)
|
|
{
|
|
// 이름을 변경하지 않는 경우는, 이름을 지금 이름으로 덮어씌운다.
|
|
memcpy(local_InfoST.Name, m_CharInfo.Name,
|
|
sizeof(char) * CHAR_INFOST::MAX_NAME_LEN);
|
|
}
|
|
|
|
if(m_CharInfo.CID != local_InfoST.CID || 0 == local_InfoST.Level)
|
|
{
|
|
SERLOG3(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 에러 : UpdateCID : %10u, Level : %d",
|
|
m_CharInfo.CID, local_InfoST.CID, local_InfoST.Level);
|
|
|
|
return false;
|
|
}
|
|
else if(0 != memcmp(&m_CharInfo, &local_InfoST, sizeof(CHAR_INFOST)))
|
|
{
|
|
m_CharInfo = local_InfoST;
|
|
m_dwUpdateData |= CHANGED_CHAR_INFOST;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void CCharacterData::SetPos(const CHAR_POS& charPos)
|
|
{
|
|
if(0 != memcmp(&m_CharPos, &charPos, sizeof(CHAR_POS)))
|
|
{
|
|
m_CharPos = charPos;
|
|
m_dwUpdateData |= CHANGED_CHAR_POS;
|
|
}
|
|
}
|
|
|
|
void CCharacterData::SetSkill(const SKILL& skill)
|
|
{
|
|
if(0 != memcmp(&m_Skill, &skill, sizeof(SKILL)))
|
|
{
|
|
m_Skill = skill;
|
|
m_dwUpdateData |= CHANGED_SKILL;
|
|
}
|
|
|
|
}
|
|
|
|
void CCharacterData::SetQuick(const QUICK& quick)
|
|
{
|
|
if(0 != memcmp(&m_Quick, &quick, sizeof(QUICK)))
|
|
{
|
|
m_Quick = quick;
|
|
m_dwUpdateData |= CHANGED_QUICK;
|
|
}
|
|
}
|
|
|
|
void CCharacterData::SetSpell(const SPELL& spell)
|
|
{
|
|
if(0 != memcmp(&m_Spell, &spell, sizeof(SPELL)))
|
|
{
|
|
m_Spell = spell;
|
|
m_dwUpdateData |= CHANGED_SPELL;
|
|
}
|
|
}
|
|
|
|
void CCharacterData::SetInfoEx(const CHAR_INFOEX& charInfoEx)
|
|
{
|
|
if(0 != memcmp(&m_CharInfoEx, &charInfoEx, sizeof(CHAR_INFOEX)))
|
|
{
|
|
m_CharInfoEx = charInfoEx;
|
|
m_dwUpdateData |= CHANGED_CHAR_INFOEX;
|
|
}
|
|
}
|
|
|
|
|
|
void CCharacterData::SetQuest(const QUEST& quest)
|
|
{
|
|
if(0 != memcmp(&m_Quest, &quest, sizeof(QUEST)))
|
|
{
|
|
m_Quest = quest;
|
|
m_dwUpdateData |= CHANGED_QUEST;
|
|
}
|
|
}
|
|
|
|
|
|
void CCharacterData::SetHistory(const HISTORY& history)
|
|
{
|
|
if(0 != memcmp(&m_History, &history, sizeof(HISTORY)))
|
|
{
|
|
m_History = history;
|
|
m_dwUpdateData |= CHANGED_HISTORY;
|
|
}
|
|
}
|
|
|
|
|
|
void CCharacterData::SetConfig(const CONFIG& config)
|
|
{
|
|
if(0 != memcmp(&m_Config, &config, sizeof(CONFIG)))
|
|
{
|
|
m_Config = config;
|
|
m_dwUpdateData |= CHANGED_CONFIG;
|
|
}
|
|
}
|
|
|
|
|
|
bool CCharacterData::SetEquip(const char* szData, unsigned long dwDataLen)
|
|
{
|
|
if(EQUIP::MAX_EQUIP_SIZE < dwDataLen)
|
|
{
|
|
SERLOG3(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 에러 : 장비정보(%u)의 크기(%u) 에러",
|
|
GetCID(), EQUIP::MAX_EQUIP_SIZE, dwDataLen);
|
|
|
|
return false;
|
|
}
|
|
else if(m_Equip.dwSize != dwDataLen || 0 != memcmp(m_Equip.Data, szData, dwDataLen))
|
|
{
|
|
memcpy(m_Equip.Data, szData, dwDataLen);
|
|
m_Equip.dwSize = dwDataLen;
|
|
|
|
m_dwUpdateData |= CHANGED_EQUIP;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool CCharacterData::SetInven(const char* szData, unsigned long dwDataLen)
|
|
{
|
|
if(INVEN::MAX_INVEN_SIZE < dwDataLen)
|
|
{
|
|
SERLOG3(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 에러 : 인벤정보(%u)의 크기(%u) 에러",
|
|
GetCID(), INVEN::MAX_INVEN_SIZE, dwDataLen);
|
|
|
|
return false;
|
|
}
|
|
else if(m_Inven.dwSize != dwDataLen || 0 != memcmp(m_Inven.Data, szData, dwDataLen))
|
|
{
|
|
memcpy(m_Inven.Data, szData, dwDataLen);
|
|
m_Inven.dwSize = dwDataLen;
|
|
|
|
m_dwUpdateData |= CHANGED_INVEN;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool CCharacterData::SetExtra(const char* szData, unsigned long dwDataLen)
|
|
{
|
|
if(EXTRA::MAX_EXTRA_SIZE < dwDataLen)
|
|
{
|
|
SERLOG3(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 에러 : EXTRA정보(%u)의 크기(%u) 에러",
|
|
GetCID(), EXTRA::MAX_EXTRA_SIZE, dwDataLen);
|
|
|
|
return false;
|
|
}
|
|
else if(m_Extra.dwSize != dwDataLen || 0 != memcmp(m_Extra.Data, szData, dwDataLen))
|
|
{
|
|
memcpy(m_Extra.Data, szData, dwDataLen);
|
|
m_Extra.dwSize = dwDataLen;
|
|
|
|
m_dwUpdateData |= CHANGED_EXTRA;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CCharacterData::SetExchange(const char* szData, unsigned long dwDataLen)
|
|
{
|
|
if(EXCHANGE::MAX_EXCHANGE_SIZE < dwDataLen)
|
|
{
|
|
SERLOG3(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 에러 : EXCHANGE정보(%u)의 크기(%u) 에러",
|
|
GetCID(), EXCHANGE::MAX_EXCHANGE_SIZE, dwDataLen);
|
|
|
|
return false;
|
|
}
|
|
else if(m_Exchange.dwSize != dwDataLen || 0 != memcmp(m_Exchange.Data, szData, dwDataLen))
|
|
{
|
|
memcpy(m_Exchange.Data, szData, dwDataLen);
|
|
m_Exchange.dwSize = dwDataLen;
|
|
|
|
m_dwUpdateData |= CHANGED_EXCHANGE;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CCharacterData::SetTempInven(const char* szData, unsigned long dwDataLen)
|
|
{
|
|
if(TEMPINVEN::MAX_TEMPINVEN_SIZE < dwDataLen)
|
|
{
|
|
SERLOG3(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 에러 : 임시인벤정보(%u)의 크기(%u) 에러",
|
|
GetCID(), TEMPINVEN::MAX_TEMPINVEN_SIZE, dwDataLen);
|
|
|
|
return false;
|
|
}
|
|
else if(m_TempInven.dwSize != dwDataLen || 0 != memcmp(m_TempInven.Data, szData, dwDataLen))
|
|
{
|
|
memcpy(m_TempInven.Data, szData, dwDataLen);
|
|
m_TempInven.dwSize = dwDataLen;
|
|
|
|
m_dwUpdateData |= CHANGED_TEMPINVEN;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CCharacterData::SetGuildWarFlag(unsigned char cFlag)
|
|
{
|
|
if (cFlag >= Creature::WAR_OFF && cFlag <= Creature::WAR_INSTANCE)
|
|
{
|
|
m_CharInfoEx.GuildWarFlag = cFlag;
|
|
return DBComponent::GameDB::UpdateGuildWarFlag(CDBSingleObject::GetInstance(), GetCID(), cFlag);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CCharacterData::SetRealmWarFlag(unsigned char cFlag)
|
|
{
|
|
if (cFlag >= Creature::WAR_OFF && cFlag <= Creature::WAR_INSTANCE)
|
|
{
|
|
m_CharInfoEx.RealmWarFlag = cFlag;
|
|
return DBComponent::GameDB::UpdateRealmWarFlag(CDBSingleObject::GetInstance(), GetCID(), cFlag);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void CCharacterData::ClearData()
|
|
{
|
|
memset(&m_CharInfo, 0, sizeof(CHAR_INFOST)); // 기본 정보
|
|
memset(&m_CharPos, 0, sizeof(CHAR_POS)); // 위치 정보
|
|
memset(&m_Skill, 0, sizeof(SKILL)); // 스킬 정보
|
|
memset(&m_Quick, 0, sizeof(QUICK)); // 퀵슬롯
|
|
|
|
memset(&m_CharInfoEx, 0, sizeof(CHAR_INFOEX)); // 추가 정보
|
|
memset(&m_Quest, 0, sizeof(QUEST)); // 퀘스트
|
|
memset(&m_History, 0, sizeof(HISTORY)); // 히스토리
|
|
memset(&m_Config, 0, sizeof(CONFIG)); // 설정
|
|
|
|
memset(&m_Equip, 0, sizeof(EQUIP)); // 장비
|
|
memset(&m_Inven, 0, sizeof(INVEN)); // 인벤
|
|
memset(&m_Extra, 0, sizeof(EXTRA)); // 여분
|
|
memset(&m_Exchange, 0, sizeof(EXCHANGE)); // 교환
|
|
memset(&m_TempInven, 0, sizeof(TEMPINVEN)); // 임시 인벤토리
|
|
|
|
m_BanList.Clear(); // 거부
|
|
m_FriendList.Clear(); // 친구
|
|
|
|
m_dwUID = 0;
|
|
|
|
memset(&m_EquipView, 0, sizeof(unsigned short) * MAX_EQUIP_VIEW); // 장비 뷰
|
|
m_dwUpdateData = 0; // 데이터가 업데이트되었는지를 나타냄.
|
|
}
|
|
|
|
void CCharacterData::ReloadEquipView()
|
|
{
|
|
const char* lpDataPos = m_Equip.Data;
|
|
const char* lpDataEnd = m_Equip.Data + m_Equip.dwSize;
|
|
|
|
memset(m_EquipView, 0, sizeof(unsigned short) * MAX_EQUIP_VIEW);
|
|
|
|
for(; lpDataPos < lpDataEnd; )
|
|
{
|
|
const Item::ItemData* lpItemData =
|
|
reinterpret_cast<const Item::ItemData*>(lpDataPos);
|
|
|
|
unsigned short usIndex = lpItemData->m_ItemPos.m_cIndex;
|
|
|
|
if(usIndex < MAX_EQUIP_VIEW)
|
|
{
|
|
m_EquipView[usIndex] = lpItemData->m_usProtoTypeID;
|
|
}
|
|
else
|
|
{
|
|
ERRLOG3(g_Log, "CID:%10u / 장비 뷰 세팅중에 잘못된 장비(PrototypeID:%6d/Pos:%4d) 발견.",
|
|
GetCID(), lpItemData->m_usProtoTypeID, usIndex);
|
|
}
|
|
|
|
lpDataPos += lpItemData->m_cItemSize;
|
|
|
|
if(0 == lpItemData->m_cItemSize)
|
|
{
|
|
ERRLOG4(g_Log, "CID:%10u / 장비 뷰 세팅중에 잘못된 장비 정보 발견. "
|
|
"(PrototypeID:%6d/Pos:%4d/itemSize:%d)",
|
|
GetCID(), lpItemData->m_usProtoTypeID, usIndex, lpItemData->m_cItemSize);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CCharacterData::GetFromDB(CDBComponent& DBComponent, unsigned long dwCID)
|
|
{
|
|
PERFORMANCE_CHECK(FunctionTimingCheck);
|
|
|
|
ClearData();
|
|
|
|
using namespace DBComponent;
|
|
|
|
bool bResult = false;
|
|
|
|
FRIEND Friend = {0,};
|
|
BAN Ban = {0,};
|
|
|
|
// CharInfo 업데이트
|
|
if (!GameDB::GetCharInfo(DBComponent, dwCID, &m_CharInfo, m_EquipView, MAX_EQUIP_VIEW))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 로드 실패 : GetCharInfo 호출 실패", dwCID);
|
|
}
|
|
// CharPos 업데이트
|
|
else if (!GameDB::GetCharPos(DBComponent, dwCID, &m_CharPos))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 로드 실패 : GetCharPos 호출 실패", dwCID);
|
|
}
|
|
// Quick 업데이트
|
|
else if (!GameDB::GetQuick(DBComponent, dwCID, &m_Quick))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 로드 실패 : GetQuick 호출 실패", dwCID);
|
|
}
|
|
// Spell 업데이트
|
|
else if (!GameDB::GetSpell(DBComponent, dwCID, &m_Spell))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 로드 실패 : GetSpell 호출 실패", dwCID);
|
|
}
|
|
// Skill 업데이트
|
|
else if (!GameDB::GetCharSkill(DBComponent, dwCID, &m_Skill))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 로드 실패 : GetCharSkill 호출 실패", dwCID);
|
|
}
|
|
// Equip 업데이트
|
|
else if (!GameDB::GetEquip(DBComponent, dwCID, &m_Equip))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 로드 실패 : GetEquip 호출 실패", dwCID);
|
|
}
|
|
// Inven 업데이트
|
|
else if (!GameDB::GetInven(DBComponent, dwCID, &m_Inven))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 로드 실패 : GetInven 호출 실패", dwCID);
|
|
}
|
|
// Extra 업데이트
|
|
else if (!GameDB::GetExtra(DBComponent, dwCID, &m_Extra))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 로드 실패 : GetExtra 호출 실패", dwCID);
|
|
}
|
|
// Exchange 업데이트
|
|
else if (!GameDB::GetExchange(DBComponent, dwCID, &m_Exchange))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 로드 실패 : GetExchange 호출 실패", dwCID);
|
|
}
|
|
// TempInven 업데이트
|
|
else if (!GameDB::GetTempInven(DBComponent, dwCID, &m_TempInven))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 로드 실패 : GetTempInven 호출 실패", dwCID);
|
|
}
|
|
// CharInfoEx
|
|
else if (!GameDB::GetCharInfoEx(DBComponent, dwCID, &m_CharInfoEx))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 로드 실패 : GetCharInfoEx 호출 실패", dwCID);
|
|
}
|
|
// Friend
|
|
else if (!GameDB::GetFriend(DBComponent, dwCID, &Friend))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 로드 실패 : GetFriend 호출 실패", dwCID);
|
|
}
|
|
else if(!m_FriendList.SerializeIn(Friend.Data, Friend.Info, Friend.dwSize, Friend.dwInfoSize))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 로드 실패 : CFriend::SerializeIn 호출 실패", dwCID);
|
|
}
|
|
// Ban
|
|
else if(!GameDB::GetBan(DBComponent, dwCID, &Ban))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 로드 실패 : GetBan 호출 실패", dwCID);
|
|
}
|
|
else if(!m_BanList.SerializeIn(Ban.Data, Ban.Info, Ban.dwSize, Ban.dwInfoSize))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 로드 실패 : CBan::SerializeIn 호출 실패", dwCID);
|
|
}
|
|
// Quest
|
|
else if (!GameDB::GetQuest(DBComponent, dwCID, &m_Quest))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 로드 실패 : GetQuest 호출 실패", dwCID);
|
|
}
|
|
// History
|
|
else if (!GameDB::GetHistory(DBComponent, dwCID, &m_History))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 로드 실패 : GetHistory 호출 실패", dwCID);
|
|
}
|
|
// Config
|
|
else if (!GameDB::GetConfig(DBComponent, dwCID, &m_Config))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 로드 실패 : GetConfig 호출 실패", dwCID);
|
|
}
|
|
else
|
|
{
|
|
// Friend 정보 설정 (시간이 생기면 수정하겠음) //
|
|
unsigned long dwListCID[CFriendList::MAX_FRIENDS_NUM];
|
|
|
|
// 친구리스트에 CID 만 가지고 온다. //
|
|
m_FriendList.GetCIDList(dwListCID);
|
|
|
|
for(unsigned char cIndex = 0; cIndex < m_FriendList.GetFriendNum(); cIndex++)
|
|
{
|
|
CSessionData* lpSessionData = CSessionDataMgr::GetInstance().GetCharLoadedSession(dwListCID[cIndex]);
|
|
|
|
CFriendList::Rebind* lpRebind = m_FriendList.GetFriend(dwListCID[cIndex]);
|
|
|
|
if(lpRebind)
|
|
{
|
|
if(lpSessionData)
|
|
{
|
|
CCharacterData* lpCharacterData = lpSessionData->GetCharacterData();
|
|
|
|
if(lpCharacterData)
|
|
{
|
|
// Frind 초기화 //
|
|
lpRebind->InitializeFriendInfo(lpCharacterData->GetServerID(), lpCharacterData->GetGID(),
|
|
lpCharacterData->GetClass(), lpCharacterData->GetLevel());
|
|
}
|
|
else
|
|
{
|
|
lpRebind->UpdateServerID(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lpRebind->UpdateServerID(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Ban 정보 설정 (시간이 생기면 여기도 수정하겠음) //
|
|
|
|
// 거부리스트에 CID 만 가지고 온다. //
|
|
m_BanList.GetCIDList(dwListCID);
|
|
|
|
for(unsigned char cIndex = 0; cIndex < m_BanList.GetBanNum(); cIndex++)
|
|
{
|
|
CSessionData* lpSessionData = CSessionDataMgr::GetInstance().GetCharLoadedSession(dwListCID[cIndex]);
|
|
|
|
CBanList::Rebind* lpRebind = m_BanList.GetBan(dwListCID[cIndex]);
|
|
|
|
if(lpRebind)
|
|
{
|
|
if(lpSessionData)
|
|
{
|
|
CCharacterData* lpCharacterData = lpSessionData->GetCharacterData();
|
|
|
|
if(lpCharacterData)
|
|
{
|
|
// Frind 초기화 //
|
|
lpRebind->InitializeBanInfo(lpCharacterData->GetServerID(), lpCharacterData->GetGID(),
|
|
lpCharacterData->GetClass(), lpCharacterData->GetLevel());
|
|
}
|
|
else
|
|
{
|
|
lpRebind->UpdateServerID(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lpRebind->UpdateServerID(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
INFLOG1(g_Log, "CID:%10u / 캐릭터 데이터 로드 성공 : CCharacterData::GetFromDB", dwCID);
|
|
bResult = true;
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
bool CCharacterData::AddGold(unsigned long dwGold)
|
|
{
|
|
m_CharInfo.Gold += dwGold;
|
|
m_dwUpdateData |= CHANGED_CHAR_INFOST;
|
|
return true;
|
|
}
|
|
|
|
bool CCharacterData::DeductGold(unsigned long dwGold)
|
|
{
|
|
if (dwGold <= m_CharInfo.Gold)
|
|
{
|
|
m_CharInfo.Gold -= dwGold;
|
|
m_dwUpdateData |= CHANGED_CHAR_INFOST;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CCharacterData::UpdateDBData(CDBComponent& DBComponent)
|
|
{
|
|
PERFORMANCE_CHECK(FunctionTimingCheck);
|
|
|
|
unsigned long dwCID = GetCID();
|
|
|
|
// 무결성 검사
|
|
if (!IsValidData())
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / UpdateToDB 에서 무결성 검사 실패.", dwCID);
|
|
return false;
|
|
}
|
|
else if(IsDataChanged())
|
|
{
|
|
using namespace DBComponent;
|
|
|
|
// INFLOG2(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 준비 : CCharacterData::UpdateToDB, %d 부분 업데이트 시작", dwCID, m_dwUpdateData);
|
|
|
|
FRIEND Friend = {0,};
|
|
BAN Ban = {0,};
|
|
|
|
Friend.dwSize = FRIEND::MAX_FRIEND_SIZE;
|
|
Friend.dwInfoSize = FRIEND::MAX_FRIENDINFO_SIZE;
|
|
Ban.dwSize = BAN::MAX_BAN_SIZE;
|
|
Ban.dwInfoSize = BAN::MAX_BANINFO_SIZE;
|
|
|
|
// 장비 뷰 다시 로드
|
|
ReloadEquipView();
|
|
|
|
/*
|
|
unsigned long dwUpdateData = 0;
|
|
|
|
// CharInfo 업데이트
|
|
if((m_dwUpdateData & CHANGED_CHAR_INFOST) &&
|
|
!GameDB::UpdateCharInfo(DBComponent, dwCID, &m_CharInfo, m_EquipView, MAX_EQUIP_VIEW))
|
|
{
|
|
dwUpdateData |= CHANGED_CHAR_INFOST;
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateCharInfo 호출 실패", dwCID);
|
|
}
|
|
// CharPos 업데이트
|
|
if((m_dwUpdateData & CHANGED_CHAR_POS) &&
|
|
!GameDB::UpdateCharPos(DBComponent, dwCID, &m_CharPos))
|
|
{
|
|
dwUpdateData |= CHANGED_CHAR_POS;
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateCharPos 호출 실패", dwCID);
|
|
}
|
|
// Quick 업데이트
|
|
if((m_dwUpdateData & CHANGED_QUICK) &&
|
|
!GameDB::UpdateQuick(DBComponent, dwCID, &m_Quick))
|
|
{
|
|
dwUpdateData |= CHANGED_QUICK;
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateCharInfo 호출 실패", dwCID);
|
|
}
|
|
// Spell 업데이트
|
|
if((m_dwUpdateData & CHANGED_SPELL) &&
|
|
!GameDB::UpdateSpell(DBComponent, dwCID, &m_Spell))
|
|
{
|
|
dwUpdateData |= CHANGED_SPELL;
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateSpellInfo 호출 실패", dwCID);
|
|
}
|
|
// Skill 업데이트
|
|
if((m_dwUpdateData & CHANGED_SKILL) &&
|
|
!GameDB::UpdateCharSkill(DBComponent, dwCID, &m_Skill))
|
|
{
|
|
dwUpdateData |= CHANGED_SKILL;
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateCharSkill 호출 실패", dwCID);
|
|
}
|
|
// Equip 업데이트
|
|
if((m_dwUpdateData & CHANGED_EQUIP) &&
|
|
!GameDB::UpdateEquip(DBComponent, dwCID, &m_Equip))
|
|
{
|
|
dwUpdateData |= CHANGED_EQUIP;
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateEquip 호출 실패", dwCID);
|
|
}
|
|
// Inven 업데이트
|
|
if((m_dwUpdateData & CHANGED_INVEN) &&
|
|
!GameDB::UpdateInven(DBComponent, dwCID, &m_Inven))
|
|
{
|
|
dwUpdateData |= CHANGED_INVEN;
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateInven 호출 실패", dwCID);
|
|
}
|
|
// Extra 업데이트
|
|
if((m_dwUpdateData & CHANGED_EXTRA) &&
|
|
!GameDB::UpdateExtra(DBComponent, dwCID, &m_Extra))
|
|
{
|
|
dwUpdateData |= CHANGED_EXTRA;
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateExtra 호출 실패", dwCID);
|
|
}
|
|
// Exchange 업데이트
|
|
if((m_dwUpdateData & CHANGED_EXCHANGE) &&
|
|
!GameDB::UpdateExchange(DBComponent, dwCID, &m_Exchange))
|
|
{
|
|
dwUpdateData |= CHANGED_EXCHANGE;
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateExchange 호출 실패", dwCID);
|
|
}
|
|
// TempInven 업데이트
|
|
if((m_dwUpdateData & CHANGED_TEMPINVEN) &&
|
|
!GameDB::UpdateTempInven(DBComponent, dwCID, &m_TempInven))
|
|
{
|
|
dwUpdateData |= CHANGED_TEMPINVEN;
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateTempInven 호출 실패", dwCID);
|
|
}
|
|
// CharInfoEx
|
|
if((m_dwUpdateData & CHANGED_CHAR_INFOEX) &&
|
|
!GameDB::UpdateCharInfoEx(DBComponent, dwCID, &m_CharInfoEx))
|
|
{
|
|
dwUpdateData |= CHANGED_CHAR_INFOEX;
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateCharInfoEx 호출 실패", dwCID);
|
|
}
|
|
// Quest
|
|
if((m_dwUpdateData & CHANGED_QUEST) &&
|
|
!GameDB::UpdateQuest(DBComponent, dwCID, &m_Quest))
|
|
{
|
|
dwUpdateData |= CHANGED_QUEST;
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateQuest 호출 실패", dwCID);
|
|
}
|
|
// History
|
|
if((m_dwUpdateData & CHANGED_HISTORY) &&
|
|
!GameDB::UpdateHistory(DBComponent, dwCID, &m_History))
|
|
{
|
|
dwUpdateData |= CHANGED_HISTORY;
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateHistory 호출 실패", dwCID);
|
|
}
|
|
// Config
|
|
if((m_dwUpdateData & CHANGED_CONFIG) &&
|
|
!GameDB::UpdateConfig(DBComponent, dwCID, &m_Config))
|
|
{
|
|
dwUpdateData |= CHANGED_CONFIG;
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateConfig 호출 실패", dwCID);
|
|
}
|
|
// Friend
|
|
if(m_dwUpdateData & CHANGED_FRIENDLIST)
|
|
{
|
|
if(!m_FriendList.SerializeOut(Friend.Data, Friend.Info, Friend.dwSize, Friend.dwInfoSize))
|
|
{
|
|
dwUpdateData |= CHANGED_FRIENDLIST;
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : CFriend::SerializeOut 호출 실패", dwCID);
|
|
}
|
|
else if(!GameDB::UpdateFriend(DBComponent, dwCID, &Friend))
|
|
{
|
|
dwUpdateData |= CHANGED_FRIENDLIST;
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateFriend 호출 실패", dwCID);
|
|
}
|
|
}
|
|
|
|
if(m_dwUpdateData & CHANGED_BANLIST)
|
|
{
|
|
// Ban
|
|
if(!m_BanList.SerializeOut(Ban.Data, Ban.Info, Ban.dwSize, Ban.dwInfoSize))
|
|
{
|
|
dwUpdateData |= CHANGED_BANLIST;
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : CBan::SerializeOut 호출 실패", dwCID);
|
|
return false;
|
|
}
|
|
else if(!GameDB::UpdateBan(DBComponent, dwCID, &Ban))
|
|
{
|
|
dwUpdateData |= CHANGED_BANLIST;
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateBan 호출 실패", dwCID);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// 데이터 업데이트 플래그 리셋.
|
|
if(dwUpdateData == 0)
|
|
{
|
|
INFLOG2(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 성공 : CCharacterData::UpdateToDB, %d 부분 업데이트 성공", dwCID, m_dwUpdateData);
|
|
m_dwUpdateData = 0;
|
|
}
|
|
else
|
|
{
|
|
// SERLOG2(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : %d 부분 실패", dwCID, m_dwUpdateData);
|
|
// m_dwUpdateData = 0;
|
|
m_dwUpdateData = dwUpdateData;
|
|
SERLOG2(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : %d 부분 재도전", dwCID, m_dwUpdateData);
|
|
}
|
|
*/
|
|
// CharInfo 업데이트
|
|
if((m_dwUpdateData & CHANGED_CHAR_INFOST) &&
|
|
!GameDB::UpdateCharInfo(DBComponent, dwCID, &m_CharInfo, m_EquipView, MAX_EQUIP_VIEW))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateCharInfo 호출 실패", dwCID);
|
|
}
|
|
// CharPos 업데이트
|
|
else if((m_dwUpdateData & CHANGED_CHAR_POS) &&
|
|
!GameDB::UpdateCharPos(DBComponent, dwCID, &m_CharPos))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateCharPos 호출 실패", dwCID);
|
|
}
|
|
// Quick 업데이트
|
|
else if((m_dwUpdateData & CHANGED_QUICK) &&
|
|
!GameDB::UpdateQuick(DBComponent, dwCID, &m_Quick))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateCharInfo 호출 실패", dwCID);
|
|
}
|
|
// Spell 업데이트
|
|
else if((m_dwUpdateData & CHANGED_SPELL) &&
|
|
!GameDB::UpdateSpell(DBComponent, dwCID, &m_Spell))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateSpellInfo 호출 실패", dwCID);
|
|
}
|
|
// Skill 업데이트
|
|
else if((m_dwUpdateData & CHANGED_SKILL) &&
|
|
!GameDB::UpdateCharSkill(DBComponent, dwCID, &m_Skill))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateCharSkill 호출 실패", dwCID);
|
|
}
|
|
// Equip 업데이트
|
|
else if((m_dwUpdateData & CHANGED_EQUIP) &&
|
|
!GameDB::UpdateEquip(DBComponent, dwCID, &m_Equip))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateEquip 호출 실패", dwCID);
|
|
}
|
|
// Inven 업데이트
|
|
else if((m_dwUpdateData & CHANGED_INVEN) &&
|
|
!GameDB::UpdateInven(DBComponent, dwCID, &m_Inven))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateInven 호출 실패", dwCID);
|
|
}
|
|
// Extra 업데이트
|
|
else if((m_dwUpdateData & CHANGED_EXTRA) &&
|
|
!GameDB::UpdateExtra(DBComponent, dwCID, &m_Extra))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateExtra 호출 실패", dwCID);
|
|
}
|
|
// Exchange 업데이트
|
|
else if((m_dwUpdateData & CHANGED_EXCHANGE) &&
|
|
!GameDB::UpdateExchange(DBComponent, dwCID, &m_Exchange))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateExchange 호출 실패", dwCID);
|
|
}
|
|
// TempInven 업데이트
|
|
else if((m_dwUpdateData & CHANGED_TEMPINVEN) &&
|
|
!GameDB::UpdateTempInven(DBComponent, dwCID, &m_TempInven))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateTempInven 호출 실패", dwCID);
|
|
}
|
|
// CharInfoEx
|
|
else if((m_dwUpdateData & CHANGED_CHAR_INFOEX) &&
|
|
!GameDB::UpdateCharInfoEx(DBComponent, dwCID, &m_CharInfoEx))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateCharInfoEx 호출 실패", dwCID);
|
|
}
|
|
else
|
|
{
|
|
// Friend
|
|
if(m_dwUpdateData & CHANGED_FRIENDLIST)
|
|
{
|
|
if(!m_FriendList.SerializeOut(Friend.Data, Friend.Info, Friend.dwSize, Friend.dwInfoSize))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : CFriend::SerializeOut 호출 실패", dwCID);
|
|
return false;
|
|
}
|
|
else if(!GameDB::UpdateFriend(DBComponent, dwCID, &Friend))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateFriend 호출 실패", dwCID);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if(m_dwUpdateData & CHANGED_BANLIST)
|
|
{
|
|
// Ban
|
|
if(!m_BanList.SerializeOut(Ban.Data, Ban.Info, Ban.dwSize, Ban.dwInfoSize))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : CBan::SerializeOut 호출 실패", dwCID);
|
|
return false;
|
|
}
|
|
else if(!GameDB::UpdateBan(DBComponent, dwCID, &Ban))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateBan 호출 실패", dwCID);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Quest
|
|
if((m_dwUpdateData & CHANGED_QUEST) &&
|
|
!GameDB::UpdateQuest(DBComponent, dwCID, &m_Quest))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateQuest 호출 실패", dwCID);
|
|
}
|
|
// History
|
|
else if((m_dwUpdateData & CHANGED_HISTORY) &&
|
|
!GameDB::UpdateHistory(DBComponent, dwCID, &m_History))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateHistory 호출 실패", dwCID);
|
|
}
|
|
// Config
|
|
else if((m_dwUpdateData & CHANGED_CONFIG) &&
|
|
!GameDB::UpdateConfig(DBComponent, dwCID, &m_Config))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 실패 : UpdateConfig 호출 실패", dwCID);
|
|
}
|
|
else
|
|
{
|
|
// 데이터 업데이트 플래그 리셋.
|
|
m_dwUpdateData = 0;
|
|
INFLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 성공 : CCharacterData::UpdateToDB", dwCID);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// 데이터 업데이트 실패
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
INFLOG1(g_Log, "CID:%10u / 캐릭터 데이터 업데이트 성공 : 변경된 데이터가 없어서 업데이트하지 않았습니다.", dwCID);
|
|
}
|
|
|
|
m_dwLastDBUpdateTime = timeGetTime();
|
|
return true;
|
|
}
|
|
|
|
|
|
inline void CopyAndAdvanceDst(char*& lpWritePos, const void* lpData, unsigned long dwSize,
|
|
unsigned short* lpSizeArray_Out, DBUpdateData::UpdateList eUpdatePos)
|
|
{
|
|
memcpy(lpWritePos, lpData, dwSize);
|
|
lpWritePos += dwSize;
|
|
lpSizeArray_Out[eUpdatePos] = static_cast<unsigned short>(dwSize);
|
|
}
|
|
|
|
bool CCharacterData::SerializeOut(char* lpBuffer_Out, unsigned short* lpSizeArray_Out,
|
|
unsigned long &dwBufferSize_InOut, unsigned long dwSizeArrayNum)
|
|
{
|
|
// 버퍼 바운딩 체크 및 SizeArray체크
|
|
|
|
if(0 == lpBuffer_Out || 0 == lpSizeArray_Out)
|
|
{
|
|
SERLOG3(g_Log, "CID:%10u / 캐릭터 데이터 버퍼에 쓰기 실패 : 입력 데이터가 이상합니다."
|
|
"lpBuffer_Out:%p / lpSizeArray_Out:%p", GetCID(), lpBuffer_Out, lpSizeArray_Out);
|
|
|
|
return false;
|
|
}
|
|
|
|
unsigned long dwEstimateSize =
|
|
sizeof(CHAR_INFOST) + sizeof(CHAR_POS) + sizeof(SKILL) + sizeof(QUICK) + sizeof(SPELL) +
|
|
m_Equip.dwSize + m_Inven.dwSize + m_Extra.dwSize + m_Exchange.dwSize + m_TempInven.dwSize;
|
|
|
|
if(dwBufferSize_InOut < dwEstimateSize)
|
|
{
|
|
SERLOG3(g_Log, "CID:%10u / 캐릭터 데이터 버퍼에 쓰기 실패 : 버퍼 크기가 부족합니다."
|
|
"필요 크기:%10u / 받은 크기:%10u", GetCID(), dwEstimateSize, dwBufferSize_InOut);
|
|
|
|
return false;
|
|
}
|
|
|
|
if(dwSizeArrayNum < DBUpdateData::MAX_UPDATE_DB)
|
|
{
|
|
SERLOG3(g_Log, "CID:%10u / 캐릭터 데이터 버퍼에 쓰기 실패 : SizeArray 크기가 부족합니다."
|
|
"필요 개수:%10u / 받은 개수:%10u", GetCID(), DBUpdateData::MAX_UPDATE_DB, dwSizeArrayNum);
|
|
|
|
return false;
|
|
}
|
|
|
|
char* lpWritePos = lpBuffer_Out;
|
|
|
|
CopyAndAdvanceDst(lpWritePos, &m_CharInfo, sizeof(CHAR_INFOST), lpSizeArray_Out, DBUpdateData::STATUS_UPDATE);
|
|
CopyAndAdvanceDst(lpWritePos, &m_CharPos, sizeof(CHAR_POS), lpSizeArray_Out, DBUpdateData::POSITION_UPDATE);
|
|
CopyAndAdvanceDst(lpWritePos, &m_Skill, sizeof(SKILL), lpSizeArray_Out, DBUpdateData::SKILL_UPDATE);
|
|
CopyAndAdvanceDst(lpWritePos, &m_Quick, sizeof(QUICK), lpSizeArray_Out, DBUpdateData::QUICKSLOT_UPDATE);
|
|
CopyAndAdvanceDst(lpWritePos, &m_Spell, sizeof(SPELL), lpSizeArray_Out, DBUpdateData::SPELL_UPDATE);
|
|
CopyAndAdvanceDst(lpWritePos, m_Equip.Data, m_Equip.dwSize, lpSizeArray_Out, DBUpdateData::ITEM_EQUIP_UPDATE);
|
|
CopyAndAdvanceDst(lpWritePos, m_Inven.Data, m_Inven.dwSize, lpSizeArray_Out, DBUpdateData::ITEM_INVEN_UPDATE);
|
|
CopyAndAdvanceDst(lpWritePos, m_Extra.Data, m_Extra.dwSize, lpSizeArray_Out, DBUpdateData::ITEM_EXTRA_UPDATE);
|
|
CopyAndAdvanceDst(lpWritePos, m_Exchange.Data, m_Exchange.dwSize, lpSizeArray_Out, DBUpdateData::ITEM_EXCHANGE_UPDATE);
|
|
CopyAndAdvanceDst(lpWritePos, m_TempInven.Data, m_TempInven.dwSize, lpSizeArray_Out, DBUpdateData::ITEM_TEMPINVEN_UPDATE);
|
|
|
|
|
|
dwBufferSize_InOut = static_cast<unsigned long>(lpWritePos - lpBuffer_Out);
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CCharacterData::SerializeIn(const char* lpBuffer_In, const unsigned short* lpSizeArray_In,
|
|
unsigned long dwBufferSize, unsigned long dwSizeArrayNum)
|
|
{
|
|
unsigned long dwCID = GetCID();
|
|
|
|
// 데이터길이 체크 및 버퍼길이 체크
|
|
if(0 == lpBuffer_In || 0 == lpSizeArray_In || dwSizeArrayNum < DBUpdateData::MAX_UPDATE_DB)
|
|
{
|
|
SERLOG4(g_Log, "CID:%10u / 버퍼 데이터를 캐릭터에 쓰기 실패 : 입력 데이터가 이상합니다."
|
|
"lpBuffer_Out:%p / lpSizeArray_Out:%p / dwSizeArrayNum : %d",
|
|
dwCID, lpBuffer_In, lpSizeArray_In, dwSizeArrayNum);
|
|
|
|
return false;
|
|
}
|
|
|
|
if (sizeof(CHAR_INFOST) != lpSizeArray_In[DBUpdateData::STATUS_UPDATE] ||
|
|
sizeof(CHAR_POS) != lpSizeArray_In[DBUpdateData::POSITION_UPDATE] ||
|
|
sizeof(SKILL) != lpSizeArray_In[DBUpdateData::SKILL_UPDATE] ||
|
|
sizeof(QUICK) != lpSizeArray_In[DBUpdateData::QUICKSLOT_UPDATE] ||
|
|
sizeof(SPELL) != lpSizeArray_In[DBUpdateData::SPELL_UPDATE])
|
|
{
|
|
// SERLOG10(g_Log, "CID:%10u / 버퍼 데이터를 캐릭터에 쓰기 실패 : 입력 데이터가 이상합니다. sizeof(CHAR_INFOST) : %d/%d / sizeof(CHAR_POS) : %d/%d / sizeof(SKILL) : %d/%d / sizeof(QUICK) : %d/%d / sizeof(SPELL) : %d/%d",
|
|
SERLOG10(g_Log, "CID:%10u / 버퍼 데이터를 캐릭터에 쓰기 실패 : 입력 데이터가 이상합니다. sizeof(CHAR_INFOST) : %d/%d / sizeof(CHAR_POS) : %d/%d / sizeof(SKILL) : %d/%d / sizeof(QUICK) : %d/%d / sizeof(SPELL) : %d",
|
|
dwCID,
|
|
sizeof(CHAR_INFOST), lpSizeArray_In[DBUpdateData::STATUS_UPDATE],
|
|
sizeof(CHAR_POS), lpSizeArray_In[DBUpdateData::POSITION_UPDATE],
|
|
sizeof(SKILL), lpSizeArray_In[DBUpdateData::SKILL_UPDATE],
|
|
sizeof(QUICK), lpSizeArray_In[DBUpdateData::QUICKSLOT_UPDATE],
|
|
lpSizeArray_In[DBUpdateData::SPELL_UPDATE]);
|
|
// sizeof(SPELL), lpSizeArray_In[DBUpdateData::SPELL_UPDATE]);
|
|
|
|
return false;
|
|
}
|
|
|
|
const char* lpReadPos = lpBuffer_In;
|
|
|
|
// 업데이트시 CID다르면 즐!
|
|
if(!SetInfo(*reinterpret_cast<const CHAR_INFOST*>(lpReadPos)))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
lpReadPos += sizeof(CHAR_INFOST);
|
|
|
|
SetPos(*reinterpret_cast<const CHAR_POS*>(lpReadPos));
|
|
lpReadPos += sizeof(CHAR_POS);
|
|
|
|
SetSkill(*reinterpret_cast<const SKILL*>(lpReadPos));
|
|
lpReadPos += sizeof(SKILL);
|
|
|
|
SetQuick(*reinterpret_cast<const QUICK*>(lpReadPos));
|
|
lpReadPos += sizeof(QUICK);
|
|
|
|
//! 스펠 데이터 세팅
|
|
SetSpell(*reinterpret_cast<const SPELL*>(lpReadPos));
|
|
lpReadPos += sizeof(SPELL);
|
|
|
|
|
|
//! 장비 데이터 세팅
|
|
if(!SetEquip(lpReadPos, lpSizeArray_In[DBUpdateData::ITEM_EQUIP_UPDATE]))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 버퍼 데이터를 캐릭터에 쓰기 실패 : 장비 세팅 실패.", dwCID);
|
|
return false;
|
|
}
|
|
lpReadPos += lpSizeArray_In[DBUpdateData::ITEM_EQUIP_UPDATE];
|
|
|
|
//! 인벤토리 데이터 세팅
|
|
if(!SetInven(lpReadPos, lpSizeArray_In[DBUpdateData::ITEM_INVEN_UPDATE]))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 버퍼 데이터를 캐릭터에 쓰기 실패 : 인벤 세팅 실패.", dwCID);
|
|
return false;
|
|
}
|
|
lpReadPos += lpSizeArray_In[DBUpdateData::ITEM_INVEN_UPDATE];
|
|
|
|
//! 추가 데이터 세팅
|
|
if(!SetExtra(lpReadPos, lpSizeArray_In[DBUpdateData::ITEM_EXTRA_UPDATE]))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 버퍼 데이터를 캐릭터에 쓰기 실패 : Extra 세팅 실패.", dwCID);
|
|
return false;
|
|
}
|
|
lpReadPos += lpSizeArray_In[DBUpdateData::ITEM_EXTRA_UPDATE];
|
|
|
|
//! 교환창 데이터 세팅
|
|
if(!SetExchange(lpReadPos, lpSizeArray_In[DBUpdateData::ITEM_EXCHANGE_UPDATE]))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 버퍼 데이터를 캐릭터에 쓰기 실패 : Exchange 세팅 실패.", dwCID);
|
|
return false;
|
|
}
|
|
lpReadPos += lpSizeArray_In[DBUpdateData::ITEM_EXCHANGE_UPDATE];
|
|
|
|
//! 임시 인벤토리 데이터 세팅
|
|
if(!SetTempInven(lpReadPos, lpSizeArray_In[DBUpdateData::ITEM_TEMPINVEN_UPDATE]))
|
|
{
|
|
SERLOG1(g_Log, "CID:%10u / 버퍼 데이터를 캐릭터에 쓰기 실패 : 임시인벤 세팅 실패.", dwCID);
|
|
return false;
|
|
}
|
|
lpReadPos += lpSizeArray_In[DBUpdateData::ITEM_TEMPINVEN_UPDATE];
|
|
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CCharacterData::AddFriend(unsigned long dwFriendCID, const char* szCharacterName, unsigned long dwGID, unsigned short wClass, char cLevel, unsigned long dwServerID)
|
|
{
|
|
if(m_FriendList.Add(dwFriendCID, szCharacterName, dwGID, wClass, cLevel, dwServerID))
|
|
{
|
|
m_dwUpdateData |= CHANGED_FRIENDLIST;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CCharacterData::RemoveFriend(unsigned long dwFriendCID)
|
|
{
|
|
if(m_FriendList.Remove(dwFriendCID))
|
|
{
|
|
m_dwUpdateData |= CHANGED_FRIENDLIST;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CCharacterData::AddBan(unsigned long dwBanCID, const char* szBanName, unsigned long dwGID, unsigned short wClass, char cLevel, unsigned long dwServerID)
|
|
{
|
|
if(m_BanList.Add(dwBanCID, szBanName, dwGID, wClass, cLevel, dwServerID))
|
|
{
|
|
m_dwUpdateData |= CHANGED_BANLIST;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CCharacterData::RemoveBan(unsigned long dwBanCID)
|
|
{
|
|
if(m_BanList.Remove(dwBanCID))
|
|
{
|
|
m_dwUpdateData |= CHANGED_BANLIST;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
bool CCharacterData::SetFriendGroup(unsigned long dwCID, unsigned long dwGroup)
|
|
{
|
|
CFriendList::Rebind* lpRebind = m_FriendList.GetFriend(dwCID);
|
|
if (0 != lpRebind && lpRebind->SetGroup(dwGroup))
|
|
{
|
|
m_dwUpdateData |= CHANGED_FRIENDLIST;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CCharacterData::FriendSerializeIn(const char* lpData, unsigned long dwDataLen)
|
|
{
|
|
if(m_FriendList.SerializeIn(lpData, dwDataLen))
|
|
{
|
|
m_dwUpdateData |= CHANGED_FRIENDLIST;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CCharacterData::BanSerializeIn(const char* lpData, unsigned long dwDataLen)
|
|
{
|
|
if(m_BanList.SerializeIn(lpData, dwDataLen))
|
|
{
|
|
m_dwUpdateData |= CHANGED_BANLIST;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
//! 가지고 있는 데이터를 파일로 덤프를 남기거나, 파일에서 데이터를 불러 온다.
|
|
bool CCharacterData::WriteDataToDumpFile(const char* szFileName)
|
|
{
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CCharacterData::ReadDataFromDumpFile(const char* szFileName)
|
|
{
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
bool CCharacterData::ConvertToPart2Item(bool bConvertSkillToTicket)
|
|
{
|
|
RebalanceLib::CItemArrayChecker<
|
|
ContainerConstant::INVENTORY_WIDTH,
|
|
ContainerConstant::INVENTORY_HEIGHT,
|
|
ContainerConstant::MAX_INVENTORY_TAB> invenChecker(TakeType::TS_INVEN);
|
|
|
|
RebalanceLib::CItemListChecker<Item::MAX_TEMP_INVEN_ITEM_NUM>
|
|
tempInvenChecker(TakeType::TS_TEMPINVEN);
|
|
|
|
RebalanceLib::SkillBookInfo skillBookInfo;
|
|
|
|
EQUIP Equip; // 장비
|
|
INVEN Inven; // 인벤
|
|
EXTRA Extra; // 여분
|
|
EXCHANGE Exchange; // 교환창
|
|
TEMPINVEN TempInven; // 임시 인벤토리
|
|
|
|
unsigned long dwGold = m_CharInfo.Gold;
|
|
|
|
// 캐릭터 이전.
|
|
m_CharInfo.Chance = 3;
|
|
|
|
CDBAgentItemSerialMgr& dbItemSerialMgr =
|
|
CDBAgentItemSerialMgr::GetInstance();
|
|
|
|
unsigned __int64 dwItemSerial = dbItemSerialMgr.GetItemSerial();
|
|
|
|
memset(&skillBookInfo, 0, sizeof(RebalanceLib::SkillBookInfo));
|
|
memset(&Equip, 0, sizeof(EQUIP));
|
|
memset(&Inven, 0, sizeof(INVEN));
|
|
memset(&Extra, 0, sizeof(EXTRA));
|
|
memset(&Exchange, 0, sizeof(EXCHANGE));
|
|
memset(&TempInven, 0, sizeof(TEMPINVEN));
|
|
|
|
Equip.dwSize = EQUIP::MAX_EQUIP_SIZE;
|
|
Inven.dwSize = INVEN::MAX_INVEN_SIZE;
|
|
Extra.dwSize = EXTRA::MAX_EXTRA_SIZE;
|
|
Exchange.dwSize = EXCHANGE::MAX_EXCHANGE_SIZE;
|
|
TempInven.dwSize = TEMPINVEN::MAX_TEMPINVEN_SIZE;
|
|
|
|
// 스킬 더하기
|
|
int nMaxSlotNum = std::min(m_Skill.wSlotNum, unsigned short(SKILL::MAX_SLOT_NUM));
|
|
for(int nCount = 0; nCount < nMaxSlotNum; ++nCount)
|
|
{
|
|
SKILLSLOT& skillSlot = m_Skill.SSlot[nCount];
|
|
|
|
if(skillSlot.SKILLINFO.cLockCount < CSkillMgr::MAX_SKILL_LOCKCOUNT)
|
|
{
|
|
for(int nLockCount = 0; nLockCount < skillSlot.SKILLINFO.cLockCount; ++nLockCount)
|
|
{
|
|
skillBookInfo.m_dwBookNum[nLockCount] += CSkillMgr::MAX_SKILL_LEVEL;
|
|
}
|
|
|
|
skillBookInfo.m_dwBookNum[skillSlot.SKILLINFO.cLockCount] +=
|
|
skillSlot.SKILLINFO.cSkillLevel;
|
|
}
|
|
}
|
|
|
|
// 아이템 컨버팅
|
|
if(!RebalanceLib::ConvertContainer(0, m_CharInfo.CID, 0, 0,
|
|
m_Equip.Data, m_Equip.dwSize, Equip.Data, Equip.dwSize))
|
|
{
|
|
ERRLOG1(g_Log, "CID:%10u / EQUIP 컨버팅에 실패했습니다", m_CharInfo.CID);
|
|
}
|
|
else if(!RebalanceLib::ConvertContainer(0, m_CharInfo.CID, &invenChecker,
|
|
bConvertSkillToTicket ? &skillBookInfo : 0,
|
|
m_Inven.Data, m_Inven.dwSize, Inven.Data, Inven.dwSize))
|
|
{
|
|
ERRLOG1(g_Log, "CID:%10u / INVEN 컨버팅에 실패했습니다", m_CharInfo.CID);
|
|
}
|
|
else if(!RebalanceLib::ConvertContainer(0, m_CharInfo.CID, 0,
|
|
bConvertSkillToTicket ? &skillBookInfo : 0,
|
|
m_Extra.Data, m_Extra.dwSize, Extra.Data, Extra.dwSize))
|
|
{
|
|
ERRLOG1(g_Log, "CID:%10u / EXTRA 컨버팅에 실패했습니다", m_CharInfo.CID);
|
|
}
|
|
else if(!RebalanceLib::ConvertContainer(0, m_CharInfo.CID, 0,
|
|
bConvertSkillToTicket ? &skillBookInfo : 0,
|
|
m_Exchange.Data, m_Exchange.dwSize, Exchange.Data, Exchange.dwSize))
|
|
{
|
|
ERRLOG1(g_Log, "CID:%10u / EXCHANGE 컨버팅에 실패했습니다", m_CharInfo.CID);
|
|
}
|
|
else if(!RebalanceLib::ConvertContainer(0, m_CharInfo.CID, &tempInvenChecker,
|
|
bConvertSkillToTicket ? &skillBookInfo : 0,
|
|
m_TempInven.Data, m_TempInven.dwSize, TempInven.Data, TempInven.dwSize))
|
|
{
|
|
ERRLOG1(g_Log, "CID:%10u / TEMPINVEN 컨버팅에 실패했습니다", m_CharInfo.CID);
|
|
}
|
|
else
|
|
{
|
|
for(int nCount = 0; nCount < CSkillMgr::MAX_SKILL_LOCKCOUNT; ++nCount)
|
|
{
|
|
// 3배로 보상한다.
|
|
skillBookInfo.m_dwBookNum[nCount] *= 3;
|
|
}
|
|
|
|
if (bConvertSkillToTicket && !RebalanceLib::AddSkillBook(
|
|
0, m_CharInfo.CID, "Inventory", dbItemSerialMgr, dwGold,
|
|
Inven.Data, Inven.dwSize, INVEN::MAX_INVEN_SIZE, invenChecker, skillBookInfo))
|
|
{
|
|
ERRLOG1(g_Log, "CID:%10u / 인벤토리 스킬북 넣어주기에 실패했습니다", m_CharInfo.CID);
|
|
}
|
|
else if (bConvertSkillToTicket && !skillBookInfo.IsEmpty() &&
|
|
!RebalanceLib::AddSkillBook(0, m_CharInfo.CID, "TempInven", dbItemSerialMgr, dwGold,
|
|
TempInven.Data, TempInven.dwSize, TEMPINVEN::MAX_TEMPINVEN_SIZE, tempInvenChecker, skillBookInfo))
|
|
{
|
|
ERRLOG1(g_Log, "CID:%10u / 임시인벤 스킬북 넣어주기에 실패했습니다", m_CharInfo.CID);
|
|
}
|
|
else
|
|
{
|
|
if(dwItemSerial < dbItemSerialMgr.GetItemSerial())
|
|
{
|
|
dbItemSerialMgr.SaveItemSerial(
|
|
CDBSingleObject::GetInstance(), dbItemSerialMgr.GetServerID());
|
|
}
|
|
|
|
m_CharInfo.Gold = dwGold;
|
|
|
|
unsigned char cLevelIndex = (0 < m_CharInfo.Level) ? m_CharInfo.Level - 1 : 0;
|
|
|
|
m_CharInfo.Exp = static_cast<unsigned __int64>(
|
|
m_CharInfo.Exp * EXP::ExpConvertTable[cLevelIndex]);
|
|
|
|
memset(&m_Skill, 0, sizeof(SKILL));
|
|
memset(&m_Quick, 0, sizeof(QUICK));
|
|
memset(&m_Quest, 0, sizeof(QUEST)); // 컨버팅할때 퀘스트/히스토리 전부 날린다.
|
|
memset(&m_History, 0, sizeof(HISTORY)); //
|
|
|
|
unsigned short usHumanCount = 0;
|
|
unsigned short usAkhanCount = 0;
|
|
unsigned char cChannelCount = 0;
|
|
|
|
CGameDispatch::GetDispatchTable().Process(
|
|
CGetTotalCount(usHumanCount, usAkhanCount, cChannelCount));
|
|
|
|
// 캐릭터 좌표를 세팅한다.
|
|
m_CharPos.LastPoint = CharCreate::GetDefaultCharacterPos(m_CharInfo.Race,
|
|
0 == m_CharInfo.Race ? usHumanCount : usAkhanCount);
|
|
|
|
memset(&m_CharPos.SavePoint, 0, sizeof(POS));
|
|
|
|
// 선택 서버군을 0으로 놓는다. 자동으로 신의 대지로 이동할것임.
|
|
m_CharInfoEx.ServerID = 0;
|
|
|
|
m_Equip = Equip; // 장비
|
|
m_Inven = Inven; // 인벤
|
|
m_Extra = Extra; // 여분
|
|
m_Exchange = Exchange; // 교환창
|
|
m_TempInven = TempInven; // 임시 인벤토리
|
|
}
|
|
|
|
if(!skillBookInfo.IsEmpty())
|
|
{
|
|
for(int nCount = 0; nCount < CSkillMgr::MAX_SKILL_LOCKCOUNT; ++nCount)
|
|
{
|
|
if(0 != skillBookInfo.m_dwBookNum[nCount])
|
|
{
|
|
ERRLOG3(g_Log, "CID:%10u / LockCount:%d / Num:%d / 스킬북을 넣어주지 못했습니다",
|
|
m_CharInfo.CID, nCount + 1, skillBookInfo.m_dwBookNum[nCount]);
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
}
|
|
} |