Files
Client/Server/RylServerProject/RylDBAgentServer/Network/ParsePacket/ParseCharManage.cpp
LGram16 dd97ddec92 Restructure repository to include all source folders
Move git root from Client/ to src/ to track all source code:
- Client: Game client source (moved to Client/Client/)
- Server: Game server source
- GameTools: Development tools
- CryptoSource: Encryption utilities
- database: Database scripts
- Script: Game scripts
- rylCoder_16.02.2008_src: Legacy coder tools
- GMFont, Game: Additional resources

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 20:17:20 +09:00

1616 lines
55 KiB
C++

#include "stdafx.h"
#include <DataStorage/StoreDataMgr.h>
#include <DataStorage/CharacterDataMgr.h>
#include <DataStorage/SessionDataMgr.h>
#include <DataStorage/DBItemSerialMgr.h>
#include <Network/Stream/SendStream.h>
#include <Network/SendPacket/SendServerInfo.h>
#include <Network/SendPacket/SendLoginout.h>
#include <Network/SendPacket/SendCharManage.h>
#include <Network/Packet/PacketCommand.h>
#include <Network/Packet/PacketStruct/ServerInfo.h>
#include <Network/Packet/PacketStruct/DataPacket.h>
#include <Network/Packet/PacketStruct/BGServerPacket.h>
#include <Network/Packet/PacketStruct/AuthServerToDBAgentServer.h>
#include <Network/Packet/PacketStruct/ClientToAuthServer.h>
#include <Network/Dispatch/Part1DBAgentDispatch.h>
// WORK_LIST 2.3 계정 국적 변경 기능 구현
#include <Network/SendPacket/SendGuild.h>
#include <DB/DBComponent.h>
#include <DB/GameDBComponent.h>
#include <Utility/Setup/ServerSetup.h>
#include <Creature/CreatureStructure.h>
#include <Creature/Character/CharacterClass.h>
#include <Log/ServerLog.h>
#include <Community/Guild/GuildDB.h>
#include <Community/Guild/GuildDBMgr.h>
#include "ParseCharManage.h"
#include <GameTime/GameTimeDBMgr.h>
#ifdef AUTH_MY
#include "NFAuthClient/AuthClient.h"
#endif
namespace DBAgent
{
namespace ParseCharManage
{
bool StartSession(CSendStream& SendStream, unsigned long dwServerID, PktSSD* lpPktSSD);
bool UserLogin(CSendStream& SendStream, PktULD* lpPktULD);
bool UserLogout(CSendStream& SendStream, PktULoD* lpPktULoD);
bool UserMove(CSendStream& SendStream, PktUMvD* lpPktUMvD);
bool CharSelect(CSendStream& SendStream, PktCSD* lpPktCSD);
bool CharCreate(CSendStream& SendStream, PktCCD* lpPktCCD);
bool CharDelete(CSendStream& SendStream, PktCDD* lpPktCDD);
bool CreateItem(CSendStream& SendStream, unsigned long dwServerID,
Item::CItemSerialMgr& itemSerialMgr, PktCCID* lpPktCCID);
// WORK_LIST 2.1 계정 국적 추가
bool SelectAccountNation(CSendStream& SendStream, PktSAND* lpPktSAND);
bool Parse(CSendStream& SendStream, unsigned long dwServerID,
Item::CItemSerialMgr& itemSerialMgr, PktDD* lpPktDD)
{
#ifdef ENABLE_PACKET_LOG
unsigned short shCmd = lpPktDD->m_wCmd;
unsigned long dwRequestKey = lpPktDD->m_dwRequestKey;
unsigned long dwSessionID = 0;
unsigned long dwUID = 0;
unsigned long dwCID = 0;
bool bLog = true;
switch (lpPktDD->m_wCmd)
{
case PktDD::SCmdStartSession: // 세션 시작
{
PktSSD* lpPktSSD = static_cast<PktSSD*>(lpPktDD);
dwSessionID = lpPktSSD->m_dwSessionID;
dwUID = lpPktSSD->m_dwUserID;
}
break;
case PktDD::SCmdUserLogin: // 유저 로그인 - 하는 일은 캐릭터 뷰 얻기 정도이다.
{
PktULD* lpPktULD = static_cast<PktULD*>(lpPktDD);
dwSessionID = lpPktULD->m_dwSessionID;
dwUID = lpPktULD->m_dwUserID;
}
break;
case PktDD::SCmdUserLogout: // 유저 로그아웃 - 세션 닫기.
{
PktULoD* lpPktULoD = static_cast<PktULoD*>(lpPktDD);
dwSessionID = lpPktULoD->m_dwSessionID;
dwUID = lpPktULoD->m_dwUserID;
}
break;
case PktDD::SCmdUserMove: // 유저 이동
{
PktUMvD* lpPktUMvD = static_cast<PktUMvD*>(lpPktDD);
dwSessionID = lpPktUMvD->m_dwSessionID;
dwUID = lpPktUMvD->m_dwUserID;
}
break;
// WORK_LIST 2.1 계정 국적 추가
case PktDD::SCmdSelectNation: // 계정 국적 설정 및 변경
{
PktSAND* lpPktSAND = static_cast<PktSAND*>(lpPktDD);
dwUID = lpPktSAND->m_dwUserID;
}
break;
case PktDD::SCmdCharSelect: // 캐릭터 선택
{
PktCSD* lpPktCSD = static_cast<PktCSD*>(lpPktDD);
dwUID = lpPktCSD->m_dwUserID;
dwCID = lpPktCSD->m_dwCharID;
}
break;
case PktDD::SCmdCharCreate: // 캐릭터 생성
{
PktCCD* lpPktCCD = static_cast<PktCCD*>(lpPktDD);
dwUID = lpPktCCD->m_dwUserID;
}
break;
case PktDD::SCmdCharDelete: // 캐릭터 삭제
{
PktCDD* lpPktCCD = static_cast<PktCDD*>(lpPktDD);
dwUID = lpPktCCD->m_dwUserID;
dwCID = lpPktCCD->m_dwCharID;
}
break;
case PktDD::SCmdCharCreateItem: // 캐릭터 생성 아이템
{
PktCCID* lpPktCCID = static_cast<PktCCID*>(lpPktDD);
dwCID = lpPktCCID->m_dwCharID;
}
break;
default:
bLog = false;
break;
}
if(bLog)
{
DETLOG5(g_PacketLog, "ParseCharManage::Parse %d : UID:%10u / CID:%10u / SessionID:%10u / ServerID:0x%08X / ",
shCmd, dwUID, dwCID, dwSessionID, dwServerID);
}
#endif
// 여기는 캐릭터 선택,삭제 화면에서
// 게임시작 하기 전까지 하는곳인듯.
bool bResult = false;
switch (lpPktDD->m_wCmd)
{
case PktDD::SCmdStartSession: // 세션 시작
// SERLOG0(g_Log, "세션시작");
bResult = StartSession(SendStream, dwServerID, static_cast<PktSSD*>(lpPktDD));
SERLOG0(g_Log, "세션시작 완료");
break;
case PktDD::SCmdUserLogin: // 유저 로그인 - 하는 일은 캐릭터 뷰 얻기 정도이다.
// SERLOG0(g_Log, "유저로그인 시도");
bResult = UserLogin(SendStream, static_cast<PktULD*>(lpPktDD));
SERLOG0(g_Log, "유저로그인 완료");
break;
case PktDD::SCmdUserLogout: // 유저 로그아웃 - 세션 닫기.
// SERLOG0(g_Log, "유저로그아웃 시도");
bResult = UserLogout(SendStream, static_cast<PktULoD*>(lpPktDD));
SERLOG0(g_Log, "유저로그아웃 완료");
break;
case PktDD::SCmdUserMove: // 유저 이동
bResult = UserMove(SendStream, static_cast<PktUMvD*>(lpPktDD));
break;
// WORK_LIST 2.1 계정 국적 추가
case PktDD::SCmdSelectNation: // 계정 국적 설정 및 변경
bResult = SelectAccountNation(SendStream, static_cast<PktSAND*>(lpPktDD));
break;
case PktDD::SCmdCharSelect: // 캐릭터 선택
bResult = CharSelect(SendStream, static_cast<PktCSD*>(lpPktDD));
break;
case PktDD::SCmdCharCreate: // 캐릭터 생성
bResult = CharCreate(SendStream, static_cast<PktCCD*>(lpPktDD));
break;
case PktDD::SCmdCharDelete: // 캐릭터 삭제
bResult = CharDelete(SendStream, static_cast<PktCDD*>(lpPktDD));
break;
case PktDD::SCmdCharCreateItem: // 캐릭터 생성 아이템
bResult = CreateItem(SendStream, dwServerID, itemSerialMgr, static_cast<PktCCID*>(lpPktDD));
break;
default:
ERRLOG1(g_Log, "CharacterManage 패킷 처리 에러 : 알 수 없는 패킷 CMD:0x%02X를 받았습니다.",
lpPktDD->m_wCmd);
bResult = true;
break;
}
return bResult;
}
bool StartSession(CSendStream& SendStream, unsigned long dwServerID, PktSSD* lpPktSSD)
{
// edith 2008.01.15 Auth 에서 세션 시작패킷이 날라왔다.
unsigned long dwSessionID = lpPktSSD->m_dwSessionID;
unsigned long dwUID = lpPktSSD->m_dwUserID;
unsigned long dwRequestKey = lpPktSSD->m_dwRequestKey;
IN_ADDR peerAddress = lpPktSSD->m_Address;
const char* szAccountName = lpPktSSD->m_AccountName;
const char* szPassword = lpPktSSD->m_Password;
unsigned short usFlag = lpPktSSD->GetError(); // 접속 끊기.
unsigned short usStartSessionError = 0;
using namespace DataStorage;
// 세션 열기
CSessionData* lpSessionData = CSessionDataMgr::GetInstance().GetOpenSession(dwUID);
if(0 != lpSessionData &&
(CSessionData::SE_USER_ENABLED == lpSessionData->GetSessionState() ||
CSessionData::SE_CHAR_ENABLED == lpSessionData->GetSessionState()))
{
// 이미 로그인 해 있으므로 접속 끊기 루틴 수행
if(0 == usFlag)
{
// 접속 끊기 보내라고 요청
usStartSessionError = 41;
}
else if(1 == usFlag)
{
// 같은 서버군에서 접속 끊기 처리를 한다.
DETLOG5(g_Log, "UID:%10u / CID:%10u / ServerID:0x%08X / Account:%s / IP:%15s / 접속 끊기 전송 : 인증 서버 명령으로 접속 끊기 보냄.",
lpSessionData->GetUID(), lpSessionData->GetCID(),
lpSessionData->GetServerID(), lpSessionData->GetAccountName(), inet_ntoa(peerAddress));
SendPacket::UserKill(*lpSessionData);
// 재접속 시도 요청
usStartSessionError = 42;
}
else
{
// 알 수 없는 경우. 그냥 세션 열기 실패로 간다.
ERRLOG4(g_Log, "UID:%10u / CID:%10u / ServerID:0x%08X / usFlag:%d / 세션 열기 실패 : 클라이언트가 알 수 없는 플래그를 보냈습니다.",
lpSessionData->GetUID(), lpSessionData->GetCID(), lpSessionData->GetServerID(), usFlag);
usStartSessionError = 40;
}
}
else if(0 == (lpSessionData = CSessionDataMgr::GetInstance().SessionOpen(dwUID)))
{
// 세션 열기 실패
usStartSessionError = 40;
}
else
{
#ifdef AUTH_MY
// edith 2009.09.11 MY를 위한 AllowIP 처리작업
char* szAdd = inet_ntoa(peerAddress);
if(!g_IPSec.IsAliveIP(szAdd))
{
usStartSessionError = 57;
ERRLOG4(g_Log, "DBAgent Error. IPSEC Error:%d Account:%s UID:%d (%s)", usStartSessionError, lpSessionData->GetAccountName(), lpSessionData->GetUID(), szAdd);
}
#endif
if(usStartSessionError == 0)
{
SERLOG4(g_Log, "UID:%10u / CID:%10u / ServerID:0x%08X / %s / UID로 인증 시도",
lpSessionData->GetUID(), lpSessionData->GetCID(), lpSessionData->GetServerID(), szAccountName);
// 인증서버로 서버군 ID세팅한다.
SERVER_ID serverID;
serverID.sID.ID = 0;
serverID.sID.Channel = 0;
serverID.sID.Group = CServerSetup::GetInstance().GetServerGroup();
serverID.sID.Type = CServerSetup::AuthServer;
dwServerID = serverID.dwID;
// edith 2008.01.15 세션을 열기에 성공했다. 리퀘스트 데이타를 세션에 입력한다. 설정후 UID로 로그인시도.
// 패스워드를 저장하려면 여기까지 날아와야한다.
// 세션 열기 성공
lpSessionData->PushRequest(
RequestData(dwRequestKey, 0, dwServerID, dwSessionID, peerAddress, szAccountName, szPassword));
// edith 2008.01.15 UID서버로 유저 로그인을 전송한다.
if (!SendPacket::UpdateUIDTable(PktUUT::UpdateUIDTableUserLogin,
szAccountName, szPassword, dwUID, 0, dwSessionID, dwServerID, peerAddress,
(1 == usFlag) ? PktUUT::DISCONNECT_USER : 0))
{
ERRLOG1(g_Log, "UID:%10u / UID서버에 유저 로그인 전송 실패", dwUID);
lpSessionData->PopRequest();
usStartSessionError = 1;
}
// 나중에 빼자
// INFLOG5(g_Log, "UID:%10u / Account:%s, Pass:%s, Session:0x%08X, ServerID:0x%08X ",
// dwUID, szAccountName, szPassword, dwSessionID, dwServerID);
}
}
if(0 != usStartSessionError)
{
if(!SendPacket::StartSession(SendStream, dwRequestKey,
dwUID, dwSessionID, 0, usStartSessionError))
{
ERRLOG2(g_Log, "UID:%10u / 인증서버에 세션 시작 실패 에러 전송 실패 : %u",
dwUID, usStartSessionError);
}
}
return true;
}
bool UserLogin(CSendStream& SendStream, PktULD* lpPktULD)
{
unsigned long dwSessionID = lpPktULD->m_dwSessionID;
unsigned long dwUID = lpPktULD->m_dwUserID;
IN_ADDR peerAddress = lpPktULD->m_Address;
unsigned char cLoginType = lpPktULD->m_cLoginType;
unsigned long dwRequestKey = lpPktULD->m_dwRequestKey;
unsigned short usError = 0;
int nPlayTime = 0;
unsigned char cBillingUser = 0;
unsigned char cBillingType = 0;
unsigned char cAdminLevel = 0;
const CHAR_VIEW* lpCharView = 0;
unsigned long dwCharViewNum = 0;
// WORK_LIST 2.1 계정 국적 추가
unsigned char cAccountNation = 0;
sGuildData GuildData[PktULDAck::MAX_CHAR_VIEW];
memset(&GuildData[0], 0, sizeof(sGuildData) * PktULDAck::MAX_CHAR_VIEW);
STORE_INFO storeInfo;
memset(&storeInfo, 0, sizeof(STORE_INFO));
using namespace DataStorage;
CSessionData* lpSessionData = CSessionDataMgr::GetInstance().GetOpenSession(dwUID);
// 세션 얻기
if(0 == lpSessionData)
{
ERRLOG1(g_Log, "UID:%10u / 유저 로그인 실패 : 세션이 없습니다", dwUID);
usError = 1;
}
// 세션 ID검사
else if(dwSessionID != lpSessionData->GetSessionID())
{
ERRLOG3(g_Log, "UID:%10u / SessionID:%10u / ReceivedSessionID:%10u / "
"유저 로그인 실패 : - 세션ID가 다릅니다",
dwUID, lpSessionData->GetSessionID(), dwSessionID);
usError = 1;
}
else
{
unsigned char cAgentServerType = static_cast<unsigned char>(
CServerSetup::GetInstance().GetAgentServerType());
switch(cAgentServerType)
{
case UnifiedConst::Part1:
case UnifiedConst::Part1Unified:
// 있을 수 없다. 이건 파트 2서버라구!
usError = 1;
SERLOG0(g_Log, "Part2 서버를 Part1설정으로 켜려고 하셨습니다. 서버를 다시 켜 주십시오");
break;
case UnifiedConst::ROW:
case UnifiedConst::Part2Unified:
// Part2 / Part2 통합서버는, 읽어올 UserInfo가 하나뿐이다.
lpSessionData->SetOldServerGroupID(cAgentServerType);
break;
case UnifiedConst::Part2Selectable:
// 선택을 안 하고 그냥 UserLogin을 보내면, 신규/기존인가에 따라
// UnifiedConst::Part2Selectable 번 혹은 1번에서 데이터를 읽어온다.
break;
}
// 유저 로그인
if(0 == usError)
{
if (!(lpSessionData->GetFirstLogin() & UnifiedConst::SELECTED_PART2))
{
/*
ERRLOG2(g_Log, "UID:%10u / FirstLogin:%d / "
"UserLogin 까지 진입했는데, Part2 에서 창고 선택한 적 없는 것처럼 되어 있음. 값을 세팅함.",
lpSessionData->GetUID(), lpSessionData->GetFirstLogin());
*/
lpSessionData->SetFirstLogin(
lpSessionData->GetFirstLogin() | UnifiedConst::SELECTED_PART2);
DBComponent::GameDB::UpdateUserFirstLogin(CDBSingleObject::GetInstance(),
lpSessionData->GetUID(), lpSessionData->GetFirstLogin());
}
CBilling& Billing = lpSessionData->GetBilling();
nPlayTime = Billing.GetPlayTime();
cBillingUser = (0 == Billing.GetCRMData()) ? 0 : 1;
cBillingType = Billing.GetBillingType();
cAdminLevel = lpSessionData->GetAdminLevel();
lpCharView = lpSessionData->GetCharView(0);
dwCharViewNum = USER_INFO::MAX_CHAR_NUM;
// WORK_LIST 2.1 계정 국적 추가
cAccountNation = lpSessionData->GetAccountNation();
// 길드 및 국적 정보 셋팅
for (int i=0; i< USER_INFO::MAX_CHAR_NUM; ++i)
{
if (0 != lpCharView[i].CID)
{
if (lpCharView[i].GID)
{
Guild::CGuildDB* lpGuild = static_cast<Guild::CGuildDB*>(
Guild::CGuildDBMgr::GetInstance().GetGuild( lpCharView[i].GID ));
if (lpGuild)
{
GuildData[i].m_cNation = lpGuild->GetNation();
strcpy(GuildData[i].m_szName, lpGuild->GetName());
}
}
else
{
// WORK_LIST 2.1 계정 국적 추가
GuildData[i].m_cNation = 0;
strcpy(GuildData[i].m_szName, "");
// switch (lpCharView[i].Race)
// {
// case CClass::RaceType::HUMAN: GuildData[i].m_cNation = Creature::KARTERANT; break;
// case CClass::RaceType::AKHAN: GuildData[i].m_cNation = Creature::MERKADIA; break;
// default: GuildData[i].m_cNation = Creature::STATELESS; break;
// }
}
}
}
// 로그인한다.
// PlayTime을 Login 상태로 바꾼다.
using namespace DBComponent;
GameDB::GetUnifiedItemStoreInfo(CDBSingleObject::GetInstance(), dwUID,
lpSessionData->GetOldServerGroupID(), &storeInfo, true);
KeyInfo* pKeyInfo = lpSessionData->GetKeyInfo();
memset(pKeyInfo, 0, sizeof(KeyInfo));
//GameDB::GetKeyInfo(CDBSingleObject::GetInstance(), pKeyInfo, dwUID);
lpSessionData->LogUserData("캐릭터 뷰 얻기 성공");
}
}
// WORK_LIST 2.1 계정 국적 추가
if(!SendPacket::UserLogin(SendStream, dwRequestKey, dwUID,
lpCharView, GuildData, &storeInfo, dwCharViewNum, cAccountNation, nPlayTime, cAdminLevel,
cBillingUser, cBillingType, cLoginType, usError))
{
ERRLOG1(g_Log, "UID:%10u / 캐릭터 뷰 얻기 실패 : 캐릭터 뷰 전송 실패", dwUID);
return false;
}
return true;
}
bool UserLogout(CSendStream& SendStream, PktULoD* lpPktULoD)
{
unsigned long dwSessionID = lpPktULoD->m_dwSessionID;
unsigned long dwUID = lpPktULoD->m_dwUserID;
// 접속 DB에서 유저 검사
using namespace DataStorage;
CSessionData* lpSessionData = CSessionDataMgr::GetInstance().GetOpenSession(dwUID);
// 세션 얻기
if(0 == lpSessionData)
{
ERRLOG1(g_Log, "UID:%10u / 유저 로그아웃 실패 : 세션이 없습니다", dwUID);
}
// 세션 ID검사
else if(dwSessionID != lpSessionData->GetSessionID())
{
ERRLOG3(g_Log, "UID:%10u / SessionID:%10u / RSessionID:%10u / 유저 로그아웃 실패 : 세션ID가 다릅니다",
dwUID, lpSessionData->GetSessionID(), dwSessionID);
}
else if(!lpSessionData->UserDisable())
{
ERRLOG1(g_Log, "UID:%10u / 유저 로그아웃 실패 : 유저 비활성화 실패", dwUID);
}
else
{
// 게임타임을 업데이트한다.
// 로그아웃한다.
// PlayTime을 Logout 상태로 바꾼다.
INFLOG1(g_Log, "UID:%10u / 유저 로그아웃 성공 : 유저를 비활성화했습니다.", dwUID);
return true;
}
return false;
}
bool UserMove(CSendStream& SendStream, PktUMvD* lpPktUMvD)
{
unsigned long dwSessionID = lpPktUMvD->m_dwSessionID;
unsigned long dwUID = lpPktUMvD->m_dwUserID;
// 접속 DB에서 유저 검사
using namespace DataStorage;
CSessionData* lpSessionData = CSessionDataMgr::GetInstance().GetOpenSession(dwUID);
// 세션 얻기
if(0 == lpSessionData)
{
ERRLOG1(g_Log, "UID:%10u / 유저 이동(캐릭터 선택) 실패 : 세션이 없습니다", dwUID);
}
// 세션 ID검사
else if(dwSessionID != lpSessionData->GetSessionID())
{
ERRLOG3(g_Log, "UID:%10u / SessionID:%10u / ReceivedSessionID:%10u / "
"유저 이동(캐릭터 선택) 실패 : 세션ID가 다릅니다",
dwUID, lpSessionData->GetSessionID(), dwSessionID);
}
else if(!lpSessionData->UserMove())
{
ERRLOG1(g_Log, "UID:%10u / 유저 이동(캐릭터 선택) 실패 : 유저 이동 실패", dwUID);
}
else
{
return true;
}
return false;
}
// WORK_LIST 2.1 계정 국적 추가
bool SelectAccountNation(CSendStream& SendStream, PktSAND* lpPktSAND)
{
unsigned long dwUID = lpPktSAND->m_dwUserID;
unsigned char cType = lpPktSAND->m_cType;
unsigned char cAccountNation = lpPktSAND->m_cAccountNation;
unsigned long dwRequestKey = lpPktSAND->m_dwRequestKey;
unsigned short usError = 0;
using namespace DataStorage;
CSessionData* lpSessionData = CSessionDataMgr::GetInstance().GetOpenSession(dwUID);
// 세션 얻기
if(0 == lpSessionData)
{
ERRLOG1(g_Log, "UID:%10u / 계정 국적 설정 및 변경 실패 : 세션이 없습니다", dwUID);
usError = 4;
}
else
{
unsigned char cOldServerGroupID = lpSessionData->GetOldServerGroupID();
// 계정 국가 설정
if ( PktSAND::TYPE_SET == cType )
{
if (!DBComponent::GameDB::UpdateAccountNation(
CDBSingleObject::GetInstance(), dwUID, cAccountNation, cOldServerGroupID))
{
ERRLOG3(g_Log, "UID:%10u / AccountNation:%d / ServerGroupID:%d / 계정 국적 설정 실패 : UpdateAccountNation DB에러",
dwUID, cAccountNation, cOldServerGroupID);
usError = 2;
}
}
// WORK_LIST 2.3 계정 국적 변경 기능 구현
// 계정 국가 변경
else if ( PktSAND::TYPE_CHANGE == cType )
{
if ( lpSessionData->GetAccountNation() != cAccountNation )
{
if ( !DBComponent::GameDB::UpdateAccountNation( CDBSingleObject::GetInstance(),
dwUID, cAccountNation, cOldServerGroupID ) )
{
ERRLOG3(g_Log, "UID:%10u / AccountNation:%d / ServerGroupID:%d / 계정 국적 설정 실패 : UpdateAccountNation DB에러",
dwUID, cAccountNation, cOldServerGroupID);
usError = 2;
}
else
{
unsigned char cOldAccountNation = lpSessionData->GetAccountNation();
unsigned long aryGID[ USER_INFO::MAX_CHAR_NUM ] = { 0, 0, 0, 0, 0 };
unsigned long aryFame[ USER_INFO::MAX_CHAR_NUM ] = { 0, 0, 0, 0, 0 };
unsigned long aryOldFame[ USER_INFO::MAX_CHAR_NUM ] = { 0, 0, 0, 0, 0 };
unsigned long aryOldGID[ USER_INFO::MAX_CHAR_NUM ] = { 0, 0, 0, 0, 0 };
for (int i=0; i < USER_INFO::MAX_CHAR_NUM; ++i)
{
const CHAR_VIEW* pCharView = lpSessionData->GetCharView(i);
if ( 0 != pCharView->CID )
{
aryOldFame[ i ] = pCharView->Fame;
aryOldGID[ i ] = pCharView->GID;
Guild::CGuildDB* lpGuild = static_cast<Guild::CGuildDB*>(
Guild::CGuildDBMgr::GetInstance().GetGuild( pCharView->GID ));
if (NULL != lpGuild)
{
// 명성이 5000(미국은 1000) 이상이었다면, 명성치에 패널티 적용
const unsigned short wFamePaneltyValue1st = CSessionData::FAME_PANELTY_VALUE_1ST;
if ( pCharView->Fame > wFamePaneltyValue1st )
{
if ( pCharView->Fame < CSessionData::FAME_PANELTY_VALUE_2ND )
{
lpGuild->AddMemberFame( Guild::TYPE_VALUE, pCharView->CID,
int(wFamePaneltyValue1st - pCharView->Fame) );
lpSessionData->SetCharViewFame( pCharView->CID, wFamePaneltyValue1st );
}
else
{
lpGuild->AddMemberFame( Guild::TYPE_HALF, pCharView->CID, 0 );
lpSessionData->SetCharViewFame( pCharView->CID, pCharView->Fame / 2 );
}
}
if ( 1 < lpGuild->GetCurrentMemberNum() )
{
bool bLeaveGuild = true;
// 길드 마스터의 경우 권한을 양도한 후 탈퇴시킨다.
if (pCharView->CID == lpGuild->GetMaster().m_dwCID)
{
unsigned long dwNewMaster = lpGuild->SetNewMaster();
if (0 != dwNewMaster)
{
SendPacket::GuildCmd(&SendStream, lpGuild->GetGID(), dwNewMaster, MASTER,
PktGuildCmd::GC_SETUP_TITLE, NULL, NULL, PktBase::NO_SERVER_ERR);
DETLOG3(g_Log, "GID:%10u 길드마스터(이전:%10u, 현재:%10u)가 변경되었습니다. - 길드마스터 국적 변경",
lpGuild->GetGID(), pCharView->CID, dwNewMaster);
}
else
{
DETLOG1(g_Log, "GID:%10u 길드가 해체되었습니다. - 길드마스터 국적 변경(양도할 길원 없음)", lpGuild->GetGID());
CGuildDBMgr::GetInstance().DissolveGuild(lpGuild->GetGID(),
PktCreateGuild::NONE_NEXT_GUILDMASTER_BY_GUILDMASTER_OUT);
bLeaveGuild = false;
}
}
if (true == bLeaveGuild)
{
// 길드 국적과 변경된 계정 국적이 다르므로, 탈퇴 처리 시킨다.
if ( lpGuild->LeaveMember( pCharView->CID ) )
{
// 길드 탈퇴 정보를 모든 게임 서버로 전송
SendPacket::GuildCmd( NULL, pCharView->GID, pCharView->CID, 0,
PktGuildCmd::GC_KICK, NULL, NULL, PktBase::NO_SERVER_ERR );
}
else
{
// 길드 탈퇴 실패
ERRLOG3(g_Log, "UID:%10u / CID:%10u / GID:%10u 길드 강제 탈퇴 실패 : 계정 국적 변경으로 인한 탈퇴 실패",
dwUID, pCharView->CID, pCharView->GID);
}
}
}
else
{
// 길드원이 한명뿐이므로, 길드를 해체한다.
DETLOG1(g_Log, "GID:%10u 길드가 해체되었습니다. - 길드마스터 국적 변경(길마뿐인 길드)", lpGuild->GetGID());
CGuildDBMgr::GetInstance().DissolveGuild(
lpGuild->GetGID(), PktCreateGuild::NONE_NEXT_GUILDMASTER_BY_GUILDMASTER_OUT);
}
lpSessionData->SetCharViewGID( pCharView->CID, 0 );
}
else
{
// 명성이 5000(미국은 1000) 이상이었다면, 명성치에 패널티 적용
const unsigned short wFamePaneltyValue1st = CSessionData::FAME_PANELTY_VALUE_1ST;
if ( pCharView->Fame > wFamePaneltyValue1st )
{
CCharacterData* lpCharacterData = 0;
CSessionData* lpCharSessionData =
CSessionDataMgr::GetInstance().GetCharLoadedSession( pCharView->CID );
if ( 0 == lpCharSessionData || 0 == (lpCharacterData = lpCharSessionData->GetCharacterData()) )
{
// 캐릭터가 안매달려있는 경우, 캐릭터를 불러온다.
lpCharacterData = static_cast<CCharacterData*>(
CCharacterDataMgr::GetInstance().GetLogoutData( pCharView->CID ));
if ( 0 != lpCharacterData )
{
CHAR_INFOST charInfoST = lpCharacterData->GetInfo();
if ( pCharView->Fame < CSessionData::FAME_PANELTY_VALUE_2ND )
{
charInfoST.Fame = wFamePaneltyValue1st;
lpSessionData->SetCharViewFame( pCharView->CID, wFamePaneltyValue1st );
}
else
{
charInfoST.Fame /= 2;
lpSessionData->SetCharViewFame( pCharView->CID, pCharView->Fame / 2 );
}
lpCharacterData->SetInfo( charInfoST );
}
}
else if( CSessionData::SE_CHAR_ENABLED == lpCharSessionData->GetSessionState() )
{
ERRLOG1( g_Log, "CID:%10u 캐릭터 선택화면에서 계정 국적 변경시, 이미 게임에 로드된 캐릭터가 존재합니다.", pCharView->CID );
}
}
lpSessionData->SetCharViewGID( pCharView->CID, 0 );
}
aryGID[ i ] = pCharView->GID;
aryFame[ i ] = pCharView->Fame;
/*
- 국적변경 관련 로그
UID CID 캐릭터명 변경전국가 변경후국가 기존명성 변경명성
현재레벨 이전길드ID 새길드ID 파티ID
*/
INFLOG11(g_Log, "국적로그\t%10u\t%10u\t%s\t%s\t%s\t%u\t%u\t%u\t%u\t%u\t%u\t",
dwUID, pCharView->CID, pCharView->Name,
Creature::GetShortNationName(cOldAccountNation),
Creature::GetShortNationName(cAccountNation),
aryOldFame[ i ], aryFame[ i ], pCharView->Level,
aryOldGID[ i ], aryGID[ i ], pCharView->PID);
}
}
// 국적 변경으로 인해 길드 ID가 바뀐 정보를 Auth 서버로 보내서, Client 가 갱신하도록 한다.
SendPacket::NationChangeResult(SendStream, dwRequestKey, dwUID, aryGID, aryFame);
}
}
else
{
ERRLOG3(g_Log, "UID:%10u / Old_AccountNation:%d / New_AccountNation:%d / 계정 국적 변경 실패 : 같은 국적임",
dwUID, lpSessionData->GetAccountNation(), cAccountNation);
usError = 5; // 이미 변경할려는 국적이다.
}
}
if (0 == usError)
{
// 계정 국가 설정 및 변경 성공
RULLOG2(g_Log, "UID:%10u / AccountNation:%d 계정 국가 설정", dwUID, cAccountNation);
// 계정 국가 설정
lpSessionData->SetAccountNation( cAccountNation );
}
}
return SendPacket::SelectAccountNation(SendStream, dwRequestKey, dwUID, cType, cAccountNation, usError);
}
bool CharSelect(CSendStream& SendStream, PktCSD* lpPktCSD)
{
// 서버 세션 얻기
unsigned long dwUID = lpPktCSD->m_dwUserID;
unsigned long dwCID = lpPktCSD->m_dwCharID;
unsigned long dwRequestKey = lpPktCSD->m_dwRequestKey;
unsigned short usError = 0;
unsigned char cZone = 1;
using namespace DataStorage;
CSessionData* lpSessionData = CSessionDataMgr::GetInstance().GetOpenSession(dwUID);
CCharacterData* lpCharacterData = 0;
// 세션 얻기
if(0 == lpSessionData)
{
ERRLOG1(g_Log, "UID:%10u / 캐릭터 선택 실패 : 세션이 없습니다", dwUID);
usError = 5;
}
// 캐릭터 아이디 검사
else if (!lpSessionData->HasCharacter(dwCID))
{
const USER_INFO& userInfo = lpSessionData->GetUserInfo();
// WORK_LIST 2.1 계정 국적 추가
ERRLOG8(g_Log, "UID:%10u / SelectedCID:%10u / Char1:%10u / Char2:%10u / Char3:%10u / Char4:%10u / Char5:%10u / Nation:%d"
"캐릭터 선택 실패 : 소유하고 있지 않은 캐릭터입니다.",
dwUID, dwCID, userInfo.CharID[0], userInfo.CharID[1], userInfo.CharID[2],
userInfo.CharID[3], userInfo.CharID[4], userInfo.Nation);
usError = 3;
}
else
{
if (!lpSessionData->LoadData(dwCID))
{
ERRLOG2(g_Log, "UID:%10u / SelectedCID:%10u / 캐릭터 선택 실패 : 캐릭터 로드 실패", dwUID, dwCID);
usError = 3;
}
else
{
CCharacterData* lpCharacterData = lpSessionData->GetCharacterData();
lpCharacterData->SetUID(dwUID);
SERVER_ID serverID;
serverID.dwID = lpCharacterData->GetInfoEx().ServerID;
// 국가전쟁 미 참여시 공헌훈장 포인트 삭감.
unsigned char cRealmPoint = lpCharacterData->GetRealmPoint();
unsigned long dwRealmCount_Out = 0;
// 서버 세션이 시작되면
// 로그아웃 시간을 기점으로 공헌훈장의 포인트 추가 삭감을
// 계산한다.
TIME* pTime = lpCharacterData->GetLogoutTime();
if(pTime)
{
CTime timeLoggout(pTime->Year, pTime->Month, pTime->Day, pTime->Hour, pTime->Minute, pTime->Second);
CGameTimeDBMgr::GetInstance().CheckRealmCount(timeLoggout, &dwRealmCount_Out);
if(lpCharacterData->GetRealmCheckPoint() && dwRealmCount_Out)
{
dwRealmCount_Out -= 1;
lpCharacterData->SetRealmCheckPoint(0);
lpCharacterData->SetRealmMinute(0);
if(cRealmPoint<=dwRealmCount_Out)
{
lpCharacterData->SetRealmPoint(0);
}
else
{
cRealmPoint -= static_cast<unsigned char>(dwRealmCount_Out);
lpCharacterData->SetRealmPoint(cRealmPoint);
}
}
else if(dwRealmCount_Out)
{
if(cRealmPoint<=dwRealmCount_Out)
{
lpCharacterData->SetRealmPoint(0);
}
else
{
cRealmPoint -= static_cast<unsigned char>(dwRealmCount_Out);
lpCharacterData->SetRealmPoint(cRealmPoint);
}
lpCharacterData->SetRealmMinute(0);
}
else if(lpCharacterData->GetRealmCheckPoint() && !dwRealmCount_Out)
{
if(CGameTimeDBMgr::GetInstance().GetCurrentGameTime(GameTime::REALM)!=GameTime::RT_REALM_WAR)
{
unsigned char cRealmPoint = lpCharacterData->GetRealmPoint();
lpCharacterData->SetRealmCheckPoint(0);
lpCharacterData->SetRealmMinute(0);
if(cRealmPoint<DBAgent::DataStorage::CSessionData::MAX_REALM_POINT)
{
cRealmPoint++;
lpCharacterData->SetRealmPoint(cRealmPoint);
}
}
}
CTime timeLogin = CTime::GetCurrentTime();
pTime->Year = timeLogin.GetYear();
pTime->Month = timeLogin.GetMonth();
pTime->Day = timeLogin.GetDay();
pTime->Hour = timeLogin.GetHour();
pTime->Minute = timeLogin.GetMinute();
pTime->Second = timeLogin.GetSecond();
}
// edith 2010.01.02 공헌포인트를 길드원 정보에 따라 처리해주는 함수.
unsigned int GID = lpCharacterData->GetGID();
Guild::CGuildDB* lpGuild = static_cast<Guild::CGuildDB*>(
Guild::CGuildDBMgr::GetInstance().GetGuild( GID ));
if(lpGuild)
{
unsigned char MaxNum = lpGuild->GetMaxMemberNum();
unsigned char CurNum = lpGuild->GetCurrentMemberNum();
lpCharacterData->SetRealmPoint(MaxNum/10);
}
else
lpCharacterData->SetRealmPoint(0);
if (CServerSetup::AuthServer == serverID.GetType() || 0 == serverID.dwID)
{
// 초기화되어 있지 않은 캐릭터
// cZone = CServerSetup::GetInstance().IsBattleAgentServer()
// ? SERVER_ID::BATTLE_SERVER : SERVER_ID::ZONE12;
if(CServerSetup::GetInstance().IsBattleAgentServer())
cZone = SERVER_ID::BATTLE_SERVER;
else
{
unsigned char cRace = (0 != lpCharacterData) ? lpCharacterData->GetRace() : -1;
if(cRace == CHAR_CREATE::HUMAN)
cZone = SERVER_ID::ZONE1;
else
cZone = SERVER_ID::ZONE2;
}
}
else
{
cZone = serverID.sID.ID;
if (SERVER_ID::BATTLE_ZONE == cZone)
{
cZone = SERVER_ID::ZONE3;
}
// edith 2009.06.13
// 해당 종족 검사
if (!lpSessionData->CheckCharZone(cZone))
{
// 0 : Human
// 1 : Akhan
// -1 : 캐릭터 데이터 연결 안됨
unsigned char cRace = (0 != lpCharacterData) ? lpCharacterData->GetRace() : -1;
unsigned char cStartZone = lpSessionData->GetCharStartZone(cRace);
/*
if(cRace == CHAR_CREATE::HUMAN)
cStartZone = SERVER_ID::ZONE1;
else
cStartZone = SERVER_ID::ZONE2;
*/
/*
if(SERVER_ID::ZONE5 == cZone && !CGameTimeDBMgr::GetInstance().IsEnterTime())
{
// 테섭용 신규존 진입제한에 걸렸음.
DETLOG5(g_Log, "UID:%10u / CID:%10u / Zone:%u / StartZone:%u / Race:%u / 신규존 진입제한 : 시작 존으로 이동합니다",
dwUID, dwCID, cZone, cStartZone, cRace);
}
else
{
DETLOG5(g_Log, "UID:%10u / CID:%10u / Zone:%u / StartZone:%u / Race:%u / 잘못된 존 체크 : 시작 존으로 이동합니다",
dwUID, dwCID, cZone, cStartZone, cRace);
}
*/
DETLOG5(g_Log, "UID:%10u / CID:%10u / Zone:%u / StartZone:%u / Race:%u / 잘못된 존 체크 : 시작 존으로 이동합니다",
dwUID, dwCID, cZone, cStartZone, cRace);
cZone = cStartZone;
}
/*
// edith 2009.06.13 Character Select GameTime Over
if(CGameTimeDBMgr::GetInstance().IsGuildWarTime() && cZone == SERVER_ID::CAPITAL)
{
DETLOG5(g_Log, "UID:%10u / CID:%10u / Zone:%u / StartZone:%u / Race:%u / IsGuildWarTime 존 체크 : 시작 존으로 이동합니다",
dwUID, dwCID, cZone, cStartZone, cRace);
cZone = cStartZone;
}
else if(CGameTimeDBMgr::GetInstance().IsRealmWarTime() && (SERVER_ID::STONE_WAR1 <= cZone && cZone <= SERVER_ID::STONE_WAR3))
{
DETLOG5(g_Log, "UID:%10u / CID:%10u / Zone:%u / StartZone:%u / Race:%u / IsRealmWarTime 존 체크 : 시작 존으로 이동합니다",
dwUID, dwCID, cZone, cStartZone, cRace);
cZone = cStartZone;
}
*/
}
INFLOG2(g_Log, "UID:%10u / SelectedCID:%10u / 캐릭터 선택 성공", dwUID, dwCID);
lpSessionData->UnloadData();
}
}
return SendPacket::CharSelect(SendStream, dwRequestKey, cZone, usError);
}
bool CharCreate(CSendStream& SendStream, PktCCD* lpPktCCD)
{
unsigned long dwUID = lpPktCCD->m_dwUserID;
unsigned long dwSlot = lpPktCCD->m_dwSlot;
unsigned long dwGold = lpPktCCD->m_dwGold;
unsigned long dwRequestKey = lpPktCCD->m_dwRequestKey;
unsigned long dwCID = 0;
CHAR_VIEW CharView = {0,};
unsigned short usError = 0;
using namespace DataStorage;
CSessionData* lpSessionData = CSessionDataMgr::GetInstance().GetOpenSession(dwUID);
// 세션 얻기
if(0 == lpSessionData)
{
ERRLOG1(g_Log, "UID:%10u / 캐릭터 생성 실패 : 세션이 없습니다", dwUID);
usError = PktCCAck::NULL_SESSION;
}
else
{
// 스킬 세팅
SKILL Skill(1, 1);
switch(lpPktCCD->m_CharCreate.Class)
{
case CClass::Fighter: Skill.SSlot[0] = SKILLSLOT(0x8104, 0, 1); break;
case CClass::Rogue: Skill.SSlot[0] = SKILLSLOT(0x8205, 0, 1); break;
case CClass::Mage: Skill.SSlot[0] = SKILLSLOT(0x8303, 0, 1); break;
case CClass::Acolyte: Skill.SSlot[0] = SKILLSLOT(0x8405, 0, 1); break;
case CClass::Combatant: Skill.SSlot[0] = SKILLSLOT(0x9104, 0, 1); break;
case CClass::Officiator: Skill.SSlot[0] = SKILLSLOT(0x9202, 0, 1); break;
default:
ERRLOG3(g_Log, "UID:%10u / CID:%10u / Class:%u/ 캐릭터 생성 : 스킬 넣기 실패 - 잘못된 클래스입니다",
dwUID, dwCID, lpPktCCD->m_CharCreate.Class);
usError = PktCCAck::FAIL_INSERT_DATA;
break;
}
// Edith 2008.06.14 캐릭터 생성시 생성값 문제 검출
if(dwGold > 0)
{
ERRLOG3(g_Log, "UID:%10u / CID:%10u / Gold:%u/ 캐릭터 생성 : 골드값 이상", dwUID, dwCID, dwGold);
usError = PktCCAck::FAIL_INSERT_DATA;
}
else if(lpPktCCD->m_CharCreate.Face < 0 && lpPktCCD->m_CharCreate.Face >= 7)
{
ERRLOG3(g_Log, "UID:%10u / CID:%10u / Face:%u/ 캐릭터 생성 : 얼굴 이상", dwUID, dwCID, lpPktCCD->m_CharCreate.Hair);
usError = PktCCAck::FAIL_INSERT_DATA;
}
else if(lpPktCCD->m_CharCreate.Race == 0)
{
if(lpPktCCD->m_CharCreate.Sex == 1) // 인간 남자
{
if(lpPktCCD->m_CharCreate.Hair < 0 && lpPktCCD->m_CharCreate.Hair >= 5)
{
ERRLOG3(g_Log, "UID:%10u / CID:%10u / Hair:%u/ 캐릭터 생성 : 헤어 이상", dwUID, dwCID, lpPktCCD->m_CharCreate.Hair);
usError = PktCCAck::FAIL_INSERT_DATA;
}
}
else if(lpPktCCD->m_CharCreate.Sex == 2)// 인간 여자
{
if(lpPktCCD->m_CharCreate.Hair < 0 && lpPktCCD->m_CharCreate.Hair >= 7)
{
ERRLOG3(g_Log, "UID:%10u / CID:%10u / Hair:%u/ 캐릭터 생성 : 헤어 이상", dwUID, dwCID, lpPktCCD->m_CharCreate.Hair);
usError = PktCCAck::FAIL_INSERT_DATA;
}
}
else
{
ERRLOG3(g_Log, "UID:%10u / CID:%10u / Sex:%u/ 캐릭터 생성 : 성별 이상", dwUID, dwCID, lpPktCCD->m_CharCreate.Sex);
usError = PktCCAck::FAIL_INSERT_DATA;
}
}
else if(lpPktCCD->m_CharCreate.Race == 1)
{
if(lpPktCCD->m_CharCreate.Sex == 1) // 아칸남자
{
if(lpPktCCD->m_CharCreate.Hair < 0 && lpPktCCD->m_CharCreate.Hair >= 7)
{
ERRLOG3(g_Log, "UID:%10u / CID:%10u / Hair:%u/ 캐릭터 생성 : 헤어 이상", dwUID, dwCID, lpPktCCD->m_CharCreate.Hair);
usError = PktCCAck::FAIL_INSERT_DATA;
}
}
else if(lpPktCCD->m_CharCreate.Sex == 2) // 아칸여자
{
if(lpPktCCD->m_CharCreate.Hair < 0 && lpPktCCD->m_CharCreate.Hair >= 7)
{
ERRLOG3(g_Log, "UID:%10u / CID:%10u / Hair:%u/ 캐릭터 생성 : 헤어 이상", dwUID, dwCID, lpPktCCD->m_CharCreate.Hair);
usError = PktCCAck::FAIL_INSERT_DATA;
}
}
else
{
ERRLOG3(g_Log, "UID:%10u / CID:%10u / Sex:%u/ 캐릭터 생성 : 성별 이상", dwUID, dwCID, lpPktCCD->m_CharCreate.Sex);
usError = PktCCAck::FAIL_INSERT_DATA;
}
}
else
{
ERRLOG3(g_Log, "UID:%10u / CID:%10u / Race:%u/ 캐릭터 생성 : 종족 이상", dwUID, dwCID, lpPktCCD->m_CharCreate.Race);
usError = PktCCAck::FAIL_INSERT_DATA;
}
int iStat = lpPktCCD->m_CharCreate.STR+lpPktCCD->m_CharCreate.DEX
+lpPktCCD->m_CharCreate.CON+lpPktCCD->m_CharCreate.INT+lpPktCCD->m_CharCreate.WIS - 100;
if(iStat != 5)
{
ERRLOG3(g_Log, "UID:%10u / CID:%10u / iStat:%u/ 캐릭터 생성 : 스텟 이상", dwUID, dwCID, iStat+100);
usError = PktCCAck::FAIL_INSERT_DATA;
}
if (usError != 0)
{
;
}
// DB에 캐릭터 생성
else if (!DBComponent::GameDB::InsertChar(CDBSingleObject::GetInstance(), dwUID, dwSlot,
lpPktCCD->m_CharCreate, dwGold, lpPktCCD->m_Pos, Skill,
lpSessionData->GetOldServerGroupID(), dwCID))
{
ERRLOG1(g_Log, "UID:%10u / 캐릭터 생성 실패 : DB에러", dwUID);
// 캐릭터 생성 실패
usError = PktCCAck::FAIL_INSERT_DATA;
}
else if (-1 == dwCID)
{
// 동일한 이름을 가지고 있는 캐릭터가 있는 경우
usError = PktCCAck::EXIST_CHAR_NAME;
}
else if (-2 == dwCID)
{
// 동일한 이름을 가지고 있는 캐릭터가 있는 경우
usError = PktCCAck::EXIST_SLOT;
}
else if (!lpSessionData->GetUserInfoFromDB(CDBSingleObject::GetInstance()))
{
// 캐릭터를 생성했으니. 뷰를 다시한번 로드한다.
ERRLOG1(g_Log, "UID:%10u / 캐릭터 생성 실패 : 캐릭터 뷰 재로드 실패.", dwUID);
usError = PktCCAck::VIEW_RELOAD_FAILED;
}
else if (!lpSessionData->GetCharView(dwCID, CharView))
{
// 뷰를 얻어서 보내 준다.
ERRLOG1(g_Log, "UID:%10u / 캐릭터 생성 실패 : 캐릭터 뷰 얻기 실패.", dwUID);
usError = PktCCAck::VIEW_RELOAD_FAILED;
}
else
{
// 캐릭터 생성 성공.
RULLOG4(g_Log, "UID:%10u / CID:%10u / 캐릭터 [%s]%s 생성",
dwUID, dwCID, (CharView.Race == 0) ? "Human" : "Akhan", CharView.Name);
/*
- 국적변경 관련 로그
UID CID 캐릭터명 변경전국가 변경후국가 기존명성 변경명성
현재레벨 이전길드ID 새길드ID 파티ID
*/
INFLOG11(g_Log, "국적로그\t%10u\t%10u\t%s\t%s\t%s\t%u\t%u\t%u\t%u\t%u\t%u\t",
dwUID, dwCID, CharView.Name,
Creature::GetShortNationName(lpSessionData->GetUserInfo().Nation),
Creature::GetShortNationName(lpSessionData->GetUserInfo().Nation),
0, CharView.Fame, CharView.Level,
0, CharView.GID, CharView.PID);
}
}
return SendPacket::CharCreate(SendStream,
dwRequestKey, dwCID, dwSlot, CharView, usError);
}
bool CharDelete(CSendStream& SendStream, PktCDD* lpPktCDD)
{
unsigned long dwUID = lpPktCDD->m_dwUserID;
unsigned long dwCID = lpPktCDD->m_dwCharID;
unsigned long dwSlot = lpPktCDD->m_dwSlotNum;
unsigned long dwRequestKey = lpPktCDD->m_dwRequestKey;
unsigned short usError = 0;
using namespace DataStorage;
CSessionData* lpSessionData = CSessionDataMgr::GetInstance().GetOpenSession(dwUID);
// 세션 얻기
if(0 == lpSessionData)
{
ERRLOG1(g_Log, "UID:%10u / 캐릭터 삭제 실패 : 세션이 없습니다", dwUID);
usError = 4;
}
else if (CCharacterDataMgr::GetInstance().IsDataLoginDB(dwCID) ||
CSessionData::SE_CHAR_ENABLED == lpSessionData->GetSessionState())
{
// 활성화된 캐릭터 삭제 시도
ERRLOG2(g_Log, "UID:%10u / CID:%10u / 캐릭터 삭제 실패 : 활성화된 캐릭터 삭제 시도", dwUID, dwCID);
usError = 3;
}
else
{
const CHAR_VIEW* lpCharView =
lpSessionData->GetCharView(static_cast<unsigned char>(dwSlot));
if(0 == lpCharView)
{
ERRLOG3(g_Log, "UID:%10u / CID:%10u / Slot:%u / 캐릭터 삭제 실패 : 원하는 슬롯에 뷰 없음",
dwUID, dwCID, dwSlot);
usError = 2;
}
else if(lpCharView->CID != dwCID)
{
ERRLOG4(g_Log, "UID:%10u / CID:%10u / DeleteCID:%10u / Slot:%u / 캐릭터 삭제 실패 : 뷰의 CID와 지우려는 캐릭터의 CID다름",
dwUID, lpCharView->CID, dwCID, dwSlot);
usError = 2;
}
else
{
// DB로 부터 캐릭터 삭제
if(CServerSetup::GetInstance().IsBattleAgentServer())
{
if(!DBComponent::GameDB::DeleteCharBattleServer(
CDBSingleObject::GetInstance(), dwUID, dwCID,
static_cast<unsigned char>(dwSlot),
CServerSetup::GetInstance().GetServerGroup(),
lpSessionData->GetOldServerGroupID()))
{
ERRLOG3(g_Log, "UID:%10u / CID:%10u / Slot:%u / 캐릭터 삭제 실패 : DeleteCharBattleServer DB에러",
dwUID, dwCID, dwSlot);
usError = 2;
}
}
else
{
if (!DBComponent::GameDB::DeleteChar(
CDBSingleObject::GetInstance(), dwUID, dwCID,
static_cast<unsigned char>(dwSlot),
CServerSetup::GetInstance().GetServerGroup(),
lpSessionData->GetOldServerGroupID()))
{
ERRLOG3(g_Log, "UID:%10u / CID:%10u / Slot:%u / 캐릭터 삭제 실패 : DeleteChar DB에러",
dwUID, dwCID, dwSlot);
usError = 2;
}
}
if(0 == usError)
{
// 캐릭터 삭제 성공
RULLOG4(g_Log, "UID:%10u / CID:%10u / 캐릭터 [%s]%s 삭제",
dwUID, dwCID, (lpCharView->Race == 0) ? "Human" : "Akhan", lpCharView->Name);
// 캐릭터 초기화
lpSessionData->UnloadData();
lpSessionData->DelUnifiedCharData(dwCID);
}
}
}
return SendPacket::CharDelete(SendStream,
dwRequestKey, dwUID, dwSlot, dwCID, usError);
}
bool CreateItem(CSendStream& SendStream, unsigned long dwServerID,
Item::CItemSerialMgr& itemSerialMgr, PktCCID* lpPktCCID)
{
if (sizeof(PktCCID) < lpPktCCID->GetLen())
{
EQUIP Equip;
memset(&Equip, 0, sizeof(EQUIP));
Equip.dwSize = lpPktCCID->m_dwSize;
memcpy(Equip.Data, lpPktCCID + 1, lpPktCCID->m_dwSize);
if(!DBComponent::GameDB::UpdateEquip(
CDBSingleObject::GetInstance(), lpPktCCID->m_dwCharID, &Equip))
{
ERRLOG1(g_Log, "CID:%10u / 장비 업데이트 실패", lpPktCCID->m_dwCharID);
}
else
{
// 아이템 시리얼 업데이트
if(itemSerialMgr.SetItemSerial(lpPktCCID->m_dwItemSerial))
{
// 시리얼이 바뀌었으므로 DB에 업데이트한다.
if(!itemSerialMgr.SaveItemSerial(CDBSingleObject::GetInstance(), dwServerID))
{
ERRLOG3(g_Log, "CID:%10u / ServerID:0x%08X / Serial:0x%016I64X / 아이템 시리얼 업데이트 실패",
lpPktCCID->m_dwCharID, dwServerID, itemSerialMgr.GetItemSerial());
}
}
}
return true;
}
return false;
}
// TODO : FIX FOR BATTLEGROUND!
bool BGServerCharSlot(CSendStream& SendStream, PktBase* lpPktBase)
{
PktBGServerCharSlot* lpPktBGServerCharSlot = static_cast<PktBGServerCharSlot*>(lpPktBase);
unsigned long dwUID = lpPktBGServerCharSlot->m_dwUID;
unsigned long dwCID = lpPktBGServerCharSlot->m_dwCID;
unsigned char cGroup = lpPktBGServerCharSlot->m_cGroup;
unsigned short usError = 0;
char* lpBuffer = SendStream.GetBuffer(sizeof(PktBGServerCharSlotAck));
if(0 != lpBuffer)
{
PktBGServerCharSlotAck* lpPktBGServerCharSlotAck =
reinterpret_cast<PktBGServerCharSlotAck*>(lpBuffer);
lpPktBGServerCharSlotAck->m_dwCID = dwCID;
lpPktBGServerCharSlotAck->m_cGroup = cGroup;
memset(lpPktBGServerCharSlotAck->m_dwSlotCID, 0,
sizeof(unsigned long) * USER_INFO::MAX_CHAR_NUM);
memset(lpPktBGServerCharSlotAck->m_szSlotName, 0,
sizeof(char) * USER_INFO::MAX_CHAR_NUM * CHAR_INFOST::MAX_NAME_LEN);
unsigned char cOldServerGroupID = 0;
switch(CServerSetup::GetInstance().GetAgentServerType())
{
case UnifiedConst::Part1:
case UnifiedConst::Part1Unified:
default:
cOldServerGroupID = 0;
break;
case UnifiedConst::ROW:
case UnifiedConst::Part2Unified:
case UnifiedConst::Part2Selectable:
cOldServerGroupID = static_cast<unsigned char>(
CServerSetup::GetInstance().GetAgentServerType());
break;
}
USER_INFO userInfo;
memset(&userInfo, 0, sizeof(USER_INFO));
if (!DBComponent::GameDB::GetUserInfo(CDBSingleObject::GetInstance(),
dwUID, userInfo, cOldServerGroupID))
{
ERRLOG2(g_Log, "UID:%10u / 배틀로한으로 캐릭터 정보 주기 실패 : 유저 정보 얻기 실패 : %s",
dwUID, CDBSingleObject::GetInstance().GetErrorString());
usError = PktBGServerCharSlotAck::FAIL_NOT_USER;
}
else
{
CHAR_VIEW charView;
// WORK_LIST 2.1 계정 국적 추가 (배틀 로한에 Nation 정보를 줘야하나? 아직 추가안했음)
for (unsigned int nIndex = 0; nIndex < USER_INFO::MAX_CHAR_NUM; ++nIndex)
{
unsigned long dwLoadViewCID = userInfo.CharID[nIndex];
lpPktBGServerCharSlotAck->m_dwSlotCID[nIndex] = dwLoadViewCID;
if (0 != dwLoadViewCID)
{
memset(&charView, 0, sizeof(CHAR_VIEW));
if (!DBComponent::GameDB::GetCharView(CDBSingleObject::GetInstance(),
dwLoadViewCID, &charView))
{
ERRLOG3(g_Log, "UID:%10u / CID:%10u / 배틀로한으로 캐릭터 정보 주기 실패 : 캐릭터 뷰 얻기 실패 : %s",
dwUID, dwLoadViewCID, CDBSingleObject::GetInstance().GetErrorString());
usError = PktBGServerCharSlotAck::FAIL_NOT_CHAR;
break;
}
strncpy(lpPktBGServerCharSlotAck->m_szSlotName[nIndex],
charView.Name, CHAR_INFOST::MAX_NAME_LEN);
lpPktBGServerCharSlotAck->m_szSlotName[nIndex][CHAR_INFOST::MAX_NAME_LEN - 1] = 0;
}
}
}
return SendStream.WrapHeader(sizeof(PktBGServerCharSlotAck), CmdBGServerCharSlot, 0, usError);
}
return false;
}
bool UnifiedCharSelect(CSendStream& SendStream, PktBase* lpPktBase)
{
PktUnifiedCharSelectReq* lpUnifiedSelectReq = static_cast<PktUnifiedCharSelectReq*>(lpPktBase);
/*
Part2Unified
0 : 창고 가져온 적 없다
1 : Part1 통합에서 창고 가져왔다
2 : Part2 통합에서 창고 가져왔다.
Part2Selectable
*/
unsigned char cAgentServerType = static_cast<unsigned char>(
CServerSetup::GetInstance().GetAgentServerType());
using namespace DBAgent::DataStorage;
CSessionData* lpSessionData = 0;
unsigned long dwUID = lpUnifiedSelectReq->dwUID;
unsigned long dwRequestKey = lpUnifiedSelectReq->dwRequestKey;
unsigned short usError = 0;
unsigned char cSelectedServerGroupID = lpUnifiedSelectReq->cSelectedServerGroupID;
unsigned char cSelectedNation = lpUnifiedSelectReq->cSelectedNation;
bool bSupressSendAck = false;
switch(cAgentServerType)
{
case UnifiedConst::Part2Unified:
if(0 == (lpSessionData = CSessionDataMgr::GetInstance().GetOpenSession(dwUID)))
{
// 해당 UID가 없다.
ERRLOG1(g_Log, "UID:%10u / Part2Unified 캐릭터 선택 실패 - 세션이 닫혀 있습니다", dwUID);
usError = PktUnifiedCharSelectAck::SERVER_ERROR;
}
else
{
// 일단 데이터를 확인하고, 정리한 후에, Part1 DB중계서버에 선택 결과를 알려준다.
// Part1 DB중계서버는 해당 계정/캐릭터가 캐쉬에 있으면, 언로드하고,
// 해당 캐릭터를 파티/길드에서 탈퇴시킨 후 Ack를 보내준다.
// Ack를 받으면 창고/캐릭터 선택을 시작한다.
if (!(lpSessionData->GetFirstLogin() & UnifiedConst::SELECTED_PART2))
{
// 존재하는 창고를 선택했는지 검증
if (!lpSessionData->HasUnifiedStoreInfo(cSelectedServerGroupID))
{
usError = PktUnifiedCharSelectAck::WRONG_STORE_SELECTED;
}
}
if(0 == usError)
{
// 가져올 대상 캐릭터를 검증한다.
USER_INFO userInfo = lpSessionData->GetUserInfo();
unsigned long dwSelectedCID[USER_INFO::MAX_CHAR_NUM];
unsigned long* lpdwRequestedCID = lpUnifiedSelectReq->dwCID;
int nSelectedCount = 0;
std::fill_n(dwSelectedCID, size_t(USER_INFO::MAX_CHAR_NUM), 0);
// 데이터를 제대로 얻어 왔다.
// 현재 바인딩 된 캐릭터인지 아닌지 판단한다.
unsigned char cRestrictedPart1ToPart2Level =
CServerSetup::GetInstance().GetRestrictedPart1ToPart2Level();
for(int nCount = 0; nCount < USER_INFO::MAX_CHAR_NUM; ++nCount)
{
unsigned long dwBindCID = lpdwRequestedCID[nCount];
const UnifiedCharData* lpUnifiedCharData = 0;
if (0 == userInfo.CharID[nCount] &&
0 != dwBindCID && !userInfo.HasCharacter(dwBindCID) &&
0 != (lpUnifiedCharData = lpSessionData->GetUnifiedCharData(dwBindCID)) &&
(lpUnifiedCharData->cOldServerGroupID < UnifiedConst::Part1 ||
(lpUnifiedCharData->cOldServerGroupID == UnifiedConst::Part1Unified &&
cRestrictedPart1ToPart2Level <= lpUnifiedCharData->cLevel)))
{
dwSelectedCID[nCount] = dwBindCID;
++nSelectedCount;
}
}
if (0 < nSelectedCount &&
CClass::MAX_RACE == lpSessionData->CheckUnifiedCharRace(dwSelectedCID))
{
// 캐릭터가 있는데 종족이 다르면 에러!
usError = PktUnifiedCharSelectAck::PACKET_ERROR;
}
else if (CServerSetup::GetInstance().GetMaxTransferPart1ToPart2Count() <
nSelectedCount + lpSessionData->GetTransferedCharCount(CDBSingleObject::GetInstance()))
{
// 최대 캐릭터 선택 회수 이상 선택하면 에러
usError = PktUnifiedCharSelectAck::TRANSFER_COUNT_OVER;
}
else if (0 < nSelectedCount || !(lpSessionData->GetFirstLogin() & UnifiedConst::SELECTED_PART2))
{
// Part1중계서버로 '검증된' 데이터를 보낸다.
GET_SINGLE_DISPATCH(lpPart1DBAgentDispatch, CPart1DBAgentDispatch,
CPart1DBAgentDispatch::GetDispatchTable());
if (0 != lpPart1DBAgentDispatch)
{
bSupressSendAck = SendPacket::UnifiedCharSelectReq(lpPart1DBAgentDispatch->GetSendStream(),
dwUID, dwRequestKey, dwSelectedCID, USER_INFO::MAX_CHAR_NUM,
cSelectedServerGroupID, cSelectedNation);
usError = bSupressSendAck ? 0 : PktUnifiedCharSelectAck::SERVER_ERROR;
}
}
}
}
break;
case UnifiedConst::Part2Selectable:
if(0 == (lpSessionData = CSessionDataMgr::GetInstance().GetOpenSession(dwUID)))
{
// 해당 UID가 없다.
ERRLOG1(g_Log, "UID:%10u / Part2Selectable 캐릭터 선택 실패 - 세션이 닫혀 있습니다", dwUID);
usError = PktUnifiedCharSelectAck::SERVER_ERROR;
}
else
{
if (0 < cSelectedServerGroupID &&
cSelectedServerGroupID <= CServerSetup::GetInstance().GetSelectableUnifiedServerNum())
{
// 여기서는 데이터를 컨버팅 할 필요가 없다.
// 이미 컨버팅 된 데이터를 넣을 예정이다.
// 서버군을 선택했다. 선택한 서버군을 세팅한다.
lpSessionData->SetOldServerGroupID(cSelectedServerGroupID);
if(!lpSessionData->GetUserInfoFromDB(CDBSingleObject::GetInstance()))
{
ERRLOG3(g_Log, "UID:%10u / FirstLogin:%d / SelectedServerGroupID:%d / "
"Part2Selectable 캐릭터 선택 실패 - 유저 정보 DB에서 읽기 실패.",
dwUID, lpSessionData->GetFirstLogin(), cSelectedServerGroupID);
usError = PktUnifiedCharSelectAck::SERVER_ERROR;
}
}
else
{
ERRLOG3(g_Log, "UID:%10u / FirstLogin:%d / SelectedServerGroupID:%d / "
"Part2Selectable 캐릭터 선택 실패 - FirstLogin이나 SelectedServerGroupID값이 다릅니다.",
dwUID, lpSessionData->GetFirstLogin(), cSelectedServerGroupID);
usError = PktUnifiedCharSelectAck::PACKET_ERROR;
}
}
break;
default:
usError = PktUnifiedCharSelectAck::PACKET_ERROR;
break;
}
return !bSupressSendAck ?
SendPacket::UnifiedCharSelectAck(SendStream, dwUID, dwRequestKey, usError) : true;
}
}
}