Restructure repository to include all source folders
Move git root from Client/ to src/ to track all source code: - Client: Game client source (moved to Client/Client/) - Server: Game server source - GameTools: Development tools - CryptoSource: Encryption utilities - database: Database scripts - Script: Game scripts - rylCoder_16.02.2008_src: Legacy coder tools - GMFont, Game: Additional resources 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,910 @@
|
||||
#include "stdafx.h"
|
||||
#include "AdminToolDispatch.h"
|
||||
|
||||
#include <Log/ServerLog.h>
|
||||
#include <Network/Address/INET_Addr.h>
|
||||
#include <Network/Packet/PacketCommand.h>
|
||||
#include <Network/Packet/PacketStruct/ServerInfo.h>
|
||||
#include <Network/Packet/PacketStruct/ServerPacket.h>
|
||||
#include <Network/Packet/PacketStruct/CharAdminPacket.h>
|
||||
#include <Network/Packet/PacketStruct/GameEventPacket.h>
|
||||
#include <Network/Packet/PacketStruct/CharLoginOutPacketStruct.h>
|
||||
|
||||
#include <Network/SendPacket/SendAdminTool.h>
|
||||
#include <Network/SendPacket/SendServerInfo.h>
|
||||
|
||||
#include <Network/Dispatch/GameDispatch.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharAdmin.h>
|
||||
|
||||
#include <DataStorage/AdminDataMgr.h>
|
||||
#include <DataStorage/SessionData.h>
|
||||
#include <DataStorage/SessionDataMgr.h>
|
||||
#include <DataStorage/StoreData.h>
|
||||
#include <DataStorage/StoreDataMgr.h>
|
||||
#include <DataStorage/CharacterData.h>
|
||||
#include <DataStorage/CharacterDataMgr.h>
|
||||
|
||||
#include <DB/DBComponent.h>
|
||||
#include <DB/GameDBComponent.h>
|
||||
#include <DB/GuildDBComponent.h>
|
||||
#include <GameEvent/GameEventDBMgr.h>
|
||||
#include <Utility/Setup/ServerSetup.h>
|
||||
#include <Creature/Character/CharacterClass.h>
|
||||
|
||||
#include <Network/Packet/PacketStruct/GuildPacket.h>
|
||||
|
||||
#include <Community/Guild/GuildDB.h>
|
||||
#include <Community/Guild/GuildDBMgr.h>
|
||||
|
||||
namespace DBAgent
|
||||
{
|
||||
|
||||
// forward decl.
|
||||
bool GetUIDCIDFromName(const char* szName, unsigned long& dwUID_Out,
|
||||
unsigned long& dwCID_Out, unsigned char& cOldServerGroupID);
|
||||
|
||||
|
||||
CMultiDispatch& CAdminToolDispatch::GetDispatchTable()
|
||||
{
|
||||
static CMultiDispatch gameDispatch;
|
||||
return gameDispatch;
|
||||
}
|
||||
|
||||
|
||||
CAdminToolDispatch::CAdminToolDispatch(CSession& Session)
|
||||
: CRylServerDispatch(Session, MAX_PACKET_DISPATCH_PER_PULSE),
|
||||
m_dwServerID(0)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
CAdminToolDispatch::~CAdminToolDispatch()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
void CAdminToolDispatch::Connected()
|
||||
{
|
||||
DETLOG3(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/AdminToolServer Connected",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string());
|
||||
}
|
||||
|
||||
void CAdminToolDispatch::Disconnected()
|
||||
{
|
||||
DETLOG3(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/AdminToolServer Disconnected",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string());
|
||||
|
||||
if(0 != m_dwServerID)
|
||||
{
|
||||
GetDispatchTable().RemoveDispatch(m_dwServerID);
|
||||
|
||||
if(0LL != m_AdminItemSerialMgr.GetItemSerial())
|
||||
{
|
||||
// 아이템 시리얼 DB에 저장
|
||||
m_AdminItemSerialMgr.SaveItemSerial(
|
||||
CDBSingleObject::GetInstance(), m_dwServerID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CAdminToolDispatch::DispatchPacket(PktBase* lpPktBase)
|
||||
{
|
||||
bool bResult = false;
|
||||
PktBase::CMDType cCmd = lpPktBase->GetCmd();
|
||||
|
||||
switch(cCmd)
|
||||
{
|
||||
case CmdSysServerLogin: bResult = ParseServerLogin(static_cast<PktSL*>(lpPktBase)); break;
|
||||
case CmdSysServerLogout: bResult = ParseServerLogout(lpPktBase); break;
|
||||
case CmdUserKill: bResult = ParseUserKill(static_cast<PktUK*>(lpPktBase)); break;
|
||||
case CmdAdminToolGetData: bResult = ParseGetData(static_cast<PktAdminToolGetData*>(lpPktBase)); break;
|
||||
case CmdAdminToolSetData: bResult = ParseSetData(static_cast<PktAdminToolSetData*>(lpPktBase)); break;
|
||||
case CmdItemQtyCheck: bResult = ParseItemQtyCheck(static_cast<PktItemQtyControl*>(lpPktBase)); break;
|
||||
case CmdGuildPosition: bResult = ParseGuildPosition(static_cast<PktGuildPosition*>(lpPktBase)); break;
|
||||
|
||||
default:
|
||||
|
||||
ERRLOG4(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/Cmd:0x%02X/ 운영툴 서버 패킷 처리 실패 : 없는 커맨드입니다",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string(), cCmd);
|
||||
|
||||
bResult = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!bResult)
|
||||
{
|
||||
ERRLOG4(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/Cmd:0x%02X/ 운영툴 서버 패킷 처리 실패 : 처리를 실패했습니다",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string(), cCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CAdminToolDispatch::ParseServerLogin(PktSL* lpPktSL)
|
||||
{
|
||||
m_dwServerID = lpPktSL->m_dwServerID;
|
||||
|
||||
INFLOG4(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/ServerID:0x%08X/ 운영툴 서버 연결 시도 : 패킷 받음",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string(), m_dwServerID);
|
||||
|
||||
GET_MULTI_DISPATCH(lpAdminToolDispatch, m_dwServerID,
|
||||
CAdminToolDispatch, GetDispatchTable());
|
||||
|
||||
if(0 != lpAdminToolDispatch)
|
||||
{
|
||||
ERRLOG4(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/ServerID:0x%08X/ 운영툴 서버 연결 실패 : 이미 연결이 있습니다",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string(), m_dwServerID);
|
||||
|
||||
CloseSession();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Dispatch 세팅.
|
||||
GetDispatchTable().SetDispatch(m_dwServerID, this);
|
||||
|
||||
// 아이템 시리얼 로드.
|
||||
if(!m_AdminItemSerialMgr.LoadItemSerial(CDBSingleObject::GetInstance(), m_dwServerID))
|
||||
{
|
||||
ERRLOG4(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/ServerID:0x%08X/ 운영툴 서버 연결 실패 : 아이템 시리얼 로드 실패. 접속을 끊습니다",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string(), m_dwServerID);
|
||||
|
||||
CloseSession();
|
||||
return false;
|
||||
}
|
||||
|
||||
return SendPacket::ServerLoginAck(m_SendStream,
|
||||
m_dwServerID, m_AdminItemSerialMgr.GetItemSerial());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CAdminToolDispatch::ParseServerLogout(PktBase* lpPktBase)
|
||||
{
|
||||
// 받은 패킷 그대로 돌려 준다.
|
||||
|
||||
char* lpBuffer = m_SendStream.GetBuffer(sizeof(PktBase));
|
||||
if(0 != lpBuffer)
|
||||
{
|
||||
return m_SendStream.WrapHeader(sizeof(PktBase), CmdSysServerLogout, 0, 0);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CAdminToolDispatch::ParseUserKill(PktUK* lpPktUK)
|
||||
{
|
||||
using namespace DataStorage;
|
||||
|
||||
// 접속 DB를 전부 뒤져서, 계정과 IP가 일치하는 넘한테 뜨거운 맛을 보여 준다.
|
||||
CSessionData* lpSessionData =
|
||||
CSessionDataMgr::GetInstance().GetOpenSession(lpPktUK->m_dwUserID);
|
||||
|
||||
if(0 == lpSessionData)
|
||||
{
|
||||
ERRLOG1(g_Log, "UID:%10u / 운영툴 서버 유저 접속 끊기 실패 : 유저가 없습니다", lpPktUK->m_dwUserID);
|
||||
}
|
||||
else
|
||||
{
|
||||
SERVER_ID serverID;
|
||||
serverID.dwID = lpSessionData->GetServerID();
|
||||
CSessionData::SessionState eSessionState = lpSessionData->GetSessionState();
|
||||
|
||||
if ((serverID.GetType() == CServerSetup::AuthServer && CSessionData::SE_USER_ENABLED != eSessionState) ||
|
||||
(serverID.GetType() == CServerSetup::GameServer && CSessionData::SE_CHAR_ENABLED != eSessionState))
|
||||
{
|
||||
ERRLOG3(g_Log, "UID:%10u / ServerID:0x%08X / ST:%s / 운영툴 서버 유저 접속 끊기 실패 : 유저나 캐릭터가 비활성화되어 있습니다",
|
||||
lpPktUK->m_dwUserID, serverID.dwID, g_szSessionStateString[lpSessionData->GetSessionState()]);
|
||||
}
|
||||
else if(!SendPacket::UserKill(*lpSessionData))
|
||||
{
|
||||
ERRLOG3(g_Log, "UID:%10u / ServerID:0x%08X / ST:%s / 운영툴 서버 유저 접속 끊기 실패 : 접속 끊기 패킷 보내기 실패",
|
||||
lpPktUK->m_dwUserID, serverID.dwID, g_szSessionStateString[lpSessionData->GetSessionState()]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CAdminToolDispatch::ParseGetData(PktBase* lpPktBase)
|
||||
{
|
||||
// 데이터 얻어 오기. 패킷 오면 캐릭터 정보 및 창고 정보를 준다.
|
||||
PktAdminToolGetData* lpPktAdminToolGetData = static_cast<PktAdminToolGetData*>(lpPktBase);
|
||||
|
||||
switch(lpPktAdminToolGetData->m_cType)
|
||||
{
|
||||
case PktAdminToolGetData::GET_CHAR_DATA:
|
||||
|
||||
return ParseAdminToolGetData(lpPktAdminToolGetData);
|
||||
|
||||
case PktAdminToolGetData::CHANGE_CHAR_NAME:
|
||||
|
||||
return ParseAdminToolChangeName(lpPktAdminToolGetData);
|
||||
|
||||
default:
|
||||
|
||||
ERRLOG2(g_Log, "IP:%15s / Cmd:%d / 알 수 없는 운영툴 데이터 얻기 커맨드입니다.",
|
||||
GetRemoteAddr().get_addr_string(), lpPktAdminToolGetData->m_cType);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CAdminToolDispatch::ParseSetData(PktBase* lpPktBase)
|
||||
{
|
||||
// 데이터 기록하기. 패킷 오면 캐릭터 관련 데이터를 쓴다.
|
||||
// CharLogin때 보내주는 데이터, 창고 데이터 1, 창고 데이터 2, 창고 정보
|
||||
|
||||
// 데이터 얻어 오기. 패킷 오면 캐릭터 정보 및 창고 정보를 준다.
|
||||
PktAdminToolSetData* lpPktAdminToolSetData = static_cast<PktAdminToolSetData*>(lpPktBase);
|
||||
|
||||
switch(lpPktAdminToolSetData->m_cType)
|
||||
{
|
||||
case PktAdminToolSetData::CHAR_BASIC_DATA:
|
||||
case PktAdminToolSetData::CHAR_EXTRA_DATA:
|
||||
case PktAdminToolSetData::CHAR_FRIEND_DATA:
|
||||
case PktAdminToolSetData::CHAR_BAN_DATA:
|
||||
case PktAdminToolSetData::STORE_12_DATA:
|
||||
case PktAdminToolSetData::STORE_34_DATA:
|
||||
case PktAdminToolSetData::OPEN_UPDATE_DATA:
|
||||
case PktAdminToolSetData::FINISH_UPDATE_DATA:
|
||||
|
||||
return ParseAdminToolSetData(lpPktAdminToolSetData);
|
||||
|
||||
case PktAdminToolSetData::RELOAD_ADMINLIST:
|
||||
|
||||
return DataStorage::CAdminDataMgr::GetInstance().LoadAdminList(CDBSingleObject::GetInstance());
|
||||
|
||||
default:
|
||||
|
||||
ERRLOG2(g_Log, "IP:%15s / Cmd:%d / 알 수 없는 운영자 데이터 셋 패킷 커맨드입니다",
|
||||
GetRemoteAddr().get_addr_string(), lpPktAdminToolSetData->m_cType);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CAdminToolDispatch::ParseAdminToolGetData(PktAdminToolGetData* lpPktAdminToolGetData)
|
||||
{
|
||||
// DBRequestKey.
|
||||
unsigned long dwRequestKey = lpPktAdminToolGetData->m_dwRequestKey;
|
||||
unsigned long dwUID = lpPktAdminToolGetData->m_dwUID;
|
||||
unsigned long dwCID = lpPktAdminToolGetData->m_dwCID;
|
||||
unsigned char cOldServerGroupID = 0;
|
||||
|
||||
if (UnifiedConst::Part2Selectable == CServerSetup::GetInstance().GetAgentServerType())
|
||||
{
|
||||
cOldServerGroupID = lpPktAdminToolGetData->m_cOldServerGroupID;
|
||||
}
|
||||
else
|
||||
{
|
||||
cOldServerGroupID = static_cast<unsigned char>(
|
||||
CServerSetup::GetInstance().GetAgentServerType());
|
||||
}
|
||||
|
||||
PktAdminToolGetData::GetDataType eDataType =
|
||||
static_cast<PktAdminToolGetData::GetDataType>(lpPktAdminToolGetData->m_cType);
|
||||
|
||||
unsigned short wError = 0;
|
||||
|
||||
if(eDataType != PktAdminToolGetData::GET_CHAR_DATA)
|
||||
{
|
||||
// 잘못된 패킷임
|
||||
wError = PktAdminToolGetData::INVALID_REQUEST;
|
||||
}
|
||||
else
|
||||
{
|
||||
// UID, CID가 없으면 캐릭터 이름을 가지고 UID와 CID를 얻어 온다.
|
||||
if(0 == dwUID || 0 == dwCID || 0 == cOldServerGroupID)
|
||||
{
|
||||
if(!GetUIDCIDFromName(lpPktAdminToolGetData->m_szName,
|
||||
dwUID, dwCID, cOldServerGroupID))
|
||||
{
|
||||
// DB Query 실패.
|
||||
wError = PktAdminToolGetData::GET_UIDCID_QUERY_FAILED;
|
||||
}
|
||||
|
||||
if(0 == dwUID || 0 == dwCID || 0 == cOldServerGroupID)
|
||||
{
|
||||
// 얻어온 데이터가 이상함.
|
||||
wError = PktAdminToolGetData::INVALID_UID_CID_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
DETLOG4(g_Log, "UID:%10u / ServerGroupID:%d / CID:%10u / IP:%15s / 운영툴로부터 데이터 요청 받음",
|
||||
dwUID, cOldServerGroupID, dwCID, GetRemoteAddr().get_addr_string());
|
||||
|
||||
if(0 == wError)
|
||||
{
|
||||
using namespace DataStorage;
|
||||
|
||||
CStoreData* lpStoreData = 0;
|
||||
CCharacterData* lpCharacterData = 0;
|
||||
|
||||
CSessionData* lpSessionData = CSessionDataMgr::GetInstance().GetOpenSession(dwUID);
|
||||
|
||||
if(0 != lpSessionData)
|
||||
{
|
||||
// 이미 로드된 세션에서 데이터 가져옴.
|
||||
if(dwUID == lpSessionData->GetUID())
|
||||
{
|
||||
lpStoreData = lpSessionData->GetStoreData();
|
||||
}
|
||||
|
||||
if(dwCID == lpSessionData->GetCID())
|
||||
{
|
||||
lpCharacterData = lpSessionData->GetCharacterData();
|
||||
}
|
||||
}
|
||||
|
||||
// 캐쉬에서 데이터 로드. 캐쉬에 데이터가 없으면, DB에서 로드해서 캐쉬에 추가.
|
||||
if(0 == lpStoreData)
|
||||
{
|
||||
lpStoreData = CStoreDataMgr::GetInstance().GetLogoutData(
|
||||
UnifiedStoreKey(dwUID, cOldServerGroupID));
|
||||
}
|
||||
|
||||
if(0 == lpCharacterData)
|
||||
{
|
||||
lpCharacterData = CCharacterDataMgr::GetInstance().GetLogoutData(dwCID);
|
||||
}
|
||||
|
||||
|
||||
if(0 == lpStoreData)
|
||||
{
|
||||
wError = PktAdminToolGetData::GET_STORE_QUERY_FAILED;
|
||||
}
|
||||
else if(0 == lpCharacterData)
|
||||
{
|
||||
wError = PktAdminToolGetData::GET_CHAR_DATA_QUERY_FAILED;
|
||||
}
|
||||
else
|
||||
{
|
||||
SendPacket::TotalDataToAdminTool(GetSendStream(), dwRequestKey,
|
||||
GetRemoteAddr().get_addr_in().sin_addr, *lpStoreData, *lpCharacterData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 최종 전송
|
||||
return SendPacket::AdminToolGetDataAck(GetSendStream(),
|
||||
PktAdminToolGetData::FINISH_GET_DATA, dwRequestKey, dwUID, dwCID, 0, 0, wError, cOldServerGroupID);
|
||||
}
|
||||
|
||||
bool CAdminToolDispatch::ParseAdminToolSetData(PktAdminToolSetData* lpPktAdminToolSetData)
|
||||
{
|
||||
SERVER_ID serverID;
|
||||
serverID.dwID = m_dwServerID;
|
||||
|
||||
unsigned long dwUID = lpPktAdminToolSetData->m_dwUID;
|
||||
unsigned long dwCID = lpPktAdminToolSetData->m_dwCID;
|
||||
unsigned long dwRequestKey = lpPktAdminToolSetData->m_dwRequestKey;
|
||||
unsigned long dwDataSize = lpPktAdminToolSetData->GetLen() - sizeof(PktAdminToolSetData);
|
||||
unsigned char cType = lpPktAdminToolSetData->m_cType;
|
||||
unsigned char cOldServerGroupID = 0;
|
||||
|
||||
if (UnifiedConst::Part2Selectable == CServerSetup::GetInstance().GetAgentServerType())
|
||||
{
|
||||
cOldServerGroupID = lpPktAdminToolSetData->m_cOldServerGroupID;
|
||||
}
|
||||
else
|
||||
{
|
||||
cOldServerGroupID = static_cast<unsigned char>(
|
||||
CServerSetup::GetInstance().GetAgentServerType());
|
||||
}
|
||||
|
||||
unsigned short wError = 0;
|
||||
|
||||
if(0 == dwUID || 0 == dwCID)
|
||||
{
|
||||
wError = PktAdminToolSetData::INVALID_UID_CID_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
DETLOG3(g_Log, "UID:%10u / CID:%10u / IP:%15s / 운영자가 운영툴로 데이터 세팅 시도",
|
||||
dwUID, dwCID, GetRemoteAddr().get_addr_string());
|
||||
|
||||
using namespace DataStorage;
|
||||
|
||||
CStoreData* lpStoreData = 0;
|
||||
CCharacterData* lpCharacterData = 0;
|
||||
|
||||
CSessionData* lpSessionData = CSessionDataMgr::GetInstance().GetOpenSession(dwUID);
|
||||
|
||||
if(0 != lpSessionData)
|
||||
{
|
||||
if(CSessionData::SE_USER_ENABLED == lpSessionData->GetSessionState() ||
|
||||
CSessionData::SE_CHAR_ENABLED == lpSessionData->GetSessionState())
|
||||
{
|
||||
// 활성화된 캐릭터 편집 에러
|
||||
wError = PktAdminToolSetData::LOGIN_ANOTHER_GAMESERVER;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 이미 로드된 세션에서 데이터 가져옴.
|
||||
if(dwUID == lpSessionData->GetUID())
|
||||
{
|
||||
lpStoreData = lpSessionData->GetStoreData();
|
||||
}
|
||||
|
||||
if(dwCID == lpSessionData->GetCID())
|
||||
{
|
||||
lpCharacterData = lpSessionData->GetCharacterData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(0 == wError)
|
||||
{
|
||||
// 캐쉬에서 데이터 로드. 캐쉬에 데이터가 없으면, DB에서 로드해서 캐쉬에 추가.
|
||||
if(0 == lpStoreData)
|
||||
{
|
||||
lpStoreData = CStoreDataMgr::GetInstance().GetLogoutData(
|
||||
UnifiedStoreKey(dwUID, cOldServerGroupID));
|
||||
}
|
||||
|
||||
if(0 == lpCharacterData)
|
||||
{
|
||||
lpCharacterData = CCharacterDataMgr::GetInstance().GetLogoutData(dwCID);
|
||||
}
|
||||
|
||||
if(0 != lpStoreData && 0 != lpCharacterData)
|
||||
{
|
||||
switch(lpPktAdminToolSetData->m_cType)
|
||||
{
|
||||
case PktAdminToolSetData::OPEN_UPDATE_DATA:
|
||||
// 세션을 열고 DB에 업데이트하려 시도한다. : 이제는 세션 열 필요 없다. 그냥 한다.
|
||||
break;
|
||||
|
||||
case PktAdminToolSetData::FINISH_UPDATE_DATA:
|
||||
// 데이터를 DB에 업데이트하고 세션을 닫는다. : 이제는 세션 닫을 필요 없다. 그냥 한다.
|
||||
break;
|
||||
|
||||
case PktAdminToolSetData::CHAR_BASIC_DATA: // 캐릭터 정보. 다음 정보들이 들어감.
|
||||
|
||||
// 세션이 운영툴에서 연 세션인지 확인한다. 운영툴에서 연 세션이면, 데이터를 세팅한다.
|
||||
{
|
||||
unsigned short* lpSizeArray = reinterpret_cast<unsigned short*>(lpPktAdminToolSetData + 1);
|
||||
char* lpData = reinterpret_cast<char*>(lpSizeArray + DBUpdateData::MAX_UPDATE_DB);
|
||||
|
||||
if(!lpCharacterData->SerializeIn(lpData, lpSizeArray,
|
||||
dwDataSize - sizeof(unsigned short) * DBUpdateData::MAX_UPDATE_DB, DBUpdateData::MAX_UPDATE_DB))
|
||||
{
|
||||
ERRLOG3(g_Log, "UID:%10u / CID:%10u / IP:%15s / 운영툴 데이터 세팅 실패 : CHAR_BASIC_DATA",
|
||||
dwUID, dwCID, GetRemoteAddr().get_addr_string());
|
||||
|
||||
wError = PktAdminToolSetData::SETTING_DATA_FAILED;
|
||||
}
|
||||
else
|
||||
{
|
||||
INFLOG3(g_Log, "UID:%10u / CID:%10u / IP:%15s / 운영툴 데이터 세팅 성공 : CHAR_BASIC_DATA",
|
||||
dwUID, dwCID, GetRemoteAddr().get_addr_string());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PktAdminToolSetData::CHAR_EXTRA_DATA: // 캐릭터 추가 정보들. 다음 정보들이 들어감.
|
||||
|
||||
{
|
||||
unsigned long dwExpectDataSize = sizeof(CHAR_INFOEX) + sizeof(QUEST) +
|
||||
sizeof(HISTORY) + sizeof(CONFIG) + sizeof(STORE_INFO);
|
||||
|
||||
if(dwDataSize == dwExpectDataSize)
|
||||
{
|
||||
char* lpCharDataExPos = reinterpret_cast<char*>(lpPktAdminToolSetData + 1);
|
||||
|
||||
// CHAR_INFOEX : 캐릭터 추가 정보
|
||||
lpCharacterData->SetInfoEx(*reinterpret_cast<CHAR_INFOEX*>(lpCharDataExPos));
|
||||
lpCharDataExPos += sizeof(CHAR_INFOEX);
|
||||
|
||||
// QUEST : 퀘스트
|
||||
lpCharacterData->SetQuest(*reinterpret_cast<QUEST*>(lpCharDataExPos));
|
||||
lpCharDataExPos += sizeof(QUEST);
|
||||
|
||||
// HISTORY : 히스토리
|
||||
lpCharacterData->SetHistory(*reinterpret_cast<HISTORY*>(lpCharDataExPos));
|
||||
lpCharDataExPos += sizeof(HISTORY);
|
||||
|
||||
// CONFIG : 설정
|
||||
lpCharacterData->SetConfig(*reinterpret_cast<CONFIG*>(lpCharDataExPos));
|
||||
lpCharDataExPos += sizeof(CONFIG);
|
||||
|
||||
// STORE_INFO : 창고 정보
|
||||
lpStoreData->SetStoreInfo(*reinterpret_cast<STORE_INFO*>(lpCharDataExPos));
|
||||
lpCharDataExPos += sizeof(STORE_INFO);
|
||||
}
|
||||
else
|
||||
{
|
||||
wError = PktAdminToolSetData::SETTING_DATA_FAILED;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PktAdminToolSetData::CHAR_FRIEND_DATA: // 캐릭터 친구 정보
|
||||
|
||||
if(!lpCharacterData->FriendSerializeIn(
|
||||
reinterpret_cast<char*>(lpPktAdminToolSetData + 1), dwDataSize))
|
||||
{
|
||||
wError = PktAdminToolSetData::SETTING_DATA_FAILED;
|
||||
}
|
||||
break;
|
||||
|
||||
case PktAdminToolSetData::CHAR_BAN_DATA: // 캐릭터 거부 정보
|
||||
|
||||
if(!lpCharacterData->BanSerializeIn(
|
||||
reinterpret_cast<char*>(lpPktAdminToolSetData + 1), dwDataSize))
|
||||
{
|
||||
wError = PktAdminToolSetData::SETTING_DATA_FAILED;
|
||||
}
|
||||
break;
|
||||
|
||||
case PktAdminToolSetData::STORE_12_DATA: // 창고 1, 2탭 데이터
|
||||
|
||||
if(dwDataSize == sizeof(STORE))
|
||||
{
|
||||
const STORE& store1 = *reinterpret_cast<STORE*>(lpPktAdminToolSetData + 1);
|
||||
lpStoreData->SetStore1(store1.Data, store1.dwSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
wError = PktAdminToolSetData::SETTING_DATA_FAILED;
|
||||
}
|
||||
break;
|
||||
|
||||
case PktAdminToolSetData::STORE_34_DATA: // 창고 3, 4탭 데이터
|
||||
|
||||
if(dwDataSize == sizeof(STORE))
|
||||
{
|
||||
const STORE& store2 = *reinterpret_cast<STORE*>(lpPktAdminToolSetData + 1);
|
||||
lpStoreData->SetStore2(store2.Data, store2.dwSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
wError = PktAdminToolSetData::SETTING_DATA_FAILED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ItemSerial 업데이트
|
||||
if(m_AdminItemSerialMgr.SetItemSerial(lpPktAdminToolSetData->m_dwSerial))
|
||||
{
|
||||
m_AdminItemSerialMgr.SaveItemSerial(CDBSingleObject::GetInstance(), m_dwServerID);
|
||||
}
|
||||
|
||||
return SendPacket::AdminToolSetDataAck(
|
||||
GetSendStream(), dwRequestKey, dwUID, dwCID, cType, wError);
|
||||
}
|
||||
|
||||
|
||||
bool CAdminToolDispatch::ParseGuildPosition(PktGuildPosition* lpPktGuildPosition)
|
||||
{
|
||||
using namespace DataStorage;
|
||||
|
||||
unsigned short wError = PktBase::NO_SERVER_ERR;
|
||||
|
||||
unsigned long dwGID = lpPktGuildPosition->m_dwGID;
|
||||
unsigned long dwCID = lpPktGuildPosition->m_dwCID;
|
||||
unsigned char cPosition = lpPktGuildPosition->m_cPosition;
|
||||
unsigned char cType = lpPktGuildPosition->m_cType;
|
||||
|
||||
using namespace Guild;
|
||||
|
||||
CGuildDB* lpGuild = static_cast<CGuildDB*>(CGuildDBMgr::GetInstance().GetGuild(dwGID));
|
||||
|
||||
char* lpBuffer = GetSendStream().GetBuffer(sizeof(PktGuildPosition));
|
||||
|
||||
PktGuildPosition* pktSendPacket = NULL;
|
||||
|
||||
if(lpBuffer)
|
||||
{
|
||||
pktSendPacket = reinterpret_cast<PktGuildPosition*>(lpBuffer);
|
||||
|
||||
pktSendPacket->m_cPosition = lpPktGuildPosition->m_cPosition;
|
||||
pktSendPacket->m_dwCID = lpPktGuildPosition->m_dwCID;
|
||||
pktSendPacket->m_dwGID = lpPktGuildPosition->m_dwGID;
|
||||
pktSendPacket->m_cType = lpPktGuildPosition->m_cType;
|
||||
}
|
||||
|
||||
if(!lpGuild)
|
||||
{
|
||||
wError = PktGuildPosition::FAIL_GUILD;
|
||||
}
|
||||
else
|
||||
{
|
||||
CSessionData* lpSessionData = CSessionDataMgr::GetInstance().GetCharLoadedSession(dwCID);
|
||||
|
||||
if(lpSessionData)
|
||||
{
|
||||
wError = PktGuildPosition::FAIL_CONNECT_CHAR;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(cType==PktGuildPosition::TYPE_POSITION)
|
||||
{
|
||||
lpGuild->SetTitle(dwCID, cPosition);
|
||||
|
||||
SYSTEMTIME systemTime;
|
||||
::memset(&systemTime, 0, sizeof(SYSTEMTIME));
|
||||
GetLocalTime(&systemTime);
|
||||
|
||||
if(!DBComponent::GuildDB::UpdateMemberTitle(CDBSingleObject::GetInstance(), dwCID, cPosition, systemTime))
|
||||
{
|
||||
wError = PktGuildPosition::FAIL_DB_UPDATE;
|
||||
}
|
||||
}
|
||||
else if(cType==PktGuildPosition::TYPE_MEMBERDELETE)
|
||||
{
|
||||
if(!lpGuild->LeaveMember(dwCID))
|
||||
{
|
||||
wError = PktGuildPosition::FAIL_MEMBER_DELETE;
|
||||
}
|
||||
else
|
||||
{
|
||||
using namespace DBAgent::DataStorage;
|
||||
|
||||
DBComponent::GameDB::UpdateGuildWarFlag(CDBSingleObject::GetInstance(), dwCID, Creature::WAR_OFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return GetSendStream().WrapHeader(sizeof(PktGuildPosition), CmdGuildPosition, 0, wError);
|
||||
}
|
||||
|
||||
bool CAdminToolDispatch::ParseItemQtyCheck(PktItemQtyControl* lpPktItemQtyControl)
|
||||
{
|
||||
tm* lpTm = localtime(&lpPktItemQtyControl->m_tStartTime);
|
||||
if(0 == lpTm)
|
||||
{
|
||||
ERRLOG2(g_Log, "IP:%15s / StartTime:%d / 아이템 수량 제어 실패 : 시간이 맞지 않습니다",
|
||||
GetRemoteAddr().get_addr_string(), lpPktItemQtyControl->m_tStartTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
tm tStartTime = *lpTm;
|
||||
|
||||
lpTm = localtime(&lpPktItemQtyControl->m_tEndTime);
|
||||
if(0 == lpTm)
|
||||
{
|
||||
ERRLOG2(g_Log, "IP:%15s / EndTime:%d / 아이템 수량 제어 실패 : 시간이 맞지 않습니다",
|
||||
GetRemoteAddr().get_addr_string(), lpPktItemQtyControl->m_tEndTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
tm tEndTime = *lpTm;
|
||||
|
||||
if(lpPktItemQtyControl->m_cGroup != CServerSetup::GetInstance().GetServerGroup())
|
||||
{
|
||||
ERRLOG3(g_Log, "IP:%15s / CurrentServerGroup:%d / ReceivedServerGroup:%d / 아이템 수량 제어 실패 : 서버 그룹이 맞지 않습니다",
|
||||
GetRemoteAddr().get_addr_string(), CServerSetup::GetInstance().GetServerGroup(), lpPktItemQtyControl->m_cGroup);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool bResult = false;
|
||||
|
||||
switch(lpPktItemQtyControl->m_cType)
|
||||
{
|
||||
case PktItemQtyControl::ADD:
|
||||
|
||||
bResult = CGameEventDBMgr::GetInstance().InsertDropItem(
|
||||
static_cast<unsigned short>(lpPktItemQtyControl->m_dwItemTypeID),
|
||||
static_cast<unsigned short>(lpPktItemQtyControl->m_dwItemQty),
|
||||
tStartTime, tEndTime);
|
||||
|
||||
DETLOG5(g_Log, "아이템 수량 제어 추가 %s : ID:%u/Qty:%u/StartTime:%d/EndTime:%d",
|
||||
bResult ? "성공" : "실패",
|
||||
lpPktItemQtyControl->m_dwItemTypeID, lpPktItemQtyControl->m_dwItemQty,
|
||||
lpPktItemQtyControl->m_tStartTime, lpPktItemQtyControl->m_tEndTime);
|
||||
|
||||
SendPacket::ItemQtyCheck(lpPktItemQtyControl->m_dwItemTypeID,
|
||||
lpPktItemQtyControl->m_dwItemQty, 0,
|
||||
lpPktItemQtyControl->m_tStartTime,
|
||||
lpPktItemQtyControl->m_tEndTime,
|
||||
PktItemQtyControl::ADD, bResult ? 0 : 1);
|
||||
break;
|
||||
|
||||
case PktItemQtyControl::DEL:
|
||||
|
||||
bResult = CGameEventDBMgr::GetInstance().EraseDropItem(
|
||||
static_cast<unsigned short>(lpPktItemQtyControl->m_dwItemTypeID));
|
||||
|
||||
DETLOG5(g_Log, "아이템 수량 제어 삭제 %s : ID:%u/Qty:%u/StartTime:%d/EndTime:%d",
|
||||
bResult ? "성공" : "실패",
|
||||
lpPktItemQtyControl->m_dwItemTypeID, lpPktItemQtyControl->m_dwItemQty,
|
||||
lpPktItemQtyControl->m_tStartTime, lpPktItemQtyControl->m_tEndTime);
|
||||
|
||||
SendPacket::ItemQtyCheck(lpPktItemQtyControl->m_dwItemTypeID,
|
||||
lpPktItemQtyControl->m_dwItemQty, 0,
|
||||
lpPktItemQtyControl->m_tStartTime, lpPktItemQtyControl->m_tEndTime,
|
||||
PktItemQtyControl::DEL, bResult ? 0 : 1);
|
||||
break;
|
||||
|
||||
case PktItemQtyControl::STATUS_REQUEST:
|
||||
|
||||
DETLOG0(g_Log, "아이템 수량 제어 상태 요청");
|
||||
CGameEventDBMgr::GetInstance().SendDropItemInfo();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
class CSendNameChanged
|
||||
{
|
||||
public:
|
||||
|
||||
CSendNameChanged(unsigned long dwUID, unsigned long dwCID, const char* szChangedName,
|
||||
unsigned char cNameChangeCount, unsigned short usError)
|
||||
: m_dwUID(dwUID), m_dwCID(dwCID),
|
||||
m_cNameChangeCount(cNameChangeCount),
|
||||
m_usError(usError)
|
||||
{
|
||||
strncpy(m_szChangedName, szChangedName, CHAR_INFOST::MAX_NAME_LEN);
|
||||
m_szChangedName[ CHAR_INFOST::MAX_NAME_LEN - 1 ] = 0;
|
||||
}
|
||||
|
||||
bool operator () (unsigned long dwServerID, CPacketDispatch& dispatch)
|
||||
{
|
||||
return GameClientSendPacket::SendCharNameChange(
|
||||
static_cast<CRylServerDispatch&>(dispatch).GetSendStream(),
|
||||
m_dwUID, m_dwCID, m_szChangedName, m_cNameChangeCount, NULL, m_usError);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
unsigned long m_dwUID;
|
||||
unsigned long m_dwCID;
|
||||
unsigned char m_cNameChangeCount;
|
||||
unsigned short m_usError;
|
||||
|
||||
char m_szChangedName[CHAR_INFOST::MAX_NAME_LEN];
|
||||
};
|
||||
|
||||
bool CAdminToolDispatch::ParseAdminToolChangeName(PktAdminToolGetData* lpPktAdminToolGetData)
|
||||
{
|
||||
unsigned long dwUID = lpPktAdminToolGetData->m_dwUID;
|
||||
unsigned long dwCID = lpPktAdminToolGetData->m_dwCID;
|
||||
unsigned long dwRequestKey = lpPktAdminToolGetData->m_dwRequestKey;
|
||||
const char* szChangeName = lpPktAdminToolGetData->m_szName;
|
||||
|
||||
unsigned short usError = 0;
|
||||
|
||||
using namespace DBAgent::DataStorage;
|
||||
|
||||
CSessionData* lpSessionData =
|
||||
CSessionDataMgr::GetInstance().GetCharLoadedSession(dwCID);
|
||||
|
||||
CCharacterData* lpCharacterData = 0;
|
||||
|
||||
if (0 == lpSessionData ||
|
||||
lpSessionData->GetUID() != dwUID ||
|
||||
lpSessionData->GetCID() != dwCID ||
|
||||
(0 == (lpCharacterData = lpSessionData->GetCharacterData())) ||
|
||||
dwCID != lpCharacterData->GetCID())
|
||||
{
|
||||
lpCharacterData = CCharacterDataMgr::GetInstance().GetLogoutData(dwCID);
|
||||
}
|
||||
|
||||
if (0 != lpCharacterData)
|
||||
{
|
||||
unsigned long dwResult = 0;
|
||||
|
||||
if (DBComponent::GameDB::ChangeCharName(
|
||||
CDBSingleObject::GetInstance(), dwCID, szChangeName, dwResult))
|
||||
{
|
||||
if (0 == dwResult)
|
||||
{
|
||||
// 이름을 바꾼다.
|
||||
CHAR_INFOST charInfoST = lpCharacterData->GetInfo();
|
||||
|
||||
strncpy(charInfoST.Name, szChangeName, CHAR_INFOST::MAX_NAME_LEN);
|
||||
charInfoST.Name[CHAR_INFOST::MAX_NAME_LEN - 1] = 0;
|
||||
|
||||
lpCharacterData->SetInfo(charInfoST, true);
|
||||
}
|
||||
else if(1 == dwResult)
|
||||
{
|
||||
ERRLOG3(g_Log, "UID:%10u / CID:%10u / ChangeName:%s / 운영툴로 캐릭터 이름 바꾸기 실패 : 이름이 이미 있습니다",
|
||||
dwUID, dwCID, szChangeName);
|
||||
|
||||
usError = PktCharNameChange::ERR_ALREADY_USE_NAME;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERRLOG4(g_Log, "UID:%10u / CID:%10u / ChangeName:%s / dwResult:%10u / 운영툴로 캐릭터 이름 바꾸기 실패 : 알 수 없는 dwResult값입니다",
|
||||
dwUID, dwCID, szChangeName, dwResult);
|
||||
|
||||
usError = PktCharNameChange::ERR_SERVER;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERRLOG3(g_Log, "UID:%10u / CID:%10u / ChangeName:%s / 운영툴로 캐릭터 이름 바꾸기 실패 : DB호출 에러",
|
||||
dwUID, dwCID, szChangeName);
|
||||
|
||||
usError = PktCharNameChange::ERR_SERVER;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERRLOG3(g_Log, "UID:%10u / CID:%10u / ChangeName:%s / "
|
||||
"운영툴로 캐릭터 이름 바꾸기 실패 : 해당하는 캐릭터를 찾을 수 없습니다.", dwUID, dwCID, szChangeName);
|
||||
|
||||
usError = PktCharNameChange::ERR_CANNOT_FIND_CHARACTER;
|
||||
}
|
||||
|
||||
if (0 != lpSessionData && 0 != lpCharacterData && 0 == usError)
|
||||
{
|
||||
// 모든 게임 서버에 전송한다.
|
||||
DBAgent::CGameDispatch::GetDispatchTable().Process(
|
||||
CSendNameChanged(dwUID, dwCID, szChangeName,
|
||||
lpCharacterData->GetInfoEx().cNameChangeCount, usError));
|
||||
}
|
||||
|
||||
// 운영툴로 Ack를 전송한다.
|
||||
return SendPacket::AdminToolGetDataAck(GetSendStream(),
|
||||
PktAdminToolGetData::CHANGE_CHAR_NAME, dwRequestKey, dwUID, dwCID, 0, 0, usError);
|
||||
}
|
||||
|
||||
|
||||
bool GetUIDCIDFromName(const char* szName, unsigned long& dwUID_Out,
|
||||
unsigned long& dwCID_Out, unsigned char& cOldServerGroupID)
|
||||
{
|
||||
#pragma pack(1)
|
||||
|
||||
struct UIDCID
|
||||
{
|
||||
unsigned long dwUID;
|
||||
unsigned long dwCID;
|
||||
unsigned char cOldServerGroupID;
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
UIDCID uidcid;
|
||||
|
||||
uidcid.dwUID = 0;
|
||||
uidcid.dwCID = 0;
|
||||
|
||||
const int MAX_BUFFER = 1024;
|
||||
char szQuery[MAX_BUFFER] = { 0, };
|
||||
|
||||
int nLength = _snprintf(szQuery, MAX_BUFFER - 1, "dbo.GetUIDCIDFromName '%s'", szName);
|
||||
szQuery[MAX_BUFFER - 1] = 0;
|
||||
|
||||
if(0 < nLength)
|
||||
{
|
||||
szQuery[nLength] = 0;
|
||||
if(CDBSingleObject::GetInstance().ExecuteQueryGetData(szQuery, &uidcid))
|
||||
{
|
||||
dwUID_Out = uidcid.dwUID;
|
||||
dwCID_Out = uidcid.dwCID;
|
||||
cOldServerGroupID = uidcid.cOldServerGroupID;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
ERRLOG2(g_Log, "캐릭터 이름으로 UID / CID 얻어 오는 쿼리에 실패했습니다. %s : %s",
|
||||
CDBSingleObject::GetInstance().GetErrorString(), szQuery);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#ifndef _DBAGENT_SERVER_ADMIN_TOOL_DISPATCH_H_
|
||||
#define _DBAGENT_SERVER_ADMIN_TOOL_DISPATCH_H_
|
||||
|
||||
#include <Network/Dispatch/RylServerDispatch.h>
|
||||
#include <Network/Dispatch/MultiDispatchStorage.h>
|
||||
|
||||
#include <Item/ItemSerialMgr.h>
|
||||
|
||||
// forward decl.
|
||||
struct PktSL;
|
||||
struct PktUK;
|
||||
struct PktItemQtyControl;
|
||||
struct PktAdminToolGetData;
|
||||
struct PktAdminToolSetData;
|
||||
struct PktGuildPosition;
|
||||
|
||||
namespace DBAgent
|
||||
{
|
||||
class CAdminToolDispatch : public CRylServerDispatch
|
||||
{
|
||||
public:
|
||||
|
||||
static CMultiDispatch& GetDispatchTable();
|
||||
|
||||
enum Const
|
||||
{
|
||||
MAX_PACKET_DISPATCH_PER_PULSE = 100,
|
||||
MAX_STREAM_BUFFER_SIZE = 16000
|
||||
};
|
||||
|
||||
CAdminToolDispatch(CSession& Session);
|
||||
virtual ~CAdminToolDispatch();
|
||||
|
||||
virtual void Connected();
|
||||
virtual void Disconnected();
|
||||
virtual bool DispatchPacket(PktBase* lpPktBase);
|
||||
|
||||
private:
|
||||
|
||||
bool ParseServerLogin(PktSL* lpPktSL);
|
||||
bool ParseServerLogout(PktBase* lpPktBase);
|
||||
bool ParseUserKill(PktUK* lpPktUK);
|
||||
|
||||
bool ParseGetData(PktBase* lpPktBase);
|
||||
bool ParseSetData(PktBase* lpPktBase);
|
||||
bool ParseItemQtyCheck(PktItemQtyControl* lpPktItemQtyControl); // 이벤트 아이템 수량 관련 패킷
|
||||
|
||||
bool ParseAdminToolGetData(PktAdminToolGetData* lpPktAdminToolGetData); // 현재 운영툴(AdminTool)
|
||||
bool ParseAdminToolSetData(PktAdminToolSetData* lpPktAdminToolSetData); // 현재 운영툴(AdminTool)
|
||||
|
||||
bool ParseAdminToolChangeName(PktAdminToolGetData* lpPktAdminToolGetData); // 운영툴로 캐릭터 이름 바꾸기
|
||||
|
||||
bool ParseGuildPosition(PktGuildPosition* lpPktGuildPosition); // 길드 포지션 설정.
|
||||
|
||||
Item::CItemSerialMgr m_AdminItemSerialMgr;
|
||||
|
||||
unsigned long m_dwServerID;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,232 @@
|
||||
#include "stdafx.h"
|
||||
#include "AuthDispatch.h"
|
||||
|
||||
#include <Log/ServerLog.h>
|
||||
#include <Utility/Setup/ServerSetup.h>
|
||||
#include <Network/Address/INET_Addr.h>
|
||||
#include <Network/SendPacket/SendServerInfo.h>
|
||||
#include <Network/SendPacket/SendLoginout.h>
|
||||
|
||||
#include <Network/ParsePacket/ParseCharManage.h>
|
||||
#include <Network/ParsePacket/ParseGuild.h>
|
||||
#include <Network/ParsePacket/ParseParty.h>
|
||||
#include <Network/ParsePacket/ParseMoveZone.h>
|
||||
|
||||
#include <Network/Packet/PacketCommand.h>
|
||||
|
||||
#include <Network/Dispatch/LoginDispatch.h>
|
||||
|
||||
#include <DB/DBComponent.h>
|
||||
#include <DB/GameDBComponent.h>
|
||||
|
||||
#include <DataStorage/SessionData.h>
|
||||
#include <DataStorage/SessionDataMgr.h>
|
||||
|
||||
|
||||
namespace DBAgent
|
||||
{
|
||||
|
||||
CSingleDispatch& CAuthDispatch::GetDispatchTable()
|
||||
{
|
||||
static CSingleDispatch authDispatch;
|
||||
return authDispatch;
|
||||
}
|
||||
|
||||
|
||||
CAuthDispatch::CAuthDispatch(CSession& Session)
|
||||
: CRylServerDispatch(Session, MAX_PACKET_DISPATCH_PER_PULSE),
|
||||
m_dwServerID(0),
|
||||
m_nUserNum(1)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
CAuthDispatch::~CAuthDispatch()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
void CAuthDispatch::Connected()
|
||||
{
|
||||
DETLOG3(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/AuthServer Connected",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string());
|
||||
}
|
||||
|
||||
void CAuthDispatch::Disconnected()
|
||||
{
|
||||
DETLOG3(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/AuthServer Disconnected",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string());
|
||||
|
||||
if(0 != m_dwServerID)
|
||||
{
|
||||
GetDispatchTable().RemoveDispatch(this);
|
||||
|
||||
if(0LL != m_AuthItemSerialMgr.GetItemSerial())
|
||||
{
|
||||
// 아이템 시리얼 DB에 저장
|
||||
m_AuthItemSerialMgr.SaveItemSerial(
|
||||
CDBSingleObject::GetInstance(), m_dwServerID);
|
||||
}
|
||||
|
||||
GET_SINGLE_DISPATCH(lpLoginDispatch, CLoginDispatch,
|
||||
CLoginDispatch::GetDispatchTable());
|
||||
|
||||
if(0 != lpLoginDispatch)
|
||||
{
|
||||
// 로그인서버로 서버 버전 업데이트
|
||||
SendPacket::UpdateServerVersion(lpLoginDispatch->GetSendStream());
|
||||
}
|
||||
|
||||
// 현재 서버에 로그인된 사람을 전부 내려버린다.
|
||||
DataStorage::CSessionDataMgr::GetInstance().SessionCloseCurrentServer(m_dwServerID);
|
||||
}
|
||||
}
|
||||
|
||||
bool CAuthDispatch::DispatchPacket(PktBase* lpPktBase)
|
||||
{
|
||||
// Auth 에서 보낸 패킷을 처리하는 부분이다.
|
||||
|
||||
bool bResult = false;
|
||||
PktBase::CMDType cCmd = lpPktBase->GetCmd();
|
||||
|
||||
switch(cCmd)
|
||||
{
|
||||
case CmdSysServerLogin: bResult = ParseServerLogin(static_cast<PktSL*>(lpPktBase)); break;
|
||||
case CmdSysServerLogout: bResult = ParseServerLogout(lpPktBase); break;
|
||||
case CmdUserKill: bResult = ParseUserKill(static_cast<PktUK*>(lpPktBase)); break;
|
||||
|
||||
case CmdDBGetData:
|
||||
{
|
||||
PktDD* pkDD = static_cast<PktDD*>(lpPktBase);
|
||||
|
||||
// DETLOG4(g_Log, "SS:0x%08x/DP:0x%08x/Len:0x%08x/CMD:0x%04x : CmdDBGetData", &GetSession(), this, pkDD->GetLen(), pkDD->m_wCmd);
|
||||
|
||||
bResult = ParseCharManage::Parse(GetSendStream(), m_dwServerID,
|
||||
m_AuthItemSerialMgr, pkDD);
|
||||
}
|
||||
break;
|
||||
|
||||
case CmdAgentZone: bResult = ParseMoveZone::Parse(GetSendStream(), static_cast<PktDD*>(lpPktBase)); break;
|
||||
case CmdAgentParty: bResult = ParseParty::Parse(GetSendStream(), lpPktBase); break;
|
||||
case CmdGuildCmd: bResult = ParseGuild::GuildCmd(GetSendStream(), lpPktBase); break;
|
||||
|
||||
|
||||
case CmdUnifiedCharSelect:
|
||||
bResult = ParseCharManage::UnifiedCharSelect(GetSendStream(), lpPktBase);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
ERRLOG4(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/Cmd:0x%02X/ 인증서버 패킷 처리 실패 : 없는 커맨드입니다",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string(), cCmd);
|
||||
|
||||
bResult = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!bResult)
|
||||
{
|
||||
ERRLOG4(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/Cmd:0x%02X/ 인증서버 패킷 처리 실패 : 처리를 실패했습니다",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string(), cCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CAuthDispatch::ParseServerLogin(PktSL* lpPktSL)
|
||||
{
|
||||
m_dwServerID = lpPktSL->m_dwServerID;
|
||||
|
||||
INFLOG4(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/ServerID:0x%08X/ 인증서버 연결 시도 : 패킷 받음",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string(), m_dwServerID);
|
||||
|
||||
GET_SINGLE_DISPATCH(lpAuthDispatch,
|
||||
CAuthDispatch, GetDispatchTable());
|
||||
|
||||
if(0 != lpAuthDispatch)
|
||||
{
|
||||
ERRLOG4(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/ServerID:0x%08X/ 인증서버 연결 실패 : 이미 연결이 있습니다",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string(), m_dwServerID);
|
||||
|
||||
CloseSession();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Dispatch 세팅.
|
||||
GetDispatchTable().SetDispatch(this);
|
||||
|
||||
// 아이템 시리얼 로드.
|
||||
if(!m_AuthItemSerialMgr.LoadItemSerial(CDBSingleObject::GetInstance(), m_dwServerID))
|
||||
{
|
||||
ERRLOG4(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/ServerID:0x%08X/인증서버 연결 실패 : 아이템 시리얼 로드 실패. 접속을 끊습니다.",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string(), m_dwServerID);
|
||||
|
||||
CloseSession();
|
||||
return false;
|
||||
}
|
||||
|
||||
GET_SINGLE_DISPATCH(lpLoginDispatch, CLoginDispatch,
|
||||
CLoginDispatch::GetDispatchTable());
|
||||
|
||||
if(0 != lpLoginDispatch)
|
||||
{
|
||||
// 로그인서버로 서버 버전 업데이트
|
||||
SendPacket::UpdateServerVersion(lpLoginDispatch->GetSendStream());
|
||||
}
|
||||
|
||||
return SendPacket::ServerLoginAck(m_SendStream,
|
||||
m_dwServerID, m_AuthItemSerialMgr.GetItemSerial());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CAuthDispatch::ParseServerLogout(PktBase* lpPktBase)
|
||||
{
|
||||
// 받은 패킷 그대로 돌려 준다.
|
||||
|
||||
char* lpBuffer = m_SendStream.GetBuffer(sizeof(PktBase));
|
||||
if(0 != lpBuffer)
|
||||
{
|
||||
return m_SendStream.WrapHeader(sizeof(PktBase), CmdSysServerLogout, 0, 0);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CAuthDispatch::ParseUserKill(PktUK* lpPktUK)
|
||||
{
|
||||
// 유저 죽이기를 실패해서, Ack로 오는 경우이다.
|
||||
|
||||
if(2 == lpPktUK->GetError())
|
||||
{
|
||||
DataStorage::CSessionData* lpSessionData =
|
||||
DataStorage::CSessionDataMgr::GetInstance().GetOpenSession(lpPktUK->m_dwUserID);
|
||||
|
||||
if(0 != lpSessionData &&
|
||||
DataStorage::CSessionData::SE_USER_ENABLED == lpSessionData->GetSessionState())
|
||||
{
|
||||
if(lpSessionData->GetServerID() == lpPktUK->m_dwServerID)
|
||||
{
|
||||
DataStorage::CSessionDataMgr::GetInstance().SessionCloseWithLogout(
|
||||
lpPktUK->m_dwUserID, lpPktUK->m_dwServerID);
|
||||
|
||||
ERRLOG2(g_Log, "UID:%10u / ServerID:0x%08X / 게임서버 세션 강제 종료 : 캐릭터 죽이기 실패",
|
||||
lpPktUK->m_dwUserID, lpPktUK->m_dwServerID);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERRLOG3(g_Log, "UID:%10u / FromServerID:0x%08X / TargetServerID:0x%08X / "
|
||||
"게임서버 세션 강제 종료 실패 : 실패 서버와 죽이기 요청 서버가 다름",
|
||||
lpPktUK->m_dwUserID, lpPktUK->m_dwServerID, lpSessionData->GetServerID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
#ifndef _DBAGENT_SERVER_AUTH_DISPATCH_H_
|
||||
#define _DBAGENT_SERVER_AUTH_DISPATCH_H_
|
||||
|
||||
#include <Network/Dispatch/RylServerDispatch.h>
|
||||
#include <Network/Dispatch/SingleDispatchStorage.h>
|
||||
|
||||
#include <Item/ItemSerialMgr.h>
|
||||
|
||||
// forward decl.
|
||||
struct PktSL;
|
||||
struct PktUK;
|
||||
struct PktDD;
|
||||
|
||||
namespace DBAgent
|
||||
{
|
||||
class CAuthDispatch : public CRylServerDispatch
|
||||
{
|
||||
public:
|
||||
|
||||
static CSingleDispatch& GetDispatchTable();
|
||||
|
||||
enum Const
|
||||
{
|
||||
MAX_PACKET_DISPATCH_PER_PULSE = 100,
|
||||
MAX_STREAM_BUFFER_SIZE = 16000
|
||||
};
|
||||
|
||||
CAuthDispatch(CSession& Session);
|
||||
virtual ~CAuthDispatch();
|
||||
|
||||
virtual void Connected();
|
||||
virtual void Disconnected();
|
||||
virtual bool DispatchPacket(PktBase* lpPktBase);
|
||||
|
||||
void IncUserNum() { ++m_nUserNum; }
|
||||
void DecUserNum() { --m_nUserNum; }
|
||||
|
||||
int GetUserNum() const { return (m_nUserNum < 1) ? 1 : m_nUserNum; }
|
||||
|
||||
private:
|
||||
|
||||
bool ParseServerLogin(PktSL* lpPktSL);
|
||||
bool ParseServerLogout(PktBase* lpPktBase);
|
||||
bool ParseUserKill(PktUK* lpPktUK);
|
||||
|
||||
unsigned long m_dwServerID;
|
||||
int m_nUserNum;
|
||||
Item::CItemSerialMgr m_AuthItemSerialMgr;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,126 @@
|
||||
#include "stdafx.h"
|
||||
#include "ChatDispatch.h"
|
||||
|
||||
#include <Log/ServerLog.h>
|
||||
#include <Network/Address/INET_Addr.h>
|
||||
#include <Network/Packet/PacketCommand.h>
|
||||
#include <Network/SendPacket/SendServerInfo.h>
|
||||
|
||||
namespace DBAgent
|
||||
{
|
||||
|
||||
CSingleDispatch& CChatDispatch::GetDispatchTable()
|
||||
{
|
||||
static CSingleDispatch chatDispatch;
|
||||
return chatDispatch;
|
||||
}
|
||||
|
||||
CChatDispatch::CChatDispatch(CSession& Session)
|
||||
: CRylServerDispatch(Session, MAX_PACKET_DISPATCH_PER_PULSE)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
CChatDispatch::~CChatDispatch()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
void CChatDispatch::Connected()
|
||||
{
|
||||
DETLOG3(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/ChatServer Connected",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string());
|
||||
}
|
||||
|
||||
void CChatDispatch::Disconnected()
|
||||
{
|
||||
DETLOG3(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/ChatServer Disconnected",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string());
|
||||
|
||||
if(0 != m_dwServerID)
|
||||
{
|
||||
GetDispatchTable().RemoveDispatch(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool CChatDispatch::DispatchPacket(PktBase* lpPktBase)
|
||||
{
|
||||
bool bResult = false;
|
||||
PktBase::CMDType cCmd = lpPktBase->GetCmd();
|
||||
|
||||
switch(cCmd)
|
||||
{
|
||||
case CmdSysServerLogin:
|
||||
bResult = ParseServerLogin(static_cast<PktSL*>(lpPktBase));
|
||||
break;
|
||||
|
||||
case CmdSysServerLogout:
|
||||
bResult = ParseServerLogout(lpPktBase);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
ERRLOG4(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/Cmd:0x%02X/ 채팅서버 패킷 처리 실패 : 없는 커맨드입니다",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string(), cCmd);
|
||||
|
||||
bResult = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!bResult)
|
||||
{
|
||||
ERRLOG4(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/Cmd:0x%02X/ 채팅서버 패킷 처리 실패 : 처리를 실패했습니다",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string(), cCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CChatDispatch::ParseServerLogin(PktSL* lpPktSL)
|
||||
{
|
||||
m_dwServerID = lpPktSL->m_dwServerID;
|
||||
|
||||
INFLOG4(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/ServerID:0x%08X/ 채팅서버 연결 시도 : 패킷 받음",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string(), m_dwServerID);
|
||||
|
||||
GET_SINGLE_DISPATCH(lpChatDispatch,
|
||||
CChatDispatch, GetDispatchTable());
|
||||
|
||||
if(0 != lpChatDispatch)
|
||||
{
|
||||
ERRLOG4(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/ServerID:0x%08X/ 채팅서버 연결 실패 : 이미 연결이 있습니다",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string(), m_dwServerID);
|
||||
|
||||
CloseSession();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Dispatch 세팅.
|
||||
GetDispatchTable().SetDispatch(this);
|
||||
return SendPacket::ServerLoginAck(m_SendStream, m_dwServerID, 0LL);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CChatDispatch::ParseServerLogout(PktBase* lpPktBase)
|
||||
{
|
||||
// 받은 패킷 그대로 돌려 준다.
|
||||
|
||||
char* lpBuffer = m_SendStream.GetBuffer(sizeof(PktBase));
|
||||
if(0 != lpBuffer)
|
||||
{
|
||||
return m_SendStream.WrapHeader(sizeof(PktBase), CmdSysServerLogout, 0, 0);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
#ifndef _DBAGENT_SERVER_CHAT_DISPATCH_H_
|
||||
#define _DBAGENT_SERVER_CHAT_DISPATCH_H_
|
||||
|
||||
#include <Network/Dispatch/RylServerDispatch.h>
|
||||
#include <Network/Dispatch/SingleDispatchStorage.h>
|
||||
|
||||
// forward decl.
|
||||
struct PktSL;
|
||||
|
||||
namespace DBAgent
|
||||
{
|
||||
class CChatDispatch : public CRylServerDispatch
|
||||
{
|
||||
public:
|
||||
|
||||
static CSingleDispatch& GetDispatchTable();
|
||||
|
||||
enum Const
|
||||
{
|
||||
MAX_PACKET_DISPATCH_PER_PULSE = 100,
|
||||
MAX_STREAM_BUFFER_SIZE = 16000
|
||||
};
|
||||
|
||||
CChatDispatch(CSession& Session);
|
||||
virtual ~CChatDispatch();
|
||||
|
||||
virtual void Connected();
|
||||
virtual void Disconnected();
|
||||
virtual bool DispatchPacket(PktBase* lpPktBase);
|
||||
|
||||
private:
|
||||
|
||||
bool ParseServerLogin(PktSL* lpPktSL);
|
||||
bool ParseServerLogout(PktBase* lpPktBase);
|
||||
|
||||
unsigned long m_dwServerID;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,827 @@
|
||||
#include "stdafx.h"
|
||||
#include "GameDispatch.h"
|
||||
|
||||
#include <Log/ServerLog.h>
|
||||
#include <Utility/Setup/ServerSetup.h>
|
||||
|
||||
#include <Network/Address/INET_Addr.h>
|
||||
#include <Network/Stream/SendStream.h>
|
||||
#include <Network/Packet/PacketDispatchTable.h>
|
||||
#include <Network/Packet/PacketCommand.h>
|
||||
#include <Network/Packet/WrapPacket.h>
|
||||
#include <Network/Packet/PacketStruct/ServerInfo.h>
|
||||
#include <Network/Packet/PacketStruct/ServerPacket.h>
|
||||
#include <Network/Packet/PacketStruct/ServerLogPacket.h>
|
||||
#include <Network/Packet/PacketStruct/CharAdminPacket.h>
|
||||
|
||||
#include <Network/ParsePacket/ParseMoveZone.h>
|
||||
#include <Network/ParsePacket/ParseCharManage.h>
|
||||
#include <Network/ParsePacket/ParseCharUpdate.h>
|
||||
#include <Network/ParsePacket/ParseParty.h>
|
||||
#include <Network/ParsePacket/ParseCastle.h>
|
||||
#include <Network/ParsePacket/ParseGuild.h>
|
||||
|
||||
#include <Network/SendPacket/SendServerInfo.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharAdmin.h>
|
||||
|
||||
#include <Creature/Character/CharacterClass.h>
|
||||
#include <Creature/StatueDBMgr.h>
|
||||
|
||||
#include <DB/DBComponent.h>
|
||||
#include <DB/GameDBComponent.h>
|
||||
#include <DataStorage/SessionData.h>
|
||||
#include <DataStorage/SessionDataMgr.h>
|
||||
|
||||
#include <Castle/CastleDBMgr.h>
|
||||
#include <GameTime/GameTimeDBMgr.h>
|
||||
#include <Creature/Siege/SiegeObjectDBMgr.h>
|
||||
#include <Community/Guild/GuildDBMgr.h>
|
||||
#include <Ranking/RankingDBMgr.h>
|
||||
#include <GameEvent/GiveItemMgr.h>
|
||||
|
||||
#include <DataStorage/SessionDataMgr.h>
|
||||
#include <DataStorage/CharacterDataMgr.h>
|
||||
|
||||
#include <Map/FieldMap/MineralVeinDBMgr.h>
|
||||
|
||||
#include <Ranking/RankingMgr.h>
|
||||
|
||||
#include <Community/Party/PartyDBMgr.h>
|
||||
|
||||
namespace DBAgent
|
||||
{
|
||||
|
||||
typedef bool (*GameDispatchFunc) (CSendStream& SendStream, PktBase* lpPktBase);
|
||||
|
||||
|
||||
// forward delc.
|
||||
bool ParseServerLog(CSendStream& SendStream, PktBase* lpPktBase);
|
||||
|
||||
|
||||
class CGameDispatchTable : public CPacketDispatchTable<GameDispatchFunc>
|
||||
{
|
||||
public:
|
||||
|
||||
static CGameDispatchTable& GetInstance();
|
||||
|
||||
private:
|
||||
|
||||
CGameDispatchTable();
|
||||
};
|
||||
|
||||
|
||||
CGameDispatchTable& CGameDispatchTable::GetInstance()
|
||||
{
|
||||
static CGameDispatchTable gameDispatchTable;
|
||||
return gameDispatchTable;
|
||||
}
|
||||
|
||||
CGameDispatchTable::CGameDispatchTable()
|
||||
: CPacketDispatchTable<GameDispatchFunc>(UCHAR_MAX)
|
||||
{
|
||||
// 데이터 업데이트 관련
|
||||
AddDispatch(CmdDepositUpdate, ParseCharUpdate::UpdateDepositDB);
|
||||
AddDispatch(CmdDeposit, ParseCharUpdate::UpdateDeposit);
|
||||
AddDispatch(CmdFriendDB, ParseCharUpdate::UpdateFriendDB);
|
||||
AddDispatch(CmdQuestDB, ParseCharUpdate::UpdateQuestDB);
|
||||
AddDispatch(CmdConfigInfoDB, ParseCharUpdate::UpdateConfigInfoDB);
|
||||
|
||||
// 존이동 관련
|
||||
AddDispatch(CmdAgentZone, ParseMoveZone::Parse);
|
||||
|
||||
// 파티 관련
|
||||
AddDispatch(CmdAgentParty, ParseParty::Parse);
|
||||
|
||||
// 배틀그라운드 관련
|
||||
AddDispatch(CmdBGServerCharSlot, ParseCharManage::BGServerCharSlot);
|
||||
|
||||
// 로그 관련
|
||||
AddDispatch(CmdServerLog, ParseServerLog);
|
||||
|
||||
// 길드 관련
|
||||
AddDispatch(CmdCreateGuild, ParseGuild::CreateGuild);
|
||||
AddDispatch(CmdGuildCmd, ParseGuild::GuildCmd);
|
||||
AddDispatch(CmdGuildMark, ParseGuild::GuildMark);
|
||||
AddDispatch(CmdGuildLevel, ParseGuild::GuildLevel);
|
||||
AddDispatch(CmdGuildRelation, ParseGuild::GuildRelation);
|
||||
AddDispatch(CmdGuildInclination, ParseGuild::GuildInclination);
|
||||
AddDispatch(CmdGuildRight, ParseGuild::SetGuildRight);
|
||||
AddDispatch(CmdGuildSafe, ParseGuild::GuildSafe);
|
||||
AddDispatch(CmdGuildMemberInfoUpdate, ParseGuild::GuildMemberInfoUpdate);
|
||||
|
||||
// 공성 관련
|
||||
AddDispatch(CmdCreateCamp, ParseCastle::CreateCamp);
|
||||
AddDispatch(CmdCreateSiegeArms, ParseCastle::CreateSiegeArms);
|
||||
AddDispatch(CmdCastleCmd, ParseCastle::CastleCmd);
|
||||
AddDispatch(CmdCampCmd, ParseCastle::CampCmd);
|
||||
AddDispatch(CmdSiegeArmsCmd, ParseCastle::SiegeArmsCmd);
|
||||
AddDispatch(CmdCastleRight, ParseCastle::SetCastleRight);
|
||||
AddDispatch(CmdCampRight, ParseCastle::SetCampRight);
|
||||
AddDispatch(CmdCampMessage, ParseCastle::CampMessage);
|
||||
AddDispatch(CmdMiningCampMineralInfo, ParseCastle::MiningCampMineralInfo);
|
||||
AddDispatch(CmdFertilityInfo, ParseCastle::FertilityInfo);
|
||||
AddDispatch(CmdCampShopInfo, ParseCastle::CampShopInfo);
|
||||
AddDispatch(CmdCastleTaxMove, ParseCastle::CastleTaxMove);
|
||||
AddDispatch(CmdCastleMineralInfo, ParseCastle::CastleMineralInfo);
|
||||
AddDispatch(CmdWarOnOff, ParseCastle::WarOnOff);
|
||||
AddDispatch(CmdStatueCmd, ParseCastle::StatueCmd);
|
||||
|
||||
AddDispatch(CmdAdminCommandLog, ParseCharAdmin::AdminCommandLog);
|
||||
|
||||
AddDispatch(CmdRealmPoint, ParseCastle::RealmPoint);
|
||||
|
||||
// 듀얼 관련.
|
||||
AddDispatch(CmdSaveEnemy, ParseCharUpdate::SaveEnemy);
|
||||
|
||||
// 조이스틱 관련.
|
||||
AddDispatch(CmdKeyInfo, ParseCharUpdate::UpdateKeyInfo);
|
||||
|
||||
// 아이템 관련
|
||||
AddDispatch(CmdCharUseCashItem, ParseCharUpdate::UseCashItem);
|
||||
AddDispatch(CmdExtraEvent, ParseCharUpdate::ExtraEvent);
|
||||
}
|
||||
|
||||
|
||||
CMultiDispatch& CGameDispatch::GetDispatchTable()
|
||||
{
|
||||
static CMultiDispatch gameDispatch;
|
||||
return gameDispatch;
|
||||
}
|
||||
|
||||
|
||||
CGameDispatch::CGameDispatch(CSession& Session)
|
||||
: CRylServerDispatch(Session, MAX_PACKET_DISPATCH_PER_PULSE),
|
||||
m_nHumanNum(1),
|
||||
m_nAkhanNum(1),
|
||||
m_dwServerID(0)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
CGameDispatch::~CGameDispatch()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
void CGameDispatch::Connected()
|
||||
{
|
||||
DETLOG3(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/GameServer Connected",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string());
|
||||
}
|
||||
|
||||
void CGameDispatch::Disconnected()
|
||||
{
|
||||
DETLOG3(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/GameServer Disconnected",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string());
|
||||
|
||||
if(0 != m_dwServerID)
|
||||
{
|
||||
GetDispatchTable().RemoveDispatch(m_dwServerID);
|
||||
|
||||
if(0LL != m_GameItemSerialMgr.GetItemSerial())
|
||||
{
|
||||
// 아이템 시리얼 DB에 저장
|
||||
m_GameItemSerialMgr.SaveItemSerial(
|
||||
CDBSingleObject::GetInstance(), m_dwServerID);
|
||||
}
|
||||
|
||||
// 채널 정보 업데이트
|
||||
DBAgent::SendPacket::UpdateChannelAllServer();
|
||||
|
||||
// 현재 서버에 로그인된 사람을 전부 내려버린다.
|
||||
DataStorage::CSessionDataMgr::GetInstance().SessionCloseCurrentServer(m_dwServerID);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool CGameDispatch::DispatchPacket(PktBase* lpPktBase)
|
||||
{
|
||||
// 게임서버에서 DBAgent로 보내는 패킷정보
|
||||
|
||||
PktBase::CMDType cCmd =lpPktBase->GetCmd();
|
||||
|
||||
bool bResult = false;
|
||||
GameDispatchFunc lpDispatchFunc = 0;
|
||||
|
||||
|
||||
CSendStream& SendStream = GetSendStream();
|
||||
|
||||
switch(cCmd)
|
||||
{
|
||||
// 로그인 / 로그아웃 / 데이터 업데이트
|
||||
case CmdDBUpdateData:
|
||||
// 유저가 로그인하거나 로그아웃할때 여기로 메시지를 보낸다.
|
||||
// 여기서 타임DB를 업데이트 하거나 한다.
|
||||
bResult = ParseCharUpdate::Parse(SendStream, m_dwServerID,
|
||||
m_GameItemSerialMgr, static_cast<PktDBUpdate*>(lpPktBase));
|
||||
break;
|
||||
|
||||
case CmdSysServerLogin: bResult = ServerLogin(lpPktBase); break; // 서버 로그인
|
||||
case CmdSysServerLogout: bResult = ServerLogout(lpPktBase); break; // 서버 로그아웃
|
||||
case CmdUserKill: bResult = UserKillAck(lpPktBase); break; // 유저 죽이기
|
||||
case CmdCharAdminCmd: bResult = CharAdminCmd(lpPktBase); break; // 운영자 명령
|
||||
case CmdGiveItemToTempInven: bResult = GiveItemToTempInven(lpPktBase); break; // 임시인벤으로 아이템 주기
|
||||
case CmdCharNameChange: bResult = ChangeName(lpPktBase); break; // 캐릭터 이름을 바꾼다
|
||||
|
||||
default:
|
||||
|
||||
// 기타 명령(테이블에서 검색)
|
||||
lpDispatchFunc = CGameDispatchTable::GetInstance().GetDispatch(cCmd);
|
||||
if(0 != lpDispatchFunc)
|
||||
{
|
||||
bResult = lpDispatchFunc(SendStream, lpPktBase);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERRLOG5(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/Cmd:0x%02X/ServerID:0x%08X / "
|
||||
"게임서버 패킷 처리 실패 : 없는 커맨드입니다",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string(), cCmd, m_dwServerID);
|
||||
|
||||
bResult = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(!bResult)
|
||||
{
|
||||
ERRLOG5(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/Cmd:0x%02X/ServerID:0x%08X / 게임서버 패킷 처리 실패 : 처리를 실패했습니다",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string(), cCmd, m_dwServerID);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool CGameDispatch::ServerLogin(PktBase* lpPktBase)
|
||||
{
|
||||
PktSL* lpPktSL = static_cast<PktSL*>(lpPktBase);
|
||||
|
||||
m_dwServerID = lpPktSL->m_dwServerID;
|
||||
|
||||
INFLOG4(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/ServerID:0x%08X/게임서버 연결 시도 : 패킷 받음",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string(), m_dwServerID);
|
||||
|
||||
GET_MULTI_DISPATCH(lpGameDispatch, m_dwServerID,
|
||||
CGameDispatch, GetDispatchTable());
|
||||
|
||||
if(0 != lpGameDispatch)
|
||||
{
|
||||
ERRLOG4(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/ServerID:0x%08X/게임서버 연결 실패 : 이미 연결이 있습니다. 접속을 끊습니다.",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string(), m_dwServerID);
|
||||
|
||||
CloseSession();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Dispatch 세팅.
|
||||
GetDispatchTable().SetDispatch(m_dwServerID, this);
|
||||
|
||||
// 아이템 시리얼 로드.
|
||||
if(!m_GameItemSerialMgr.LoadItemSerial(CDBSingleObject::GetInstance(), m_dwServerID))
|
||||
{
|
||||
ERRLOG4(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/ServerID:0x%08X/게임서버 연결 실패 : 아이템 시리얼 로드 실패. 접속을 끊습니다.",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string(), m_dwServerID);
|
||||
|
||||
CloseSession();
|
||||
return false;
|
||||
}
|
||||
|
||||
CSendStream& SendStream = GetSendStream();
|
||||
|
||||
// 길드 정보 업데이트
|
||||
Guild::CGuildDBMgr::GetInstance().SendGuildDBList(SendStream);
|
||||
|
||||
SERVER_ID serverID;
|
||||
serverID.dwID = m_dwServerID;
|
||||
|
||||
/// 성 및 캠프, 공성병기 관련 정보 업데이트.
|
||||
Castle::CCastleDBMgr::GetInstance().SendCastleInfo(SendStream, serverID.GetZone(), serverID.GetChannel());
|
||||
CGameTimeDBMgr::GetInstance().SendGameTimeInfo(GameTime::TYPE_GAMESERVER_LOGIN, true, true, true, true, true);
|
||||
CSiegeObjectDBMgr::GetInstance().SendWorldWeaponInfo(SendStream, serverID.GetZone(), serverID.GetChannel());
|
||||
CSiegeObjectDBMgr::GetInstance().SendCampInfo(SendStream, serverID.GetZone(), serverID.GetChannel());
|
||||
CSiegeObjectDBMgr::GetInstance().SendSiegeArmsInfo(SendStream, serverID.GetZone(), serverID.GetChannel());
|
||||
|
||||
// 컨텐츠 : 다크 카나번 국가 전쟁
|
||||
if (true == CServerSetup::GetInstance().UseContents(GameRYL::STONE_BATTLE))
|
||||
{
|
||||
// 석상 정보 업데이트
|
||||
// 주의 : 성 정보가 석상 정보보다 먼저 보내져야한다.!!
|
||||
// 성에 의해 석상 인챈트 효과가 영향을 받기 때문이다.!!
|
||||
if (SERVER_ID::STONE_WAR1 <= serverID.GetZone() && serverID.GetZone() <= SERVER_ID::STONE_WAR3)
|
||||
{
|
||||
CStatueDBMgr::GetInstance().SendStatueInfo(SendStream, serverID.GetChannel());
|
||||
}
|
||||
}
|
||||
/*
|
||||
// 컨텐츠 : 신규존
|
||||
if (true == CServerSetup::GetInstance().UseContents(GameRYL::NEWZONE_ZONE9))
|
||||
{
|
||||
// 생명축출기 정보 업데이트
|
||||
// 주의 : 성 정보가 생명축출기 정보보다 먼저 보내져야한다.!!
|
||||
if (serverID.GetZone() == SERVER_ID::ZONE9)
|
||||
{
|
||||
CStatueDBMgr::GetInstance().SendStatueInfo(SendStream, serverID.GetChannel());
|
||||
}
|
||||
}
|
||||
*/
|
||||
// 지력 정보 업데이트
|
||||
CMineralVeinDBMgr::GetInstance().SendFertilityInfo(SendStream, serverID.GetZone(), serverID.GetChannel());
|
||||
|
||||
// 채널 정보 업데이트
|
||||
DBAgent::SendPacket::UpdateChannelAllServer();
|
||||
|
||||
// 랭킹 정보 업데이트
|
||||
CRankingDBMgr::GetInstance().SendRankingInfo(SendStream);
|
||||
|
||||
// 파티 정보가 있으면 보내준다 //
|
||||
CPartyDBMgr::GetInstance().SendToGameServerPartyData(SendStream);
|
||||
|
||||
// 서버 로그인 Ack보냄.
|
||||
return SendPacket::ServerLoginAck(m_SendStream,
|
||||
m_dwServerID, m_GameItemSerialMgr.GetItemSerial());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CGameDispatch::ServerLogout(PktBase* lpPktBase)
|
||||
{
|
||||
// 받은 패킷 그대로 돌려 준다.
|
||||
|
||||
char* lpBuffer = m_SendStream.GetBuffer(sizeof(PktBase));
|
||||
if(0 != lpBuffer)
|
||||
{
|
||||
return m_SendStream.WrapHeader(sizeof(PktBase), CmdSysServerLogout, 0, 0);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CGameDispatch::UserKillAck(PktBase* lpPktBase)
|
||||
{
|
||||
// 유저 죽이기를 실패해서, Ack로 오는 경우이다.
|
||||
|
||||
PktUK* lpPktUK = static_cast<PktUK*>(lpPktBase);
|
||||
|
||||
if(2 == lpPktUK->GetError())
|
||||
{
|
||||
using namespace DataStorage;
|
||||
|
||||
CSessionData* lpSessionData =
|
||||
CSessionDataMgr::GetInstance().GetOpenSession(lpPktUK->m_dwUserID);
|
||||
|
||||
if(0 != lpSessionData &&
|
||||
CSessionData::SE_CHAR_ENABLED == lpSessionData->GetSessionState())
|
||||
{
|
||||
if(lpSessionData->GetServerID() == lpPktUK->m_dwServerID)
|
||||
{
|
||||
CSessionDataMgr::GetInstance().SessionCloseWithLogout(
|
||||
lpPktUK->m_dwUserID, lpPktUK->m_dwServerID);
|
||||
|
||||
ERRLOG2(g_Log, "UID:%10u / ServerID:0x%08X / 게임서버 세션 강제 종료 : 유저 죽이기 실패",
|
||||
lpPktUK->m_dwUserID, lpPktUK->m_dwServerID);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERRLOG3(g_Log, "UID:%10u / FromServerID:0x%08X / TargetServerID:0x%08X / "
|
||||
"게임서버 세션 강제 종료 실패 : 실패 서버와 죽이기 요청 서버가 다름",
|
||||
lpPktUK->m_dwUserID, lpPktUK->m_dwServerID, lpSessionData->GetServerID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool CGameDispatch::CharAdminCmd(PktBase* lpPktBase)
|
||||
{
|
||||
PktAdmin* lpPktAdmin = static_cast<PktAdmin*>(lpPktBase);
|
||||
|
||||
PktAdmin pktSendAdmin;
|
||||
|
||||
// 패킷 내용을 그대로 복사.
|
||||
memcpy(&pktSendAdmin, lpPktAdmin, sizeof(PktAdmin));
|
||||
|
||||
// 중계서버 강제 종료
|
||||
/*if(lpPktAdmin->m_usCmd == PktAdmin::DBAGENT_KILL)
|
||||
{
|
||||
int nZero = 0;
|
||||
int nError = 10 / nZero;
|
||||
*reinterpret_cast<int*>(nError) = 0xFFFFFFFF;
|
||||
}*/
|
||||
|
||||
|
||||
// 추적한 위치 좌표를, 게임 서버로부터 받은 경우라면...
|
||||
if (lpPktAdmin->m_usCmd == PktAdmin::REQUEST_TRACE_POS)
|
||||
{
|
||||
// 해당 게임 서버에게만 TRACE 명령 전송
|
||||
pktSendAdmin.m_usCmd = PktAdmin::TRACE_CHAR;
|
||||
|
||||
SERVER_ID serverID;
|
||||
|
||||
serverID.sID.Type = CServerSetup::GameServer;
|
||||
serverID.sID.Group = CServerSetup::GetInstance().GetServerGroup();
|
||||
serverID.sID.Channel = lpPktAdmin->m_ZoneInfo.m_cChannel;
|
||||
serverID.sID.ID = lpPktAdmin->m_ZoneInfo.m_cZone;
|
||||
|
||||
GET_MULTI_DISPATCH(lpGameDispatch, serverID.dwID,
|
||||
CGameDispatch, CGameDispatch::GetDispatchTable());
|
||||
|
||||
if(0 != lpGameDispatch)
|
||||
{
|
||||
serverID.dwID = m_dwServerID;
|
||||
|
||||
// 게임 서버로 보낼때는 channel 이 -1 이어야 한다. -_-;
|
||||
pktSendAdmin.m_ZoneInfo.m_cZone = serverID.GetZone();
|
||||
pktSendAdmin.m_ZoneInfo.m_cChannel = -1;
|
||||
|
||||
if(PacketWrap::WrapHeader(reinterpret_cast<char*>(&pktSendAdmin),
|
||||
sizeof(PktAdmin), CmdCharAdminCmd, 0, 0))
|
||||
{
|
||||
lpGameDispatch->GetSendStream().PutBuffer(
|
||||
reinterpret_cast<char*>(&pktSendAdmin), sizeof(PktAdmin), CmdCharAdminCmd);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (lpPktAdmin->m_usCmd == PktAdmin::TRACE_CHAR)
|
||||
{
|
||||
using namespace DBAgent::DataStorage;
|
||||
|
||||
// 캐릭터가 로그아웃한 상태라면
|
||||
if (false == CSessionDataMgr::GetInstance().IsLoadedChar(lpPktAdmin->m_stName))
|
||||
{
|
||||
// 해당 게임 서버에게 해당 캐릭터가 로그아웃 했다는 정보를 보낸다.
|
||||
pktSendAdmin.m_usCmd = PktAdmin::TRACE_CHAR;
|
||||
|
||||
GET_MULTI_DISPATCH(lpGameDispatch, m_dwServerID,
|
||||
CGameDispatch, CGameDispatch::GetDispatchTable());
|
||||
|
||||
if(0 != lpGameDispatch)
|
||||
{
|
||||
// 게임 서버로 보낼때는 channel 이 -1 이어야 한다. -_-;
|
||||
pktSendAdmin.m_ZoneInfo.m_cChannel = -1;
|
||||
pktSendAdmin.m_Position.fPointX = 0.0f;
|
||||
pktSendAdmin.m_Position.fPointY = 0.0f;
|
||||
pktSendAdmin.m_Position.fPointZ = 0.0f;
|
||||
|
||||
if(PacketWrap::WrapHeader(reinterpret_cast<char*>(&pktSendAdmin),
|
||||
sizeof(PktAdmin), CmdCharAdminCmd, 0, PktAdmin::E_LOGOUT_CHAR))
|
||||
{
|
||||
lpGameDispatch->GetSendStream().PutBuffer(
|
||||
reinterpret_cast<char*>(&pktSendAdmin), sizeof(PktAdmin), CmdCharAdminCmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pktSendAdmin.m_usCmd = PktAdmin::REQUEST_TRACE_POS;
|
||||
|
||||
SERVER_ID serverID;
|
||||
serverID.dwID = m_dwServerID;
|
||||
|
||||
// TRACE 시켜야 할 캐릭터가 현재 있는 존의 번호를 기억해둔다.
|
||||
pktSendAdmin.m_ZoneInfo.m_cZone = serverID.GetZone();
|
||||
pktSendAdmin.m_ZoneInfo.m_cChannel = 0;
|
||||
}
|
||||
}
|
||||
/*
|
||||
else if (lpPktAdmin->m_usCmd == PktAdmin::INFO_CHAR)
|
||||
{
|
||||
using namespace DBAgent::DataStorage;
|
||||
|
||||
// 캐릭터가 로그아웃한 상태라면
|
||||
if (false == CSessionDataMgr::GetInstance().IsLoadedChar(lpPktAdmin->m_stName))
|
||||
{
|
||||
pktSendAdmin.m_usCmd = PktAdmin::INFO_CHAR;
|
||||
|
||||
GET_MULTI_DISPATCH(lpGameDispatch, m_dwServerID,
|
||||
CGameDispatch, CGameDispatch::GetDispatchTable());
|
||||
|
||||
if(0 != lpGameDispatch)
|
||||
{
|
||||
// 게임 서버로 보낼때는 channel 이 -1 이어야 한다. -_-;
|
||||
pktSendAdmin.m_ZoneInfo.m_cChannel = -1;
|
||||
pktSendAdmin.m_Position.fPointX = 0.0f;
|
||||
pktSendAdmin.m_Position.fPointY = 0.0f;
|
||||
pktSendAdmin.m_Position.fPointZ = 0.0f;
|
||||
|
||||
if (PacketWrap::WrapHeader(reinterpret_cast<char*>(&pktSendAdmin),
|
||||
sizeof(PktAdmin), CmdCharAdminCmd, 0, PktAdmin::E_LOGOUT_CHAR))
|
||||
{
|
||||
lpGameDispatch->GetSendStream().PutBuffer(
|
||||
reinterpret_cast<char*>(&pktSendAdmin), sizeof(PktAdmin), CmdCharAdminCmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
if(PacketWrap::WrapHeader(reinterpret_cast<char*>(&pktSendAdmin),
|
||||
sizeof(PktAdmin), CmdCharAdminCmd, 0, 0))
|
||||
{
|
||||
// 모든 게임서버로 전송.
|
||||
GetDispatchTable().Process(CSendPacketAllServer(
|
||||
reinterpret_cast<char*>(&pktSendAdmin), sizeof(PktAdmin), CmdCharAdminCmd));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CGameDispatch::GiveItemToTempInven(PktBase* lpPktBase)
|
||||
{
|
||||
PktGiveItemToTempInven* lpPktGiveItemToTempInven =
|
||||
static_cast<PktGiveItemToTempInven*>(lpPktBase);
|
||||
|
||||
GiveItemInfo* lpPos = lpPktGiveItemToTempInven->m_GiveItemInfo;
|
||||
GiveItemInfo* lpEnd = lpPos + lpPktGiveItemToTempInven->m_cGiveItemNum;
|
||||
|
||||
CGiveItemMgr& giveItemMgr = CGiveItemMgr::GetInstance();
|
||||
|
||||
for(; lpPos != lpEnd; ++lpPos)
|
||||
{
|
||||
// 아이템 넣기에 성공했으면 아이템 시리얼을 채워서 준다. 채워서 준 시리얼을 DB에 갱신한다.
|
||||
if(0 != lpPos->m_dwItemUID)
|
||||
{
|
||||
giveItemMgr.UpdateItemSerial(
|
||||
lpPos->m_dwCreateID, lpPos->m_dwItemUID);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CGameDispatch::ChangeName(PktBase* lpPktBase)
|
||||
{
|
||||
PktCharNameChange* lpCharNameChange =
|
||||
reinterpret_cast<PktCharNameChange*>(lpPktBase);
|
||||
|
||||
unsigned long dwUID = lpCharNameChange->m_dwUID;
|
||||
unsigned long dwCID = lpCharNameChange->m_dwCID;
|
||||
const char* szChangeName = lpCharNameChange->m_szCharName;
|
||||
Item::ItemPos ItemPos = lpCharNameChange->m_ItemPos; // 계명허가서 위치
|
||||
|
||||
unsigned char cNameChangeCount = 0;
|
||||
unsigned short usError = 0;
|
||||
|
||||
using namespace DBAgent::DataStorage;
|
||||
|
||||
CSessionData* lpSessionData =
|
||||
CSessionDataMgr::GetInstance().GetCharLoadedSession(dwCID);
|
||||
|
||||
CCharacterData* lpCharacterData = 0;
|
||||
|
||||
if (0 != lpSessionData &&
|
||||
lpSessionData->GetUID() == dwUID &&
|
||||
lpSessionData->GetCID() == dwCID &&
|
||||
(0 != (lpCharacterData = lpSessionData->GetCharacterData())) &&
|
||||
dwCID == lpCharacterData->GetCID())
|
||||
{
|
||||
unsigned long dwResult = 0;
|
||||
|
||||
const char* szPrevName = lpCharacterData->GetName();
|
||||
|
||||
// 카운트를 줄인다.
|
||||
CHAR_INFOEX infoEx = lpCharacterData->GetInfoEx();
|
||||
/*
|
||||
if (0 == infoEx.cNameChangeCount)
|
||||
{
|
||||
usError = PktCharNameChange::ERR_NAMECHANGE_COUNT;
|
||||
}
|
||||
else
|
||||
*/
|
||||
// 이상이 없으면 여기서 아이템을 감소시킨다.
|
||||
if (DBComponent::GameDB::ChangeCharName(
|
||||
CDBSingleObject::GetInstance(), dwCID, szChangeName, dwResult))
|
||||
{
|
||||
if (0 == dwResult)
|
||||
{
|
||||
CHAR_INFOST charInfoST = lpCharacterData->GetInfo();
|
||||
|
||||
strncpy(charInfoST.Name, szChangeName, CHAR_INFOST::MAX_NAME_LEN);
|
||||
charInfoST.Name[CHAR_INFOST::MAX_NAME_LEN - 1] = 0;
|
||||
|
||||
lpCharacterData->SetInfo(charInfoST, true);
|
||||
|
||||
infoEx.cNameChangeCount = 0;
|
||||
// --infoEx.cNameChangeCount; // 아이템으로 바뀐후 이부분은 사용안함.
|
||||
|
||||
cNameChangeCount = infoEx.cNameChangeCount;
|
||||
lpCharacterData->SetInfoEx(infoEx);
|
||||
|
||||
// 랭킹에서 찾는다 //
|
||||
if(CRankingMgr::GetInstance().GetRank(szPrevName, (unsigned char)lpCharacterData->GetClass()))
|
||||
{
|
||||
const CHAR_INFOST& charInfo = lpCharacterData->GetInfo();
|
||||
|
||||
// 데이터 삭제 //
|
||||
CRankingDBMgr::GetInstance().DeleteRanking(RankingNode(szPrevName, charInfo.Fame,
|
||||
static_cast<unsigned char>(charInfo.Level), static_cast<unsigned char>(charInfo.Class)));
|
||||
|
||||
// 데이터 업데이트 //
|
||||
CRankingDBMgr::GetInstance().UpdateRanking(RankingNode(szChangeName, charInfo.Fame,
|
||||
static_cast<unsigned char>(charInfo.Level), static_cast<unsigned char>(charInfo.Class)));
|
||||
}
|
||||
}
|
||||
else if(1 == dwResult)
|
||||
{
|
||||
ERRLOG3(g_Log, "UID:%10u / CID:%10u / ChangeName:%s / 캐릭터 이름 바꾸기 실패 : 이름이 이미 있습니다",
|
||||
dwUID, dwCID, szChangeName);
|
||||
|
||||
usError = PktCharNameChange::ERR_ALREADY_USE_NAME;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERRLOG4(g_Log, "UID:%10u / CID:%10u / ChangeName:%s / dwResult:%10u / 캐릭터 이름 바꾸기 실패 : 알 수 없는 dwResult값입니다",
|
||||
dwUID, dwCID, szChangeName, dwResult);
|
||||
|
||||
usError = PktCharNameChange::ERR_SERVER;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERRLOG3(g_Log, "UID:%10u / CID:%10u / ChangeName:%s / 캐릭터 이름 바꾸기 실패 : DB호출 에러",
|
||||
dwUID, dwCID, szChangeName);
|
||||
|
||||
usError = PktCharNameChange::ERR_SERVER;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERRLOG3(g_Log, "UID:%10u / CID:%10u / ChangeName:%s / "
|
||||
"캐릭터 이름 바꾸기 실패 : 캐릭터가 활성화 된 세션이 없습니다",
|
||||
dwUID, dwCID, szChangeName);
|
||||
|
||||
usError = PktCharNameChange::ERR_CANNOT_FIND_CHARACTER;
|
||||
}
|
||||
|
||||
GameClientSendPacket::SendCharNameChange(GetSendStream(), dwUID, dwCID,
|
||||
szChangeName, cNameChangeCount, &ItemPos, usError);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void CGameDispatch::IncCharNum(int nRace)
|
||||
{
|
||||
switch(nRace)
|
||||
{
|
||||
case CClass::HUMAN: ++m_nHumanNum; break;
|
||||
case CClass::AKHAN: ++m_nAkhanNum; break;
|
||||
}
|
||||
}
|
||||
|
||||
void CGameDispatch::DecCharNum(int nRace)
|
||||
{
|
||||
switch(nRace)
|
||||
{
|
||||
case CClass::HUMAN: --m_nHumanNum; break;
|
||||
case CClass::AKHAN: --m_nAkhanNum; break;
|
||||
}
|
||||
}
|
||||
|
||||
int CGameDispatch::GetCharNum(int nRace) const
|
||||
{
|
||||
int nNum = -1;
|
||||
|
||||
switch(nRace)
|
||||
{
|
||||
case CClass::HUMAN: nNum = m_nHumanNum; break;
|
||||
case CClass::AKHAN: nNum = m_nAkhanNum; break;
|
||||
}
|
||||
|
||||
return (nNum < 1) ? 1 : nNum;
|
||||
}
|
||||
|
||||
int CGameDispatch::GetCharNum() const
|
||||
{
|
||||
int nUserNumber = m_nHumanNum + m_nAkhanNum - 1;
|
||||
return (nUserNumber < 1) ? 1 : nUserNumber;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 나중에 개수 많아지면 분리할 것..
|
||||
bool ParseServerLog(CSendStream& SendStream, PktBase* lpPktBase)
|
||||
{
|
||||
PktServerLog* lpPktServerLog = static_cast<PktServerLog*>(lpPktBase);
|
||||
|
||||
switch(lpPktServerLog->m_cLogCmd)
|
||||
{
|
||||
case PktServerLog::ITEM_DUPLICATED_LOG:
|
||||
{
|
||||
PktItemDuplicated* lpPktItemDup = static_cast<PktItemDuplicated*>(lpPktServerLog);
|
||||
|
||||
if(!DBComponent::GameDB::InsertItemDuplicatedLog(CDBSingleObject::GetInstance(),
|
||||
lpPktItemDup->m_dwItemSerial, lpPktItemDup->m_szName,
|
||||
lpPktItemDup->m_dwUID, lpPktItemDup->m_dwCID, lpPktItemDup->m_dwQty))
|
||||
{
|
||||
ERRLOG5(g_Log, "UID:%10u / CID:%10u / CharName:%s / ItemSerial:0x%I64X / Qty:%u / 아이템 복사가 발견되었습니다",
|
||||
lpPktItemDup->m_dwUID, lpPktItemDup->m_dwCID, lpPktItemDup->m_szName,
|
||||
lpPktItemDup->m_dwItemSerial, lpPktItemDup->m_dwQty);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
// 각종 함수자 메서드
|
||||
|
||||
CGetTotalCount::CGetTotalCount(unsigned short& usHumanCount,
|
||||
unsigned short& usAkhanCount,
|
||||
unsigned char& cChannelCount)
|
||||
: m_usHumanCount(usHumanCount),
|
||||
m_usAkhanCount(usAkhanCount),
|
||||
m_cChannelCount(cChannelCount)
|
||||
{
|
||||
m_usHumanCount = 0;
|
||||
m_usAkhanCount = 0;
|
||||
m_cChannelCount = 0;
|
||||
}
|
||||
|
||||
bool CGetTotalCount::operator () (unsigned long dwServerID, CPacketDispatch& packetDispatch)
|
||||
{
|
||||
CGameDispatch& gameDispatch = reinterpret_cast<CGameDispatch&>(packetDispatch);
|
||||
|
||||
int nCharNum = gameDispatch.GetCharNum(CClass::HUMAN);
|
||||
m_usHumanCount += nCharNum;
|
||||
|
||||
nCharNum = gameDispatch.GetCharNum(CClass::AKHAN);
|
||||
m_usAkhanCount += nCharNum;
|
||||
|
||||
++m_cChannelCount;
|
||||
return true;
|
||||
}
|
||||
|
||||
CUserPercentageInZone::CUserPercentageInZone(unsigned short* lpChannelUserNum,
|
||||
unsigned char cZone, unsigned char cChannelNum)
|
||||
: m_lpChannelUserNum(lpChannelUserNum),
|
||||
m_cZone(cZone),
|
||||
m_cChannelNum(cChannelNum),
|
||||
m_nMaxUserNum(CServerSetup::GetInstance().GetUserLimit())
|
||||
{
|
||||
std::fill_n(m_lpChannelUserNum, m_cChannelNum, 0);
|
||||
}
|
||||
|
||||
bool CUserPercentageInZone::operator () (unsigned long dwServerID, CPacketDispatch& packetDispatch)
|
||||
{
|
||||
CGameDispatch& gameDispatch = reinterpret_cast<CGameDispatch&>(packetDispatch);
|
||||
|
||||
SERVER_ID serverID;
|
||||
serverID.dwID = dwServerID;
|
||||
|
||||
if(serverID.GetZone() == m_cZone)
|
||||
{
|
||||
if(serverID.GetChannel() < m_cChannelNum)
|
||||
{
|
||||
m_lpChannelUserNum[serverID.GetChannel()] =
|
||||
gameDispatch.GetCharNum() * 100 / m_nMaxUserNum + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
CSendPacketToZone::CSendPacketToZone(const char* szData, unsigned long dwDataLen,
|
||||
unsigned char cPacketCmd, unsigned char cZone)
|
||||
: m_szData(szData), m_dwDataLen(dwDataLen),
|
||||
m_cPacketCmd(cPacketCmd), m_cZone(cZone)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
bool CSendPacketToZone::operator () (unsigned long dwServerID, CPacketDispatch& packetDispatch)
|
||||
{
|
||||
SERVER_ID serverID;
|
||||
serverID.dwID = dwServerID;
|
||||
|
||||
if(serverID.GetZone() == m_cZone)
|
||||
{
|
||||
return reinterpret_cast<CRylServerDispatch&>(packetDispatch).GetSendStream().PutBuffer(
|
||||
m_szData, m_dwDataLen, m_cPacketCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
#ifndef _DBAGENT_SERVER_GAME_DISPATCH_H_
|
||||
#define _DBAGENT_SERVER_GAME_DISPATCH_H_
|
||||
|
||||
#include <Network/Dispatch/RylServerDispatch.h>
|
||||
#include <Network/Dispatch/MultiDispatchStorage.h>
|
||||
|
||||
#include <Item/ItemSerialMgr.h>
|
||||
|
||||
// forward decl.
|
||||
struct PktSL;
|
||||
struct PktBase;
|
||||
struct PktUK;
|
||||
struct PktAdmin;
|
||||
|
||||
namespace DBAgent
|
||||
{
|
||||
class CGameDispatch : public CRylServerDispatch
|
||||
{
|
||||
public:
|
||||
|
||||
static CMultiDispatch& GetDispatchTable();
|
||||
|
||||
enum Const
|
||||
{
|
||||
// edith 2008.03.04 CGameDispatch 수정
|
||||
MAX_PACKET_DISPATCH_PER_PULSE = 100,
|
||||
MAX_STREAM_BUFFER_SIZE = 16000
|
||||
};
|
||||
|
||||
CGameDispatch(CSession& Session);
|
||||
virtual ~CGameDispatch();
|
||||
|
||||
virtual void Connected();
|
||||
virtual void Disconnected();
|
||||
virtual bool DispatchPacket(PktBase* lpPktBase);
|
||||
|
||||
void IncCharNum(int nRace);
|
||||
void DecCharNum(int nRace);
|
||||
|
||||
int GetCharNum(int nRace) const; // 항상 실 인원수보다 한명이 많다.
|
||||
int GetCharNum() const; // 항상 실 인원수보다 한명이 많다.
|
||||
|
||||
unsigned long GetServerID() const { return m_dwServerID; }
|
||||
|
||||
private:
|
||||
|
||||
bool ServerLogin(PktBase* lpPktBase);
|
||||
bool ServerLogout(PktBase* lpPktBase);
|
||||
|
||||
bool UserKillAck(PktBase* lpPktBase);
|
||||
bool CharAdminCmd(PktBase* lpPktBase);
|
||||
bool GiveItemToTempInven(PktBase* lpPktBase);
|
||||
bool ChangeName(PktBase* lpPktBase);
|
||||
|
||||
Item::CItemSerialMgr m_GameItemSerialMgr;
|
||||
|
||||
// 인원수는 항상 한명이 많게 관리하고, 보여줄때만 1씩 빼서 보여준다.
|
||||
// 그 이유는 채널의 존재 여부를 인원수가 0인지 아닌지로 파악하기 때문이다.
|
||||
int m_nHumanNum;
|
||||
int m_nAkhanNum;
|
||||
|
||||
unsigned long m_dwServerID;
|
||||
};
|
||||
|
||||
|
||||
// 전체 캐릭터 수를 얻어오는 함수자이다. CMultiDispatch::Process 에 사용한다.
|
||||
class CGetTotalCount
|
||||
{
|
||||
public:
|
||||
|
||||
CGetTotalCount(unsigned short& usHumanCount, unsigned short& usAkhanCount,
|
||||
unsigned char& cChannelCount);
|
||||
bool operator () (unsigned long dwServerID, CPacketDispatch& packetDispatch);
|
||||
|
||||
private:
|
||||
|
||||
unsigned short& m_usHumanCount;
|
||||
unsigned short& m_usAkhanCount;
|
||||
unsigned char& m_cChannelCount;
|
||||
};
|
||||
|
||||
// 존당 캐릭터 수 퍼센티지를 얻어오는 함수자이다. CMultiDispatch::Process 에 사용한다.
|
||||
class CUserPercentageInZone
|
||||
{
|
||||
public:
|
||||
|
||||
CUserPercentageInZone(unsigned short* lpChannelUserNum,
|
||||
unsigned char cZone, unsigned char cChannelNum);
|
||||
bool operator () (unsigned long dwServerID, CPacketDispatch& packetDispatch);
|
||||
|
||||
private:
|
||||
|
||||
int m_nMaxUserNum;
|
||||
unsigned short* m_lpChannelUserNum;
|
||||
unsigned char m_cZone;
|
||||
unsigned char m_cChannelNum;
|
||||
};
|
||||
|
||||
// 특정 존의 모든 채널에 패킷을 보낸다.
|
||||
class CSendPacketToZone
|
||||
{
|
||||
public:
|
||||
|
||||
CSendPacketToZone(const char* szData, unsigned long dwDataLen,
|
||||
unsigned char cPacketCmd, unsigned char cZone);
|
||||
bool operator () (unsigned long dwServerID, CPacketDispatch& packetDispatch);
|
||||
|
||||
private:
|
||||
|
||||
const char* m_szData;
|
||||
unsigned long m_dwDataLen;
|
||||
unsigned char m_cPacketCmd;
|
||||
unsigned char m_cZone;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
#include "stdafx.h"
|
||||
#include "LoginDispatch.h"
|
||||
|
||||
#include <Log/ServerLog.h>
|
||||
#include <Network/Address/INET_Addr.h>
|
||||
#include <Network/SendPacket/SendServerInfo.h>
|
||||
|
||||
#include <Utility/Setup/ServerSetup.h>
|
||||
|
||||
namespace DBAgent
|
||||
{
|
||||
|
||||
CSingleDispatch& CLoginDispatch::GetDispatchTable()
|
||||
{
|
||||
static CSingleDispatch loginDispatch;
|
||||
return loginDispatch;
|
||||
}
|
||||
|
||||
CLoginDispatch::CLoginDispatch(CSession& Session)
|
||||
: CRylServerDispatch(Session, MAX_PACKET_DISPATCH_PER_PULSE)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
CLoginDispatch::~CLoginDispatch()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
void CLoginDispatch::Connected()
|
||||
{
|
||||
DETLOG3(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/LoginServer Connected",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string());
|
||||
|
||||
GetDispatchTable().SetDispatch(this);
|
||||
|
||||
CSendStream& SendStream = GetSendStream();
|
||||
unsigned long dwServerID = CServerSetup::GetInstance().GetServerID();
|
||||
|
||||
SendPacket::ServerLogin(SendStream, dwServerID);
|
||||
SendPacket::UpdateServerVersion(SendStream);
|
||||
SendPacket::UpdateChannel(SendStream, dwServerID);
|
||||
}
|
||||
|
||||
void CLoginDispatch::Disconnected()
|
||||
{
|
||||
DETLOG3(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/LoginServer Disconnected",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string());
|
||||
|
||||
GetDispatchTable().RemoveDispatch(this);
|
||||
}
|
||||
|
||||
bool CLoginDispatch::DispatchPacket(PktBase* lpPktBase)
|
||||
{
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef _DBAGENT_SERVER_LOGIN_DISPATCH_H_
|
||||
#define _DBAGENT_SERVER_LOGIN_DISPATCH_H_
|
||||
|
||||
#include <Network/Dispatch/RylServerDispatch.h>
|
||||
#include <Network/Dispatch/SingleDispatchStorage.h>
|
||||
|
||||
namespace DBAgent
|
||||
{
|
||||
class CLoginDispatch : public CRylServerDispatch
|
||||
{
|
||||
public:
|
||||
|
||||
static CSingleDispatch& GetDispatchTable();
|
||||
|
||||
enum Const
|
||||
{
|
||||
MAX_PACKET_DISPATCH_PER_PULSE = 10,
|
||||
MAX_STREAM_BUFFER_SIZE = 16000
|
||||
};
|
||||
|
||||
CLoginDispatch(CSession& Session);
|
||||
virtual ~CLoginDispatch();
|
||||
|
||||
virtual void Connected();
|
||||
virtual void Disconnected();
|
||||
virtual bool DispatchPacket(PktBase* lpPktBase);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,623 @@
|
||||
#include "stdafx.h"
|
||||
#include "AuthDispatch.h"
|
||||
#include "Part1DBAgentDispatch.h"
|
||||
|
||||
#include <Log/ServerLog.h>
|
||||
#include <Network/Address/INET_Addr.h>
|
||||
#include <Network/SendPacket/SendServerInfo.h>
|
||||
#include <Network/SendPacket/SendCharManage.h>
|
||||
|
||||
#include <Network/Packet/PacketCommand.h>
|
||||
#include <Network/Packet/PacketStruct/UnifiedCharPacket.h>
|
||||
|
||||
#include <Utility/Setup/ServerSetup.h>
|
||||
|
||||
#include <DataStorage/SessionDataMgr.h>
|
||||
#include <DataStorage/StoreDataMgr.h>
|
||||
#include <DataStorage/CharacterDataMgr.h>
|
||||
|
||||
#include <Creature/Creature.h>
|
||||
#include <Creature/Character/CharacterClass.h>
|
||||
|
||||
#include <DB/DBComponent.h>
|
||||
#include <DB/GameDBComponent.h>
|
||||
|
||||
#include <Network/Packet/PacketStruct/CharQuestPacket.h>
|
||||
|
||||
namespace DBAgent
|
||||
{
|
||||
|
||||
class CCharBackupItemData
|
||||
{
|
||||
public:
|
||||
|
||||
CCharBackupItemData()
|
||||
: m_bBackupData(false), m_cOldServerGroupID(0)
|
||||
{
|
||||
memset(&m_CharInfo, 0, sizeof(CHAR_INFOST)); // 기본 정보
|
||||
memset(&m_Skill, 0, sizeof(SKILL)); // 스킬 정보
|
||||
|
||||
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)); // 임시 인벤토리
|
||||
|
||||
memset(&m_Quest, 0, sizeof(QUEST)); // 퀘스트
|
||||
memset(&m_History, 0, sizeof(HISTORY)); // 히스토리
|
||||
}
|
||||
|
||||
bool IsBackupedData() const { return m_bBackupData; }
|
||||
unsigned char GetOldServerGroupID() const { return m_cOldServerGroupID; }
|
||||
|
||||
void BackupData(DataStorage::CSessionData& sessionData, DataStorage::CCharacterData& charData)
|
||||
{
|
||||
m_CharInfo = charData.GetInfo();
|
||||
m_Skill = charData.GetSkill();
|
||||
m_Equip = charData.GetEquip();
|
||||
m_Inven = charData.GetInven();
|
||||
m_Extra = charData.GetExtra();
|
||||
m_Exchange = charData.GetExchange();
|
||||
m_TempInven = charData.GetTempInven();
|
||||
|
||||
m_Quest = charData.GetQuest();
|
||||
m_History = charData.GetHistory();
|
||||
|
||||
const UnifiedCharData* lpUnifiedCharData =
|
||||
sessionData.GetUnifiedCharData(charData.GetCID());
|
||||
|
||||
if(0 != lpUnifiedCharData)
|
||||
{
|
||||
m_cOldServerGroupID = lpUnifiedCharData->cOldServerGroupID;
|
||||
}
|
||||
|
||||
m_bBackupData = true;
|
||||
}
|
||||
|
||||
void RestoreData(DataStorage::CCharacterData& charData)
|
||||
{
|
||||
if (m_bBackupData)
|
||||
{
|
||||
charData.SetInfo(m_CharInfo);
|
||||
charData.SetSkill(m_Skill);
|
||||
charData.SetEquip(m_Equip.Data, m_Equip.dwSize);
|
||||
charData.SetInven(m_Inven.Data, m_Inven.dwSize);
|
||||
charData.SetExtra(m_Extra.Data, m_Extra.dwSize);
|
||||
charData.SetExchange(m_Exchange.Data, m_Exchange.dwSize);
|
||||
charData.SetTempInven(m_TempInven.Data, m_TempInven.dwSize);
|
||||
|
||||
charData.SetQuest(m_Quest);
|
||||
charData.SetHistory(m_History);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
CHAR_INFOST m_CharInfo; // 기본 정보
|
||||
SKILL m_Skill; // 스킬 정보
|
||||
|
||||
EQUIP m_Equip; // 장비
|
||||
INVEN m_Inven; // 인벤
|
||||
EXTRA m_Extra; // 여분
|
||||
EXCHANGE m_Exchange; // 교환
|
||||
TEMPINVEN m_TempInven; // 임시 인벤토리
|
||||
|
||||
QUEST m_Quest; // 퀘스트
|
||||
HISTORY m_History; // History
|
||||
|
||||
unsigned char m_cOldServerGroupID; // 예전 서버그룹 ID
|
||||
bool m_bBackupData; // 데이터 백업되었는지 여부
|
||||
|
||||
};
|
||||
|
||||
void ProcessUnifiedCharSelect(CSendStream& SendStream, PktBase* lpPktBase);
|
||||
|
||||
|
||||
CSingleDispatch& CPart1DBAgentDispatch::GetDispatchTable()
|
||||
{
|
||||
static CSingleDispatch part1DBAgentDispatch;
|
||||
return part1DBAgentDispatch;
|
||||
}
|
||||
|
||||
CPart1DBAgentDispatch::CPart1DBAgentDispatch(CSession& Session)
|
||||
: CRylServerDispatch(Session, MAX_PACKET_DISPATCH_PER_PULSE)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
CPart1DBAgentDispatch::~CPart1DBAgentDispatch()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
void CPart1DBAgentDispatch::Connected()
|
||||
{
|
||||
DETLOG3(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/Part1 DBAgentServer Connected",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string());
|
||||
|
||||
GetDispatchTable().SetDispatch(this);
|
||||
|
||||
SendPacket::ServerLogin(GetSendStream(),
|
||||
CServerSetup::GetInstance().GetServerID());
|
||||
}
|
||||
|
||||
|
||||
void CPart1DBAgentDispatch::Disconnected()
|
||||
{
|
||||
DETLOG3(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/Part1 DBAgentServer Disconnected",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string());
|
||||
|
||||
GetDispatchTable().RemoveDispatch(this);
|
||||
}
|
||||
|
||||
|
||||
bool CPart1DBAgentDispatch::DispatchPacket(PktBase* lpPktBase)
|
||||
{
|
||||
switch(lpPktBase->GetCmd())
|
||||
{
|
||||
case CmdUnifiedCharSelect:
|
||||
ProcessUnifiedCharSelect(GetSendStream(), lpPktBase);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPart1DBAgentDispatch::TransferCharPart1ToPart2(CSendStream& SendStream, unsigned long dwUID,
|
||||
unsigned char cSelectedServerGroup,
|
||||
unsigned char cSelectedNation,
|
||||
unsigned long* lpdwSelectedCID,
|
||||
unsigned char cSelectedCharNum)
|
||||
{
|
||||
char* lpBuffer = SendStream.GetBuffer(sizeof(PktUnifiedCharSelectReq));
|
||||
|
||||
if(0 != lpBuffer)
|
||||
{
|
||||
PktUnifiedCharSelectReq* lpPktUnifiedCharSelectReq =
|
||||
reinterpret_cast<PktUnifiedCharSelectReq*>(lpBuffer);
|
||||
|
||||
memset(lpPktUnifiedCharSelectReq->szPassword, 0,
|
||||
sizeof(char) * PktUnifiedCharSelectReq::MAX_PASSWORD_LEN);
|
||||
|
||||
lpPktUnifiedCharSelectReq->cSelectedNation = cSelectedNation;
|
||||
lpPktUnifiedCharSelectReq->cSelectedServerGroupID = cSelectedServerGroup;
|
||||
lpPktUnifiedCharSelectReq->dwRequestKey = 0;
|
||||
|
||||
lpPktUnifiedCharSelectReq->dwUID = dwUID;
|
||||
memcpy(lpPktUnifiedCharSelectReq->dwCID, lpdwSelectedCID,
|
||||
sizeof(unsigned long) * std::min(int(cSelectedCharNum), int(USER_INFO::MAX_CHAR_NUM)));
|
||||
|
||||
return SendStream.WrapHeader(sizeof(PktUnifiedCharSelectReq), CmdUnifiedCharSelect, 0, 0);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void ProcessUnifiedCharSelect(CSendStream& SendStream, PktBase* lpPktBase)
|
||||
{
|
||||
PktUnifiedCharSelectReq* lpPktUnifiedCharSelectReq =
|
||||
reinterpret_cast<PktUnifiedCharSelectReq*>(lpPktBase);
|
||||
|
||||
unsigned long dwUID = lpPktUnifiedCharSelectReq->dwUID;
|
||||
unsigned long dwRequestKey = lpPktUnifiedCharSelectReq->dwRequestKey;
|
||||
unsigned char cSelectedServerGroupID = lpPktUnifiedCharSelectReq->cSelectedServerGroupID;
|
||||
unsigned char cSelectedNation = lpPktUnifiedCharSelectReq->cSelectedNation;
|
||||
|
||||
unsigned short usError = 0;
|
||||
|
||||
using namespace DBAgent::DataStorage;
|
||||
|
||||
unsigned char cAgentServerType = static_cast<unsigned char>(
|
||||
CServerSetup::GetInstance().GetAgentServerType());
|
||||
|
||||
CStoreDataMgr& storeDataMgr = CStoreDataMgr::GetInstance();
|
||||
CCharacterDataMgr& charDataMgr = CCharacterDataMgr::GetInstance();
|
||||
CDBComponent& dbComponent = CDBSingleObject::GetInstance();
|
||||
|
||||
UnifiedStoreKey srcStoreKey(dwUID, cSelectedServerGroupID);
|
||||
UnifiedStoreKey dstStoreKey(dwUID, cAgentServerType);
|
||||
|
||||
CSessionData* lpSessionData = 0;
|
||||
CStoreData* lpStoreData = 0;
|
||||
CCharacterData* lpCharacterData = 0;
|
||||
|
||||
if(0 != lpPktBase->GetError())
|
||||
{
|
||||
// 해당 UID가 없다.
|
||||
ERRLOG2(g_Log, "UID:%10u / Part2Unified 캐릭터 선택 실패 - Part1 DB중계서버에서 %d에러를 전송했습니다.",
|
||||
dwUID, lpPktBase->GetError());
|
||||
|
||||
usError = lpPktBase->GetError();
|
||||
}
|
||||
else if(0 == (lpSessionData = CSessionDataMgr::GetInstance().GetOpenSession(dwUID)))
|
||||
{
|
||||
// 해당 UID가 없다.
|
||||
ERRLOG1(g_Log, "UID:%10u / Part2Unified 캐릭터 선택 실패 - 세션이 닫혀 있습니다", dwUID);
|
||||
|
||||
usError = PktUnifiedCharSelectAck::SERVER_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 창고 선택한 적 없음
|
||||
if (!(lpSessionData->GetFirstLogin() & UnifiedConst::SELECTED_PART2))
|
||||
{
|
||||
// 혹시 캐쉬나 loginDB에 데이터가 들어있는지 살핀다. 있으면 전부 제거한다.
|
||||
if(storeDataMgr.IsDataLoginDB(srcStoreKey))
|
||||
{
|
||||
ERRLOG2(g_Log, "UID:%10u / SrcServerGroupID:%d / Part2Unified 창고 선택 실패 - 해당 창고가 로그인해 있습니다.",
|
||||
srcStoreKey.first, srcStoreKey.second);
|
||||
|
||||
usError = PktUnifiedCharSelectAck::SERVER_ERROR;
|
||||
}
|
||||
else if(storeDataMgr.IsDataLoginDB(dstStoreKey))
|
||||
{
|
||||
ERRLOG2(g_Log, "UID:%10u / DstServerGroupID:%d / Part2Unified 창고 선택 실패 - 해당 창고가 로그인해 있습니다.",
|
||||
dstStoreKey.first, dstStoreKey.second);
|
||||
|
||||
usError = PktUnifiedCharSelectAck::SERVER_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 일단 캐쉬에서 데이터를 내린다.
|
||||
if(storeDataMgr.RemoveLogoutData(srcStoreKey))
|
||||
{
|
||||
ERRLOG2(g_Log, "UID:%10u / SrcServerGroupID:%d / "
|
||||
"Part2Unified 창고 선택 이상 - 해당 데이터가 캐쉬에 들어 있어 강제로 내립니다.",
|
||||
srcStoreKey.first, srcStoreKey.second);
|
||||
}
|
||||
|
||||
if(storeDataMgr.RemoveLogoutData(dstStoreKey))
|
||||
{
|
||||
ERRLOG2(g_Log, "UID:%10u / DstServerGroupID:%d / "
|
||||
"Part2Unified 창고 선택 이상 - 해당 데이터가 캐쉬에 들어 있어 강제로 내립니다.",
|
||||
dstStoreKey.first, dstStoreKey.second);
|
||||
}
|
||||
|
||||
// 선택한 서버군 창고를 내 서버그룹 창고로 복사한다!
|
||||
if (!lpSessionData->ChangeUnifiedStoreInfoGroup(
|
||||
dbComponent, cSelectedServerGroupID, cAgentServerType))
|
||||
{
|
||||
usError = PktUnifiedCharSelectAck::UNIFIED_STORE_READ_ERROR;
|
||||
}
|
||||
// 복사 잘 됐으면 캐쉬로 로드해서 컨버팅을 한다.
|
||||
else
|
||||
{
|
||||
if(0 == (lpStoreData = storeDataMgr.GetLogoutData(dstStoreKey)))
|
||||
{
|
||||
ERRLOG2(g_Log, "UID:%10u / ServerGroupID:%d / 통합서버 선택 실패 : 창고 캐쉬로 데이터 로드 실패",
|
||||
dwUID, cSelectedServerGroupID);
|
||||
|
||||
usError = PktUnifiedCharSelectAck::UNIFIED_STORE_READ_ERROR;
|
||||
}
|
||||
// 창고 데이터를 Part2아이템으로 컨버팅한다.
|
||||
else if (!lpStoreData->ConvertToPart2Item(true))
|
||||
{
|
||||
ERRLOG2(g_Log, "UID:%10u / ServerGroupID:%d / 통합서버 선택 실패 : 창고 파트2 아이템으로 아이템 컨버팅 실패",
|
||||
dwUID, cSelectedServerGroupID);
|
||||
|
||||
usError = PktUnifiedCharSelectAck::UNIFIED_STORE_WRITE_ERROR;
|
||||
}
|
||||
// 창고 데이터를 저장한다.
|
||||
else if(!lpStoreData->ForceUpdateDBAllData(dbComponent))
|
||||
{
|
||||
ERRLOG2(g_Log, "UID:%10u / ServerGroupID:%d / 통합서버 선택 실패 : 컨버팅된 창고 데이터를 저장 실패",
|
||||
dwUID, cSelectedServerGroupID);
|
||||
|
||||
usError = PktUnifiedCharSelectAck::UNIFIED_STORE_WRITE_ERROR;
|
||||
}
|
||||
else if(!DBComponent::GameDB::UpdateUserFirstLogin(dbComponent, dwUID,
|
||||
lpSessionData->GetFirstLogin() | UnifiedConst::SELECTED_PART2))
|
||||
{
|
||||
ERRLOG2(g_Log, "UID:%10u / ServerGroupID:%d / 통합서버 선택 실패 : 창고 가져왔음을 기록 실패",
|
||||
dwUID, cSelectedServerGroupID);
|
||||
}
|
||||
|
||||
if(0 != usError)
|
||||
{
|
||||
// 에러가 난 건 창고 데이터를 저장을 못 했기 때문이니,
|
||||
// 그냥 캐쉬에서 날리고 다시 세팅하면 된다.
|
||||
storeDataMgr.RemoveLogoutData(dstStoreKey);
|
||||
|
||||
if(!lpSessionData->ChangeUnifiedStoreInfoGroup(
|
||||
dbComponent, cAgentServerType, cSelectedServerGroupID))
|
||||
{
|
||||
ERRLOG3(g_Log, "UID:%10u / ServerGroupID:%d -> %d / 통합서버 선택 실패 : 창고 데이터 롤백 실패",
|
||||
dwUID, cAgentServerType, cSelectedServerGroupID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lpSessionData->SetFirstLogin(
|
||||
lpSessionData->GetFirstLogin() | UnifiedConst::SELECTED_PART2);
|
||||
|
||||
INFLOG2(g_Log, "UID:%10u / ServerGroupID:%d / 통합서버 선택 성공",
|
||||
dwUID, cSelectedServerGroupID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 캐릭터 선택 쪽을 처리한다.
|
||||
|
||||
// 1. 캐릭터를 받으면, 일단 UserInfo를 로드한 후에,
|
||||
// 올바른 슬롯에 넣은 중복되지 않는 캐릭터를 찾는다.
|
||||
|
||||
// 2. 정리가 끝나면 Part1 DB중계서버에, 해당 캐릭터를 캐쉬에서 언로드하고
|
||||
// 길드 / 파티를 탈퇴시키라고 요청한다.
|
||||
|
||||
// 3. 요청 결과가 성공으로 돌아오면, 해당 캐릭터를 DB에서 로드하고
|
||||
// 데이터를 컨버팅 한 후에 저장한다. 컨버팅이나 저장이 실패하면 데이터를 롤백한다.
|
||||
|
||||
// 4. 모든 작업이 무사히 끝나면, DB의 UserInfo를 갱신한다.
|
||||
|
||||
CClass::RaceType eRace =
|
||||
lpSessionData->CheckUnifiedCharRace(lpPktUnifiedCharSelectReq->dwCID);
|
||||
|
||||
USER_INFO userInfo = lpSessionData->GetUserInfo();
|
||||
|
||||
// 유저 바인딩 검사를 한번 더 한다.
|
||||
unsigned long dwSelectedCID[USER_INFO::MAX_CHAR_NUM];
|
||||
unsigned long* lpdwRequestedCID = lpPktUnifiedCharSelectReq->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 == eRace)
|
||||
{
|
||||
usError = PktUnifiedCharSelectAck::PACKET_ERROR;
|
||||
}
|
||||
else if(0 == usError)
|
||||
{
|
||||
// 한바퀴 돌면서 아이템 컨버팅 / 스킬북 컨버팅 등을 수행한다.
|
||||
CCharBackupItemData backupData[USER_INFO::MAX_CHAR_NUM];
|
||||
|
||||
for(int nCount = 0; nCount < USER_INFO::MAX_CHAR_NUM; ++nCount)
|
||||
{
|
||||
if(0 != dwSelectedCID[nCount])
|
||||
{
|
||||
if(0 == (lpCharacterData = charDataMgr.GetLogoutData(dwSelectedCID[nCount])))
|
||||
{
|
||||
ERRLOG3(g_Log, "UID:%10u / CID:%10u / ServerGroupID:%d / 통합서버 선택 실패 : 캐릭터 캐쉬로 데이터 로드 실패",
|
||||
dwUID, dwSelectedCID[nCount], cSelectedServerGroupID);
|
||||
|
||||
usError = PktUnifiedCharSelectAck::UNIFIED_CHAR_READ_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 데이터를 백업한다.
|
||||
backupData[nCount].BackupData(*lpSessionData, *lpCharacterData);
|
||||
|
||||
// Part2 아이템으로 컨버팅한다.
|
||||
if (!lpCharacterData->ConvertToPart2Item(true))
|
||||
{
|
||||
ERRLOG3(g_Log, "UID:%10u / CID:%10u / ServerGroupID:%d / 통합서버 선택 실패 : 캐릭터 Part2아이템으로 컨버팅 실패",
|
||||
dwUID, dwSelectedCID[nCount], cSelectedServerGroupID);
|
||||
|
||||
usError = PktUnifiedCharSelectAck::UNIFIED_CHAR_WRITE_ERROR;
|
||||
}
|
||||
// UnifiedCharInfo에서, 캐릭터 서버군 번호를 수정한다.
|
||||
else if (!lpSessionData->ChangeUnifiedCharServerGroupID(
|
||||
dbComponent, dwUID, dwSelectedCID[nCount], cAgentServerType))
|
||||
{
|
||||
usError = PktUnifiedCharSelectAck::UNIFIED_CHAR_WRITE_ERROR;
|
||||
}
|
||||
else if (!lpCharacterData->ForceUpdateDBAllData(dbComponent))
|
||||
{
|
||||
ERRLOG3(g_Log, "UID:%10u / CID:%10u / ServerGroupID:%d / 통합서버 선택 실패 : 캐릭터 아이템 저장 실패",
|
||||
dwUID, dwSelectedCID[nCount], cSelectedServerGroupID);
|
||||
|
||||
usError = PktUnifiedCharSelectAck::UNIFIED_CHAR_WRITE_ERROR;
|
||||
}
|
||||
|
||||
if(0 != usError)
|
||||
{
|
||||
// 에러가 있으면 바로 롤백;;
|
||||
break;
|
||||
}
|
||||
|
||||
// 양국체제로 변경 //
|
||||
if(lpSessionData->GetAccountNation()==Creature::ALMIGHTY_PIRATE)
|
||||
{
|
||||
/* 국적이 신의 해적단이면서, 종족이 휴먼인 사람들의 국적을 카르테란트로 바꿔준다. */
|
||||
if(lpCharacterData->GetRace()==CClass::HUMAN)
|
||||
{
|
||||
lpSessionData->SetAccountNation(Creature::KARTERANT);
|
||||
}
|
||||
/* 국적이 신의 해적단이면서, 종족이 아칸인 사람들의 국적을 메르카디아로 바꿔준다. */
|
||||
else if(lpCharacterData->GetRace()==CClass::AKHAN)
|
||||
{
|
||||
lpSessionData->SetAccountNation(Creature::MERKADIA);
|
||||
}
|
||||
}
|
||||
|
||||
// 친구리스트, 거부 리스트 삭제 //
|
||||
/*unsigned long dwMemberCID[CFriendList::MAX_FRIENDS_NUM] = {0,};
|
||||
unsigned long dwDeleteCID[CFriendList::MAX_FRIENDS_NUM] = {0,};
|
||||
|
||||
// 친구리스트에 CID 만 가지고 온다. //
|
||||
CFriendList friendList = lpCharacterData->GetFriendList();
|
||||
|
||||
friendList.GetCIDList(dwMemberCID);
|
||||
|
||||
for(unsigned char cIndex = 0; cIndex < friendList.GetFriendNum(); cIndex++)
|
||||
{
|
||||
CFriendList::Rebind* lpRebind = friendList.GetFriend(dwMemberCID[cIndex]);
|
||||
|
||||
if(lpCharacterData->GetRace()==CClass::HUMAN)
|
||||
{
|
||||
if(lpRebind->GetClass()>=CClass::Combatant)
|
||||
{
|
||||
dwDeleteCID[cIndex] = dwMemberCID[cIndex];
|
||||
}
|
||||
}
|
||||
else if(lpCharacterData->GetRace()==CClass::AKHAN)
|
||||
{
|
||||
if(lpRebind->GetClass()<CClass::Combatant)
|
||||
{
|
||||
dwDeleteCID[cIndex] = dwMemberCID[cIndex];
|
||||
}
|
||||
}
|
||||
|
||||
// 다른 종족일 경우 삭제 //
|
||||
if(dwDeleteCID[cIndex])
|
||||
{
|
||||
friendList.Remove(dwDeleteCID[cIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
memset(dwMemberCID, 0, sizeof(unsigned long) * CFriendList::MAX_FRIENDS_NUM);
|
||||
memset(dwDeleteCID, 0, sizeof(unsigned long) * CFriendList::MAX_FRIENDS_NUM);
|
||||
|
||||
CBanList banList = lpCharacterData->GetBanList();
|
||||
|
||||
banList.GetCIDList(dwMemberCID);
|
||||
|
||||
for(unsigned char cIndex = 0; cIndex < banList.GetBanNum(); cIndex++)
|
||||
{
|
||||
CBanList::Rebind* lpRebind = banList.GetBan(dwMemberCID[cIndex]);
|
||||
|
||||
if(lpCharacterData->GetRace()==CClass::HUMAN)
|
||||
{
|
||||
if(lpRebind->GetClass()>=CClass::Combatant)
|
||||
{
|
||||
dwDeleteCID[cIndex] = dwMemberCID[cIndex];
|
||||
}
|
||||
}
|
||||
else if(lpCharacterData->GetRace()==CClass::AKHAN)
|
||||
{
|
||||
if(lpRebind->GetClass()<CClass::Combatant)
|
||||
{
|
||||
dwDeleteCID[cIndex] = dwMemberCID[cIndex];
|
||||
}
|
||||
}
|
||||
|
||||
// 다른 종족일 경우 삭제 //
|
||||
if(dwDeleteCID[cIndex])
|
||||
{
|
||||
banList.Remove(dwDeleteCID[cIndex]);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 에러가 없으면 데이터를 바인딩한다.
|
||||
if(0 == usError)
|
||||
{
|
||||
// 선택된 캐릭터가 한마리도 없었으면, 국적을 선택한다.
|
||||
if(0 == userInfo.GetCharacterNum())
|
||||
{
|
||||
unsigned char cOldAccountNation = lpSessionData->GetAccountNation();
|
||||
|
||||
// 선택한 국가가 종족과 맞는지 체크한 후 세팅한다.
|
||||
if(Creature::ALMIGHTY_PIRATE == cSelectedNation)
|
||||
{
|
||||
lpSessionData->SetAccountNation(Creature::ALMIGHTY_PIRATE);
|
||||
}
|
||||
else
|
||||
{
|
||||
lpSessionData->SetAccountNation(
|
||||
CClass::HUMAN == eRace ? Creature::KARTERANT : Creature::MERKADIA);
|
||||
}
|
||||
|
||||
if (cOldAccountNation != lpSessionData->GetAccountNation())
|
||||
{
|
||||
INFLOG3(g_Log, "UID:%10u / OldAccountNation:%s / AccountNation:%s / 국적 변경",
|
||||
dwUID, Creature::GetShortNationName(cOldAccountNation),
|
||||
Creature::GetShortNationName(lpSessionData->GetAccountNation()));
|
||||
}
|
||||
}
|
||||
|
||||
if(!lpSessionData->UpdateCharacterBinding(dbComponent, dwSelectedCID))
|
||||
{
|
||||
ERRLOG2(g_Log, "UID:%10u / ServerGroupID:%d / 통합서버 선택 실패 : 최종 캐릭터 바인딩에 실패했습니다",
|
||||
dwUID, cSelectedServerGroupID);
|
||||
|
||||
usError = PktUnifiedCharSelectAck::UNIFIED_CHAR_WRITE_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 창고/캐릭터 이전에 성공했다!
|
||||
lpSessionData->SetOldServerGroupID(cAgentServerType);
|
||||
}
|
||||
}
|
||||
|
||||
if(0 != usError)
|
||||
{
|
||||
// 문제가 생겼다. 데이터를 전부 Rollback한다.
|
||||
for(int nCount = 0; nCount < USER_INFO::MAX_CHAR_NUM; ++nCount)
|
||||
{
|
||||
if(0 != dwSelectedCID[nCount] && backupData[nCount].IsBackupedData())
|
||||
{
|
||||
if(0 == (lpCharacterData = charDataMgr.GetLogoutData(dwSelectedCID[nCount])))
|
||||
{
|
||||
ERRLOG3(g_Log, "UID:%10u / CID:%10u / ServerGroupID:%d / 통합서버 선택 실패 - 데이터 복구 실패 : 캐릭터 캐쉬로 데이터 로드 실패",
|
||||
dwUID, dwSelectedCID[nCount], cSelectedServerGroupID);
|
||||
}
|
||||
else
|
||||
{
|
||||
backupData[nCount].RestoreData(*lpCharacterData);
|
||||
|
||||
lpCharacterData->ForceUpdateDBAllData(dbComponent);
|
||||
lpSessionData->ChangeUnifiedCharServerGroupID(dbComponent,
|
||||
dwUID, dwSelectedCID[nCount], backupData[nCount].GetOldServerGroupID());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GET_SINGLE_DISPATCH(lpAuthDispatch, CAuthDispatch,
|
||||
CAuthDispatch::GetDispatchTable());
|
||||
|
||||
if(0 != lpAuthDispatch && SendPacket::UnifiedCharSelectAck(
|
||||
lpAuthDispatch->GetSendStream(), dwUID, dwRequestKey, usError))
|
||||
{
|
||||
if(0 == usError)
|
||||
{
|
||||
INFLOG2(g_Log, "UID:%10u / ServerGroupID:%d / 캐릭터 및 창고 선택 성공",
|
||||
dwUID, cSelectedServerGroupID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERRLOG2(g_Log, "UID:%10u / ServerGroupID:%d / 캐릭터 선택 실패 : "
|
||||
"인증서버와 접속이 끊기거나 전송에 실패했습니다.", dwUID, cSelectedServerGroupID);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifndef _DBAGENT_SERVER_PART1_DBAGENT_DISPATCH_H_
|
||||
#define _DBAGENT_SERVER_PART1_DBAGENT_DISPATCH_H_
|
||||
|
||||
#include <Network/Dispatch/RylServerDispatch.h>
|
||||
#include <Network/Dispatch/SingleDispatchStorage.h>
|
||||
#include <Community/FriendList.h>
|
||||
#include <Community/BanList.h>
|
||||
|
||||
namespace DBAgent
|
||||
{
|
||||
// Part1 DBAgent¼¹ö¿¡ Á¢¼ÓÇÑ´Ù.
|
||||
|
||||
class CPart1DBAgentDispatch : public CRylServerDispatch
|
||||
{
|
||||
public:
|
||||
|
||||
static CSingleDispatch& GetDispatchTable();
|
||||
|
||||
enum Const
|
||||
{
|
||||
MAX_PACKET_DISPATCH_PER_PULSE = 100,
|
||||
MAX_STREAM_BUFFER_SIZE = 16000
|
||||
};
|
||||
|
||||
CPart1DBAgentDispatch(CSession& Session);
|
||||
virtual ~CPart1DBAgentDispatch();
|
||||
|
||||
virtual void Connected();
|
||||
virtual void Disconnected();
|
||||
virtual bool DispatchPacket(PktBase* lpPktBase);
|
||||
|
||||
static bool TransferCharPart1ToPart2(CSendStream& SendStream, unsigned long dwUID,
|
||||
unsigned char cSelectedServerGroup, unsigned char cSelectedNation,
|
||||
unsigned long* lpdwSelectedCID, unsigned char cSelectedCharNum);
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
typedef std::map<unsigned short, unsigned short> QuestDelete;
|
||||
typedef std::map<unsigned short, unsigned short> QuestChange;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,731 @@
|
||||
#include "stdafx.h"
|
||||
#include "UIDDispatch.h"
|
||||
|
||||
#include "AuthDispatch.h"
|
||||
#include "GameDispatch.h"
|
||||
#include "ChatDispatch.h"
|
||||
|
||||
#include <DB/DBComponent.h>
|
||||
#include <DB/GameDBComponent.h>
|
||||
|
||||
#include <Log/ServerLog.h>
|
||||
#include <Network/Address/INET_Addr.h>
|
||||
#include <Network/Packet/PacketCommand.h>
|
||||
#include <Network/Packet/PacketStruct/ServerInfo.h>
|
||||
#include <Network/Packet/PacketStruct/ServerPacket.h>
|
||||
#include <Network/Packet/PacketStruct/CharLoginOutPacket.h>
|
||||
#include <Network/Packet/PacketStruct/CharLoginOutPacketStruct.h>
|
||||
#include <Network/SendPacket/SendServerInfo.h>
|
||||
#include <Network/SendPacket/SendLoginout.h>
|
||||
#include <Network/SendPacket/SendCharManage.h>
|
||||
|
||||
#include <DataStorage/Billing.h>
|
||||
#include <DataStorage/SessionData.h>
|
||||
#include <DataStorage/SessionDataMgr.h>
|
||||
|
||||
#include <Utility/Setup/ServerSetup.h>
|
||||
|
||||
namespace DBAgent
|
||||
{
|
||||
|
||||
const char* g_szPktUUTString[PktUUT::MAX_UPDATE_TYPE] =
|
||||
{
|
||||
"UpdateUIDTableNone",
|
||||
"UpdateUIDTableUserLogin",
|
||||
"UpdateUIDTableUserLogout",
|
||||
"UpdateUIDTableUserMove",
|
||||
"UpdateUIDTableCharLogin",
|
||||
"UpdateUIDTableCharLogout",
|
||||
"UpdateUIDTableCharMove",
|
||||
"UpdateUIDTableBillingCheck",
|
||||
};
|
||||
|
||||
|
||||
|
||||
// UpdateUIDTable처리시 유저 로그인 처리를 한다.
|
||||
// 리턴값은 상수 에러 문자열이다. NULL이면 성공이다.
|
||||
const char* ProcessUpdateTableUserLogin(DataStorage::CSessionData& sessionData,
|
||||
DataStorage::RequestData& requestData,
|
||||
unsigned long dwFlag, int nPlayTime,
|
||||
unsigned long dwCRMIndex1,
|
||||
unsigned char cCmd, char cBillingType,
|
||||
unsigned short usUUKAckError);
|
||||
|
||||
// UpdateUIDTable처리시 캐릭터 로그인 처리를 한다.
|
||||
// 리턴값은 상수 에러 문자열이다. NULL이면 성공이다.
|
||||
const char* ProcessUpdateTableCharLogin(DataStorage::CSessionData& sessionData,
|
||||
DataStorage::RequestData& requestData,
|
||||
unsigned long dwFlag, int nPlayTime,
|
||||
unsigned long dwCRMIndex1,
|
||||
unsigned char cCmd, char cBillingType);
|
||||
|
||||
CSingleDispatch& CUIDDispatch::GetDispatchTable()
|
||||
{
|
||||
static CSingleDispatch uidDispatch;
|
||||
return uidDispatch;
|
||||
}
|
||||
|
||||
CUIDDispatch::CUIDDispatch(CSession& Session)
|
||||
: CRylServerDispatch(Session, MAX_PACKET_DISPATCH_PER_PULSE)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
CUIDDispatch::~CUIDDispatch()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
void CUIDDispatch::Connected()
|
||||
{
|
||||
DETLOG3(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/UIDServer Connected",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string());
|
||||
|
||||
GetDispatchTable().SetDispatch(this);
|
||||
|
||||
SendPacket::ServerLogin(GetSendStream(),
|
||||
CServerSetup::GetInstance().GetServerID());
|
||||
}
|
||||
|
||||
void CUIDDispatch::Disconnected()
|
||||
{
|
||||
DETLOG3(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/UIDServer Disconnected",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string());
|
||||
|
||||
GetDispatchTable().RemoveDispatch(this);
|
||||
}
|
||||
|
||||
bool CUIDDispatch::DispatchPacket(PktBase* lpPktBase)
|
||||
{
|
||||
PktBase::CMDType cCmd = lpPktBase->GetCmd();
|
||||
|
||||
bool bResult = false;
|
||||
|
||||
switch(cCmd)
|
||||
{
|
||||
case CmdSysServerLogout: bResult = ParseServerLogoutAck(lpPktBase); break;
|
||||
case CmdUserKill: bResult = ParseUserKill(static_cast<PktUK*>(lpPktBase)); break;
|
||||
case CmdBillingTimeoutNotify: bResult = ParseBillingTimeNotify(static_cast<PktBTN*>(lpPktBase)); break;
|
||||
case CmdBillingTimeCheckNotify: bResult = ParseBillingTimeCheckNotify(static_cast<PktBTN*>(lpPktBase)); break;
|
||||
case CmdHanBTNWarning: bResult = ParseHanBTNWarning(static_cast<PktHanBTN*>(lpPktBase)); break;
|
||||
case CmdHanBTNUserKill: bResult = ParseHanBTNUserKill(static_cast<PktHanUserKill*>(lpPktBase)); break;
|
||||
case CmdUpdateUIDTable: bResult = ParseUpdateUIDTable(static_cast<PktUUTAck*>(lpPktBase)); break;
|
||||
|
||||
default:
|
||||
|
||||
ERRLOG4(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/Cmd:0x%02X/ UID서버 패킷 처리 실패 : 없는 커맨드입니다",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string(), cCmd);
|
||||
|
||||
bResult = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!bResult)
|
||||
{
|
||||
ERRLOG4(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/Cmd:0x%02X/ UID서버 패킷 처리 실패 : 처리를 실패했습니다",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string(), cCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CUIDDispatch::ParseServerLogoutAck(PktBase* lpPktBase)
|
||||
{
|
||||
INFLOG3(g_Log, "SS:0x%08x/DP:0x%08x/IP:%15s/Cmd:0x%02X/ UID서버 접속 종료 : 서버 로그아웃 패킷을 받았습니다.",
|
||||
&GetSession(), this, GetRemoteAddr().get_addr_string());
|
||||
|
||||
CloseSession();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CUIDDispatch::ParseUpdateUIDTable(PktUUTAck* lpPktUUTAck)
|
||||
{
|
||||
// edith 2008.01.15 UID에서 보낸 UpdateUIDTable 결과값 처리루틴
|
||||
|
||||
using namespace DBAgent::DataStorage;
|
||||
|
||||
unsigned char cCmd = lpPktUUTAck->m_cCmd;
|
||||
unsigned long dwUID = lpPktUUTAck->m_dwUserID;
|
||||
unsigned long dwFlag = lpPktUUTAck->m_dwFlag;
|
||||
int nPlayTime = lpPktUUTAck->m_nPlayTime;
|
||||
unsigned long dwCRMIndex1 = lpPktUUTAck->m_dwCRMIndex1; // 피시방 ID (0이면 개인유저)
|
||||
char cBillingType = lpPktUUTAck->m_cstrBillingType;
|
||||
|
||||
CBilling::WarningType eOldWarnMsgType = CBilling::WARN_BEFORE_1SEC;
|
||||
CBilling::WarningType eNewWarnMsgType = static_cast<CBilling::WarningType>(lpPktUUTAck->GetState());
|
||||
|
||||
const char* szErrorReason = 0;
|
||||
|
||||
RequestData requestData;
|
||||
memset(&requestData, 0, sizeof(RequestData));
|
||||
|
||||
CSessionData* lpSessionData = CSessionDataMgr::GetInstance().GetOpenSession(dwUID);
|
||||
|
||||
if(PktUUT::MAX_UPDATE_TYPE <= cCmd)
|
||||
{
|
||||
szErrorReason = "로그인 실패 - 알 수 없는 커맨드입니다";
|
||||
}
|
||||
else if(0 == lpSessionData)
|
||||
{
|
||||
szErrorReason = "로그인 실패 - 세션이 없습니다";
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(cCmd)
|
||||
{
|
||||
case PktUUT::UpdateUIDTableUserLogin:
|
||||
|
||||
requestData = lpSessionData->PopRequest();
|
||||
|
||||
if(0 == requestData.m_dwRequestKey)
|
||||
{
|
||||
szErrorReason = "로그인 실패 - RequestKey가 이상합니다";
|
||||
}
|
||||
else
|
||||
{
|
||||
szErrorReason = ProcessUpdateTableUserLogin(*lpSessionData, requestData, dwFlag,
|
||||
nPlayTime, dwCRMIndex1, cCmd, cBillingType, lpPktUUTAck->GetError());
|
||||
|
||||
eOldWarnMsgType = lpSessionData->GetBilling().GetWarnMsgType();
|
||||
lpSessionData->GetBilling().SetWarnMsgType(eNewWarnMsgType);
|
||||
|
||||
if(CBilling::WARN_EVERY_MINUTE == eNewWarnMsgType)
|
||||
{
|
||||
// 경고 상태로 이행. 매분마다 메시지를 보내도록 한다.
|
||||
SendPacket::BillingCheckNotify(*lpSessionData, 5, cBillingType);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PktUUT::UpdateUIDTableCharLogin:
|
||||
|
||||
requestData = lpSessionData->PopRequest();
|
||||
|
||||
if(0 == requestData.m_dwRequestKey)
|
||||
{
|
||||
szErrorReason = "로그인 실패 - RequestKey가 이상합니다";
|
||||
}
|
||||
else
|
||||
{
|
||||
szErrorReason = ProcessUpdateTableCharLogin(*lpSessionData, requestData,
|
||||
dwFlag, nPlayTime, dwCRMIndex1, cCmd, cBillingType);
|
||||
}
|
||||
break;
|
||||
|
||||
case PktUUT::UpdateUIDTableBillingCheck:
|
||||
|
||||
eOldWarnMsgType = lpSessionData->GetBilling().GetWarnMsgType();
|
||||
|
||||
if(0 == dwFlag)
|
||||
{
|
||||
lpSessionData->GetBilling().SetWarnMsgType(eNewWarnMsgType);
|
||||
|
||||
if (CBilling::NO_WARNING == eOldWarnMsgType &&
|
||||
CBilling::WARN_EVERY_MINUTE == eNewWarnMsgType)
|
||||
{
|
||||
// 무경고 상태에서 경고 상태로 이행. 매분마다 메시지를 보내도록 한다.
|
||||
SendPacket::BillingCheckNotify(*lpSessionData, 5, cBillingType);
|
||||
}
|
||||
else
|
||||
if (CBilling::WARN_EVERY_MINUTE == eOldWarnMsgType &&
|
||||
CBilling::NO_WARNING == eNewWarnMsgType)
|
||||
{
|
||||
// 경고 상태에서 무경고 상태로 이행. 메시지를 그만 보내도록 한다.
|
||||
SendPacket::BillingCheckNotify(*lpSessionData, 20, cBillingType);
|
||||
}
|
||||
}
|
||||
|
||||
lpSessionData->GetBilling().AddYouxiLandPoint(nPlayTime, cBillingType);
|
||||
|
||||
DETLOG4(g_Log, "UID:%10u / CID:%10u / nPlayTime:%d / cBillingType:%c / UpdateUIDTableBillingCheck 성공",
|
||||
lpSessionData->GetUID(), lpSessionData->GetCID(), nPlayTime, cBillingType);
|
||||
|
||||
if (0 != dwFlag)
|
||||
{
|
||||
// 유저 킬 처리 - 특별히 하지 않는다. 나중에 빌링체크에서 끊을 것이다.
|
||||
// KillUser(lpDataSession);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(0 != szErrorReason)
|
||||
{
|
||||
ERRLOG10(g_Log, "UID:%10u / Cmd:%s / Flag:%u / PlayTime:%d / CRMIndex:%u / BillingType:%c / "
|
||||
" RequestKey:%10u / SelectedCID:%10u / ServerID:0x%08X / ParseUIDTable 실패 : %s",
|
||||
dwUID, g_szPktUUTString[cCmd], dwFlag, nPlayTime, dwCRMIndex1, cBillingType,
|
||||
requestData.m_dwRequestKey, requestData.m_dwSelectedCID,
|
||||
requestData.m_dwServerID, szErrorReason);
|
||||
|
||||
if(0 == dwFlag)
|
||||
{
|
||||
PktUUT::UpdateType eUpdateType = PktUUT::UpdateUIDTableNone;
|
||||
|
||||
switch(cCmd)
|
||||
{
|
||||
case PktUUT::UpdateUIDTableUserLogin:
|
||||
eUpdateType = PktUUT::UpdateUIDTableUserLogout;
|
||||
break;
|
||||
|
||||
case PktUUT::UpdateUIDTableCharLogin:
|
||||
eUpdateType = PktUUT::UpdateUIDTableCharLogout;
|
||||
break;
|
||||
}
|
||||
|
||||
// edith 2008.01.15 UID로 로그인 메시지 전송
|
||||
if(0 == lpSessionData)
|
||||
{
|
||||
ERRLOG1(g_Log, "UID:%10u / UID서버 전송 실패 : 세션이 없습니다.", dwUID);
|
||||
}
|
||||
else if(eUpdateType != PktUUT::UpdateUIDTableNone &&
|
||||
!SendPacket::UpdateUIDTable(eUpdateType, requestData.m_szAccount, requestData.m_szPassword,
|
||||
dwUID, requestData.m_dwSelectedCID, requestData.m_dwSessionID,
|
||||
requestData.m_dwServerID, requestData.m_PeerAddress))
|
||||
{
|
||||
ERRLOG1(g_Log, "UID:%10u / UID서버 전송 실패 : 전송에 실패했습니다.", dwUID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* ProcessUpdateTableUserLogin(DataStorage::CSessionData& sessionData,
|
||||
DataStorage::RequestData& requestData,
|
||||
unsigned long dwFlag, int nPlayTime, unsigned long dwCRMIndex1,
|
||||
unsigned char cCmd, char cBillingType, unsigned short usUUKAckError)
|
||||
{
|
||||
// edith 2008.01.15 UpdateTableUserLogin에 관련된 프로세싱 로직
|
||||
const char* szErrorReason = 0;
|
||||
unsigned long dwUID = sessionData.GetUID();
|
||||
|
||||
GET_SINGLE_DISPATCH(lpAuthDispatch,
|
||||
CAuthDispatch, CAuthDispatch::GetDispatchTable());
|
||||
|
||||
if(0 == lpAuthDispatch)
|
||||
{
|
||||
szErrorReason = "유저 로그인 실패 - 인증서버 접속 끊김";
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned short usError = 1; // Default : Server Error(Unknown Error)
|
||||
|
||||
if (0 == dwFlag)
|
||||
{
|
||||
// 통합서버 정보를 얻어서 보내준다.
|
||||
unsigned char cAgentServerType = static_cast<unsigned char>(
|
||||
CServerSetup::GetInstance().GetAgentServerType());
|
||||
|
||||
unsigned char cFirstLogin = 0;
|
||||
|
||||
switch(cAgentServerType)
|
||||
{
|
||||
case UnifiedConst::Part1:
|
||||
case UnifiedConst::Part1Unified:
|
||||
// 서버 세팅 잘못 했음. 나중에 UserLogin
|
||||
szErrorReason = "유저 로그인 실패 - 서버 잘못 켰음";
|
||||
break;
|
||||
|
||||
case UnifiedConst::ROW:
|
||||
sessionData.SetOldServerGroupID(UnifiedConst::ROW);
|
||||
break;
|
||||
|
||||
case UnifiedConst::Part2Unified:
|
||||
case UnifiedConst::Part2Selectable:
|
||||
|
||||
if(!sessionData.GetUnifiedDataFromDB(CDBSingleObject::GetInstance()))
|
||||
{
|
||||
szErrorReason = "유저 로그인 실패 - 통합서버 데이터 얻기 실패";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
cFirstLogin = sessionData.GetFirstLogin();
|
||||
|
||||
if(0 != szErrorReason)
|
||||
{
|
||||
// 데이터 읽어오다 에러 난 모양이다. UserLogin을 취소한다.
|
||||
}
|
||||
else if(!sessionData.UserEnable(CDBSingleObject::GetInstance(), dwUID))
|
||||
{
|
||||
szErrorReason = "유저 로그인 실패 - 유저 활성화 실패";
|
||||
}
|
||||
else if(!SendPacket::StartSession(lpAuthDispatch->GetSendStream(),
|
||||
requestData.m_dwRequestKey, dwUID, requestData.m_dwSessionID, cFirstLogin, 0))
|
||||
{
|
||||
szErrorReason = "유저 로그인 실패 - 유저 로그인 성공 전송 실패";
|
||||
}
|
||||
else
|
||||
{
|
||||
// 빌링 시작(접속 끊기 시작. 예전 한게임 과금과 요시랜드 과금만 사용함).
|
||||
// 인증서버에서는 과금 안함. 과금 정보 표시를 위해서 세팅함.
|
||||
sessionData.GetBilling().StartBilling(nPlayTime, dwCRMIndex1, cBillingType);
|
||||
|
||||
// edith 2008.01.15 로그인에 성공했으니 세션에 등록한다.
|
||||
// 로그인 성공했을때만 세션 ID등의 데이터를 세팅한다.
|
||||
sessionData.SetRequestData(requestData);
|
||||
|
||||
// 세션 열기 성공
|
||||
usError = 0;
|
||||
|
||||
// StartSession을 받았을 때, 에러가 0이고, 중계서버 타입이 통합서버이면,
|
||||
// 통합서버 데이터를 기다리므로, 데이터를 여기서 전송해 준다.
|
||||
|
||||
switch(cAgentServerType)
|
||||
{
|
||||
case UnifiedConst::Part2Unified:
|
||||
case UnifiedConst::Part2Selectable:
|
||||
|
||||
// 신규 계정인지 아닌지 생각할 필요는 없다. 일단 정보 주고 나면
|
||||
// 선택할 캐릭이 없으면 알아서 그냥 로그인하기 때문이다.
|
||||
if (!SendPacket::UnifiedCharInfo(lpAuthDispatch->GetSendStream(),
|
||||
dwUID, sessionData.GetTransferedCharCount(CDBSingleObject::GetInstance()),
|
||||
sessionData.GetUserInfo(),
|
||||
sessionData.GetUnifiedStoreInfo(), sessionData.GetUnifiedStoreInfoNum(),
|
||||
sessionData.GetUnifiedCharData(), sessionData.GetUnifiedCharDataNum()))
|
||||
{
|
||||
// 정보 전송에 실패했으면 뭐 하는 수 없지;; 알아서 데이터 기다리다 끊어지겠지;;
|
||||
ERRLOG1(g_Log, "UID:%10u / 유저 로그인 실패 - 통합서버 정보 전송 실패", dwUID);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (1 == dwFlag)
|
||||
{
|
||||
switch(usUUKAckError)
|
||||
{
|
||||
default:
|
||||
usError = 41; // 중복로그인
|
||||
break;
|
||||
|
||||
case PktUUT::DISCONNECT_USER:
|
||||
usError = 42; // Disconnect를 했으니 재시도해 봐..
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (2 == dwFlag) { usError = 24; } // 개인,피시방 관련 과금 정보가 없음(한게임)
|
||||
else if (4 == dwFlag) { usError = 1; } // 서버 에러 (DB Query 실패)
|
||||
else if (11 == dwFlag || 13 == dwFlag || 19 == dwFlag)
|
||||
{
|
||||
// 개인,피시방 관련 과금 정보가 없음(대만)
|
||||
usError = 24;
|
||||
}
|
||||
else if (20 == dwFlag) { usError = 40; } // 대만, 일본 중복 로그인 방지
|
||||
// edith 2009.09.11 MY를 위한 AllowIP 처리작업
|
||||
else if (57 == dwFlag) { usError = 57; } // ROW에서 AllowIP 에서 걸림
|
||||
else if (100 >= dwFlag) { usError = (unsigned short)(dwFlag-100); }; // 감마니아 오류
|
||||
|
||||
if(0 != usError)
|
||||
{
|
||||
SendPacket::StartSession(lpAuthDispatch->GetSendStream(),
|
||||
requestData.m_dwRequestKey, dwUID, sessionData.GetSessionID(), 0, usError);
|
||||
}
|
||||
}
|
||||
|
||||
return szErrorReason;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char* ProcessUpdateTableCharLogin(DataStorage::CSessionData& sessionData,
|
||||
DataStorage::RequestData& requestData,
|
||||
unsigned long dwFlag, int nPlayTime,
|
||||
unsigned long dwCRMIndex1,
|
||||
unsigned char cCmd, char cBillingType)
|
||||
{
|
||||
const char* szErrorReason = 0;
|
||||
unsigned long dwUID = sessionData.GetUID();
|
||||
|
||||
GET_MULTI_DISPATCH(lpGameDispatch, requestData.m_dwServerID,
|
||||
CGameDispatch, CGameDispatch::GetDispatchTable());
|
||||
|
||||
if(0 == lpGameDispatch)
|
||||
{
|
||||
szErrorReason = "캐릭터 로그인 실패 - 게임서버 접속 끊김";
|
||||
}
|
||||
else if(!sessionData.HasCharacter(requestData.m_dwSelectedCID))
|
||||
{
|
||||
szErrorReason = "캐릭터 로그인 실패 - 소유하지 않은 캐릭터 활성화";
|
||||
|
||||
const USER_INFO& userInfo = sessionData.GetUserInfo();
|
||||
|
||||
// WORK_LIST 2.1 계정 국적 추가
|
||||
SERLOG9(g_Log, "UID:%10u / SelectedCID:%10u / Char1:%10u / Char2:%10u / Char3:%10u / Char4:%10u / Char5:%10u / Nation:%d %s",
|
||||
dwUID, requestData.m_dwSelectedCID,
|
||||
userInfo.CharID[0], userInfo.CharID[1], userInfo.CharID[2],
|
||||
userInfo.CharID[3], userInfo.CharID[4], userInfo.Nation, szErrorReason);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 기본값은 실패. 서버 에러.
|
||||
unsigned short usError = 1;
|
||||
|
||||
if (0 == dwFlag)
|
||||
{
|
||||
// 캐릭터 활성화
|
||||
if (!sessionData.CharEnable(requestData.m_dwSelectedCID, requestData.m_dwServerID))
|
||||
{
|
||||
szErrorReason = "캐릭터 로그인 실패 - 세션 활성화 실패";
|
||||
}
|
||||
// 캐릭터 데이터 전송
|
||||
else if (!SendPacket::CharLogin(lpGameDispatch->GetSendStream(),
|
||||
sessionData, requestData.m_dwRequestKey))
|
||||
{
|
||||
szErrorReason = "캐릭터 로그인 실패 - 캐릭터 데이터 전송 실패";
|
||||
|
||||
// 활성화된 캐릭터를 Disable함.
|
||||
sessionData.CharDisable(requestData.m_dwSelectedCID, requestData.m_dwServerID);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 빌링 시작
|
||||
switch(CServerSetup::GetInstance().GetBillingType())
|
||||
{
|
||||
case CServerSetup::GamaBilling:
|
||||
case CServerSetup::GamaUnitedBilling:
|
||||
sessionData.GetBilling().StartBilling(nPlayTime, dwCRMIndex1, cBillingType);
|
||||
break;
|
||||
}
|
||||
|
||||
// 로그인 성공했을때만 세션 ID등의 데이터를 세팅한다.
|
||||
sessionData.SetRequestData(requestData);
|
||||
|
||||
// 접속 성공!
|
||||
usError = 0;
|
||||
}
|
||||
}
|
||||
else if (1 == dwFlag) { usError = 41; } // 중복로그인
|
||||
else if (2 == dwFlag) { usError = 24; } // 개인,피시방 관련 과금 정보가 없음
|
||||
else if (4 == dwFlag) { usError = 1; } // 서버 에러 (DB Query 실패)
|
||||
else if (11 == dwFlag || 13 == dwFlag || 19 == dwFlag)
|
||||
{
|
||||
// 개인,피시방 관련 과금 정보가 없음(대만)
|
||||
usError = 24;
|
||||
}
|
||||
else if (20 == dwFlag) { usError = 40; } // 대만, 일본 중복 로그인 방지
|
||||
// edith 2009.09.11 MY를 위한 AllowIP 처리작업
|
||||
else if (57 == dwFlag) { usError = 57; } // ROW에서 AllowIP 에서 걸림
|
||||
else if (100 >= dwFlag) { usError = (unsigned short)(dwFlag-100); }; // 감마니아 오류
|
||||
|
||||
if (0 != usError)
|
||||
{
|
||||
SendPacket::CharLoginError(lpGameDispatch->GetSendStream(),
|
||||
requestData.m_dwRequestKey, DBUpdateData::LOGIN,
|
||||
dwUID, requestData.m_dwSelectedCID, usError);
|
||||
}
|
||||
}
|
||||
|
||||
return szErrorReason;
|
||||
}
|
||||
|
||||
|
||||
bool CUIDDispatch::ParseBillingTimeNotify(PktBTN* lpPktBTN)
|
||||
{
|
||||
using namespace DataStorage;
|
||||
|
||||
CSessionData* lpSessionData = CSessionDataMgr::GetInstance().GetOpenSession(lpPktBTN->m_dwUserID);
|
||||
if(0 == lpSessionData)
|
||||
{
|
||||
ERRLOG2(g_Log, "UID:%10u / cRemainMin:%u / 시간 만료 공지를 보내기 실패 : 유저가 없습니다",
|
||||
lpPktBTN->m_dwUserID, lpPktBTN->m_cRemainMinute);
|
||||
}
|
||||
else if(CSessionData::SE_CHAR_ENABLED != lpSessionData->GetSessionState())
|
||||
{
|
||||
ERRLOG2(g_Log, "UID:%10u / ST:%s / 시간 만료 공지를 보내기 실패 : 캐릭터가 비활성화되어 있습니다",
|
||||
lpPktBTN->m_dwUserID, g_szSessionStateString[lpSessionData->GetSessionState()]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 시간이 다 떨어져서 경고 보냄.
|
||||
if(!SendPacket::BillingNotify(*lpSessionData,
|
||||
lpPktBTN->m_cRemainMinute, lpPktBTN->m_cBillingType))
|
||||
{
|
||||
INFLOG4(g_Log, "UID:%10u / ServerID:0x%08X / cRemainMin:%u / cBillingType:%c / 시간 만료 공지 보내기 성공",
|
||||
lpPktBTN->m_dwUserID, lpSessionData->GetServerID(), lpPktBTN->m_cRemainMinute, lpPktBTN->m_cBillingType);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERRLOG2(g_Log, "UID:%10u / ServerID:0x%08X / 시간 만료 공지를 보내기 실패 : 게임서버와의 연결이 끊어져 있습니다",
|
||||
lpPktBTN->m_dwUserID, lpSessionData->GetServerID());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CUIDDispatch::ParseBillingTimeCheckNotify(PktBTN* lpPktBTN)
|
||||
{
|
||||
using namespace DataStorage;
|
||||
|
||||
CSessionData* lpSessionData = CSessionDataMgr::GetInstance().GetOpenSession(lpPktBTN->m_dwUserID);
|
||||
if(0 == lpSessionData)
|
||||
{
|
||||
ERRLOG2(g_Log, "UID:%10u / cRemainMin:%u / 시간 다시 체크(대만) 공지를 보내기 실패 : 유저가 없습니다",
|
||||
lpPktBTN->m_dwUserID, lpPktBTN->m_cRemainMinute);
|
||||
}
|
||||
else if(CSessionData::SE_CHAR_ENABLED != lpSessionData->GetSessionState())
|
||||
{
|
||||
ERRLOG2(g_Log, "UID:%10u / ST:%s / 시간 다시 체크(대만) 공지를 보내기 실패 : 캐릭터가 비활성화되어 있습니다",
|
||||
lpPktBTN->m_dwUserID, g_szSessionStateString[lpSessionData->GetSessionState()]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 시간이 다 떨어져서 경고 보냄.
|
||||
if(!SendPacket::BillingCheckNotify(*lpSessionData,
|
||||
lpPktBTN->m_cRemainMinute, lpPktBTN->m_cBillingType))
|
||||
{
|
||||
INFLOG4(g_Log, "UID:%10u / ServerID:0x%08X / cRemainMin:%u / cBillingType:%c / 시간 다시 체크(대만) 공지 보내기 성공",
|
||||
lpPktBTN->m_dwUserID, lpSessionData->GetServerID(), lpPktBTN->m_cRemainMinute, lpPktBTN->m_cBillingType);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERRLOG2(g_Log, "UID:%10u / ServerID:0x%08X / 시간 다시 체크 공지(대만)를 보내기 실패 : 게임서버와의 연결이 끊어져 있습니다",
|
||||
lpPktBTN->m_dwUserID, lpSessionData->GetServerID());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CUIDDispatch::ParseHanBTNWarning(PktHanBTN* lpPktHanBTN)
|
||||
{
|
||||
// 채팅서버로 메시지를 Relay한다.
|
||||
using namespace DataStorage;
|
||||
|
||||
IN_ADDR peerAddress;
|
||||
peerAddress.S_un.S_addr = lpPktHanBTN->m_dwIP;
|
||||
|
||||
bool bCheckAddress = (0xFFFFFFFF != peerAddress.S_un.S_addr);
|
||||
|
||||
CSessionData* lpSessionData = CSessionDataMgr::GetInstance().GetOpenSession(
|
||||
lpPktHanBTN->m_szAccount, peerAddress, bCheckAddress);
|
||||
|
||||
if(0 == lpSessionData)
|
||||
{
|
||||
ERRLOG2(g_Log, "AccountName:%16s / IP:%15s / 과금 만료 메시지 전송 실패 : 유저가 없습니다",
|
||||
lpPktHanBTN->m_szAccount, inet_ntoa(peerAddress));
|
||||
}
|
||||
else if(CSessionData::SE_CHAR_ENABLED != lpSessionData->GetSessionState())
|
||||
{
|
||||
ERRLOG4(g_Log, "UID:%10u / AccountName:%16s / IP:%15s / ST:%s / 과금 만료 메시지 전송 실패 : 캐릭터가 비활성화되어 있습니다",
|
||||
lpSessionData->GetUID(), lpPktHanBTN->m_szAccount, inet_ntoa(peerAddress),
|
||||
g_szSessionStateString[lpSessionData->GetSessionState()]);
|
||||
}
|
||||
else
|
||||
{
|
||||
GET_SINGLE_DISPATCH(lpChatDispatch,
|
||||
CChatDispatch, CChatDispatch::GetDispatchTable());
|
||||
|
||||
if(0 != lpChatDispatch)
|
||||
{
|
||||
char* lpBuffer = lpChatDispatch->GetSendStream().GetBuffer(sizeof(PktHanBTN));
|
||||
|
||||
if(0 != lpBuffer)
|
||||
{
|
||||
PktHanBTN* lpPktChatBTN = reinterpret_cast<PktHanBTN*>(lpBuffer);
|
||||
|
||||
*lpPktChatBTN = *lpPktHanBTN;
|
||||
|
||||
lpPktChatBTN->m_dwUID = lpSessionData->GetUID();
|
||||
lpPktChatBTN->m_dwCID = lpSessionData->GetCID();
|
||||
|
||||
return lpChatDispatch->GetSendStream().WrapHeader(
|
||||
sizeof(PktHanBTN), CmdHanBTNWarning, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
ERRLOG5(g_Log, "UID:%10u / AccountName:%16s / IP:%15s / ST:%s / ChatDispatch:%p / 과금 만료 메시지 전송 실패 : 채팅서버와 연결이 끊겼거나, 버퍼 할당 실패",
|
||||
lpSessionData->GetUID(), lpPktHanBTN->m_szAccount, inet_ntoa(peerAddress),
|
||||
g_szSessionStateString[lpSessionData->GetSessionState()], lpChatDispatch);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CUIDDispatch::ParseHanBTNUserKill(PktHanUserKill* lpPktHanUserKill)
|
||||
{
|
||||
using namespace DataStorage;
|
||||
|
||||
IN_ADDR peerAddress;
|
||||
peerAddress.S_un.S_addr = lpPktHanUserKill->m_dwIP;
|
||||
|
||||
// 접속 DB를 전부 뒤져서, 계정과 IP가 일치하는 넘한테 뜨거운 맛을 보여 준다.
|
||||
bool bCheckAddress = (peerAddress.S_un.S_addr != 0xFFFFFFFF);
|
||||
|
||||
CSessionData* lpSessionData = CSessionDataMgr::GetInstance().GetOpenSession(
|
||||
lpPktHanUserKill->m_szAccount, peerAddress, bCheckAddress);
|
||||
|
||||
if(0 == lpSessionData)
|
||||
{
|
||||
ERRLOG2(g_Log, "AccountName:%16s / IP:%15s / 과금 만료 접속 끊기 실패 : 유저가 없습니다",
|
||||
lpPktHanUserKill->m_szAccount, inet_ntoa(peerAddress));
|
||||
}
|
||||
else
|
||||
{
|
||||
SERVER_ID serverID;
|
||||
serverID.dwID = lpSessionData->GetServerID();
|
||||
CSessionData::SessionState eSessionState = lpSessionData->GetSessionState();
|
||||
|
||||
if ((serverID.GetType() == CServerSetup::AuthServer && CSessionData::SE_USER_ENABLED != eSessionState) ||
|
||||
(serverID.GetType() == CServerSetup::GameServer && CSessionData::SE_CHAR_ENABLED != eSessionState))
|
||||
{
|
||||
ERRLOG3(g_Log, "UID:%10u / ServerID:0x%08X / ST:%s / 과금 만료 접속 끊기 실패 : 유저나 캐릭터가 비활성화되어 있습니다",
|
||||
lpSessionData->GetUID(), serverID.dwID, g_szSessionStateString[lpSessionData->GetSessionState()]);
|
||||
}
|
||||
else if(!SendPacket::UserKill(*lpSessionData))
|
||||
{
|
||||
ERRLOG3(g_Log, "UID:%10u / ServerID:0x%08X / ST:%s / 과금 만료 접속 끊기 실패 : 접속 끊기 패킷 보내기 실패",
|
||||
lpSessionData->GetUID(), serverID.dwID, g_szSessionStateString[lpSessionData->GetSessionState()]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CUIDDispatch::ParseUserKill(PktUK* lpPktUK)
|
||||
{
|
||||
using namespace DataStorage;
|
||||
|
||||
// 접속 DB를 전부 뒤져서, 계정과 IP가 일치하는 넘한테 뜨거운 맛을 보여 준다.
|
||||
CSessionData* lpSessionData =
|
||||
CSessionDataMgr::GetInstance().GetOpenSession(lpPktUK->m_dwUserID);
|
||||
|
||||
if(0 == lpSessionData)
|
||||
{
|
||||
ERRLOG1(g_Log, "UID:%10u / UID 서버 유저 접속 끊기 실패 : 유저가 없습니다", lpPktUK->m_dwUserID);
|
||||
}
|
||||
else
|
||||
{
|
||||
SERVER_ID serverID;
|
||||
serverID.dwID = lpSessionData->GetServerID();
|
||||
CSessionData::SessionState eSessionState = lpSessionData->GetSessionState();
|
||||
|
||||
if ((serverID.GetType() == CServerSetup::AuthServer && CSessionData::SE_USER_ENABLED != eSessionState) ||
|
||||
(serverID.GetType() == CServerSetup::GameServer && CSessionData::SE_CHAR_ENABLED != eSessionState))
|
||||
{
|
||||
ERRLOG3(g_Log, "UID:%10u / ServerID:0x%08X / ST:%s / UID 서버 유저 접속 끊기 실패 : 유저나 캐릭터가 비활성화되어 있습니다",
|
||||
lpPktUK->m_dwUserID, serverID.dwID, g_szSessionStateString[lpSessionData->GetSessionState()]);
|
||||
}
|
||||
else if(!SendPacket::UserKill(*lpSessionData))
|
||||
{
|
||||
ERRLOG3(g_Log, "UID:%10u / ServerID:0x%08X / ST:%s / UID 서버 유저 접속 끊기 실패 : 접속 끊기 패킷 보내기 실패",
|
||||
lpPktUK->m_dwUserID, serverID.dwID, g_szSessionStateString[lpSessionData->GetSessionState()]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
#ifndef _DBAGENT_SERVER_UID_DISPATCH_H_
|
||||
#define _DBAGENT_SERVER_UID_DISPATCH_H_
|
||||
|
||||
#include <Network/Packet/PacketStruct/ServerPacket.h>
|
||||
#include <Network/Dispatch/RylServerDispatch.h>
|
||||
#include <Network/Dispatch/SingleDispatchStorage.h>
|
||||
|
||||
// forward decl.
|
||||
struct PktBase;
|
||||
struct PktUUTAck;
|
||||
struct PktBTN;
|
||||
struct PktHanBTN;
|
||||
struct PktHanUserKill;
|
||||
struct PktUK;
|
||||
struct PktSLAck;
|
||||
|
||||
namespace DBAgent
|
||||
{
|
||||
extern const char* g_szPktUUTString[PktUUT::MAX_UPDATE_TYPE];
|
||||
|
||||
class CUIDDispatch : public CRylServerDispatch
|
||||
{
|
||||
public:
|
||||
|
||||
static CSingleDispatch& GetDispatchTable();
|
||||
|
||||
enum Const
|
||||
{
|
||||
MAX_PACKET_DISPATCH_PER_PULSE = 100,
|
||||
MAX_STREAM_BUFFER_SIZE = 16000
|
||||
};
|
||||
|
||||
CUIDDispatch(CSession& Session);
|
||||
virtual ~CUIDDispatch();
|
||||
|
||||
virtual void Connected();
|
||||
virtual void Disconnected();
|
||||
virtual bool DispatchPacket(PktBase* lpPktBase);
|
||||
|
||||
private:
|
||||
|
||||
bool ParseServerLoginAck(PktSLAck* lpPktSLAck);
|
||||
bool ParseServerLogoutAck(PktBase* lpPktBase);
|
||||
|
||||
bool ParseUpdateUIDTable(PktUUTAck* lpPktUUTAck);
|
||||
|
||||
bool ParseBillingTimeNotify(PktBTN* lpPktBTN); // 한국 과금 경고 메시지
|
||||
bool ParseBillingTimeCheckNotify(PktBTN* lpPktBTN); // 대만 과금 경고 메시지
|
||||
|
||||
bool ParseHanBTNWarning(PktHanBTN* lpPktHanBTN); // 한국 통합빌링 과금 경고 메시지
|
||||
bool ParseHanBTNUserKill(PktHanUserKill* lpPktHanUserKill); // 한국 통합빌링 과금 접속 끊기
|
||||
|
||||
bool ParseUserKill(PktUK* lpPktUK); // 접속 끊기
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user