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:
2025-11-29 20:17:20 +09:00
parent 5d3cd64a25
commit dd97ddec92
11602 changed files with 1446576 additions and 0 deletions

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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);
}
}
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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